- add sources.
[platform/framework/web/crosswalk.git] / src / tools / deep_memory_profiler / visualizer / static / third_party / jqTree / tree.jquery.js
1 // Generated by CoffeeScript 1.6.3
2 /*
3 Copyright 2013 Marco Braak
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9     http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 */
17
18
19 (function() {
20   var $, BorderDropHint, DragAndDropHandler, DragElement, FolderElement, GhostDropHint, JqTreeWidget, KeyHandler, MouseWidget, Node, NodeElement, Position, SaveStateHandler, ScrollHandler, SelectNodeHandler, SimpleWidget, html_escape, indexOf, json_escapable, json_meta, json_quote, json_str, _indexOf, _ref, _ref1, _ref2,
21     __slice = [].slice,
22     __hasProp = {}.hasOwnProperty,
23     __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; };
24
25   $ = this.jQuery;
26
27   SimpleWidget = (function() {
28     SimpleWidget.prototype.defaults = {};
29
30     function SimpleWidget(el, options) {
31       this.$el = $(el);
32       this.options = $.extend({}, this.defaults, options);
33     }
34
35     SimpleWidget.prototype.destroy = function() {
36       return this._deinit();
37     };
38
39     SimpleWidget.prototype._init = function() {
40       return null;
41     };
42
43     SimpleWidget.prototype._deinit = function() {
44       return null;
45     };
46
47     SimpleWidget.register = function(widget_class, widget_name) {
48       var callFunction, createWidget, destroyWidget, getDataKey;
49       getDataKey = function() {
50         return "simple_widget_" + widget_name;
51       };
52       createWidget = function($el, options) {
53         var data_key, el, widget, _i, _len;
54         data_key = getDataKey();
55         for (_i = 0, _len = $el.length; _i < _len; _i++) {
56           el = $el[_i];
57           widget = new widget_class(el, options);
58           if (!$.data(el, data_key)) {
59             $.data(el, data_key, widget);
60           }
61           widget._init();
62         }
63         return $el;
64       };
65       destroyWidget = function($el) {
66         var data_key, el, widget, _i, _len, _results;
67         data_key = getDataKey();
68         _results = [];
69         for (_i = 0, _len = $el.length; _i < _len; _i++) {
70           el = $el[_i];
71           widget = $.data(el, data_key);
72           if (widget && (widget instanceof SimpleWidget)) {
73             widget.destroy();
74           }
75           _results.push($.removeData(el, data_key));
76         }
77         return _results;
78       };
79       callFunction = function($el, function_name, args) {
80         var el, result, widget, widget_function, _i, _len;
81         result = null;
82         for (_i = 0, _len = $el.length; _i < _len; _i++) {
83           el = $el[_i];
84           widget = $.data(el, getDataKey());
85           if (widget && (widget instanceof SimpleWidget)) {
86             widget_function = widget[function_name];
87             if (widget_function && (typeof widget_function === 'function')) {
88               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     __extends(MouseWidget, _super);
125
126     function MouseWidget() {
127       _ref = MouseWidget.__super__.constructor.apply(this, arguments);
128       return _ref;
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       this.$el.bind('touchstart.mousewidget', $.proxy(this._touchStart, this));
136       this.is_mouse_started = false;
137       this.mouse_delay = 0;
138       this._mouse_delay_timer = null;
139       this._is_mouse_delay_met = true;
140       return this.mouse_down_info = null;
141     };
142
143     MouseWidget.prototype._deinit = function() {
144       var $document;
145       this.$el.unbind('mousedown.mousewidget');
146       this.$el.unbind('touchstart.mousewidget');
147       $document = $(document);
148       $document.unbind('mousemove.mousewidget');
149       return $document.unbind('mouseup.mousewidget');
150     };
151
152     MouseWidget.prototype._mouseDown = function(e) {
153       var result;
154       if (e.which !== 1) {
155         return;
156       }
157       result = this._handleMouseDown(e, this._getPositionInfo(e));
158       if (result) {
159         e.preventDefault();
160       }
161       return result;
162     };
163
164     MouseWidget.prototype._handleMouseDown = function(e, position_info) {
165       if (MouseWidget.is_mouse_handled) {
166         return;
167       }
168       if (this.is_mouse_started) {
169         this._handleMouseUp(position_info);
170       }
171       this.mouse_down_info = position_info;
172       if (!this._mouseCapture(position_info)) {
173         return;
174       }
175       this._handleStartMouse();
176       this.is_mouse_handled = true;
177       return true;
178     };
179
180     MouseWidget.prototype._handleStartMouse = function() {
181       var $document;
182       $document = $(document);
183       $document.bind('mousemove.mousewidget', $.proxy(this._mouseMove, this));
184       $document.bind('touchmove.mousewidget', $.proxy(this._touchMove, this));
185       $document.bind('mouseup.mousewidget', $.proxy(this._mouseUp, this));
186       $document.bind('touchend.mousewidget', $.proxy(this._touchEnd, this));
187       if (this.mouse_delay) {
188         return this._startMouseDelayTimer();
189       }
190     };
191
192     MouseWidget.prototype._startMouseDelayTimer = function() {
193       var _this = this;
194       if (this._mouse_delay_timer) {
195         clearTimeout(this._mouse_delay_timer);
196       }
197       this._mouse_delay_timer = setTimeout(function() {
198         return _this._is_mouse_delay_met = true;
199       }, this.mouse_delay);
200       return this._is_mouse_delay_met = false;
201     };
202
203     MouseWidget.prototype._mouseMove = function(e) {
204       return this._handleMouseMove(e, this._getPositionInfo(e));
205     };
206
207     MouseWidget.prototype._handleMouseMove = function(e, position_info) {
208       if (this.is_mouse_started) {
209         this._mouseDrag(position_info);
210         return e.preventDefault();
211       }
212       if (this.mouse_delay && !this._is_mouse_delay_met) {
213         return true;
214       }
215       this.is_mouse_started = this._mouseStart(this.mouse_down_info) !== false;
216       if (this.is_mouse_started) {
217         this._mouseDrag(position_info);
218       } else {
219         this._handleMouseUp(position_info);
220       }
221       return !this.is_mouse_started;
222     };
223
224     MouseWidget.prototype._getPositionInfo = function(e) {
225       return {
226         page_x: e.pageX,
227         page_y: e.pageY,
228         target: e.target,
229         original_event: e
230       };
231     };
232
233     MouseWidget.prototype._mouseUp = function(e) {
234       return this._handleMouseUp(this._getPositionInfo(e));
235     };
236
237     MouseWidget.prototype._handleMouseUp = function(position_info) {
238       var $document;
239       $document = $(document);
240       $document.unbind('mousemove.mousewidget');
241       $document.unbind('touchmove.mousewidget');
242       $document.unbind('mouseup.mousewidget');
243       $document.unbind('touchend.mousewidget');
244       if (this.is_mouse_started) {
245         this.is_mouse_started = false;
246         this._mouseStop(position_info);
247       }
248     };
249
250     MouseWidget.prototype._mouseCapture = function(position_info) {
251       return true;
252     };
253
254     MouseWidget.prototype._mouseStart = function(position_info) {
255       return null;
256     };
257
258     MouseWidget.prototype._mouseDrag = function(position_info) {
259       return null;
260     };
261
262     MouseWidget.prototype._mouseStop = function(position_info) {
263       return null;
264     };
265
266     MouseWidget.prototype.setMouseDelay = function(mouse_delay) {
267       return this.mouse_delay = mouse_delay;
268     };
269
270     MouseWidget.prototype._touchStart = function(e) {
271       var touch;
272       if (e.originalEvent.touches.length > 1) {
273         return;
274       }
275       touch = e.originalEvent.changedTouches[0];
276       return this._handleMouseDown(e, this._getPositionInfo(touch));
277     };
278
279     MouseWidget.prototype._touchMove = function(e) {
280       var touch;
281       if (e.originalEvent.touches.length > 1) {
282         return;
283       }
284       touch = e.originalEvent.changedTouches[0];
285       return this._handleMouseMove(e, this._getPositionInfo(touch));
286     };
287
288     MouseWidget.prototype._touchEnd = function(e) {
289       var touch;
290       if (e.originalEvent.touches.length > 1) {
291         return;
292       }
293       touch = e.originalEvent.changedTouches[0];
294       return this._handleMouseUp(this._getPositionInfo(touch));
295     };
296
297     return MouseWidget;
298
299   })(SimpleWidget);
300
301   this.Tree = {};
302
303   $ = this.jQuery;
304
305   Position = {
306     getName: function(position) {
307       return Position.strings[position - 1];
308     },
309     nameToIndex: function(name) {
310       var i, _i, _ref1;
311       for (i = _i = 1, _ref1 = Position.strings.length; 1 <= _ref1 ? _i <= _ref1 : _i >= _ref1; i = 1 <= _ref1 ? ++_i : --_i) {
312         if (Position.strings[i - 1] === name) {
313           return i;
314         }
315       }
316       return 0;
317     }
318   };
319
320   Position.BEFORE = 1;
321
322   Position.AFTER = 2;
323
324   Position.INSIDE = 3;
325
326   Position.NONE = 4;
327
328   Position.strings = ['before', 'after', 'inside', 'none'];
329
330   this.Tree.Position = Position;
331
332   Node = (function() {
333     function Node(o, is_root, node_class) {
334       if (is_root == null) {
335         is_root = false;
336       }
337       if (node_class == null) {
338         node_class = Node;
339       }
340       this.setData(o);
341       this.children = [];
342       this.parent = null;
343       if (is_root) {
344         this.id_mapping = {};
345         this.tree = this;
346         this.node_class = node_class;
347       }
348     }
349
350     Node.prototype.setData = function(o) {
351       var key, value, _results;
352       if (typeof o !== 'object') {
353         return this.name = o;
354       } else {
355         _results = [];
356         for (key in o) {
357           value = o[key];
358           if (key === 'label') {
359             _results.push(this.name = value);
360           } else {
361             _results.push(this[key] = value);
362           }
363         }
364         return _results;
365       }
366     };
367
368     Node.prototype.initFromData = function(data) {
369       var addChildren, addNode,
370         _this = this;
371       addNode = function(node_data) {
372         _this.setData(node_data);
373         if (node_data.children) {
374           return addChildren(node_data.children);
375         }
376       };
377       addChildren = function(children_data) {
378         var child, node, _i, _len;
379         for (_i = 0, _len = children_data.length; _i < _len; _i++) {
380           child = children_data[_i];
381           node = new _this.tree.node_class('');
382           node.initFromData(child);
383           _this.addChild(node);
384         }
385         return null;
386       };
387       addNode(data);
388       return null;
389     };
390
391     /*
392     Create tree from data.
393     
394     Structure of data is:
395     [
396         {
397             label: 'node1',
398             children: [
399                 { label: 'child1' },
400                 { label: 'child2' }
401             ]
402         },
403         {
404             label: 'node2'
405         }
406     ]
407     */
408
409
410     Node.prototype.loadFromData = function(data) {
411       var node, o, _i, _len;
412       this.removeChildren();
413       for (_i = 0, _len = data.length; _i < _len; _i++) {
414         o = data[_i];
415         node = new this.tree.node_class(o);
416         this.addChild(node);
417         if (typeof o === 'object' && o.children) {
418           node.loadFromData(o.children);
419         }
420       }
421       return null;
422     };
423
424     /*
425     Add child.
426     
427     tree.addChild(
428         new Node('child1')
429     );
430     */
431
432
433     Node.prototype.addChild = function(node) {
434       this.children.push(node);
435       return node._setParent(this);
436     };
437
438     /*
439     Add child at position. Index starts at 0.
440     
441     tree.addChildAtPosition(
442         new Node('abc'),
443         1
444     );
445     */
446
447
448     Node.prototype.addChildAtPosition = function(node, index) {
449       this.children.splice(index, 0, node);
450       return node._setParent(this);
451     };
452
453     Node.prototype._setParent = function(parent) {
454       this.parent = parent;
455       this.tree = parent.tree;
456       return this.tree.addNodeToIndex(this);
457     };
458
459     /*
460     Remove child. This also removes the children of the node.
461     
462     tree.removeChild(tree.children[0]);
463     */
464
465
466     Node.prototype.removeChild = function(node) {
467       node.removeChildren();
468       return this._removeChild(node);
469     };
470
471     Node.prototype._removeChild = function(node) {
472       this.children.splice(this.getChildIndex(node), 1);
473       return this.tree.removeNodeFromIndex(node);
474     };
475
476     /*
477     Get child index.
478     
479     var index = getChildIndex(node);
480     */
481
482
483     Node.prototype.getChildIndex = function(node) {
484       return $.inArray(node, this.children);
485     };
486
487     /*
488     Does the tree have children?
489     
490     if (tree.hasChildren()) {
491         //
492     }
493     */
494
495
496     Node.prototype.hasChildren = function() {
497       return this.children.length !== 0;
498     };
499
500     Node.prototype.isFolder = function() {
501       return this.hasChildren() || this.load_on_demand;
502     };
503
504     /*
505     Iterate over all the nodes in the tree.
506     
507     Calls callback with (node, level).
508     
509     The callback must return true to continue the iteration on current node.
510     
511     tree.iterate(
512         function(node, level) {
513            console.log(node.name);
514     
515            // stop iteration after level 2
516            return (level <= 2);
517         }
518     );
519     */
520
521
522     Node.prototype.iterate = function(callback) {
523       var _iterate,
524         _this = this;
525       _iterate = function(node, level) {
526         var child, result, _i, _len, _ref1;
527         if (node.children) {
528           _ref1 = node.children;
529           for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
530             child = _ref1[_i];
531             result = callback(child, level);
532             if (_this.hasChildren() && result) {
533               _iterate(child, level + 1);
534             }
535           }
536           return null;
537         }
538       };
539       _iterate(this, 0);
540       return null;
541     };
542
543     /*
544     Move node relative to another node.
545     
546     Argument position: Position.BEFORE, Position.AFTER or Position.Inside
547     
548     // move node1 after node2
549     tree.moveNode(node1, node2, Position.AFTER);
550     */
551
552
553     Node.prototype.moveNode = function(moved_node, target_node, position) {
554       if (moved_node.isParentOf(target_node)) {
555         return;
556       }
557       moved_node.parent._removeChild(moved_node);
558       if (position === Position.AFTER) {
559         return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node) + 1);
560       } else if (position === Position.BEFORE) {
561         return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node));
562       } else if (position === Position.INSIDE) {
563         return target_node.addChildAtPosition(moved_node, 0);
564       }
565     };
566
567     /*
568     Get the tree as data.
569     */
570
571
572     Node.prototype.getData = function() {
573       var getDataFromNodes,
574         _this = this;
575       getDataFromNodes = function(nodes) {
576         var data, k, node, tmp_node, v, _i, _len;
577         data = [];
578         for (_i = 0, _len = nodes.length; _i < _len; _i++) {
579           node = nodes[_i];
580           tmp_node = {};
581           for (k in node) {
582             v = node[k];
583             if ((k !== 'parent' && k !== 'children' && k !== 'element' && k !== 'tree') && Object.prototype.hasOwnProperty.call(node, k)) {
584               tmp_node[k] = v;
585             }
586           }
587           if (node.hasChildren()) {
588             tmp_node.children = getDataFromNodes(node.children);
589           }
590           data.push(tmp_node);
591         }
592         return data;
593       };
594       return getDataFromNodes(this.children);
595     };
596
597     Node.prototype.getNodeByName = function(name) {
598       var result;
599       result = null;
600       this.iterate(function(node) {
601         if (node.name === name) {
602           result = node;
603           return false;
604         } else {
605           return true;
606         }
607       });
608       return result;
609     };
610
611     Node.prototype.addAfter = function(node_info) {
612       var child_index, node;
613       if (!this.parent) {
614         return null;
615       } else {
616         node = new this.tree.node_class(node_info);
617         child_index = this.parent.getChildIndex(this);
618         this.parent.addChildAtPosition(node, child_index + 1);
619         return node;
620       }
621     };
622
623     Node.prototype.addBefore = function(node_info) {
624       var child_index, node;
625       if (!this.parent) {
626         return null;
627       } else {
628         node = new this.tree.node_class(node_info);
629         child_index = this.parent.getChildIndex(this);
630         this.parent.addChildAtPosition(node, child_index);
631         return node;
632       }
633     };
634
635     Node.prototype.addParent = function(node_info) {
636       var child, new_parent, original_parent, _i, _len, _ref1;
637       if (!this.parent) {
638         return null;
639       } else {
640         new_parent = new this.tree.node_class(node_info);
641         new_parent._setParent(this.tree);
642         original_parent = this.parent;
643         _ref1 = original_parent.children;
644         for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
645           child = _ref1[_i];
646           new_parent.addChild(child);
647         }
648         original_parent.children = [];
649         original_parent.addChild(new_parent);
650         return new_parent;
651       }
652     };
653
654     Node.prototype.remove = function() {
655       if (this.parent) {
656         this.parent.removeChild(this);
657         return this.parent = null;
658       }
659     };
660
661     Node.prototype.append = function(node_info) {
662       var node;
663       node = new this.tree.node_class(node_info);
664       this.addChild(node);
665       return node;
666     };
667
668     Node.prototype.prepend = function(node_info) {
669       var node;
670       node = new this.tree.node_class(node_info);
671       this.addChildAtPosition(node, 0);
672       return node;
673     };
674
675     Node.prototype.isParentOf = function(node) {
676       var parent;
677       parent = node.parent;
678       while (parent) {
679         if (parent === this) {
680           return true;
681         }
682         parent = parent.parent;
683       }
684       return false;
685     };
686
687     Node.prototype.getLevel = function() {
688       var level, node;
689       level = 0;
690       node = this;
691       while (node.parent) {
692         level += 1;
693         node = node.parent;
694       }
695       return level;
696     };
697
698     Node.prototype.getNodeById = function(node_id) {
699       return this.id_mapping[node_id];
700     };
701
702     Node.prototype.addNodeToIndex = function(node) {
703       if (node.id) {
704         return this.id_mapping[node.id] = node;
705       }
706     };
707
708     Node.prototype.removeNodeFromIndex = function(node) {
709       if (node.id) {
710         return delete this.id_mapping[node.id];
711       }
712     };
713
714     Node.prototype.removeChildren = function() {
715       var _this = this;
716       this.iterate(function(child) {
717         _this.tree.removeNodeFromIndex(child);
718         return true;
719       });
720       return this.children = [];
721     };
722
723     Node.prototype.getPreviousSibling = function() {
724       var previous_index;
725       if (!this.parent) {
726         return null;
727       } else {
728         previous_index = this.parent.getChildIndex(this) - 1;
729         if (previous_index >= 0) {
730           return this.parent.children[previous_index];
731         } else {
732           return null;
733         }
734       }
735     };
736
737     Node.prototype.getNextSibling = function() {
738       var next_index;
739       if (!this.parent) {
740         return null;
741       } else {
742         next_index = this.parent.getChildIndex(this) + 1;
743         if (next_index < this.parent.children.length) {
744           return this.parent.children[next_index];
745         } else {
746           return null;
747         }
748       }
749     };
750
751     return Node;
752
753   })();
754
755   this.Tree.Node = Node;
756
757   /*
758   Copyright 2013 Marco Braak
759   
760   Licensed under the Apache License, Version 2.0 (the "License");
761   you may not use this file except in compliance with the License.
762   You may obtain a copy of the License at
763   
764       http://www.apache.org/licenses/LICENSE-2.0
765   
766   Unless required by applicable law or agreed to in writing, software
767   distributed under the License is distributed on an "AS IS" BASIS,
768   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
769   See the License for the specific language governing permissions and
770   limitations under the License.
771   */
772
773
774   JqTreeWidget = (function(_super) {
775     __extends(JqTreeWidget, _super);
776
777     function JqTreeWidget() {
778       _ref1 = JqTreeWidget.__super__.constructor.apply(this, arguments);
779       return _ref1;
780     }
781
782     JqTreeWidget.prototype.defaults = {
783       autoOpen: false,
784       saveState: false,
785       dragAndDrop: false,
786       selectable: true,
787       useContextMenu: true,
788       onCanSelectNode: null,
789       onSetStateFromStorage: null,
790       onGetStateFromStorage: null,
791       onCreateLi: null,
792       onIsMoveHandle: null,
793       onCanMove: null,
794       onCanMoveTo: null,
795       onLoadFailed: null,
796       autoEscape: true,
797       dataUrl: null,
798       closedIcon: '&#x25ba;',
799       openedIcon: '&#x25bc;',
800       slide: true,
801       nodeClass: Node
802     };
803
804     JqTreeWidget.prototype.toggle = function(node, slide) {
805       if (slide == null) {
806         slide = true;
807       }
808       if (node.is_open) {
809         return this.closeNode(node, slide);
810       } else {
811         return this.openNode(node, slide);
812       }
813     };
814
815     JqTreeWidget.prototype.getTree = function() {
816       return this.tree;
817     };
818
819     JqTreeWidget.prototype.selectNode = function(node) {
820       return this._selectNode(node, true);
821     };
822
823     JqTreeWidget.prototype._selectNode = function(node, must_toggle) {
824       var canSelect, openParents, saveState,
825         _this = this;
826       if (must_toggle == null) {
827         must_toggle = false;
828       }
829       if (!this.select_node_handler) {
830         return;
831       }
832       canSelect = function() {
833         if (_this.options.onCanSelectNode) {
834           return _this.options.selectable && _this.options.onCanSelectNode(node);
835         } else {
836           return _this.options.selectable;
837         }
838       };
839       openParents = function() {
840         var parent;
841         parent = node.parent;
842         if (parent && parent.parent && !parent.is_open) {
843           return _this.openNode(parent, false);
844         }
845       };
846       saveState = function() {
847         if (_this.options.saveState) {
848           return _this.save_state_handler.saveState();
849         }
850       };
851       if (!node) {
852         this._deselectCurrentNode();
853         saveState();
854         return;
855       }
856       if (!canSelect()) {
857         return;
858       }
859       if (this.select_node_handler.isNodeSelected(node)) {
860         if (must_toggle) {
861           this._deselectCurrentNode();
862           this._triggerEvent('tree.select', {
863             node: null,
864             previous_node: node
865           });
866         }
867       } else {
868         this._deselectCurrentNode();
869         this.addToSelection(node);
870         this._triggerEvent('tree.select', {
871           node: node
872         });
873         openParents();
874       }
875       return saveState();
876     };
877
878     JqTreeWidget.prototype.getSelectedNode = function() {
879       return this.select_node_handler.getSelectedNode();
880     };
881
882     JqTreeWidget.prototype.toJson = function() {
883       return JSON.stringify(this.tree.getData());
884     };
885
886     JqTreeWidget.prototype.loadData = function(data, parent_node) {
887       return this._loadData(data, parent_node);
888     };
889
890     JqTreeWidget.prototype.loadDataFromUrl = function(url, parent_node, on_finished) {
891       if ($.type(url) !== 'string') {
892         on_finished = parent_node;
893         parent_node = url;
894         url = null;
895       }
896       return this._loadDataFromUrl(url, parent_node, on_finished);
897     };
898
899     JqTreeWidget.prototype._loadDataFromUrl = function(url_info, parent_node, on_finished) {
900       var $el, addLoadingClass, parseUrlInfo, removeLoadingClass,
901         _this = this;
902       $el = null;
903       addLoadingClass = function() {
904         var folder_element;
905         if (!parent_node) {
906           $el = _this.element;
907         } else {
908           folder_element = new FolderElement(parent_node, _this);
909           $el = folder_element.getLi();
910         }
911         return $el.addClass('jqtree-loading');
912       };
913       removeLoadingClass = function() {
914         if ($el) {
915           return $el.removeClass('jqtree-loading');
916         }
917       };
918       parseUrlInfo = function() {
919         if ($.type(url_info) === 'string') {
920           url_info = {
921             url: url_info
922           };
923         }
924         if (!url_info.method) {
925           return url_info.method = 'get';
926         }
927       };
928       addLoadingClass();
929       if (!url_info) {
930         url_info = this._getDataUrlInfo(parent_node);
931       }
932       parseUrlInfo();
933       return $.ajax({
934         url: url_info.url,
935         data: url_info.data,
936         type: url_info.method.toUpperCase(),
937         cache: false,
938         dataType: 'json',
939         success: function(response) {
940           var data;
941           if ($.isArray(response) || typeof response === 'object') {
942             data = response;
943           } else {
944             data = $.parseJSON(response);
945           }
946           removeLoadingClass();
947           _this._loadData(data, parent_node);
948           if (on_finished && $.isFunction(on_finished)) {
949             return on_finished();
950           }
951         },
952         error: function(response) {
953           removeLoadingClass();
954           if (_this.options.onLoadFailed) {
955             return _this.options.onLoadFailed(response);
956           }
957         }
958       });
959     };
960
961     JqTreeWidget.prototype._loadData = function(data, parent_node) {
962       var n, selected_nodes_under_parent, _i, _len;
963       this._triggerEvent('tree.load_data', {
964         tree_data: data
965       });
966       if (!parent_node) {
967         this._initTree(data);
968       } else {
969         selected_nodes_under_parent = this.select_node_handler.getSelectedNodes(parent_node);
970         for (_i = 0, _len = selected_nodes_under_parent.length; _i < _len; _i++) {
971           n = selected_nodes_under_parent[_i];
972           this.select_node_handler.removeFromSelection(n);
973         }
974         parent_node.loadFromData(data);
975         parent_node.load_on_demand = false;
976         this._refreshElements(parent_node.parent);
977       }
978       if (this.is_dragging) {
979         return this.dnd_handler.refreshHitAreas();
980       }
981     };
982
983     JqTreeWidget.prototype.getNodeById = function(node_id) {
984       return this.tree.getNodeById(node_id);
985     };
986
987     JqTreeWidget.prototype.getNodeByName = function(name) {
988       return this.tree.getNodeByName(name);
989     };
990
991     JqTreeWidget.prototype.openNode = function(node, slide) {
992       if (slide == null) {
993         slide = true;
994       }
995       return this._openNode(node, slide);
996     };
997
998     JqTreeWidget.prototype._openNode = function(node, slide, on_finished) {
999       var doOpenNode, parent,
1000         _this = this;
1001       if (slide == null) {
1002         slide = true;
1003       }
1004       doOpenNode = function(_node, _slide, _on_finished) {
1005         var folder_element;
1006         folder_element = new FolderElement(_node, _this);
1007         return folder_element.open(_on_finished, _slide);
1008       };
1009       if (node.isFolder()) {
1010         if (node.load_on_demand) {
1011           return this._loadFolderOnDemand(node, slide, on_finished);
1012         } else {
1013           parent = node.parent;
1014           while (parent && !parent.is_open) {
1015             if (parent.parent) {
1016               doOpenNode(parent, false, null);
1017             }
1018             parent = parent.parent;
1019           }
1020           doOpenNode(node, slide, on_finished);
1021           return this._saveState();
1022         }
1023       }
1024     };
1025
1026     JqTreeWidget.prototype._loadFolderOnDemand = function(node, slide, on_finished) {
1027       var _this = this;
1028       if (slide == null) {
1029         slide = true;
1030       }
1031       return this._loadDataFromUrl(null, node, function() {
1032         return _this._openNode(node, slide, on_finished);
1033       });
1034     };
1035
1036     JqTreeWidget.prototype.closeNode = function(node, slide) {
1037       if (slide == null) {
1038         slide = true;
1039       }
1040       if (node.isFolder()) {
1041         new FolderElement(node, this).close(slide);
1042         return this._saveState();
1043       }
1044     };
1045
1046     JqTreeWidget.prototype.isDragging = function() {
1047       return this.is_dragging;
1048     };
1049
1050     JqTreeWidget.prototype.refreshHitAreas = function() {
1051       return this.dnd_handler.refreshHitAreas();
1052     };
1053
1054     JqTreeWidget.prototype.addNodeAfter = function(new_node_info, existing_node) {
1055       var new_node;
1056       new_node = existing_node.addAfter(new_node_info);
1057       this._refreshElements(existing_node.parent);
1058       return new_node;
1059     };
1060
1061     JqTreeWidget.prototype.addNodeBefore = function(new_node_info, existing_node) {
1062       var new_node;
1063       new_node = existing_node.addBefore(new_node_info);
1064       this._refreshElements(existing_node.parent);
1065       return new_node;
1066     };
1067
1068     JqTreeWidget.prototype.addParentNode = function(new_node_info, existing_node) {
1069       var new_node;
1070       new_node = existing_node.addParent(new_node_info);
1071       this._refreshElements(new_node.parent);
1072       return new_node;
1073     };
1074
1075     JqTreeWidget.prototype.removeNode = function(node) {
1076       var parent;
1077       parent = node.parent;
1078       if (parent) {
1079         this.select_node_handler.removeFromSelection(node, true);
1080         node.remove();
1081         return this._refreshElements(parent.parent);
1082       }
1083     };
1084
1085     JqTreeWidget.prototype.appendNode = function(new_node_info, parent_node) {
1086       var is_already_root_node, node;
1087       if (!parent_node) {
1088         parent_node = this.tree;
1089       }
1090       is_already_root_node = parent_node.isFolder();
1091       node = parent_node.append(new_node_info);
1092       if (is_already_root_node) {
1093         this._refreshElements(parent_node);
1094       } else {
1095         this._refreshElements(parent_node.parent);
1096       }
1097       return node;
1098     };
1099
1100     JqTreeWidget.prototype.prependNode = function(new_node_info, parent_node) {
1101       var node;
1102       if (!parent_node) {
1103         parent_node = this.tree;
1104       }
1105       node = parent_node.prepend(new_node_info);
1106       this._refreshElements(parent_node);
1107       return node;
1108     };
1109
1110     JqTreeWidget.prototype.updateNode = function(node, data) {
1111       var id_is_changed;
1112       id_is_changed = data.id && data.id !== node.id;
1113       if (id_is_changed) {
1114         this.tree.removeNodeFromIndex(node);
1115       }
1116       node.setData(data);
1117       if (id_is_changed) {
1118         this.tree.addNodeToIndex(node);
1119       }
1120       this._refreshElements(node.parent);
1121       return this._selectCurrentNode();
1122     };
1123
1124     JqTreeWidget.prototype.moveNode = function(node, target_node, position) {
1125       var position_index;
1126       position_index = Position.nameToIndex(position);
1127       this.tree.moveNode(node, target_node, position_index);
1128       return this._refreshElements();
1129     };
1130
1131     JqTreeWidget.prototype.getStateFromStorage = function() {
1132       return this.save_state_handler.getStateFromStorage();
1133     };
1134
1135     JqTreeWidget.prototype.addToSelection = function(node) {
1136       this.select_node_handler.addToSelection(node);
1137       return this._getNodeElementForNode(node).select();
1138     };
1139
1140     JqTreeWidget.prototype.getSelectedNodes = function() {
1141       return this.select_node_handler.getSelectedNodes();
1142     };
1143
1144     JqTreeWidget.prototype.isNodeSelected = function(node) {
1145       return this.select_node_handler.isNodeSelected(node);
1146     };
1147
1148     JqTreeWidget.prototype.removeFromSelection = function(node) {
1149       this.select_node_handler.removeFromSelection(node);
1150       return this._getNodeElementForNode(node).deselect();
1151     };
1152
1153     JqTreeWidget.prototype.scrollToNode = function(node) {
1154       var $element, top;
1155       $element = $(node.element);
1156       top = $element.offset().top - this.$el.offset().top;
1157       return this.scroll_handler.scrollTo(top);
1158     };
1159
1160     JqTreeWidget.prototype.getState = function() {
1161       return this.save_state_handler.getState();
1162     };
1163
1164     JqTreeWidget.prototype.setState = function(state) {
1165       this.save_state_handler.setState(state);
1166       return this._refreshElements();
1167     };
1168
1169     JqTreeWidget.prototype._init = function() {
1170       JqTreeWidget.__super__._init.call(this);
1171       this.element = this.$el;
1172       this.mouse_delay = 300;
1173       this.is_initialized = false;
1174       if (typeof SaveStateHandler !== "undefined" && SaveStateHandler !== null) {
1175         this.save_state_handler = new SaveStateHandler(this);
1176       } else {
1177         this.options.saveState = false;
1178       }
1179       if (typeof SelectNodeHandler !== "undefined" && SelectNodeHandler !== null) {
1180         this.select_node_handler = new SelectNodeHandler(this);
1181       }
1182       if (typeof DragAndDropHandler !== "undefined" && DragAndDropHandler !== null) {
1183         this.dnd_handler = new DragAndDropHandler(this);
1184       } else {
1185         this.options.dragAndDrop = false;
1186       }
1187       if (typeof ScrollHandler !== "undefined" && ScrollHandler !== null) {
1188         this.scroll_handler = new ScrollHandler(this);
1189       }
1190       if ((typeof KeyHandler !== "undefined" && KeyHandler !== null) && (typeof SelectNodeHandler !== "undefined" && SelectNodeHandler !== null)) {
1191         this.key_handler = new KeyHandler(this);
1192       }
1193       this._initData();
1194       this.element.click($.proxy(this._click, this));
1195       if (this.options.useContextMenu) {
1196         return this.element.bind('contextmenu', $.proxy(this._contextmenu, this));
1197       }
1198     };
1199
1200     JqTreeWidget.prototype._deinit = function() {
1201       this.element.empty();
1202       this.element.unbind();
1203       this.key_handler.deinit();
1204       this.tree = null;
1205       return JqTreeWidget.__super__._deinit.call(this);
1206     };
1207
1208     JqTreeWidget.prototype._initData = function() {
1209       if (this.options.data) {
1210         return this._loadData(this.options.data);
1211       } else {
1212         return this._loadDataFromUrl(this._getDataUrlInfo());
1213       }
1214     };
1215
1216     JqTreeWidget.prototype._getDataUrlInfo = function(node) {
1217       var data, data_url, url_info;
1218       data_url = this.options.dataUrl || this.element.data('url');
1219       if ($.isFunction(data_url)) {
1220         return data_url(node);
1221       } else if ($.type(data_url) === 'string') {
1222         url_info = {
1223           url: data_url
1224         };
1225         if (node && node.id) {
1226           data = {
1227             node: node.id
1228           };
1229           url_info['data'] = data;
1230         }
1231         return url_info;
1232       } else {
1233         return data_url;
1234       }
1235     };
1236
1237     JqTreeWidget.prototype._initTree = function(data) {
1238       this.tree = new this.options.nodeClass(null, true, this.options.nodeClass);
1239       if (this.select_node_handler) {
1240         this.select_node_handler.clear();
1241       }
1242       this.tree.loadFromData(data);
1243       this._openNodes();
1244       this._refreshElements();
1245       if (!this.is_initialized) {
1246         this.is_initialized = true;
1247         return this._triggerEvent('tree.init');
1248       }
1249     };
1250
1251     JqTreeWidget.prototype._openNodes = function() {
1252       var max_level;
1253       if (this.options.saveState) {
1254         if (this.save_state_handler.restoreState()) {
1255           return;
1256         }
1257       }
1258       if (this.options.autoOpen === false) {
1259         return;
1260       } else if (this.options.autoOpen === true) {
1261         max_level = -1;
1262       } else {
1263         max_level = parseInt(this.options.autoOpen);
1264       }
1265       return this.tree.iterate(function(node, level) {
1266         if (node.hasChildren()) {
1267           node.is_open = true;
1268         }
1269         return level !== max_level;
1270       });
1271     };
1272
1273     JqTreeWidget.prototype._refreshElements = function(from_node) {
1274       var $element, createFolderLi, createLi, createNodeLi, createUl, doCreateDomElements, escapeIfNecessary, is_root_node, node_element,
1275         _this = this;
1276       if (from_node == null) {
1277         from_node = null;
1278       }
1279       escapeIfNecessary = function(value) {
1280         if (_this.options.autoEscape) {
1281           return html_escape(value);
1282         } else {
1283           return value;
1284         }
1285       };
1286       createUl = function(is_root_node) {
1287         var class_string;
1288         if (is_root_node) {
1289           class_string = 'jqtree-tree';
1290         } else {
1291           class_string = '';
1292         }
1293         return $("<ul class=\"jqtree_common " + class_string + "\"></ul>");
1294       };
1295       createLi = function(node) {
1296         var $li;
1297         if (node.isFolder()) {
1298           $li = createFolderLi(node);
1299         } else {
1300           $li = createNodeLi(node);
1301         }
1302         if (_this.options.onCreateLi) {
1303           _this.options.onCreateLi(node, $li);
1304         }
1305         return $li;
1306       };
1307       createNodeLi = function(node) {
1308         var class_string, escaped_name, li_classes;
1309         li_classes = ['jqtree_common'];
1310         if (_this.select_node_handler && _this.select_node_handler.isNodeSelected(node)) {
1311           li_classes.push('jqtree-selected');
1312         }
1313         class_string = li_classes.join(' ');
1314         escaped_name = escapeIfNecessary(node.name);
1315         return $("<li class=\"" + class_string + "\"><div class=\"jqtree-element jqtree_common\"><span class=\"jqtree-title jqtree_common\">" + escaped_name + "</span></div></li>");
1316       };
1317       createFolderLi = function(node) {
1318         var button_char, button_classes, escaped_name, folder_classes, getButtonClasses, getFolderClasses;
1319         getButtonClasses = function() {
1320           var classes;
1321           classes = ['jqtree-toggler'];
1322           if (!node.is_open) {
1323             classes.push('jqtree-closed');
1324           }
1325           return classes.join(' ');
1326         };
1327         getFolderClasses = function() {
1328           var classes;
1329           classes = ['jqtree-folder'];
1330           if (!node.is_open) {
1331             classes.push('jqtree-closed');
1332           }
1333           if (_this.select_node_handler && _this.select_node_handler.isNodeSelected(node)) {
1334             classes.push('jqtree-selected');
1335           }
1336           return classes.join(' ');
1337         };
1338         button_classes = getButtonClasses();
1339         folder_classes = getFolderClasses();
1340         escaped_name = escapeIfNecessary(node.name);
1341         if (node.is_open) {
1342           button_char = _this.options.openedIcon;
1343         } else {
1344           button_char = _this.options.closedIcon;
1345         }
1346         return $("<li class=\"jqtree_common " + folder_classes + "\"><div class=\"jqtree-element jqtree_common\"><a class=\"jqtree_common " + button_classes + "\">" + button_char + "</a><span class=\"jqtree_common jqtree-title\">" + escaped_name + "</span></div></li>");
1347       };
1348       doCreateDomElements = function($element, children, is_root_node, is_open) {
1349         var $li, $ul, child, _i, _len;
1350         $ul = createUl(is_root_node);
1351         $element.append($ul);
1352         for (_i = 0, _len = children.length; _i < _len; _i++) {
1353           child = children[_i];
1354           $li = createLi(child);
1355           $ul.append($li);
1356           child.element = $li[0];
1357           $li.data('node', child);
1358           if (child.hasChildren()) {
1359             doCreateDomElements($li, child.children, false, child.is_open);
1360           }
1361         }
1362         return null;
1363       };
1364       if (from_node && from_node.parent) {
1365         is_root_node = false;
1366         node_element = this._getNodeElementForNode(from_node);
1367         node_element.getUl().remove();
1368         $element = node_element.$element;
1369       } else {
1370         from_node = this.tree;
1371         $element = this.element;
1372         $element.empty();
1373         is_root_node = true;
1374       }
1375       doCreateDomElements($element, from_node.children, is_root_node, is_root_node);
1376       return this._triggerEvent('tree.refresh');
1377     };
1378
1379     JqTreeWidget.prototype._click = function(e) {
1380       var $button, $el, $target, event, node;
1381       $target = $(e.target);
1382       $button = $target.closest('.jqtree-toggler');
1383       if ($button.length) {
1384         node = this._getNode($button);
1385         if (node) {
1386           this.toggle(node, this.options.slide);
1387           e.preventDefault();
1388           return e.stopPropagation();
1389         }
1390       } else {
1391         $el = $target.closest('.jqtree-element');
1392         if ($el.length) {
1393           node = this._getNode($el);
1394           if (node) {
1395             event = this._triggerEvent('tree.click', {
1396               node: node
1397             });
1398             if (!event.isDefaultPrevented()) {
1399               return this._selectNode(node, true);
1400             }
1401           }
1402         }
1403       }
1404     };
1405
1406     JqTreeWidget.prototype._getNode = function($element) {
1407       var $li;
1408       $li = $element.closest('li');
1409       if ($li.length === 0) {
1410         return null;
1411       } else {
1412         return $li.data('node');
1413       }
1414     };
1415
1416     JqTreeWidget.prototype._getNodeElementForNode = function(node) {
1417       if (node.isFolder()) {
1418         return new FolderElement(node, this);
1419       } else {
1420         return new NodeElement(node, this);
1421       }
1422     };
1423
1424     JqTreeWidget.prototype._getNodeElement = function($element) {
1425       var node;
1426       node = this._getNode($element);
1427       if (node) {
1428         return this._getNodeElementForNode(node);
1429       } else {
1430         return null;
1431       }
1432     };
1433
1434     JqTreeWidget.prototype._contextmenu = function(e) {
1435       var $div, node;
1436       $div = $(e.target).closest('ul.jqtree-tree .jqtree-element');
1437       if ($div.length) {
1438         node = this._getNode($div);
1439         if (node) {
1440           e.preventDefault();
1441           e.stopPropagation();
1442           this._triggerEvent('tree.contextmenu', {
1443             node: node,
1444             click_event: e
1445           });
1446           return false;
1447         }
1448       }
1449     };
1450
1451     JqTreeWidget.prototype._saveState = function() {
1452       if (this.options.saveState) {
1453         return this.save_state_handler.saveState();
1454       }
1455     };
1456
1457     JqTreeWidget.prototype._mouseCapture = function(position_info) {
1458       if (this.options.dragAndDrop) {
1459         return this.dnd_handler.mouseCapture(position_info);
1460       } else {
1461         return false;
1462       }
1463     };
1464
1465     JqTreeWidget.prototype._mouseStart = function(position_info) {
1466       if (this.options.dragAndDrop) {
1467         return this.dnd_handler.mouseStart(position_info);
1468       } else {
1469         return false;
1470       }
1471     };
1472
1473     JqTreeWidget.prototype._mouseDrag = function(position_info) {
1474       var result;
1475       if (this.options.dragAndDrop) {
1476         result = this.dnd_handler.mouseDrag(position_info);
1477         if (this.scroll_handler) {
1478           this.scroll_handler.checkScrolling();
1479         }
1480         return result;
1481       } else {
1482         return false;
1483       }
1484     };
1485
1486     JqTreeWidget.prototype._mouseStop = function(position_info) {
1487       if (this.options.dragAndDrop) {
1488         return this.dnd_handler.mouseStop(position_info);
1489       } else {
1490         return false;
1491       }
1492     };
1493
1494     JqTreeWidget.prototype._triggerEvent = function(event_name, values) {
1495       var event;
1496       event = $.Event(event_name);
1497       $.extend(event, values);
1498       this.element.trigger(event);
1499       return event;
1500     };
1501
1502     JqTreeWidget.prototype.testGenerateHitAreas = function(moving_node) {
1503       this.dnd_handler.current_item = this._getNodeElementForNode(moving_node);
1504       this.dnd_handler.generateHitAreas();
1505       return this.dnd_handler.hit_areas;
1506     };
1507
1508     JqTreeWidget.prototype._selectCurrentNode = function() {
1509       var node, node_element;
1510       node = this.getSelectedNode();
1511       if (node) {
1512         node_element = this._getNodeElementForNode(node);
1513         if (node_element) {
1514           return node_element.select();
1515         }
1516       }
1517     };
1518
1519     JqTreeWidget.prototype._deselectCurrentNode = function() {
1520       var node;
1521       node = this.getSelectedNode();
1522       if (node) {
1523         return this.removeFromSelection(node);
1524       }
1525     };
1526
1527     return JqTreeWidget;
1528
1529   })(MouseWidget);
1530
1531   SimpleWidget.register(JqTreeWidget, 'tree');
1532
1533   NodeElement = (function() {
1534     function NodeElement(node, tree_widget) {
1535       this.init(node, tree_widget);
1536     }
1537
1538     NodeElement.prototype.init = function(node, tree_widget) {
1539       this.node = node;
1540       this.tree_widget = tree_widget;
1541       return this.$element = $(node.element);
1542     };
1543
1544     NodeElement.prototype.getUl = function() {
1545       return this.$element.children('ul:first');
1546     };
1547
1548     NodeElement.prototype.getSpan = function() {
1549       return this.$element.children('.jqtree-element').find('span.jqtree-title');
1550     };
1551
1552     NodeElement.prototype.getLi = function() {
1553       return this.$element;
1554     };
1555
1556     NodeElement.prototype.addDropHint = function(position) {
1557       if (position === Position.INSIDE) {
1558         return new BorderDropHint(this.$element);
1559       } else {
1560         return new GhostDropHint(this.node, this.$element, position);
1561       }
1562     };
1563
1564     NodeElement.prototype.select = function() {
1565       return this.getLi().addClass('jqtree-selected');
1566     };
1567
1568     NodeElement.prototype.deselect = function() {
1569       return this.getLi().removeClass('jqtree-selected');
1570     };
1571
1572     return NodeElement;
1573
1574   })();
1575
1576   FolderElement = (function(_super) {
1577     __extends(FolderElement, _super);
1578
1579     function FolderElement() {
1580       _ref2 = FolderElement.__super__.constructor.apply(this, arguments);
1581       return _ref2;
1582     }
1583
1584     FolderElement.prototype.open = function(on_finished, slide) {
1585       var $button, doOpen,
1586         _this = this;
1587       if (slide == null) {
1588         slide = true;
1589       }
1590       if (!this.node.is_open) {
1591         this.node.is_open = true;
1592         $button = this.getButton();
1593         $button.removeClass('jqtree-closed');
1594         $button.html(this.tree_widget.options.openedIcon);
1595         doOpen = function() {
1596           _this.getLi().removeClass('jqtree-closed');
1597           if (on_finished) {
1598             on_finished();
1599           }
1600           return _this.tree_widget._triggerEvent('tree.open', {
1601             node: _this.node
1602           });
1603         };
1604         if (slide) {
1605           return this.getUl().slideDown('fast', doOpen);
1606         } else {
1607           this.getUl().show();
1608           return doOpen();
1609         }
1610       }
1611     };
1612
1613     FolderElement.prototype.close = function(slide) {
1614       var $button, doClose,
1615         _this = this;
1616       if (slide == null) {
1617         slide = true;
1618       }
1619       if (this.node.is_open) {
1620         this.node.is_open = false;
1621         $button = this.getButton();
1622         $button.addClass('jqtree-closed');
1623         $button.html(this.tree_widget.options.closedIcon);
1624         doClose = function() {
1625           _this.getLi().addClass('jqtree-closed');
1626           return _this.tree_widget._triggerEvent('tree.close', {
1627             node: _this.node
1628           });
1629         };
1630         if (slide) {
1631           return this.getUl().slideUp('fast', doClose);
1632         } else {
1633           this.getUl().hide();
1634           return doClose();
1635         }
1636       }
1637     };
1638
1639     FolderElement.prototype.getButton = function() {
1640       return this.$element.children('.jqtree-element').find('a.jqtree-toggler');
1641     };
1642
1643     FolderElement.prototype.addDropHint = function(position) {
1644       if (!this.node.is_open && position === Position.INSIDE) {
1645         return new BorderDropHint(this.$element);
1646       } else {
1647         return new GhostDropHint(this.node, this.$element, position);
1648       }
1649     };
1650
1651     return FolderElement;
1652
1653   })(NodeElement);
1654
1655   html_escape = function(string) {
1656     return ('' + string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g, '&#x2F;');
1657   };
1658
1659   _indexOf = function(array, item) {
1660     var i, value, _i, _len;
1661     for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) {
1662       value = array[i];
1663       if (value === item) {
1664         return i;
1665       }
1666     }
1667     return -1;
1668   };
1669
1670   indexOf = function(array, item) {
1671     if (array.indexOf) {
1672       return array.indexOf(item);
1673     } else {
1674       return _indexOf(array, item);
1675     }
1676   };
1677
1678   this.Tree.indexOf = indexOf;
1679
1680   this.Tree._indexOf = _indexOf;
1681
1682   if (!((this.JSON != null) && (this.JSON.stringify != null) && typeof this.JSON.stringify === 'function')) {
1683     json_escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
1684     json_meta = {
1685       '\b': '\\b',
1686       '\t': '\\t',
1687       '\n': '\\n',
1688       '\f': '\\f',
1689       '\r': '\\r',
1690       '"': '\\"',
1691       '\\': '\\\\'
1692     };
1693     json_quote = function(string) {
1694       json_escapable.lastIndex = 0;
1695       if (json_escapable.test(string)) {
1696         return '"' + string.replace(json_escapable, function(a) {
1697           var c;
1698           c = json_meta[a];
1699           return (typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4));
1700         }) + '"';
1701       } else {
1702         return '"' + string + '"';
1703       }
1704     };
1705     json_str = function(key, holder) {
1706       var i, k, partial, v, value, _i, _len;
1707       value = holder[key];
1708       switch (typeof value) {
1709         case 'string':
1710           return json_quote(value);
1711         case 'number':
1712           if (isFinite(value)) {
1713             return String(value);
1714           } else {
1715             return 'null';
1716           }
1717         case 'boolean':
1718         case 'null':
1719           return String(value);
1720         case 'object':
1721           if (!value) {
1722             return 'null';
1723           }
1724           partial = [];
1725           if (Object.prototype.toString.apply(value) === '[object Array]') {
1726             for (i = _i = 0, _len = value.length; _i < _len; i = ++_i) {
1727               v = value[i];
1728               partial[i] = json_str(i, value) || 'null';
1729             }
1730             return (partial.length === 0 ? '[]' : '[' + partial.join(',') + ']');
1731           }
1732           for (k in value) {
1733             if (Object.prototype.hasOwnProperty.call(value, k)) {
1734               v = json_str(k, value);
1735               if (v) {
1736                 partial.push(json_quote(k) + ':' + v);
1737               }
1738             }
1739           }
1740           return (partial.length === 0 ? '{}' : '{' + partial.join(',') + '}');
1741       }
1742     };
1743     if (this.JSON == null) {
1744       this.JSON = {};
1745     }
1746     this.JSON.stringify = function(value) {
1747       return json_str('', {
1748         '': value
1749       });
1750     };
1751   }
1752
1753   SaveStateHandler = (function() {
1754     function SaveStateHandler(tree_widget) {
1755       this.tree_widget = tree_widget;
1756     }
1757
1758     SaveStateHandler.prototype.saveState = function() {
1759       var state;
1760       state = JSON.stringify(this.getState());
1761       if (this.tree_widget.options.onSetStateFromStorage) {
1762         return this.tree_widget.options.onSetStateFromStorage(state);
1763       } else if (typeof localStorage !== "undefined" && localStorage !== null) {
1764         return localStorage.setItem(this.getCookieName(), state);
1765       } else if ($.cookie) {
1766         $.cookie.raw = true;
1767         return $.cookie(this.getCookieName(), state, {
1768           path: '/'
1769         });
1770       }
1771     };
1772
1773     SaveStateHandler.prototype.restoreState = function() {
1774       var state;
1775       state = this.getStateFromStorage();
1776       if (state) {
1777         this.setState($.parseJSON(state));
1778         return true;
1779       } else {
1780         return false;
1781       }
1782     };
1783
1784     SaveStateHandler.prototype.getStateFromStorage = function() {
1785       if (this.tree_widget.options.onGetStateFromStorage) {
1786         return this.tree_widget.options.onGetStateFromStorage();
1787       } else if (typeof localStorage !== "undefined" && localStorage !== null) {
1788         return localStorage.getItem(this.getCookieName());
1789       } else if ($.cookie) {
1790         $.cookie.raw = true;
1791         return $.cookie(this.getCookieName());
1792       } else {
1793         return null;
1794       }
1795     };
1796
1797     SaveStateHandler.prototype.getState = function() {
1798       var open_nodes, selected_node, selected_node_id,
1799         _this = this;
1800       open_nodes = [];
1801       this.tree_widget.tree.iterate(function(node) {
1802         if (node.is_open && node.id && node.hasChildren()) {
1803           open_nodes.push(node.id);
1804         }
1805         return true;
1806       });
1807       selected_node = this.tree_widget.getSelectedNode();
1808       if (selected_node) {
1809         selected_node_id = selected_node.id;
1810       } else {
1811         selected_node_id = '';
1812       }
1813       return {
1814         open_nodes: open_nodes,
1815         selected_node: selected_node_id
1816       };
1817     };
1818
1819     SaveStateHandler.prototype.setState = function(state) {
1820       var open_nodes, selected_node, selected_node_id,
1821         _this = this;
1822       if (state) {
1823         open_nodes = state.open_nodes;
1824         selected_node_id = state.selected_node;
1825         this.tree_widget.tree.iterate(function(node) {
1826           node.is_open = node.id && node.hasChildren() && (indexOf(open_nodes, node.id) >= 0);
1827           return true;
1828         });
1829         if (selected_node_id && this.tree_widget.select_node_handler) {
1830           this.tree_widget.select_node_handler.clear();
1831           selected_node = this.tree_widget.getNodeById(selected_node_id);
1832           if (selected_node) {
1833             return this.tree_widget.select_node_handler.addToSelection(selected_node);
1834           }
1835         }
1836       }
1837     };
1838
1839     SaveStateHandler.prototype.getCookieName = function() {
1840       if (typeof this.tree_widget.options.saveState === 'string') {
1841         return this.tree_widget.options.saveState;
1842       } else {
1843         return 'tree';
1844       }
1845     };
1846
1847     return SaveStateHandler;
1848
1849   })();
1850
1851   SelectNodeHandler = (function() {
1852     function SelectNodeHandler(tree_widget) {
1853       this.tree_widget = tree_widget;
1854       this.clear();
1855     }
1856
1857     SelectNodeHandler.prototype.getSelectedNode = function() {
1858       var selected_nodes;
1859       selected_nodes = this.getSelectedNodes();
1860       if (selected_nodes.length) {
1861         return selected_nodes[0];
1862       } else {
1863         return false;
1864       }
1865     };
1866
1867     SelectNodeHandler.prototype.getSelectedNodes = function() {
1868       var id, node, selected_nodes;
1869       if (this.selected_single_node) {
1870         return [this.selected_single_node];
1871       } else {
1872         selected_nodes = [];
1873         for (id in this.selected_nodes) {
1874           node = this.tree_widget.getNodeById(id);
1875           if (node) {
1876             selected_nodes.push(node);
1877           }
1878         }
1879         return selected_nodes;
1880       }
1881     };
1882
1883     SelectNodeHandler.prototype.isNodeSelected = function(node) {
1884       if (node.id) {
1885         return this.selected_nodes[node.id];
1886       } else if (this.selected_single_node) {
1887         return this.selected_single_node.element === node.element;
1888       } else {
1889         return false;
1890       }
1891     };
1892
1893     SelectNodeHandler.prototype.clear = function() {
1894       this.selected_nodes = {};
1895       return this.selected_single_node = null;
1896     };
1897
1898     SelectNodeHandler.prototype.removeFromSelection = function(node, include_children) {
1899       var _this = this;
1900       if (include_children == null) {
1901         include_children = false;
1902       }
1903       if (!node.id) {
1904         if (node.element === this.selected_single_node.element) {
1905           return this.selected_single_node = null;
1906         }
1907       } else {
1908         delete this.selected_nodes[node.id];
1909         if (include_children) {
1910           return node.iterate(function(n) {
1911             delete _this.selected_nodes[node.id];
1912             return true;
1913           });
1914         }
1915       }
1916     };
1917
1918     SelectNodeHandler.prototype.addToSelection = function(node) {
1919       if (node.id) {
1920         return this.selected_nodes[node.id] = true;
1921       } else {
1922         return this.selected_single_node = node;
1923       }
1924     };
1925
1926     return SelectNodeHandler;
1927
1928   })();
1929
1930   DragAndDropHandler = (function() {
1931     function DragAndDropHandler(tree_widget) {
1932       this.tree_widget = tree_widget;
1933       this.hovered_area = null;
1934       this.$ghost = null;
1935       this.hit_areas = [];
1936       this.is_dragging = false;
1937     }
1938
1939     DragAndDropHandler.prototype.mouseCapture = function(position_info) {
1940       var $element, node_element;
1941       $element = $(position_info.target);
1942       if (this.tree_widget.options.onIsMoveHandle && !this.tree_widget.options.onIsMoveHandle($element)) {
1943         return null;
1944       }
1945       node_element = this.tree_widget._getNodeElement($element);
1946       if (node_element && this.tree_widget.options.onCanMove) {
1947         if (!this.tree_widget.options.onCanMove(node_element.node)) {
1948           node_element = null;
1949         }
1950       }
1951       this.current_item = node_element;
1952       return this.current_item !== null;
1953     };
1954
1955     DragAndDropHandler.prototype.mouseStart = function(position_info) {
1956       var offset;
1957       this.refreshHitAreas();
1958       offset = $(position_info.target).offset();
1959       this.drag_element = new DragElement(this.current_item.node, position_info.page_x - offset.left, position_info.page_y - offset.top, this.tree_widget.element);
1960       this.is_dragging = true;
1961       this.current_item.$element.addClass('jqtree-moving');
1962       return true;
1963     };
1964
1965     DragAndDropHandler.prototype.mouseDrag = function(position_info) {
1966       var area, can_move_to;
1967       this.drag_element.move(position_info.page_x, position_info.page_y);
1968       area = this.findHoveredArea(position_info.page_x, position_info.page_y);
1969       can_move_to = this.canMoveToArea(area);
1970       if (area) {
1971         if (this.hovered_area !== area) {
1972           this.hovered_area = area;
1973           if (this.mustOpenFolderTimer(area)) {
1974             this.startOpenFolderTimer(area.node);
1975           }
1976           if (can_move_to) {
1977             this.updateDropHint();
1978           }
1979         }
1980       } else {
1981         this.removeHover();
1982         this.removeDropHint();
1983         this.stopOpenFolderTimer();
1984       }
1985       return true;
1986     };
1987
1988     DragAndDropHandler.prototype.canMoveToArea = function(area) {
1989       var position_name;
1990       if (!area) {
1991         return false;
1992       } else if (this.tree_widget.options.onCanMoveTo) {
1993         position_name = Position.getName(area.position);
1994         return this.tree_widget.options.onCanMoveTo(this.current_item.node, area.node, position_name);
1995       } else {
1996         return true;
1997       }
1998     };
1999
2000     DragAndDropHandler.prototype.mouseStop = function(position_info) {
2001       this.moveItem(position_info);
2002       this.clear();
2003       this.removeHover();
2004       this.removeDropHint();
2005       this.removeHitAreas();
2006       if (this.current_item) {
2007         this.current_item.$element.removeClass('jqtree-moving');
2008       }
2009       this.is_dragging = false;
2010       return false;
2011     };
2012
2013     DragAndDropHandler.prototype.refreshHitAreas = function() {
2014       this.removeHitAreas();
2015       return this.generateHitAreas();
2016     };
2017
2018     DragAndDropHandler.prototype.removeHitAreas = function() {
2019       return this.hit_areas = [];
2020     };
2021
2022     DragAndDropHandler.prototype.clear = function() {
2023       this.drag_element.remove();
2024       return this.drag_element = null;
2025     };
2026
2027     DragAndDropHandler.prototype.removeDropHint = function() {
2028       if (this.previous_ghost) {
2029         return this.previous_ghost.remove();
2030       }
2031     };
2032
2033     DragAndDropHandler.prototype.removeHover = function() {
2034       return this.hovered_area = null;
2035     };
2036
2037     DragAndDropHandler.prototype.generateHitAreas = function() {
2038       var addPosition, getTop, groupPositions, handleAfterOpenFolder, handleClosedFolder, handleFirstNode, handleNode, handleOpenFolder, hit_areas, last_top, positions,
2039         _this = this;
2040       positions = [];
2041       last_top = 0;
2042       getTop = function($element) {
2043         return $element.offset().top;
2044       };
2045       addPosition = function(node, position, top) {
2046         positions.push({
2047           top: top,
2048           node: node,
2049           position: position
2050         });
2051         return last_top = top;
2052       };
2053       groupPositions = function(handle_group) {
2054         var group, position, previous_top, _i, _len;
2055         previous_top = -1;
2056         group = [];
2057         for (_i = 0, _len = positions.length; _i < _len; _i++) {
2058           position = positions[_i];
2059           if (position.top !== previous_top) {
2060             if (group.length) {
2061               handle_group(group, previous_top, position.top);
2062             }
2063             previous_top = position.top;
2064             group = [];
2065           }
2066           group.push(position);
2067         }
2068         return handle_group(group, previous_top, _this.tree_widget.element.offset().top + _this.tree_widget.element.height());
2069       };
2070       handleNode = function(node, next_node, $element) {
2071         var top;
2072         top = getTop($element);
2073         if (node === _this.current_item.node) {
2074           addPosition(node, Position.NONE, top);
2075         } else {
2076           addPosition(node, Position.INSIDE, top);
2077         }
2078         if (next_node === _this.current_item.node || node === _this.current_item.node) {
2079           return addPosition(node, Position.NONE, top);
2080         } else {
2081           return addPosition(node, Position.AFTER, top);
2082         }
2083       };
2084       handleOpenFolder = function(node, $element) {
2085         if (node === _this.current_item.node) {
2086           return false;
2087         }
2088         if (node.children[0] !== _this.current_item.node) {
2089           addPosition(node, Position.INSIDE, getTop($element));
2090         }
2091         return true;
2092       };
2093       handleAfterOpenFolder = function(node, next_node, $element) {
2094         if (node === _this.current_item.node || next_node === _this.current_item.node) {
2095           return addPosition(node, Position.NONE, last_top);
2096         } else {
2097           return addPosition(node, Position.AFTER, last_top);
2098         }
2099       };
2100       handleClosedFolder = function(node, next_node, $element) {
2101         var top;
2102         top = getTop($element);
2103         if (node === _this.current_item.node) {
2104           return addPosition(node, Position.NONE, top);
2105         } else {
2106           addPosition(node, Position.INSIDE, top);
2107           if (next_node !== _this.current_item.node) {
2108             return addPosition(node, Position.AFTER, top);
2109           }
2110         }
2111       };
2112       handleFirstNode = function(node, $element) {
2113         if (node !== _this.current_item.node) {
2114           return addPosition(node, Position.BEFORE, getTop($(node.element)));
2115         }
2116       };
2117       this.iterateVisibleNodes(handleNode, handleOpenFolder, handleClosedFolder, handleAfterOpenFolder, handleFirstNode);
2118       hit_areas = [];
2119       groupPositions(function(positions_in_group, top, bottom) {
2120         var area_height, area_top, position, _i, _len;
2121         area_height = (bottom - top) / positions_in_group.length;
2122         area_top = top;
2123         for (_i = 0, _len = positions_in_group.length; _i < _len; _i++) {
2124           position = positions_in_group[_i];
2125           hit_areas.push({
2126             top: area_top,
2127             bottom: area_top + area_height,
2128             node: position.node,
2129             position: position.position
2130           });
2131           area_top += area_height;
2132         }
2133         return null;
2134       });
2135       return this.hit_areas = hit_areas;
2136     };
2137
2138     DragAndDropHandler.prototype.iterateVisibleNodes = function(handle_node, handle_open_folder, handle_closed_folder, handle_after_open_folder, handle_first_node) {
2139       var is_first_node, iterate,
2140         _this = this;
2141       is_first_node = true;
2142       iterate = function(node, next_node) {
2143         var $element, child, children_length, i, must_iterate_inside, _i, _len, _ref3;
2144         must_iterate_inside = (node.is_open || !node.element) && node.hasChildren();
2145         if (node.element) {
2146           $element = $(node.element);
2147           if (!$element.is(':visible')) {
2148             return;
2149           }
2150           if (is_first_node) {
2151             handle_first_node(node, $element);
2152             is_first_node = false;
2153           }
2154           if (!node.hasChildren()) {
2155             handle_node(node, next_node, $element);
2156           } else if (node.is_open) {
2157             if (!handle_open_folder(node, $element)) {
2158               must_iterate_inside = false;
2159             }
2160           } else {
2161             handle_closed_folder(node, next_node, $element);
2162           }
2163         }
2164         if (must_iterate_inside) {
2165           children_length = node.children.length;
2166           _ref3 = node.children;
2167           for (i = _i = 0, _len = _ref3.length; _i < _len; i = ++_i) {
2168             child = _ref3[i];
2169             if (i === (children_length - 1)) {
2170               iterate(node.children[i], null);
2171             } else {
2172               iterate(node.children[i], node.children[i + 1]);
2173             }
2174           }
2175           if (node.is_open) {
2176             return handle_after_open_folder(node, next_node, $element);
2177           }
2178         }
2179       };
2180       return iterate(this.tree_widget.tree);
2181     };
2182
2183     DragAndDropHandler.prototype.findHoveredArea = function(x, y) {
2184       var area, high, low, mid, tree_offset;
2185       tree_offset = this.tree_widget.element.offset();
2186       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())) {
2187         return null;
2188       }
2189       low = 0;
2190       high = this.hit_areas.length;
2191       while (low < high) {
2192         mid = (low + high) >> 1;
2193         area = this.hit_areas[mid];
2194         if (y < area.top) {
2195           high = mid;
2196         } else if (y > area.bottom) {
2197           low = mid + 1;
2198         } else {
2199           return area;
2200         }
2201       }
2202       return null;
2203     };
2204
2205     DragAndDropHandler.prototype.mustOpenFolderTimer = function(area) {
2206       var node;
2207       node = area.node;
2208       return node.isFolder() && !node.is_open && area.position === Position.INSIDE;
2209     };
2210
2211     DragAndDropHandler.prototype.updateDropHint = function() {
2212       var node_element;
2213       if (!this.hovered_area) {
2214         return;
2215       }
2216       this.removeDropHint();
2217       node_element = this.tree_widget._getNodeElementForNode(this.hovered_area.node);
2218       return this.previous_ghost = node_element.addDropHint(this.hovered_area.position);
2219     };
2220
2221     DragAndDropHandler.prototype.startOpenFolderTimer = function(folder) {
2222       var openFolder,
2223         _this = this;
2224       openFolder = function() {
2225         return _this.tree_widget._openNode(folder, _this.tree_widget.options.slide, function() {
2226           _this.refreshHitAreas();
2227           return _this.updateDropHint();
2228         });
2229       };
2230       return this.open_folder_timer = setTimeout(openFolder, 500);
2231     };
2232
2233     DragAndDropHandler.prototype.stopOpenFolderTimer = function() {
2234       if (this.open_folder_timer) {
2235         clearTimeout(this.open_folder_timer);
2236         return this.open_folder_timer = null;
2237       }
2238     };
2239
2240     DragAndDropHandler.prototype.moveItem = function(position_info) {
2241       var doMove, event, moved_node, position, previous_parent, target_node,
2242         _this = this;
2243       if (this.hovered_area && this.hovered_area.position !== Position.NONE && this.canMoveToArea(this.hovered_area)) {
2244         moved_node = this.current_item.node;
2245         target_node = this.hovered_area.node;
2246         position = this.hovered_area.position;
2247         previous_parent = moved_node.parent;
2248         if (position === Position.INSIDE) {
2249           this.hovered_area.node.is_open = true;
2250         }
2251         doMove = function() {
2252           _this.tree_widget.tree.moveNode(moved_node, target_node, position);
2253           _this.tree_widget.element.empty();
2254           return _this.tree_widget._refreshElements();
2255         };
2256         event = this.tree_widget._triggerEvent('tree.move', {
2257           move_info: {
2258             moved_node: moved_node,
2259             target_node: target_node,
2260             position: Position.getName(position),
2261             previous_parent: previous_parent,
2262             do_move: doMove,
2263             original_event: position_info.original_event
2264           }
2265         });
2266         if (!event.isDefaultPrevented()) {
2267           return doMove();
2268         }
2269       }
2270     };
2271
2272     return DragAndDropHandler;
2273
2274   })();
2275
2276   DragElement = (function() {
2277     function DragElement(node, offset_x, offset_y, $tree) {
2278       this.offset_x = offset_x;
2279       this.offset_y = offset_y;
2280       this.$element = $("<span class=\"jqtree-title jqtree-dragging\">" + node.name + "</span>");
2281       this.$element.css("position", "absolute");
2282       $tree.append(this.$element);
2283     }
2284
2285     DragElement.prototype.move = function(page_x, page_y) {
2286       return this.$element.offset({
2287         left: page_x - this.offset_x,
2288         top: page_y - this.offset_y
2289       });
2290     };
2291
2292     DragElement.prototype.remove = function() {
2293       return this.$element.remove();
2294     };
2295
2296     return DragElement;
2297
2298   })();
2299
2300   GhostDropHint = (function() {
2301     function GhostDropHint(node, $element, position) {
2302       this.$element = $element;
2303       this.node = node;
2304       this.$ghost = $('<li class="jqtree_common jqtree-ghost"><span class="jqtree_common jqtree-circle"></span><span class="jqtree_common jqtree-line"></span></li>');
2305       if (position === Position.AFTER) {
2306         this.moveAfter();
2307       } else if (position === Position.BEFORE) {
2308         this.moveBefore();
2309       } else if (position === Position.INSIDE) {
2310         if (node.isFolder() && node.is_open) {
2311           this.moveInsideOpenFolder();
2312         } else {
2313           this.moveInside();
2314         }
2315       }
2316     }
2317
2318     GhostDropHint.prototype.remove = function() {
2319       return this.$ghost.remove();
2320     };
2321
2322     GhostDropHint.prototype.moveAfter = function() {
2323       return this.$element.after(this.$ghost);
2324     };
2325
2326     GhostDropHint.prototype.moveBefore = function() {
2327       return this.$element.before(this.$ghost);
2328     };
2329
2330     GhostDropHint.prototype.moveInsideOpenFolder = function() {
2331       return $(this.node.children[0].element).before(this.$ghost);
2332     };
2333
2334     GhostDropHint.prototype.moveInside = function() {
2335       this.$element.after(this.$ghost);
2336       return this.$ghost.addClass('jqtree-inside');
2337     };
2338
2339     return GhostDropHint;
2340
2341   })();
2342
2343   BorderDropHint = (function() {
2344     function BorderDropHint($element) {
2345       var $div, width;
2346       $div = $element.children('.jqtree-element');
2347       width = $element.width() - 4;
2348       this.$hint = $('<span class="jqtree-border"></span>');
2349       $div.append(this.$hint);
2350       this.$hint.css({
2351         width: width,
2352         height: $div.height() - 4
2353       });
2354     }
2355
2356     BorderDropHint.prototype.remove = function() {
2357       return this.$hint.remove();
2358     };
2359
2360     return BorderDropHint;
2361
2362   })();
2363
2364   ScrollHandler = (function() {
2365     function ScrollHandler(tree_widget) {
2366       this.tree_widget = tree_widget;
2367       this.previous_top = -1;
2368       this._initScrollParent();
2369     }
2370
2371     ScrollHandler.prototype._initScrollParent = function() {
2372       var $scroll_parent, getParentWithOverflow, setDocumentAsScrollParent,
2373         _this = this;
2374       getParentWithOverflow = function() {
2375         var css_value, css_values, parent, scroll_parent, _i, _j, _len, _len1, _ref3, _ref4;
2376         css_values = ['overflow', 'overflow-y'];
2377         scroll_parent = null;
2378         _ref3 = _this.tree_widget.$el.parents();
2379         for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
2380           parent = _ref3[_i];
2381           for (_j = 0, _len1 = css_values.length; _j < _len1; _j++) {
2382             css_value = css_values[_j];
2383             if ((_ref4 = $.css(parent, css_value)) === 'auto' || _ref4 === 'scroll') {
2384               return $(parent);
2385             }
2386           }
2387         }
2388         return null;
2389       };
2390       setDocumentAsScrollParent = function() {
2391         _this.scroll_parent_top = 0;
2392         return _this.$scroll_parent = null;
2393       };
2394       if (this.tree_widget.$el.css('position') === 'fixed') {
2395         setDocumentAsScrollParent();
2396       }
2397       $scroll_parent = getParentWithOverflow();
2398       if ($scroll_parent && $scroll_parent.length && $scroll_parent[0].tagName !== 'HTML') {
2399         this.$scroll_parent = $scroll_parent;
2400         return this.scroll_parent_top = this.$scroll_parent.offset().top;
2401       } else {
2402         return setDocumentAsScrollParent();
2403       }
2404     };
2405
2406     ScrollHandler.prototype.checkScrolling = function() {
2407       var hovered_area;
2408       hovered_area = this.tree_widget.dnd_handler.hovered_area;
2409       if (hovered_area && hovered_area.top !== this.previous_top) {
2410         this.previous_top = hovered_area.top;
2411         if (this.$scroll_parent) {
2412           return this._handleScrollingWithScrollParent(hovered_area);
2413         } else {
2414           return this._handleScrollingWithDocument(hovered_area);
2415         }
2416       }
2417     };
2418
2419     ScrollHandler.prototype._handleScrollingWithScrollParent = function(area) {
2420       var distance_bottom;
2421       distance_bottom = this.scroll_parent_top + this.$scroll_parent[0].offsetHeight - area.bottom;
2422       if (distance_bottom < 20) {
2423         this.$scroll_parent[0].scrollTop += 20;
2424         this.tree_widget.refreshHitAreas();
2425         return this.previous_top = -1;
2426       } else if ((area.top - this.scroll_parent_top) < 20) {
2427         this.$scroll_parent[0].scrollTop -= 20;
2428         this.tree_widget.refreshHitAreas();
2429         return this.previous_top = -1;
2430       }
2431     };
2432
2433     ScrollHandler.prototype._handleScrollingWithDocument = function(area) {
2434       var distance_top;
2435       distance_top = area.top - $(document).scrollTop();
2436       if (distance_top < 20) {
2437         return $(document).scrollTop($(document).scrollTop() - 20);
2438       } else if ($(window).height() - (area.bottom - $(document).scrollTop()) < 20) {
2439         return $(document).scrollTop($(document).scrollTop() + 20);
2440       }
2441     };
2442
2443     ScrollHandler.prototype.scrollTo = function(top) {
2444       var tree_top;
2445       if (this.$scroll_parent) {
2446         return this.$scroll_parent[0].scrollTop = top;
2447       } else {
2448         tree_top = this.tree_widget.$el.offset().top;
2449         return $(document).scrollTop(top + tree_top);
2450       }
2451     };
2452
2453     ScrollHandler.prototype.isScrolledIntoView = function(element) {
2454       var $element, element_bottom, element_top, view_bottom, view_top;
2455       $element = $(element);
2456       if (this.$scroll_parent) {
2457         view_top = 0;
2458         view_bottom = this.$scroll_parent.height();
2459         element_top = $element.offset().top - this.scroll_parent_top;
2460         element_bottom = element_top + $element.height();
2461       } else {
2462         view_top = $(window).scrollTop();
2463         view_bottom = view_top + $(window).height();
2464         element_top = $element.offset().top;
2465         element_bottom = element_top + $element.height();
2466       }
2467       return (element_bottom <= view_bottom) && (element_top >= view_top);
2468     };
2469
2470     return ScrollHandler;
2471
2472   })();
2473
2474   KeyHandler = (function() {
2475     var DOWN, LEFT, RIGHT, UP;
2476
2477     LEFT = 37;
2478
2479     UP = 38;
2480
2481     RIGHT = 39;
2482
2483     DOWN = 40;
2484
2485     function KeyHandler(tree_widget) {
2486       this.tree_widget = tree_widget;
2487       $(document).bind('keydown.jqtree', $.proxy(this.handleKeyDown, this));
2488     }
2489
2490     KeyHandler.prototype.deinit = function() {
2491       return $(document).unbind('keydown.jqtree');
2492     };
2493
2494     KeyHandler.prototype.handleKeyDown = function(e) {
2495       var current_node, key, moveDown, moveLeft, moveRight, moveUp, selectNode,
2496         _this = this;
2497       current_node = this.tree_widget.getSelectedNode();
2498       selectNode = function(node) {
2499         if (node) {
2500           _this.tree_widget.selectNode(node);
2501           if (_this.tree_widget.scroll_handler && (!_this.tree_widget.scroll_handler.isScrolledIntoView($(node.element).find('.jqtree-element')))) {
2502             _this.tree_widget.scrollToNode(node);
2503           }
2504           return false;
2505         } else {
2506           return true;
2507         }
2508       };
2509       moveDown = function() {
2510         return selectNode(_this.getNextNode(current_node));
2511       };
2512       moveUp = function() {
2513         return selectNode(_this.getPreviousNode(current_node));
2514       };
2515       moveRight = function() {
2516         if (current_node.hasChildren() && !current_node.is_open) {
2517           _this.tree_widget.openNode(current_node);
2518           return false;
2519         } else {
2520           return true;
2521         }
2522       };
2523       moveLeft = function() {
2524         if (current_node.hasChildren() && current_node.is_open) {
2525           _this.tree_widget.closeNode(current_node);
2526           return false;
2527         } else {
2528           return true;
2529         }
2530       };
2531       if (!current_node) {
2532         return true;
2533       } else {
2534         key = e.which;
2535         switch (key) {
2536           case DOWN:
2537             return moveDown();
2538           case UP:
2539             return moveUp();
2540           case RIGHT:
2541             return moveRight();
2542           case LEFT:
2543             return moveLeft();
2544         }
2545       }
2546     };
2547
2548     KeyHandler.prototype.getNextNode = function(node, include_children) {
2549       var next_sibling;
2550       if (include_children == null) {
2551         include_children = true;
2552       }
2553       if (include_children && node.hasChildren() && node.is_open) {
2554         return node.children[0];
2555       } else {
2556         if (!node.parent) {
2557           return null;
2558         } else {
2559           next_sibling = node.getNextSibling();
2560           if (next_sibling) {
2561             return next_sibling;
2562           } else {
2563             return this.getNextNode(node.parent, false);
2564           }
2565         }
2566       }
2567     };
2568
2569     KeyHandler.prototype.getPreviousNode = function(node) {
2570       var previous_sibling;
2571       if (!node.parent) {
2572         return null;
2573       } else {
2574         previous_sibling = node.getPreviousSibling();
2575         if (previous_sibling) {
2576           if (!previous_sibling.hasChildren() || !previous_sibling.is_open) {
2577             return previous_sibling;
2578           } else {
2579             return this.getLastChild(previous_sibling);
2580           }
2581         } else {
2582           if (node.parent.parent) {
2583             return node.parent;
2584           } else {
2585             return null;
2586           }
2587         }
2588       }
2589     };
2590
2591     KeyHandler.prototype.getLastChild = function(node) {
2592       var last_child;
2593       if (!node.hasChildren()) {
2594         return null;
2595       } else {
2596         last_child = node.children[node.children.length - 1];
2597         if (!last_child.hasChildren() || !last_child.is_open) {
2598           return last_child;
2599         } else {
2600           return this.getLastChild(last_child);
2601         }
2602       }
2603     };
2604
2605     return KeyHandler;
2606
2607   })();
2608
2609 }).call(this);