CMS Tree Page View - Version 0.4.6

Version Description

  • could get database error because post_content had no default value
  • removed usage of console.log and one alert. ouch!
  • when adding page inside, several posts could get menu_order
Download this release

Release Info

Developer eskapism
Plugin Icon wp plugin CMS Tree Page View
Version 0.4.6
Comparing to
See all releases

Version 0.4.6

functions.php ADDED
@@ -0,0 +1,565 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ function cms_tpv_admin_head() {
4
+ global $cms_tpv_view;
5
+ if (isset($_GET["cms_tpv_view"])) {
6
+ $cms_tpv_view = $_GET["cms_tpv_view"];
7
+ } else {
8
+ $cms_tpv_view = "all";
9
+ }
10
+ ?>
11
+ <script type="text/javascript">
12
+ var CMS_TPV_URL = "<?php echo CMS_TPV_URL ?>";
13
+ var CMS_TPV_AJAXURL = "?action=cms_tpv_get_childs&view=";
14
+ var CMS_TPV_VIEW = "<?php echo $cms_tpv_view ?>";
15
+ </script>
16
+
17
+ <!--[if IE 6]>
18
+ <style>
19
+ #cms_tree_view_search_form {
20
+ display: none !important;
21
+ }
22
+ #cms_tpv_dashboard_widget .subsubsub li {
23
+ }
24
+ </style>
25
+ <![endif]-->
26
+ <?php
27
+ }
28
+
29
+ function cms_tpv_admin_init() {
30
+ wp_enqueue_style( "cms_tpv_styles", CMS_TPV_URL . "styles/styles.css", false, CMS_TPV_VERSION );
31
+ wp_enqueue_script( "jquery-cookie", CMS_TPV_URL . "scripts/jquery.cookie.js", array("jquery"));
32
+ wp_enqueue_script( "jquery-jstree", CMS_TPV_URL . "scripts/jquery.tree.js", false, CMS_TPV_VERSION);
33
+ wp_enqueue_script( "jquery-jstree-plugin-cookie", CMS_TPV_URL . "scripts/plugins/jquery.tree.cookie.js", false, CMS_TPV_VERSION);
34
+ wp_enqueue_script( "cms_tree_page_view", CMS_TPV_URL . "scripts/cms_tree_page_view.php?wp-abspath=" . urlencode(ABSPATH), false, CMS_TPV_VERSION);
35
+ load_plugin_textdomain('cms-tree-page-view', WP_CONTENT_DIR . "/plugins/languages", "/cms-tree-page-view/languages");
36
+
37
+ }
38
+
39
+ function cms_tpv_wp_dashboard_setup() {
40
+ if ( cms_tpv_show_on_dashboard() ) {
41
+ wp_add_dashboard_widget('cms_tpv_dashboard_widget', 'CMS Tree Page View', 'cms_tpv_dashboard');
42
+ }
43
+ }
44
+
45
+ function cms_tpv_show_on_dashboard() {
46
+ // @todo: fix this
47
+ return false;
48
+ if ( get_option('cms_tpv_show_on_dashboard', 1) == 1 && current_user_can("edit_pages") ) {
49
+ return true;
50
+ } else {
51
+ return false;
52
+ }
53
+ }
54
+ function cms_tpv_show_under_pages() {
55
+ if ( get_option('cms_tpv_show_under_pages', 1) == 1 && current_user_can("edit_pages") ) {
56
+ return true;
57
+ } else {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Output on dashboard
64
+ */
65
+ function cms_tpv_dashboard() {
66
+
67
+ cms_tpv_print_common_tree_stuff();
68
+
69
+ }
70
+
71
+ function cms_tpv_admin_menu() {
72
+ if ( cms_tpv_show_under_pages() ) {
73
+ add_pages_page( CMS_TPV_NAME, CMS_TPV_NAME, "edit_pages", "cms-tpv-pages-page", "cms_tpv_pages_page" );
74
+ }
75
+ add_submenu_page( 'options-general.php' , CMS_TPV_NAME, CMS_TPV_NAME, "administrator", "cms-tpv-options", "cms_tpv_options");
76
+ }
77
+
78
+
79
+ /**
80
+ * Output options page
81
+ */
82
+ function cms_tpv_options() {
83
+ ?>
84
+
85
+ <div class="wrap">
86
+ <h2><?php echo CMS_TPV_NAME ?> <?php _e("settings", 'cms-tree-page-view') ?></h2>
87
+
88
+ <form method="post" action="options.php">
89
+ <?php wp_nonce_field('update-options'); ?>
90
+ <table class="form-table">
91
+ <tr valign="top">
92
+ <th scope="row">
93
+ <?php _e("Show tree", 'cms-tree-page-view') ?>
94
+ </th>
95
+ <td>
96
+ <!--
97
+ @todo: fix this
98
+ <input type="checkbox" name="cms_tpv_show_on_dashboard" id="cms_tpv_show_on_dashboard" value="1" <?php echo get_option('cms_tpv_show_on_dashboard', 1) ? " checked='checked'" : "" ?> />
99
+ <label for="cms_tpv_show_on_dashboard"><?php _e("on the dashboard", 'cms-tree-page-view') ?></label>
100
+ <br />
101
+ -->
102
+ <input type="checkbox" name="cms_tpv_show_under_pages" id="cms_tpv_show_under_pages" value="1" <?php echo get_option('cms_tpv_show_under_pages', 1) ? " checked='checked'" : "" ?> />
103
+ <label for="cms_tpv_show_under_pages"><?php _e("under the pages menu", 'cms-tree-page-view') ?></label>
104
+ </td>
105
+ </tr>
106
+ </table>
107
+ <input type="hidden" name="action" value="update" />
108
+ <input type="hidden" name="page_options" value="cms_tpv_show_on_dashboard,cms_tpv_show_under_pages" />
109
+ <p class="submit">
110
+ <input type="submit" class="button-primary" value="<?php _e('Save Changes', 'cms-tree-page-view') ?>" />
111
+ </p>
112
+ </form>
113
+ </div>
114
+
115
+ <?php
116
+ }
117
+
118
+
119
+ /**
120
+ * Print tree stuff that is common for both dashboard and page
121
+ */
122
+ function cms_tpv_print_common_tree_stuff() {
123
+ $pages = cms_tpv_get_pages();
124
+ if (empty($pages)) {
125
+ echo '<div class="updated fade below-h2"><p>No pages found. Maybe you want to <a href="page-new.php">add a new page</a>?</p></div>';
126
+ } else {
127
+ // start the party!
128
+ global $cms_tpv_view;
129
+ ?>
130
+
131
+ <ul class="cms-tpv-subsubsub">
132
+ <li><a id="cms_tvp_view_all" class="<?php echo ($cms_tpv_view=="all") ? "current" : "" ?>" href="<?php echo CMS_TPV_PAGE_FILE ?>&amp;cms_tpv_view=all"><?php _e("All", 'cms-tree-page-view') ?></a> |</li>
133
+ <li><a id="cms_tvp_view_public" class="<?php echo ($cms_tpv_view=="public") ? "current" : "" ?>" href="<?php echo CMS_TPV_PAGE_FILE ?>&amp;cms_tpv_view=public"><?php _e("Public", 'cms-tree-page-view') ?></a></li>
134
+
135
+ <li><a href="#" id="cms_tpv_open_all"><?php _e("Expand", 'cms-tree-page-view') ?></a> |</li>
136
+ <li><a href="#" id="cms_tpv_close_all"><?php _e("Collapse", 'cms-tree-page-view') ?></a></li>
137
+
138
+ <li>
139
+ <form id="cms_tree_view_search_form">
140
+ <input type="text" name="search" id="cms_tree_view_search" />
141
+ <input type="submit" id="cms_tree_view_search_submit" value="<?php _e("Search", 'cms-tree-page-view') ?>" />
142
+ <span id="cms_tree_view_search_form_working"><?php _e("Searching...", 'cms-tree-page-view') ?></span>
143
+ </form>
144
+ </li>
145
+ </ul>
146
+
147
+ <div class="" id="cms_tpv_working"><?php _e("Loading...", 'cms-tree-page-view') ?></div>
148
+
149
+ <div class="updated below-h2 hidden" id="cms_tpv_search_no_hits"><p><?php _e("Search: no pages found", 'cms-tree-page-view') ?></p></div>
150
+
151
+ <div id="cms_tpv_container" class="tree-default"><?php _e("Loading tree", 'cms-tree-page-view') ?></div>
152
+ <div style="clear: both;"></div>
153
+
154
+ <?php
155
+ }
156
+ } // func
157
+
158
+
159
+ /**
160
+ * Pages page
161
+ * A page with the tree. Good stuff.
162
+ */
163
+ function cms_tpv_pages_page() {
164
+ ?>
165
+ <div class="wrap">
166
+
167
+ <h2><?php echo CMS_TPV_NAME ?></h2>
168
+
169
+ <?php
170
+ cms_tpv_print_common_tree_stuff();
171
+ ?>
172
+
173
+ </div>
174
+ <?php
175
+ }
176
+
177
+ /**
178
+ * Stripped down code from get_pages. Modified to get drafts and some other stuff too.
179
+ *
180
+ * @todo: cache, check permissions for private pages
181
+ */
182
+ function cms_tpv_get_pages($args = null) {
183
+
184
+ global $wpdb;
185
+
186
+ $defaults = array(
187
+ "parent" => -1,
188
+ "view" => "all" // all | public
189
+ );
190
+ $r = wp_parse_args( $args, $defaults );
191
+ extract($r, EXTR_SKIP);
192
+
193
+ $where = "";
194
+ if ($parent >= 0) {
195
+ $where = $wpdb->prepare(' AND post_parent = %d ', $parent);
196
+ }
197
+
198
+ $whereView = "";
199
+ if ($view == "all") {
200
+ } else {
201
+ // list of statuses:
202
+ // http://wordpress.org/support/topic/314325
203
+ $whereView = " AND ( post_status NOT IN ('pending', 'private', 'future', 'draft') ) ";
204
+ }
205
+
206
+ $where_post_type = $wpdb->prepare( "post_type = '%s' AND post_status <> '%s'", "page", "trash");
207
+ $query = "SELECT * FROM $wpdb->posts WHERE ($where_post_type) $where $whereView";
208
+ $query .= " ORDER BY menu_order ASC, post_title ASC" ;
209
+ #echo $query;
210
+ $pages = $wpdb->get_results($query);
211
+
212
+ return $pages;
213
+
214
+ }
215
+
216
+
217
+
218
+
219
+ /**
220
+ * Output JSON for the children of a node
221
+ * $arrOpenChilds = array with id of pages to open children on
222
+ */
223
+ function cms_tpv_print_childs($pageID, $view = "all", $arrOpenChilds = null) {
224
+
225
+ $arrPages = cms_tpv_get_pages("parent=$pageID&view=$view");
226
+ if ($arrPages) {
227
+ ?>[<?php
228
+ for ($i=0, $pagesCount = sizeof($arrPages); $i<$pagesCount; $i++) {
229
+ $onePage = $arrPages[$i];
230
+ $editLink = get_edit_post_link($onePage->ID, 'display');
231
+ $content = wp_specialchars($onePage->post_content);
232
+ $content = str_replace(array("\n","\r"), "", $content);
233
+ $hasChildren = false;
234
+ $arrChildPages = cms_tpv_get_pages("parent={$onePage->ID}&view=$view");
235
+
236
+ if ($arrChildPages) {
237
+ $hasChildren = true;
238
+ }
239
+ // if no children, output no state
240
+ $strState = '"state": "closed",';
241
+ if (!$hasChildren) {
242
+ $strState = '';
243
+ }
244
+
245
+ // type of node
246
+ $rel = $onePage->post_status;
247
+ if ($onePage->post_password) {
248
+ $rel = "password";
249
+ }
250
+
251
+ $title = get_the_title($onePage->ID); // so hooks and stuff will do their work
252
+ if (empty($title)) {
253
+ $title = __("<Untitled page>", 'cms-tree-page-view');
254
+ }
255
+ $title = wp_specialchars($title);
256
+ ?>
257
+ {
258
+ "data": {
259
+ "title": "<?php echo $title ?>",
260
+ "attributes": {
261
+ "href": "<?php echo $editLink ?>"
262
+ }
263
+ },
264
+ <?php echo $strState ?>
265
+ "attributes": {
266
+ "id": "cms-tpv-<?php echo $onePage->ID ?>",
267
+ "rel": "<?php echo $rel ?>",
268
+ "childCount": <?php echo sizeof($arrChildPages) ?>,
269
+ "title": "<?php _e("Click to edit. Drag to move.", 'cms-tree-page-view') ?>",
270
+ "permalink": "<?php echo get_permalink($onePage->ID) ?>"
271
+ }
272
+ <?php
273
+ // if id is in $arrOpenChilds then also output children on this one
274
+ if ($hasChildren && isset($arrOpenChilds) && in_array($onePage->ID, $arrOpenChilds)) {
275
+ ?>, "children": <?php
276
+ cms_tpv_print_childs($onePage->ID, $view, $arrOpenChilds);
277
+ ?><?php
278
+ }
279
+ ?>
280
+
281
+ }
282
+ <?php
283
+ // no comma for last page
284
+ if ($i < $pagesCount-1) {
285
+ ?>,<?php
286
+ }
287
+ }
288
+ ?>]<?php
289
+ }
290
+ }
291
+
292
+ // Act on AJAX-call
293
+ function cms_tpv_get_childs() {
294
+
295
+ $action = $_GET["action"];
296
+ $view = $_GET["view"]; // all | public
297
+ $search = trim($_GET["search"]); // exits if we're doing a search
298
+ if ($action) {
299
+
300
+ if ($search) {
301
+
302
+ // find all pages that contains $search
303
+ // collect all post_parent
304
+ // for each parent id traverse up until post_parent is 0, saving all ids on the way
305
+
306
+ // what to search: since all we see in the GUI is the title, just search that
307
+ global $wpdb;
308
+ $sqlsearch = "%{$search}%";
309
+ // fells bad to leave out the "'" in the query, but prepare seems to add it..??
310
+ $sql = $wpdb->prepare("SELECT id, post_parent FROM $wpdb->posts WHERE post_type = 'page' AND post_title LIKE %s", $sqlsearch);
311
+ $hits = $wpdb->get_results($sql);
312
+ $arrNodesToOpen = array();
313
+ foreach ($hits as $oneHit) {
314
+ $arrNodesToOpen[] = $oneHit->post_parent;
315
+ }
316
+
317
+ $arrNodesToOpen = array_unique($arrNodesToOpen);
318
+ $arrNodesToOpen2 = array();
319
+ // find all parents to the arrnodestopen
320
+ foreach ($arrNodesToOpen as $oneNode) {
321
+ if ($oneNode > 0) {
322
+ // not at top so check it out
323
+ $parentNodeID = $oneNode;
324
+ while ($parentNodeID != 0) {
325
+ $hits = $wpdb->get_results($sql);
326
+ $sql = "SELECT id, post_parent FROM $wpdb->posts WHERE id = $parentNodeID";
327
+ $row = $wpdb->get_row($sql);
328
+ $parentNodeID = $row->post_parent;
329
+ $arrNodesToOpen2[] = $parentNodeID;
330
+ }
331
+ }
332
+ }
333
+
334
+ $arrNodesToOpen = array_merge($arrNodesToOpen, $arrNodesToOpen2);
335
+ $sReturn = "";
336
+ foreach ($arrNodesToOpen as $oneNodeID) {
337
+ $sReturn .= "cms-tpv-{$oneNodeID},";
338
+ }
339
+ $sReturn = preg_replace("/,$/", "", $sReturn);
340
+
341
+ if ($sReturn) {
342
+ echo $sReturn;
343
+ } else {
344
+ // if no hits
345
+ echo 0;
346
+ }
347
+
348
+ exit;
349
+
350
+ } else {
351
+ $id = $_GET["id"];
352
+ $id = (int) str_replace("cms-tpv-", "", $id);
353
+
354
+ $jstree_open = array();
355
+ if ( isset( $_COOKIE["jstree_open"] ) ) {
356
+ $jstree_open = $_COOKIE["jstree_open"]; // like this: [jstree_open] => cms-tpv-1282,cms-tpv-1284,cms-tpv-3
357
+ $jstree_open = explode( ",", $jstree_open );
358
+ for( $i=0; $i<sizeof( $jstree_open ); $i++ ) {
359
+ $jstree_open[$i] = (int) str_replace("cms-tpv-", "", $jstree_open[$i]);
360
+ }
361
+ }
362
+
363
+ cms_tpv_print_childs($id, $view, $jstree_open);
364
+ exit;
365
+ }
366
+ }
367
+
368
+ exit;
369
+ }
370
+
371
+ function cms_tpv_add_page() {
372
+ global $wpdb;
373
+
374
+ /*
375
+ (
376
+ [action] => cms_tpv_add_page
377
+ [pageID] => cms-tpv-1318
378
+ type
379
+ )
380
+ */
381
+ $type = $_POST["type"];
382
+ $pageID = $_POST["pageID"];
383
+ $pageID = str_replace("cms-tpv-", "", $pageID);
384
+ $page_title = trim($_POST["page_title"]);
385
+ if (!$page_title) { $page_title = __("New page", 'cms-tree-page-view'); }
386
+
387
+ $ref_post = get_post($pageID);
388
+
389
+ if ("after" == $type) {
390
+
391
+ /*
392
+ add page under/below ref_post
393
+ */
394
+
395
+ // update menu_order of all pages below our page
396
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+2 WHERE post_parent = %d AND menu_order >= %d AND id <> %d ", $ref_post->post_parent, $ref_post->menu_order, $ref_post->ID ) );
397
+
398
+ // create a new page and then goto it
399
+ $post_new = array();
400
+ $post_new["menu_order"] = $ref_post->menu_order+1;
401
+ $post_new["post_parent"] = $ref_post->post_parent;
402
+ $post_new["post_type"] = "page";
403
+ $post_new["post_status"] = "draft";
404
+ $post_new["post_title"] = $page_title;
405
+ $post_new["post_content"] = "";
406
+ $newPostID = wp_insert_post($post_new);
407
+
408
+ } else if ( "inside" == $type ) {
409
+
410
+ /*
411
+ add page inside ref_post
412
+ */
413
+
414
+ // update menu_order, so our new post is the only one with order 0
415
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+1 WHERE post_parent = %d", $ref_post->ID) );
416
+
417
+ $post_new = array();
418
+ $post_new["menu_order"] = 0;
419
+ $post_new["post_parent"] = $ref_post->ID;
420
+ $post_new["post_type"] = "page";
421
+ $post_new["post_status"] = "draft";
422
+ $post_new["post_title"] = $page_title;
423
+ $post_new["post_content"] = "";
424
+ $newPostID = wp_insert_post($post_new);
425
+
426
+ }
427
+
428
+ if ($newPostID) {
429
+ // return editlink for the newly created page
430
+ $editLink = get_edit_post_link($newPostID, '');
431
+ echo $editLink;
432
+ } else {
433
+ // fail, tell js
434
+ echo "0";
435
+ }
436
+
437
+
438
+ exit;
439
+ }
440
+
441
+
442
+ // AJAX: perform move of article
443
+ function cms_tpv_move_page() {
444
+ /*
445
+ the node that was moved,
446
+ the reference node in the move,
447
+ the new position relative to the reference node (one of "before", "after" or "inside"),
448
+ inside = man placerar den under en sida som inte har några barn?
449
+ */
450
+
451
+ global $wpdb;
452
+
453
+ $node_id = $_POST["node_id"]; // the node that was moved
454
+ $ref_node_id = $_POST["ref_node_id"];
455
+ $type = $_POST["type"];
456
+
457
+ $node_id = str_replace("cms-tpv-", "", $node_id);
458
+ $ref_node_id = str_replace("cms-tpv-", "", $ref_node_id);
459
+
460
+ if ($node_id && $ref_node_id) {
461
+ #echo "\nnode_id: $node_id";
462
+ #echo "\ntype: $type";
463
+
464
+ $post_node = get_post($node_id);
465
+ $post_ref_node = get_post($ref_node_id);
466
+
467
+ if ( "inside" == $type ) {
468
+
469
+ // post_node is moved inside ref_post_node
470
+ // add ref_post_node as parent to post_node and set post_nodes menu_order to 0
471
+ $post_to_save = array(
472
+ "ID" => $post_node->ID,
473
+ "menu_order" => 0,
474
+ "post_parent" => $post_ref_node->ID
475
+ );
476
+ wp_update_post( $post_to_save );
477
+
478
+ echo "did inside";
479
+
480
+ } elseif ( "before" == $type ) {
481
+
482
+ // post_node is placed before ref_post_node
483
+ // @todo: check how this works with revisions
484
+
485
+ // update menu_order of all pages with a meny order more than or equal ref_node_post and with the same parent as ref_node_post
486
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+1 WHERE post_parent = %d", $post_ref_node->post_parent ) );
487
+
488
+ // update menu_order of $post_node to the menu_order that ref_post_node had, and update post_parent to the same as ref_post
489
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = %d, post_parent = %d WHERE ID = %d", $post_ref_node->menu_order, $post_ref_node->post_parent, $post_node->ID ) );
490
+
491
+ echo "did before";
492
+
493
+ } elseif ( "after" == $type ) {
494
+
495
+ // post_node is placed after ref_post_node
496
+
497
+ // update menu_order of all posts with the same parent ref_post_node and with a menu_order of the same as ref_post_node, but do not include ref_post_node
498
+ // +2 since multiple can have same menu order and we want our moved post to have a unique "spot"
499
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+2 WHERE post_parent = %d AND menu_order >= %d AND id <> %d ", $post_ref_node->post_parent, $post_ref_node->menu_order, $post_ref_node->ID ) );
500
+
501
+ // update menu_order of post_node to the same that ref_post_node_had+1
502
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = %d, post_parent = %d WHERE ID = %d", $post_ref_node->menu_order+1, $post_ref_node->post_parent, $post_node->ID ) );
503
+
504
+ echo "did after";
505
+ }
506
+
507
+ #echo "ok"; // I'm done here!
508
+
509
+
510
+ } else {
511
+ // error
512
+
513
+ }
514
+
515
+ exit;
516
+ }
517
+
518
+ function bonny_d($var) {
519
+ echo "<pre>";
520
+ print_r($var);
521
+ echo "</pre>";
522
+ }
523
+
524
+ /**
525
+ * Shortcode for videos
526
+ * Usage: [video source="<youtube url>" w=<width, default 480> h=<height, default 385>]
527
+ * Example: [video source="http://www.youtube.com/watch?v=QMGVWCPRNLI&feature=related" w=650]
528
+ */
529
+ function shortcode_pb_video($options) {
530
+
531
+ $defaults = array(
532
+ "source" => "",
533
+ "w" => 480,
534
+ "h" => 385
535
+ );
536
+ $options = polarbear_extend($defaults, $options);
537
+ $source = $options["source"];
538
+
539
+ // if opnly one option and no source, that first one is probably the source...
540
+ if (!$source && isset($options[0])) {
541
+ $source = $options[0];
542
+ }
543
+
544
+ $return = "";
545
+
546
+ /*
547
+ Array
548
+ (
549
+ [source] => http://www.youtube.com/watch?v=UiIxRxG39KY&feature=related
550
+ )
551
+ */
552
+ // check for youtube
553
+ if (strpos($source, "youtube.com/") !== false) {
554
+ preg_match("/v=([a-zA-Z0-9_]+)/", $source, $matches);
555
+ if (isset($matches[1])) {
556
+ $youtube_videoID = $matches[1];
557
+ #$return .= "<br>youtube_videoID: $youtube_videoID";
558
+ $return .= "<object width='{$options["w"]}' height='{$options["h"]}'><param name='movie' value='http://www.youtube.com/v/{$youtube_videoID}'></param><param name='allowFullScreen' value='true'></param><param name='allowscriptaccess' value='always'></param><embed src='http://www.youtube.com/v/{$youtube_videoID}' type='application/x-shockwave-flash' allowscriptaccess='always' allowfullscreen='true' width='{$options["w"]}' height='{$options["h"]}'></embed></object>";
559
+ }
560
+ }
561
+
562
+ return $return;
563
+ }
564
+
565
+ ?>
images/page_white_text.png ADDED
Binary file
index.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: CMS Tree Page View
4
+ Plugin URI: http://eskapism.se/code-playground/cms-tree-page-view/
5
+ Description: Adds a CMS-like tree view of all your pages, like the view often found in a page-focused CMS. By using the tree you can edit, view, add pages and even search pages (useful if you have many pages). And with drag and drop you can rearrange the order of your pages. Page management won't get any easier than this!
6
+ Version: 0.4.6
7
+ Author: Pär Thernström
8
+ Author URI: http://eskapism.se/
9
+ License: GPL2
10
+ */
11
+
12
+ /* Copyright 2010 Pär Thernström (email: par.thernstrom@gmail.com)
13
+
14
+ This program is free software; you can redistribute it and/or modify
15
+ it under the terms of the GNU General Public License, version 2, as
16
+ published by the Free Software Foundation.
17
+
18
+ This program is distributed in the hope that it will be useful,
19
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
+ GNU General Public License for more details.
22
+
23
+ You should have received a copy of the GNU General Public License
24
+ along with this program; if not, write to the Free Software
25
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
+ */
27
+
28
+
29
+ require("functions.php");
30
+
31
+ define( "CMS_TPV_URL", WP_PLUGIN_URL . '/cms-tree-page-view/');
32
+ define( "CMS_TPV_NAME", "CMS Tree Page View");
33
+ define( "CMS_TPV_VERSION", "0.4.5");
34
+ define( "CMS_TPV_PAGE_FILE", "edit-pages.php?page=cms-tpv-pages-page"); // this feels nasty
35
+
36
+ // on admin init: add styles and scripts
37
+ add_action( 'admin_init', 'cms_tpv_admin_init' );
38
+
39
+ // Hook onto dashboard and admin menu
40
+ add_action( 'wp_dashboard_setup', "cms_tpv_wp_dashboard_setup" );
41
+ add_action( 'admin_menu', "cms_tpv_admin_menu" );
42
+ add_action( 'admin_head', "cms_tpv_admin_head" );
43
+
44
+ // Ajax hooks
45
+ add_action('wp_ajax_cms_tpv_get_childs', 'cms_tpv_get_childs');
46
+ add_action('wp_ajax_cms_tpv_move_page', 'cms_tpv_move_page');
47
+ add_action('wp_ajax_cms_tpv_add_page', 'cms_tpv_add_page');
48
+
49
+ ?>
languages/cms-tree-page-view-be_BY.mo ADDED
Binary file
languages/cms-tree-page-view-be_BY.po ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Translation of the WordPress plugin by .
2
+ # Copyright (C) 2010
3
+ # This file is distributed under the same license as the package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
5
+ #
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: CTPV\n"
9
+ "Report-Msgid-Bugs-To: http://wordpress.org/tag/cms-tree-page-view\n"
10
+ "POT-Creation-Date: 2010-04-09 11:39+0000\n"
11
+ "PO-Revision-Date: 2010-04-15 23:43+0300\n"
12
+ "Last-Translator: FatCow <zhr@tut.by>\n"
13
+ "Language-Team: Marcis G. <by.marcis@gmail.com>\n"
14
+ "MIME-Version: 1.0\n"
15
+ "Content-Type: text/plain; charset=utf-8\n"
16
+ "Content-Transfer-Encoding: 8bit\n"
17
+ "X-Poedit-Language: Belarusian\n"
18
+ "X-Poedit-Country: BELARUS\n"
19
+ "X-Poedit-SourceCharset: utf8\n"
20
+
21
+ #: functions.php:84
22
+ msgid "settings"
23
+ msgstr "налады"
24
+
25
+ #: functions.php:91
26
+ msgid "Show tree"
27
+ msgstr "Паказаць дрэва"
28
+
29
+ #: functions.php:95
30
+ msgid "on the dashboard"
31
+ msgstr "у панэлі кіравання"
32
+
33
+ #: functions.php:98
34
+ msgid "under the pages menu"
35
+ msgstr "па старонках меню"
36
+
37
+ #: functions.php:105
38
+ msgid "Save Changes"
39
+ msgstr "Захаваць змены"
40
+
41
+ #: functions.php:127
42
+ msgid "All"
43
+ msgstr "Усё"
44
+
45
+ #: functions.php:128
46
+ msgid "Public"
47
+ msgstr "Публічна"
48
+
49
+ #: functions.php:130
50
+ msgid "Expand"
51
+ msgstr "Разгарнуць"
52
+
53
+ #: functions.php:131
54
+ msgid "Collapse"
55
+ msgstr "Згарнуць"
56
+
57
+ #: functions.php:136
58
+ msgid "Search"
59
+ msgstr "Пошук"
60
+
61
+ #: functions.php:137
62
+ msgid "Searching..."
63
+ msgstr "Пошук..."
64
+
65
+ #: functions.php:142
66
+ msgid "Loading..."
67
+ msgstr "Загрузка..."
68
+
69
+ #: functions.php:144
70
+ msgid "Search: no pages found"
71
+ msgstr "Пошук: старонкі не знойдзены"
72
+
73
+ #: functions.php:146
74
+ msgid "Loading tree"
75
+ msgstr "Загрузка дрэва"
76
+
77
+ #: functions.php:248
78
+ msgid "<Untitled page>"
79
+ msgstr "<Безназоўная старонка>"
80
+
81
+ #: functions.php:264
82
+ msgid "Click to edit. Drag to move."
83
+ msgstr "Націсніце для рэдагавання. Цягніце для перасоўвання."
84
+
85
+ #: functions.php:380
86
+ msgid "New page"
87
+ msgstr "Новая старонка"
88
+
89
+ #: scripts/cms_tree_page_view.php:85
90
+ #: scripts/cms_tree_page_view.php:102
91
+ msgid "Enter title of new page"
92
+ msgstr "Увядзіце назву новай старонкі"
93
+
94
+ #: scripts/cms_tree_page_view.php:283
95
+ msgid "child pages"
96
+ msgstr "даччыныя старонкі"
97
+
98
+ #: scripts/cms_tree_page_view.php:293
99
+ msgid "Edit page"
100
+ msgstr "Рэдагаваць старонку"
101
+
102
+ #: scripts/cms_tree_page_view.php:293
103
+ msgid "Edit"
104
+ msgstr "Рэдагаваць"
105
+
106
+ #: scripts/cms_tree_page_view.php:294
107
+ msgid "View page"
108
+ msgstr "Прагляд старонкі"
109
+
110
+ #: scripts/cms_tree_page_view.php:294
111
+ msgid "View"
112
+ msgstr "Прагляд"
113
+
114
+ #: scripts/cms_tree_page_view.php:296
115
+ msgid "Add page"
116
+ msgstr "Дадаць старонку"
117
+
118
+ #: scripts/cms_tree_page_view.php:297
119
+ msgid "Add new page after"
120
+ msgstr "Дадаць новую старонку пасля "
121
+
122
+ #: scripts/cms_tree_page_view.php:297
123
+ msgid "after"
124
+ msgstr "пасля"
125
+
126
+ #: scripts/cms_tree_page_view.php:298
127
+ msgid "Add new page inside"
128
+ msgstr "Дадаць новую старонку ўсярэдзіне"
129
+
130
+ #: scripts/cms_tree_page_view.php:298
131
+ msgid "inside"
132
+ msgstr "усярэдзіне"
133
+
languages/cms-tree-page-view-sv_SE.mo ADDED
Binary file
languages/cms-tree-page-view.pot ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Translation of the WordPress plugin by .
2
+ # Copyright (C) 2010
3
+ # This file is distributed under the same license as the package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
5
+ #
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: \n"
9
+ "Report-Msgid-Bugs-To: http://wordpress.org/tag/cms-tree-page-view\n"
10
+ "POT-Creation-Date: 2010-04-14 15:28+0000\n"
11
+ "PO-Revision-Date: 2010-04-14 17:41+0100\n"
12
+ "Last-Translator: Pär Thernström <par.thernstrom@gmail.com>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
+ "MIME-Version: 1.0\n"
15
+ "Content-Type: text/plain; charset=utf-8\n"
16
+ "Content-Transfer-Encoding: 8bit\n"
17
+
18
+ #: functions.php:84
19
+ msgid "settings"
20
+ msgstr ""
21
+
22
+ #: functions.php:91
23
+ msgid "Show tree"
24
+ msgstr ""
25
+
26
+ #: functions.php:95
27
+ msgid "on the dashboard"
28
+ msgstr ""
29
+
30
+ #: functions.php:98
31
+ msgid "under the pages menu"
32
+ msgstr ""
33
+
34
+ #: functions.php:105
35
+ msgid "Save Changes"
36
+ msgstr ""
37
+
38
+ #: functions.php:127
39
+ msgid "All"
40
+ msgstr ""
41
+
42
+ #: functions.php:128
43
+ msgid "Public"
44
+ msgstr ""
45
+
46
+ #: functions.php:130
47
+ msgid "Expand"
48
+ msgstr ""
49
+
50
+ #: functions.php:131
51
+ msgid "Collapse"
52
+ msgstr ""
53
+
54
+ #: functions.php:136
55
+ msgid "Search"
56
+ msgstr ""
57
+
58
+ #: functions.php:137
59
+ msgid "Searching..."
60
+ msgstr ""
61
+
62
+ #: functions.php:142
63
+ msgid "Loading..."
64
+ msgstr ""
65
+
66
+ #: functions.php:144
67
+ msgid "Search: no pages found"
68
+ msgstr ""
69
+
70
+ #: functions.php:146
71
+ msgid "Loading tree"
72
+ msgstr ""
73
+
74
+ #: functions.php:248
75
+ msgid "<Untitled page>"
76
+ msgstr ""
77
+
78
+ #: functions.php:264
79
+ msgid "Click to edit. Drag to move."
80
+ msgstr ""
81
+
82
+ #: functions.php:380
83
+ msgid "New page"
84
+ msgstr ""
85
+
86
+ #: scripts/cms_tree_page_view.php:85
87
+ #: scripts/cms_tree_page_view.php:102
88
+ msgid "Enter title of new page"
89
+ msgstr ""
90
+
91
+ #: scripts/cms_tree_page_view.php:283
92
+ msgid "child pages"
93
+ msgstr ""
94
+
95
+ #: scripts/cms_tree_page_view.php:293
96
+ msgid "Edit page"
97
+ msgstr ""
98
+
99
+ #: scripts/cms_tree_page_view.php:293
100
+ msgid "Edit"
101
+ msgstr ""
102
+
103
+ #: scripts/cms_tree_page_view.php:294
104
+ msgid "View page"
105
+ msgstr ""
106
+
107
+ #: scripts/cms_tree_page_view.php:294
108
+ msgid "View"
109
+ msgstr ""
110
+
111
+ #: scripts/cms_tree_page_view.php:296
112
+ msgid "Add page"
113
+ msgstr ""
114
+
115
+ #: scripts/cms_tree_page_view.php:297
116
+ msgid "Add new page after"
117
+ msgstr ""
118
+
119
+ #: scripts/cms_tree_page_view.php:297
120
+ msgid "after"
121
+ msgstr ""
122
+
123
+ #: scripts/cms_tree_page_view.php:298
124
+ msgid "Add new page inside"
125
+ msgstr ""
126
+
127
+ #: scripts/cms_tree_page_view.php:298
128
+ msgid "inside"
129
+ msgstr ""
130
+
readme.txt ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Plugin Name ===
2
+ Contributors: eskapism
3
+ Tags: page, pages, tree, cms, dashboard, overview, drag-and-drop, rearrange, management, manage
4
+ Requires at least: 2.9.2
5
+ Tested up to: 2.9.2
6
+ Stable tag: trunk
7
+
8
+ Adds a CMS-like tree overview of all your pages. Edit, view, add pages, search pages, and drag and drop to rearrange the order of your pages.
9
+
10
+ == Description ==
11
+
12
+ This plugin adds a CMS-like tree overview of all your pages to WordPress - like the view often found in a page-focused CMS.
13
+ Within this page tree you can edit pages, view pages, add pages, search pages, and drag and drop pages to rearrange the order.
14
+
15
+ Page management won't get any easier than this!
16
+
17
+ #### Features and highlights:
18
+
19
+ * drag and drop to rearrange your pages
20
+ * add pages after or inside a page
21
+ * edit pages
22
+ * view pages
23
+ * search pages
24
+
25
+ #### Screencast
26
+ See the plugin in action with this short screencast:
27
+ [youtube http://www.youtube.com/watch?v=H4BGomLi_FU]
28
+
29
+ == Installation ==
30
+
31
+ 1. Upload the folder "cms-tree-page-view" to "/wp-content/plugins/"
32
+ 1. Activate the plugin through the "Plugins" menu in WordPress
33
+ 1. Done!
34
+
35
+ Now the tree with the pages will be visible both on the dashboard and in the menu under pages.
36
+
37
+ == Screenshots ==
38
+
39
+ 1. The page tree in action
40
+ 2. Edit, view and add pages (choices visible upon mouse over).
41
+ 3. Search pages.
42
+ 4. Drag-and-drop to rearrange/change the order of the pages.
43
+ 5. The tree is also available on the dashboard and therefore available immediately after you login.
44
+
45
+ == Changelog ==
46
+
47
+ = 0.4.6 =
48
+ - could get database error because post_content had no default value
49
+ - removed usage of console.log and one alert. ouch!
50
+ - when adding page inside, several posts could get menu_order = 0, which led to sorting problems
51
+
52
+ = 0.4.5 =
53
+ - added Belorussian translation by [Marcis G.](http://pc.de/)
54
+ - settings page did not check checkboxes by default
55
+ - tree removed from dashboard due some problems with event bubbling (will be re-added later when problem is fixed)
56
+
57
+ = 0.4.4 =
58
+ - translation now works in javascript (forgot to use load_plugin_textdomain)
59
+ - added swedish translation by Måns Jonasson
60
+
61
+ = 0.4.3 =
62
+ - forgot the domain for _e at some places
63
+
64
+ = 0.4.2 =
65
+ - added .pot-file
66
+
67
+ = 0.4.1 =
68
+ - more prepare for translation
69
+ - fixed some <? into <?php
70
+
71
+ = 0.4 =
72
+ - uses strict json (fix for jquery 1.4)
73
+ - pages with no title now show "untitled" instead of just disappearing
74
+ - uses get_the_title instead of getting the title direct from the db, making plugins such as qtranslate work
75
+ - preparing for translation, using __ and _e
76
+
77
+ = 0.3 =
78
+ * all | public: works on the dasboard
79
+ * all | public: are now loaded using ajax. no more reloads!
80
+ * added options page so you can choose where to show the tree (i.e. the dasboard or under "pages"...or both, of course!). only available for admins.
81
+ * capability "edit_pages" required to view the tree
82
+
83
+ = 0.2 =
84
+ * Possible fix for Fluency Admin
85
+
86
+ = 0.1a =
87
+ * First public version.
screenshot-1.png ADDED
Binary file
screenshot-2.png ADDED
Binary file
screenshot-3.png ADDED
Binary file
screenshot-4.png ADDED
Binary file
screenshot-5.png ADDED
Binary file
scripts/cms_tree_page_view.php ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $wp_abspath = $_GET["wp-abspath"];
4
+ define('WP_USE_THEMES', false);
5
+ require($wp_abspath.'/wp-blog-header.php');
6
+ load_plugin_textdomain('cms-tree-page-view', WP_CONTENT_DIR . "/plugins/languages", "/cms-tree-page-view/languages");
7
+
8
+ ?>
9
+
10
+ // Case Insensitive :contains()
11
+ // Source: http://ericphan.info/blog/2009/3/4/jquery-13-case-insensitive-contains.html
12
+ jQuery.extend(jQuery.expr[":"], {
13
+ "containsNC": function(elem, i, match, array) {
14
+ return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
15
+ }
16
+ });
17
+
18
+ // check if tree is beging dragged
19
+ function cms_tpv_is_dragging() {
20
+ return (jQuery("#jstree-dragged").length == 1) ? true : false;
21
+ }
22
+
23
+ // mouse over, show actions
24
+ jQuery(".tree li a").live("mouseover", function() {
25
+ $t = jQuery(this);
26
+ $actions = $t.find(".cms_tpv_action_view, .cms_tpv_action_edit, .cms_tpv_action_add_page, .cms_tpv_action_add_page_after, .cms_tpv_action_add_page_inside");
27
+ if (cms_tpv_is_dragging() == false) {
28
+ $actions.show();
29
+ // remove possible timeoutID
30
+ /*
31
+ var timeoutID = $t.data("timeoutID");
32
+ if (timeoutID) {
33
+ clearTimeout(timeoutID);
34
+ $t.data("timeoutID", null);
35
+ }
36
+ */
37
+ }
38
+ });
39
+ // ..and hide them again
40
+ // @todo: hide after a short delay. fitts law stuff
41
+ jQuery(".tree li a").live("mouseout", function() {
42
+ $t = jQuery(this);
43
+ $actions = $t.find(".cms_tpv_action_view, .cms_tpv_action_edit, .cms_tpv_action_add_page, .cms_tpv_action_add_page_after, .cms_tpv_action_add_page_inside");
44
+ $actions.hide();
45
+ /*
46
+ var func = test($actions);
47
+ var timeoutID = setTimeout(func, 500);
48
+ $t.data("timeoutID", timeoutID);
49
+ */
50
+ });
51
+
52
+
53
+ jQuery(".tree li .cms_tpv_action_view").live("mouseover", function() {
54
+ return true;
55
+ });
56
+ jQuery(".tree li .cms_tpv_action_view").live("click", function() {
57
+ return true;
58
+ });
59
+
60
+
61
+
62
+ // go to page on click
63
+ jQuery(".tree li a .cms_tpv_action_view").live("click", function() {
64
+ var $li = jQuery(this).closest("li");
65
+ var permalink = $li.attr("permalink");
66
+ if (permalink) {
67
+ document.location = permalink;
68
+ }
69
+ return false;
70
+ });
71
+ // edit page on click
72
+ jQuery(".tree li a .cms_tpv_action_edit").live("click", function() {
73
+ var $a = jQuery(this).closest("a");
74
+ var editlink = $a.attr("href");
75
+ if (editlink) {
76
+ document.location = editlink;
77
+ }
78
+ return false;
79
+ });
80
+
81
+ // add page after
82
+ jQuery(".tree li a .cms_tpv_action_add_page_after").live("click", function() {
83
+ var new_page_title = prompt("<?php _e("Enter title of new page", 'cms-tree-page-view') ?>", "");
84
+ if (new_page_title) {
85
+ var pageID = jQuery(this).closest("li").attr("id");
86
+ jQuery.post(ajaxurl, {
87
+ action: "cms_tpv_add_page",
88
+ pageID: pageID,
89
+ type: "after",
90
+ page_title: new_page_title
91
+ }, function(data, textStatus) {
92
+ document.location = data;
93
+ });
94
+ }
95
+ return false;
96
+ });
97
+
98
+ // add page inside
99
+ jQuery(".tree li a .cms_tpv_action_add_page_inside").live("click", function() {
100
+ var new_page_title = prompt("<?php _e("Enter title of new page", 'cms-tree-page-view') ?>", "");
101
+ if (new_page_title) {
102
+ var pageID = jQuery(this).closest("li").attr("id");
103
+ jQuery.post(ajaxurl, {
104
+ action: "cms_tpv_add_page",
105
+ pageID: pageID,
106
+ type: "inside",
107
+ page_title: new_page_title
108
+ }, function(data, textStatus) {
109
+ document.location = data;
110
+ });
111
+ }
112
+ return false;
113
+ });
114
+
115
+
116
+ // hide action links on drag
117
+ jQuery.tree.drag_start = function() {
118
+ jQuery(".cms_tpv_action_view, .cms_tpv_action_edit, .cms_tpv_action_add_page, .cms_tpv_action_add_page_after, .cms_tpv_action_add_page_inside").hide();
119
+ }
120
+
121
+ var cms_tpv_tree;
122
+ jQuery(function($) {
123
+
124
+ var treeOptions = {
125
+ data: {
126
+ async: true,
127
+ type: "json",
128
+ opts: {
129
+ url: ajaxurl + CMS_TPV_AJAXURL + CMS_TPV_VIEW
130
+ }
131
+ },
132
+ ui: {
133
+ theme_path: CMS_TPV_URL + "scripts/themes/default/style.css", // this setting seems a bit bananas. be sure to check that it works when jstree 1.0 is released
134
+ theme_name: "default",
135
+ animation: 200
136
+ },
137
+ plugins: {
138
+ cookie: {
139
+ prefix: "jstree_",
140
+ types : {
141
+ selected: false
142
+ }
143
+ }
144
+ },
145
+ types: {
146
+ "default": {
147
+ icon: {
148
+ image: CMS_TPV_URL + "images/page_white_text.png"
149
+ }
150
+ },
151
+ "draft": {
152
+ },
153
+ "pending": {
154
+ },
155
+ "password": {
156
+ },
157
+ "future": {
158
+ }
159
+ },
160
+ callback: {
161
+ // data = array of objects
162
+ ondata: function(DATA, TREE_OBJ) {
163
+
164
+ jQuery.each(DATA, function(index, value) {
165
+
166
+ // add number of children and page type and span-actions
167
+ cms_tree_page_view_add_spans_to_tree_ondata(DATA[index]);
168
+
169
+ });
170
+ return DATA;
171
+ },
172
+
173
+ // select = go and edit
174
+ // hm..or not...let me think about this... use actions-popup for now
175
+ // @todo: check if jquery live's click and dblclick can make 1 click = edit, 2 clicks = open
176
+ // @todo: currently this swallows to many clicks (on links outside the tree for example).
177
+ // newer version of jquery + next version of jstree is supposed to fix this
178
+ onselect: function(NODE, TREE_OBJ) {
179
+ $selected = $(cms_tpv_tree.selected);
180
+
181
+ // jquery < 1.4 has problems
182
+ //if (parseFloat(jQuery.fn.jquery)>=1.4) {
183
+ // @todo: 1.4 gives us problems too... fix later when jstree v1 is released
184
+ // live on the action-links does not work here...
185
+ //return true;
186
+ //} else {
187
+ var editLink = $selected.find("a").attr("href");
188
+ document.location = editLink;
189
+ //}
190
+ },
191
+
192
+ onmove: function(NODE, REF_NODE, TYPE, TREE_OBJ, RB) {
193
+ // get ids of our friends
194
+ var node_id = $( NODE ).attr( "id" );
195
+ ref_node_id = $( REF_NODE ).attr( "id" );
196
+
197
+ // Update parent or menu order
198
+ $.post(ajaxurl, {
199
+ action: "cms_tpv_move_page",
200
+ "node_id": node_id,
201
+ "ref_node_id": ref_node_id,
202
+ type: TYPE
203
+ }, function(data, textStatus) {
204
+ });
205
+
206
+ },
207
+
208
+ onsearch: function(NODES, TREE_OBJ) {
209
+ // if empy nodes = no hits
210
+ if (NODES.length == 0) {
211
+ $("#cms_tpv_search_no_hits").show();
212
+ }
213
+ NODES.addClass("search");
214
+ $("#cms_tree_view_search_form_working").fadeOut("fast");
215
+ }
216
+
217
+ }
218
+ }
219
+
220
+ if ($("#cms_tpv_container").length == 1) {
221
+ $("#cms_tpv_container").tree(treeOptions);
222
+ cms_tpv_tree = jQuery.tree.reference("#cms_tpv_container");
223
+ }
224
+
225
+ jQuery("#cms_tree_view_search_form").submit(function() {
226
+ $("#cms_tpv_search_no_hits").hide();
227
+ var s = jQuery("#cms_tree_view_search").attr("value");
228
+ s = jQuery.trim( s );
229
+ // search, oh the mighty search!
230
+ if (s) {
231
+ $("#cms_tree_view_search_form_working").fadeIn("fast");
232
+ }
233
+ cms_tpv_tree.search(s, "containsNC");
234
+ return false;
235
+ });
236
+
237
+
238
+ // open/close links
239
+ jQuery("#cms_tpv_open_all").click(function() {
240
+ cms_tpv_tree.open_all();
241
+ return false;
242
+ });
243
+ jQuery("#cms_tpv_close_all").click(function() {
244
+ cms_tpv_tree.close_all();
245
+ return false;
246
+ });
247
+
248
+ // view all or public
249
+ jQuery("#cms_tvp_view_all").click(function() {
250
+ cms_tvp_set_view("all");
251
+ jQuery(this).addClass("current");
252
+ return false;
253
+ });
254
+ jQuery("#cms_tvp_view_public").click(function() {
255
+ cms_tvp_set_view("public");
256
+ jQuery(this).addClass("current");
257
+ return false;
258
+ });
259
+
260
+ function cms_tvp_set_view(view) {
261
+ jQuery("#cms_tpv_working").fadeIn("slow");
262
+ jQuery("#cms_tvp_view_all,#cms_tvp_view_public").removeClass("current");
263
+ cms_tpv_tree.settings.data.opts.url = ajaxurl + CMS_TPV_AJAXURL + view;
264
+ cms_tpv_tree.refresh();
265
+ jQuery("#cms_tpv_working").fadeOut("slow");
266
+ }
267
+
268
+
269
+ }); // end ondomready
270
+
271
+
272
+ /**
273
+ * Add type, children count and span-actions
274
+ * data is one DATA[index]
275
+ */
276
+ function cms_tree_page_view_add_spans_to_tree_ondata(data) {
277
+
278
+ var childCount = data.attributes.childCount;
279
+ if (childCount > 0) {
280
+ data.data.title += "<span title='" + childCount + " <?php _e("child pages", 'cms-tree-page-view') ?>" + "' class='child_count'>("+childCount+")</span>";
281
+ }
282
+
283
+ // add page type
284
+ var rel = data.attributes.rel;
285
+ if (rel != "publish") {
286
+ data.data.title = "<span class='post_type post_type_"+rel+"'>"+rel+"</span>" + data.data.title;
287
+ }
288
+
289
+ // add actions that are revealed on mouse over
290
+ data.data.title += " <span title='<?php _e("Edit page", 'cms-tree-page-view') ?>' class='cms_tpv_action_edit'><?php _e("Edit", 'cms-tree-page-view') ?></span>";
291
+ data.data.title += " <span title='<?php _e("View page", 'cms-tree-page-view') ?>' class='cms_tpv_action_view'><?php _e("View", 'cms-tree-page-view') ?></span>";
292
+
293
+ data.data.title += " <span class='cms_tpv_action_add_page'><?php _e("Add page", 'cms-tree-page-view') ?>:</span>";
294
+ data.data.title += " <span title='<?php _e("Add new page after", 'cms-tree-page-view') ?>' class='cms_tpv_action_add_page_after'><?php _e("after", 'cms-tree-page-view') ?></span> ";
295
+ data.data.title += " <span title='<?php _e("Add new page inside", 'cms-tree-page-view') ?>' class='cms_tpv_action_add_page_inside'><?php _e("inside", 'cms-tree-page-view') ?></span>";
296
+
297
+ // check if children exists. id they do: update their data too
298
+ // DATA[index][children] is an array that may exists. in that case we must do this on all kids to...
299
+ if (data.children) {
300
+ jQuery.each(data.children, function(index, value) {
301
+ cms_tree_page_view_add_spans_to_tree_ondata(data.children[index]);
302
+ });
303
+
304
+ }
305
+
306
+ return data;
307
+ }
scripts/jquery.cookie.js ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Cookie plugin
3
+ *
4
+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
5
+ * Dual licensed under the MIT and GPL licenses:
6
+ * http://www.opensource.org/licenses/mit-license.php
7
+ * http://www.gnu.org/licenses/gpl.html
8
+ *
9
+ */
10
+
11
+ /**
12
+ * Create a cookie with the given name and value and other optional parameters.
13
+ *
14
+ * @example $.cookie('the_cookie', 'the_value');
15
+ * @desc Set the value of a cookie.
16
+ * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
17
+ * @desc Create a cookie with all available options.
18
+ * @example $.cookie('the_cookie', 'the_value');
19
+ * @desc Create a session cookie.
20
+ * @example $.cookie('the_cookie', null);
21
+ * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
22
+ * used when the cookie was set.
23
+ *
24
+ * @param String name The name of the cookie.
25
+ * @param String value The value of the cookie.
26
+ * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
27
+ * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
28
+ * If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
29
+ * If set to null or omitted, the cookie will be a session cookie and will not be retained
30
+ * when the the browser exits.
31
+ * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
32
+ * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
33
+ * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
34
+ * require a secure protocol (like HTTPS).
35
+ * @type undefined
36
+ *
37
+ * @name $.cookie
38
+ * @cat Plugins/Cookie
39
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
40
+ */
41
+
42
+ /**
43
+ * Get the value of a cookie with the given name.
44
+ *
45
+ * @example $.cookie('the_cookie');
46
+ * @desc Get the value of a cookie.
47
+ *
48
+ * @param String name The name of the cookie.
49
+ * @return The value of the cookie.
50
+ * @type String
51
+ *
52
+ * @name $.cookie
53
+ * @cat Plugins/Cookie
54
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
55
+ */
56
+ jQuery.cookie = function(name, value, options) {
57
+ if (typeof value != 'undefined') { // name and value given, set cookie
58
+ options = options || {};
59
+ if (value === null) {
60
+ value = '';
61
+ options.expires = -1;
62
+ }
63
+ var expires = '';
64
+ if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
65
+ var date;
66
+ if (typeof options.expires == 'number') {
67
+ date = new Date();
68
+ date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
69
+ } else {
70
+ date = options.expires;
71
+ }
72
+ expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
73
+ }
74
+ // CAUTION: Needed to parenthesize options.path and options.domain
75
+ // in the following expressions, otherwise they evaluate to undefined
76
+ // in the packed version for some reason...
77
+ var path = options.path ? '; path=' + (options.path) : '';
78
+ var domain = options.domain ? '; domain=' + (options.domain) : '';
79
+ var secure = options.secure ? '; secure' : '';
80
+ document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
81
+ } else { // only name given, get cookie
82
+ var cookieValue = null;
83
+ if (document.cookie && document.cookie != '') {
84
+ var cookies = document.cookie.split(';');
85
+ for (var i = 0; i < cookies.length; i++) {
86
+ var cookie = jQuery.trim(cookies[i]);
87
+ // Does this cookie string begin with the name we want?
88
+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
89
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
90
+ break;
91
+ }
92
+ }
93
+ }
94
+ return cookieValue;
95
+ }
96
+ };
scripts/jquery.tree.js ADDED
@@ -0,0 +1,2064 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jsTree 0.9.9a
3
+ * http://jstree.com/
4
+ *
5
+ * Copyright (c) 2009 Ivan Bozhanov (vakata.com)
6
+ *
7
+ * Dual licensed under the MIT and GPL licenses:
8
+ * http://www.opensource.org/licenses/mit-license.php
9
+ * http://www.gnu.org/licenses/gpl.html
10
+ *
11
+ * Date: 2009-10-06
12
+ *
13
+ */
14
+
15
+ (function($) {
16
+ // jQuery plugin
17
+ $.tree = {
18
+ datastores : { },
19
+ plugins : { },
20
+ defaults : {
21
+ data : {
22
+ async : false, // Are async requests used to load open_branch contents
23
+ type : "html", // One of included datastores
24
+ opts : { method: "GET", url: false } // Options passed to datastore
25
+ },
26
+ selected : false, // FALSE or STRING or ARRAY
27
+ opened : [], // ARRAY OF INITIALLY OPENED NODES
28
+ languages : [], // ARRAY of string values (which will be used as CSS classes - so they must be valid)
29
+ ui : {
30
+ dots : true, // BOOL - dots or no dots
31
+ animation : 0, // INT - duration of open/close animations in miliseconds
32
+ scroll_spd : 4,
33
+ theme_path : false, // Path to the theme CSS file - if set to false and theme_name is not false - will lookup jstree-path-here/themes/theme-name-here/style.css
34
+ theme_name : "default",// if set to false no theme will be loaded
35
+ selected_parent_close : "select_parent", // false, "deselect", "select_parent"
36
+ selected_delete : "select_previous" // false, "select_previous"
37
+ },
38
+ types : {
39
+ "default" : {
40
+ clickable : true, // can be function
41
+ renameable : true, // can be function
42
+ deletable : true, // can be function
43
+ creatable : true, // can be function
44
+ draggable : true, // can be function
45
+ max_children : -1, // -1 - not set, 0 - no children, 1 - one child, etc // can be function
46
+ max_depth : -1, // -1 - not set, 0 - no children, 1 - one level of children, etc // can be function
47
+ valid_children : "all", // all, none, array of values // can be function
48
+ icon : {
49
+ image : false,
50
+ position : false
51
+ }
52
+ }
53
+ },
54
+ rules : {
55
+ multiple : false, // FALSE | CTRL | ON - multiple selection off/ with or without holding Ctrl
56
+ multitree : "none", // all, none, array of tree IDs to accept from
57
+ type_attr : "rel", // STRING attribute name (where is the type stored as string)
58
+ createat : "bottom", // STRING (top or bottom) new nodes get inserted at top or bottom
59
+ drag_copy : "ctrl", // FALSE | CTRL | ON - drag to copy off/ with or without holding Ctrl
60
+ drag_button : "left", // left, right or both
61
+ use_max_children : true,
62
+ use_max_depth : true,
63
+
64
+ max_children: -1,
65
+ max_depth : -1,
66
+ valid_children : "all"
67
+ },
68
+ lang : {
69
+ new_node : "New folder",
70
+ loading : "Loading ..."
71
+ },
72
+ callback : {
73
+ beforechange: function(NODE,TREE_OBJ) { return true },
74
+ beforeopen : function(NODE,TREE_OBJ) { return true },
75
+ beforeclose : function(NODE,TREE_OBJ) { return true },
76
+ beforemove : function(NODE,REF_NODE,TYPE,TREE_OBJ) { return true },
77
+ beforecreate: function(NODE,REF_NODE,TYPE,TREE_OBJ) { return true },
78
+ beforerename: function(NODE,LANG,TREE_OBJ) { return true },
79
+ beforedelete: function(NODE,TREE_OBJ) { return true },
80
+ beforedata : function(NODE,TREE_OBJ) { return { id : $(NODE).attr("id") || 0 } }, // PARAMETERS PASSED TO SERVER
81
+ ondata : function(DATA,TREE_OBJ) { return DATA; }, // modify data before parsing it
82
+ onparse : function(STR,TREE_OBJ) { return STR; }, // modify string before visualizing it
83
+ onhover : function(NODE,TREE_OBJ) { }, // node hovered
84
+ onselect : function(NODE,TREE_OBJ) { }, // node selected
85
+ ondeselect : function(NODE,TREE_OBJ) { }, // node deselected
86
+ onchange : function(NODE,TREE_OBJ) { }, // focus changed
87
+ onrename : function(NODE,TREE_OBJ,RB) { }, // node renamed
88
+ onmove : function(NODE,REF_NODE,TYPE,TREE_OBJ,RB) { }, // move completed
89
+ oncopy : function(NODE,REF_NODE,TYPE,TREE_OBJ,RB) { }, // copy completed
90
+ oncreate : function(NODE,REF_NODE,TYPE,TREE_OBJ,RB) { }, // node created
91
+ ondelete : function(NODE,TREE_OBJ,RB) { }, // node deleted
92
+ onopen : function(NODE,TREE_OBJ) { }, // node opened
93
+ onopen_all : function(TREE_OBJ) { }, // all nodes opened
94
+ onclose_all : function(TREE_OBJ) { }, // all nodes closed
95
+ onclose : function(NODE,TREE_OBJ) { }, // node closed
96
+ error : function(TEXT,TREE_OBJ) { }, // error occured
97
+ ondblclk : function(NODE,TREE_OBJ) { TREE_OBJ.toggle_branch.call(TREE_OBJ, NODE); TREE_OBJ.select_branch.call(TREE_OBJ, NODE); },
98
+ onrgtclk : function(NODE,TREE_OBJ,EV) { }, // right click - to prevent use: EV.preventDefault(); EV.stopPropagation(); return false
99
+ onload : function(TREE_OBJ) { },
100
+ oninit : function(TREE_OBJ) { },
101
+ onfocus : function(TREE_OBJ) { },
102
+ ondestroy : function(TREE_OBJ) { },
103
+ onsearch : function(NODES, TREE_OBJ) { NODES.addClass("search"); },
104
+ ondrop : function(NODE,REF_NODE,TYPE,TREE_OBJ) { },
105
+ check : function(RULE,NODE,VALUE,TREE_OBJ) { return VALUE; },
106
+ check_move : function(NODE,REF_NODE,TYPE,TREE_OBJ) { return true; }
107
+ },
108
+ plugins : { }
109
+ },
110
+
111
+ create : function () { return new tree_component(); },
112
+ focused : function () { return tree_component.inst[tree_component.focused]; },
113
+ reference : function (obj) {
114
+ var o = $(obj);
115
+ if(!o.size()) o = $("#" + obj);
116
+ if(!o.size()) return null;
117
+ o = (o.is(".tree")) ? o.attr("id") : o.parents(".tree:eq(0)").attr("id");
118
+ return tree_component.inst[o] || null;
119
+ },
120
+ rollback : function (data) {
121
+ for(var i in data) {
122
+ if(!data.hasOwnProperty(i)) continue;
123
+ var tmp = tree_component.inst[i];
124
+ var lock = !tmp.locked;
125
+
126
+ // if not locked - lock the tree
127
+ if(lock) tmp.lock(true);
128
+ // Cancel ongoing rename
129
+ tmp.inp = false;
130
+ tmp.container.html(data[i].html).find(".dragged").removeClass("dragged").end().find(".hover").removeClass("hover");
131
+
132
+ if(data[i].selected) {
133
+ tmp.selected = $("#" + data[i].selected);
134
+ tmp.selected_arr = [];
135
+ tmp.container
136
+ .find("a.clicked").each( function () {
137
+ tmp.selected_arr.push(tmp.get_node(this));
138
+ });
139
+ }
140
+ // if this function set the lock - unlock
141
+ if(lock) tmp.lock(false);
142
+
143
+ delete lock;
144
+ delete tmp;
145
+ }
146
+ },
147
+ drop_mode : function (opts) {
148
+ opts = $.extend(opts, { show : false, type : "default", str : "Foreign node" });
149
+ tree_component.drag_drop.foreign = true;
150
+ tree_component.drag_drop.isdown = true;
151
+ tree_component.drag_drop.moving = true;
152
+ tree_component.drag_drop.appended = false;
153
+ tree_component.drag_drop.f_type = opts.type;
154
+ tree_component.drag_drop.f_data = opts;
155
+
156
+
157
+ if(!opts.show) {
158
+ tree_component.drag_drop.drag_help = false;
159
+ tree_component.drag_drop.drag_node = false;
160
+ }
161
+ else {
162
+ tree_component.drag_drop.drag_help = $("<div id='jstree-dragged' class='tree tree-default'><ul><li class='last dragged foreign'><a href='#'><ins>&nbsp;</ins>" + opts.str + "</a></li></ul></div>");
163
+ tree_component.drag_drop.drag_node = tree_component.drag_drop.drag_help.find("li:eq(0)");
164
+ }
165
+ if($.tree.drag_start !== false) $.tree.drag_start.call(null, false);
166
+ },
167
+ drag_start : false,
168
+ drag : false,
169
+ drag_end : false
170
+ };
171
+ $.fn.tree = function (opts) {
172
+ return this.each(function() {
173
+ var conf = $.extend({},opts);
174
+ if(tree_component.inst && tree_component.inst[$(this).attr('id')]) tree_component.inst[$(this).attr('id')].destroy();
175
+ if(conf !== false) new tree_component().init(this, conf);
176
+ });
177
+ };
178
+
179
+ // core
180
+ function tree_component () {
181
+ return {
182
+ cntr : ++tree_component.cntr,
183
+ settings : $.extend({},$.tree.defaults),
184
+
185
+ init : function(elem, conf) {
186
+ var _this = this;
187
+ this.container = $(elem);
188
+ if(this.container.size == 0) return false;
189
+ tree_component.inst[this.cntr] = this;
190
+ if(!this.container.attr("id")) this.container.attr("id","jstree_" + this.cntr);
191
+ tree_component.inst[this.container.attr("id")] = tree_component.inst[this.cntr];
192
+ tree_component.focused = this.cntr;
193
+ this.settings = $.extend(true, {}, this.settings, conf);
194
+
195
+ // DEAL WITH LANGUAGE VERSIONS
196
+ if(this.settings.languages && this.settings.languages.length) {
197
+ this.current_lang = this.settings.languages[0];
198
+ var st = false;
199
+ var id = "#" + this.container.attr("id");
200
+ for(var ln = 0; ln < this.settings.languages.length; ln++) {
201
+ st = tree_component.add_css(id + " ." + this.settings.languages[ln]);
202
+ if(st !== false) st.style.display = (this.settings.languages[ln] == this.current_lang) ? "" : "none";
203
+ }
204
+ }
205
+ else this.current_lang = false;
206
+ // THEMES
207
+ this.container.addClass("tree");
208
+ if(this.settings.ui.theme_name !== false) {
209
+ if(this.settings.ui.theme_path === false) {
210
+ $("script").each(function () {
211
+ if(this.src.toString().match(/jquery\.tree.*?js$/)) { _this.settings.ui.theme_path = this.src.toString().replace(/jquery\.tree.*?js$/, "") + "themes/" + _this.settings.ui.theme_name + "/style.css"; return false; }
212
+ });
213
+ }
214
+ if(this.settings.ui.theme_path != "" && $.inArray(this.settings.ui.theme_path, tree_component.themes) == -1) {
215
+ tree_component.add_sheet({ url : this.settings.ui.theme_path });
216
+ tree_component.themes.push(this.settings.ui.theme_path);
217
+ }
218
+ this.container.addClass("tree-" + this.settings.ui.theme_name);
219
+ }
220
+ // TYPE ICONS
221
+ var type_icons = "";
222
+ for(var t in this.settings.types) {
223
+ if(!this.settings.types.hasOwnProperty(t)) continue;
224
+ if(!this.settings.types[t].icon) continue;
225
+ if( this.settings.types[t].icon.image || this.settings.types[t].icon.position) {
226
+ if(t == "default") type_icons += "#" + this.container.attr("id") + " li > a ins { ";
227
+ else type_icons += "#" + this.container.attr("id") + " li[rel=" + t + "] > a ins { ";
228
+ if(this.settings.types[t].icon.image) type_icons += " background-image:url(" + this.settings.types[t].icon.image + "); ";
229
+ if(this.settings.types[t].icon.position) type_icons += " background-position:" + this.settings.types[t].icon.position + "; ";
230
+ type_icons += "} ";
231
+ }
232
+ }
233
+ if(type_icons != "") tree_component.add_sheet({ str : type_icons });
234
+
235
+ if(this.settings.rules.multiple) this.selected_arr = [];
236
+ this.offset = false;
237
+ this.hovered = false;
238
+ this.locked = false;
239
+
240
+ if(tree_component.drag_drop.marker === false) tree_component.drag_drop.marker = $("<div>").attr({ id : "jstree-marker" }).hide().appendTo("body");
241
+ this.callback("oninit", [this]);
242
+ this.refresh();
243
+ this.attach_events();
244
+ this.focus();
245
+ },
246
+ refresh : function (obj) {
247
+ if(this.locked) return this.error("LOCKED");
248
+ var _this = this;
249
+ if(obj && !this.settings.data.async) obj = false;
250
+ this.is_partial_refresh = obj ? true : false;
251
+
252
+ // SAVE OPENED
253
+ this.opened = Array();
254
+ if(this.settings.opened != false) {
255
+ $.each(this.settings.opened, function (i, item) {
256
+ if(this.replace(/^#/,"").length > 0) { _this.opened.push("#" + this.replace(/^#/,"")); }
257
+ });
258
+ this.settings.opened = false;
259
+ }
260
+ else {
261
+ this.container.find("li.open").each(function (i) { if(this.id) { _this.opened.push("#" + this.id); } });
262
+ }
263
+
264
+ // SAVE SELECTED
265
+ if(this.selected) {
266
+ this.settings.selected = Array();
267
+ if(obj) {
268
+ $(obj).find("li:has(a.clicked)").each(function () {
269
+ if(this.id) _this.settings.selected.push("#" + this.id);
270
+ });
271
+ }
272
+ else {
273
+ if(this.selected_arr) {
274
+ $.each(this.selected_arr, function () {
275
+ if(this.attr("id")) _this.settings.selected.push("#" + this.attr("id"));
276
+ });
277
+ }
278
+ else {
279
+ if(this.selected.attr("id")) this.settings.selected.push("#" + this.selected.attr("id"));
280
+ }
281
+ }
282
+ }
283
+ else if(this.settings.selected !== false) {
284
+ var tmp = Array();
285
+ if((typeof this.settings.selected).toLowerCase() == "object") {
286
+ $.each(this.settings.selected, function () {
287
+ if(this.replace(/^#/,"").length > 0) tmp.push("#" + this.replace(/^#/,""));
288
+ });
289
+ }
290
+ else {
291
+ if(this.settings.selected.replace(/^#/,"").length > 0) tmp.push("#" + this.settings.selected.replace(/^#/,""));
292
+ }
293
+ this.settings.selected = tmp;
294
+ }
295
+
296
+ if(obj && this.settings.data.async) {
297
+ this.opened = Array();
298
+ obj = this.get_node(obj);
299
+ obj.find("li.open").each(function (i) { _this.opened.push("#" + this.id); });
300
+ if(obj.hasClass("open")) obj.removeClass("open").addClass("closed");
301
+ if(obj.hasClass("leaf")) obj.removeClass("leaf");
302
+ obj.children("ul:eq(0)").html("");
303
+ return this.open_branch(obj, true, function () { _this.reselect.apply(_this); });
304
+ }
305
+
306
+ var _this = this;
307
+ var _datastore = new $.tree.datastores[this.settings.data.type]();
308
+ if(this.container.children("ul").size() == 0) {
309
+ this.container.html("<ul class='ltr' style='direction:ltr;'><li class='last'><a class='loading' href='#'><ins>&nbsp;</ins>" + (this.settings.lang.loading || "Loading ...") + "</a></li></ul>");
310
+ }
311
+ _datastore.load(this.callback("beforedata",[false,this]),this,this.settings.data.opts,function(data) {
312
+ data = _this.callback("ondata",[data, _this]);
313
+ _datastore.parse(data,_this,_this.settings.data.opts,function(str) {
314
+ str = _this.callback("onparse", [str, _this]);
315
+ _this.container.empty().append($("<ul class='ltr'>").html(str));
316
+ _this.container.find("li:last-child").addClass("last").end().find("li:has(ul)").not(".open").addClass("closed");
317
+ _this.container.find("li").not(".open").not(".closed").addClass("leaf");
318
+ _this.reselect();
319
+ });
320
+ });
321
+ },
322
+ reselect : function (is_callback) {
323
+ var _this = this;
324
+
325
+ if(!is_callback) this.cl_count = 0;
326
+ else this.cl_count --;
327
+ // REOPEN BRANCHES
328
+ if(this.opened && this.opened.length) {
329
+ var opn = false;
330
+ for(var j = 0; this.opened && j < this.opened.length; j++) {
331
+ if(this.settings.data.async) {
332
+ var tmp = this.get_node(this.opened[j]);
333
+ if(tmp.size() && tmp.hasClass("closed") > 0) {
334
+ opn = true;
335
+ var tmp = this.opened[j].toString().replace('/','\\/');
336
+ delete this.opened[j];
337
+ this.open_branch(tmp, true, function () { _this.reselect.apply(_this, [true]); } );
338
+ this.cl_count ++;
339
+ }
340
+ }
341
+ else this.open_branch(this.opened[j], true);
342
+ }
343
+ if(this.settings.data.async && opn) return;
344
+ if(this.cl_count > 0) return;
345
+ delete this.opened;
346
+ }
347
+ if(this.cl_count > 0) return;
348
+
349
+ // DOTS and RIGHT TO LEFT
350
+ this.container.css("direction","ltr").children("ul:eq(0)").addClass("ltr");
351
+ if(this.settings.ui.dots == false) this.container.children("ul:eq(0)").addClass("no_dots");
352
+
353
+ // REPOSITION SCROLL
354
+ if(this.scrtop) {
355
+ this.container.scrollTop(_this.scrtop);
356
+ delete this.scrtop;
357
+ }
358
+ // RESELECT PREVIOUSLY SELECTED
359
+ if(this.settings.selected !== false) {
360
+ $.each(this.settings.selected, function (i) {
361
+ if(_this.is_partial_refresh) _this.select_branch($(_this.settings.selected[i].toString().replace('/','\\/'), _this.container), (_this.settings.rules.multiple !== false) );
362
+ else _this.select_branch($(_this.settings.selected[i].toString().replace('/','\\/'), _this.container), (_this.settings.rules.multiple !== false && i > 0) );
363
+ });
364
+ this.settings.selected = false;
365
+ }
366
+ this.callback("onload", [_this]);
367
+ },
368
+
369
+ get : function (obj, format, opts) {
370
+ if(!format) format = this.settings.data.type;
371
+ if(!opts) opts = this.settings.data.opts;
372
+ return new $.tree.datastores[format]().get(obj, this, opts);
373
+ },
374
+
375
+ attach_events : function () {
376
+ var _this = this;
377
+
378
+ this.container
379
+ .bind("mousedown.jstree", function (event) {
380
+ if(tree_component.drag_drop.isdown) {
381
+ tree_component.drag_drop.move_type = false;
382
+ event.preventDefault();
383
+ event.stopPropagation();
384
+ event.stopImmediatePropagation();
385
+ return false;
386
+ }
387
+ })
388
+ .bind("mouseup.jstree", function (event) {
389
+ setTimeout( function() { _this.focus.apply(_this); }, 5);
390
+ })
391
+ .bind("click.jstree", function (event) {
392
+ //event.stopPropagation();
393
+ return true;
394
+ });
395
+ $("li", this.container.get(0))
396
+ .live("click", function(event) { // WHEN CLICK IS ON THE ARROW
397
+ if(event.target.tagName != "LI") return true;
398
+ _this.off_height();
399
+ if(event.pageY - $(event.target).offset().top > _this.li_height) return true;
400
+ _this.toggle_branch.apply(_this, [event.target]);
401
+ event.stopPropagation();
402
+ return false;
403
+ });
404
+ $("a", this.container.get(0))
405
+ .live("click", function (event) { // WHEN CLICK IS ON THE TEXT OR ICON
406
+ if(event.which && event.which == 3) return true;
407
+ if(_this.locked) {
408
+ event.preventDefault();
409
+ event.target.blur();
410
+ return _this.error("LOCKED");
411
+ }
412
+ _this.select_branch.apply(_this, [event.target, event.ctrlKey || _this.settings.rules.multiple == "on"]);
413
+ if(_this.inp) { _this.inp.blur(); }
414
+ event.preventDefault();
415
+ event.target.blur();
416
+ return false;
417
+ })
418
+ .live("dblclick", function (event) { // WHEN DOUBLECLICK ON TEXT OR ICON
419
+ if(_this.locked) {
420
+ event.preventDefault();
421
+ event.stopPropagation();
422
+ event.target.blur();
423
+ return _this.error("LOCKED");
424
+ }
425
+ _this.callback("ondblclk", [_this.get_node(event.target).get(0), _this]);
426
+ event.preventDefault();
427
+ event.stopPropagation();
428
+ event.target.blur();
429
+ })
430
+ .live("contextmenu", function (event) {
431
+ if(_this.locked) {
432
+ event.target.blur();
433
+ return _this.error("LOCKED");
434
+ }
435
+ return _this.callback("onrgtclk", [_this.get_node(event.target).get(0), _this, event]);
436
+ })
437
+ .live("mouseover", function (event) {
438
+ if(_this.locked) {
439
+ event.preventDefault();
440
+ event.stopPropagation();
441
+ return _this.error("LOCKED");
442
+ }
443
+ if(_this.hovered !== false && (event.target.tagName == "A" || event.target.tagName == "INS")) {
444
+ _this.hovered.children("a").removeClass("hover");
445
+ _this.hovered = false;
446
+ }
447
+ _this.callback("onhover",[_this.get_node(event.target).get(0), _this]);
448
+ })
449
+ .live("mousedown", function (event) {
450
+ if(_this.settings.rules.drag_button == "left" && event.which && event.which != 1) return true;
451
+ if(_this.settings.rules.drag_button == "right" && event.which && event.which != 3) return true;
452
+ _this.focus.apply(_this);
453
+ if(_this.locked) return _this.error("LOCKED");
454
+ // SELECT LIST ITEM NODE
455
+ var obj = _this.get_node(event.target);
456
+ // IF ITEM IS DRAGGABLE
457
+ if(_this.settings.rules.multiple != false && _this.selected_arr.length > 1 && obj.children("a:eq(0)").hasClass("clicked")) {
458
+ var counter = 0;
459
+ for(var i in _this.selected_arr) {
460
+ if(!_this.selected_arr.hasOwnProperty(i)) continue;
461
+ if(_this.check("draggable", _this.selected_arr[i])) {
462
+ _this.selected_arr[i].addClass("dragged");
463
+ tree_component.drag_drop.origin_tree = _this;
464
+ counter ++;
465
+ }
466
+ }
467
+ if(counter > 0) {
468
+ if(_this.check("draggable", obj)) tree_component.drag_drop.drag_node = obj;
469
+ else tree_component.drag_drop.drag_node = _this.container.find("li.dragged:eq(0)");
470
+ tree_component.drag_drop.isdown = true;
471
+ tree_component.drag_drop.drag_help = $("<div id='jstree-dragged' class='tree " + ( _this.settings.ui.theme_name != "" ? " tree-" + _this.settings.ui.theme_name : "" ) + "' />").append("<ul class='" + _this.container.children("ul:eq(0)").get(0).className + "' />");
472
+ var tmp = tree_component.drag_drop.drag_node.clone();
473
+ if(_this.settings.languages.length > 0) tmp.find("a").not("." + _this.current_lang).hide();
474
+ tree_component.drag_drop.drag_help.children("ul:eq(0)").append(tmp);
475
+ tree_component.drag_drop.drag_help.find("li:eq(0)").removeClass("last").addClass("last").children("a").html("<ins>&nbsp;</ins>Multiple selection").end().children("ul").remove();
476
+
477
+ tree_component.drag_drop.dragged = _this.container.find("li.dragged");
478
+ }
479
+ }
480
+ else {
481
+ if(_this.check("draggable", obj)) {
482
+ tree_component.drag_drop.drag_node = obj;
483
+ tree_component.drag_drop.drag_help = $("<div id='jstree-dragged' class='tree " + ( _this.settings.ui.theme_name != "" ? " tree-" + _this.settings.ui.theme_name : "" ) + "' />").append("<ul class='" + _this.container.children("ul:eq(0)").get(0).className + "' />");
484
+ var tmp = obj.clone();
485
+ if(_this.settings.languages.length > 0) tmp.find("a").not("." + _this.current_lang).hide();
486
+ tree_component.drag_drop.drag_help.children("ul:eq(0)").append(tmp);
487
+ tree_component.drag_drop.drag_help.find("li:eq(0)").removeClass("last").addClass("last");
488
+ tree_component.drag_drop.isdown = true;
489
+ tree_component.drag_drop.foreign = false;
490
+ tree_component.drag_drop.origin_tree = _this;
491
+ obj.addClass("dragged");
492
+
493
+ tree_component.drag_drop.dragged = _this.container.find("li.dragged");
494
+ }
495
+ }
496
+ tree_component.drag_drop.init_x = event.pageX;
497
+ tree_component.drag_drop.init_y = event.pageY;
498
+ obj.blur();
499
+ event.preventDefault();
500
+ event.stopPropagation();
501
+ return false;
502
+ });
503
+ },
504
+ focus : function () {
505
+ if(this.locked) return false;
506
+ if(tree_component.focused != this.cntr) {
507
+ tree_component.focused = this.cntr;
508
+ this.callback("onfocus",[this]);
509
+ }
510
+ },
511
+
512
+ off_height : function () {
513
+ if(this.offset === false) {
514
+ this.container.css({ position : "relative" });
515
+ this.offset = this.container.offset();
516
+ var tmp = 0;
517
+ tmp = parseInt($.curCSS(this.container.get(0), "paddingTop", true),10);
518
+ if(tmp) this.offset.top += tmp;
519
+ tmp = parseInt($.curCSS(this.container.get(0), "borderTopWidth", true),10);
520
+ if(tmp) this.offset.top += tmp;
521
+ this.container.css({ position : "" });
522
+ }
523
+ if(!this.li_height) {
524
+ var tmp = this.container.find("ul li.closed, ul li.leaf").eq(0);
525
+ this.li_height = tmp.height();
526
+ if(tmp.children("ul:eq(0)").size()) this.li_height -= tmp.children("ul:eq(0)").height();
527
+ if(!this.li_height) this.li_height = 18;
528
+ }
529
+ },
530
+ scroll_check : function (x,y) {
531
+ var _this = this;
532
+ var cnt = _this.container;
533
+ var off = _this.container.offset();
534
+
535
+ var st = cnt.scrollTop();
536
+ var sl = cnt.scrollLeft();
537
+ // DETECT HORIZONTAL SCROLL
538
+ var h_cor = (cnt.get(0).scrollWidth > cnt.width()) ? 40 : 20;
539
+
540
+ if(y - off.top < 20) cnt.scrollTop(Math.max( (st - _this.settings.ui.scroll_spd) ,0)); // NEAR TOP
541
+ if(cnt.height() - (y - off.top) < h_cor) cnt.scrollTop(st + _this.settings.ui.scroll_spd); // NEAR BOTTOM
542
+ if(x - off.left < 20) cnt.scrollLeft(Math.max( (sl - _this.settings.ui.scroll_spd),0)); // NEAR LEFT
543
+ if(cnt.width() - (x - off.left) < 40) cnt.scrollLeft(sl + _this.settings.ui.scroll_spd); // NEAR RIGHT
544
+
545
+ if(cnt.scrollLeft() != sl || cnt.scrollTop() != st) {
546
+ tree_component.drag_drop.move_type = false;
547
+ tree_component.drag_drop.ref_node = false;
548
+ tree_component.drag_drop.marker.hide();
549
+ }
550
+ tree_component.drag_drop.scroll_time = setTimeout( function() { _this.scroll_check(x,y); }, 50);
551
+ },
552
+ scroll_into_view : function (obj) {
553
+ obj = obj ? this.get_node(obj) : this.selected;
554
+ if(!obj) return false;
555
+ var off_t = obj.offset().top;
556
+ var beg_t = this.container.offset().top;
557
+ var end_t = beg_t + this.container.height();
558
+ var h_cor = (this.container.get(0).scrollWidth > this.container.width()) ? 40 : 20;
559
+ if(off_t + 5 < beg_t) this.container.scrollTop(this.container.scrollTop() - (beg_t - off_t + 5) );
560
+ if(off_t + h_cor > end_t) this.container.scrollTop(this.container.scrollTop() + (off_t + h_cor - end_t) );
561
+ },
562
+
563
+ get_node : function (obj) {
564
+ return $(obj).closest("li");
565
+ },
566
+ get_type : function (obj) {
567
+ obj = !obj ? this.selected : this.get_node(obj);
568
+ if(!obj) return;
569
+ var tmp = obj.attr(this.settings.rules.type_attr);
570
+ return tmp || "default";
571
+ },
572
+ set_type : function (str, obj) {
573
+ obj = !obj ? this.selected : this.get_node(obj);
574
+ if(!obj || !str) return;
575
+ obj.attr(this.settings.rules.type_attr, str);
576
+ },
577
+ get_text : function (obj, lang) {
578
+ obj = this.get_node(obj);
579
+ if(!obj || obj.size() == 0) return "";
580
+ if(this.settings.languages && this.settings.languages.length) {
581
+ lang = lang ? lang : this.current_lang;
582
+ obj = obj.children("a." + lang);
583
+ }
584
+ else obj = obj.children("a:visible");
585
+ var val = "";
586
+ obj.contents().each(function () {
587
+ if(this.nodeType == 3) { val = this.data; return false; }
588
+ });
589
+ return val;
590
+ },
591
+
592
+ check : function (rule, obj) {
593
+ if(this.locked) return false;
594
+ var v = false;
595
+ // if root node
596
+ if(obj === -1) { if(typeof this.settings.rules[rule] != "undefined") v = this.settings.rules[rule]; }
597
+ else {
598
+ obj = !obj ? this.selected : this.get_node(obj);
599
+ if(!obj) return;
600
+ var t = this.get_type(obj);
601
+ if(typeof this.settings.types[t] != "undefined" && typeof this.settings.types[t][rule] != "undefined") v = this.settings.types[t][rule];
602
+ else if(typeof this.settings.types["default"] != "undefined" && typeof this.settings.types["default"][rule] != "undefined") v = this.settings.types["default"][rule];
603
+ }
604
+ if(typeof v == "function") v = v.call(null, obj, this);
605
+ v = this.callback("check", [rule, obj, v, this]);
606
+ return v;
607
+ },
608
+ check_move : function (nod, ref_node, how) {
609
+ if(this.locked) return false;
610
+ if($(ref_node).closest("li.dragged").size()) return false;
611
+
612
+ var tree1 = nod.parents(".tree:eq(0)").get(0);
613
+ var tree2 = ref_node.parents(".tree:eq(0)").get(0);
614
+ // if different trees
615
+ if(tree1 && tree1 != tree2) {
616
+ var m = $.tree.reference(tree2.id).settings.rules.multitree;
617
+ if(m == "none" || ($.isArray(m) && $.inArray(tree1.id, m) == -1)) return false;
618
+ }
619
+
620
+ var p = (how != "inside") ? this.parent(ref_node) : this.get_node(ref_node);
621
+ nod = this.get_node(nod);
622
+ if(p == false) return false;
623
+ var r = {
624
+ max_depth : this.settings.rules.use_max_depth ? this.check("max_depth", p) : -1,
625
+ max_children : this.settings.rules.use_max_children ? this.check("max_children", p) : -1,
626
+ valid_children : this.check("valid_children", p)
627
+ };
628
+ var nod_type = (typeof nod == "string") ? nod : this.get_type(nod);
629
+ if(typeof r.valid_children != "undefined" && (r.valid_children == "none" || (typeof r.valid_children == "object" && $.inArray(nod_type, $.makeArray(r.valid_children)) == -1))) return false;
630
+
631
+ if(this.settings.rules.use_max_children) {
632
+ if(typeof r.max_children != "undefined" && r.max_children != -1) {
633
+ if(r.max_children == 0) return false;
634
+ var c_count = 1;
635
+ if(tree_component.drag_drop.moving == true && tree_component.drag_drop.foreign == false) {
636
+ c_count = tree_component.drag_drop.dragged.size();
637
+ c_count = c_count - p.find('> ul > li.dragged').size();
638
+ }
639
+ if(r.max_children < p.find('> ul > li').size() + c_count) return false;
640
+ }
641
+ }
642
+
643
+ if(this.settings.rules.use_max_depth) {
644
+ if(typeof r.max_depth != "undefined" && r.max_depth === 0) return this.error("MOVE: MAX-DEPTH REACHED");
645
+ // check for max_depth up the chain
646
+ var mx = (r.max_depth > 0) ? r.max_depth : false;
647
+ var i = 0;
648
+ var t = p;
649
+ while(t !== -1) {
650
+ t = this.parent(t);
651
+ i ++;
652
+ var m = this.check("max_depth",t);
653
+ if(m >= 0) {
654
+ mx = (mx === false) ? (m - i) : Math.min(mx, m - i);
655
+ }
656
+ if(mx !== false && mx <= 0) return this.error("MOVE: MAX-DEPTH REACHED");
657
+ }
658
+ if(mx !== false && mx <= 0) return this.error("MOVE: MAX-DEPTH REACHED");
659
+ if(mx !== false) {
660
+ var incr = 1;
661
+ if(typeof nod != "string") {
662
+ var t = nod;
663
+ // possible async problem - when nodes are not all loaded down the chain
664
+ while(t.size() > 0) {
665
+ if(mx - incr < 0) return this.error("MOVE: MAX-DEPTH REACHED");
666
+ t = t.children("ul").children("li");
667
+ incr ++;
668
+ }
669
+ }
670
+ }
671
+ }
672
+ if(this.callback("check_move", [nod, ref_node, how, this]) == false) return false;
673
+ return true;
674
+ },
675
+
676
+ hover_branch : function (obj) {
677
+ if(this.locked) return this.error("LOCKED");
678
+ var _this = this;
679
+ var obj = _this.get_node(obj);
680
+ if(!obj.size()) return this.error("HOVER: NOT A VALID NODE");
681
+ if(!_this.check("clickable", obj)) return this.error("SELECT: NODE NOT SELECTABLE");
682
+ if(this.hovered) this.hovered.children("A").removeClass("hover");
683
+ this.hovered = obj;
684
+ this.hovered.children("a").addClass("hover");
685
+ this.scroll_into_view(this.hovered);
686
+ },
687
+ select_branch : function (obj, multiple) {
688
+ if(this.locked) return this.error("LOCKED");
689
+ if(!obj && this.hovered !== false) obj = this.hovered;
690
+ var _this = this;
691
+ obj = _this.get_node(obj);
692
+ if(!obj.size()) return this.error("SELECT: NOT A VALID NODE");
693
+ obj.children("a").removeClass("hover");
694
+ // CHECK AGAINST RULES FOR SELECTABLE NODES
695
+ if(!_this.check("clickable", obj)) return this.error("SELECT: NODE NOT SELECTABLE");
696
+ if(_this.callback("beforechange",[obj.get(0),_this]) === false) return this.error("SELECT: STOPPED BY USER");
697
+ // IF multiple AND obj IS ALREADY SELECTED - DESELECT IT
698
+ if(this.settings.rules.multiple != false && multiple && obj.children("a.clicked").size() > 0) {
699
+ return this.deselect_branch(obj);
700
+ }
701
+ if(this.settings.rules.multiple != false && multiple) {
702
+ this.selected_arr.push(obj);
703
+ }
704
+ if(this.settings.rules.multiple != false && !multiple) {
705
+ for(var i in this.selected_arr) {
706
+ if(!this.selected_arr.hasOwnProperty(i)) continue;
707
+ this.selected_arr[i].children("A").removeClass("clicked");
708
+ this.callback("ondeselect", [this.selected_arr[i].get(0), _this]);
709
+ }
710
+ this.selected_arr = [];
711
+ this.selected_arr.push(obj);
712
+ if(this.selected && this.selected.children("A").hasClass("clicked")) {
713
+ this.selected.children("A").removeClass("clicked");
714
+ this.callback("ondeselect", [this.selected.get(0), _this]);
715
+ }
716
+ }
717
+ if(!this.settings.rules.multiple) {
718
+ if(this.selected) {
719
+ this.selected.children("A").removeClass("clicked");
720
+ this.callback("ondeselect", [this.selected.get(0), _this]);
721
+ }
722
+ }
723
+ // SAVE NEWLY SELECTED
724
+ this.selected = obj;
725
+ if(this.hovered !== false) {
726
+ this.hovered.children("A").removeClass("hover");
727
+ this.hovered = obj;
728
+ }
729
+
730
+ // FOCUS NEW NODE AND OPEN ALL PARENT NODES IF CLOSED
731
+ this.selected.children("a").addClass("clicked").end().parents("li.closed").each( function () { _this.open_branch(this, true); });
732
+
733
+ // SCROLL SELECTED NODE INTO VIEW
734
+ this.scroll_into_view(this.selected);
735
+
736
+ this.callback("onselect", [this.selected.get(0), _this]);
737
+ this.callback("onchange", [this.selected.get(0), _this]);
738
+ },
739
+ deselect_branch : function (obj) {
740
+ if(this.locked) return this.error("LOCKED");
741
+ var _this = this;
742
+ var obj = this.get_node(obj);
743
+ if(obj.children("a.clicked").size() == 0) return this.error("DESELECT: NODE NOT SELECTED");
744
+
745
+ obj.children("a").removeClass("clicked");
746
+ this.callback("ondeselect", [obj.get(0), _this]);
747
+ if(this.settings.rules.multiple != false && this.selected_arr.length > 1) {
748
+ this.selected_arr = [];
749
+ this.container.find("a.clicked").filter(":first-child").parent().each(function () {
750
+ _this.selected_arr.push($(this));
751
+ });
752
+ if(obj.get(0) == this.selected.get(0)) {
753
+ this.selected = this.selected_arr[0];
754
+ }
755
+ }
756
+ else {
757
+ if(this.settings.rules.multiple != false) this.selected_arr = [];
758
+ this.selected = false;
759
+ }
760
+ this.callback("onchange", [obj.get(0), _this]);
761
+ },
762
+ toggle_branch : function (obj) {
763
+ if(this.locked) return this.error("LOCKED");
764
+ var obj = this.get_node(obj);
765
+ if(obj.hasClass("closed")) return this.open_branch(obj);
766
+ if(obj.hasClass("open")) return this.close_branch(obj);
767
+ },
768
+ open_branch : function (obj, disable_animation, callback) {
769
+ var _this = this;
770
+
771
+ if(this.locked) return this.error("LOCKED");
772
+ var obj = this.get_node(obj);
773
+ if(!obj.size()) return this.error("OPEN: NO SUCH NODE");
774
+ if(obj.hasClass("leaf")) return this.error("OPEN: OPENING LEAF NODE");
775
+ if(this.settings.data.async && obj.find("li").size() == 0) {
776
+
777
+ if(this.callback("beforeopen",[obj.get(0),this]) === false) return this.error("OPEN: STOPPED BY USER");
778
+
779
+ obj.children("ul:eq(0)").remove().end().append("<ul><li class='last'><a class='loading' href='#'><ins>&nbsp;</ins>" + (_this.settings.lang.loading || "Loading ...") + "</a></li></ul>");
780
+ obj.removeClass("closed").addClass("open");
781
+
782
+ var _datastore = new $.tree.datastores[this.settings.data.type]();
783
+ _datastore.load(this.callback("beforedata",[obj,this]),this,this.settings.data.opts,function(data){
784
+ data = _this.callback("ondata", [data, _this]);
785
+ if(!data || data.length == 0) {
786
+ obj.removeClass("closed").removeClass("open").addClass("leaf").children("ul").remove();
787
+ if(callback) callback.call();
788
+ return;
789
+ }
790
+ _datastore.parse(data,_this,_this.settings.data.opts,function(str){
791
+ str = _this.callback("onparse", [str, _this]);
792
+ // if(obj.children('ul:eq(0)').children('li').size() > 1) obj.children("ul").find('.loaading').parent().replaceWith(str); else
793
+ obj.children("ul:eq(0)").replaceWith($("<ul>").html(str));
794
+ obj.find("li:last-child").addClass("last").end().find("li:has(ul)").not(".open").addClass("closed");
795
+ obj.find("li").not(".open").not(".closed").addClass("leaf");
796
+ _this.open_branch.apply(_this, [obj]);
797
+ if(callback) callback.call();
798
+ });
799
+ });
800
+ return true;
801
+ }
802
+ else {
803
+ if(!this.settings.data.async) {
804
+ if(this.callback("beforeopen",[obj.get(0),this]) === false) return this.error("OPEN: STOPPED BY USER");
805
+ }
806
+ if(parseInt(this.settings.ui.animation) > 0 && !disable_animation ) {
807
+ obj.children("ul:eq(0)").css("display","none");
808
+ obj.removeClass("closed").addClass("open");
809
+ obj.children("ul:eq(0)").slideDown(parseInt(this.settings.ui.animation), function() {
810
+ $(this).css("display","");
811
+ if(callback) callback.call();
812
+ });
813
+ } else {
814
+ obj.removeClass("closed").addClass("open");
815
+ if(callback) callback.call();
816
+ }
817
+ this.callback("onopen", [obj.get(0), this]);
818
+ return true;
819
+ }
820
+ },
821
+ close_branch : function (obj, disable_animation) {
822
+ if(this.locked) return this.error("LOCKED");
823
+ var _this = this;
824
+ var obj = this.get_node(obj);
825
+ if(!obj.size()) return this.error("CLOSE: NO SUCH NODE");
826
+ if(_this.callback("beforeclose",[obj.get(0),_this]) === false) return this.error("CLOSE: STOPPED BY USER");
827
+ if(parseInt(this.settings.ui.animation) > 0 && !disable_animation && obj.children("ul:eq(0)").size() == 1) {
828
+ obj.children("ul:eq(0)").slideUp(parseInt(this.settings.ui.animation), function() {
829
+ if(obj.hasClass("open")) obj.removeClass("open").addClass("closed");
830
+ $(this).css("display","");
831
+ });
832
+ }
833
+ else {
834
+ if(obj.hasClass("open")) obj.removeClass("open").addClass("closed");
835
+ }
836
+ if(this.selected && this.settings.ui.selected_parent_close !== false && obj.children("ul:eq(0)").find("a.clicked").size() > 0) {
837
+ obj.find("li:has(a.clicked)").each(function() {
838
+ _this.deselect_branch(this);
839
+ });
840
+ if(this.settings.ui.selected_parent_close == "select_parent" && obj.children("a.clicked").size() == 0) this.select_branch(obj, (this.settings.rules.multiple != false && this.selected_arr.length > 0) );
841
+ }
842
+ this.callback("onclose", [obj.get(0), this]);
843
+ },
844
+ open_all : function (obj, callback) {
845
+ if(this.locked) return this.error("LOCKED");
846
+ var _this = this;
847
+ obj = obj ? this.get_node(obj) : this.container;
848
+
849
+ var s = obj.find("li.closed").size();
850
+ if(!callback) this.cl_count = 0;
851
+ else this.cl_count --;
852
+ if(s > 0) {
853
+ this.cl_count += s;
854
+ // maybe add .andSelf()
855
+ obj.find("li.closed").each( function () { var __this = this; _this.open_branch.apply(_this, [this, true, function() { _this.open_all.apply(_this, [__this, true]); } ]); });
856
+ }
857
+ else if(this.cl_count == 0) this.callback("onopen_all",[this]);
858
+ },
859
+ close_all : function (obj) {
860
+ if(this.locked) return this.error("LOCKED");
861
+ var _this = this;
862
+ obj = obj ? this.get_node(obj) : this.container;
863
+ // maybe add .andSelf()
864
+ obj.find("li.open").each( function () { _this.close_branch(this, true); });
865
+ this.callback("onclose_all",[this]);
866
+ },
867
+
868
+ set_lang : function (i) {
869
+ if(!$.isArray(this.settings.languages) || this.settings.languages.length == 0) return false;
870
+ if(this.locked) return this.error("LOCKED");
871
+ if(!$.inArray(i,this.settings.languages) && typeof this.settings.languages[i] != "undefined") i = this.settings.languages[i];
872
+ if(typeof i == "undefined") return false;
873
+ if(i == this.current_lang) return true;
874
+ var st = false;
875
+ var id = "#" + this.container.attr("id");
876
+ st = tree_component.get_css(id + " ." + this.current_lang);
877
+ if(st !== false) st.style.display = "none";
878
+ st = tree_component.get_css(id + " ." + i);
879
+ if(st !== false) st.style.display = "";
880
+ this.current_lang = i;
881
+ return true;
882
+ },
883
+ get_lang : function () {
884
+ if(!$.isArray(this.settings.languages) || this.settings.languages.length == 0) return false;
885
+ return this.current_lang;
886
+ },
887
+
888
+ create : function (obj, ref_node, position) {
889
+ if(this.locked) return this.error("LOCKED");
890
+
891
+ var root = false;
892
+ if(ref_node == -1) { root = true; ref_node = this.container; }
893
+ else ref_node = ref_node ? this.get_node(ref_node) : this.selected;
894
+
895
+ if(!root && (!ref_node || !ref_node.size())) return this.error("CREATE: NO NODE SELECTED");
896
+
897
+ var pos = position;
898
+
899
+ var tmp = ref_node; // for type calculation
900
+ if(position == "before") {
901
+ position = ref_node.parent().children().index(ref_node);
902
+ ref_node = ref_node.parents("li:eq(0)");
903
+ }
904
+ if(position == "after") {
905
+ position = ref_node.parent().children().index(ref_node) + 1;
906
+ ref_node = ref_node.parents("li:eq(0)");
907
+ }
908
+ if(!root && ref_node.size() == 0) { root = true; ref_node = this.container; }
909
+
910
+ if(!root) {
911
+ if(!this.check("creatable", ref_node)) return this.error("CREATE: CANNOT CREATE IN NODE");
912
+ if(ref_node.hasClass("closed")) {
913
+ if(this.settings.data.async && ref_node.children("ul").size() == 0) {
914
+ var _this = this;
915
+ return this.open_branch(ref_node, true, function () { _this.create.apply(_this, [obj, ref_node, position]); } );
916
+ }
917
+ else this.open_branch(ref_node, true);
918
+ }
919
+ }
920
+
921
+ // creating new object to pass to parseJSON
922
+ var torename = false;
923
+ if(!obj) obj = {};
924
+ else obj = $.extend(true, {}, obj);
925
+ if(!obj.attributes) obj.attributes = {};
926
+ if(!obj.attributes[this.settings.rules.type_attr]) obj.attributes[this.settings.rules.type_attr] = this.get_type(tmp) || "default";
927
+ if(this.settings.languages.length) {
928
+ if(!obj.data) { obj.data = {}; torename = true; }
929
+ for(var i = 0; i < this.settings.languages.length; i++) {
930
+ if(!obj.data[this.settings.languages[i]]) obj.data[this.settings.languages[i]] = ((typeof this.settings.lang.new_node).toLowerCase() != "string" && this.settings.lang.new_node[i]) ? this.settings.lang.new_node[i] : this.settings.lang.new_node;
931
+ }
932
+ }
933
+ else {
934
+ if(!obj.data) { obj.data = this.settings.lang.new_node; torename = true; }
935
+ }
936
+
937
+ obj = this.callback("ondata",[obj, this]);
938
+ var obj_s = $.tree.datastores.json().parse(obj,this);
939
+ obj_s = this.callback("onparse", [obj_s, this]);
940
+ var $li = $(obj_s);
941
+
942
+ if($li.children("ul").size()) {
943
+ if(!$li.is(".open")) $li.addClass("closed");
944
+ }
945
+ else $li.addClass("leaf");
946
+ $li.find("li:last-child").addClass("last").end().find("li:has(ul)").not(".open").addClass("closed");
947
+ $li.find("li").not(".open").not(".closed").addClass("leaf");
948
+
949
+ var r = {
950
+ max_depth : this.settings.rules.use_max_depth ? this.check("max_depth", (root ? -1 : ref_node) ) : -1,
951
+ max_children : this.settings.rules.use_max_children ? this.check("max_children", (root ? -1 : ref_node) ) : -1,
952
+ valid_children : this.check("valid_children", (root ? -1 : ref_node) )
953
+ };
954
+ var nod_type = this.get_type($li);
955
+ if(typeof r.valid_children != "undefined" && (r.valid_children == "none" || ($.isArray(r.valid_children) && $.inArray(nod_type, r.valid_children) == -1))) return this.error("CREATE: NODE NOT A VALID CHILD");
956
+
957
+ if(this.settings.rules.use_max_children) {
958
+ if(typeof r.max_children != "undefined" && r.max_children != -1 && r.max_children >= this.children(ref_node).size()) return this.error("CREATE: MAX_CHILDREN REACHED");
959
+ }
960
+
961
+ if(this.settings.rules.use_max_depth) {
962
+ if(typeof r.max_depth != "undefined" && r.max_depth === 0) return this.error("CREATE: MAX-DEPTH REACHED");
963
+ // check for max_depth up the chain
964
+ var mx = (r.max_depth > 0) ? r.max_depth : false;
965
+ var i = 0;
966
+ var t = ref_node;
967
+
968
+ while(t !== -1 && !root) {
969
+ t = this.parent(t);
970
+ i ++;
971
+ var m = this.check("max_depth",t);
972
+ if(m >= 0) {
973
+ mx = (mx === false) ? (m - i) : Math.min(mx, m - i);
974
+ }
975
+ if(mx !== false && mx <= 0) return this.error("CREATE: MAX-DEPTH REACHED");
976
+ }
977
+ if(mx !== false && mx <= 0) return this.error("CREATE: MAX-DEPTH REACHED");
978
+ if(mx !== false) {
979
+ var incr = 1;
980
+ var t = $li;
981
+ while(t.size() > 0) {
982
+ if(mx - incr < 0) return this.error("CREATE: MAX-DEPTH REACHED");
983
+ t = t.children("ul").children("li");
984
+ incr ++;
985
+ }
986
+ }
987
+ }
988
+
989
+ if((typeof position).toLowerCase() == "undefined" || position == "inside")
990
+ position = (this.settings.rules.createat == "top") ? 0 : ref_node.children("ul:eq(0)").children("li").size();
991
+ if(ref_node.children("ul").size() == 0 || (root == true && ref_node.children("ul").children("li").size() == 0) ) {
992
+ if(!root) var a = this.moved($li,ref_node.children("a:eq(0)"),"inside", true);
993
+ else var a = this.moved($li,this.container.children("ul:eq(0)"),"inside", true);
994
+ }
995
+ else if(pos == "before" && ref_node.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size())
996
+ var a = this.moved($li,ref_node.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before", true);
997
+ else if(pos == "after" && ref_node.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").size())
998
+ var a = this.moved($li,ref_node.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").children("a:eq(0)"),"after", true);
999
+ else if(ref_node.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size())
1000
+ var a = this.moved($li,ref_node.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before", true);
1001
+ else
1002
+ var a = this.moved($li,ref_node.children("ul:eq(0)").children("li:last").children("a:eq(0)"),"after",true);
1003
+
1004
+ if(a === false) return this.error("CREATE: ABORTED");
1005
+
1006
+ if(torename) {
1007
+ this.select_branch($li.children("a:eq(0)"));
1008
+ this.rename();
1009
+ }
1010
+ return $li;
1011
+ },
1012
+ rename : function (obj, new_name) {
1013
+ if(this.locked) return this.error("LOCKED");
1014
+ obj = obj ? this.get_node(obj) : this.selected;
1015
+ var _this = this;
1016
+ if(!obj || !obj.size()) return this.error("RENAME: NO NODE SELECTED");
1017
+ if(!this.check("renameable", obj)) return this.error("RENAME: NODE NOT RENAMABLE");
1018
+ if(!this.callback("beforerename",[obj.get(0), _this.current_lang, _this])) return this.error("RENAME: STOPPED BY USER");
1019
+
1020
+ obj.parents("li.closed").each(function () { _this.open_branch(this) });
1021
+ if(this.current_lang) obj = obj.find("a." + this.current_lang);
1022
+ else obj = obj.find("a:first");
1023
+
1024
+ // Rollback
1025
+ var rb = {};
1026
+ rb[this.container.attr("id")] = this.get_rollback();
1027
+
1028
+ var icn = obj.children("ins").clone();
1029
+ if((typeof new_name).toLowerCase() == "string") {
1030
+ obj.text(new_name).prepend(icn);
1031
+ _this.callback("onrename", [_this.get_node(obj).get(0), _this, rb]);
1032
+ }
1033
+ else {
1034
+ var last_value = "";
1035
+ obj.contents().each(function () {
1036
+ if(this.nodeType == 3) { last_value = this.data; return false; }
1037
+ });
1038
+ _this.inp = $("<input type='text' autocomplete='off' />");
1039
+ _this.inp
1040
+ .val(last_value.replace(/&amp;/g,"&").replace(/&gt;/g,">").replace(/&lt;/g,"<"))
1041
+ .bind("mousedown", function (event) { event.stopPropagation(); })
1042
+ .bind("mouseup", function (event) { event.stopPropagation(); })
1043
+ .bind("click", function (event) { event.stopPropagation(); })
1044
+ .bind("keyup", function (event) {
1045
+ var key = event.keyCode || event.which;
1046
+ if(key == 27) { this.value = last_value; this.blur(); return }
1047
+ if(key == 13) { this.blur(); return; }
1048
+ });
1049
+ _this.inp.blur(function(event) {
1050
+ if(this.value == "") this.value = last_value;
1051
+ obj.text(this.value).prepend(icn);
1052
+ obj.get(0).style.display = "";
1053
+ obj.prevAll("span").remove();
1054
+ _this.inp = false;
1055
+ _this.callback("onrename", [_this.get_node(obj).get(0), _this, rb]);
1056
+ });
1057
+
1058
+ var spn = $("<span />").addClass(obj.attr("class")).append(icn).append(_this.inp);
1059
+ obj.get(0).style.display = "none";
1060
+ obj.parent().prepend(spn);
1061
+ _this.inp.get(0).focus();
1062
+ _this.inp.get(0).select();
1063
+ }
1064
+ },
1065
+ remove : function(obj) {
1066
+ if(this.locked) return this.error("LOCKED");
1067
+ var _this = this;
1068
+
1069
+ // Rollback
1070
+ var rb = {};
1071
+ rb[this.container.attr("id")] = this.get_rollback();
1072
+
1073
+ if(obj && (!this.selected || this.get_node(obj).get(0) != this.selected.get(0) )) {
1074
+ obj = this.get_node(obj);
1075
+ if(obj.size()) {
1076
+ if(!this.check("deletable", obj)) return this.error("DELETE: NODE NOT DELETABLE");
1077
+ if(!this.callback("beforedelete",[obj.get(0), _this])) return this.error("DELETE: STOPPED BY USER");
1078
+ $parent = obj.parent();
1079
+ if(obj.find("a.clicked").size()) {
1080
+ var reset_selected = false;
1081
+ _this.selected_arr = [];
1082
+ this.container.find("a.clicked").filter(":first-child").parent().each(function () {
1083
+ if(!reset_selected && this == _this.selected.get(0)) reset_selected = true;
1084
+ if($(this).parents().index(obj) != -1) return true;
1085
+ _this.selected_arr.push($(this));
1086
+ });
1087
+ if(reset_selected) this.selected = this.selected_arr[0] || false;
1088
+ }
1089
+ obj = obj.remove();
1090
+ $parent.children("li:last").addClass("last");
1091
+ if($parent.children("li").size() == 0) {
1092
+ $li = $parent.parents("li:eq(0)");
1093
+ $li.removeClass("open").removeClass("closed").addClass("leaf").children("ul").remove();
1094
+ }
1095
+ this.callback("ondelete", [obj.get(0), this, rb]);
1096
+ }
1097
+ }
1098
+ else if(this.selected) {
1099
+ if(!this.check("deletable", this.selected)) return this.error("DELETE: NODE NOT DELETABLE");
1100
+ if(!this.callback("beforedelete",[this.selected.get(0), _this])) return this.error("DELETE: STOPPED BY USER");
1101
+ $parent = this.selected.parent();
1102
+ var obj = this.selected;
1103
+ if(this.settings.rules.multiple == false || this.selected_arr.length == 1) {
1104
+ var stop = true;
1105
+ var tmp = this.settings.ui.selected_delete == "select_previous" ? this.prev(this.selected) : false;
1106
+ }
1107
+ obj = obj.remove();
1108
+ $parent.children("li:last").addClass("last");
1109
+ if($parent.children("li").size() == 0) {
1110
+ $li = $parent.parents("li:eq(0)");
1111
+ $li.removeClass("open").removeClass("closed").addClass("leaf").children("ul").remove();
1112
+ }
1113
+ if(!stop && this.settings.rules.multiple != false) {
1114
+ var _this = this;
1115
+ this.selected_arr = [];
1116
+ this.container.find("a.clicked").filter(":first-child").parent().each(function () {
1117
+ _this.selected_arr.push($(this));
1118
+ });
1119
+ if(this.selected_arr.length > 0) {
1120
+ this.selected = this.selected_arr[0];
1121
+ this.remove();
1122
+ }
1123
+ }
1124
+ if(stop && tmp) this.select_branch(tmp);
1125
+ this.callback("ondelete", [obj.get(0), this, rb]);
1126
+ }
1127
+ else return this.error("DELETE: NO NODE SELECTED");
1128
+ },
1129
+
1130
+ next : function (obj, strict) {
1131
+ obj = this.get_node(obj);
1132
+ if(!obj.size()) return false;
1133
+ if(strict) return (obj.nextAll("li").size() > 0) ? obj.nextAll("li:eq(0)") : false;
1134
+
1135
+ if(obj.hasClass("open")) return obj.find("li:eq(0)");
1136
+ else if(obj.nextAll("li").size() > 0) return obj.nextAll("li:eq(0)");
1137
+ else return obj.parents("li").next("li").eq(0);
1138
+ },
1139
+ prev : function(obj, strict) {
1140
+ obj = this.get_node(obj);
1141
+ if(!obj.size()) return false;
1142
+ if(strict) return (obj.prevAll("li").size() > 0) ? obj.prevAll("li:eq(0)") : false;
1143
+
1144
+ if(obj.prev("li").size()) {
1145
+ var obj = obj.prev("li").eq(0);
1146
+ while(obj.hasClass("open")) obj = obj.children("ul:eq(0)").children("li:last");
1147
+ return obj;
1148
+ }
1149
+ else return obj.parents("li:eq(0)").size() ? obj.parents("li:eq(0)") : false;
1150
+ },
1151
+ parent : function(obj) {
1152
+ obj = this.get_node(obj);
1153
+ if(!obj.size()) return false;
1154
+ return obj.parents("li:eq(0)").size() ? obj.parents("li:eq(0)") : -1;
1155
+ },
1156
+ children : function(obj) {
1157
+ if(obj === -1) return this.container.children("ul:eq(0)").children("li");
1158
+
1159
+ obj = this.get_node(obj);
1160
+ if(!obj.size()) return false;
1161
+ return obj.children("ul:eq(0)").children("li");
1162
+ },
1163
+
1164
+ toggle_dots : function () {
1165
+ if(this.settings.ui.dots) {
1166
+ this.settings.ui.dots = false;
1167
+ this.container.children("ul:eq(0)").addClass("no_dots");
1168
+ }
1169
+ else {
1170
+ this.settings.ui.dots = true;
1171
+ this.container.children("ul:eq(0)").removeClass("no_dots");
1172
+ }
1173
+ },
1174
+
1175
+ callback : function (cb, args) {
1176
+ var p = false;
1177
+ var r = null;
1178
+ for(var i in this.settings.plugins) {
1179
+ if(typeof $.tree.plugins[i] != "object") continue;
1180
+ p = $.tree.plugins[i];
1181
+ if(p.callbacks && typeof p.callbacks[cb] == "function") r = p.callbacks[cb].apply(this, args);
1182
+ if(typeof r !== "undefined" && r !== null) {
1183
+ if(cb == "ondata" || cb == "onparse") args[0] = r; // keep the chain if data or parse
1184
+ else return r;
1185
+ }
1186
+ }
1187
+ p = this.settings.callback[cb];
1188
+ if(typeof p == "function") return p.apply(null, args);
1189
+ },
1190
+ get_rollback : function () {
1191
+ var rb = {};
1192
+ rb.html = this.container.html();
1193
+ rb.selected = this.selected ? this.selected.attr("id") : false;
1194
+ return rb;
1195
+ },
1196
+ moved : function (what, where, how, is_new, is_copy, rb) {
1197
+ var what = $(what);
1198
+ var $parent = $(what).parents("ul:eq(0)");
1199
+ var $where = $(where);
1200
+ if($where.is("ins")) $where = $where.parent();
1201
+
1202
+ // Rollback
1203
+ if(!rb) {
1204
+ var rb = {};
1205
+ rb[this.container.attr("id")] = this.get_rollback();
1206
+ if(!is_new) {
1207
+ var tmp = what.size() > 1 ? what.eq(0).parents(".tree:eq(0)") : what.parents(".tree:eq(0)");
1208
+ if(tmp.get(0) != this.container.get(0)) {
1209
+ tmp = tree_component.inst[tmp.attr("id")];
1210
+ rb[tmp.container.attr("id")] = tmp.get_rollback();
1211
+ }
1212
+ delete tmp;
1213
+ }
1214
+ }
1215
+
1216
+ if(how == "inside" && this.settings.data.async) {
1217
+ var _this = this;
1218
+ if(this.get_node($where).hasClass("closed")) {
1219
+ return this.open_branch(this.get_node($where), true, function () { _this.moved.apply(_this, [what, where, how, is_new, is_copy, rb]); });
1220
+ }
1221
+ if(this.get_node($where).find("> ul > li > a.loading").size() == 1) {
1222
+ setTimeout(function () { _this.moved.apply(_this, [what, where, how, is_new, is_copy]); }, 200);
1223
+ return;
1224
+ }
1225
+ }
1226
+
1227
+
1228
+ // IF MULTIPLE
1229
+ if(what.size() > 1) {
1230
+ var _this = this;
1231
+ var tmp = this.moved(what.eq(0), where, how, false, is_copy, rb);
1232
+ what.each(function (i) {
1233
+ if(i == 0) return;
1234
+ if(tmp) { // if tmp is false - the previous move was a no-go
1235
+ tmp = _this.moved(this, tmp.children("a:eq(0)"), "after", false, is_copy, rb);
1236
+ }
1237
+ });
1238
+ return what;
1239
+ }
1240
+
1241
+ if(is_copy) {
1242
+ _what = what.clone();
1243
+ _what.each(function (i) {
1244
+ this.id = this.id + "_copy";
1245
+ $(this).find("li").each(function () {
1246
+ this.id = this.id + "_copy";
1247
+ });
1248
+ $(this).removeClass("dragged").find("a.clicked").removeClass("clicked").end().find("li.dragged").removeClass("dragged");
1249
+ });
1250
+ }
1251
+ else _what = what;
1252
+ if(is_new) {
1253
+ if(!this.callback("beforecreate", [this.get_node(what).get(0), this.get_node(where).get(0),how,this])) return false;
1254
+ }
1255
+ else {
1256
+ if(!this.callback("beforemove", [this.get_node(what).get(0), this.get_node(where).get(0),how,this])) return false;
1257
+ }
1258
+
1259
+ if(!is_new) {
1260
+ var tmp = what.parents(".tree:eq(0)");
1261
+ // if different trees
1262
+ if(tmp.get(0) != this.container.get(0)) {
1263
+ tmp = tree_component.inst[tmp.attr("id")];
1264
+
1265
+ // if there are languages - otherwise - no cleanup needed
1266
+ if(tmp.settings.languages.length) {
1267
+ var res = [];
1268
+ // if new tree has no languages - use current visible
1269
+ if(this.settings.languages.length == 0) res.push("." + tmp.current_lang);
1270
+ else {
1271
+ for(var i in this.settings.languages) {
1272
+ if(!this.settings.languages.hasOwnProperty(i)) continue;
1273
+ for(var j in tmp.settings.languages) {
1274
+ if(!tmp.settings.languages.hasOwnProperty(j)) continue;
1275
+ if(this.settings.languages[i] == tmp.settings.languages[j]) res.push("." + this.settings.languages[i]);
1276
+ }
1277
+ }
1278
+ }
1279
+ if(res.length == 0) return this.error("MOVE: NO COMMON LANGUAGES");
1280
+ _what.find("a").not(res.join(",")).remove();
1281
+ }
1282
+ _what.find("a.clicked").removeClass("clicked");
1283
+ }
1284
+ }
1285
+ what = _what;
1286
+
1287
+ // ADD NODE TO NEW PLACE
1288
+ switch(how) {
1289
+ case "before":
1290
+ $where.parents("ul:eq(0)").children("li.last").removeClass("last");
1291
+ $where.parent().before(what.removeClass("last"));
1292
+ $where.parents("ul:eq(0)").children("li:last").addClass("last");
1293
+ break;
1294
+ case "after":
1295
+ $where.parents("ul:eq(0)").children("li.last").removeClass("last");
1296
+ $where.parent().after(what.removeClass("last"));
1297
+ $where.parents("ul:eq(0)").children("li:last").addClass("last");
1298
+ break;
1299
+ case "inside":
1300
+ if($where.parent().children("ul:first").size()) {
1301
+ if(this.settings.rules.createat == "top") {
1302
+ $where.parent().children("ul:first").prepend(what.removeClass("last")).children("li:last").addClass("last");
1303
+
1304
+ // restored this section
1305
+ var tmp_node = $where.parent().children("ul:first").children("li:first");
1306
+ if(tmp_node.size()) {
1307
+ how = "before";
1308
+ where = tmp_node;
1309
+ }
1310
+ }
1311
+ else {
1312
+ // restored this section
1313
+ var tmp_node = $where.parent().children("ul:first").children(".last");
1314
+ if(tmp_node.size()) {
1315
+ how = "after";
1316
+ where = tmp_node;
1317
+ }
1318
+
1319
+ $where.parent().children("ul:first").children(".last").removeClass("last").end().append(what.removeClass("last")).children("li:last").addClass("last");
1320
+ }
1321
+ }
1322
+ else {
1323
+ what.addClass("last");
1324
+ $where.parent().removeClass("leaf").append("<ul/>");
1325
+ if(!$where.parent().hasClass("open")) $where.parent().addClass("closed");
1326
+ $where.parent().children("ul:first").prepend(what);
1327
+ }
1328
+ if($where.parent().hasClass("closed")) { this.open_branch($where); }
1329
+ break;
1330
+ default:
1331
+ break;
1332
+ }
1333
+ // CLEANUP OLD PARENT
1334
+ if($parent.find("li").size() == 0) {
1335
+ var $li = $parent.parent();
1336
+ $li.removeClass("open").removeClass("closed").addClass("leaf");
1337
+ if(!$li.is(".tree")) $li.children("ul").remove();
1338
+ $li.parents("ul:eq(0)").children("li.last").removeClass("last").end().children("li:last").addClass("last");
1339
+ }
1340
+ else {
1341
+ $parent.children("li.last").removeClass("last");
1342
+ $parent.children("li:last").addClass("last");
1343
+ }
1344
+
1345
+ // NO LONGER CORRECT WITH position PARAM - if(is_new && how != "inside") where = this.get_node(where).parents("li:eq(0)");
1346
+ if(is_copy) this.callback("oncopy", [this.get_node(what).get(0), this.get_node(where).get(0), how, this, rb]);
1347
+ else if(is_new) this.callback("oncreate", [this.get_node(what).get(0), ($where.is("ul") ? -1 : this.get_node(where).get(0) ), how, this, rb]);
1348
+ else this.callback("onmove", [this.get_node(what).get(0), this.get_node(where).get(0), how, this, rb]);
1349
+ return what;
1350
+ },
1351
+ error : function (code) {
1352
+ this.callback("error",[code,this]);
1353
+ return false;
1354
+ },
1355
+ lock : function (state) {
1356
+ this.locked = state;
1357
+ if(this.locked) this.container.children("ul:eq(0)").addClass("locked");
1358
+ else this.container.children("ul:eq(0)").removeClass("locked");
1359
+ },
1360
+ cut : function (obj) {
1361
+ if(this.locked) return this.error("LOCKED");
1362
+ obj = obj ? this.get_node(obj) : this.container.find("a.clicked").filter(":first-child").parent();
1363
+ if(!obj || !obj.size()) return this.error("CUT: NO NODE SELECTED");
1364
+ tree_component.cut_copy.copy_nodes = false;
1365
+ tree_component.cut_copy.cut_nodes = obj;
1366
+ },
1367
+ copy : function (obj) {
1368
+ if(this.locked) return this.error("LOCKED");
1369
+ obj = obj ? this.get_node(obj) : this.container.find("a.clicked").filter(":first-child").parent();
1370
+ if(!obj || !obj.size()) return this.error("COPY: NO NODE SELECTED");
1371
+ tree_component.cut_copy.copy_nodes = obj;
1372
+ tree_component.cut_copy.cut_nodes = false;
1373
+ },
1374
+ paste : function (obj, position) {
1375
+ if(this.locked) return this.error("LOCKED");
1376
+
1377
+ var root = false;
1378
+ if(obj == -1) { root = true; obj = this.container; }
1379
+ else obj = obj ? this.get_node(obj) : this.selected;
1380
+
1381
+ if(!root && (!obj || !obj.size())) return this.error("PASTE: NO NODE SELECTED");
1382
+ if(!tree_component.cut_copy.copy_nodes && !tree_component.cut_copy.cut_nodes) return this.error("PASTE: NOTHING TO DO");
1383
+
1384
+ var _this = this;
1385
+
1386
+ var pos = position;
1387
+
1388
+ if(position == "before") {
1389
+ position = obj.parent().children().index(obj);
1390
+ obj = obj.parents("li:eq(0)");
1391
+ }
1392
+ else if(position == "after") {
1393
+ position = obj.parent().children().index(obj) + 1;
1394
+ obj = obj.parents("li:eq(0)");
1395
+ }
1396
+ else if((typeof position).toLowerCase() == "undefined" || position == "inside") {
1397
+ position = (this.settings.rules.createat == "top") ? 0 : obj.children("ul:eq(0)").children("li").size();
1398
+ }
1399
+ if(!root && obj.size() == 0) { root = true; obj = this.container; }
1400
+
1401
+ if(tree_component.cut_copy.copy_nodes && tree_component.cut_copy.copy_nodes.size()) {
1402
+ var ok = true;
1403
+ if(!root && !this.check_move(tree_component.cut_copy.copy_nodes, obj.children("a:eq(0)"), "inside")) return false;
1404
+
1405
+ if(obj.children("ul").size() == 0 || (root == true && obj.children("ul").children("li").size() == 0) ) {
1406
+ if(!root) var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("a:eq(0)"),"inside", false, true);
1407
+ else var a = this.moved(tree_component.cut_copy.copy_nodes,this.container.children("ul:eq(0)"),"inside", false, true);
1408
+ }
1409
+ else if(pos == "before" && obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size())
1410
+ var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before", false, true);
1411
+ else if(pos == "after" && obj.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").size())
1412
+ var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").children("a:eq(0)"),"after", false, true);
1413
+ else if(obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size())
1414
+ var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before", false, true);
1415
+ else
1416
+ var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("ul:eq(0)").children("li:last").children("a:eq(0)"),"after", false, true);
1417
+ tree_component.cut_copy.copy_nodes = false;
1418
+ }
1419
+ if(tree_component.cut_copy.cut_nodes && tree_component.cut_copy.cut_nodes.size()) {
1420
+ var ok = true;
1421
+ obj.parents().andSelf().each(function () {
1422
+ if(tree_component.cut_copy.cut_nodes.index(this) != -1) {
1423
+ ok = false;
1424
+ return false;
1425
+ }
1426
+ });
1427
+ if(!ok) return this.error("Invalid paste");
1428
+ if(!root && !this.check_move(tree_component.cut_copy.cut_nodes, obj.children("a:eq(0)"), "inside")) return false;
1429
+
1430
+ if(obj.children("ul").size() == 0 || (root == true && obj.children("ul").children("li").size() == 0) ) {
1431
+ if(!root) var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("a:eq(0)"),"inside");
1432
+ else var a = this.moved(tree_component.cut_copy.cut_nodes,this.container.children("ul:eq(0)"),"inside");
1433
+ }
1434
+ else if(pos == "before" && obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size())
1435
+ var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before");
1436
+ else if(pos == "after" && obj.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").size())
1437
+ var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").children("a:eq(0)"),"after");
1438
+ else if(obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size())
1439
+ var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before");
1440
+ else
1441
+ var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("ul:eq(0)").children("li:last").children("a:eq(0)"),"after");
1442
+ tree_component.cut_copy.cut_nodes = false;
1443
+ }
1444
+ },
1445
+ search : function(str, func) {
1446
+ var _this = this;
1447
+ if(!str || (this.srch && str != this.srch) ) {
1448
+ this.srch = "";
1449
+ this.srch_opn = false;
1450
+ this.container.find("a.search").removeClass("search");
1451
+ }
1452
+ this.srch = str;
1453
+ if(!str) return;
1454
+
1455
+ if(!func) func = "contains";
1456
+ if(this.settings.data.async) {
1457
+ if(!this.srch_opn) {
1458
+ var dd = $.extend( { "search" : str } , this.callback("beforedata", [false, this] ) );
1459
+ $.ajax({
1460
+ type : this.settings.data.opts.method,
1461
+ url : this.settings.data.opts.url,
1462
+ data : dd,
1463
+ dataType : "text",
1464
+ success : function (data) {
1465
+ _this.srch_opn = $.unique(data.split(","));
1466
+ _this.search.apply(_this,[str, func]);
1467
+ }
1468
+ });
1469
+ }
1470
+ else if(this.srch_opn.length) {
1471
+ if(this.srch_opn && this.srch_opn.length) {
1472
+ var opn = false;
1473
+ for(var j = 0; j < this.srch_opn.length; j++) {
1474
+ if(this.get_node("#" + this.srch_opn[j]).size() > 0) {
1475
+ opn = true;
1476
+ var tmp = "#" + this.srch_opn[j];
1477
+ delete this.srch_opn[j];
1478
+ this.open_branch(tmp, true, function () { _this.search.apply(_this,[str, func]); } );
1479
+ }
1480
+ }
1481
+ if(!opn) {
1482
+ this.srch_opn = [];
1483
+ _this.search.apply(_this,[str, func]);
1484
+ }
1485
+ }
1486
+ }
1487
+ else {
1488
+ this.srch_opn = false;
1489
+ var selector = "a";
1490
+ // IF LANGUAGE VERSIONS
1491
+ if(this.settings.languages.length) selector += "." + this.current_lang;
1492
+ this.callback("onsearch", [this.container.find(selector + ":" + func + "('" + str + "')"), this]);
1493
+ }
1494
+ }
1495
+ else {
1496
+ var selector = "a";
1497
+ // IF LANGUAGE VERSIONS
1498
+ if(this.settings.languages.length) selector += "." + this.current_lang;
1499
+ var nn = this.container.find(selector + ":" + func + "('" + str + "')");
1500
+ nn.parents("li.closed").each( function () { _this.open_branch(this, true); });
1501
+ this.callback("onsearch", [nn, this]);
1502
+ }
1503
+ },
1504
+ add_sheet : tree_component.add_sheet,
1505
+
1506
+ destroy : function() {
1507
+ this.callback("ondestroy", [this]);
1508
+
1509
+ this.container.unbind(".jstree");
1510
+ $("#" + this.container.attr("id")).die("click.jstree").die("dblclick.jstree").die("mouseover.jstree").die("mouseout.jstree").die("mousedown.jstree");
1511
+ this.container.removeClass("tree ui-widget ui-widget-content tree-default tree-" + this.settings.ui.theme_name).children("ul").removeClass("no_dots ltr locked").find("li").removeClass("leaf").removeClass("open").removeClass("closed").removeClass("last").children("a").removeClass("clicked hover search");
1512
+
1513
+ if(this.cntr == tree_component.focused) {
1514
+ for(var i in tree_component.inst) {
1515
+ if(i != this.cntr && i != this.container.attr("id")) {
1516
+ tree_component.inst[i].focus();
1517
+ break;
1518
+ }
1519
+ }
1520
+ }
1521
+
1522
+ tree_component.inst[this.cntr] = false;
1523
+ tree_component.inst[this.container.attr("id")] = false;
1524
+ delete tree_component.inst[this.cntr];
1525
+ delete tree_component.inst[this.container.attr("id")];
1526
+ tree_component.cntr --;
1527
+ }
1528
+ }
1529
+ };
1530
+
1531
+ // instance manager
1532
+ tree_component.cntr = 0;
1533
+ tree_component.inst = {};
1534
+
1535
+ // themes
1536
+ tree_component.themes = [];
1537
+
1538
+ // drag'n'drop stuff
1539
+ tree_component.drag_drop = {
1540
+ isdown : false, // Is there a drag
1541
+ drag_node : false, // The actual node
1542
+ drag_help : false, // The helper
1543
+ dragged : false,
1544
+
1545
+ init_x : false,
1546
+ init_y : false,
1547
+ moving : false,
1548
+
1549
+ origin_tree : false,
1550
+ marker : false,
1551
+
1552
+ move_type : false, // before, after or inside
1553
+ ref_node : false, // reference node
1554
+ appended : false, // is helper appended
1555
+
1556
+ foreign : false, // Is the dragged node a foreign one
1557
+ droppable : [], // Array of classes that can be dropped onto the tree
1558
+
1559
+ open_time : false, // Timeout for opening nodes
1560
+ scroll_time : false // Timeout for scrolling
1561
+ };
1562
+ tree_component.mouseup = function(event) {
1563
+ var tmp = tree_component.drag_drop;
1564
+ if(tmp.open_time) clearTimeout(tmp.open_time);
1565
+ if(tmp.scroll_time) clearTimeout(tmp.scroll_time);
1566
+
1567
+ if(tmp.moving && $.tree.drag_end !== false) $.tree.drag_end.call(null, event, tmp);
1568
+
1569
+ if(tmp.foreign === false && tmp.drag_node && tmp.drag_node.size()) {
1570
+ tmp.drag_help.remove();
1571
+ if(tmp.move_type) {
1572
+ var tree1 = tree_component.inst[tmp.ref_node.parents(".tree:eq(0)").attr("id")];
1573
+ if(tree1) tree1.moved(tmp.dragged, tmp.ref_node, tmp.move_type, false, (tmp.origin_tree.settings.rules.drag_copy == "on" || (tmp.origin_tree.settings.rules.drag_copy == "ctrl" && event.ctrlKey) ) );
1574
+ }
1575
+ tmp.move_type = false;
1576
+ tmp.ref_node = false;
1577
+ }
1578
+ if(tmp.foreign !== false) {
1579
+ if(tmp.drag_help) tmp.drag_help.remove();
1580
+ if(tmp.move_type) {
1581
+ var tree1 = tree_component.inst[tmp.ref_node.parents(".tree:eq(0)").attr("id")];
1582
+ if(tree1) tree1.callback("ondrop",[tmp.f_data, tree1.get_node(tmp.ref_node).get(0), tmp.move_type, tree1]);
1583
+ }
1584
+ tmp.foreign = false;
1585
+ tmp.move_type = false;
1586
+ tmp.ref_node = false;
1587
+ }
1588
+ // RESET EVERYTHING
1589
+ if(tree_component.drag_drop.marker) tree_component.drag_drop.marker.hide();
1590
+ if(tmp.dragged && tmp.dragged.size()) tmp.dragged.removeClass("dragged");
1591
+ tmp.dragged = false;
1592
+ tmp.drag_help = false;
1593
+ tmp.drag_node = false;
1594
+ tmp.f_type = false;
1595
+ tmp.f_data = false;
1596
+ tmp.init_x = false;
1597
+ tmp.init_y = false;
1598
+ tmp.moving = false;
1599
+ tmp.appended = false;
1600
+ tmp.origin_tree = false;
1601
+ if(tmp.isdown) {
1602
+ tmp.isdown = false;
1603
+ event.preventDefault();
1604
+ event.stopPropagation();
1605
+ return false;
1606
+ }
1607
+ };
1608
+ tree_component.mousemove = function(event) {
1609
+ var tmp = tree_component.drag_drop;
1610
+ var is_start = false;
1611
+
1612
+ if(tmp.isdown) {
1613
+ if(!tmp.moving && Math.abs(tmp.init_x - event.pageX) < 5 && Math.abs(tmp.init_y - event.pageY) < 5) {
1614
+ event.preventDefault();
1615
+ event.stopPropagation();
1616
+ return false;
1617
+ }
1618
+ else {
1619
+ if(!tmp.moving) {
1620
+ tree_component.drag_drop.moving = true;
1621
+ is_start = true;
1622
+ }
1623
+ }
1624
+
1625
+ if(tmp.open_time) clearTimeout(tmp.open_time);
1626
+
1627
+ if(tmp.drag_help !== false) {
1628
+ if(!tmp.appended) {
1629
+ if(tmp.foreign !== false) tmp.origin_tree = $.tree.focused();
1630
+ $("body").append(tmp.drag_help);
1631
+ tmp.w = tmp.drag_help.width();
1632
+ tmp.appended = true;
1633
+ }
1634
+ tmp.drag_help.css({ "left" : (event.pageX + 5 ), "top" : (event.pageY + 15) });
1635
+ }
1636
+
1637
+ if(is_start && $.tree.drag_start !== false) $.tree.drag_start.call(null, event, tmp);
1638
+ if($.tree.drag !== false) $.tree.drag.call(null, event, tmp);
1639
+
1640
+ if(event.target.tagName == "DIV" && event.target.id == "jstree-marker") return false;
1641
+
1642
+ var et = $(event.target);
1643
+ if(et.is("ins")) et = et.parent();
1644
+ var cnt = et.is(".tree") ? et : et.parents(".tree:eq(0)");
1645
+
1646
+ // if not moving over a tree
1647
+ if(cnt.size() == 0 || !tree_component.inst[cnt.attr("id")]) {
1648
+ if(tmp.scroll_time) clearTimeout(tmp.scroll_time);
1649
+ if(tmp.drag_help !== false) tmp.drag_help.find("li:eq(0) ins").addClass("forbidden");
1650
+ tmp.move_type = false;
1651
+ tmp.ref_node = false;
1652
+ tree_component.drag_drop.marker.hide();
1653
+ return false;
1654
+ }
1655
+
1656
+ var tree2 = tree_component.inst[cnt.attr("id")];
1657
+ tree2.off_height();
1658
+
1659
+ if(tmp.scroll_time) clearTimeout(tmp.scroll_time);
1660
+ tmp.scroll_time = setTimeout( function() { tree2.scroll_check(event.pageX,event.pageY); }, 50);
1661
+
1662
+ var mov = false;
1663
+ var st = cnt.scrollTop();
1664
+
1665
+ if(event.target.tagName == "A" || event.target.tagName == "INS") {
1666
+ // just in case if hover is over the draggable
1667
+ if(et.is("#jstree-dragged")) return false;
1668
+ if(tree2.get_node(event.target).hasClass("closed")) {
1669
+ tmp.open_time = setTimeout( function () { tree2.open_branch(et); }, 500);
1670
+ }
1671
+
1672
+ var et_off = et.offset();
1673
+ var goTo = {
1674
+ x : (et_off.left - 1),
1675
+ y : (event.pageY - et_off.top)
1676
+ };
1677
+
1678
+ var arr = [];
1679
+ if(goTo.y < tree2.li_height/3 + 1 ) arr = ["before","inside","after"];
1680
+ else if(goTo.y > tree2.li_height*2/3 - 1 ) arr = ["after","inside","before"];
1681
+ else {
1682
+ if(goTo.y < tree2.li_height/2) arr = ["inside","before","after"];
1683
+ else arr = ["inside","after","before"];
1684
+ }
1685
+ var ok = false;
1686
+ var nn = (tmp.foreign == false) ? tmp.origin_tree.container.find("li.dragged") : tmp.f_type;
1687
+ $.each(arr, function(i, val) {
1688
+ if(tree2.check_move(nn, et, val)) {
1689
+ mov = val;
1690
+ ok = true;
1691
+ return false;
1692
+ }
1693
+ });
1694
+ if(ok) {
1695
+ switch(mov) {
1696
+ case "before":
1697
+ goTo.y = et_off.top - 2;
1698
+ tree_component.drag_drop.marker.attr("class","marker");
1699
+ break;
1700
+ case "after":
1701
+ goTo.y = et_off.top - 2 + tree2.li_height;
1702
+ tree_component.drag_drop.marker.attr("class","marker");
1703
+ break;
1704
+ case "inside":
1705
+ goTo.x -= 2;
1706
+ goTo.y = et_off.top - 2 + tree2.li_height/2;
1707
+ tree_component.drag_drop.marker.attr("class","marker_plus");
1708
+ break;
1709
+ }
1710
+ tmp.move_type = mov;
1711
+ tmp.ref_node = $(event.target);
1712
+ if(tmp.drag_help !== false) tmp.drag_help.find(".forbidden").removeClass("forbidden");
1713
+ tree_component.drag_drop.marker.css({ "left" : goTo.x , "top" : goTo.y }).show();
1714
+ }
1715
+ }
1716
+
1717
+ if( (et.is(".tree") || et.is("ul") ) && et.find("li:eq(0)").size() == 0) {
1718
+ var et_off = et.offset();
1719
+ tmp.move_type = "inside";
1720
+ tmp.ref_node = cnt.children("ul:eq(0)");
1721
+ if(tmp.drag_help !== false) tmp.drag_help.find(".forbidden").removeClass("forbidden");
1722
+ tree_component.drag_drop.marker.attr("class","marker_plus");
1723
+ tree_component.drag_drop.marker.css({ "left" : (et_off.left + 10) , "top" : et_off.top + 15 }).show();
1724
+ }
1725
+ else if( (event.target.tagName != "A" && event.target.tagName != "INS") || !ok) {
1726
+ if(tmp.drag_help !== false) tmp.drag_help.find("li:eq(0) ins").addClass("forbidden");
1727
+ tmp.move_type = false;
1728
+ tmp.ref_node = false;
1729
+ tree_component.drag_drop.marker.hide();
1730
+ }
1731
+ event.preventDefault();
1732
+ event.stopPropagation();
1733
+ return false;
1734
+ }
1735
+ return true;
1736
+ };
1737
+ $(function () {
1738
+ $(document).bind("mousemove.jstree", tree_component.mousemove);
1739
+ $(document).bind("mouseup.jstree", tree_component.mouseup);
1740
+ });
1741
+
1742
+ // cut, copy, paste stuff
1743
+ tree_component.cut_copy = {
1744
+ copy_nodes : false,
1745
+ cut_nodes : false
1746
+ };
1747
+
1748
+ // css stuff
1749
+ tree_component.css = false;
1750
+ tree_component.get_css = function(rule_name, delete_flag) {
1751
+ rule_name = rule_name.toLowerCase();
1752
+ var css_rules = tree_component.css.cssRules || tree_component.css.rules;
1753
+ var j = 0;
1754
+ do {
1755
+ if(css_rules.length && j > css_rules.length + 5) return false;
1756
+ if(css_rules[j].selectorText && css_rules[j].selectorText.toLowerCase() == rule_name) {
1757
+ if(delete_flag == true) {
1758
+ if(tree_component.css.removeRule) document.styleSheets[i].removeRule(j);
1759
+ if(tree_component.css.deleteRule) document.styleSheets[i].deleteRule(j);
1760
+ return true;
1761
+ }
1762
+ else return css_rules[j];
1763
+ }
1764
+ }
1765
+ while (css_rules[++j]);
1766
+ return false;
1767
+ };
1768
+ tree_component.add_css = function(rule_name) {
1769
+ if(tree_component.get_css(rule_name)) return false;
1770
+ (tree_component.css.insertRule) ? tree_component.css.insertRule(rule_name + ' { }', 0) : tree_component.css.addRule(rule_name, null, 0);
1771
+ return tree_component.get_css(rule_name);
1772
+ };
1773
+ tree_component.remove_css = function(rule_name) {
1774
+ return tree_component.get_css(rule_name, true);
1775
+ };
1776
+ tree_component.add_sheet = function(opts) {
1777
+ if(opts.str) {
1778
+ var tmp = document.createElement("style");
1779
+ tmp.setAttribute('type',"text/css");
1780
+ if(tmp.styleSheet) {
1781
+ document.getElementsByTagName("head")[0].appendChild(tmp);
1782
+ tmp.styleSheet.cssText = opts.str;
1783
+ }
1784
+ else {
1785
+ tmp.appendChild(document.createTextNode(opts.str));
1786
+ document.getElementsByTagName("head")[0].appendChild(tmp);
1787
+ }
1788
+ return tmp.sheet || tmp.styleSheet;
1789
+ }
1790
+ if(opts.url) {
1791
+ if(document.createStyleSheet) {
1792
+ try { document.createStyleSheet(opts.url); } catch (e) { };
1793
+ }
1794
+ else {
1795
+ var newSS = document.createElement('link');
1796
+ newSS.rel = 'stylesheet';
1797
+ newSS.type = 'text/css';
1798
+ newSS.media = "all";
1799
+ newSS.href = opts.url;
1800
+ // var styles = "@import url(' " + url + " ');";
1801
+ // newSS.href ='data:text/css,'+escape(styles);
1802
+ document.getElementsByTagName("head")[0].appendChild(newSS);
1803
+ return newSS.styleSheet;
1804
+ }
1805
+ }
1806
+ };
1807
+ $(function () {
1808
+ var u = navigator.userAgent.toLowerCase();
1809
+ var v = (u.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1];
1810
+
1811
+ var css = '/* TREE LAYOUT */ .tree ul { margin:0 0 0 5px; padding:0 0 0 0; list-style-type:none; } .tree li { display:block; min-height:18px; line-height:18px; padding:0 0 0 15px; margin:0 0 0 0; /* Background fix */ clear:both; } .tree li ul { display:none; } .tree li a, .tree li span { display:inline-block;line-height:16px;height:16px;color:black;white-space:nowrap;text-decoration:none;padding:1px 4px 1px 4px;margin:0; } .tree li a:focus { outline: none; } .tree li a input, .tree li span input { margin:0;padding:0 0;display:inline-block;height:12px !important;border:1px solid white;background:white;font-size:10px;font-family:Verdana; } .tree li a input:not([class="xxx"]), .tree li span input:not([class="xxx"]) { padding:1px 0; } /* FOR DOTS */ .tree .ltr li.last { float:left; } .tree > ul li.last { overflow:visible; } /* OPEN OR CLOSE */ .tree li.open ul { display:block; } .tree li.closed ul { display:none !important; } /* FOR DRAGGING */ #jstree-dragged { position:absolute; top:-10px; left:-10px; margin:0; padding:0; } #jstree-dragged ul ul ul { display:none; } #jstree-marker { padding:0; margin:0; line-height:5px; font-size:1px; overflow:hidden; height:5px; position:absolute; left:-45px; top:-30px; z-index:1000; background-color:transparent; background-repeat:no-repeat; display:none; } #jstree-marker.marker { width:45px; background-position:-32px top; } #jstree-marker.marker_plus { width:5px; background-position:right top; } /* BACKGROUND DOTS */ .tree li li { overflow:hidden; } .tree > .ltr > li { display:table; } /* ICONS */ .tree ul ins { display:inline-block; text-decoration:none; width:16px; height:16px; } .tree .ltr ins { margin:0 4px 0 0px; } ';
1812
+ if($.browser.msie) {
1813
+ if($.browser.version == 6) css += '.tree li { height:18px; zoom:1; } .tree li li { overflow:visible; } .tree .ltr li.last { margin-top: expression( (this.previousSibling && /open/.test(this.previousSibling.className) ) ? "-2px" : "0"); } .marker { width:45px; background-position:-32px top; } .marker_plus { width:5px; background-position:right top; }';
1814
+ if($.browser.version == 7) css += '.tree li li { overflow:visible; } .tree .ltr li.last { margin-top: expression( (this.previousSibling && /open/.test(this.previousSibling.className) ) ? "-2px" : "0"); }';
1815
+ }
1816
+ if($.browser.opera) css += '.tree > ul > li.last:after { content:"."; display: block; height:1px; clear:both; visibility:hidden; }';
1817
+ if($.browser.mozilla && $.browser.version.indexOf("1.8") == 0) css += '.tree .ltr li a { display:inline; float:left; } .tree li ul { clear:both; }';
1818
+ tree_component.css = tree_component.add_sheet({ str : css });
1819
+ });
1820
+ })(jQuery);
1821
+
1822
+ // Datastores
1823
+ // HTML and JSON are included here by default
1824
+ (function ($) {
1825
+ $.extend($.tree.datastores, {
1826
+ "html" : function () {
1827
+ return {
1828
+ get : function(obj, tree, opts) {
1829
+ return obj && $(obj).size() ? $('<div>').append(tree.get_node(obj).clone()).html() : tree.container.children("ul:eq(0)").html();
1830
+ },
1831
+ parse : function(data, tree, opts, callback) {
1832
+ if(callback) callback.call(null, data);
1833
+ return data;
1834
+ },
1835
+ load : function(data, tree, opts, callback) {
1836
+ if(opts.url) {
1837
+ $.ajax({
1838
+ 'type' : opts.method,
1839
+ 'url' : opts.url,
1840
+ 'data' : data,
1841
+ 'dataType' : "html",
1842
+ 'success' : function (d, textStatus) {
1843
+ callback.call(null, d);
1844
+ },
1845
+ 'error' : function (xhttp, textStatus, errorThrown) {
1846
+ callback.call(null, false);
1847
+ tree.error(errorThrown + " " + textStatus);
1848
+ }
1849
+ });
1850
+ }
1851
+ else {
1852
+ callback.call(null, opts.static || tree.container.children("ul:eq(0)").html());
1853
+ }
1854
+ }
1855
+ };
1856
+ },
1857
+ "json" : function () {
1858
+ return {
1859
+ get : function(obj, tree, opts) {
1860
+ var _this = this;
1861
+ if(!obj || $(obj).size() == 0) obj = tree.container.children("ul").children("li");
1862
+ else obj = $(obj);
1863
+
1864
+ if(!opts) opts = {};
1865
+ if(!opts.outer_attrib) opts.outer_attrib = [ "id", "rel", "class" ];
1866
+ if(!opts.inner_attrib) opts.inner_attrib = [ ];
1867
+
1868
+ if(obj.size() > 1) {
1869
+ var arr = [];
1870
+ obj.each(function () {
1871
+ arr.push(_this.get(this, tree, opts));
1872
+ });
1873
+ return arr;
1874
+ }
1875
+ if(obj.size() == 0) return [];
1876
+
1877
+ var json = { attributes : {}, data : {} };
1878
+ if(obj.hasClass("open")) json.data.state = "open";
1879
+ if(obj.hasClass("closed")) json.data.state = "closed";
1880
+
1881
+ for(var i in opts.outer_attrib) {
1882
+ if(!opts.outer_attrib.hasOwnProperty(i)) continue;
1883
+ var val = (opts.outer_attrib[i] == "class") ? obj.attr(opts.outer_attrib[i]).replace(/(^| )last( |$)/ig," ").replace(/(^| )(leaf|closed|open)( |$)/ig," ") : obj.attr(opts.outer_attrib[i]);
1884
+ if(typeof val != "undefined" && val.toString().replace(" ","").length > 0) json.attributes[opts.outer_attrib[i]] = val;
1885
+ delete val;
1886
+ }
1887
+
1888
+ if(tree.settings.languages.length) {
1889
+ for(var i in tree.settings.languages) {
1890
+ if(!tree.settings.languages.hasOwnProperty(i)) continue;
1891
+ var a = obj.children("a." + tree.settings.languages[i]);
1892
+ if(opts.force || opts.inner_attrib.length || a.children("ins").get(0).style.backgroundImage.toString().length || a.children("ins").get(0).className.length) {
1893
+ json.data[tree.settings.languages[i]] = {};
1894
+ json.data[tree.settings.languages[i]].title = tree.get_text(obj,tree.settings.languages[i]);
1895
+ if(a.children("ins").get(0).style.className.length) {
1896
+ json.data[tree.settings.languages[i]].icon = a.children("ins").get(0).style.className;
1897
+ }
1898
+ if(a.children("ins").get(0).style.backgroundImage.length) {
1899
+ json.data[tree.settings.languages[i]].icon = a.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","");
1900
+ }
1901
+ if(opts.inner_attrib.length) {
1902
+ json.data[tree.settings.languages[i]].attributes = {};
1903
+ for(var j in opts.inner_attrib) {
1904
+ if(!opts.inner_attrib.hasOwnProperty(j)) continue;
1905
+ var val = a.attr(opts.inner_attrib[j]);
1906
+ if(typeof val != "undefined" && val.toString().replace(" ","").length > 0) json.data[tree.settings.languages[i]].attributes[opts.inner_attrib[j]] = val;
1907
+ delete val;
1908
+ }
1909
+ }
1910
+ }
1911
+ else {
1912
+ json.data[tree.settings.languages[i]] = tree.get_text(obj,tree.settings.languages[i]);
1913
+ }
1914
+ }
1915
+ }
1916
+ else {
1917
+ var a = obj.children("a");
1918
+ json.data.title = tree.get_text(obj);
1919
+
1920
+ if(a.children("ins").size() && a.children("ins").get(0).className.length) {
1921
+ json.data.icon = a.children("ins").get(0).className;
1922
+ }
1923
+ if(a.children("ins").size() && a.children("ins").get(0).style.backgroundImage.length) {
1924
+ json.data.icon = a.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","");
1925
+ }
1926
+
1927
+ if(opts.inner_attrib.length) {
1928
+ json.data.attributes = {};
1929
+ for(var j in opts.inner_attrib) {
1930
+ if(!opts.inner_attrib.hasOwnProperty(j)) continue;
1931
+ var val = a.attr(opts.inner_attrib[j]);
1932
+ if(typeof val != "undefined" && val.toString().replace(" ","").length > 0) json.data.attributes[opts.inner_attrib[j]] = val;
1933
+ delete val;
1934
+ }
1935
+ }
1936
+ }
1937
+
1938
+ if(obj.children("ul").size() > 0) {
1939
+ json.children = [];
1940
+ obj.children("ul").children("li").each(function () {
1941
+ json.children.push(_this.get(this, tree, opts));
1942
+ });
1943
+ }
1944
+ return json;
1945
+ },
1946
+ parse : function(data, tree, opts, callback) {
1947
+ if(Object.prototype.toString.apply(data) === "[object Array]") {
1948
+ var str = '';
1949
+ for(var i = 0; i < data.length; i ++) {
1950
+ if(typeof data[i] == "function") continue;
1951
+ str += this.parse(data[i], tree, opts);
1952
+ }
1953
+ if(callback) callback.call(null, str);
1954
+ return str;
1955
+ }
1956
+
1957
+ if(!data || !data.data) {
1958
+ if(callback) callback.call(null, false);
1959
+ return "";
1960
+ }
1961
+
1962
+ var str = '';
1963
+ str += "<li ";
1964
+ var cls = false;
1965
+ if(data.attributes) {
1966
+ for(var i in data.attributes) {
1967
+ if(!data.attributes.hasOwnProperty(i)) continue;
1968
+ if(i == "class") {
1969
+ str += " class='" + data.attributes[i] + " ";
1970
+ if(data.state == "closed" || data.state == "open") str += " " + data.state + " ";
1971
+ str += "' ";
1972
+ cls = true;
1973
+ }
1974
+ else str += " " + i + "='" + data.attributes[i] + "' ";
1975
+ }
1976
+ }
1977
+ if(!cls && (data.state == "closed" || data.state == "open")) str += " class='" + data.state + "' ";
1978
+ str += ">";
1979
+
1980
+ if(tree.settings.languages.length) {
1981
+ for(var i = 0; i < tree.settings.languages.length; i++) {
1982
+ var attr = {};
1983
+ attr["href"] = "";
1984
+ attr["style"] = "";
1985
+ attr["class"] = tree.settings.languages[i];
1986
+ if(data.data[tree.settings.languages[i]] && (typeof data.data[tree.settings.languages[i]].attributes).toLowerCase() != "undefined") {
1987
+ for(var j in data.data[tree.settings.languages[i]].attributes) {
1988
+ if(!data.data[tree.settings.languages[i]].attributes.hasOwnProperty(j)) continue;
1989
+ if(j == "style" || j == "class") attr[j] += " " + data.data[tree.settings.languages[i]].attributes[j];
1990
+ else attr[j] = data.data[tree.settings.languages[i]].attributes[j];
1991
+ }
1992
+ }
1993
+ str += "<a";
1994
+ for(var j in attr) {
1995
+ if(!attr.hasOwnProperty(j)) continue;
1996
+ str += ' ' + j + '="' + attr[j] + '" ';
1997
+ }
1998
+ str += ">";
1999
+ if(data.data[tree.settings.languages[i]] && data.data[tree.settings.languages[i]].icon) {
2000
+ str += "<ins " + (data.data[tree.settings.languages[i]].icon.indexOf("/") == -1 ? " class='" + data.data[tree.settings.languages[i]].icon + "' " : " style='background-image:url(\"" + data.data[tree.settings.languages[i]].icon + "\");' " ) + ">&nbsp;</ins>";
2001
+ }
2002
+ else str += "<ins>&nbsp;</ins>";
2003
+ str += ( (typeof data.data[tree.settings.languages[i]].title).toLowerCase() != "undefined" ? data.data[tree.settings.languages[i]].title : data.data[tree.settings.languages[i]] ) + "</a>";
2004
+ }
2005
+ }
2006
+ else {
2007
+ var attr = {};
2008
+ attr["href"] = "";
2009
+ attr["style"] = "";
2010
+ attr["class"] = "";
2011
+ if((typeof data.data.attributes).toLowerCase() != "undefined") {
2012
+ for(var i in data.data.attributes) {
2013
+ if(!data.data.attributes.hasOwnProperty(i)) continue;
2014
+ if(i == "style" || i == "class") attr[i] += " " + data.data.attributes[i];
2015
+ else attr[i] = data.data.attributes[i];
2016
+ }
2017
+ }
2018
+ str += "<a";
2019
+ for(var i in attr) {
2020
+ if(!attr.hasOwnProperty(i)) continue;
2021
+ str += ' ' + i + '="' + attr[i] + '" ';
2022
+ }
2023
+ str += ">";
2024
+ if(data.data.icon) {
2025
+ str += "<ins " + (data.data.icon.indexOf("/") == -1 ? " class='" + data.data.icon + "' " : " style='background-image:url(\"" + data.data.icon + "\");' " ) + ">&nbsp;</ins>";
2026
+ }
2027
+ else str += "<ins>&nbsp;</ins>";
2028
+ str += ( (typeof data.data.title).toLowerCase() != "undefined" ? data.data.title : data.data ) + "</a>";
2029
+ }
2030
+ if(data.children && data.children.length) {
2031
+ str += '<ul>';
2032
+ for(var i = 0; i < data.children.length; i++) {
2033
+ str += this.parse(data.children[i], tree, opts);
2034
+ }
2035
+ str += '</ul>';
2036
+ }
2037
+ str += "</li>";
2038
+ if(callback) callback.call(null, str);
2039
+ return str;
2040
+ },
2041
+ load : function(data, tree, opts, callback) {
2042
+ if(opts.static) {
2043
+ callback.call(null, opts.static);
2044
+ }
2045
+ else {
2046
+ $.ajax({
2047
+ 'type' : opts.method,
2048
+ 'url' : opts.url,
2049
+ 'data' : data,
2050
+ 'dataType' : "json",
2051
+ 'success' : function (d, textStatus) {
2052
+ callback.call(null, d);
2053
+ },
2054
+ 'error' : function (xhttp, textStatus, errorThrown) {
2055
+ callback.call(null, false);
2056
+ tree.error(errorThrown + " " + textStatus);
2057
+ }
2058
+ });
2059
+ }
2060
+ }
2061
+ }
2062
+ }
2063
+ });
2064
+ })(jQuery);
scripts/plugins/_jquery.tree.rtl.js ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($) {
2
+ $.extend($.tree.plugins, {
3
+ "rtl" : {
4
+ defaults : {
5
+ attribute : "data"
6
+ },
7
+ callbacks : {
8
+ onload : function() {
9
+ this.container.css("direction","rtl").children("ul:eq(0)").removeClass("ltr").addClass("rtl");
10
+ },
11
+ oninit : function() {
12
+ if(!$.tree.plugins.rtl.css) {
13
+ var css = '.tree .rtl li.last { float:right; } #jstree-dragged .rtl { margin:0; padding:0; } #jstree-marker.marker_rtl { width:40px; background-position:right center; } /* RTL modification */ .tree .rtl, .tree .rtl ul { margin:0 10px 0 0; } .tree .rtl li { padding:0 10px 0 0; } .tree .rtl li a, .tree .rtl li span { padding:1px 4px 1px 4px; } .tree > .rtl > li { display:table; } .tree .rtl ins { margin:0 0px 0 4px; }';
14
+ if(/msie/.test(u) && !/opera/.test(u)) {
15
+ if(parseInt(v) == 6) css += '#jstree-dragged .rtl { width:20px; } .tree .rtl li.last { margin-top: expression( (this.previousSibling && /open/.test(this.previousSibling.className) ) ? "-2px" : "0"); } .marker_rtl { width:40px; background-position:right center; } ';
16
+ if(parseInt(v) == 7) css += '.tree .rtl li.last { float:none; } #jstree-dragged .rtl { width:200px; }';
17
+ }
18
+ if(/mozilla/.test(u) && !/(compatible|webkit)/.test(u) && v.indexOf("1.8") == 0) css += '.tree .rtl li a { display:inline; float:right; }';
19
+ $.tree.plugins.rtl.css = this.add_sheet({ str : css });
20
+ }
21
+ }
22
+ }
23
+ }
24
+ });
25
+ })(jQuery);
26
+
27
+ // in mousemove:
28
+ // tmp.drag_help.css({ "left" : (event.pageX - (tmp.origin_tree.settings.ui.rtl ? tmp.w : -5 ) ), "top" : (event.pageY + 15) });
29
+ // if(cnt.children("ul:eq(0)").hasClass("rtl")) goTo.x += et.width() - 28;
30
+ // if(cnt.children("ul:eq(0)").hasClass("rtl")) { tree_component.drag_drop.marker.attr("class","marker_rtl"); }
31
+ // if(cnt.children("ul:eq(0)").hasClass("rtl")) goTo.x += 36;
32
+ // tree_component.drag_drop.marker.css({ "left" : et_off.left + ( cnt.children("ul:eq(0)").hasClass("rtl") ? (cnt.width() - 10) : 10 ) , "top" : et_off.top + 15 }).show();
scripts/plugins/jquery.tree.cookie.js ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($) {
2
+ if(typeof $.cookie == "undefined") throw "jsTree cookie: jQuery cookie plugin not included.";
3
+
4
+ $.extend($.tree.plugins, {
5
+ "cookie" : {
6
+ defaults : {
7
+ prefix : "", // a prefix that will be used for all cookies for this tree
8
+ options : {
9
+ expires: false,
10
+ path: false,
11
+ domain: false,
12
+ secure: false
13
+ },
14
+ types : {
15
+ selected : true, // should we set the selected cookie
16
+ open : true // should we set the open cookie
17
+ },
18
+ keep_selected : false, // should we merge with the selected option or overwrite it
19
+ keep_opened : false // should we merge with the opened option or overwrite it
20
+ },
21
+ set_cookie : function (type) {
22
+ var opts = $.extend(true, {}, $.tree.plugins.cookie.defaults, this.settings.plugins.cookie);
23
+ if(opts.types[type] !== true) return false;
24
+ switch(type) {
25
+ case "selected":
26
+ if(this.settings.rules.multiple != false && this.selected_arr.length > 1) {
27
+ var val = Array();
28
+ $.each(this.selected_arr, function () {
29
+ if(this.attr("id")) { val.push(this.attr("id")); }
30
+ });
31
+ val = val.join(",");
32
+ }
33
+ else var val = this.selected ? this.selected.attr("id") : false;
34
+ $.cookie(opts.prefix + 'selected', val, opts.options);
35
+ break;
36
+ case "open":
37
+ var str = "";
38
+ this.container.find("li.open").each(function (i) { if(this.id) { str += this.id + ","; } });
39
+ $.cookie(opts.prefix + 'open', str.replace(/,$/ig,""), opts.options);
40
+ break;
41
+ }
42
+ },
43
+ callbacks : {
44
+ oninit : function (t) {
45
+ var opts = $.extend(true, {}, $.tree.plugins.cookie.defaults, this.settings.plugins.cookie);
46
+ var tmp = false;
47
+ tmp = $.cookie(opts.prefix + 'open');
48
+ if(tmp) {
49
+ tmp = tmp.split(",");
50
+ if(opts.keep_opened) this.settings.opened = $.unique($.merge(tmp, this.settings.opened));
51
+ else this.settings.opened = tmp;
52
+ }
53
+ tmp = $.cookie(opts.prefix + 'selected');
54
+ if(tmp) {
55
+ tmp = tmp.split(",");
56
+ if(opts.keep_selected) this.settings.selected = $.unique($.merge(tmp, this.settings.opened));
57
+ else this.settings.selected = tmp;
58
+ }
59
+ },
60
+ onchange : function() { $.tree.plugins.cookie.set_cookie.apply(this, ["selected"]); },
61
+ onopen : function() { $.tree.plugins.cookie.set_cookie.apply(this, ["open"]); },
62
+ onclose : function() { $.tree.plugins.cookie.set_cookie.apply(this, ["open"]); },
63
+ ondelete : function() { $.tree.plugins.cookie.set_cookie.apply(this, ["open"]); },
64
+ oncopy : function() { $.tree.plugins.cookie.set_cookie.apply(this, ["open"]); },
65
+ oncreate : function() { $.tree.plugins.cookie.set_cookie.apply(this, ["open"]); },
66
+ onmoved : function() { $.tree.plugins.cookie.set_cookie.apply(this, ["open"]); }
67
+ }
68
+ }
69
+ });
70
+ })(jQuery);
scripts/themes/default/dot_for_ie.gif ADDED
Binary file
scripts/themes/default/icons.png ADDED
Binary file
scripts/themes/default/style.css ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* LOCKED */
2
+ .tree-default .locked li a { color:gray; }
3
+ /* DOTS */
4
+ .tree-default ul { background-position:6px 1px; background-repeat:repeat-y; background-image:url(data:image/gif;base64,R0lGODlhAgACAIAAAB4dGf///yH5BAEAAAEALAAAAAACAAIAAAICRF4AOw==); _background-image:url("dot_for_ie.gif"); *background-image:url("dot_for_ie.gif"); }
5
+ .tree-default li { background-position:-64px -16px; background-repeat:no-repeat; background-image:url("icons.png"); }
6
+ /* NO DOTS */
7
+ .tree-default .no_dots, .tree-default .no_dots ul { background:transparent; }
8
+ .tree-default .no_dots li.leaf { background-image:none; background-color:transparent; }
9
+ /* OPEN or CLOSED */
10
+ .tree-default li.open { background:url("icons.png") -32px -48px no-repeat; }
11
+ .tree-default li.closed, #jstree-dragged.tree-default li li.open { background:url("icons.png") -48px -32px no-repeat; }
12
+ #jstree-marker { background-image:url("icons.png"); }
13
+ /* DEFAULT, HOVER, CLICKED, LOADING STATES */
14
+ .tree-default li a, .tree-default li span { border-radius:3px; -moz-border-radius:3px; -webkit-border-radius:3px; }
15
+ .tree-default li a:hover, .tree-default li a.hover, .tree-default li span { background: #e7f4f9; border:1px solid #d8f0fa; padding:0px 3px 0px 3px; }
16
+ .tree-default li a.clicked, .tree-default li a.clicked:hover, .tree-default li span.clicked { background: #beebff; border:1px solid #99defd; padding:0px 3px 0px 3px; }
17
+ /* ICONS */
18
+ .tree-default ins { background-image:url("icons.png"); background-position:0 0; background-repeat:no-repeat; }
19
+ .tree-default ul li a.loading ins { background-image:url("throbber.gif") !important; background-position:0 0 !important; } /* UL is added to make selector stronger */
20
+ .tree-default li a ins.forbidden { background-position:-16px -16px; }
21
+ .tree-default .locked li a ins { background-position:0 -48px; }
22
+ .tree-default li span ins { background-position:-16px 0; }
23
+ #jstree-dragged.tree-default ins { background:url("icons.png") -16px -32px no-repeat; }
24
+ #jstree-dragged.tree-default ins.forbidden { background:url("icons.png") -16px -16px no-repeat; }
25
+
26
+ /* CONTEXT MENU */
27
+ .tree-default-context a ins { background-image:url("icons.png"); background-repeat:no-repeat; background-position:-64px -64px; }
28
+ .tree-default-context a ins.create { background-position:0 -16px; }
29
+ .tree-default-context a ins.rename { background-position:-16px 0px; }
30
+ .tree-default-context a ins.remove { background-position:0 -32px; }
scripts/themes/default/throbber.gif ADDED
Binary file
styles/styles.css ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #cms_tpv_dashboard_widget {
3
+ z-index: 10;
4
+ }
5
+
6
+
7
+ #cms_tpv_container {
8
+ clear: both;
9
+ overflow: visible;
10
+ margin-top: 1.5em;
11
+ }
12
+
13
+ .pages_page_cms-tpv-pages-page .updated {
14
+ clear: both;
15
+ }
16
+
17
+ .cms-tpv-subsubsub li {
18
+ display: inline;
19
+ }
20
+
21
+ .cms-tpv-subsubsub li a.current {
22
+ font-weight: bold;
23
+ text-decoration: none;
24
+ color: black;
25
+ }
26
+
27
+ .pages_page_cms-tpv-pages-page .cms-tpv-subsubsub li {
28
+ zoom: 1; /* weird ie-problems otherwise, like li-items that disappear on search. */
29
+ }
30
+
31
+ #cms_tpv_search_no_hits {
32
+ clear: both;
33
+ }
34
+
35
+ .tree li {
36
+ margin-top: 2px !important;
37
+ margin-bottom: 2px !important;
38
+ }
39
+
40
+
41
+ .tree li span.cms_tpv_action_edit,
42
+ .tree li span.cms_tpv_action_view,
43
+ .tree li span.cms_tpv_action_add_page_after,
44
+ .tree li span.cms_tpv_action_add_page_inside
45
+ {
46
+ display: none;
47
+ text-decoration: underline;
48
+ border: 0;
49
+ -moz-border-radius: 0;
50
+ -webkit-border-radius: 0;
51
+ border-radius: 0;
52
+ padding: 0 0 0 .5ex;
53
+
54
+ }
55
+ .tree li span.cms_tpv_action_add_page {
56
+ display: none;
57
+ border: 0;
58
+ padding: 0 0 0 .5em;
59
+ color: #666;
60
+ }
61
+
62
+ .tree li a.search,
63
+ .cms-tree-view-search
64
+ {
65
+ background-color: #ffefba;
66
+ font-weight: bold;
67
+ font-family: "Lucida Grande",Verdana,Arial,"Bitstream Vera Sans",sans-serif;
68
+ font-size: 12px;
69
+ }
70
+
71
+
72
+ .cms_tpv_action_edit,
73
+ .cms_tpv_action_view,
74
+ .cms_tpv_action_add_page_after,
75
+ .cms_tpv_action_add_page_inside
76
+ {
77
+ color: #21759B !important;
78
+ }
79
+
80
+ .cms_tpv_action_edit:hover,
81
+ .cms_tpv_action_view:hover,
82
+ .cms_tpv_action_add_page_after:hover,
83
+ cms_tpv_action_add_page_inside:hover
84
+ {
85
+ color: #d54e21 !important;
86
+ }
87
+
88
+ .tree ins {
89
+ cursor: move;
90
+ }
91
+
92
+ .tree-default li.open,
93
+ .tree-default li.closed
94
+ {
95
+ margin-top: 4px !important;
96
+ margin-bottom: 4px !important;
97
+ cursor: pointer;
98
+ }
99
+
100
+ .tree-default span.child_count {
101
+ background-color: transparent;
102
+ color: #999;
103
+ border: none;
104
+ font-size: .8em;
105
+ }
106
+
107
+ .tree li:nth-child(odd) {
108
+ }
109
+
110
+ .tree-default span.post_type {
111
+ background-color: #f85b11;
112
+ -moz-border-radius: 2px;
113
+ -webkit-border-radius: 2px;
114
+ border-radius: 2px;
115
+ padding: 1px 4px 1px 4px;
116
+ color: white;
117
+ border: none;
118
+ font-size: .8em;
119
+ display: inline;
120
+ margin-right: .75ex;
121
+ }
122
+ .tree-default span.post_type_draft {
123
+
124
+ }
125
+ .tree-default span.post_type_password {
126
+ background-color: #25b61a;
127
+ }
128
+ .tree-default span.post_type_private {
129
+ background-color: #25b61a;
130
+ }
131
+ .tree-default span.post_type_pending,
132
+ .tree-default span.post_type_future
133
+ {
134
+ background-color: #0069e0;
135
+ }
136
+
137
+
138
+ #jstree-dragged {
139
+ background-color: white;
140
+ opacity: .9;
141
+ }
142
+
143
+ #cms_tpv_open_all
144
+ {
145
+ margin-left: 1em;
146
+ }
147
+
148
+ #cms_tree_view_search_form {
149
+ display: inline;
150
+ position: relative;
151
+ margin-left: 1em;
152
+ }
153
+
154
+
155
+ #cms_tpv_dashboard_widget #cms_tree_view_search_form {
156
+ display: block;
157
+ margin-left: 0;
158
+ margin-top: .5em;
159
+ }
160
+
161
+ #cms_tpv_dashboard_widget .cms-tpv-subsubsub {
162
+ margin-top: -6px;
163
+ position: relative;
164
+ right: auto;
165
+ left: auto;
166
+ top: auto;
167
+ bottom: auto;
168
+ }
169
+
170
+ #cms_tree_view_search {
171
+ width: 130px;
172
+ }
173
+ #cms_tree_view_search_form_working {
174
+ position: absolute;
175
+ left: 0;
176
+ top: 2em;
177
+ display: none;
178
+ }
179
+
180
+ #cms_tpv_working {
181
+ position: absolute;
182
+ line-height: 1;
183
+ display: none;
184
+ }