1 // Generated by CoffeeScript 1.6.3
3 Copyright 2013 Marco Braak
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
9 http://www.apache.org/licenses/LICENSE-2.0
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.
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,
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; };
27 SimpleWidget = (function() {
28 SimpleWidget.prototype.defaults = {};
30 function SimpleWidget(el, options) {
32 this.options = $.extend({}, this.defaults, options);
35 SimpleWidget.prototype.destroy = function() {
36 return this._deinit();
39 SimpleWidget.prototype._init = function() {
43 SimpleWidget.prototype._deinit = function() {
47 SimpleWidget.register = function(widget_class, widget_name) {
48 var callFunction, createWidget, destroyWidget, getDataKey;
49 getDataKey = function() {
50 return "simple_widget_" + widget_name;
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++) {
57 widget = new widget_class(el, options);
58 if (!$.data(el, data_key)) {
59 $.data(el, data_key, widget);
65 destroyWidget = function($el) {
66 var data_key, el, widget, _i, _len, _results;
67 data_key = getDataKey();
69 for (_i = 0, _len = $el.length; _i < _len; _i++) {
71 widget = $.data(el, data_key);
72 if (widget && (widget instanceof SimpleWidget)) {
75 _results.push($.removeData(el, data_key));
79 callFunction = function($el, function_name, args) {
80 var el, result, widget, widget_function, _i, _len;
82 for (_i = 0, _len = $el.length; _i < _len; _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);
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) : [];
98 if (argument1 === void 0 || typeof argument1 === 'object') {
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);
106 return callFunction($el, function_name, args);
116 this.SimpleWidget = SimpleWidget;
119 This widget does the same a the mouse widget in jqueryui.
123 MouseWidget = (function(_super) {
124 __extends(MouseWidget, _super);
126 function MouseWidget() {
127 _ref = MouseWidget.__super__.constructor.apply(this, arguments);
131 MouseWidget.is_mouse_handled = false;
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;
143 MouseWidget.prototype._deinit = function() {
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');
152 MouseWidget.prototype._mouseDown = function(e) {
157 result = this._handleMouseDown(e, this._getPositionInfo(e));
164 MouseWidget.prototype._handleMouseDown = function(e, position_info) {
165 if (MouseWidget.is_mouse_handled) {
168 if (this.is_mouse_started) {
169 this._handleMouseUp(position_info);
171 this.mouse_down_info = position_info;
172 if (!this._mouseCapture(position_info)) {
175 this._handleStartMouse();
176 this.is_mouse_handled = true;
180 MouseWidget.prototype._handleStartMouse = function() {
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();
192 MouseWidget.prototype._startMouseDelayTimer = function() {
194 if (this._mouse_delay_timer) {
195 clearTimeout(this._mouse_delay_timer);
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;
203 MouseWidget.prototype._mouseMove = function(e) {
204 return this._handleMouseMove(e, this._getPositionInfo(e));
207 MouseWidget.prototype._handleMouseMove = function(e, position_info) {
208 if (this.is_mouse_started) {
209 this._mouseDrag(position_info);
210 return e.preventDefault();
212 if (this.mouse_delay && !this._is_mouse_delay_met) {
215 this.is_mouse_started = this._mouseStart(this.mouse_down_info) !== false;
216 if (this.is_mouse_started) {
217 this._mouseDrag(position_info);
219 this._handleMouseUp(position_info);
221 return !this.is_mouse_started;
224 MouseWidget.prototype._getPositionInfo = function(e) {
233 MouseWidget.prototype._mouseUp = function(e) {
234 return this._handleMouseUp(this._getPositionInfo(e));
237 MouseWidget.prototype._handleMouseUp = function(position_info) {
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);
250 MouseWidget.prototype._mouseCapture = function(position_info) {
254 MouseWidget.prototype._mouseStart = function(position_info) {
258 MouseWidget.prototype._mouseDrag = function(position_info) {
262 MouseWidget.prototype._mouseStop = function(position_info) {
266 MouseWidget.prototype.setMouseDelay = function(mouse_delay) {
267 return this.mouse_delay = mouse_delay;
270 MouseWidget.prototype._touchStart = function(e) {
272 if (e.originalEvent.touches.length > 1) {
275 touch = e.originalEvent.changedTouches[0];
276 return this._handleMouseDown(e, this._getPositionInfo(touch));
279 MouseWidget.prototype._touchMove = function(e) {
281 if (e.originalEvent.touches.length > 1) {
284 touch = e.originalEvent.changedTouches[0];
285 return this._handleMouseMove(e, this._getPositionInfo(touch));
288 MouseWidget.prototype._touchEnd = function(e) {
290 if (e.originalEvent.touches.length > 1) {
293 touch = e.originalEvent.changedTouches[0];
294 return this._handleMouseUp(this._getPositionInfo(touch));
306 getName: function(position) {
307 return Position.strings[position - 1];
309 nameToIndex: function(name) {
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) {
328 Position.strings = ['before', 'after', 'inside', 'none'];
330 this.Tree.Position = Position;
333 function Node(o, is_root, node_class) {
334 if (is_root == null) {
337 if (node_class == null) {
344 this.id_mapping = {};
346 this.node_class = node_class;
350 Node.prototype.setData = function(o) {
351 var key, value, _results;
352 if (typeof o !== 'object') {
353 return this.name = o;
358 if (key === 'label') {
359 _results.push(this.name = value);
361 _results.push(this[key] = value);
368 Node.prototype.initFromData = function(data) {
369 var addChildren, addNode,
371 addNode = function(node_data) {
372 _this.setData(node_data);
373 if (node_data.children) {
374 return addChildren(node_data.children);
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);
392 Create tree from data.
394 Structure of data is:
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++) {
415 node = new this.tree.node_class(o);
417 if (typeof o === 'object' && o.children) {
418 node.loadFromData(o.children);
433 Node.prototype.addChild = function(node) {
434 this.children.push(node);
435 return node._setParent(this);
439 Add child at position. Index starts at 0.
441 tree.addChildAtPosition(
448 Node.prototype.addChildAtPosition = function(node, index) {
449 this.children.splice(index, 0, node);
450 return node._setParent(this);
453 Node.prototype._setParent = function(parent) {
454 this.parent = parent;
455 this.tree = parent.tree;
456 return this.tree.addNodeToIndex(this);
460 Remove child. This also removes the children of the node.
462 tree.removeChild(tree.children[0]);
466 Node.prototype.removeChild = function(node) {
467 node.removeChildren();
468 return this._removeChild(node);
471 Node.prototype._removeChild = function(node) {
472 this.children.splice(this.getChildIndex(node), 1);
473 return this.tree.removeNodeFromIndex(node);
479 var index = getChildIndex(node);
483 Node.prototype.getChildIndex = function(node) {
484 return $.inArray(node, this.children);
488 Does the tree have children?
490 if (tree.hasChildren()) {
496 Node.prototype.hasChildren = function() {
497 return this.children.length !== 0;
500 Node.prototype.isFolder = function() {
501 return this.hasChildren() || this.load_on_demand;
505 Iterate over all the nodes in the tree.
507 Calls callback with (node, level).
509 The callback must return true to continue the iteration on current node.
512 function(node, level) {
513 console.log(node.name);
515 // stop iteration after level 2
522 Node.prototype.iterate = function(callback) {
525 _iterate = function(node, level) {
526 var child, result, _i, _len, _ref1;
528 _ref1 = node.children;
529 for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
531 result = callback(child, level);
532 if (_this.hasChildren() && result) {
533 _iterate(child, level + 1);
544 Move node relative to another node.
546 Argument position: Position.BEFORE, Position.AFTER or Position.Inside
548 // move node1 after node2
549 tree.moveNode(node1, node2, Position.AFTER);
553 Node.prototype.moveNode = function(moved_node, target_node, position) {
554 if (moved_node.isParentOf(target_node)) {
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);
568 Get the tree as data.
572 Node.prototype.getData = function() {
573 var getDataFromNodes,
575 getDataFromNodes = function(nodes) {
576 var data, k, node, tmp_node, v, _i, _len;
578 for (_i = 0, _len = nodes.length; _i < _len; _i++) {
583 if ((k !== 'parent' && k !== 'children' && k !== 'element' && k !== 'tree') && Object.prototype.hasOwnProperty.call(node, k)) {
587 if (node.hasChildren()) {
588 tmp_node.children = getDataFromNodes(node.children);
594 return getDataFromNodes(this.children);
597 Node.prototype.getNodeByName = function(name) {
600 this.iterate(function(node) {
601 if (node.name === name) {
611 Node.prototype.addAfter = function(node_info) {
612 var child_index, node;
616 node = new this.tree.node_class(node_info);
617 child_index = this.parent.getChildIndex(this);
618 this.parent.addChildAtPosition(node, child_index + 1);
623 Node.prototype.addBefore = function(node_info) {
624 var child_index, node;
628 node = new this.tree.node_class(node_info);
629 child_index = this.parent.getChildIndex(this);
630 this.parent.addChildAtPosition(node, child_index);
635 Node.prototype.addParent = function(node_info) {
636 var child, new_parent, original_parent, _i, _len, _ref1;
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++) {
646 new_parent.addChild(child);
648 original_parent.children = [];
649 original_parent.addChild(new_parent);
654 Node.prototype.remove = function() {
656 this.parent.removeChild(this);
657 return this.parent = null;
661 Node.prototype.append = function(node_info) {
663 node = new this.tree.node_class(node_info);
668 Node.prototype.prepend = function(node_info) {
670 node = new this.tree.node_class(node_info);
671 this.addChildAtPosition(node, 0);
675 Node.prototype.isParentOf = function(node) {
677 parent = node.parent;
679 if (parent === this) {
682 parent = parent.parent;
687 Node.prototype.getLevel = function() {
691 while (node.parent) {
698 Node.prototype.getNodeById = function(node_id) {
699 return this.id_mapping[node_id];
702 Node.prototype.addNodeToIndex = function(node) {
704 return this.id_mapping[node.id] = node;
708 Node.prototype.removeNodeFromIndex = function(node) {
710 return delete this.id_mapping[node.id];
714 Node.prototype.removeChildren = function() {
716 this.iterate(function(child) {
717 _this.tree.removeNodeFromIndex(child);
720 return this.children = [];
723 Node.prototype.getPreviousSibling = function() {
728 previous_index = this.parent.getChildIndex(this) - 1;
729 if (previous_index >= 0) {
730 return this.parent.children[previous_index];
737 Node.prototype.getNextSibling = function() {
742 next_index = this.parent.getChildIndex(this) + 1;
743 if (next_index < this.parent.children.length) {
744 return this.parent.children[next_index];
755 this.Tree.Node = Node;
758 Copyright 2013 Marco Braak
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
764 http://www.apache.org/licenses/LICENSE-2.0
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.
774 JqTreeWidget = (function(_super) {
775 __extends(JqTreeWidget, _super);
777 function JqTreeWidget() {
778 _ref1 = JqTreeWidget.__super__.constructor.apply(this, arguments);
782 JqTreeWidget.prototype.defaults = {
787 useContextMenu: true,
788 onCanSelectNode: null,
789 onSetStateFromStorage: null,
790 onGetStateFromStorage: null,
792 onIsMoveHandle: null,
798 closedIcon: '►',
799 openedIcon: '▼',
804 JqTreeWidget.prototype.toggle = function(node, slide) {
809 return this.closeNode(node, slide);
811 return this.openNode(node, slide);
815 JqTreeWidget.prototype.getTree = function() {
819 JqTreeWidget.prototype.selectNode = function(node) {
820 return this._selectNode(node, true);
823 JqTreeWidget.prototype._selectNode = function(node, must_toggle) {
824 var canSelect, openParents, saveState,
826 if (must_toggle == null) {
829 if (!this.select_node_handler) {
832 canSelect = function() {
833 if (_this.options.onCanSelectNode) {
834 return _this.options.selectable && _this.options.onCanSelectNode(node);
836 return _this.options.selectable;
839 openParents = function() {
841 parent = node.parent;
842 if (parent && parent.parent && !parent.is_open) {
843 return _this.openNode(parent, false);
846 saveState = function() {
847 if (_this.options.saveState) {
848 return _this.save_state_handler.saveState();
852 this._deselectCurrentNode();
859 if (this.select_node_handler.isNodeSelected(node)) {
861 this._deselectCurrentNode();
862 this._triggerEvent('tree.select', {
868 this._deselectCurrentNode();
869 this.addToSelection(node);
870 this._triggerEvent('tree.select', {
878 JqTreeWidget.prototype.getSelectedNode = function() {
879 return this.select_node_handler.getSelectedNode();
882 JqTreeWidget.prototype.toJson = function() {
883 return JSON.stringify(this.tree.getData());
886 JqTreeWidget.prototype.loadData = function(data, parent_node) {
887 return this._loadData(data, parent_node);
890 JqTreeWidget.prototype.loadDataFromUrl = function(url, parent_node, on_finished) {
891 if ($.type(url) !== 'string') {
892 on_finished = parent_node;
896 return this._loadDataFromUrl(url, parent_node, on_finished);
899 JqTreeWidget.prototype._loadDataFromUrl = function(url_info, parent_node, on_finished) {
900 var $el, addLoadingClass, parseUrlInfo, removeLoadingClass,
903 addLoadingClass = function() {
908 folder_element = new FolderElement(parent_node, _this);
909 $el = folder_element.getLi();
911 return $el.addClass('jqtree-loading');
913 removeLoadingClass = function() {
915 return $el.removeClass('jqtree-loading');
918 parseUrlInfo = function() {
919 if ($.type(url_info) === 'string') {
924 if (!url_info.method) {
925 return url_info.method = 'get';
930 url_info = this._getDataUrlInfo(parent_node);
936 type: url_info.method.toUpperCase(),
939 success: function(response) {
941 if ($.isArray(response) || typeof response === 'object') {
944 data = $.parseJSON(response);
946 removeLoadingClass();
947 _this._loadData(data, parent_node);
948 if (on_finished && $.isFunction(on_finished)) {
949 return on_finished();
952 error: function(response) {
953 removeLoadingClass();
954 if (_this.options.onLoadFailed) {
955 return _this.options.onLoadFailed(response);
961 JqTreeWidget.prototype._loadData = function(data, parent_node) {
962 var n, selected_nodes_under_parent, _i, _len;
963 this._triggerEvent('tree.load_data', {
967 this._initTree(data);
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);
974 parent_node.loadFromData(data);
975 parent_node.load_on_demand = false;
976 this._refreshElements(parent_node.parent);
978 if (this.is_dragging) {
979 return this.dnd_handler.refreshHitAreas();
983 JqTreeWidget.prototype.getNodeById = function(node_id) {
984 return this.tree.getNodeById(node_id);
987 JqTreeWidget.prototype.getNodeByName = function(name) {
988 return this.tree.getNodeByName(name);
991 JqTreeWidget.prototype.openNode = function(node, slide) {
995 return this._openNode(node, slide);
998 JqTreeWidget.prototype._openNode = function(node, slide, on_finished) {
999 var doOpenNode, parent,
1001 if (slide == null) {
1004 doOpenNode = function(_node, _slide, _on_finished) {
1006 folder_element = new FolderElement(_node, _this);
1007 return folder_element.open(_on_finished, _slide);
1009 if (node.isFolder()) {
1010 if (node.load_on_demand) {
1011 return this._loadFolderOnDemand(node, slide, on_finished);
1013 parent = node.parent;
1014 while (parent && !parent.is_open) {
1015 if (parent.parent) {
1016 doOpenNode(parent, false, null);
1018 parent = parent.parent;
1020 doOpenNode(node, slide, on_finished);
1021 return this._saveState();
1026 JqTreeWidget.prototype._loadFolderOnDemand = function(node, slide, on_finished) {
1028 if (slide == null) {
1031 return this._loadDataFromUrl(null, node, function() {
1032 return _this._openNode(node, slide, on_finished);
1036 JqTreeWidget.prototype.closeNode = function(node, slide) {
1037 if (slide == null) {
1040 if (node.isFolder()) {
1041 new FolderElement(node, this).close(slide);
1042 return this._saveState();
1046 JqTreeWidget.prototype.isDragging = function() {
1047 return this.is_dragging;
1050 JqTreeWidget.prototype.refreshHitAreas = function() {
1051 return this.dnd_handler.refreshHitAreas();
1054 JqTreeWidget.prototype.addNodeAfter = function(new_node_info, existing_node) {
1056 new_node = existing_node.addAfter(new_node_info);
1057 this._refreshElements(existing_node.parent);
1061 JqTreeWidget.prototype.addNodeBefore = function(new_node_info, existing_node) {
1063 new_node = existing_node.addBefore(new_node_info);
1064 this._refreshElements(existing_node.parent);
1068 JqTreeWidget.prototype.addParentNode = function(new_node_info, existing_node) {
1070 new_node = existing_node.addParent(new_node_info);
1071 this._refreshElements(new_node.parent);
1075 JqTreeWidget.prototype.removeNode = function(node) {
1077 parent = node.parent;
1079 this.select_node_handler.removeFromSelection(node, true);
1081 return this._refreshElements(parent.parent);
1085 JqTreeWidget.prototype.appendNode = function(new_node_info, parent_node) {
1086 var is_already_root_node, node;
1088 parent_node = this.tree;
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);
1095 this._refreshElements(parent_node.parent);
1100 JqTreeWidget.prototype.prependNode = function(new_node_info, parent_node) {
1103 parent_node = this.tree;
1105 node = parent_node.prepend(new_node_info);
1106 this._refreshElements(parent_node);
1110 JqTreeWidget.prototype.updateNode = function(node, data) {
1112 id_is_changed = data.id && data.id !== node.id;
1113 if (id_is_changed) {
1114 this.tree.removeNodeFromIndex(node);
1117 if (id_is_changed) {
1118 this.tree.addNodeToIndex(node);
1120 this._refreshElements(node.parent);
1121 return this._selectCurrentNode();
1124 JqTreeWidget.prototype.moveNode = function(node, target_node, position) {
1126 position_index = Position.nameToIndex(position);
1127 this.tree.moveNode(node, target_node, position_index);
1128 return this._refreshElements();
1131 JqTreeWidget.prototype.getStateFromStorage = function() {
1132 return this.save_state_handler.getStateFromStorage();
1135 JqTreeWidget.prototype.addToSelection = function(node) {
1136 this.select_node_handler.addToSelection(node);
1137 return this._getNodeElementForNode(node).select();
1140 JqTreeWidget.prototype.getSelectedNodes = function() {
1141 return this.select_node_handler.getSelectedNodes();
1144 JqTreeWidget.prototype.isNodeSelected = function(node) {
1145 return this.select_node_handler.isNodeSelected(node);
1148 JqTreeWidget.prototype.removeFromSelection = function(node) {
1149 this.select_node_handler.removeFromSelection(node);
1150 return this._getNodeElementForNode(node).deselect();
1153 JqTreeWidget.prototype.scrollToNode = function(node) {
1155 $element = $(node.element);
1156 top = $element.offset().top - this.$el.offset().top;
1157 return this.scroll_handler.scrollTo(top);
1160 JqTreeWidget.prototype.getState = function() {
1161 return this.save_state_handler.getState();
1164 JqTreeWidget.prototype.setState = function(state) {
1165 this.save_state_handler.setState(state);
1166 return this._refreshElements();
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);
1177 this.options.saveState = false;
1179 if (typeof SelectNodeHandler !== "undefined" && SelectNodeHandler !== null) {
1180 this.select_node_handler = new SelectNodeHandler(this);
1182 if (typeof DragAndDropHandler !== "undefined" && DragAndDropHandler !== null) {
1183 this.dnd_handler = new DragAndDropHandler(this);
1185 this.options.dragAndDrop = false;
1187 if (typeof ScrollHandler !== "undefined" && ScrollHandler !== null) {
1188 this.scroll_handler = new ScrollHandler(this);
1190 if ((typeof KeyHandler !== "undefined" && KeyHandler !== null) && (typeof SelectNodeHandler !== "undefined" && SelectNodeHandler !== null)) {
1191 this.key_handler = new KeyHandler(this);
1194 this.element.click($.proxy(this._click, this));
1195 if (this.options.useContextMenu) {
1196 return this.element.bind('contextmenu', $.proxy(this._contextmenu, this));
1200 JqTreeWidget.prototype._deinit = function() {
1201 this.element.empty();
1202 this.element.unbind();
1203 this.key_handler.deinit();
1205 return JqTreeWidget.__super__._deinit.call(this);
1208 JqTreeWidget.prototype._initData = function() {
1209 if (this.options.data) {
1210 return this._loadData(this.options.data);
1212 return this._loadDataFromUrl(this._getDataUrlInfo());
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') {
1225 if (node && node.id) {
1229 url_info['data'] = data;
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();
1242 this.tree.loadFromData(data);
1244 this._refreshElements();
1245 if (!this.is_initialized) {
1246 this.is_initialized = true;
1247 return this._triggerEvent('tree.init');
1251 JqTreeWidget.prototype._openNodes = function() {
1253 if (this.options.saveState) {
1254 if (this.save_state_handler.restoreState()) {
1258 if (this.options.autoOpen === false) {
1260 } else if (this.options.autoOpen === true) {
1263 max_level = parseInt(this.options.autoOpen);
1265 return this.tree.iterate(function(node, level) {
1266 if (node.hasChildren()) {
1267 node.is_open = true;
1269 return level !== max_level;
1273 JqTreeWidget.prototype._refreshElements = function(from_node) {
1274 var $element, createFolderLi, createLi, createNodeLi, createUl, doCreateDomElements, escapeIfNecessary, is_root_node, node_element,
1276 if (from_node == null) {
1279 escapeIfNecessary = function(value) {
1280 if (_this.options.autoEscape) {
1281 return html_escape(value);
1286 createUl = function(is_root_node) {
1289 class_string = 'jqtree-tree';
1293 return $("<ul class=\"jqtree_common " + class_string + "\"></ul>");
1295 createLi = function(node) {
1297 if (node.isFolder()) {
1298 $li = createFolderLi(node);
1300 $li = createNodeLi(node);
1302 if (_this.options.onCreateLi) {
1303 _this.options.onCreateLi(node, $li);
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');
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>");
1317 createFolderLi = function(node) {
1318 var button_char, button_classes, escaped_name, folder_classes, getButtonClasses, getFolderClasses;
1319 getButtonClasses = function() {
1321 classes = ['jqtree-toggler'];
1322 if (!node.is_open) {
1323 classes.push('jqtree-closed');
1325 return classes.join(' ');
1327 getFolderClasses = function() {
1329 classes = ['jqtree-folder'];
1330 if (!node.is_open) {
1331 classes.push('jqtree-closed');
1333 if (_this.select_node_handler && _this.select_node_handler.isNodeSelected(node)) {
1334 classes.push('jqtree-selected');
1336 return classes.join(' ');
1338 button_classes = getButtonClasses();
1339 folder_classes = getFolderClasses();
1340 escaped_name = escapeIfNecessary(node.name);
1342 button_char = _this.options.openedIcon;
1344 button_char = _this.options.closedIcon;
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>");
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);
1356 child.element = $li[0];
1357 $li.data('node', child);
1358 if (child.hasChildren()) {
1359 doCreateDomElements($li, child.children, false, child.is_open);
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;
1370 from_node = this.tree;
1371 $element = this.element;
1373 is_root_node = true;
1375 doCreateDomElements($element, from_node.children, is_root_node, is_root_node);
1376 return this._triggerEvent('tree.refresh');
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);
1386 this.toggle(node, this.options.slide);
1388 return e.stopPropagation();
1391 $el = $target.closest('.jqtree-element');
1393 node = this._getNode($el);
1395 event = this._triggerEvent('tree.click', {
1398 if (!event.isDefaultPrevented()) {
1399 return this._selectNode(node, true);
1406 JqTreeWidget.prototype._getNode = function($element) {
1408 $li = $element.closest('li');
1409 if ($li.length === 0) {
1412 return $li.data('node');
1416 JqTreeWidget.prototype._getNodeElementForNode = function(node) {
1417 if (node.isFolder()) {
1418 return new FolderElement(node, this);
1420 return new NodeElement(node, this);
1424 JqTreeWidget.prototype._getNodeElement = function($element) {
1426 node = this._getNode($element);
1428 return this._getNodeElementForNode(node);
1434 JqTreeWidget.prototype._contextmenu = function(e) {
1436 $div = $(e.target).closest('ul.jqtree-tree .jqtree-element');
1438 node = this._getNode($div);
1441 e.stopPropagation();
1442 this._triggerEvent('tree.contextmenu', {
1451 JqTreeWidget.prototype._saveState = function() {
1452 if (this.options.saveState) {
1453 return this.save_state_handler.saveState();
1457 JqTreeWidget.prototype._mouseCapture = function(position_info) {
1458 if (this.options.dragAndDrop) {
1459 return this.dnd_handler.mouseCapture(position_info);
1465 JqTreeWidget.prototype._mouseStart = function(position_info) {
1466 if (this.options.dragAndDrop) {
1467 return this.dnd_handler.mouseStart(position_info);
1473 JqTreeWidget.prototype._mouseDrag = function(position_info) {
1475 if (this.options.dragAndDrop) {
1476 result = this.dnd_handler.mouseDrag(position_info);
1477 if (this.scroll_handler) {
1478 this.scroll_handler.checkScrolling();
1486 JqTreeWidget.prototype._mouseStop = function(position_info) {
1487 if (this.options.dragAndDrop) {
1488 return this.dnd_handler.mouseStop(position_info);
1494 JqTreeWidget.prototype._triggerEvent = function(event_name, values) {
1496 event = $.Event(event_name);
1497 $.extend(event, values);
1498 this.element.trigger(event);
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;
1508 JqTreeWidget.prototype._selectCurrentNode = function() {
1509 var node, node_element;
1510 node = this.getSelectedNode();
1512 node_element = this._getNodeElementForNode(node);
1514 return node_element.select();
1519 JqTreeWidget.prototype._deselectCurrentNode = function() {
1521 node = this.getSelectedNode();
1523 return this.removeFromSelection(node);
1527 return JqTreeWidget;
1531 SimpleWidget.register(JqTreeWidget, 'tree');
1533 NodeElement = (function() {
1534 function NodeElement(node, tree_widget) {
1535 this.init(node, tree_widget);
1538 NodeElement.prototype.init = function(node, tree_widget) {
1540 this.tree_widget = tree_widget;
1541 return this.$element = $(node.element);
1544 NodeElement.prototype.getUl = function() {
1545 return this.$element.children('ul:first');
1548 NodeElement.prototype.getSpan = function() {
1549 return this.$element.children('.jqtree-element').find('span.jqtree-title');
1552 NodeElement.prototype.getLi = function() {
1553 return this.$element;
1556 NodeElement.prototype.addDropHint = function(position) {
1557 if (position === Position.INSIDE) {
1558 return new BorderDropHint(this.$element);
1560 return new GhostDropHint(this.node, this.$element, position);
1564 NodeElement.prototype.select = function() {
1565 return this.getLi().addClass('jqtree-selected');
1568 NodeElement.prototype.deselect = function() {
1569 return this.getLi().removeClass('jqtree-selected');
1576 FolderElement = (function(_super) {
1577 __extends(FolderElement, _super);
1579 function FolderElement() {
1580 _ref2 = FolderElement.__super__.constructor.apply(this, arguments);
1584 FolderElement.prototype.open = function(on_finished, slide) {
1585 var $button, doOpen,
1587 if (slide == null) {
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');
1600 return _this.tree_widget._triggerEvent('tree.open', {
1605 return this.getUl().slideDown('fast', doOpen);
1607 this.getUl().show();
1613 FolderElement.prototype.close = function(slide) {
1614 var $button, doClose,
1616 if (slide == null) {
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', {
1631 return this.getUl().slideUp('fast', doClose);
1633 this.getUl().hide();
1639 FolderElement.prototype.getButton = function() {
1640 return this.$element.children('.jqtree-element').find('a.jqtree-toggler');
1643 FolderElement.prototype.addDropHint = function(position) {
1644 if (!this.node.is_open && position === Position.INSIDE) {
1645 return new BorderDropHint(this.$element);
1647 return new GhostDropHint(this.node, this.$element, position);
1651 return FolderElement;
1655 html_escape = function(string) {
1656 return ('' + string).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/');
1659 _indexOf = function(array, item) {
1660 var i, value, _i, _len;
1661 for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) {
1663 if (value === item) {
1670 indexOf = function(array, item) {
1671 if (array.indexOf) {
1672 return array.indexOf(item);
1674 return _indexOf(array, item);
1678 this.Tree.indexOf = indexOf;
1680 this.Tree._indexOf = _indexOf;
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;
1693 json_quote = function(string) {
1694 json_escapable.lastIndex = 0;
1695 if (json_escapable.test(string)) {
1696 return '"' + string.replace(json_escapable, function(a) {
1699 return (typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4));
1702 return '"' + string + '"';
1705 json_str = function(key, holder) {
1706 var i, k, partial, v, value, _i, _len;
1707 value = holder[key];
1708 switch (typeof value) {
1710 return json_quote(value);
1712 if (isFinite(value)) {
1713 return String(value);
1719 return String(value);
1725 if (Object.prototype.toString.apply(value) === '[object Array]') {
1726 for (i = _i = 0, _len = value.length; _i < _len; i = ++_i) {
1728 partial[i] = json_str(i, value) || 'null';
1730 return (partial.length === 0 ? '[]' : '[' + partial.join(',') + ']');
1733 if (Object.prototype.hasOwnProperty.call(value, k)) {
1734 v = json_str(k, value);
1736 partial.push(json_quote(k) + ':' + v);
1740 return (partial.length === 0 ? '{}' : '{' + partial.join(',') + '}');
1743 if (this.JSON == null) {
1746 this.JSON.stringify = function(value) {
1747 return json_str('', {
1753 SaveStateHandler = (function() {
1754 function SaveStateHandler(tree_widget) {
1755 this.tree_widget = tree_widget;
1758 SaveStateHandler.prototype.saveState = function() {
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, {
1773 SaveStateHandler.prototype.restoreState = function() {
1775 state = this.getStateFromStorage();
1777 this.setState($.parseJSON(state));
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());
1797 SaveStateHandler.prototype.getState = function() {
1798 var open_nodes, selected_node, selected_node_id,
1801 this.tree_widget.tree.iterate(function(node) {
1802 if (node.is_open && node.id && node.hasChildren()) {
1803 open_nodes.push(node.id);
1807 selected_node = this.tree_widget.getSelectedNode();
1808 if (selected_node) {
1809 selected_node_id = selected_node.id;
1811 selected_node_id = '';
1814 open_nodes: open_nodes,
1815 selected_node: selected_node_id
1819 SaveStateHandler.prototype.setState = function(state) {
1820 var open_nodes, selected_node, selected_node_id,
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);
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);
1839 SaveStateHandler.prototype.getCookieName = function() {
1840 if (typeof this.tree_widget.options.saveState === 'string') {
1841 return this.tree_widget.options.saveState;
1847 return SaveStateHandler;
1851 SelectNodeHandler = (function() {
1852 function SelectNodeHandler(tree_widget) {
1853 this.tree_widget = tree_widget;
1857 SelectNodeHandler.prototype.getSelectedNode = function() {
1859 selected_nodes = this.getSelectedNodes();
1860 if (selected_nodes.length) {
1861 return selected_nodes[0];
1867 SelectNodeHandler.prototype.getSelectedNodes = function() {
1868 var id, node, selected_nodes;
1869 if (this.selected_single_node) {
1870 return [this.selected_single_node];
1872 selected_nodes = [];
1873 for (id in this.selected_nodes) {
1874 node = this.tree_widget.getNodeById(id);
1876 selected_nodes.push(node);
1879 return selected_nodes;
1883 SelectNodeHandler.prototype.isNodeSelected = function(node) {
1885 return this.selected_nodes[node.id];
1886 } else if (this.selected_single_node) {
1887 return this.selected_single_node.element === node.element;
1893 SelectNodeHandler.prototype.clear = function() {
1894 this.selected_nodes = {};
1895 return this.selected_single_node = null;
1898 SelectNodeHandler.prototype.removeFromSelection = function(node, include_children) {
1900 if (include_children == null) {
1901 include_children = false;
1904 if (node.element === this.selected_single_node.element) {
1905 return this.selected_single_node = null;
1908 delete this.selected_nodes[node.id];
1909 if (include_children) {
1910 return node.iterate(function(n) {
1911 delete _this.selected_nodes[node.id];
1918 SelectNodeHandler.prototype.addToSelection = function(node) {
1920 return this.selected_nodes[node.id] = true;
1922 return this.selected_single_node = node;
1926 return SelectNodeHandler;
1930 DragAndDropHandler = (function() {
1931 function DragAndDropHandler(tree_widget) {
1932 this.tree_widget = tree_widget;
1933 this.hovered_area = null;
1935 this.hit_areas = [];
1936 this.is_dragging = false;
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)) {
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;
1951 this.current_item = node_element;
1952 return this.current_item !== null;
1955 DragAndDropHandler.prototype.mouseStart = function(position_info) {
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');
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);
1971 if (this.hovered_area !== area) {
1972 this.hovered_area = area;
1973 if (this.mustOpenFolderTimer(area)) {
1974 this.startOpenFolderTimer(area.node);
1977 this.updateDropHint();
1982 this.removeDropHint();
1983 this.stopOpenFolderTimer();
1988 DragAndDropHandler.prototype.canMoveToArea = function(area) {
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);
2000 DragAndDropHandler.prototype.mouseStop = function(position_info) {
2001 this.moveItem(position_info);
2004 this.removeDropHint();
2005 this.removeHitAreas();
2006 if (this.current_item) {
2007 this.current_item.$element.removeClass('jqtree-moving');
2009 this.is_dragging = false;
2013 DragAndDropHandler.prototype.refreshHitAreas = function() {
2014 this.removeHitAreas();
2015 return this.generateHitAreas();
2018 DragAndDropHandler.prototype.removeHitAreas = function() {
2019 return this.hit_areas = [];
2022 DragAndDropHandler.prototype.clear = function() {
2023 this.drag_element.remove();
2024 return this.drag_element = null;
2027 DragAndDropHandler.prototype.removeDropHint = function() {
2028 if (this.previous_ghost) {
2029 return this.previous_ghost.remove();
2033 DragAndDropHandler.prototype.removeHover = function() {
2034 return this.hovered_area = null;
2037 DragAndDropHandler.prototype.generateHitAreas = function() {
2038 var addPosition, getTop, groupPositions, handleAfterOpenFolder, handleClosedFolder, handleFirstNode, handleNode, handleOpenFolder, hit_areas, last_top, positions,
2042 getTop = function($element) {
2043 return $element.offset().top;
2045 addPosition = function(node, position, top) {
2051 return last_top = top;
2053 groupPositions = function(handle_group) {
2054 var group, position, previous_top, _i, _len;
2057 for (_i = 0, _len = positions.length; _i < _len; _i++) {
2058 position = positions[_i];
2059 if (position.top !== previous_top) {
2061 handle_group(group, previous_top, position.top);
2063 previous_top = position.top;
2066 group.push(position);
2068 return handle_group(group, previous_top, _this.tree_widget.element.offset().top + _this.tree_widget.element.height());
2070 handleNode = function(node, next_node, $element) {
2072 top = getTop($element);
2073 if (node === _this.current_item.node) {
2074 addPosition(node, Position.NONE, top);
2076 addPosition(node, Position.INSIDE, top);
2078 if (next_node === _this.current_item.node || node === _this.current_item.node) {
2079 return addPosition(node, Position.NONE, top);
2081 return addPosition(node, Position.AFTER, top);
2084 handleOpenFolder = function(node, $element) {
2085 if (node === _this.current_item.node) {
2088 if (node.children[0] !== _this.current_item.node) {
2089 addPosition(node, Position.INSIDE, getTop($element));
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);
2097 return addPosition(node, Position.AFTER, last_top);
2100 handleClosedFolder = function(node, next_node, $element) {
2102 top = getTop($element);
2103 if (node === _this.current_item.node) {
2104 return addPosition(node, Position.NONE, top);
2106 addPosition(node, Position.INSIDE, top);
2107 if (next_node !== _this.current_item.node) {
2108 return addPosition(node, Position.AFTER, top);
2112 handleFirstNode = function(node, $element) {
2113 if (node !== _this.current_item.node) {
2114 return addPosition(node, Position.BEFORE, getTop($(node.element)));
2117 this.iterateVisibleNodes(handleNode, handleOpenFolder, handleClosedFolder, handleAfterOpenFolder, handleFirstNode);
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;
2123 for (_i = 0, _len = positions_in_group.length; _i < _len; _i++) {
2124 position = positions_in_group[_i];
2127 bottom: area_top + area_height,
2128 node: position.node,
2129 position: position.position
2131 area_top += area_height;
2135 return this.hit_areas = hit_areas;
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,
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();
2146 $element = $(node.element);
2147 if (!$element.is(':visible')) {
2150 if (is_first_node) {
2151 handle_first_node(node, $element);
2152 is_first_node = false;
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;
2161 handle_closed_folder(node, next_node, $element);
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) {
2169 if (i === (children_length - 1)) {
2170 iterate(node.children[i], null);
2172 iterate(node.children[i], node.children[i + 1]);
2176 return handle_after_open_folder(node, next_node, $element);
2180 return iterate(this.tree_widget.tree);
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())) {
2190 high = this.hit_areas.length;
2191 while (low < high) {
2192 mid = (low + high) >> 1;
2193 area = this.hit_areas[mid];
2196 } else if (y > area.bottom) {
2205 DragAndDropHandler.prototype.mustOpenFolderTimer = function(area) {
2208 return node.isFolder() && !node.is_open && area.position === Position.INSIDE;
2211 DragAndDropHandler.prototype.updateDropHint = function() {
2213 if (!this.hovered_area) {
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);
2221 DragAndDropHandler.prototype.startOpenFolderTimer = function(folder) {
2224 openFolder = function() {
2225 return _this.tree_widget._openNode(folder, _this.tree_widget.options.slide, function() {
2226 _this.refreshHitAreas();
2227 return _this.updateDropHint();
2230 return this.open_folder_timer = setTimeout(openFolder, 500);
2233 DragAndDropHandler.prototype.stopOpenFolderTimer = function() {
2234 if (this.open_folder_timer) {
2235 clearTimeout(this.open_folder_timer);
2236 return this.open_folder_timer = null;
2240 DragAndDropHandler.prototype.moveItem = function(position_info) {
2241 var doMove, event, moved_node, position, previous_parent, target_node,
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;
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();
2256 event = this.tree_widget._triggerEvent('tree.move', {
2258 moved_node: moved_node,
2259 target_node: target_node,
2260 position: Position.getName(position),
2261 previous_parent: previous_parent,
2263 original_event: position_info.original_event
2266 if (!event.isDefaultPrevented()) {
2272 return DragAndDropHandler;
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);
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
2292 DragElement.prototype.remove = function() {
2293 return this.$element.remove();
2300 GhostDropHint = (function() {
2301 function GhostDropHint(node, $element, position) {
2302 this.$element = $element;
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) {
2307 } else if (position === Position.BEFORE) {
2309 } else if (position === Position.INSIDE) {
2310 if (node.isFolder() && node.is_open) {
2311 this.moveInsideOpenFolder();
2318 GhostDropHint.prototype.remove = function() {
2319 return this.$ghost.remove();
2322 GhostDropHint.prototype.moveAfter = function() {
2323 return this.$element.after(this.$ghost);
2326 GhostDropHint.prototype.moveBefore = function() {
2327 return this.$element.before(this.$ghost);
2330 GhostDropHint.prototype.moveInsideOpenFolder = function() {
2331 return $(this.node.children[0].element).before(this.$ghost);
2334 GhostDropHint.prototype.moveInside = function() {
2335 this.$element.after(this.$ghost);
2336 return this.$ghost.addClass('jqtree-inside');
2339 return GhostDropHint;
2343 BorderDropHint = (function() {
2344 function BorderDropHint($element) {
2346 $div = $element.children('.jqtree-element');
2347 width = $element.width() - 4;
2348 this.$hint = $('<span class="jqtree-border"></span>');
2349 $div.append(this.$hint);
2352 height: $div.height() - 4
2356 BorderDropHint.prototype.remove = function() {
2357 return this.$hint.remove();
2360 return BorderDropHint;
2364 ScrollHandler = (function() {
2365 function ScrollHandler(tree_widget) {
2366 this.tree_widget = tree_widget;
2367 this.previous_top = -1;
2368 this._initScrollParent();
2371 ScrollHandler.prototype._initScrollParent = function() {
2372 var $scroll_parent, getParentWithOverflow, setDocumentAsScrollParent,
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++) {
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') {
2390 setDocumentAsScrollParent = function() {
2391 _this.scroll_parent_top = 0;
2392 return _this.$scroll_parent = null;
2394 if (this.tree_widget.$el.css('position') === 'fixed') {
2395 setDocumentAsScrollParent();
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;
2402 return setDocumentAsScrollParent();
2406 ScrollHandler.prototype.checkScrolling = function() {
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);
2414 return this._handleScrollingWithDocument(hovered_area);
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;
2433 ScrollHandler.prototype._handleScrollingWithDocument = function(area) {
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);
2443 ScrollHandler.prototype.scrollTo = function(top) {
2445 if (this.$scroll_parent) {
2446 return this.$scroll_parent[0].scrollTop = top;
2448 tree_top = this.tree_widget.$el.offset().top;
2449 return $(document).scrollTop(top + tree_top);
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) {
2458 view_bottom = this.$scroll_parent.height();
2459 element_top = $element.offset().top - this.scroll_parent_top;
2460 element_bottom = element_top + $element.height();
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();
2467 return (element_bottom <= view_bottom) && (element_top >= view_top);
2470 return ScrollHandler;
2474 KeyHandler = (function() {
2475 var DOWN, LEFT, RIGHT, UP;
2485 function KeyHandler(tree_widget) {
2486 this.tree_widget = tree_widget;
2487 $(document).bind('keydown.jqtree', $.proxy(this.handleKeyDown, this));
2490 KeyHandler.prototype.deinit = function() {
2491 return $(document).unbind('keydown.jqtree');
2494 KeyHandler.prototype.handleKeyDown = function(e) {
2495 var current_node, key, moveDown, moveLeft, moveRight, moveUp, selectNode,
2497 current_node = this.tree_widget.getSelectedNode();
2498 selectNode = function(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);
2509 moveDown = function() {
2510 return selectNode(_this.getNextNode(current_node));
2512 moveUp = function() {
2513 return selectNode(_this.getPreviousNode(current_node));
2515 moveRight = function() {
2516 if (current_node.hasChildren() && !current_node.is_open) {
2517 _this.tree_widget.openNode(current_node);
2523 moveLeft = function() {
2524 if (current_node.hasChildren() && current_node.is_open) {
2525 _this.tree_widget.closeNode(current_node);
2531 if (!current_node) {
2548 KeyHandler.prototype.getNextNode = function(node, include_children) {
2550 if (include_children == null) {
2551 include_children = true;
2553 if (include_children && node.hasChildren() && node.is_open) {
2554 return node.children[0];
2559 next_sibling = node.getNextSibling();
2561 return next_sibling;
2563 return this.getNextNode(node.parent, false);
2569 KeyHandler.prototype.getPreviousNode = function(node) {
2570 var previous_sibling;
2574 previous_sibling = node.getPreviousSibling();
2575 if (previous_sibling) {
2576 if (!previous_sibling.hasChildren() || !previous_sibling.is_open) {
2577 return previous_sibling;
2579 return this.getLastChild(previous_sibling);
2582 if (node.parent.parent) {
2591 KeyHandler.prototype.getLastChild = function(node) {
2593 if (!node.hasChildren()) {
2596 last_child = node.children[node.children.length - 1];
2597 if (!last_child.hasChildren() || !last_child.is_open) {
2600 return this.getLastChild(last_child);