1/** 2 * Script for the tree management interface 3 */ 4 5var $GUI = jQuery('#plugin_move__tree'); 6 7$GUI.show(); 8jQuery('#plugin_move__treelink').show(); 9 10/** 11 * Checks if the given list item was moved in the tree 12 * 13 * Moved elements are highlighted and a title shows where they came from 14 * 15 * @param {jQuery} $li 16 */ 17var checkForMovement = function ($li) { 18 // we need to check this LI and all previously moved sub LIs 19 var $all = $li.add($li.find('li.moved')); 20 $all.each(function () { 21 var $this = jQuery(this); 22 var oldid = $this.data('id'); 23 var newid = determineNewID($this); 24 25 if (newid != oldid && !$this.hasClass('created')) { 26 $this.addClass('moved'); 27 $this.children('div').attr('title', oldid + ' -> ' + newid); 28 } else { 29 $this.removeClass('moved'); 30 $this.children('div').attr('title', ''); 31 } 32 }); 33}; 34 35/** 36 * Check if the given name is allowed in the given parent 37 * 38 * @param {jQuery} $li the edited or moved LI 39 * @param {jQuery} $parent the (new) parent of the edited or moved LI 40 * @param {string} name the (new) name to check 41 * @returns {boolean} 42 */ 43var checkNameAllowed = function ($li, $parent, name) { 44 var ok = true; 45 $parent.children('li').each(function () { 46 if (this === $li[0]) return; 47 var cname = 'type-f'; 48 if ($li.hasClass('type-d')) cname = 'type-d'; 49 50 var $this = jQuery(this); 51 if ($this.data('name') == name && $this.hasClass(cname)) ok = false; 52 }); 53 return ok; 54}; 55 56/** 57 * Returns the new ID of a given list item 58 * 59 * @param {jQuery} $li 60 * @returns {string} 61 */ 62var determineNewID = function ($li) { 63 var myname = $li.data('name'); 64 65 var $parent = $li.parent().closest('li'); 66 if ($parent.length) { 67 return (determineNewID($parent) + ':' + myname).replace(/^:/, ''); 68 } else { 69 return myname; 70 } 71}; 72 73/** 74 * Very simplistic cleanID() in JavaScript 75 * 76 * Strips out namespaces 77 * 78 * @param {string} id 79 */ 80var cleanID = function (id) { 81 if (!id) return ''; 82 83 id = id.replace(/[!"#$%§&\'()+,/;<=>?@\[\]^`\{|\}~\\;:\/\*]+/g, '_'); 84 id = id.replace(/^_+/, ''); 85 id = id.replace(/_+$/, ''); 86 id = id.toLowerCase(); 87 88 return id; 89}; 90 91/** 92 * Initialize the drag & drop-tree at the given li (must be this). 93 */ 94var initTree = function () { 95 var $li = jQuery(this); 96 var my_root = $li.closest('.tree_root')[0]; 97 $li.draggable({ 98 revert: true, 99 revertDuration: 0, 100 opacity: 0.5, 101 stop : function(event, ui) { 102 ui.helper.css({height: "auto", width: "auto"}); 103 } 104 }).droppable({ 105 tolerance: 'pointer', 106 greedy: true, 107 accept : function(draggable) { 108 return my_root == draggable.closest('.tree_root')[0]; 109 }, 110 drop : function (event, ui) { 111 var $dropped = ui.draggable; 112 var $me = jQuery(this); 113 114 if ($dropped.children('div.li').children('input').prop('checked')) { 115 $dropped = $dropped.add( 116 jQuery(my_root) 117 .find('input') 118 .filter(function() { 119 return jQuery(this).prop('checked'); 120 }).parent().parent() 121 ); 122 } 123 124 if ($me.parents().addBack().is($dropped)) { 125 return; 126 } 127 128 var insert_child = !($me.hasClass("type-f") || $me.hasClass("closed")); 129 var $new_parent = insert_child ? $me.children('ul') : $me.parent(); 130 var allowed = true; 131 132 $dropped.each(function () { 133 var $this = jQuery(this); 134 allowed &= checkNameAllowed($this, $new_parent, $this.data('name')); 135 }); 136 137 if (allowed) { 138 if (insert_child) { 139 $dropped.prependTo($new_parent); 140 } else { 141 $dropped.insertAfter($me); 142 } 143 } 144 145 checkForMovement($dropped); 146 } 147 }) 148 // add title to rename icon 149 .find('img.rename').attr('title', LANG.plugins.move.renameitem) 150 .end() 151 .find('img.add').attr('title', LANG.plugins.move.add); 152}; 153 154var add_template = '<li class="type-d open created" data-name="%s" data-id="%s"><div class="li"><input type="checkbox"> <a href="%s" class="idx_dir">%s</a><img class="rename" src="' + DOKU_BASE + 'lib/plugins/move/images/rename.png"></div><ul class="tree_list"></ul></li>'; 155 156/** 157 * Attach event listeners to the tree 158 */ 159$GUI.find('div.tree_root > ul.tree_list') 160 .click(function (e) { 161 var $clicky = jQuery(e.target); 162 var $li = $clicky.parent().parent(); 163 164 if ($clicky[0].tagName == 'A' && $li.hasClass('type-d')) { // Click on folder - open and close via AJAX 165 e.stopPropagation(); 166 if ($li.hasClass('open')) { 167 $li 168 .removeClass('open') 169 .addClass('closed'); 170 171 } else { 172 $li 173 .removeClass('closed') 174 .addClass('open'); 175 176 // if had not been loaded before, load via AJAX 177 if (!$li.find('ul').length) { 178 var is_media = $li.closest('div.tree_root').hasClass('tree_media') ? 1 : 0; 179 jQuery.post( 180 DOKU_BASE + 'lib/exe/ajax.php', 181 { 182 call: 'plugin_move_tree', 183 ns: $clicky.attr('href'), 184 is_media: is_media 185 }, 186 function (data) { 187 $li.append(data); 188 $li.find('li').each(initTree); 189 } 190 ); 191 } 192 } 193 e.preventDefault(); 194 } else if ($clicky[0].tagName == 'IMG') { // Click on IMG - do rename 195 e.stopPropagation(); 196 var $a = $clicky.parent().find('a'); 197 198 if ($clicky.hasClass('rename')) { 199 var newname = window.prompt(LANG.plugins.move.renameitem, $li.data('name')); 200 newname = cleanID(newname); 201 if (newname) { 202 if (checkNameAllowed($li, $li.parent(), newname)) { 203 $li.data('name', newname); 204 $a.text(newname); 205 checkForMovement($li); 206 } else { 207 alert(LANG.plugins.move.duplicate.replace('%s', newname)); 208 } 209 } 210 } else { 211 var newname = window.prompt(LANG.plugins.move.add); 212 newname = cleanID(newname); 213 if (newname) { 214 if (checkNameAllowed($li, $li.children('ul'), newname)) { 215 var $new_li = jQuery(add_template.replace(/%s/g, newname)); 216 $li.children('ul').prepend($new_li); 217 218 $new_li.each(initTree); 219 } else { 220 alert(LANG.plugins.move.duplicate.replace('%s', newname)); 221 } 222 } 223 } 224 e.preventDefault(); 225 } 226 }).find('li').each(initTree); 227 228/** 229 * Gather all moves from the trees and put them as JSON into the form before submit 230 * 231 * @fixme has some duplicate code 232 */ 233jQuery('#plugin_move__tree_execute').submit(function (e) { 234 var data = []; 235 236 $GUI.find('.tree_pages .moved').each(function (idx, el) { 237 var $el = jQuery(el); 238 var newid = determineNewID($el); 239 240 data[data.length] = { 241 'class': $el.hasClass('type-d') ? 'ns' : 'doc', 242 type: 'page', 243 src: $el.data('id'), 244 dst: newid 245 }; 246 }); 247 $GUI.find('.tree_media .moved').each(function (idx, el) { 248 var $el = jQuery(el); 249 var newid = determineNewID($el); 250 251 data[data.length] = { 252 'class': $el.hasClass('type-d') ? 'ns' : 'doc', 253 type: 'media', 254 src: $el.data('id'), 255 dst: newid 256 }; 257 }); 258 259 jQuery(this).find('input[name=json]').val(JSON.stringify(data)); 260}); 261