1// Generated by CoffeeScript 1.6.3
2/*
3Copyright 2013 Marco Braak
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9    http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations 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);
2610