1 var $, BorderDropHint, DragAndDropHandler, DragElement, ElementsRenderer, FolderElement, GhostDropHint, HitAreasGenerator, JqTreeWidget, KeyHandler, MouseWidget, Node, NodeElement, Position, SaveStateHandler, ScrollHandler, SelectNodeHandler, SimpleWidget, __version__, drag_and_drop_handler, isFunction, node_module, ref, util_module,
2 extend = 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; },
3 hasProp = {}.hasOwnProperty;
5 __version__ = require('./version');
7 drag_and_drop_handler = require('./drag_and_drop_handler');
9 ElementsRenderer = require('./elements_renderer');
11 KeyHandler = require('./key_handler');
13 MouseWidget = require('./mouse.widget');
15 SaveStateHandler = require('./save_state_handler');
17 ScrollHandler = require('./scroll_handler');
19 SelectNodeHandler = require('./select_node_handler');
21 SimpleWidget = require('./simple.widget');
23 node_module = require('./node');
25 Node = node_module.Node;
27 Position = node_module.Position;
29 util_module = require('./util');
31 isFunction = util_module.isFunction;
33 ref = require('./node_element'), BorderDropHint = ref.BorderDropHint, FolderElement = ref.FolderElement, GhostDropHint = ref.GhostDropHint, NodeElement = ref.NodeElement;
35 DragAndDropHandler = drag_and_drop_handler.DragAndDropHandler, DragElement = drag_and_drop_handler.DragElement, HitAreasGenerator = drag_and_drop_handler.HitAreasGenerator;
39 JqTreeWidget = (function(superClass) {
40 extend(JqTreeWidget, superClass);
42 function JqTreeWidget() {
43 return JqTreeWidget.__super__.constructor.apply(this, arguments);
46 JqTreeWidget.prototype.BorderDropHint = BorderDropHint;
48 JqTreeWidget.prototype.DragElement = DragElement;
50 JqTreeWidget.prototype.DragAndDropHandler = DragAndDropHandler;
52 JqTreeWidget.prototype.ElementsRenderer = ElementsRenderer;
54 JqTreeWidget.prototype.GhostDropHint = GhostDropHint;
56 JqTreeWidget.prototype.HitAreasGenerator = HitAreasGenerator;
58 JqTreeWidget.prototype.Node = Node;
60 JqTreeWidget.prototype.SaveStateHandler = SaveStateHandler;
62 JqTreeWidget.prototype.ScrollHandler = ScrollHandler;
64 JqTreeWidget.prototype.SelectNodeHandler = SelectNodeHandler;
66 JqTreeWidget.prototype.defaults = {
72 onCanSelectNode: null,
73 onSetStateFromStorage: null,
74 onGetStateFromStorage: null,
83 openedIcon: '▼',
87 keyboardSupport: true,
96 JqTreeWidget.prototype.toggle = function(node, slide) {
100 if (slide === null) {
101 slide = this.options.slide;
104 this.closeNode(node, slide);
106 this.openNode(node, slide);
111 JqTreeWidget.prototype.getTree = function() {
115 JqTreeWidget.prototype.selectNode = function(node) {
116 this._selectNode(node, false);
120 JqTreeWidget.prototype._selectNode = function(node, must_toggle) {
121 var canSelect, deselected_node, openParents, saveState;
122 if (must_toggle == null) {
125 if (!this.select_node_handler) {
128 canSelect = (function(_this) {
130 if (_this.options.onCanSelectNode) {
131 return _this.options.selectable && _this.options.onCanSelectNode(node);
133 return _this.options.selectable;
137 openParents = (function(_this) {
140 parent = node.parent;
141 if (parent && parent.parent && !parent.is_open) {
142 return _this.openNode(parent, false);
146 saveState = (function(_this) {
148 if (_this.options.saveState) {
149 return _this.save_state_handler.saveState();
154 this._deselectCurrentNode();
161 if (this.select_node_handler.isNodeSelected(node)) {
163 this._deselectCurrentNode();
164 this._triggerEvent('tree.select', {
170 deselected_node = this.getSelectedNode();
171 this._deselectCurrentNode();
172 this.addToSelection(node);
173 this._triggerEvent('tree.select', {
175 deselected_node: deselected_node
182 JqTreeWidget.prototype.getSelectedNode = function() {
183 if (this.select_node_handler) {
184 return this.select_node_handler.getSelectedNode();
190 JqTreeWidget.prototype.toJson = function() {
191 return JSON.stringify(this.tree.getData());
194 JqTreeWidget.prototype.loadData = function(data, parent_node) {
195 this._loadData(data, parent_node);
202 - loadDataFromUrl(url, parent_node=null, on_finished=null)
203 loadDataFromUrl('/my_data');
204 loadDataFromUrl('/my_data', node1);
205 loadDataFromUrl('/my_data', node1, function() { console.log('finished'); });
206 loadDataFromUrl('/my_data', null, function() { console.log('finished'); });
208 - loadDataFromUrl(parent_node=null, on_finished=null)
210 loadDataFromUrl(node1);
211 loadDataFromUrl(null, function() { console.log('finished'); });
212 loadDataFromUrl(node1, function() { console.log('finished'); });
215 JqTreeWidget.prototype.loadDataFromUrl = function(param1, param2, param3) {
216 if ($.type(param1) === 'string') {
217 this._loadDataFromUrl(param1, param2, param3);
219 this._loadDataFromUrl(null, param1, param2);
224 JqTreeWidget.prototype.reload = function(on_finished) {
225 this._loadDataFromUrl(null, null, on_finished);
229 JqTreeWidget.prototype._loadDataFromUrl = function(url_info, parent_node, on_finished) {
230 var $el, addLoadingClass, handeLoadData, handleError, handleSuccess, loadDataFromUrlInfo, parseUrlInfo, removeLoadingClass;
232 addLoadingClass = (function(_this) {
235 $el = $(parent_node.element);
239 $el.addClass('jqtree-loading');
240 return _this._notifyLoading(true, parent_node, $el);
243 removeLoadingClass = (function(_this) {
246 $el.removeClass('jqtree-loading');
247 return _this._notifyLoading(false, parent_node, $el);
251 parseUrlInfo = function() {
252 if ($.type(url_info) === 'string') {
257 if (!url_info.method) {
258 url_info.method = 'get';
262 handeLoadData = (function(_this) {
263 return function(data) {
264 removeLoadingClass();
265 _this._loadData(data, parent_node);
266 if (on_finished && $.isFunction(on_finished)) {
267 return on_finished();
271 handleSuccess = (function(_this) {
272 return function(response) {
274 if ($.isArray(response) || typeof response === 'object') {
276 } else if (data != null) {
277 data = $.parseJSON(response);
281 if (_this.options.dataFilter) {
282 data = _this.options.dataFilter(data);
284 return handeLoadData(data);
287 handleError = (function(_this) {
288 return function(response) {
289 removeLoadingClass();
290 if (_this.options.onLoadFailed) {
291 return _this.options.onLoadFailed(response);
295 loadDataFromUrlInfo = function() {
296 url_info = parseUrlInfo();
297 return $.ajax($.extend({}, url_info, {
298 method: url_info.method != null ? url_info.method.toUpperCase() : 'GET',
301 success: handleSuccess,
306 url_info = this._getDataUrlInfo(parent_node);
310 removeLoadingClass();
311 } else if ($.isArray(url_info)) {
312 handeLoadData(url_info);
314 loadDataFromUrlInfo();
318 JqTreeWidget.prototype._loadData = function(data, parent_node) {
319 var deselectNodes, loadSubtree;
320 if (parent_node == null) {
323 deselectNodes = (function(_this) {
325 var i, len, n, selected_nodes_under_parent;
326 if (_this.select_node_handler) {
327 selected_nodes_under_parent = _this.select_node_handler.getSelectedNodesUnder(parent_node);
328 for (i = 0, len = selected_nodes_under_parent.length; i < len; i++) {
329 n = selected_nodes_under_parent[i];
330 _this.select_node_handler.removeFromSelection(n);
336 loadSubtree = (function(_this) {
338 parent_node.loadFromData(data);
339 parent_node.load_on_demand = false;
340 parent_node.is_loading = false;
341 return _this._refreshElements(parent_node);
347 this._triggerEvent('tree.load_data', {
351 this._initTree(data);
356 if (this.isDragging()) {
357 return this.dnd_handler.refresh();
361 JqTreeWidget.prototype.getNodeById = function(node_id) {
362 return this.tree.getNodeById(node_id);
365 JqTreeWidget.prototype.getNodeByName = function(name) {
366 return this.tree.getNodeByName(name);
369 JqTreeWidget.prototype.getNodesByProperty = function(key, value) {
370 return this.tree.getNodesByProperty(key, value);
373 JqTreeWidget.prototype.getNodeByHtmlElement = function(element) {
374 return this._getNode($(element));
377 JqTreeWidget.prototype.getNodeByCallback = function(callback) {
378 return this.tree.getNodeByCallback(callback);
381 JqTreeWidget.prototype.openNode = function(node, slide_param, on_finished_param) {
382 var on_finished, parseParams, ref1, slide;
383 if (slide_param == null) {
386 if (on_finished_param == null) {
387 on_finished_param = null;
389 parseParams = (function(_this) {
391 var on_finished, slide;
392 if (isFunction(slide_param)) {
393 on_finished = slide_param;
397 on_finished = on_finished_param;
399 if (slide === null) {
400 slide = _this.options.slide;
402 return [slide, on_finished];
405 ref1 = parseParams(), slide = ref1[0], on_finished = ref1[1];
407 this._openNode(node, slide, on_finished);
412 JqTreeWidget.prototype._openNode = function(node, slide, on_finished) {
413 var doOpenNode, parent;
417 doOpenNode = (function(_this) {
418 return function(_node, _slide, _on_finished) {
420 folder_element = new FolderElement(_node, _this);
421 return folder_element.open(_on_finished, _slide);
424 if (node.isFolder()) {
425 if (node.load_on_demand) {
426 return this._loadFolderOnDemand(node, slide, on_finished);
428 parent = node.parent;
431 doOpenNode(parent, false, null);
433 parent = parent.parent;
435 doOpenNode(node, slide, on_finished);
436 return this._saveState();
441 JqTreeWidget.prototype._loadFolderOnDemand = function(node, slide, on_finished) {
445 node.is_loading = true;
446 return this._loadDataFromUrl(null, node, (function(_this) {
448 return _this._openNode(node, slide, on_finished);
453 JqTreeWidget.prototype.closeNode = function(node, slide) {
457 if (slide === null) {
458 slide = this.options.slide;
460 if (node.isFolder()) {
461 new FolderElement(node, this).close(slide);
467 JqTreeWidget.prototype.isDragging = function() {
468 if (this.dnd_handler) {
469 return this.dnd_handler.is_dragging;
475 JqTreeWidget.prototype.refreshHitAreas = function() {
476 this.dnd_handler.refresh();
480 JqTreeWidget.prototype.addNodeAfter = function(new_node_info, existing_node) {
482 new_node = existing_node.addAfter(new_node_info);
483 this._refreshElements(existing_node.parent);
487 JqTreeWidget.prototype.addNodeBefore = function(new_node_info, existing_node) {
489 new_node = existing_node.addBefore(new_node_info);
490 this._refreshElements(existing_node.parent);
494 JqTreeWidget.prototype.addParentNode = function(new_node_info, existing_node) {
496 new_node = existing_node.addParent(new_node_info);
497 this._refreshElements(new_node.parent);
501 JqTreeWidget.prototype.removeNode = function(node) {
503 parent = node.parent;
505 this.select_node_handler.removeFromSelection(node, true);
507 this._refreshElements(parent);
512 JqTreeWidget.prototype.appendNode = function(new_node_info, parent_node) {
514 parent_node = parent_node || this.tree;
515 node = parent_node.append(new_node_info);
516 this._refreshElements(parent_node);
520 JqTreeWidget.prototype.prependNode = function(new_node_info, parent_node) {
523 parent_node = this.tree;
525 node = parent_node.prepend(new_node_info);
526 this._refreshElements(parent_node);
530 JqTreeWidget.prototype.updateNode = function(node, data) {
532 id_is_changed = data.id && data.id !== node.id;
534 this.tree.removeNodeFromIndex(node);
538 this.tree.addNodeToIndex(node);
540 if (typeof data === 'object' && data.children) {
541 node.removeChildren();
542 if (data.children.length) {
543 node.loadFromData(data.children);
546 this.renderer.renderFromNode(node);
547 this._selectCurrentNode();
551 JqTreeWidget.prototype.moveNode = function(node, target_node, position) {
553 position_index = Position.nameToIndex(position);
554 this.tree.moveNode(node, target_node, position_index);
555 this._refreshElements();
559 JqTreeWidget.prototype.getStateFromStorage = function() {
560 return this.save_state_handler.getStateFromStorage();
563 JqTreeWidget.prototype.addToSelection = function(node) {
565 this.select_node_handler.addToSelection(node);
566 this._getNodeElementForNode(node).select();
572 JqTreeWidget.prototype.getSelectedNodes = function() {
573 return this.select_node_handler.getSelectedNodes();
576 JqTreeWidget.prototype.isNodeSelected = function(node) {
577 return this.select_node_handler.isNodeSelected(node);
580 JqTreeWidget.prototype.removeFromSelection = function(node) {
581 this.select_node_handler.removeFromSelection(node);
582 this._getNodeElementForNode(node).deselect();
587 JqTreeWidget.prototype.scrollToNode = function(node) {
589 $element = $(node.element);
590 top = $element.offset().top - this.$el.offset().top;
591 this.scroll_handler.scrollTo(top);
595 JqTreeWidget.prototype.getState = function() {
596 return this.save_state_handler.getState();
599 JqTreeWidget.prototype.setState = function(state) {
600 this.save_state_handler.setInitialState(state);
601 this._refreshElements();
605 JqTreeWidget.prototype.setOption = function(option, value) {
606 this.options[option] = value;
610 JqTreeWidget.prototype.moveDown = function() {
611 if (this.key_handler) {
612 this.key_handler.moveDown();
617 JqTreeWidget.prototype.moveUp = function() {
618 if (this.key_handler) {
619 this.key_handler.moveUp();
624 JqTreeWidget.prototype.getVersion = function() {
628 JqTreeWidget.prototype._init = function() {
629 JqTreeWidget.__super__._init.call(this);
630 this.element = this.$el;
631 this.mouse_delay = 300;
632 this.is_initialized = false;
633 this.options.rtl = this._getRtlOption();
634 if (!this.options.closedIcon) {
635 this.options.closedIcon = this._getDefaultClosedIcon();
637 this.renderer = new ElementsRenderer(this);
638 if (SaveStateHandler != null) {
639 this.save_state_handler = new SaveStateHandler(this);
641 this.options.saveState = false;
643 if (SelectNodeHandler != null) {
644 this.select_node_handler = new SelectNodeHandler(this);
646 if (DragAndDropHandler != null) {
647 this.dnd_handler = new DragAndDropHandler(this);
649 this.options.dragAndDrop = false;
651 if (ScrollHandler != null) {
652 this.scroll_handler = new ScrollHandler(this);
654 if ((KeyHandler != null) && (SelectNodeHandler != null)) {
655 this.key_handler = new KeyHandler(this);
658 this.element.click($.proxy(this._click, this));
659 this.element.dblclick($.proxy(this._dblclick, this));
660 if (this.options.useContextMenu) {
661 return this.element.bind('contextmenu', $.proxy(this._contextmenu, this));
665 JqTreeWidget.prototype._deinit = function() {
666 this.element.empty();
667 this.element.unbind();
668 if (this.key_handler) {
669 this.key_handler.deinit();
672 return JqTreeWidget.__super__._deinit.call(this);
675 JqTreeWidget.prototype._initData = function() {
677 if (this.options.data) {
678 return this._loadData(this.options.data);
680 data_url = this._getDataUrlInfo();
682 return this._loadDataFromUrl();
684 return this._loadData([]);
689 JqTreeWidget.prototype._getDataUrlInfo = function(node) {
690 var data_url, getUrlFromString;
691 data_url = this.options.dataUrl || this.element.data('url');
692 getUrlFromString = (function(_this) {
694 var data, selected_node_id, url_info;
698 if (node && node.id) {
702 url_info['data'] = data;
704 selected_node_id = _this._getNodeIdToBeSelected();
705 if (selected_node_id) {
707 selected_node: selected_node_id
709 url_info['data'] = data;
715 if ($.isFunction(data_url)) {
716 return data_url(node);
717 } else if ($.type(data_url) === 'string') {
718 return getUrlFromString();
724 JqTreeWidget.prototype._getNodeIdToBeSelected = function() {
725 if (this.options.saveState) {
726 return this.save_state_handler.getNodeIdToBeSelected();
732 JqTreeWidget.prototype._initTree = function(data) {
733 var doInit, must_load_on_demand;
734 doInit = (function(_this) {
736 if (!_this.is_initialized) {
737 _this.is_initialized = true;
738 return _this._triggerEvent('tree.init');
742 this.tree = new this.options.nodeClass(null, true, this.options.nodeClass);
743 if (this.select_node_handler) {
744 this.select_node_handler.clear();
746 this.tree.loadFromData(data);
747 must_load_on_demand = this._setInitialState();
748 this._refreshElements();
749 if (!must_load_on_demand) {
752 return this._setInitialStateOnDemand(doInit);
756 JqTreeWidget.prototype._setInitialState = function() {
757 var autoOpenNodes, is_restored, must_load_on_demand, ref1, restoreState;
758 restoreState = (function(_this) {
760 var must_load_on_demand, state;
761 if (!(_this.options.saveState && _this.save_state_handler)) {
762 return [false, false];
764 state = _this.save_state_handler.getStateFromStorage();
766 return [false, false];
768 must_load_on_demand = _this.save_state_handler.setInitialState(state);
769 return [true, must_load_on_demand];
774 autoOpenNodes = (function(_this) {
776 var max_level, must_load_on_demand;
777 if (_this.options.autoOpen === false) {
780 max_level = _this._getAutoOpenMaxLevel();
781 must_load_on_demand = false;
782 _this.tree.iterate(function(node, level) {
783 if (node.load_on_demand) {
784 must_load_on_demand = true;
786 } else if (!node.hasChildren()) {
790 return level !== max_level;
793 return must_load_on_demand;
796 ref1 = restoreState(), is_restored = ref1[0], must_load_on_demand = ref1[1];
798 must_load_on_demand = autoOpenNodes();
800 return must_load_on_demand;
803 JqTreeWidget.prototype._setInitialStateOnDemand = function(cb_finished) {
804 var autoOpenNodes, restoreState;
805 restoreState = (function(_this) {
808 if (!(_this.options.saveState && _this.save_state_handler)) {
811 state = _this.save_state_handler.getStateFromStorage();
815 _this.save_state_handler.setInitialStateOnDemand(state, cb_finished);
821 autoOpenNodes = (function(_this) {
823 var loadAndOpenNode, loading_count, max_level, openNodes;
824 max_level = _this._getAutoOpenMaxLevel();
826 loadAndOpenNode = function(node) {
828 return _this._openNode(node, false, function() {
833 openNodes = function() {
834 _this.tree.iterate(function(node, level) {
835 if (node.load_on_demand) {
836 if (!node.is_loading) {
837 loadAndOpenNode(node);
841 _this._openNode(node, false);
842 return level !== max_level;
845 if (loading_count === 0) {
846 return cb_finished();
852 if (!restoreState()) {
853 return autoOpenNodes();
857 JqTreeWidget.prototype._getAutoOpenMaxLevel = function() {
858 if (this.options.autoOpen === true) {
861 return parseInt(this.options.autoOpen);
867 Redraw the tree or part of the tree.
868 * from_node: redraw this subtree
871 JqTreeWidget.prototype._refreshElements = function(from_node) {
872 if (from_node == null) {
875 this.renderer.render(from_node);
876 return this._triggerEvent('tree.refresh');
879 JqTreeWidget.prototype._click = function(e) {
880 var click_target, event, node;
881 click_target = this._getClickTarget(e.target);
883 if (click_target.type === 'button') {
884 this.toggle(click_target.node, this.options.slide);
886 return e.stopPropagation();
887 } else if (click_target.type === 'label') {
888 node = click_target.node;
889 event = this._triggerEvent('tree.click', {
893 if (!event.isDefaultPrevented()) {
894 return this._selectNode(node, true);
900 JqTreeWidget.prototype._dblclick = function(e) {
902 click_target = this._getClickTarget(e.target);
903 if (click_target && click_target.type === 'label') {
904 return this._triggerEvent('tree.dblclick', {
905 node: click_target.node,
911 JqTreeWidget.prototype._getClickTarget = function(element) {
912 var $button, $el, $target, node;
913 $target = $(element);
914 $button = $target.closest('.jqtree-toggler');
915 if ($button.length) {
916 node = this._getNode($button);
924 $el = $target.closest('.jqtree-element');
926 node = this._getNode($el);
938 JqTreeWidget.prototype._getNode = function($element) {
940 $li = $element.closest('li.jqtree_common');
941 if ($li.length === 0) {
944 return $li.data('node');
948 JqTreeWidget.prototype._getNodeElementForNode = function(node) {
949 if (node.isFolder()) {
950 return new FolderElement(node, this);
952 return new NodeElement(node, this);
956 JqTreeWidget.prototype._getNodeElement = function($element) {
958 node = this._getNode($element);
960 return this._getNodeElementForNode(node);
966 JqTreeWidget.prototype._contextmenu = function(e) {
968 $div = $(e.target).closest('ul.jqtree-tree .jqtree-element');
970 node = this._getNode($div);
974 this._triggerEvent('tree.contextmenu', {
983 JqTreeWidget.prototype._saveState = function() {
984 if (this.options.saveState) {
985 return this.save_state_handler.saveState();
989 JqTreeWidget.prototype._mouseCapture = function(position_info) {
990 if (this.options.dragAndDrop) {
991 return this.dnd_handler.mouseCapture(position_info);
997 JqTreeWidget.prototype._mouseStart = function(position_info) {
998 if (this.options.dragAndDrop) {
999 return this.dnd_handler.mouseStart(position_info);
1005 JqTreeWidget.prototype._mouseDrag = function(position_info) {
1007 if (this.options.dragAndDrop) {
1008 result = this.dnd_handler.mouseDrag(position_info);
1009 if (this.scroll_handler) {
1010 this.scroll_handler.checkScrolling();
1018 JqTreeWidget.prototype._mouseStop = function(position_info) {
1019 if (this.options.dragAndDrop) {
1020 return this.dnd_handler.mouseStop(position_info);
1026 JqTreeWidget.prototype._triggerEvent = function(event_name, values) {
1028 event = $.Event(event_name);
1029 $.extend(event, values);
1030 this.element.trigger(event);
1034 JqTreeWidget.prototype.testGenerateHitAreas = function(moving_node) {
1035 this.dnd_handler.current_item = this._getNodeElementForNode(moving_node);
1036 this.dnd_handler.generateHitAreas();
1037 return this.dnd_handler.hit_areas;
1040 JqTreeWidget.prototype._selectCurrentNode = function() {
1041 var node, node_element;
1042 node = this.getSelectedNode();
1044 node_element = this._getNodeElementForNode(node);
1046 return node_element.select();
1051 JqTreeWidget.prototype._deselectCurrentNode = function() {
1053 node = this.getSelectedNode();
1055 return this.removeFromSelection(node);
1059 JqTreeWidget.prototype._getDefaultClosedIcon = function() {
1060 if (this.options.rtl) {
1067 JqTreeWidget.prototype._getRtlOption = function() {
1069 if (this.options.rtl !== null) {
1070 return this.options.rtl;
1072 data_rtl = this.element.data('rtl');
1073 if ((data_rtl != null) && data_rtl !== false) {
1081 JqTreeWidget.prototype._notifyLoading = function(is_loading, node, $el) {
1082 if (this.options.onLoading) {
1083 return this.options.onLoading(is_loading, node, $el);
1087 return JqTreeWidget;
1091 JqTreeWidget.getModule = function(name) {
1094 'node': node_module,
1095 'util': util_module,
1096 'drag_and_drop_handler': drag_and_drop_handler
1098 return modules[name];
1101 SimpleWidget.register(JqTreeWidget, 'tree');