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