Home | History | Annotate | Download | only in jqTree
      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);
   2610