Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / tools / deep_memory_profiler / visualizer / static / third_party / jqTree / tree.jquery.js
blob2ebff8b2d9d195b3188cda6e62ed2e7f2f47c4b5
1 // Generated by CoffeeScript 1.6.3
2 /*
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.
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; };
25 $ = this.jQuery;
27 SimpleWidget = (function() {
28 SimpleWidget.prototype.defaults = {};
30 function SimpleWidget(el, options) {
31 this.$el = $(el);
32 this.options = $.extend({}, this.defaults, options);
35 SimpleWidget.prototype.destroy = function() {
36 return this._deinit();
39 SimpleWidget.prototype._init = function() {
40 return null;
43 SimpleWidget.prototype._deinit = function() {
44 return null;
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++) {
56 el = $el[_i];
57 widget = new widget_class(el, options);
58 if (!$.data(el, data_key)) {
59 $.data(el, data_key, widget);
61 widget._init();
63 return $el;
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();
75 _results.push($.removeData(el, data_key));
77 return _results;
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);
92 return result;
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);
112 return SimpleWidget;
114 })();
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);
128 return _ref;
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() {
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');
152 MouseWidget.prototype._mouseDown = function(e) {
153 var result;
154 if (e.which !== 1) {
155 return;
157 result = this._handleMouseDown(e, this._getPositionInfo(e));
158 if (result) {
159 e.preventDefault();
161 return result;
164 MouseWidget.prototype._handleMouseDown = function(e, position_info) {
165 if (MouseWidget.is_mouse_handled) {
166 return;
168 if (this.is_mouse_started) {
169 this._handleMouseUp(position_info);
171 this.mouse_down_info = position_info;
172 if (!this._mouseCapture(position_info)) {
173 return;
175 this._handleStartMouse();
176 this.is_mouse_handled = true;
177 return true;
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();
192 MouseWidget.prototype._startMouseDelayTimer = function() {
193 var _this = this;
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) {
213 return true;
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);
221 return !this.is_mouse_started;
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
233 MouseWidget.prototype._mouseUp = function(e) {
234 return this._handleMouseUp(this._getPositionInfo(e));
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);
250 MouseWidget.prototype._mouseCapture = function(position_info) {
251 return true;
254 MouseWidget.prototype._mouseStart = function(position_info) {
255 return null;
258 MouseWidget.prototype._mouseDrag = function(position_info) {
259 return null;
262 MouseWidget.prototype._mouseStop = function(position_info) {
263 return null;
266 MouseWidget.prototype.setMouseDelay = function(mouse_delay) {
267 return this.mouse_delay = mouse_delay;
270 MouseWidget.prototype._touchStart = function(e) {
271 var touch;
272 if (e.originalEvent.touches.length > 1) {
273 return;
275 touch = e.originalEvent.changedTouches[0];
276 return this._handleMouseDown(e, this._getPositionInfo(touch));
279 MouseWidget.prototype._touchMove = function(e) {
280 var touch;
281 if (e.originalEvent.touches.length > 1) {
282 return;
284 touch = e.originalEvent.changedTouches[0];
285 return this._handleMouseMove(e, this._getPositionInfo(touch));
288 MouseWidget.prototype._touchEnd = function(e) {
289 var touch;
290 if (e.originalEvent.touches.length > 1) {
291 return;
293 touch = e.originalEvent.changedTouches[0];
294 return this._handleMouseUp(this._getPositionInfo(touch));
297 return MouseWidget;
299 })(SimpleWidget);
301 this.Tree = {};
303 $ = this.jQuery;
305 Position = {
306 getName: function(position) {
307 return Position.strings[position - 1];
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;
316 return 0;
320 Position.BEFORE = 1;
322 Position.AFTER = 2;
324 Position.INSIDE = 3;
326 Position.NONE = 4;
328 Position.strings = ['before', 'after', 'inside', 'none'];
330 this.Tree.Position = Position;
332 Node = (function() {
333 function Node(o, is_root, node_class) {
334 if (is_root == null) {
335 is_root = false;
337 if (node_class == null) {
338 node_class = Node;
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;
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);
364 return _results;
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);
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);
385 return null;
387 addNode(data);
388 return null;
392 Create tree from data.
394 Structure of data is:
397 label: 'node1',
398 children: [
399 { label: 'child1' },
400 { label: 'child2' }
404 label: 'node2'
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);
421 return null;
425 Add child.
427 tree.addChild(
428 new Node('child1')
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(
442 new Node('abc'),
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);
477 Get child index.
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.
511 tree.iterate(
512 function(node, level) {
513 console.log(node.name);
515 // stop iteration after level 2
516 return (level <= 2);
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);
536 return null;
539 _iterate(this, 0);
540 return null;
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)) {
555 return;
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,
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;
587 if (node.hasChildren()) {
588 tmp_node.children = getDataFromNodes(node.children);
590 data.push(tmp_node);
592 return data;
594 return getDataFromNodes(this.children);
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;
608 return result;
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;
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;
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);
648 original_parent.children = [];
649 original_parent.addChild(new_parent);
650 return new_parent;
654 Node.prototype.remove = function() {
655 if (this.parent) {
656 this.parent.removeChild(this);
657 return this.parent = null;
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;
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;
675 Node.prototype.isParentOf = function(node) {
676 var parent;
677 parent = node.parent;
678 while (parent) {
679 if (parent === this) {
680 return true;
682 parent = parent.parent;
684 return false;
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;
695 return level;
698 Node.prototype.getNodeById = function(node_id) {
699 return this.id_mapping[node_id];
702 Node.prototype.addNodeToIndex = function(node) {
703 if (node.id) {
704 return this.id_mapping[node.id] = node;
708 Node.prototype.removeNodeFromIndex = function(node) {
709 if (node.id) {
710 return delete this.id_mapping[node.id];
714 Node.prototype.removeChildren = function() {
715 var _this = this;
716 this.iterate(function(child) {
717 _this.tree.removeNodeFromIndex(child);
718 return true;
720 return this.children = [];
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;
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;
751 return Node;
753 })();
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);
779 return _ref1;
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
804 JqTreeWidget.prototype.toggle = function(node, slide) {
805 if (slide == null) {
806 slide = true;
808 if (node.is_open) {
809 return this.closeNode(node, slide);
810 } else {
811 return this.openNode(node, slide);
815 JqTreeWidget.prototype.getTree = function() {
816 return this.tree;
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,
825 _this = this;
826 if (must_toggle == null) {
827 must_toggle = false;
829 if (!this.select_node_handler) {
830 return;
832 canSelect = function() {
833 if (_this.options.onCanSelectNode) {
834 return _this.options.selectable && _this.options.onCanSelectNode(node);
835 } else {
836 return _this.options.selectable;
839 openParents = function() {
840 var parent;
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();
851 if (!node) {
852 this._deselectCurrentNode();
853 saveState();
854 return;
856 if (!canSelect()) {
857 return;
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
867 } else {
868 this._deselectCurrentNode();
869 this.addToSelection(node);
870 this._triggerEvent('tree.select', {
871 node: node
873 openParents();
875 return saveState();
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;
893 parent_node = url;
894 url = null;
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,
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();
911 return $el.addClass('jqtree-loading');
913 removeLoadingClass = function() {
914 if ($el) {
915 return $el.removeClass('jqtree-loading');
918 parseUrlInfo = function() {
919 if ($.type(url_info) === 'string') {
920 url_info = {
921 url: url_info
924 if (!url_info.method) {
925 return url_info.method = 'get';
928 addLoadingClass();
929 if (!url_info) {
930 url_info = this._getDataUrlInfo(parent_node);
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);
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', {
964 tree_data: data
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);
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) {
992 if (slide == null) {
993 slide = true;
995 return this._openNode(node, slide);
998 JqTreeWidget.prototype._openNode = function(node, slide, on_finished) {
999 var doOpenNode, parent,
1000 _this = this;
1001 if (slide == null) {
1002 slide = true;
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);
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);
1018 parent = parent.parent;
1020 doOpenNode(node, slide, on_finished);
1021 return this._saveState();
1026 JqTreeWidget.prototype._loadFolderOnDemand = function(node, slide, on_finished) {
1027 var _this = this;
1028 if (slide == null) {
1029 slide = true;
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) {
1038 slide = true;
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) {
1055 var new_node;
1056 new_node = existing_node.addAfter(new_node_info);
1057 this._refreshElements(existing_node.parent);
1058 return new_node;
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;
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;
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);
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;
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);
1097 return node;
1100 JqTreeWidget.prototype.prependNode = function(new_node_info, parent_node) {
1101 var node;
1102 if (!parent_node) {
1103 parent_node = this.tree;
1105 node = parent_node.prepend(new_node_info);
1106 this._refreshElements(parent_node);
1107 return node;
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);
1116 node.setData(data);
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) {
1125 var position_index;
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) {
1154 var $element, top;
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);
1176 } else {
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);
1184 } else {
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);
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));
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);
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());
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
1225 if (node && node.id) {
1226 data = {
1227 node: node.id
1229 url_info['data'] = data;
1231 return url_info;
1232 } else {
1233 return data_url;
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);
1243 this._openNodes();
1244 this._refreshElements();
1245 if (!this.is_initialized) {
1246 this.is_initialized = true;
1247 return this._triggerEvent('tree.init');
1251 JqTreeWidget.prototype._openNodes = function() {
1252 var max_level;
1253 if (this.options.saveState) {
1254 if (this.save_state_handler.restoreState()) {
1255 return;
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);
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,
1275 _this = this;
1276 if (from_node == null) {
1277 from_node = null;
1279 escapeIfNecessary = function(value) {
1280 if (_this.options.autoEscape) {
1281 return html_escape(value);
1282 } else {
1283 return value;
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 = '';
1293 return $("<ul class=\"jqtree_common " + class_string + "\"></ul>");
1295 createLi = function(node) {
1296 var $li;
1297 if (node.isFolder()) {
1298 $li = createFolderLi(node);
1299 } else {
1300 $li = createNodeLi(node);
1302 if (_this.options.onCreateLi) {
1303 _this.options.onCreateLi(node, $li);
1305 return $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() {
1320 var classes;
1321 classes = ['jqtree-toggler'];
1322 if (!node.is_open) {
1323 classes.push('jqtree-closed');
1325 return classes.join(' ');
1327 getFolderClasses = function() {
1328 var classes;
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);
1341 if (node.is_open) {
1342 button_char = _this.options.openedIcon;
1343 } else {
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);
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);
1362 return null;
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;
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);
1385 if (node) {
1386 this.toggle(node, this.options.slide);
1387 e.preventDefault();
1388 return e.stopPropagation();
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
1398 if (!event.isDefaultPrevented()) {
1399 return this._selectNode(node, true);
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');
1416 JqTreeWidget.prototype._getNodeElementForNode = function(node) {
1417 if (node.isFolder()) {
1418 return new FolderElement(node, this);
1419 } else {
1420 return new NodeElement(node, this);
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;
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
1446 return false;
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);
1460 } else {
1461 return false;
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;
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();
1480 return result;
1481 } else {
1482 return false;
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;
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;
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();
1511 if (node) {
1512 node_element = this._getNodeElementForNode(node);
1513 if (node_element) {
1514 return node_element.select();
1519 JqTreeWidget.prototype._deselectCurrentNode = function() {
1520 var node;
1521 node = this.getSelectedNode();
1522 if (node) {
1523 return this.removeFromSelection(node);
1527 return JqTreeWidget;
1529 })(MouseWidget);
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) {
1539 this.node = node;
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);
1559 } else {
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');
1572 return NodeElement;
1574 })();
1576 FolderElement = (function(_super) {
1577 __extends(FolderElement, _super);
1579 function FolderElement() {
1580 _ref2 = FolderElement.__super__.constructor.apply(this, arguments);
1581 return _ref2;
1584 FolderElement.prototype.open = function(on_finished, slide) {
1585 var $button, doOpen,
1586 _this = this;
1587 if (slide == null) {
1588 slide = true;
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();
1600 return _this.tree_widget._triggerEvent('tree.open', {
1601 node: _this.node
1604 if (slide) {
1605 return this.getUl().slideDown('fast', doOpen);
1606 } else {
1607 this.getUl().show();
1608 return doOpen();
1613 FolderElement.prototype.close = function(slide) {
1614 var $button, doClose,
1615 _this = this;
1616 if (slide == null) {
1617 slide = true;
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
1630 if (slide) {
1631 return this.getUl().slideUp('fast', doClose);
1632 } else {
1633 this.getUl().hide();
1634 return doClose();
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);
1646 } else {
1647 return new GhostDropHint(this.node, this.$element, position);
1651 return FolderElement;
1653 })(NodeElement);
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;');
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;
1667 return -1;
1670 indexOf = function(array, item) {
1671 if (array.indexOf) {
1672 return array.indexOf(item);
1673 } else {
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;
1684 json_meta = {
1685 '\b': '\\b',
1686 '\t': '\\t',
1687 '\n': '\\n',
1688 '\f': '\\f',
1689 '\r': '\\r',
1690 '"': '\\"',
1691 '\\': '\\\\'
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 + '"';
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';
1717 case 'boolean':
1718 case 'null':
1719 return String(value);
1720 case 'object':
1721 if (!value) {
1722 return 'null';
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';
1730 return (partial.length === 0 ? '[]' : '[' + partial.join(',') + ']');
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);
1740 return (partial.length === 0 ? '{}' : '{' + partial.join(',') + '}');
1743 if (this.JSON == null) {
1744 this.JSON = {};
1746 this.JSON.stringify = function(value) {
1747 return json_str('', {
1748 '': value
1753 SaveStateHandler = (function() {
1754 function SaveStateHandler(tree_widget) {
1755 this.tree_widget = tree_widget;
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: '/'
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;
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;
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);
1805 return true;
1807 selected_node = this.tree_widget.getSelectedNode();
1808 if (selected_node) {
1809 selected_node_id = selected_node.id;
1810 } else {
1811 selected_node_id = '';
1813 return {
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,
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;
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;
1842 } else {
1843 return 'tree';
1847 return SaveStateHandler;
1849 })();
1851 SelectNodeHandler = (function() {
1852 function SelectNodeHandler(tree_widget) {
1853 this.tree_widget = tree_widget;
1854 this.clear();
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;
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);
1879 return selected_nodes;
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;
1893 SelectNodeHandler.prototype.clear = function() {
1894 this.selected_nodes = {};
1895 return this.selected_single_node = null;
1898 SelectNodeHandler.prototype.removeFromSelection = function(node, include_children) {
1899 var _this = this;
1900 if (include_children == null) {
1901 include_children = false;
1903 if (!node.id) {
1904 if (node.element === this.selected_single_node.element) {
1905 return this.selected_single_node = null;
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;
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;
1926 return SelectNodeHandler;
1928 })();
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;
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;
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) {
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;
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);
1976 if (can_move_to) {
1977 this.updateDropHint();
1980 } else {
1981 this.removeHover();
1982 this.removeDropHint();
1983 this.stopOpenFolderTimer();
1985 return true;
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;
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');
2009 this.is_dragging = false;
2010 return 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,
2039 _this = this;
2040 positions = [];
2041 last_top = 0;
2042 getTop = function($element) {
2043 return $element.offset().top;
2045 addPosition = function(node, position, top) {
2046 positions.push({
2047 top: top,
2048 node: node,
2049 position: position
2051 return last_top = top;
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);
2063 previous_top = position.top;
2064 group = [];
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) {
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);
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);
2084 handleOpenFolder = function(node, $element) {
2085 if (node === _this.current_item.node) {
2086 return false;
2088 if (node.children[0] !== _this.current_item.node) {
2089 addPosition(node, Position.INSIDE, getTop($element));
2091 return true;
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);
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);
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);
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
2131 area_top += area_height;
2133 return null;
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,
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;
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;
2160 } else {
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) {
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]);
2175 if (node.is_open) {
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())) {
2187 return null;
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;
2202 return null;
2205 DragAndDropHandler.prototype.mustOpenFolderTimer = function(area) {
2206 var node;
2207 node = area.node;
2208 return node.isFolder() && !node.is_open && area.position === Position.INSIDE;
2211 DragAndDropHandler.prototype.updateDropHint = function() {
2212 var node_element;
2213 if (!this.hovered_area) {
2214 return;
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) {
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();
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,
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;
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', {
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
2266 if (!event.isDefaultPrevented()) {
2267 return doMove();
2272 return DragAndDropHandler;
2274 })();
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();
2296 return DragElement;
2298 })();
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();
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;
2341 })();
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
2356 BorderDropHint.prototype.remove = function() {
2357 return this.$hint.remove();
2360 return BorderDropHint;
2362 })();
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,
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);
2388 return null;
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;
2401 } else {
2402 return setDocumentAsScrollParent();
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);
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) {
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);
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);
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();
2467 return (element_bottom <= view_bottom) && (element_top >= view_top);
2470 return ScrollHandler;
2472 })();
2474 KeyHandler = (function() {
2475 var DOWN, LEFT, RIGHT, UP;
2477 LEFT = 37;
2479 UP = 38;
2481 RIGHT = 39;
2483 DOWN = 40;
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,
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);
2504 return false;
2505 } else {
2506 return true;
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);
2518 return false;
2519 } else {
2520 return true;
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;
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();
2548 KeyHandler.prototype.getNextNode = function(node, include_children) {
2549 var next_sibling;
2550 if (include_children == null) {
2551 include_children = true;
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);
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);
2581 } else {
2582 if (node.parent.parent) {
2583 return node.parent;
2584 } else {
2585 return null;
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);
2605 return KeyHandler;
2607 })();
2609 }).call(this);