comparison OrthancServer/OrthancExplorer/libs/tree.jquery.js @ 4044:d25f4c0fa160 framework

splitting code into OrthancFramework and OrthancServer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 10 Jun 2020 20:30:34 +0200
parents OrthancExplorer/libs/tree.jquery.js@4bc019d2f969
children
comparison
equal deleted inserted replaced
4043:6c6239aec462 4044:d25f4c0fa160
1 // Generated by CoffeeScript 1.3.3
2
3 /*
4 Copyright 2012 Marco Braak
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 */
18
19
20 (function() {
21 var $, BorderDropHint, DragAndDropHandler, DragElement, FolderElement, GhostDropHint, JqTreeWidget, Json, MouseWidget, Node, NodeElement, Position, SaveStateHandler, SelectNodeHandler, SimpleWidget, Tree, html_escape, indexOf, toJson,
22 __slice = [].slice,
23 __hasProp = {}.hasOwnProperty,
24 __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
25
26 $ = this.jQuery;
27
28 SimpleWidget = (function() {
29
30 SimpleWidget.prototype.defaults = {};
31
32 function SimpleWidget(el, options) {
33 this.$el = $(el);
34 this.options = $.extend({}, this.defaults, options);
35 this._init();
36 }
37
38 SimpleWidget.prototype.destroy = function() {
39 return this._deinit();
40 };
41
42 SimpleWidget.prototype._init = function() {
43 return null;
44 };
45
46 SimpleWidget.prototype._deinit = function() {
47 return null;
48 };
49
50 SimpleWidget.register = function(widget_class, widget_name) {
51 var callFunction, createWidget, destroyWidget, getDataKey;
52 getDataKey = function() {
53 return "simple_widget_" + widget_name;
54 };
55 createWidget = function($el, options) {
56 var data_key;
57 data_key = getDataKey();
58 $el.each(function() {
59 var widget;
60 widget = new widget_class(this, options);
61 if (!$.data(this, data_key)) {
62 return $.data(this, data_key, widget);
63 }
64 });
65 return $el;
66 };
67 destroyWidget = function($el) {
68 var data_key;
69 data_key = getDataKey();
70 return $el.each(function() {
71 var widget;
72 widget = $.data(this, data_key);
73 if (widget && (widget instanceof SimpleWidget)) {
74 widget.destroy();
75 }
76 return $.removeData(this, data_key);
77 });
78 };
79 callFunction = function($el, function_name, args) {
80 var result;
81 result = null;
82 $el.each(function() {
83 var widget, widget_function;
84 widget = $.data(this, getDataKey());
85 if (widget && (widget instanceof SimpleWidget)) {
86 widget_function = widget[function_name];
87 if (widget_function && (typeof widget_function === 'function')) {
88 return result = widget_function.apply(widget, args);
89 }
90 }
91 });
92 return result;
93 };
94 return $.fn[widget_name] = function() {
95 var $el, args, argument1, function_name, options;
96 argument1 = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
97 $el = this;
98 if (argument1 === void 0 || typeof argument1 === 'object') {
99 options = argument1;
100 return createWidget($el, options);
101 } else if (typeof argument1 === 'string' && argument1[0] !== '_') {
102 function_name = argument1;
103 if (function_name === 'destroy') {
104 return destroyWidget($el);
105 } else {
106 return callFunction($el, function_name, args);
107 }
108 }
109 };
110 };
111
112 return SimpleWidget;
113
114 })();
115
116 this.SimpleWidget = SimpleWidget;
117
118 /*
119 This widget does the same a the mouse widget in jqueryui.
120 */
121
122
123 MouseWidget = (function(_super) {
124
125 __extends(MouseWidget, _super);
126
127 function MouseWidget() {
128 return MouseWidget.__super__.constructor.apply(this, arguments);
129 }
130
131 MouseWidget.is_mouse_handled = false;
132
133 MouseWidget.prototype._init = function() {
134 this.$el.bind('mousedown.mousewidget', $.proxy(this._mouseDown, this));
135 return this.is_mouse_started = false;
136 };
137
138 MouseWidget.prototype._deinit = function() {
139 var $document;
140 this.$el.unbind('mousedown.mousewidget');
141 $document = $(document);
142 $document.unbind('mousemove.mousewidget');
143 return $document.unbind('mouseup.mousewidget');
144 };
145
146 MouseWidget.prototype._mouseDown = function(e) {
147 var $document;
148 if (MouseWidget.is_mouse_handled) {
149 return;
150 }
151 if (!this.is_mouse_started) {
152 this._mouseUp(e);
153 }
154 if (e.which !== 1) {
155 return;
156 }
157 if (!this._mouseCapture(e)) {
158 return;
159 }
160 this.mouse_down_event = e;
161 $document = $(document);
162 $document.bind('mousemove.mousewidget', $.proxy(this._mouseMove, this));
163 $document.bind('mouseup.mousewidget', $.proxy(this._mouseUp, this));
164 e.preventDefault();
165 this.is_mouse_handled = true;
166 return true;
167 };
168
169 MouseWidget.prototype._mouseMove = function(e) {
170 if (this.is_mouse_started) {
171 this._mouseDrag(e);
172 return e.preventDefault();
173 }
174 this.is_mouse_started = this._mouseStart(this.mouse_down_event) !== false;
175 if (this.is_mouse_started) {
176 this._mouseDrag(e);
177 } else {
178 this._mouseUp(e);
179 }
180 return !this.is_mouse_started;
181 };
182
183 MouseWidget.prototype._mouseUp = function(e) {
184 var $document;
185 $document = $(document);
186 $document.unbind('mousemove.mousewidget');
187 $document.unbind('mouseup.mousewidget');
188 if (this.is_mouse_started) {
189 this.is_mouse_started = false;
190 this._mouseStop(e);
191 }
192 return false;
193 };
194
195 MouseWidget.prototype._mouseCapture = function(e) {
196 return true;
197 };
198
199 MouseWidget.prototype._mouseStart = function(e) {
200 return null;
201 };
202
203 MouseWidget.prototype._mouseDrag = function(e) {
204 return null;
205 };
206
207 MouseWidget.prototype._mouseStop = function(e) {
208 return null;
209 };
210
211 return MouseWidget;
212
213 })(SimpleWidget);
214
215 /*
216 Copyright 2012 Marco Braak
217
218 Licensed under the Apache License, Version 2.0 (the "License");
219 you may not use this file except in compliance with the License.
220 You may obtain a copy of the License at
221
222 http://www.apache.org/licenses/LICENSE-2.0
223
224 Unless required by applicable law or agreed to in writing, software
225 distributed under the License is distributed on an "AS IS" BASIS,
226 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
227 See the License for the specific language governing permissions and
228 limitations under the License.
229 */
230
231
232 this.Tree = {};
233
234 $ = this.jQuery;
235
236 indexOf = function(array, item) {
237 var i, value, _i, _len;
238 if (array.indexOf) {
239 return array.indexOf(item);
240 } else {
241 for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) {
242 value = array[i];
243 if (value === item) {
244 return i;
245 }
246 }
247 return -1;
248 }
249 };
250
251 this.Tree.indexOf = indexOf;
252
253 Json = {};
254
255 Json.escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
256
257 Json.meta = {
258 '\b': '\\b',
259 '\t': '\\t',
260 '\n': '\\n',
261 '\f': '\\f',
262 '\r': '\\r',
263 '"': '\\"',
264 '\\': '\\\\'
265 };
266
267 Json.quote = function(string) {
268 Json.escapable.lastIndex = 0;
269 if (Json.escapable.test(string)) {
270 return '"' + string.replace(Json.escapable, function(a) {
271 var c;
272 c = Json.meta[a];
273 return (typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4));
274 }) + '"';
275 } else {
276 return '"' + string + '"';
277 }
278 };
279
280 Json.str = function(key, holder) {
281 var i, k, partial, v, value, _i, _len;
282 value = holder[key];
283 switch (typeof value) {
284 case 'string':
285 return Json.quote(value);
286 case 'number':
287 if (isFinite(value)) {
288 return String(value);
289 } else {
290 return 'null';
291 }
292 case 'boolean':
293 case 'null':
294 return String(value);
295 case 'object':
296 if (!value) {
297 return 'null';
298 }
299 partial = [];
300 if (Object.prototype.toString.apply(value) === '[object Array]') {
301 for (i = _i = 0, _len = value.length; _i < _len; i = ++_i) {
302 v = value[i];
303 partial[i] = Json.str(i, value) || 'null';
304 }
305 return (partial.length === 0 ? '[]' : '[' + partial.join(',') + ']');
306 }
307 for (k in value) {
308 if (Object.prototype.hasOwnProperty.call(value, k)) {
309 v = Json.str(k, value);
310 if (v) {
311 partial.push(Json.quote(k) + ':' + v);
312 }
313 }
314 }
315 return (partial.length === 0 ? '{}' : '{' + partial.join(',') + '}');
316 }
317 };
318
319 toJson = function(value) {
320 return Json.str('', {
321 '': value
322 });
323 };
324
325 this.Tree.toJson = toJson;
326
327 html_escape = function(string) {
328 return ('' + string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g, '&#x2F;');
329 };
330
331 Position = {
332 getName: function(position) {
333 if (position === Position.BEFORE) {
334 return 'before';
335 } else if (position === Position.AFTER) {
336 return 'after';
337 } else if (position === Position.INSIDE) {
338 return 'inside';
339 } else {
340 return 'none';
341 }
342 }
343 };
344
345 Position.BEFORE = 1;
346
347 Position.AFTER = 2;
348
349 Position.INSIDE = 3;
350
351 Position.NONE = 4;
352
353 this.Tree.Position = Position;
354
355 Node = (function() {
356
357 function Node(o) {
358 this.setData(o);
359 }
360
361 Node.prototype.setData = function(o) {
362 var key, value;
363 if (typeof o !== 'object') {
364 this.name = o;
365 } else {
366 for (key in o) {
367 value = o[key];
368 if (key === 'label') {
369 this.name = value;
370 } else {
371 this[key] = value;
372 }
373 }
374 }
375 this.children = [];
376 return this.parent = null;
377 };
378
379 Node.prototype.initFromData = function(data) {
380 var addChildren, addNode,
381 _this = this;
382 addNode = function(node_data) {
383 _this.setData(node_data);
384 if (node_data.children) {
385 return addChildren(node_data.children);
386 }
387 };
388 addChildren = function(children_data) {
389 var child, node, _i, _len;
390 for (_i = 0, _len = children_data.length; _i < _len; _i++) {
391 child = children_data[_i];
392 node = new Node('');
393 node.initFromData(child);
394 _this.addChild(node);
395 }
396 return null;
397 };
398 addNode(data);
399 return null;
400 };
401
402 /*
403 Create tree from data.
404
405 Structure of data is:
406 [
407 {
408 label: 'node1',
409 children: [
410 { label: 'child1' },
411 { label: 'child2' }
412 ]
413 },
414 {
415 label: 'node2'
416 }
417 ]
418 */
419
420
421 Node.prototype.loadFromData = function(data) {
422 var node, o, _i, _len;
423 this.children = [];
424 for (_i = 0, _len = data.length; _i < _len; _i++) {
425 o = data[_i];
426 node = new Node(o);
427 this.addChild(node);
428 if (typeof o === 'object' && o.children) {
429 node.loadFromData(o.children);
430 }
431 }
432 return null;
433 };
434
435 /*
436 Add child.
437
438 tree.addChild(
439 new Node('child1')
440 );
441 */
442
443
444 Node.prototype.addChild = function(node) {
445 this.children.push(node);
446 return node._setParent(this);
447 };
448
449 /*
450 Add child at position. Index starts at 0.
451
452 tree.addChildAtPosition(
453 new Node('abc'),
454 1
455 );
456 */
457
458
459 Node.prototype.addChildAtPosition = function(node, index) {
460 this.children.splice(index, 0, node);
461 return node._setParent(this);
462 };
463
464 Node.prototype._setParent = function(parent) {
465 this.parent = parent;
466 this.tree = parent.tree;
467 return this.tree.addNodeToIndex(this);
468 };
469
470 /*
471 Remove child.
472
473 tree.removeChild(tree.children[0]);
474 */
475
476
477 Node.prototype.removeChild = function(node) {
478 this.children.splice(this.getChildIndex(node), 1);
479 return this.tree.removeNodeFromIndex(node);
480 };
481
482 /*
483 Get child index.
484
485 var index = getChildIndex(node);
486 */
487
488
489 Node.prototype.getChildIndex = function(node) {
490 return $.inArray(node, this.children);
491 };
492
493 /*
494 Does the tree have children?
495
496 if (tree.hasChildren()) {
497 //
498 }
499 */
500
501
502 Node.prototype.hasChildren = function() {
503 return this.children.length !== 0;
504 };
505
506 /*
507 Iterate over all the nodes in the tree.
508
509 Calls callback with (node, level).
510
511 The callback must return true to continue the iteration on current node.
512
513 tree.iterate(
514 function(node, level) {
515 console.log(node.name);
516
517 // stop iteration after level 2
518 return (level <= 2);
519 }
520 );
521 */
522
523
524 Node.prototype.iterate = function(callback) {
525 var _iterate,
526 _this = this;
527 _iterate = function(node, level) {
528 var child, result, _i, _len, _ref;
529 if (node.children) {
530 _ref = node.children;
531 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
532 child = _ref[_i];
533 result = callback(child, level);
534 if (_this.hasChildren() && result) {
535 _iterate(child, level + 1);
536 }
537 }
538 return null;
539 }
540 };
541 _iterate(this, 0);
542 return null;
543 };
544
545 /*
546 Move node relative to another node.
547
548 Argument position: Position.BEFORE, Position.AFTER or Position.Inside
549
550 // move node1 after node2
551 tree.moveNode(node1, node2, Position.AFTER);
552 */
553
554
555 Node.prototype.moveNode = function(moved_node, target_node, position) {
556 moved_node.parent.removeChild(moved_node);
557 if (position === Position.AFTER) {
558 return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node) + 1);
559 } else if (position === Position.BEFORE) {
560 return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node));
561 } else if (position === Position.INSIDE) {
562 return target_node.addChildAtPosition(moved_node, 0);
563 }
564 };
565
566 /*
567 Get the tree as data.
568 */
569
570
571 Node.prototype.getData = function() {
572 var getDataFromNodes,
573 _this = this;
574 getDataFromNodes = function(nodes) {
575 var data, k, node, tmp_node, v, _i, _len;
576 data = [];
577 for (_i = 0, _len = nodes.length; _i < _len; _i++) {
578 node = nodes[_i];
579 tmp_node = {};
580 for (k in node) {
581 v = node[k];
582 if ((k !== 'parent' && k !== 'children' && k !== 'element' && k !== 'tree') && Object.prototype.hasOwnProperty.call(node, k)) {
583 tmp_node[k] = v;
584 }
585 }
586 if (node.hasChildren()) {
587 tmp_node.children = getDataFromNodes(node.children);
588 }
589 data.push(tmp_node);
590 }
591 return data;
592 };
593 return getDataFromNodes(this.children);
594 };
595
596 Node.prototype.getNodeByName = function(name) {
597 var result;
598 result = null;
599 this.iterate(function(node) {
600 if (node.name === name) {
601 result = node;
602 return false;
603 } else {
604 return true;
605 }
606 });
607 return result;
608 };
609
610 Node.prototype.addAfter = function(node_info) {
611 var child_index, node;
612 if (!this.parent) {
613 return null;
614 } else {
615 node = new Node(node_info);
616 child_index = this.parent.getChildIndex(this);
617 this.parent.addChildAtPosition(node, child_index + 1);
618 return node;
619 }
620 };
621
622 Node.prototype.addBefore = function(node_info) {
623 var child_index, node;
624 if (!this.parent) {
625 return null;
626 } else {
627 node = new Node(node_info);
628 child_index = this.parent.getChildIndex(this);
629 return this.parent.addChildAtPosition(node, child_index);
630 }
631 };
632
633 Node.prototype.addParent = function(node_info) {
634 var child, new_parent, original_parent, _i, _len, _ref;
635 if (!this.parent) {
636 return null;
637 } else {
638 new_parent = new Node(node_info);
639 new_parent._setParent(this.tree);
640 original_parent = this.parent;
641 _ref = original_parent.children;
642 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
643 child = _ref[_i];
644 new_parent.addChild(child);
645 }
646 original_parent.children = [];
647 original_parent.addChild(new_parent);
648 return new_parent;
649 }
650 };
651
652 Node.prototype.remove = function() {
653 if (this.parent) {
654 this.parent.removeChild(this);
655 return this.parent = null;
656 }
657 };
658
659 Node.prototype.append = function(node_info) {
660 var node;
661 node = new Node(node_info);
662 this.addChild(node);
663 return node;
664 };
665
666 Node.prototype.prepend = function(node_info) {
667 var node;
668 node = new Node(node_info);
669 this.addChildAtPosition(node, 0);
670 return node;
671 };
672
673 return Node;
674
675 })();
676
677 Tree = (function(_super) {
678
679 __extends(Tree, _super);
680
681 function Tree(o) {
682 Tree.__super__.constructor.call(this, o, null, true);
683 this.id_mapping = {};
684 this.tree = this;
685 }
686
687 Tree.prototype.getNodeById = function(node_id) {
688 return this.id_mapping[node_id];
689 };
690
691 Tree.prototype.addNodeToIndex = function(node) {
692 if (node.id) {
693 return this.id_mapping[node.id] = node;
694 }
695 };
696
697 Tree.prototype.removeNodeFromIndex = function(node) {
698 if (node.id) {
699 return delete this.id_mapping[node.id];
700 }
701 };
702
703 return Tree;
704
705 })(Node);
706
707 this.Tree.Tree = Tree;
708
709 JqTreeWidget = (function(_super) {
710
711 __extends(JqTreeWidget, _super);
712
713 function JqTreeWidget() {
714 return JqTreeWidget.__super__.constructor.apply(this, arguments);
715 }
716
717 JqTreeWidget.prototype.defaults = {
718 autoOpen: false,
719 saveState: false,
720 dragAndDrop: false,
721 selectable: false,
722 onCanSelectNode: null,
723 onSetStateFromStorage: null,
724 onGetStateFromStorage: null,
725 onCreateLi: null,
726 onIsMoveHandle: null,
727 onCanMove: null,
728 onCanMoveTo: null,
729 autoEscape: true,
730 dataUrl: null
731 };
732
733 JqTreeWidget.prototype.toggle = function(node) {
734 if (node.hasChildren()) {
735 new FolderElement(node, this.element).toggle();
736 }
737 return this._saveState();
738 };
739
740 JqTreeWidget.prototype.getTree = function() {
741 return this.tree;
742 };
743
744 JqTreeWidget.prototype.selectNode = function(node, must_open_parents) {
745 return this.select_node_handler.selectNode(node, must_open_parents);
746 };
747
748 JqTreeWidget.prototype.getSelectedNode = function() {
749 return this.selected_node || false;
750 };
751
752 JqTreeWidget.prototype.toJson = function() {
753 return toJson(this.tree.getData());
754 };
755
756 JqTreeWidget.prototype.loadData = function(data, parent_node) {
757 var child, subtree, _i, _len, _ref;
758 if (!parent_node) {
759 this._initTree(data);
760 } else {
761 subtree = new Node('');
762 subtree._setParent(parent_node.tree);
763 subtree.loadFromData(data);
764 _ref = subtree.children;
765 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
766 child = _ref[_i];
767 parent_node.addChild(child);
768 }
769 this._refreshElements(parent_node.parent);
770 }
771 if (this.is_dragging) {
772 return this.dnd_handler.refreshHitAreas();
773 }
774 };
775
776 JqTreeWidget.prototype.getNodeById = function(node_id) {
777 return this.tree.getNodeById(node_id);
778 };
779
780 JqTreeWidget.prototype.getNodeByName = function(name) {
781 return this.tree.getNodeByName(name);
782 };
783
784 JqTreeWidget.prototype.openNode = function(node, skip_slide) {
785 if (node.hasChildren()) {
786 new FolderElement(node, this.element).open(null, skip_slide);
787 return this._saveState();
788 }
789 };
790
791 JqTreeWidget.prototype.closeNode = function(node, skip_slide) {
792 if (node.hasChildren()) {
793 new FolderElement(node, this.element).close(skip_slide);
794 return this._saveState();
795 }
796 };
797
798 JqTreeWidget.prototype.isDragging = function() {
799 return this.is_dragging;
800 };
801
802 JqTreeWidget.prototype.refreshHitAreas = function() {
803 return this.dnd_handler.refreshHitAreas();
804 };
805
806 JqTreeWidget.prototype.addNodeAfter = function(new_node_info, existing_node) {
807 var new_node;
808 new_node = existing_node.addAfter(new_node_info);
809 this._refreshElements(existing_node.parent);
810 return new_node;
811 };
812
813 JqTreeWidget.prototype.addNodeBefore = function(new_node_info, existing_node) {
814 var new_node;
815 new_node = existing_node.addBefore(new_node_info);
816 this._refreshElements(existing_node.parent);
817 return new_node;
818 };
819
820 JqTreeWidget.prototype.addParentNode = function(new_node_info, existing_node) {
821 var new_node;
822 new_node = existing_node.addParent(new_node_info);
823 this._refreshElements(new_node.parent);
824 return new_node;
825 };
826
827 JqTreeWidget.prototype.removeNode = function(node) {
828 var parent;
829 parent = node.parent;
830 if (parent) {
831 node.remove();
832 return this._refreshElements(parent.parent);
833 }
834 };
835
836 JqTreeWidget.prototype.appendNode = function(new_node_info, parent_node) {
837 var is_already_root_node, node;
838 if (!parent_node) {
839 parent_node = this.tree;
840 }
841 is_already_root_node = parent_node.hasChildren();
842 node = parent_node.append(new_node_info);
843 if (is_already_root_node) {
844 this._refreshElements(parent_node);
845 } else {
846 this._refreshElements(parent_node.parent);
847 }
848 return node;
849 };
850
851 JqTreeWidget.prototype.prependNode = function(new_node_info, parent_node) {
852 var node;
853 if (!parent_node) {
854 parent_node = this.tree;
855 }
856 node = parent_node.prepend(new_node_info);
857 this._refreshElements(parent_node);
858 return node;
859 };
860
861 JqTreeWidget.prototype._init = function() {
862 JqTreeWidget.__super__._init.call(this);
863 this.element = this.$el;
864 this._initData();
865 this.element.click($.proxy(this._click, this));
866 return this.element.bind('contextmenu', $.proxy(this._contextmenu, this));
867 };
868
869 JqTreeWidget.prototype._deinit = function() {
870 this.element.empty();
871 this.element.unbind();
872 this.tree = null;
873 return JqTreeWidget.__super__._deinit.call(this);
874 };
875
876 JqTreeWidget.prototype._initData = function() {
877 var data_url,
878 _this = this;
879 if (this.options.data) {
880 return this._initTree(this.options.data);
881 } else {
882 data_url = this.options.dataUrl || this.element.data('url');
883 if (data_url) {
884 return $.ajax({
885 url: data_url,
886 cache: false,
887 success: function(response) {
888 var data;
889 if ($.isArray(response) || typeof response === 'object') {
890 data = response;
891 } else {
892 data = $.parseJSON(response);
893 }
894 return _this._initTree(data);
895 }
896 });
897 }
898 }
899 };
900
901 JqTreeWidget.prototype._initTree = function(data) {
902 var event;
903 this.tree = new Tree();
904 this.tree.loadFromData(data);
905 this.selected_node = null;
906 this.save_state_handler = new SaveStateHandler(this);
907 this.select_node_handler = new SelectNodeHandler(this);
908 this.dnd_handler = new DragAndDropHandler(this);
909 this._openNodes();
910 this._refreshElements();
911 this.select_node_handler.selectCurrentNode();
912 event = $.Event('tree.init');
913 return this.element.trigger(event);
914 };
915
916 JqTreeWidget.prototype._openNodes = function() {
917 var max_level;
918 if (this.options.saveState) {
919 if (this.save_state_handler.restoreState()) {
920 return;
921 }
922 }
923 if (this.options.autoOpen === false) {
924 return;
925 } else if (this.options.autoOpen === true) {
926 max_level = -1;
927 } else {
928 max_level = parseInt(this.options.autoOpen);
929 }
930 return this.tree.iterate(function(node, level) {
931 node.is_open = true;
932 return level !== max_level;
933 });
934 };
935
936 JqTreeWidget.prototype._refreshElements = function(from_node) {
937 var $element, createFolderLi, createLi, createNodeLi, createUl, doCreateDomElements, escapeIfNecessary, is_root_node, node_element,
938 _this = this;
939 if (from_node == null) {
940 from_node = null;
941 }
942 escapeIfNecessary = function(value) {
943 if (_this.options.autoEscape) {
944 return html_escape(value);
945 } else {
946 return value;
947 }
948 };
949 createUl = function(is_root_node) {
950 var class_string;
951 if (is_root_node) {
952 class_string = ' class="tree"';
953 } else {
954 class_string = '';
955 }
956 return $("<ul" + class_string + "></ul>");
957 };
958 createLi = function(node) {
959 var $li;
960 if (node.hasChildren()) {
961 $li = createFolderLi(node);
962 } else {
963 $li = createNodeLi(node);
964 }
965 if (_this.options.onCreateLi) {
966 _this.options.onCreateLi(node, $li);
967 }
968 return $li;
969 };
970 createNodeLi = function(node) {
971 var escaped_name;
972 escaped_name = escapeIfNecessary(node.name);
973 return $("<li><div><span class=\"title\">" + escaped_name + "</span></div></li>");
974 };
975 createFolderLi = function(node) {
976 var button_class, escaped_name, folder_class, getButtonClass, getFolderClass;
977 getButtonClass = function() {
978 var classes;
979 classes = ['toggler'];
980 if (!node.is_open) {
981 classes.push('closed');
982 }
983 return classes.join(' ');
984 };
985 getFolderClass = function() {
986 var classes;
987 classes = ['folder'];
988 if (!node.is_open) {
989 classes.push('closed');
990 }
991 return classes.join(' ');
992 };
993 button_class = getButtonClass();
994 folder_class = getFolderClass();
995 escaped_name = escapeIfNecessary(node.name);
996 return $("<li class=\"" + folder_class + "\"><div><a class=\"" + button_class + "\">&raquo;</a><span class=\"title\">" + escaped_name + "</span></div></li>");
997 };
998 doCreateDomElements = function($element, children, is_root_node, is_open) {
999 var $li, $ul, child, _i, _len;
1000 $ul = createUl(is_root_node);
1001 $element.append($ul);
1002 for (_i = 0, _len = children.length; _i < _len; _i++) {
1003 child = children[_i];
1004 $li = createLi(child);
1005 $ul.append($li);
1006 child.element = $li[0];
1007 $li.data('node', child);
1008 if (child.hasChildren()) {
1009 doCreateDomElements($li, child.children, false, child.is_open);
1010 }
1011 }
1012 return null;
1013 };
1014 if (from_node && from_node.parent) {
1015 is_root_node = false;
1016 node_element = this._getNodeElementForNode(from_node);
1017 node_element.getUl().remove();
1018 $element = node_element.$element;
1019 } else {
1020 from_node = this.tree;
1021 $element = this.element;
1022 $element.empty();
1023 is_root_node = true;
1024 }
1025 return doCreateDomElements($element, from_node.children, is_root_node, is_root_node);
1026 };
1027
1028 JqTreeWidget.prototype._click = function(e) {
1029 var $target, event, node, node_element;
1030 if (e.ctrlKey) {
1031 return;
1032 }
1033 $target = $(e.target);
1034 if ($target.is('.toggler')) {
1035 node_element = this._getNodeElement($target);
1036 if (node_element && node_element.node.hasChildren()) {
1037 node_element.toggle();
1038 this._saveState();
1039 e.preventDefault();
1040 return e.stopPropagation();
1041 }
1042 } else if ($target.is('div') || $target.is('span')) {
1043 node = this._getNode($target);
1044 if (node) {
1045 if ((!this.options.onCanSelectNode) || this.options.onCanSelectNode(node)) {
1046 this.selectNode(node);
1047 event = $.Event('tree.click');
1048 event.node = node;
1049 return this.element.trigger(event);
1050 }
1051 }
1052 }
1053 };
1054
1055 JqTreeWidget.prototype._getNode = function($element) {
1056 var $li;
1057 $li = $element.closest('li');
1058 if ($li.length === 0) {
1059 return null;
1060 } else {
1061 return $li.data('node');
1062 }
1063 };
1064
1065 JqTreeWidget.prototype._getNodeElementForNode = function(node) {
1066 if (node.hasChildren()) {
1067 return new FolderElement(node, this.element);
1068 } else {
1069 return new NodeElement(node, this.element);
1070 }
1071 };
1072
1073 JqTreeWidget.prototype._getNodeElement = function($element) {
1074 var node;
1075 node = this._getNode($element);
1076 if (node) {
1077 return this._getNodeElementForNode(node);
1078 } else {
1079 return null;
1080 }
1081 };
1082
1083 JqTreeWidget.prototype._contextmenu = function(e) {
1084 var $div, event, node;
1085 $div = $(e.target).closest('ul.tree div');
1086 if ($div.length) {
1087 node = this._getNode($div);
1088 if (node) {
1089 e.preventDefault();
1090 e.stopPropagation();
1091 event = $.Event('tree.contextmenu');
1092 event.node = node;
1093 event.click_event = e;
1094 this.element.trigger(event);
1095 return false;
1096 }
1097 }
1098 };
1099
1100 JqTreeWidget.prototype._saveState = function() {
1101 if (this.options.saveState) {
1102 return this.save_state_handler.saveState();
1103 }
1104 };
1105
1106 JqTreeWidget.prototype._mouseCapture = function(event) {
1107 if (this.options.dragAndDrop) {
1108 return this.dnd_handler.mouseCapture(event);
1109 } else {
1110 return false;
1111 }
1112 };
1113
1114 JqTreeWidget.prototype._mouseStart = function(event) {
1115 if (this.options.dragAndDrop) {
1116 return this.dnd_handler.mouseStart(event);
1117 } else {
1118 return false;
1119 }
1120 };
1121
1122 JqTreeWidget.prototype._mouseDrag = function(event) {
1123 if (this.options.dragAndDrop) {
1124 return this.dnd_handler.mouseDrag(event);
1125 } else {
1126 return false;
1127 }
1128 };
1129
1130 JqTreeWidget.prototype._mouseStop = function() {
1131 if (this.options.dragAndDrop) {
1132 return this.dnd_handler.mouseStop();
1133 } else {
1134 return false;
1135 }
1136 };
1137
1138 JqTreeWidget.prototype.testGenerateHitAreas = function(moving_node) {
1139 this.dnd_handler.current_item = this._getNodeElementForNode(moving_node);
1140 this.dnd_handler.generateHitAreas();
1141 return this.dnd_handler.hit_areas;
1142 };
1143
1144 return JqTreeWidget;
1145
1146 })(MouseWidget);
1147
1148 SimpleWidget.register(JqTreeWidget, 'tree');
1149
1150 GhostDropHint = (function() {
1151
1152 function GhostDropHint(node, $element, position) {
1153 this.$element = $element;
1154 this.node = node;
1155 this.$ghost = $('<li class="ghost"><span class="circle"></span><span class="line"></span></li>');
1156 if (position === Position.AFTER) {
1157 this.moveAfter();
1158 } else if (position === Position.BEFORE) {
1159 this.moveBefore();
1160 } else if (position === Position.INSIDE) {
1161 if (node.hasChildren() && node.is_open) {
1162 this.moveInsideOpenFolder();
1163 } else {
1164 this.moveInside();
1165 }
1166 }
1167 }
1168
1169 GhostDropHint.prototype.remove = function() {
1170 return this.$ghost.remove();
1171 };
1172
1173 GhostDropHint.prototype.moveAfter = function() {
1174 return this.$element.after(this.$ghost);
1175 };
1176
1177 GhostDropHint.prototype.moveBefore = function() {
1178 return this.$element.before(this.$ghost);
1179 };
1180
1181 GhostDropHint.prototype.moveInsideOpenFolder = function() {
1182 return $(this.node.children[0].element).before(this.$ghost);
1183 };
1184
1185 GhostDropHint.prototype.moveInside = function() {
1186 this.$element.after(this.$ghost);
1187 return this.$ghost.addClass('inside');
1188 };
1189
1190 return GhostDropHint;
1191
1192 })();
1193
1194 BorderDropHint = (function() {
1195
1196 function BorderDropHint($element) {
1197 var $div, width;
1198 $div = $element.children('div');
1199 width = $element.width() - 4;
1200 this.$hint = $('<span class="border"></span>');
1201 $div.append(this.$hint);
1202 this.$hint.css({
1203 width: width,
1204 height: $div.height() - 4
1205 });
1206 }
1207
1208 BorderDropHint.prototype.remove = function() {
1209 return this.$hint.remove();
1210 };
1211
1212 return BorderDropHint;
1213
1214 })();
1215
1216 NodeElement = (function() {
1217
1218 function NodeElement(node, tree_element) {
1219 this.init(node, tree_element);
1220 }
1221
1222 NodeElement.prototype.init = function(node, tree_element) {
1223 this.node = node;
1224 this.tree_element = tree_element;
1225 return this.$element = $(node.element);
1226 };
1227
1228 NodeElement.prototype.getUl = function() {
1229 return this.$element.children('ul:first');
1230 };
1231
1232 NodeElement.prototype.getSpan = function() {
1233 return this.$element.children('div').find('span.title');
1234 };
1235
1236 NodeElement.prototype.getLi = function() {
1237 return this.$element;
1238 };
1239
1240 NodeElement.prototype.addDropHint = function(position) {
1241 if (position === Position.INSIDE) {
1242 return new BorderDropHint(this.$element);
1243 } else {
1244 return new GhostDropHint(this.node, this.$element, position);
1245 }
1246 };
1247
1248 NodeElement.prototype.select = function() {
1249 return this.getLi().addClass('selected');
1250 };
1251
1252 NodeElement.prototype.deselect = function() {
1253 return this.getLi().removeClass('selected');
1254 };
1255
1256 return NodeElement;
1257
1258 })();
1259
1260 FolderElement = (function(_super) {
1261
1262 __extends(FolderElement, _super);
1263
1264 function FolderElement() {
1265 return FolderElement.__super__.constructor.apply(this, arguments);
1266 }
1267
1268 FolderElement.prototype.toggle = function() {
1269 if (this.node.is_open) {
1270 return this.close();
1271 } else {
1272 return this.open();
1273 }
1274 };
1275
1276 FolderElement.prototype.open = function(on_finished, skip_slide) {
1277 var doOpen,
1278 _this = this;
1279 if (!this.node.is_open) {
1280 this.node.is_open = true;
1281 this.getButton().removeClass('closed');
1282 doOpen = function() {
1283 var event;
1284 _this.getLi().removeClass('closed');
1285 if (on_finished) {
1286 on_finished();
1287 }
1288 event = $.Event('tree.open');
1289 event.node = _this.node;
1290 return _this.tree_element.trigger(event);
1291 };
1292 if (skip_slide) {
1293 return doOpen();
1294 } else {
1295 return this.getUl().slideDown('fast', doOpen);
1296 }
1297 }
1298 };
1299
1300 FolderElement.prototype.close = function(skip_slide) {
1301 var doClose,
1302 _this = this;
1303 if (this.node.is_open) {
1304 this.node.is_open = false;
1305 this.getButton().addClass('closed');
1306 doClose = function() {
1307 var event;
1308 _this.getLi().addClass('closed');
1309 event = $.Event('tree.close');
1310 event.node = _this.node;
1311 return _this.tree_element.trigger(event);
1312 };
1313 if (skip_slide) {
1314 return doClose();
1315 } else {
1316 return this.getUl().slideUp('fast', doClose);
1317 }
1318 }
1319 };
1320
1321 FolderElement.prototype.getButton = function() {
1322 return this.$element.children('div').find('a.toggler');
1323 };
1324
1325 FolderElement.prototype.addDropHint = function(position) {
1326 if (!this.node.is_open && position === Position.INSIDE) {
1327 return new BorderDropHint(this.$element);
1328 } else {
1329 return new GhostDropHint(this.node, this.$element, position);
1330 }
1331 };
1332
1333 return FolderElement;
1334
1335 })(NodeElement);
1336
1337 DragElement = (function() {
1338
1339 function DragElement(node, offset_x, offset_y, $tree) {
1340 this.offset_x = offset_x;
1341 this.offset_y = offset_y;
1342 this.$element = $("<span class=\"title tree-dragging\">" + node.name + "</span>");
1343 this.$element.css("position", "absolute");
1344 $tree.append(this.$element);
1345 }
1346
1347 DragElement.prototype.move = function(page_x, page_y) {
1348 return this.$element.offset({
1349 left: page_x - this.offset_x,
1350 top: page_y - this.offset_y
1351 });
1352 };
1353
1354 DragElement.prototype.remove = function() {
1355 return this.$element.remove();
1356 };
1357
1358 return DragElement;
1359
1360 })();
1361
1362 SaveStateHandler = (function() {
1363
1364 function SaveStateHandler(tree_widget) {
1365 this.tree_widget = tree_widget;
1366 }
1367
1368 SaveStateHandler.prototype.saveState = function() {
1369 if (this.tree_widget.options.onSetStateFromStorage) {
1370 return this.tree_widget.options.onSetStateFromStorage(this.getState());
1371 } else if (typeof localStorage !== "undefined" && localStorage !== null) {
1372 return localStorage.setItem(this.getCookieName(), this.getState());
1373 } else if ($.cookie) {
1374 return $.cookie(this.getCookieName(), this.getState(), {
1375 path: '/'
1376 });
1377 }
1378 };
1379
1380 SaveStateHandler.prototype.restoreState = function() {
1381 var state;
1382 if (this.tree_widget.options.onGetStateFromStorage) {
1383 state = this.tree_widget.options.onGetStateFromStorage();
1384 } else if (typeof localStorage !== "undefined" && localStorage !== null) {
1385 state = localStorage.getItem(this.getCookieName());
1386 } else if ($.cookie) {
1387 state = $.cookie(this.getCookieName(), {
1388 path: '/'
1389 });
1390 } else {
1391 state = null;
1392 }
1393 if (!state) {
1394 return false;
1395 } else {
1396 this.setState(state);
1397 return true;
1398 }
1399 };
1400
1401 SaveStateHandler.prototype.getState = function() {
1402 var open_nodes, selected_node,
1403 _this = this;
1404 open_nodes = [];
1405 this.tree_widget.tree.iterate(function(node) {
1406 if (node.is_open && node.id && node.hasChildren()) {
1407 open_nodes.push(node.id);
1408 }
1409 return true;
1410 });
1411 selected_node = '';
1412 if (this.tree_widget.selected_node) {
1413 selected_node = this.tree_widget.selected_node.id;
1414 }
1415 return toJson({
1416 open_nodes: open_nodes,
1417 selected_node: selected_node
1418 });
1419 };
1420
1421 SaveStateHandler.prototype.setState = function(state) {
1422 var data, open_nodes, selected_node_id,
1423 _this = this;
1424 data = $.parseJSON(state);
1425 if (data) {
1426 open_nodes = data.open_nodes;
1427 selected_node_id = data.selected_node;
1428 return this.tree_widget.tree.iterate(function(node) {
1429 if (node.id && node.hasChildren() && (indexOf(open_nodes, node.id) >= 0)) {
1430 node.is_open = true;
1431 }
1432 if (selected_node_id && (node.id === selected_node_id)) {
1433 _this.tree_widget.selected_node = node;
1434 }
1435 return true;
1436 });
1437 }
1438 };
1439
1440 SaveStateHandler.prototype.getCookieName = function() {
1441 if (typeof this.tree_widget.options.saveState === 'string') {
1442 return this.tree_widget.options.saveState;
1443 } else {
1444 return 'tree';
1445 }
1446 };
1447
1448 return SaveStateHandler;
1449
1450 })();
1451
1452 SelectNodeHandler = (function() {
1453
1454 function SelectNodeHandler(tree_widget) {
1455 this.tree_widget = tree_widget;
1456 }
1457
1458 SelectNodeHandler.prototype.selectNode = function(node, must_open_parents) {
1459 var parent;
1460 if (this.tree_widget.options.selectable) {
1461 if (this.tree_widget.selected_node) {
1462 this.tree_widget._getNodeElementForNode(this.tree_widget.selected_node).deselect();
1463 this.tree_widget.selected_node = null;
1464 }
1465 if (node) {
1466 this.tree_widget._getNodeElementForNode(node).select();
1467 this.tree_widget.selected_node = node;
1468 if (must_open_parents) {
1469 parent = this.tree_widget.selected_node.parent;
1470 while (parent) {
1471 if (!parent.is_open) {
1472 this.tree_widget.openNode(parent, true);
1473 }
1474 parent = parent.parent;
1475 }
1476 }
1477 }
1478 if (this.tree_widget.options.saveState) {
1479 return this.tree_widget.save_state_handler.saveState();
1480 }
1481 }
1482 };
1483
1484 SelectNodeHandler.prototype.selectCurrentNode = function() {
1485 var node_element;
1486 if (this.tree_widget.selected_node) {
1487 node_element = this.tree_widget._getNodeElementForNode(this.tree_widget.selected_node);
1488 if (node_element) {
1489 return node_element.select();
1490 }
1491 }
1492 };
1493
1494 return SelectNodeHandler;
1495
1496 })();
1497
1498 DragAndDropHandler = (function() {
1499
1500 function DragAndDropHandler(tree_widget) {
1501 this.tree_widget = tree_widget;
1502 this.hovered_area = null;
1503 this.$ghost = null;
1504 this.hit_areas = [];
1505 this.is_dragging = false;
1506 }
1507
1508 DragAndDropHandler.prototype.mouseCapture = function(event) {
1509 var $element, node_element;
1510 $element = $(event.target);
1511 if (this.tree_widget.options.onIsMoveHandle && !this.tree_widget.options.onIsMoveHandle($element)) {
1512 return null;
1513 }
1514 node_element = this.tree_widget._getNodeElement($element);
1515 if (node_element && this.tree_widget.options.onCanMove) {
1516 if (!this.tree_widget.options.onCanMove(node_element.node)) {
1517 node_element = null;
1518 }
1519 }
1520 this.current_item = node_element;
1521 return this.current_item !== null;
1522 };
1523
1524 DragAndDropHandler.prototype.mouseStart = function(event) {
1525 var offsetX, offsetY, _ref;
1526 this.refreshHitAreas();
1527 _ref = this.getOffsetFromEvent(event), offsetX = _ref[0], offsetY = _ref[1];
1528 this.drag_element = new DragElement(this.current_item.node, offsetX, offsetY, this.tree_widget.element);
1529 this.is_dragging = true;
1530 this.current_item.$element.addClass('moving');
1531 return true;
1532 };
1533
1534 DragAndDropHandler.prototype.mouseDrag = function(event) {
1535 var area, position_name;
1536 this.drag_element.move(event.pageX, event.pageY);
1537 area = this.findHoveredArea(event.pageX, event.pageY);
1538 if (area && this.tree_widget.options.onCanMoveTo) {
1539 position_name = Position.getName(area.position);
1540 if (!this.tree_widget.options.onCanMoveTo(this.current_item.node, area.node, position_name)) {
1541 area = null;
1542 }
1543 }
1544 if (!area) {
1545 this.removeDropHint();
1546 this.removeHover();
1547 this.stopOpenFolderTimer();
1548 } else {
1549 if (this.hovered_area !== area) {
1550 this.hovered_area = area;
1551 this.updateDropHint();
1552 }
1553 }
1554 return true;
1555 };
1556
1557 DragAndDropHandler.prototype.mouseStop = function() {
1558 this.moveItem();
1559 this.clear();
1560 this.removeHover();
1561 this.removeDropHint();
1562 this.removeHitAreas();
1563 this.current_item.$element.removeClass('moving');
1564 this.is_dragging = false;
1565 return false;
1566 };
1567
1568 DragAndDropHandler.prototype.getOffsetFromEvent = function(event) {
1569 var element_offset;
1570 element_offset = $(event.target).offset();
1571 return [event.pageX - element_offset.left, event.pageY - element_offset.top];
1572 };
1573
1574 DragAndDropHandler.prototype.refreshHitAreas = function() {
1575 this.removeHitAreas();
1576 return this.generateHitAreas();
1577 };
1578
1579 DragAndDropHandler.prototype.removeHitAreas = function() {
1580 return this.hit_areas = [];
1581 };
1582
1583 DragAndDropHandler.prototype.clear = function() {
1584 this.drag_element.remove();
1585 return this.drag_element = null;
1586 };
1587
1588 DragAndDropHandler.prototype.removeDropHint = function() {
1589 if (this.previous_ghost) {
1590 return this.previous_ghost.remove();
1591 }
1592 };
1593
1594 DragAndDropHandler.prototype.removeHover = function() {
1595 return this.hovered_area = null;
1596 };
1597
1598 DragAndDropHandler.prototype.generateHitAreas = function() {
1599 var addPosition, getTop, groupPositions, handleAfterOpenFolder, handleClosedFolder, handleFirstNode, handleNode, handleOpenFolder, hit_areas, last_top, positions,
1600 _this = this;
1601 positions = [];
1602 last_top = 0;
1603 getTop = function($element) {
1604 return $element.offset().top;
1605 };
1606 addPosition = function(node, position, top) {
1607 positions.push({
1608 top: top,
1609 node: node,
1610 position: position
1611 });
1612 return last_top = top;
1613 };
1614 groupPositions = function(handle_group) {
1615 var group, position, previous_top, _i, _len;
1616 previous_top = -1;
1617 group = [];
1618 for (_i = 0, _len = positions.length; _i < _len; _i++) {
1619 position = positions[_i];
1620 if (position.top !== previous_top) {
1621 if (group.length) {
1622 handle_group(group, previous_top, position.top);
1623 }
1624 previous_top = position.top;
1625 group = [];
1626 }
1627 group.push(position);
1628 }
1629 return handle_group(group, previous_top, _this.tree_widget.element.offset().top + _this.tree_widget.element.height());
1630 };
1631 handleNode = function(node, next_node, $element) {
1632 var top;
1633 top = getTop($element);
1634 if (node === _this.current_item.node) {
1635 addPosition(node, Position.NONE, top);
1636 } else {
1637 addPosition(node, Position.INSIDE, top);
1638 }
1639 if (next_node === _this.current_item.node || node === _this.current_item.node) {
1640 return addPosition(node, Position.NONE, top);
1641 } else {
1642 return addPosition(node, Position.AFTER, top);
1643 }
1644 };
1645 handleOpenFolder = function(node, $element) {
1646 if (node === _this.current_item.node) {
1647 return false;
1648 }
1649 if (node.children[0] !== _this.current_item.node) {
1650 addPosition(node, Position.INSIDE, getTop($element));
1651 }
1652 return true;
1653 };
1654 handleAfterOpenFolder = function(node, next_node, $element) {
1655 if (node === _this.current_item.node || next_node === _this.current_item.node) {
1656 return addPosition(node, Position.NONE, last_top);
1657 } else {
1658 return addPosition(node, Position.AFTER, last_top);
1659 }
1660 };
1661 handleClosedFolder = function(node, next_node, $element) {
1662 var top;
1663 top = getTop($element);
1664 if (node === _this.current_item.node) {
1665 return addPosition(node, Position.NONE, top);
1666 } else {
1667 addPosition(node, Position.INSIDE, top);
1668 if (next_node !== _this.current_item.node) {
1669 return addPosition(node, Position.AFTER, top);
1670 }
1671 }
1672 };
1673 handleFirstNode = function(node, $element) {
1674 if (node !== _this.current_item.node) {
1675 return addPosition(node, Position.BEFORE, getTop($(node.element)));
1676 }
1677 };
1678 this.iterateVisibleNodes(handleNode, handleOpenFolder, handleClosedFolder, handleAfterOpenFolder, handleFirstNode);
1679 hit_areas = [];
1680 groupPositions(function(positions_in_group, top, bottom) {
1681 var area_height, area_top, position, _i, _len;
1682 area_height = (bottom - top) / positions_in_group.length;
1683 area_top = top;
1684 for (_i = 0, _len = positions_in_group.length; _i < _len; _i++) {
1685 position = positions_in_group[_i];
1686 hit_areas.push({
1687 top: area_top,
1688 bottom: area_top + area_height,
1689 node: position.node,
1690 position: position.position
1691 });
1692 area_top += area_height;
1693 }
1694 return null;
1695 });
1696 return this.hit_areas = hit_areas;
1697 };
1698
1699 DragAndDropHandler.prototype.iterateVisibleNodes = function(handle_node, handle_open_folder, handle_closed_folder, handle_after_open_folder, handle_first_node) {
1700 var is_first_node, iterate,
1701 _this = this;
1702 is_first_node = true;
1703 iterate = function(node, next_node) {
1704 var $element, child, children_length, i, must_iterate_inside, _i, _len, _ref;
1705 must_iterate_inside = (node.is_open || !node.element) && node.hasChildren();
1706 if (node.element) {
1707 $element = $(node.element);
1708 if (!$element.is(':visible')) {
1709 return;
1710 }
1711 if (is_first_node) {
1712 handle_first_node(node, $element);
1713 is_first_node = false;
1714 }
1715 if (!node.hasChildren()) {
1716 handle_node(node, next_node, $element);
1717 } else if (node.is_open) {
1718 if (!handle_open_folder(node, $element)) {
1719 must_iterate_inside = false;
1720 }
1721 } else {
1722 handle_closed_folder(node, next_node, $element);
1723 }
1724 }
1725 if (must_iterate_inside) {
1726 children_length = node.children.length;
1727 _ref = node.children;
1728 for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
1729 child = _ref[i];
1730 if (i === (children_length - 1)) {
1731 iterate(node.children[i], null);
1732 } else {
1733 iterate(node.children[i], node.children[i + 1]);
1734 }
1735 }
1736 if (node.is_open) {
1737 return handle_after_open_folder(node, next_node, $element);
1738 }
1739 }
1740 };
1741 return iterate(this.tree_widget.tree);
1742 };
1743
1744 DragAndDropHandler.prototype.findHoveredArea = function(x, y) {
1745 var area, high, low, mid, tree_offset;
1746 tree_offset = this.tree_widget.element.offset();
1747 if (x < tree_offset.left || y < tree_offset.top || x > (tree_offset.left + this.tree_widget.element.width()) || y > (tree_offset.top + this.tree_widget.element.height())) {
1748 return null;
1749 }
1750 low = 0;
1751 high = this.hit_areas.length;
1752 while (low < high) {
1753 mid = (low + high) >> 1;
1754 area = this.hit_areas[mid];
1755 if (y < area.top) {
1756 high = mid;
1757 } else if (y > area.bottom) {
1758 low = mid + 1;
1759 } else {
1760 return area;
1761 }
1762 }
1763 return null;
1764 };
1765
1766 DragAndDropHandler.prototype.updateDropHint = function() {
1767 var node, node_element;
1768 this.stopOpenFolderTimer();
1769 if (!this.hovered_area) {
1770 return;
1771 }
1772 node = this.hovered_area.node;
1773 if (node.hasChildren() && !node.is_open && this.hovered_area.position === Position.INSIDE) {
1774 this.startOpenFolderTimer(node);
1775 }
1776 this.removeDropHint();
1777 node_element = this.tree_widget._getNodeElementForNode(this.hovered_area.node);
1778 return this.previous_ghost = node_element.addDropHint(this.hovered_area.position);
1779 };
1780
1781 DragAndDropHandler.prototype.startOpenFolderTimer = function(folder) {
1782 var openFolder,
1783 _this = this;
1784 openFolder = function() {
1785 return _this.tree_widget._getNodeElementForNode(folder).open(function() {
1786 _this.refreshHitAreas();
1787 return _this.updateDropHint();
1788 });
1789 };
1790 return this.open_folder_timer = setTimeout(openFolder, 500);
1791 };
1792
1793 DragAndDropHandler.prototype.stopOpenFolderTimer = function() {
1794 if (this.open_folder_timer) {
1795 clearTimeout(this.open_folder_timer);
1796 return this.open_folder_timer = null;
1797 }
1798 };
1799
1800 DragAndDropHandler.prototype.moveItem = function() {
1801 var doMove, event, moved_node, position, previous_parent, target_node,
1802 _this = this;
1803 if (this.hovered_area && this.hovered_area.position !== Position.NONE) {
1804 moved_node = this.current_item.node;
1805 target_node = this.hovered_area.node;
1806 position = this.hovered_area.position;
1807 previous_parent = moved_node.parent;
1808 if (position === Position.INSIDE) {
1809 this.hovered_area.node.is_open = true;
1810 }
1811 doMove = function() {
1812 _this.tree_widget.tree.moveNode(moved_node, target_node, position);
1813 _this.tree_widget.element.empty();
1814 return _this.tree_widget._refreshElements();
1815 };
1816 event = $.Event('tree.move');
1817 event.move_info = {
1818 moved_node: moved_node,
1819 target_node: target_node,
1820 position: Position.getName(position),
1821 previous_parent: previous_parent,
1822 do_move: doMove
1823 };
1824 this.tree_widget.element.trigger(event);
1825 if (!event.isDefaultPrevented()) {
1826 return doMove();
1827 }
1828 }
1829 };
1830
1831 return DragAndDropHandler;
1832
1833 })();
1834
1835 this.Tree.Node = Node;
1836
1837 }).call(this);