diff --git a/README.md b/README.md index 527c8f59..d290f7fb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -[![Travis Status](https://secure.travis-ci.org/mbraak/jqTree.svg)](http://travis-ci.org/mbraak/jqTree) [![Coverage Status](https://img.shields.io/coveralls/mbraak/jqTree.svg)](https://coveralls.io/r/mbraak/jqTree) [![Bower version](https://badge.fury.io/bo/jqtree.svg)](http://badge.fury.io/bo/jqtree) +[![Travis Status](https://secure.travis-ci.org/mbraak/jqTree.svg)](http://travis-ci.org/mbraak/jqTree) [![Coverage Status](https://img.shields.io/coveralls/mbraak/jqTree.svg)](https://coveralls.io/r/mbraak/jqTree) + +[![Bower version](https://badge.fury.io/bo/jqtree.svg)](http://badge.fury.io/bo/jqtree) [![NPM version](https://badge.fury.io/js/jqtree.svg)](http://badge.fury.io/js/jqtree) #jqTree diff --git a/build b/build deleted file mode 100755 index ef323461..00000000 --- a/build +++ /dev/null @@ -1,2 +0,0 @@ -# Build and watch coffeescript -coffee -w -j tree.jquery.js -c src/version.coffee src/simple.widget.coffee src/mouse.widget.coffee src/node.coffee src/elements_renderer.coffee src/tree.jquery.coffee src/save_state_handler.coffee src/select_node_handler.coffee src/drag_and_drop_handler.coffee src/scroll_handler.coffee src/key_handler.coffee diff --git a/gulpfile.coffee b/gulpfile.coffee new file mode 100644 index 00000000..ac8e1af8 --- /dev/null +++ b/gulpfile.coffee @@ -0,0 +1,27 @@ +gulp = require 'gulp' +coffee = require 'gulp-coffee' +coffeeify = require 'gulp-coffeeify' +exec = require('child_process').exec + +gulp.task 'jqtree', -> + gulp.src './src/tree.jquery.coffee' + .pipe coffeeify() + .pipe gulp.dest('./') + +gulp.task 'lib', -> + gulp.src './src/*.coffee' + .pipe coffee(bare: true) + .pipe gulp.dest('./lib') + +gulp.task 'build_test', -> + gulp.src './src/test.js' + .pipe coffeeify() + .pipe gulp.dest('./test') + +gulp.task 'jekyll', (cb) -> + exec 'jekyll build', (err, stdout, stderr) -> + console.log(stdout) + console.log(stderr) + cb(err) + +gulp.task 'default', ['jqtree', 'build_test', 'lib'] diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 00000000..c7f2b8b8 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,2 @@ +require('coffee-script/register'); +require('./gulpfile.coffee'); diff --git a/package.json b/package.json new file mode 100644 index 00000000..12106d3d --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "jqtree", + "version": "0.22.0", + "description": "Tree widget for jQuery", + "main": "lib/tree.jquery.js", + "repository": { + "type": "git", + "url": "https://github.com/mbraak/jqtree" + }, + "dependencies": { + "jquery": ">1.5" + }, + "devDependencies": { + "coffee-script": "1.8.0", + "gulp": "3.8.8", + "gulp-coffee": "2.2.0", + "gulp-coffeeify": "0.1.2" + } +} diff --git a/src/drag_and_drop_handler.coffee b/src/drag_and_drop_handler.coffee index e6e42e7b..bfa8ebe9 100644 --- a/src/drag_and_drop_handler.coffee +++ b/src/drag_and_drop_handler.coffee @@ -1,3 +1,7 @@ +node_module = require './node' +Position = node_module.Position + + class DragAndDropHandler constructor: (tree_widget) -> @tree_widget = tree_widget @@ -459,52 +463,4 @@ class DragElement @$element.remove() -class GhostDropHint - constructor: (node, $element, position) -> - @$element = $element - - @node = node - @$ghost = $('
  • ') - - if position == Position.AFTER - @moveAfter() - else if position == Position.BEFORE - @moveBefore() - else if position == Position.INSIDE - if node.isFolder() and node.is_open - @moveInsideOpenFolder() - else - @moveInside() - - remove: -> - @$ghost.remove() - - moveAfter: -> - @$element.after(@$ghost) - - moveBefore: -> - @$element.before(@$ghost) - - moveInsideOpenFolder: -> - $(@node.children[0].element).before(@$ghost) - - moveInside: -> - @$element.after(@$ghost) - @$ghost.addClass('jqtree-inside') - - -class BorderDropHint - constructor: ($element) -> - $div = $element.children('.jqtree-element') - width = $element.width() - 4 - - @$hint = $('') - $div.append(@$hint) - - @$hint.css( - width: width - height: $div.height() - 4 - ) - - remove: -> - @$hint.remove() +module.exports = DragAndDropHandler diff --git a/src/elements_renderer.coffee b/src/elements_renderer.coffee index 73f78f98..df7f3c01 100644 --- a/src/elements_renderer.coffee +++ b/src/elements_renderer.coffee @@ -1,3 +1,10 @@ +node_element = require './node_element' +NodeElement = node_element.NodeElement + +util = require './util' +html_escape = util.html_escape + + class ElementsRenderer constructor: (tree_widget) -> @tree_widget = tree_widget @@ -192,3 +199,6 @@ class ElementsRenderer return document.createTextNode(div.innerHTML) else return $(value)[0] + + +module.exports = ElementsRenderer diff --git a/src/key_handler.coffee b/src/key_handler.coffee index 04c6fbc3..f4ed2c8d 100644 --- a/src/key_handler.coffee +++ b/src/key_handler.coffee @@ -117,4 +117,7 @@ class KeyHandler if not last_child.hasChildren() or not last_child.is_open return last_child else - return @getLastChild(last_child) \ No newline at end of file + return @getLastChild(last_child) + + +module.exports = KeyHandler diff --git a/src/mouse.widget.coffee b/src/mouse.widget.coffee index da97e610..6d622649 100644 --- a/src/mouse.widget.coffee +++ b/src/mouse.widget.coffee @@ -2,6 +2,9 @@ This widget does the same a the mouse widget in jqueryui. ### +SimpleWidget = require './simple.widget' + + class MouseWidget extends SimpleWidget @is_mouse_handled = false @@ -173,4 +176,6 @@ class MouseWidget extends SimpleWidget return @_handleMouseUp( @_getPositionInfo(touch) - ) \ No newline at end of file + ) + +module.exports = MouseWidget diff --git a/src/node.coffee b/src/node.coffee index 01b65618..c09baa2f 100644 --- a/src/node.coffee +++ b/src/node.coffee @@ -1,6 +1,3 @@ -@Tree = {} -$ = @jQuery - Position = getName: (position) -> return Position.strings[position - 1] @@ -18,8 +15,6 @@ Position.NONE = 4 Position.strings = ['before', 'after', 'inside', 'none'] -@Tree.Position = Position - class Node constructor: (o, is_root=false, node_class=Node) -> @setData(o) @@ -386,4 +381,6 @@ class Node return result -@Tree.Node = Node +module.exports = + Node: Node + Position: Position diff --git a/src/node_element.coffee b/src/node_element.coffee new file mode 100644 index 00000000..489d1a43 --- /dev/null +++ b/src/node_element.coffee @@ -0,0 +1,144 @@ +node = require './node' +Position = node.Position + + +class NodeElement + constructor: (node, tree_widget) -> + @init(node, tree_widget) + + init: (node, tree_widget) -> + @node = node + @tree_widget = tree_widget + + if not node.element + node.element = @tree_widget.element + + @$element = $(node.element) + + getUl: -> + return @$element.children('ul:first') + + getSpan: -> + return @$element.children('.jqtree-element').find('span.jqtree-title') + + getLi: -> + return @$element + + addDropHint: (position) -> + if position == Position.INSIDE + return new BorderDropHint(@$element) + else + return new GhostDropHint(@node, @$element, position) + + select: -> + @getLi().addClass('jqtree-selected') + + deselect: -> + @getLi().removeClass('jqtree-selected') + + +class FolderElement extends NodeElement + open: (on_finished, slide=true) -> + if not @node.is_open + @node.is_open = true + $button = @getButton() + $button.removeClass('jqtree-closed') + $button.html('') + $button.append(@tree_widget.renderer.opened_icon_element.cloneNode()) + + doOpen = => + @getLi().removeClass('jqtree-closed') + if on_finished + on_finished() + + @tree_widget._triggerEvent('tree.open', node: @node) + + if slide + @getUl().slideDown('fast', doOpen) + else + @getUl().show() + doOpen() + + close: (slide=true) -> + if @node.is_open + @node.is_open = false + $button = @getButton() + $button.addClass('jqtree-closed') + $button.html('') + $button.append(@tree_widget.renderer.closed_icon_element.cloneNode()) + + doClose = => + @getLi().addClass('jqtree-closed') + + @tree_widget._triggerEvent('tree.close', node: @node) + + if slide + @getUl().slideUp('fast', doClose) + else + @getUl().hide() + doClose() + + getButton: -> + return @$element.children('.jqtree-element').find('a.jqtree-toggler') + + addDropHint: (position) -> + if not @node.is_open and position == Position.INSIDE + return new BorderDropHint(@$element) + else + return new GhostDropHint(@node, @$element, position) + + +class BorderDropHint + constructor: ($element) -> + $div = $element.children('.jqtree-element') + width = $element.width() - 4 + + @$hint = $('') + $div.append(@$hint) + + @$hint.css( + width: width + height: $div.height() - 4 + ) + + remove: -> + @$hint.remove() + + +class GhostDropHint + constructor: (node, $element, position) -> + @$element = $element + + @node = node + @$ghost = $('
  • ') + + if position == Position.AFTER + @moveAfter() + else if position == Position.BEFORE + @moveBefore() + else if position == Position.INSIDE + if node.isFolder() and node.is_open + @moveInsideOpenFolder() + else + @moveInside() + + remove: -> + @$ghost.remove() + + moveAfter: -> + @$element.after(@$ghost) + + moveBefore: -> + @$element.before(@$ghost) + + moveInsideOpenFolder: -> + $(@node.children[0].element).before(@$ghost) + + moveInside: -> + @$element.after(@$ghost) + @$ghost.addClass('jqtree-inside') + + +module.exports = + FolderElement: FolderElement + NodeElement: NodeElement diff --git a/src/save_state_handler.coffee b/src/save_state_handler.coffee index 3375d256..af9ed908 100644 --- a/src/save_state_handler.coffee +++ b/src/save_state_handler.coffee @@ -1,106 +1,7 @@ -# Standard javascript indexOf. Implemented here because not all browsers support it. -_indexOf = (array, item) -> - for value, i in array - if value == item - return i - return -1 - -indexOf = (array, item) -> - if array.indexOf - # The browser supports indexOf - return array.indexOf(item) - else - # Do our own indexOf - return _indexOf(array, item) - -@Tree.indexOf = indexOf -@Tree._indexOf = _indexOf - -isInt = (n) -> - return typeof n is 'number' and n % 1 == 0 - - -# JSON.stringify function; copied from json2 -get_json_stringify_function = -> - json_escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g - json_meta = { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - } - - json_quote = (string) -> - json_escapable.lastIndex = 0 - - if json_escapable.test(string) - return '"' + string.replace(json_escapable, (a) -> - c = json_meta[a] - return ( - if typeof c is 'string' then c - else '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4) - ) - ) + '"' - else - return '"' + string + '"' - - json_str = (key, holder) -> - value = holder[key] - - switch typeof value - when 'string' - return json_quote(value) - - when 'number' - return if isFinite(value) then String(value) else 'null' +util = require './util' - when 'boolean', 'null' - return String(value) - - when 'object' - if not value - return 'null' - - partial = [] - if Object::toString.apply(value) is '[object Array]' - for v, i in value - partial[i] = json_str(i, value) or 'null' - - return ( - if partial.length is 0 then '[]' - else '[' + partial.join(',') + ']' - ) - - for k of value - if Object::hasOwnProperty.call(value, k) - v = json_str(k, value) - if v - partial.push(json_quote(k) + ':' + v) - - return ( - if partial.length is 0 then '{}' - else '{' + partial.join(',') + '}' - ) - - stringify = (value) -> - return json_str( - '', - {'': value} - ) - - return stringify - - -@Tree.get_json_stringify_function = get_json_stringify_function - -if not (@JSON? and @JSON.stringify? and typeof @JSON.stringify == 'function') - if not @JSON? - @JSON = {} - - @JSON.stringify = get_json_stringify_function() +indexOf = util.indexOf +isInt = util.isInt class SaveStateHandler @@ -245,3 +146,6 @@ class SaveStateHandler return state.selected_node[0] else return null + + +module.exports = SaveStateHandler diff --git a/src/scroll_handler.coffee b/src/scroll_handler.coffee index 13ec1971..57310eea 100644 --- a/src/scroll_handler.coffee +++ b/src/scroll_handler.coffee @@ -94,4 +94,7 @@ class ScrollHandler element_top = $element.offset().top element_bottom = element_top + $element.height() - return (element_bottom <= view_bottom) and (element_top >= view_top) \ No newline at end of file + return (element_bottom <= view_bottom) and (element_top >= view_top) + + +module.exports = ScrollHandler diff --git a/src/select_node_handler.coffee b/src/select_node_handler.coffee index 7be75168..9f936c91 100644 --- a/src/select_node_handler.coffee +++ b/src/select_node_handler.coffee @@ -71,3 +71,6 @@ class SelectNodeHandler @selected_nodes[node.id] = true else @selected_single_node = node + + +module.exports = SelectNodeHandler diff --git a/src/simple.widget.coffee b/src/simple.widget.coffee index e0b21d70..cbbdd1bb 100644 --- a/src/simple.widget.coffee +++ b/src/simple.widget.coffee @@ -14,9 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. ### -$ = @jQuery - - class SimpleWidget defaults: {} @@ -101,4 +98,5 @@ class SimpleWidget else return callFunction($el, function_name, args) -@SimpleWidget = SimpleWidget + +module.exports = SimpleWidget diff --git a/src/test.js b/src/test.js new file mode 100644 index 00000000..e9a42936 --- /dev/null +++ b/src/test.js @@ -0,0 +1,1871 @@ +var node = require('./node') +var Node = node.Node; +var Position = node.Position; + +var util = require('./util') +_indexOf = util._indexOf +indexOf = util.indexOf +get_json_stringify_function = util.get_json_stringify_function + +QUnit.config.testTimeout = 5000; + +/* +example data: + +node1 +---child1 +---child2 +-node2 +---child3 +*/ + +var example_data = [ + { + label: 'node1', + id: 123, // extra data + children: [ + { label: 'child1', id: 125 }, + { label: 'child2', id: 126 } + ] + }, + { + label: 'node2', + id: 124, + children: [ + { label: 'child3', id: 127 } + ] + } + +]; + +/* +example data 2: + +-main +---c1 +---c2 +*/ + +var example_data2 = [ + { + label: 'main', + children: [ + { label: 'c1' }, + { label: 'c2' } + ] + } +]; + +function formatNodes(nodes) { + var strings = $.map(nodes, function(node) { + return node.name; + }); + return strings.join(' '); +}; + +function isNodeClosed($node) { + return ( + ($node.is('li.jqtree-folder.jqtree-closed')) && + ($node.find('a:eq(0)').is('a.jqtree-toggler.jqtree-closed')) && + ($node.find('ul:eq(0)').is('ul')) + ); +} + +function isNodeOpen($node) { + return ( + ($node.is('li.jqtree-folder')) && + ($node.find('a:eq(0)').is('a.jqtree-toggler')) && + ($node.find('ul:eq(0)').is('ul')) && + (! $node.is('li.jqtree-folder.jqtree-closed')) && + (! $node.find('span:eq(0)').is('a.jqtree-toggler.jqtree-closed')) + ); +} + +function formatTitles($node) { + var titles = $node.find('.jqtree-title').map( + function(i, el) { + return $(el).text(); + } + ); + return titles.toArray().join(' '); +} + + +QUnit.module("jqtree", { + setup: function() { + $('body').append('
    '); + }, + + teardown: function() { + var $tree = $('#tree1'); + $tree.tree('destroy'); + $tree.remove(); + } +}); + +test("create jqtree from data", function() { + $('#tree1').tree({ + data: example_data + }); + + equal( + $('#tree1').children().length, 1, + 'number of children on level 0' + ); + ok( + $('#tree1').children().is('ul.jqtree-tree'), + 'first element is ul.jqtree-tree' + ); + equal( + $('#tree1 ul.jqtree-tree > li').length, 2, + 'number of children on level 1' + ); + ok( + $('#tree1 ul.jqtree-tree li:eq(0)').is('li.jqtree-folder.jqtree-closed'), + 'first child is li.jqtree-folder.jqtree-closed' + ); + ok( + $('#tree1 ul.jqtree-tree li:eq(0) > .jqtree-element > a.jqtree-toggler').is('a.jqtree-toggler.jqtree-closed'), + 'button in first folder' + ); + equal( + $('#tree1 ul.jqtree-tree li:eq(0) > .jqtree-element span.jqtree-title').text(), + 'node1' + ); +}); + +test('toggle', function() { + // create tree + var $tree = $('#tree1'); + var $node1; + var node1; + + $tree.tree({ + data: example_data + }); + + $tree.bind( + 'tree.open', + function(e) { + start(); + + ok(! isNodeClosed($node1), 'node1 is open'); + + // 2. close node1 + $tree.tree('toggle', node1); + + stop(); + } + ); + + $tree.bind( + 'tree.close', + function(e) { + start(); + + ok(isNodeClosed($node1), 'node1 is closed'); + } + ); + + var tree = $tree.tree('getTree'); + node1 = tree.children[0]; + $node1 = $tree.find('ul.jqtree-tree li:eq(0)'); + + // node1 is initially closed + ok(isNodeClosed($node1), 'node1 is closed'); + + // 1. open node1 + $tree.tree('toggle', node1); + + stop(); +}); + +test("click event", function() { + stop(); + + // create tree + var $tree = $('#tree1'); + $tree.tree({ + data: example_data, + selectable: true + }); + + $tree.bind('tree.click', function(e) { + equal(e.node.name, 'node1'); + }); + + $tree.bind('tree.select', function(e) { + start(); + equal(e.node.name, 'node1'); + }); + + // click on node1 + var $node1 = $tree.find('ul.jqtree-tree li:first'); + var $text_span = $node1.find('span:first'); + $text_span.click(); +}); + +test('saveState', function() { + var $tree = $('#tree1'); + + var saved_state; + + function setState(state) { + saved_state = state; + } + + function getState() { + return saved_state; + } + + function createTree() { + $tree.tree({ + data: example_data, + saveState: true, + onSetStateFromStorage: setState, + onGetStateFromStorage: getState, + selectable: true + }); + } + + // create tree + createTree(); + + // nodes are initially closed + var tree = $tree.tree('getTree'); + tree.iterate(function(node) { + ok(! node.is_open, 'jqtree-closed'); + return true; + }); + + // open node1 + $tree.tree('toggle', tree.children[0]); + + // node1 is open + ok(tree.children[0].is_open, 'node1 is_open'); + + // select node2 + $tree.tree('selectNode', tree.children[1]); + + // node2 is selected + equal( + $tree.tree('getSelectedNode').name, + 'node2', + 'getSelectedNode (1)' + ); + + // create tree again + $tree.tree('destroy'); + createTree(); + + tree = $tree.tree('getTree'); + ok(tree.children[0].is_open, 'node1 is_open'); + ok(! tree.children[1].is_open, 'node2 is closed'); + + // node2 is selected + equal( + $tree.tree('getSelectedNode').name, + 'node2', + 'getSelectedNode (2)' + ); +}); + +test('getSelectedNode', function() { + var $tree = $('#tree1'); + + // create tree + $tree.tree({ + data: example_data, + selectable: true + }); + + // there is no node selected + equal( + $tree.tree('getSelectedNode'), + false, + 'getSelectedNode' + ); + + // select node1 + var tree = $tree.tree('getTree'); + var node1 = tree.children[0]; + $tree.tree('selectNode', node1); + + // node1 is selected + equal( + $tree.tree('getSelectedNode').name, + 'node1', + 'getSelectedNode' + ); +}); + +test("toJson", function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data + }); + + // 1. call toJson + equal( + $tree.tree('toJson'), + '[{"name":"node1","id":123,"children":'+ + '[{"name":"child1","id":125},{"name":"child2","id":126}]},'+ + '{"name":"node2","id":124,"children":[{"name":"child3","id":127}]}]' + ); + + // Check that properties 'children', 'parent' and 'element' still exist. + var tree = $tree.tree('getTree'); + equal(tree.children.length, 2); + ok(tree.children[0].parent != undefined, 'parent'); + ok($(tree.children[0].element).is('li'), 'element'); +}); + +test('loadData', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data, + autoOpen: true + }); + + // first node is 'node1' + equal( + $tree.find('> ul > li:first .jqtree-element:first > span').text(), + 'node1' + ); + + // - load new data + $tree.tree('loadData', example_data2); + + // first node is 'main' + equal( + $tree.find('> ul > li:first .jqtree-element:first > span').text(), + 'main' + ); + + // - load new data under node 'child3' + $tree.tree('loadData', example_data); + + var child3 = $tree.tree('getNodeByName', 'child3'); + + var data = [ + { label: 'c4', id: 200 }, + { + label: 'c5', id: 201, + children: [ + { label: 'c6', id: 202 } + ] + } + ]; + $tree.tree('loadData', data, child3); + + // first node in html is still 'node1' + equal( + $tree.find('li:eq(0)').find('.jqtree-element:eq(0) span.jqtree-title').text(), + 'node1' + ); + + // Node 'child3' now has a children 'c4' and 'c5' + var $child3 = $tree.find('span:contains(child3)'); + var $li = $child3.closest('li'); + equal( + $li.children('ul').children('li:eq(0)').find('.jqtree-element span.jqtree-title').text(), + 'c4' + ); + + // Node 'child3' must have toggler button + ok($child3.prev().is('a.jqtree-toggler')); + + // - select node 'c5' and load new data under 'child3' + var c5 = $tree.tree('getNodeByName', 'c5'); + $tree.tree('selectNode', c5); + + equal($tree.tree('getSelectedNode').name, 'c5'); + + var data2 = [ + { label: 'c7' }, + { label: 'c8' } + ]; + $tree.tree('loadData', data2, child3); + + // c5 must be deselected + equal($tree.tree('getSelectedNode'), false); + + // - select c7; load new data under child3; note that c7 has no id + $tree.tree('selectNode', $tree.tree('getNodeByName', 'c7')); + + equal($tree.tree('getSelectedNode').name, 'c7'); + + $tree.tree('loadData', [ 'c9' ], child3); + + equal($tree.tree('getSelectedNode'), false); + + // - select c9 (which has no id); load new nodes under child2 + $tree.tree('selectNode', $tree.tree('getNodeByName', 'c9')); + + var child2 = $tree.tree('getNodeByName', 'child2'); + $tree.tree('loadData', [ 'c10' ], child2); + + equal($tree.tree('getSelectedNode').name, 'c9'); +}); + +test('openNode and closeNode', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data + }); + + var node2 = $tree.tree('getNodeByName', 'node2'); + equal(node2.name, 'node2'); + equal(node2.is_open, undefined); + + // 1. open node2 + $tree.tree('openNode', node2, false); + equal(node2.is_open, true); + equal(isNodeOpen($(node2.element)), true); + + // 2. close node2 + $tree.tree('closeNode', node2, false); + equal(node2.is_open, false); + equal(isNodeClosed($(node2.element)), true); + + // 3. open child1 + var node1 = $tree.tree('getNodeByName', 'node1'); + var child1 = $tree.tree('getNodeByName', 'child1'); + + // add a child to child1 so it is a folder + $tree.tree('appendNode', 'child1a', child1); + + // node1 is initialy closed + equal(node1.is_open, undefined); + + // open child1 + $tree.tree('openNode', child1, false); + + // node1 and child1 are now open1 + equal(node1.is_open, true); + equal(child1.is_open, true); +}); + +test('selectNode', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data, + selectable: true + }); + + var node1 = $tree.tree('getTree').children[0]; + var node2 = $tree.tree('getTree').children[1]; + var child3 = node2.children[0]; + + equal(child3.name, 'child3'); + equal(node1.is_open, undefined); + equal(node2.is_open, undefined); + equal(child3.is_open, undefined); + + // -- select node 'child3', which is a child of 'node2'; must_open_parents = true + $tree.tree('selectNode', child3, true); + equal($tree.tree('getSelectedNode').name, 'child3'); + + equal(node1.is_open, undefined); + equal(node2.is_open, true); + equal(child3.is_open, undefined); + + // -- select node 'node1' + $tree.tree('selectNode', node1); + equal($tree.tree('getSelectedNode').name, 'node1'); + + // -- is 'node1' selected? + ok($tree.tree('isNodeSelected', node1)); +}); + +test('selectNode when another node is selected', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data, + selectable: true + }); + + var node1 = $tree.tree('getTree').children[0]; + var node2 = $tree.tree('getTree').children[1]; + + + // -- select node 'node2' + $tree.tree('selectNode', node2); + equal($tree.tree('getSelectedNode').name, 'node2'); + + // -- setting event + // -- is node 'node2' named 'deselected_node' in object's attributes? + stop(); + $tree.bind('tree.select', function(e) { + start(); + equal(e.deselected_node, node2); + }); + + // -- select node 'node1'; node 'node2' is selected before it + $tree.tree('selectNode', node1); + equal($tree.tree('getSelectedNode').name, 'node1'); + + ok($tree.tree('isNodeSelected', node1)); +}); + +test('click toggler', function() { + // setup + stop(); + + var $tree = $('#tree1'); + $tree.tree({ + data: example_data, + selectable: true + }); + + var $title = $tree.find('li:eq(0)').find('> .jqtree-element > span.jqtree-title'); + equal($title.text(), 'node1'); + var $toggler = $title.prev(); + ok($toggler.is('a.jqtree-toggler.jqtree-closed')); + + $tree.bind('tree.open', function(e) { + // 2. handle 'open' event + start(); + equal(e.node.name, 'node1'); + stop(); + + // 3. click toggler again + $toggler.click(); + }); + + $tree.bind('tree.close', function(e) { + start(); + equal(e.node.name, 'node1'); + }); + + // 1. click toggler of 'node1' + $toggler.click(); +}); + +test('getNodeById', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data + }); + var node2 = $tree.tree('getNodeByName', 'node2'); + + // 1. get 'node2' by id + equal( + $tree.tree('getNodeById', 124).name, + 'node2' + ); + + // 2. get id that does not exist + equal($tree.tree('getNodeById', 333), null); + + // 3. get id by string + equal( + $tree.tree('getNodeById', '124').name, + 'node2' + ); + + // 4. add node with string id; search by int + $tree.tree( + 'appendNode', + { + label: 'abc', + id: '234' + } + ); + + equal( + $tree.tree('getNodeById', 234).name, + 'abc' + ); + equal( + $tree.tree('getNodeById', '234').name, + 'abc' + ); + + // 5. load subtree in node2 + var subtree_data = [ + { + label: 'sub1', + id: 200, + children: [ + {label: 'sub2', id: 201} + ] + } + ]; + $tree.tree('loadData', subtree_data, node2); + var t = $tree.tree('getTree'); + + equal( + $tree.tree('getNodeById', 200).name, + 'sub1' + ); + equal( + $tree.tree('getNodeById', 201).name, + 'sub2' + ); +}); + +test('autoOpen', function() { + var $tree = $('#tree1'); + + function formatOpenFolders() { + var open_nodes = []; + $tree.find('li').each(function() { + var $li = $(this); + if ($li.is('.jqtree-folder') && ! $li.is('.jqtree-closed')) { + var label = $li.children('.jqtree-element').find('span').text(); + open_nodes.push(label); + }; + }); + + return open_nodes.join(';'); + } + + /* + -l1n1 (level 0) + ----l2n1 (1) + ----l2n2 (1) + -------l3n1 (2) + ----------l4n1 (3) + -l1n2 + */ + var data = [ + { + label: 'l1n1', + children: [ + 'l2n1', + { + label: 'l2n2', + children: [ + { + label: 'l3n1', + children: [ + 'l4n1' + ] + } + ] + } + ] + }, + 'l1n2' + ]; + + // 1. autoOpen is false + $tree.tree({ + data: data, + autoOpen: false + }); + equal(formatOpenFolders(), ''); + + $tree.tree('destroy'); + + // 2. autoOpen is true + $tree.tree({ + data: data, + autoOpen: true + }); + equal(formatOpenFolders(), 'l1n1;l2n2;l3n1'); + + $tree.tree('destroy'); + + // 3. autoOpen level 1 + $tree.tree({ + data: data, + autoOpen: 1 + }); + equal(formatOpenFolders(), 'l1n1;l2n2'); +}); + +test('onCreateLi', function() { + // 1. init tree with onCreateLi + var $tree = $('#tree1'); + $tree.tree({ + data: example_data, + onCreateLi: function(node, $li) { + var $span = $li.children('.jqtree-element').find('span'); + $span.html('_' + node.name + '_'); + } + }); + + equal( + $tree.find('span:eq(0)').text(), + '_node1_' + ); +}); + +test('save state', function() { + // setup + var state = null; + + // Fake $.cookie plugin for browsers that do not support localstorage + $.cookie = function(key, param2, param3) { + if (typeof param3 == 'object') { + // set + state = param2; + } + else { + // get + return state; + } + } + + // Remove state from localstorage + if (typeof localStorage != 'undefined') { + localStorage.setItem('my_tree', null); + } + + // 1. init tree + var $tree = $('#tree1'); + $tree.tree({ + data: example_data, + selectable: true, + saveState: 'my_tree' + }); + + var tree = $tree.tree('getTree'); + equal($tree.tree('getSelectedNode'), false); + + // 2. select node -> state is saved + $tree.tree('selectNode', tree.children[0]); + equal($tree.tree('getSelectedNode').name, 'node1'); + + // 3. init tree again + $tree.tree('destroy'); + + $tree.tree({ + data: example_data, + selectable: true, + saveState: 'my_tree' + }); + + equal($tree.tree('getSelectedNode').name, 'node1'); + + $.cookie = null; +}); + +test('generate hit areas', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data + }); + + // 1. get hit areas + var node = $tree.tree('getNodeById', 123); + var hit_areas = $tree.tree('testGenerateHitAreas', node); + + var strings = $.map(hit_areas, function(hit_area) { + return hit_area.node.name + ' ' + Position.getName(hit_area.position); + }); + equal(strings.join(';'), 'node1 none;node2 inside;node2 after'); +}); + +test('removeNode', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data, + selectable: true + }); + + // 1. Remove selected node; node is 'child1' + var child1 = $tree.tree('getNodeByName', 'child1'); + $tree.tree('selectNode', child1); + + equal($tree.tree('getSelectedNode').name, 'child1'); + + $tree.tree('removeNode', child1); + + equal( + formatTitles($tree), + 'node1 child2 node2 child3' + ); + + // getSelectedNode must now return false + equal($tree.tree('getSelectedNode'), false); + + // 2. No node is selected; remove child3 + $tree.tree('loadData', example_data); + + var child3 = $tree.tree('getNodeByName', 'child3'); + $tree.tree('removeNode', child3); + + equal( + formatTitles($tree), + 'node1 child1 child2 node2' + ); + + equal($tree.tree('getSelectedNode'), false); + + // 3. Remove parent of selected node + $tree.tree('loadData', example_data); + + child1 = $tree.tree('getNodeByName', 'child1'); + var node1 = $tree.tree('getNodeByName', 'node1'); + + $tree.tree('selectNode', child1); + + $tree.tree('removeNode', node1); + + // node is unselected + equal($tree.tree('getSelectedNode'), false); + + // 4. Remove unselected node without an id + $tree.tree('loadData', example_data2); + + var c1 = $tree.tree('getNodeByName', 'c1'); + + $tree.tree('removeNode', c1); + + equal( + formatTitles($tree), + 'main c2' + ) +}); + +test('appendNode', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data + }); + + var node1 = $tree.tree('getNodeByName', 'node1'); + + // 1. Add child3 to node1 + $tree.tree('appendNode', 'child3', node1); + + equal( + formatTitles($(node1.element)), + 'node1 child1 child2 child3' + ); + + // 2. Add child4 to child1 + var child1 = $tree.tree('getNodeByName', 'child1'); + + // Node 'child1' does not have a toggler button + equal( + $(child1.element).find('> .jqtree-element > .jqtree-toggler').length, + 0 + ); + + $tree.tree('appendNode', 'child4', child1); + + equal(formatTitles($(child1.element)), 'child1 child4'); + + // Node 'child1' must get a toggler button + equal( + $(child1.element).find('> .jqtree-element > .jqtree-toggler').length, + 1 + ); +}); + +test('prependNode', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data + }); + + var node1 = $tree.tree('getNodeByName', 'node1'); + + // 1. Prepend child0 to node1 + $tree.tree('prependNode', 'child0', node1); + + equal( + formatTitles($(node1.element)), + 'node1 child0 child1 child2' + ); +}); +test('init event', function() { + // setup + var $tree = $('#tree1'); + + $tree.bind('tree.init', function() { + start(); + + // Check that we can call functions in 'tree.init' event + equal($tree.tree('getNodeByName', 'node2').name, 'node2'); + }); + stop(); + + $tree.tree({ + data: example_data + }); +}); + +test('updateNode', function() { + // setup + var $tree = $('#tree1'); + + $tree.tree({ data: example_data }); + + equal(formatTitles($tree), 'node1 child1 child2 node2 child3'); + + // -- update label + var node2 = $tree.tree('getNodeByName', 'node2'); + $tree.tree('updateNode', node2, 'CHANGED'); + + equal(formatTitles($tree), 'node1 child1 child2 CHANGED child3'); + equal(node2.name, 'CHANGED'); + + // -- update data + $tree.tree( + 'updateNode', + node2, + { + name: 'xyz', + tag1: 'abc' + } + ); + + equal(formatTitles($tree), 'node1 child1 child2 xyz child3'); + equal(node2.name, 'xyz'); + equal(node2.tag1, 'abc'); + + // - update id + equal(node2.id, 124); + + $tree.tree('updateNode', node2, {id: 555}); + + equal(node2.id, 555); + equal(node2.name, 'xyz'); + + // get node by id + var node_555 = $tree.tree('getNodeById', 555); + equal(node_555.name, 'xyz'); + + var node_124 = $tree.tree('getNodeById', 124); + equal(node_124, undefined); + + // update child1 + var child1 = $tree.tree('getNodeByName', 'child1'); + + $tree.tree('updateNode', child1, 'child1a'); + + equal(formatTitles($tree), 'node1 child1a child2 xyz child3'); + + // select child1 + $tree.tree('selectNode', child1); + $tree.tree('updateNode', child1, 'child1b'); + + ok($(child1.element).hasClass('jqtree-selected')); +}); + +test('moveNode', function() { + // setup + var $tree = $('#tree1'); + + $tree.tree({ data: example_data }); + + var child1 = $tree.tree('getNodeByName', 'child1'); + var child2 = $tree.tree('getNodeByName', 'child2'); + var node1 = $tree.tree('getNodeByName', 'node1'); + var node2 = $tree.tree('getNodeByName', 'node2'); + + // -- Move child1 after node2 + $tree.tree('moveNode', child1, node2, 'after'); + + equal(formatTitles($tree), 'node1 child2 node2 child3 child1'); + + // -- Check that illegal moves are skipped + $tree.tree('moveNode', node1, child2, 'inside'); +}); + +test('load on demand', function() { + // setup + var $tree = $('#tree1'); + + $tree.tree({ + data: [ + { + id: 1, + label: 'node1', + load_on_demand: true + } + ], + dataUrl: '/tree/' + }); + + $.mockjax({ + url: '*', + response: function(options) { + equal(options.url, '/tree/', '2'); + deepEqual(options.data, { 'node' : 1 }, '3') + + this.responseText = [ + { + id: 2, + label: 'child1' + } + ]; + }, + logging: false + }); + + // -- open node + $tree.bind('tree.refresh', function(e) { + start(); + + equal(formatTitles($tree), 'node1 child1', '4'); + }); + + var node1 = $tree.tree('getNodeByName', 'node1'); + equal(formatTitles($tree), 'node1', '1'); + + $tree.tree('openNode', node1, true); + + stop(); +}); + +test('addNodeAfter', function() { + // setup + var $tree = $('#tree1'); + + $tree.tree({ data: example_data }); + var node1 = $tree.tree('getNodeByName', 'node1'); + + // -- add node after node1 + $tree.tree('addNodeAfter', 'node3', node1); + + equal(formatTitles($tree), 'node1 child1 child2 node3 node2 child3'); +}); + +test('addNodeBefore', function() { + // setup + var $tree = $('#tree1'); + + $tree.tree({ data: example_data }); + var node1 = $tree.tree('getNodeByName', 'node1'); + + // -- add node before node1 + var new_node = $tree.tree('addNodeBefore', 'node3', node1); + + equal(formatTitles($tree), 'node3 node1 child1 child2 node2 child3'); +}); + +test('addParentNode', function() { + // setup + var $tree = $('#tree1'); + + $tree.tree({ data: example_data }); + var child3 = $tree.tree('getNodeByName', 'child3'); + + // -- add parent to child3 + $tree.tree('addParentNode', 'node3', child3); + + equal(formatTitles($tree), 'node1 child1 child2 node2 node3 child3'); +}); + +test('mouse events', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ + data: example_data, + dragAndDrop: true, + autoOpen: true + }); + $tree.tree('setMouseDelay', 0); + + function getTitleElement(node_name) { + var node = $tree.tree('getNodeByName', node_name); + var $el = $(node.element); + return $($el.find('.jqtree-title')); + } + + var $node1 = getTitleElement('node1'); + var $child3 = getTitleElement('child3'); + + // Move node1 inside child3 + // trigger mousedown event on node1 + $node1.trigger( + $.Event('mousedown', { which: 1 }) + ); + + // trigger mouse move to child3 + var child3_offset = $child3.offset(); + $tree.trigger( + $.Event('mousemove', { pageX: child3_offset.left, pageY: child3_offset.top }) + ); + $tree.trigger('mouseup'); + + equal( + formatTitles($tree), + 'node2 child3 node1 child1 child2' + ); +}); + +test('multiple select', function() { + // setup + var $tree = $('#tree1'); + $tree.tree({ data: example_data }); + + var child1 = $tree.tree('getNodeByName', 'child1'); + var child2 = $tree.tree('getNodeByName', 'child2'); + + // -- add nodes to selection + // todo: more nodes as parameters? + // todo: rename to 'selection.add' or 'selection' 'add'? + $tree.tree('addToSelection', child1); + $tree.tree('addToSelection', child2); + + // -- get selected nodes + var selected_nodes = $tree.tree('getSelectedNodes'); + equal( + formatNodes(selected_nodes), + 'child1 child2' + ); +}); + +test('keyboard', function() { + // setup + var $tree = $('#tree1'); + + function keyDown(key) { + $tree.trigger( + $.Event('keydown', { which: key }) + ); + } + + $tree.tree({ data: example_data }); + + var node1 = $tree.tree('getNodeByName', 'node1'); + + // select node1 + $tree.tree('selectNode', node1); + equal(node1.is_open, undefined); + + // - move down; -> node2 + keyDown(40); + equal($tree.tree('getSelectedNode').name, 'node2'); + + // - move up; -> back to node1 + keyDown(38); + equal($tree.tree('getSelectedNode').name, 'node1'); + + // - move right; open node1 + keyDown(39); + equal(node1.is_open, true); + equal($tree.tree('getSelectedNode').name, 'node1'); + + // - select child3 and move up -> node2 + $tree.tree('selectNode', $tree.tree('getNodeByName', 'child3')); + keyDown(38); + equal($tree.tree('getSelectedNode').name, 'node2'); + + // - move up -> child2 + keyDown(38); + equal($tree.tree('getSelectedNode').name, 'child2'); + + // - select node1 and move left -> close + $tree.tree('selectNode', node1); + keyDown(37); + equal(node1.is_open, false); + equal($tree.tree('getSelectedNode').name, 'node1'); +}); + +QUnit.module("Tree"); +test('constructor', function() { + // 1. Create node from string + var node = new Node('n1'); + + equal(node.name, 'n1'); + equal(node.children.length, 0); + equal(node.parent, null); + + // 2. Create node from object + node = new Node({ + label: 'n2', + id: 123, + parent: 'abc', // parent must be ignored + children: ['c'], // children must be ignored + url: '/' + }); + + equal(node.name, 'n2'); + equal(node.id, 123); + equal(node.url, '/'); + equal(node.label, undefined); + equal(node.children.length, 0); + equal(node.parent, null); +}); + +test("create tree from data", function() { + function checkData(tree) { + equal( + formatNodes(tree.children), + 'node1 node2', + 'nodes on level 1' + ); + equal( + formatNodes(tree.children[0].children), + 'child1 child2', + 'children of node1' + ); + equal( + formatNodes(tree.children[1].children), + 'child3', + 'children of node2' + ); + equal( + tree.children[0].id, + 123, + 'id' + ); + } + + // - create tree from example data + var tree = new Node(null, true); + tree.loadFromData(example_data); + checkData(tree); + + // - create tree from new data format + var data = [ + { + label: 'node1', + id: 123, + children: ['child1', 'child2'] // nodes are only defined by a string + }, + { + label: 'node2', + id: 124, + children: ['child3'] + } + ]; + var tree = new Node(null, true); + tree.loadFromData(data); + checkData(tree); +}); + +test("addChild", function() { + var tree = new Node('tree1', true); + tree.addChild( + new Node('abc') + ); + tree.addChild( + new Node('def') + ); + + equal( + formatNodes(tree.children), + 'abc def', + 'children' + ); + + var node = tree.children[0]; + equal( + node.parent.name, + 'tree1', + 'parent of node' + ); +}); + +test('addChildAtPosition', function() { + var tree = new Node(null, true); + tree.addChildAtPosition(new Node('abc'), 0); // first + tree.addChildAtPosition(new Node('ghi'), 2); // index 2 does not exist + tree.addChildAtPosition(new Node('def'), 1); + tree.addChildAtPosition(new Node('123'), 0); + + equal( + formatNodes(tree.children), + '123 abc def ghi', + 'children' + ); +}); + +test('removeChild', function() { + var tree = new Node(null, true); + + var abc = new Node({'label': 'abc', 'id': 1}); + var def = new Node({'label': 'def', 'id': 2}); + var ghi = new Node({'label': 'ghi', 'id': 3}); + + tree.addChild(abc); + tree.addChild(def); + tree.addChild(ghi); + + var jkl = new Node({'label': 'jkl', 'id': 4}); + def.addChild(jkl); + + equal( + formatNodes(tree.children), + 'abc def ghi', + 'children' + ); + + equal(tree.id_mapping[2].name, 'def'); + equal(tree.id_mapping[4].name, 'jkl'); + + // remove 'def' + tree.removeChild(def); + equal( + formatNodes(tree.children), + 'abc ghi', + 'children' + ); + + equal(tree.id_mapping[2], null); + equal(tree.id_mapping[4], null); + + // remove 'ghi' + tree.removeChild(ghi); + equal( + formatNodes(tree.children), + 'abc', + 'children' + ); + + // remove 'abc' + tree.removeChild(abc); + equal( + formatNodes(tree.children), + '', + 'children' + ); +}); + +test('getChildIndex', function() { + // setup + var tree = new Node(null, true); + + var abc = new Node('abc'); + var def = new Node('def'); + var ghi = new Node('ghi'); + tree.addChild(abc); + tree.addChild(def); + tree.addChild(ghi); + + // 1. Get child index of 'def' + equal(tree.getChildIndex(def), 1); + + // 2. Get child index of non-existing node + equal(tree.getChildIndex(new Node('xyz')), -1); +}); + +test('hasChildren', function() { + var tree = new Node(null, true); + equal( + tree.hasChildren(), + false, + 'tree without children' + ); + + tree.addChild(new Node('abc')); + equal( + tree.hasChildren(), + true, + 'tree has children' + ); +}); + +test('iterate', function() { + var tree = new Node(null, true); + tree.loadFromData(example_data); + + // iterate over all the nodes + var nodes = []; + tree.iterate( + function(node, level) { + nodes.push(node); + return true; + } + ); + + equal( + formatNodes(nodes), + 'node1 child1 child2 node2 child3', + 'all nodes' + ); + + // iterate over nodes on first level + nodes = []; + tree.iterate( + function(node, level) { + nodes.push(node); + return false; + } + ); + + equal( + formatNodes(nodes), + 'node1 node2', + 'nodes on first level' + ); + + // add child 4 + var node3 = tree.getNodeById(124).children[0]; + node3.addChild( + new Node('child4') + ); + + // test level parameter + nodes = []; + tree.iterate( + function(node, level) { + nodes.push(node.name + ' ' + level); + return true; + } + ); + + equal( + nodes.join(','), + 'node1 0,child1 1,child2 1,node2 0,child3 1,child4 2' + ); +}); + +test('moveNode', function() { + var tree = new Node(null, true); + tree.loadFromData(example_data); + + /* + node1 + ---child1 + ---child2 + node2 + ---child3 + */ + + var node1 = tree.children[0]; + var node2 = tree.children[1]; + var child1 = node1.children[0]; + var child2 = node1.children[1]; + equal(node2.name, 'node2', 'node2 name'); + equal(child2.name, 'child2', 'child2 name'); + + // move child2 after node2 + tree.moveNode(child2, node2, Position.AFTER); + + /* + node1 + ---child1 + node2 + ---child3 + child2 + */ + equal( + formatNodes(tree.children), + 'node1 node2 child2', + 'tree nodes at first level' + ); + equal( + formatNodes(node1.children), + 'child1', + 'node1 children' + ); + + // move child1 inside node2 + // this means it's the first child + tree.moveNode(child1, node2, Position.INSIDE); + + /* + node1 + node2 + ---child1 + ---child3 + child2 + */ + equal( + formatNodes(node2.children), + 'child1 child3', + 'node2 children' + ); + equal( + formatNodes(node1.children), + '', + 'node1 has no children' + ); + + // move child2 before child1 + tree.moveNode(child2, child1, Position.BEFORE); + + /* + node1 + node2 + ---child2 + ---child1 + ---child3 + */ + equal( + formatNodes(node2.children), + 'child2 child1 child3', + 'node2 children' + ); + equal( + formatNodes(tree.children), + 'node1 node2', + 'tree nodes at first level' + ); +}); + +test('initFromData', function() { + var data = + { + label: 'main', + children: [ + 'c1', + { + label: 'c2', + id: 201 + } + ] + }; + var node = new Node(null, true); + node.initFromData(data); + + equal(node.name, 'main') + equal( + formatNodes(node.children), + 'c1 c2', + 'children' + ); + equal(node.children[1].id, 201); +}); + +test('getData', function() { + // 1. empty node + var node = new Node(null, true); + deepEqual(node.getData(), []); + + // 2.node with data + node.loadFromData( + [ + { + label: 'n1', + children: [ + { + label: 'c1' + } + ] + } + ] + ); + deepEqual( + node.getData(), + [ + { + name: 'n1', + children: [ + { + name: 'c1' + } + ] + } + ] + ); +}); + +test('addAfter', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + /* + -node1 + ---c1 + ---c2 + -node2 + ---c3 + */ + + equal(formatNodes(tree.children), 'node1 node2'); + + // - Add 'node_b' after node2 + var node2 = tree.getNodeByName('node2'); + node2.addAfter('node_b'); + + equal(formatNodes(tree.children), 'node1 node2 node_b'); + + var node_b = tree.getNodeByName('node_b'); + equal(node_b.name, 'node_b'); + + // - Add 'node_a' after node1 + var node1 = tree.getNodeByName('node1'); + node1.addAfter('node_a'); + + equal(formatNodes(tree.children), 'node1 node_a node2 node_b'); + + // - Add 'node_c' after node_b; new node is an object + node_b.addAfter({ + label: 'node_c', + id: 789 + }); + + var node_c = tree.getNodeByName('node_c'); + equal(node_c.id, 789); + + equal(formatNodes(tree.children), 'node1 node_a node2 node_b node_c'); + + // - Add after root node; this is not possible + equal(tree.addAfter('node_x'), null); +}); + +test('addBefore', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + // - Add 'node_0' before node1 + var node1 = tree.getNodeByName('node1'); + node1.addBefore('node0'); + equal(formatNodes(tree.children), 'node0 node1 node2'); + + // - Add before root node; this is not possile + equal(tree.addBefore('x'), null); +}); + +test('addParent', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + // - Add node 'root' as parent of node1 + // Note that node also becomes a child of 'root' + var node1 = tree.getNodeByName('node1'); + node1.addParent('root'); + + var root = tree.getNodeByName('root'); + equal(formatNodes(root.children), 'node1 node2'); + + // - Add parent to root node; not possible + equal(tree.addParent('x'), null); +}); + +test('remove', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + var child1 = tree.getNodeByName('child1'); + var node1 = tree.getNodeByName('node1'); + + equal(formatNodes(node1.children), 'child1 child2'); + equal(child1.parent, node1); + + // 1. Remove child1 + child1.remove(); + + equal(formatNodes(node1.children), 'child2'); + equal(child1.parent, null); +}); + +test('append', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + var node1 = tree.getNodeByName('node1'); + + // 1. Add child3 to node1 + node1.append('child3'); + + equal(formatNodes(node1.children), 'child1 child2 child3'); +}); + +test('prepend', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + var node1 = tree.getNodeByName('node1'); + + // 1. Prepend child0 to node1 + node1.prepend('child0'); + + equal(formatNodes(node1.children), 'child0 child1 child2'); +}); + +test('getNodeById', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + // 1. Get node with id 124 + var node = tree.getNodeById(124); + equal(node.name, 'node2'); + + // 2. Delete node with id 124 and search again + node.remove(); + + equal(tree.getNodeById(124), null); + + // 3. Add node with id 456 and search for it + var child3 = tree.getNodeByName('child2'); + child3.append({ + id: 456, + label: 'new node' + }); + + node = tree.getNodeById(456); + equal(node.name, 'new node'); +}); + +test('getLevel', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + // 1. get level for node1 and child1 + equal(tree.getNodeByName('node1').getLevel(), 1); + equal(tree.getNodeByName('child1').getLevel(), 2); +}); + +test('loadFromData and id mapping', function() { + // - get node from empty tree + var tree = new Node(null, true); + equal(tree.getNodeById(999), null); + + // - load example data in tree + tree.loadFromData(example_data); + equal(tree.getNodeById(124).name, 'node2'); + + var child2 = tree.getNodeById(126); + child2.addChild( + new Node({label: 'child4', id: 128}) + ); + child2.addChild( + new Node({label: 'child5', id: 129}) + ); + + // - load data in node child2 + child2.loadFromData(['abc', 'def']); + + equal(tree.getNodeById(128), null); + equal(child2.children.length, 2); + equal(child2.children[0].name, 'abc'); +}); + +test('removeChildren', function() { + // - load example data + var tree = new Node(null, true); + tree.loadFromData(example_data); + + // add child4 and child5 + var child2 = tree.getNodeById(126); + equal(child2.name, 'child2'); + + child2.addChild( + new Node({label: 'child4', id: 128}) + ); + child2.addChild( + new Node({label: 'child5', id: 129}) + ); + equal(tree.getNodeById(128).name, 'child4'); + + // - remove children from child2 + child2.removeChildren(); + equal(tree.getNodeById(128), null); + equal(child2.children.length, 0); +}); + +test('node with id 0', function() { + // - load node with id 0 + var tree = new Node(null, true); + tree.loadFromData([ + { + id: 0, + label: 'mynode' + } + ]); + + // - get node by id + var node = tree.getNodeById(0); + equal(node.name, 'mynode'); + + // -- remove the node + node.remove(); + + equal(tree.getNodeById(0), undefined); +}); + +test('getPreviousSibling', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + // - getPreviousSibling + equal( + tree.getNodeByName('child2').getPreviousSibling().name, + 'child1' + ); + equal(tree.getPreviousSibling(), null); + equal( + tree.getNodeByName('child1').getPreviousSibling(), + null + ); +}); + +test('getNextSibling', function() { + // setup + var tree = new Node(null, true); + tree.loadFromData(example_data); + + // - getNextSibling + equal( + tree.getNodeByName('node1').getNextSibling().name, + 'node2' + ); + equal( + tree.getNodeByName('node2').getNextSibling(), + null + ); + equal(tree.getNextSibling(), null); +}); + +test('getNodesByProperty', function() { + var tree = new Node(null, true); + tree.loadFromData(example_data); + + nodes = tree.getNodesByProperty('name', 'child1'); + + equal(nodes.length, 1); + equal(nodes[0].name, 'child1'); +}); + + +QUnit.module('util'); + +test('JSON.stringify', function() { + function test_stringify(stringify) { + equal(stringify('abc'), '"abc"'); + equal(stringify(123), '123'); + equal(stringify(true), 'true'); + equal(stringify({abc: 'def'}), '{"abc":"def"}'); + equal(stringify({}), '{}'); + equal(stringify([1, 2, 3]), '[1,2,3]'); + equal(stringify(null), 'null'); + equal(stringify(Number.NEGATIVE_INFINITY), 'null'); + + // test escapable + JSON.stringify("\u200c"); + } + + test_stringify(JSON.stringify); + test_stringify(get_json_stringify_function()); +}); + +test('indexOf', function() { + equal(indexOf([3, 2, 1], 1), 2); + equal(_indexOf([3, 2, 1], 1), 2); + equal(indexOf([4, 5, 6], 1), -1); + equal(_indexOf([4, 5, 6], 1), -1); +}); + +test('Position.getName', function() { + equal(Position.getName(Position.BEFORE), 'before'); + equal(Position.getName(Position.AFTER), 'after'); + equal(Position.getName(Position.INSIDE), 'inside'); + equal(Position.getName(Position.NONE), 'none'); +}); + +test('Position.nameToIndex', function() { + equal(Position.nameToIndex('before'), Position.BEFORE); + equal(Position.nameToIndex('after'), Position.AFTER); + equal(Position.nameToIndex(''), 0); +}); diff --git a/src/tree.jquery.coffee b/src/tree.jquery.coffee index c623ff99..b7b48ee5 100644 --- a/src/tree.jquery.coffee +++ b/src/tree.jquery.coffee @@ -1,5 +1,4 @@ - -### +### Copyright 2013 Marco Braak Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +14,25 @@ See the License for the specific language governing permissions and limitations under the License. ### +__version__ = require './version' +DragAndDropHandler = require './drag_and_drop_handler' +ElementsRenderer = require './elements_renderer' +KeyHandler = require './key_handler' +MouseWidget = require './mouse.widget' +SaveStateHandler = require './save_state_handler' +ScrollHandler = require './scroll_handler' +SelectNodeHandler = require './select_node_handler' +SimpleWidget = require './simple.widget' + +node = require './node' +Node = node.Node +Position = node.Position + +node_element = require './node_element' +NodeElement = node_element.NodeElement +FolderElement = node_element.FolderElement + + class JqTreeWidget extends MouseWidget defaults: autoOpen: false # true / false / int (open n levels starting at 0) @@ -102,7 +120,10 @@ class JqTreeWidget extends MouseWidget saveState() getSelectedNode: -> - return @select_node_handler.getSelectedNode() + if @select_node_handler + return @select_node_handler.getSelectedNode() + else + return null toJson: -> return JSON.stringify( @@ -205,9 +226,10 @@ class JqTreeWidget extends MouseWidget @_initTree(data) else # Node is loaded; unselect all nodes under this node. - selected_nodes_under_parent = @select_node_handler.getSelectedNodesUnder(parent_node) - for n in selected_nodes_under_parent - @select_node_handler.removeFromSelection(n) + if @select_node_handler + selected_nodes_under_parent = @select_node_handler.getSelectedNodesUnder(parent_node) + for n in selected_nodes_under_parent + @select_node_handler.removeFromSelection(n) parent_node.loadFromData(data) parent_node.load_on_demand = false @@ -424,7 +446,10 @@ class JqTreeWidget extends MouseWidget _deinit: -> @element.empty() @element.unbind() - @key_handler.deinit() + + if @key_handler + @key_handler.deinit() + @tree = null super() @@ -652,100 +677,3 @@ class JqTreeWidget extends MouseWidget @removeFromSelection(node) SimpleWidget.register(JqTreeWidget, 'tree') - - -class NodeElement - constructor: (node, tree_widget) -> - @init(node, tree_widget) - - init: (node, tree_widget) -> - @node = node - @tree_widget = tree_widget - - if not node.element - node.element = @tree_widget.element - - @$element = $(node.element) - - getUl: -> - return @$element.children('ul:first') - - getSpan: -> - return @$element.children('.jqtree-element').find('span.jqtree-title') - - getLi: -> - return @$element - - addDropHint: (position) -> - if position == Position.INSIDE - return new BorderDropHint(@$element) - else - return new GhostDropHint(@node, @$element, position) - - select: -> - @getLi().addClass('jqtree-selected') - - deselect: -> - @getLi().removeClass('jqtree-selected') - - -class FolderElement extends NodeElement - open: (on_finished, slide=true) -> - if not @node.is_open - @node.is_open = true - $button = @getButton() - $button.removeClass('jqtree-closed') - $button.html('') - $button.append(@tree_widget.renderer.opened_icon_element.cloneNode()) - - doOpen = => - @getLi().removeClass('jqtree-closed') - if on_finished - on_finished() - - @tree_widget._triggerEvent('tree.open', node: @node) - - if slide - @getUl().slideDown('fast', doOpen) - else - @getUl().show() - doOpen() - - close: (slide=true) -> - if @node.is_open - @node.is_open = false - $button = @getButton() - $button.addClass('jqtree-closed') - $button.html('') - $button.append(@tree_widget.renderer.closed_icon_element.cloneNode()) - - doClose = => - @getLi().addClass('jqtree-closed') - - @tree_widget._triggerEvent('tree.close', node: @node) - - if slide - @getUl().slideUp('fast', doClose) - else - @getUl().hide() - doClose() - - getButton: -> - return @$element.children('.jqtree-element').find('a.jqtree-toggler') - - addDropHint: (position) -> - if not @node.is_open and position == Position.INSIDE - return new BorderDropHint(@$element) - else - return new GhostDropHint(@node, @$element, position) - - -# Escape a string for HTML interpolation; copied from underscore js -html_escape = (string) -> - return (''+string) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(/\//g,'/') \ No newline at end of file diff --git a/src/util.coffee b/src/util.coffee new file mode 100644 index 00000000..0ee9aa89 --- /dev/null +++ b/src/util.coffee @@ -0,0 +1,117 @@ +# Standard javascript indexOf. Implemented here because not all browsers support it. +_indexOf = (array, item) -> + for value, i in array + if value == item + return i + return -1 + +indexOf = (array, item) -> + if array.indexOf + # The browser supports indexOf + return array.indexOf(item) + else + # Do our own indexOf + return _indexOf(array, item) + +isInt = (n) -> + return typeof n is 'number' and n % 1 == 0 + + +# JSON.stringify function; copied from json2 +get_json_stringify_function = -> + json_escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g + json_meta = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + } + + json_quote = (string) -> + json_escapable.lastIndex = 0 + + if json_escapable.test(string) + return '"' + string.replace(json_escapable, (a) -> + c = json_meta[a] + return ( + if typeof c is 'string' then c + else '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4) + ) + ) + '"' + else + return '"' + string + '"' + + json_str = (key, holder) -> + value = holder[key] + + switch typeof value + when 'string' + return json_quote(value) + + when 'number' + return if isFinite(value) then String(value) else 'null' + + when 'boolean', 'null' + return String(value) + + when 'object' + if not value + return 'null' + + partial = [] + if Object::toString.apply(value) is '[object Array]' + for v, i in value + partial[i] = json_str(i, value) or 'null' + + return ( + if partial.length is 0 then '[]' + else '[' + partial.join(',') + ']' + ) + + for k of value + if Object::hasOwnProperty.call(value, k) + v = json_str(k, value) + if v + partial.push(json_quote(k) + ':' + v) + + return ( + if partial.length is 0 then '{}' + else '{' + partial.join(',') + '}' + ) + + stringify = (value) -> + return json_str( + '', + {'': value} + ) + + return stringify + + +if not (@JSON? and @JSON.stringify? and typeof @JSON.stringify == 'function') + if not @JSON? + @JSON = {} + + @JSON.stringify = get_json_stringify_function() + + +# Escape a string for HTML interpolation; copied from underscore js +html_escape = (string) -> + return (''+string) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(/\//g,'/') + + +module.exports = + _indexOf:_indexOf + get_json_stringify_function: get_json_stringify_function + html_escape: html_escape + indexOf: indexOf + isInt: isInt diff --git a/src/version.coffee b/src/version.coffee index 81edede8..3090b4c4 100644 --- a/src/version.coffee +++ b/src/version.coffee @@ -1 +1 @@ -__version__ = '0.22.0' +module.exports = '0.22.0' diff --git a/test/test.js b/test/test.js index 26ac9cbb..7fec1cc4 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,12 @@ -$(function() { +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o'); }, @@ -244,7 +252,7 @@ test('saveState', function() { equal( $tree.tree('getSelectedNode').name, 'node2', - 'getSelectedNode' + 'getSelectedNode (1)' ); // create tree again @@ -259,7 +267,7 @@ test('saveState', function() { equal( $tree.tree('getSelectedNode').name, 'node2', - 'getSelectedNode' + 'getSelectedNode (2)' ); }); @@ -754,7 +762,7 @@ test('generate hit areas', function() { var hit_areas = $tree.tree('testGenerateHitAreas', node); var strings = $.map(hit_areas, function(hit_area) { - return hit_area.node.name + ' ' + Tree.Position.getName(hit_area.position); + return hit_area.node.name + ' ' + Position.getName(hit_area.position); }); equal(strings.join(';'), 'node1 none;node2 inside;node2 after'); }); @@ -1163,17 +1171,17 @@ test('keyboard', function() { equal($tree.tree('getSelectedNode').name, 'node1'); }); -module("Tree"); +QUnit.module("Tree"); test('constructor', function() { // 1. Create node from string - var node = new Tree.Node('n1'); + var node = new Node('n1'); equal(node.name, 'n1'); equal(node.children.length, 0); equal(node.parent, null); // 2. Create node from object - node = new Tree.Node({ + node = new Node({ label: 'n2', id: 123, parent: 'abc', // parent must be ignored @@ -1214,7 +1222,7 @@ test("create tree from data", function() { } // - create tree from example data - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); checkData(tree); @@ -1231,18 +1239,18 @@ test("create tree from data", function() { children: ['child3'] } ]; - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(data); checkData(tree); }); test("addChild", function() { - var tree = new Tree.Node('tree1', true); + var tree = new Node('tree1', true); tree.addChild( - new Tree.Node('abc') + new Node('abc') ); tree.addChild( - new Tree.Node('def') + new Node('def') ); equal( @@ -1260,11 +1268,11 @@ test("addChild", function() { }); test('addChildAtPosition', function() { - var tree = new Tree.Node(null, true); - tree.addChildAtPosition(new Tree.Node('abc'), 0); // first - tree.addChildAtPosition(new Tree.Node('ghi'), 2); // index 2 does not exist - tree.addChildAtPosition(new Tree.Node('def'), 1); - tree.addChildAtPosition(new Tree.Node('123'), 0); + var tree = new Node(null, true); + tree.addChildAtPosition(new Node('abc'), 0); // first + tree.addChildAtPosition(new Node('ghi'), 2); // index 2 does not exist + tree.addChildAtPosition(new Node('def'), 1); + tree.addChildAtPosition(new Node('123'), 0); equal( formatNodes(tree.children), @@ -1274,17 +1282,17 @@ test('addChildAtPosition', function() { }); test('removeChild', function() { - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); - var abc = new Tree.Node({'label': 'abc', 'id': 1}); - var def = new Tree.Node({'label': 'def', 'id': 2}); - var ghi = new Tree.Node({'label': 'ghi', 'id': 3}); + var abc = new Node({'label': 'abc', 'id': 1}); + var def = new Node({'label': 'def', 'id': 2}); + var ghi = new Node({'label': 'ghi', 'id': 3}); tree.addChild(abc); tree.addChild(def); tree.addChild(ghi); - var jkl = new Tree.Node({'label': 'jkl', 'id': 4}); + var jkl = new Node({'label': 'jkl', 'id': 4}); def.addChild(jkl); equal( @@ -1326,11 +1334,11 @@ test('removeChild', function() { test('getChildIndex', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); - var abc = new Tree.Node('abc'); - var def = new Tree.Node('def'); - var ghi = new Tree.Node('ghi'); + var abc = new Node('abc'); + var def = new Node('def'); + var ghi = new Node('ghi'); tree.addChild(abc); tree.addChild(def); tree.addChild(ghi); @@ -1339,18 +1347,18 @@ test('getChildIndex', function() { equal(tree.getChildIndex(def), 1); // 2. Get child index of non-existing node - equal(tree.getChildIndex(new Tree.Node('xyz')), -1); + equal(tree.getChildIndex(new Node('xyz')), -1); }); test('hasChildren', function() { - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); equal( tree.hasChildren(), false, 'tree without children' ); - tree.addChild(new Tree.Node('abc')); + tree.addChild(new Node('abc')); equal( tree.hasChildren(), true, @@ -1359,7 +1367,7 @@ test('hasChildren', function() { }); test('iterate', function() { - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); // iterate over all the nodes @@ -1395,7 +1403,7 @@ test('iterate', function() { // add child 4 var node3 = tree.getNodeById(124).children[0]; node3.addChild( - new Tree.Node('child4') + new Node('child4') ); // test level parameter @@ -1414,7 +1422,7 @@ test('iterate', function() { }); test('moveNode', function() { - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); /* @@ -1433,7 +1441,7 @@ test('moveNode', function() { equal(child2.name, 'child2', 'child2 name'); // move child2 after node2 - tree.moveNode(child2, node2, Tree.Position.AFTER); + tree.moveNode(child2, node2, Position.AFTER); /* node1 @@ -1455,7 +1463,7 @@ test('moveNode', function() { // move child1 inside node2 // this means it's the first child - tree.moveNode(child1, node2, Tree.Position.INSIDE); + tree.moveNode(child1, node2, Position.INSIDE); /* node1 @@ -1476,7 +1484,7 @@ test('moveNode', function() { ); // move child2 before child1 - tree.moveNode(child2, child1, Tree.Position.BEFORE); + tree.moveNode(child2, child1, Position.BEFORE); /* node1 @@ -1509,7 +1517,7 @@ test('initFromData', function() { } ] }; - var node = new Tree.Node(null, true); + var node = new Node(null, true); node.initFromData(data); equal(node.name, 'main') @@ -1523,7 +1531,7 @@ test('initFromData', function() { test('getData', function() { // 1. empty node - var node = new Tree.Node(null, true); + var node = new Node(null, true); deepEqual(node.getData(), []); // 2.node with data @@ -1556,7 +1564,7 @@ test('getData', function() { test('addAfter', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); /* @@ -1601,7 +1609,7 @@ test('addAfter', function() { test('addBefore', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); // - Add 'node_0' before node1 @@ -1615,7 +1623,7 @@ test('addBefore', function() { test('addParent', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); // - Add node 'root' as parent of node1 @@ -1632,7 +1640,7 @@ test('addParent', function() { test('remove', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); var child1 = tree.getNodeByName('child1'); @@ -1650,7 +1658,7 @@ test('remove', function() { test('append', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); var node1 = tree.getNodeByName('node1'); @@ -1663,7 +1671,7 @@ test('append', function() { test('prepend', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); var node1 = tree.getNodeByName('node1'); @@ -1676,7 +1684,7 @@ test('prepend', function() { test('getNodeById', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); // 1. Get node with id 124 @@ -1701,7 +1709,7 @@ test('getNodeById', function() { test('getLevel', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); // 1. get level for node1 and child1 @@ -1711,7 +1719,7 @@ test('getLevel', function() { test('loadFromData and id mapping', function() { // - get node from empty tree - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); equal(tree.getNodeById(999), null); // - load example data in tree @@ -1720,10 +1728,10 @@ test('loadFromData and id mapping', function() { var child2 = tree.getNodeById(126); child2.addChild( - new Tree.Node({label: 'child4', id: 128}) + new Node({label: 'child4', id: 128}) ); child2.addChild( - new Tree.Node({label: 'child5', id: 129}) + new Node({label: 'child5', id: 129}) ); // - load data in node child2 @@ -1736,7 +1744,7 @@ test('loadFromData and id mapping', function() { test('removeChildren', function() { // - load example data - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); // add child4 and child5 @@ -1744,10 +1752,10 @@ test('removeChildren', function() { equal(child2.name, 'child2'); child2.addChild( - new Tree.Node({label: 'child4', id: 128}) + new Node({label: 'child4', id: 128}) ); child2.addChild( - new Tree.Node({label: 'child5', id: 129}) + new Node({label: 'child5', id: 129}) ); equal(tree.getNodeById(128).name, 'child4'); @@ -1759,7 +1767,7 @@ test('removeChildren', function() { test('node with id 0', function() { // - load node with id 0 - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData([ { id: 0, @@ -1779,7 +1787,7 @@ test('node with id 0', function() { test('getPreviousSibling', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); // - getPreviousSibling @@ -1796,7 +1804,7 @@ test('getPreviousSibling', function() { test('getNextSibling', function() { // setup - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); // - getNextSibling @@ -1812,7 +1820,7 @@ test('getNextSibling', function() { }); test('getNodesByProperty', function() { - var tree = new Tree.Node(null, true); + var tree = new Node(null, true); tree.loadFromData(example_data); nodes = tree.getNodesByProperty('name', 'child1'); @@ -1822,7 +1830,7 @@ test('getNodesByProperty', function() { }); -module('util'); +QUnit.module('util'); test('JSON.stringify', function() { function test_stringify(stringify) { @@ -1840,27 +1848,628 @@ test('JSON.stringify', function() { } test_stringify(JSON.stringify); - test_stringify(Tree.get_json_stringify_function()); + test_stringify(get_json_stringify_function()); }); test('indexOf', function() { - equal(Tree.indexOf([3, 2, 1], 1), 2); - equal(Tree._indexOf([3, 2, 1], 1), 2); - equal(Tree.indexOf([4, 5, 6], 1), -1); - equal(Tree._indexOf([4, 5, 6], 1), -1); + equal(indexOf([3, 2, 1], 1), 2); + equal(_indexOf([3, 2, 1], 1), 2); + equal(indexOf([4, 5, 6], 1), -1); + equal(_indexOf([4, 5, 6], 1), -1); }); test('Position.getName', function() { - equal(Tree.Position.getName(Tree.Position.BEFORE), 'before'); - equal(Tree.Position.getName(Tree.Position.AFTER), 'after'); - equal(Tree.Position.getName(Tree.Position.INSIDE), 'inside'); - equal(Tree.Position.getName(Tree.Position.NONE), 'none'); + equal(Position.getName(Position.BEFORE), 'before'); + equal(Position.getName(Position.AFTER), 'after'); + equal(Position.getName(Position.INSIDE), 'inside'); + equal(Position.getName(Position.NONE), 'none'); }); test('Position.nameToIndex', function() { - equal(Tree.Position.nameToIndex('before'), Tree.Position.BEFORE); - equal(Tree.Position.nameToIndex('after'), Tree.Position.AFTER); - equal(Tree.Position.nameToIndex(''), 0); + equal(Position.nameToIndex('before'), Position.BEFORE); + equal(Position.nameToIndex('after'), Position.AFTER); + equal(Position.nameToIndex(''), 0); }); -}); +},{"./node":2,"./util":3}],2:[function(require,module,exports){ +(function() { + var Node, Position; + + Position = { + getName: function(position) { + return Position.strings[position - 1]; + }, + nameToIndex: function(name) { + var i, _i, _ref; + for (i = _i = 1, _ref = Position.strings.length; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) { + if (Position.strings[i - 1] === name) { + return i; + } + } + return 0; + } + }; + + Position.BEFORE = 1; + + Position.AFTER = 2; + + Position.INSIDE = 3; + + Position.NONE = 4; + + Position.strings = ['before', 'after', 'inside', 'none']; + + Node = (function() { + function Node(o, is_root, node_class) { + if (is_root == null) { + is_root = false; + } + if (node_class == null) { + node_class = Node; + } + this.setData(o); + this.children = []; + this.parent = null; + if (is_root) { + this.id_mapping = {}; + this.tree = this; + this.node_class = node_class; + } + } + + Node.prototype.setData = function(o) { + var key, value, _results; + if (typeof o !== 'object') { + return this.name = o; + } else { + _results = []; + for (key in o) { + value = o[key]; + if (key === 'label') { + _results.push(this.name = value); + } else { + _results.push(this[key] = value); + } + } + return _results; + } + }; + + Node.prototype.initFromData = function(data) { + var addChildren, addNode; + addNode = (function(_this) { + return function(node_data) { + _this.setData(node_data); + if (node_data.children) { + return addChildren(node_data.children); + } + }; + })(this); + addChildren = (function(_this) { + return function(children_data) { + var child, node, _i, _len; + for (_i = 0, _len = children_data.length; _i < _len; _i++) { + child = children_data[_i]; + node = new _this.tree.node_class(''); + node.initFromData(child); + _this.addChild(node); + } + return null; + }; + })(this); + addNode(data); + return null; + }; + + + /* + Create tree from data. + + Structure of data is: + [ + { + label: 'node1', + children: [ + { label: 'child1' }, + { label: 'child2' } + ] + }, + { + label: 'node2' + } + ] + */ + + Node.prototype.loadFromData = function(data) { + var node, o, _i, _len; + this.removeChildren(); + for (_i = 0, _len = data.length; _i < _len; _i++) { + o = data[_i]; + node = new this.tree.node_class(o); + this.addChild(node); + if (typeof o === 'object' && o.children) { + node.loadFromData(o.children); + } + } + return null; + }; + + + /* + Add child. + + tree.addChild( + new Node('child1') + ); + */ + + Node.prototype.addChild = function(node) { + this.children.push(node); + return node._setParent(this); + }; + + + /* + Add child at position. Index starts at 0. + + tree.addChildAtPosition( + new Node('abc'), + 1 + ); + */ + + Node.prototype.addChildAtPosition = function(node, index) { + this.children.splice(index, 0, node); + return node._setParent(this); + }; + + Node.prototype._setParent = function(parent) { + this.parent = parent; + this.tree = parent.tree; + return this.tree.addNodeToIndex(this); + }; + + + /* + Remove child. This also removes the children of the node. + + tree.removeChild(tree.children[0]); + */ + + Node.prototype.removeChild = function(node) { + node.removeChildren(); + return this._removeChild(node); + }; + + Node.prototype._removeChild = function(node) { + this.children.splice(this.getChildIndex(node), 1); + return this.tree.removeNodeFromIndex(node); + }; + + + /* + Get child index. + + var index = getChildIndex(node); + */ + + Node.prototype.getChildIndex = function(node) { + return $.inArray(node, this.children); + }; + + + /* + Does the tree have children? + + if (tree.hasChildren()) { + // + } + */ + + Node.prototype.hasChildren = function() { + return this.children.length !== 0; + }; + + Node.prototype.isFolder = function() { + return this.hasChildren() || this.load_on_demand; + }; + + + /* + Iterate over all the nodes in the tree. + + Calls callback with (node, level). + + The callback must return true to continue the iteration on current node. + + tree.iterate( + function(node, level) { + console.log(node.name); + + // stop iteration after level 2 + return (level <= 2); + } + ); + */ + + Node.prototype.iterate = function(callback) { + var _iterate; + _iterate = (function(_this) { + return function(node, level) { + var child, result, _i, _len, _ref; + if (node.children) { + _ref = node.children; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + result = callback(child, level); + if (_this.hasChildren() && result) { + _iterate(child, level + 1); + } + } + return null; + } + }; + })(this); + _iterate(this, 0); + return null; + }; + + + /* + Move node relative to another node. + + Argument position: Position.BEFORE, Position.AFTER or Position.Inside + + // move node1 after node2 + tree.moveNode(node1, node2, Position.AFTER); + */ + + Node.prototype.moveNode = function(moved_node, target_node, position) { + if (moved_node.isParentOf(target_node)) { + return; + } + moved_node.parent._removeChild(moved_node); + if (position === Position.AFTER) { + return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node) + 1); + } else if (position === Position.BEFORE) { + return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node)); + } else if (position === Position.INSIDE) { + return target_node.addChildAtPosition(moved_node, 0); + } + }; + + + /* + Get the tree as data. + */ + + Node.prototype.getData = function() { + var getDataFromNodes; + getDataFromNodes = (function(_this) { + return function(nodes) { + var data, k, node, tmp_node, v, _i, _len; + data = []; + for (_i = 0, _len = nodes.length; _i < _len; _i++) { + node = nodes[_i]; + tmp_node = {}; + for (k in node) { + v = node[k]; + if ((k !== 'parent' && k !== 'children' && k !== 'element' && k !== 'tree') && Object.prototype.hasOwnProperty.call(node, k)) { + tmp_node[k] = v; + } + } + if (node.hasChildren()) { + tmp_node.children = getDataFromNodes(node.children); + } + data.push(tmp_node); + } + return data; + }; + })(this); + return getDataFromNodes(this.children); + }; + + Node.prototype.getNodeByName = function(name) { + var result; + result = null; + this.iterate(function(node) { + if (node.name === name) { + result = node; + return false; + } else { + return true; + } + }); + return result; + }; + + Node.prototype.addAfter = function(node_info) { + var child_index, node; + if (!this.parent) { + return null; + } else { + node = new this.tree.node_class(node_info); + child_index = this.parent.getChildIndex(this); + this.parent.addChildAtPosition(node, child_index + 1); + return node; + } + }; + + Node.prototype.addBefore = function(node_info) { + var child_index, node; + if (!this.parent) { + return null; + } else { + node = new this.tree.node_class(node_info); + child_index = this.parent.getChildIndex(this); + this.parent.addChildAtPosition(node, child_index); + return node; + } + }; + + Node.prototype.addParent = function(node_info) { + var child, new_parent, original_parent, _i, _len, _ref; + if (!this.parent) { + return null; + } else { + new_parent = new this.tree.node_class(node_info); + new_parent._setParent(this.tree); + original_parent = this.parent; + _ref = original_parent.children; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + new_parent.addChild(child); + } + original_parent.children = []; + original_parent.addChild(new_parent); + return new_parent; + } + }; + + Node.prototype.remove = function() { + if (this.parent) { + this.parent.removeChild(this); + return this.parent = null; + } + }; + + Node.prototype.append = function(node_info) { + var node; + node = new this.tree.node_class(node_info); + this.addChild(node); + return node; + }; + + Node.prototype.prepend = function(node_info) { + var node; + node = new this.tree.node_class(node_info); + this.addChildAtPosition(node, 0); + return node; + }; + + Node.prototype.isParentOf = function(node) { + var parent; + parent = node.parent; + while (parent) { + if (parent === this) { + return true; + } + parent = parent.parent; + } + return false; + }; + + Node.prototype.getLevel = function() { + var level, node; + level = 0; + node = this; + while (node.parent) { + level += 1; + node = node.parent; + } + return level; + }; + + Node.prototype.getNodeById = function(node_id) { + return this.id_mapping[node_id]; + }; + + Node.prototype.addNodeToIndex = function(node) { + if (node.id != null) { + return this.id_mapping[node.id] = node; + } + }; + + Node.prototype.removeNodeFromIndex = function(node) { + if (node.id != null) { + return delete this.id_mapping[node.id]; + } + }; + + Node.prototype.removeChildren = function() { + this.iterate((function(_this) { + return function(child) { + _this.tree.removeNodeFromIndex(child); + return true; + }; + })(this)); + return this.children = []; + }; + + Node.prototype.getPreviousSibling = function() { + var previous_index; + if (!this.parent) { + return null; + } else { + previous_index = this.parent.getChildIndex(this) - 1; + if (previous_index >= 0) { + return this.parent.children[previous_index]; + } else { + return null; + } + } + }; + + Node.prototype.getNextSibling = function() { + var next_index; + if (!this.parent) { + return null; + } else { + next_index = this.parent.getChildIndex(this) + 1; + if (next_index < this.parent.children.length) { + return this.parent.children[next_index]; + } else { + return null; + } + } + }; + + Node.prototype.getNodesByProperty = function(key, value) { + return this.filter(function(node) { + return node[key] === value; + }); + }; + + Node.prototype.filter = function(f) { + var result; + result = []; + this.iterate(function(node) { + if (f(node)) { + result.push(node); + } + return true; + }); + return result; + }; + + return Node; + + })(); + + module.exports = { + Node: Node, + Position: Position + }; + +}).call(this); + +},{}],3:[function(require,module,exports){ +(function() { + var get_json_stringify_function, html_escape, indexOf, isInt, _indexOf; + + _indexOf = function(array, item) { + var i, value, _i, _len; + for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) { + value = array[i]; + if (value === item) { + return i; + } + } + return -1; + }; + + indexOf = function(array, item) { + if (array.indexOf) { + return array.indexOf(item); + } else { + return _indexOf(array, item); + } + }; + + isInt = function(n) { + return typeof n === 'number' && n % 1 === 0; + }; + + get_json_stringify_function = function() { + var json_escapable, json_meta, json_quote, json_str, stringify; + json_escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + json_meta = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"': '\\"', + '\\': '\\\\' + }; + json_quote = function(string) { + json_escapable.lastIndex = 0; + if (json_escapable.test(string)) { + return '"' + string.replace(json_escapable, function(a) { + var c; + c = json_meta[a]; + return (typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4)); + }) + '"'; + } else { + return '"' + string + '"'; + } + }; + json_str = function(key, holder) { + var i, k, partial, v, value, _i, _len; + value = holder[key]; + switch (typeof value) { + case 'string': + return json_quote(value); + case 'number': + if (isFinite(value)) { + return String(value); + } else { + return 'null'; + } + case 'boolean': + case 'null': + return String(value); + case 'object': + if (!value) { + return 'null'; + } + partial = []; + if (Object.prototype.toString.apply(value) === '[object Array]') { + for (i = _i = 0, _len = value.length; _i < _len; i = ++_i) { + v = value[i]; + partial[i] = json_str(i, value) || 'null'; + } + return (partial.length === 0 ? '[]' : '[' + partial.join(',') + ']'); + } + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = json_str(k, value); + if (v) { + partial.push(json_quote(k) + ':' + v); + } + } + } + return (partial.length === 0 ? '{}' : '{' + partial.join(',') + '}'); + } + }; + stringify = function(value) { + return json_str('', { + '': value + }); + }; + return stringify; + }; + + if (!((this.JSON != null) && (this.JSON.stringify != null) && typeof this.JSON.stringify === 'function')) { + if (this.JSON == null) { + this.JSON = {}; + } + this.JSON.stringify = get_json_stringify_function(); + } + + html_escape = function(string) { + return ('' + string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/'); + }; + + module.exports = { + _indexOf: _indexOf, + get_json_stringify_function: get_json_stringify_function, + html_escape: html_escape, + indexOf: indexOf, + isInt: isInt + }; + +}).call(this); + +},{}]},{},[1]) \ No newline at end of file diff --git a/tree.jquery.js b/tree.jquery.js index 37c8f740..6ac453f0 100644 --- a/tree.jquery.js +++ b/tree.jquery.js @@ -1,942 +1,627 @@ -// Generated by CoffeeScript 1.7.1 +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o dimensions.right || y > dimensions.bottom) { + return null; } - result = this._handleMouseDown(e, this._getPositionInfo(e)); - if (result) { - e.preventDefault(); + low = 0; + high = this.hit_areas.length; + while (low < high) { + mid = (low + high) >> 1; + area = this.hit_areas[mid]; + if (y < area.top) { + high = mid; + } else if (y > area.bottom) { + low = mid + 1; + } else { + return area; + } } - return result; + return null; }; - MouseWidget.prototype._handleMouseDown = function(e, position_info) { - if (MouseWidget.is_mouse_handled) { + DragAndDropHandler.prototype.mustOpenFolderTimer = function(area) { + var node; + node = area.node; + return node.isFolder() && !node.is_open && area.position === Position.INSIDE; + }; + + DragAndDropHandler.prototype.updateDropHint = function() { + var node_element; + if (!this.hovered_area) { return; } - if (this.is_mouse_started) { - this._handleMouseUp(position_info); - } - this.mouse_down_info = position_info; - if (!this._mouseCapture(position_info)) { - return; - } - this._handleStartMouse(); - this.is_mouse_handled = true; - return true; - }; - - MouseWidget.prototype._handleStartMouse = function() { - var $document; - $document = $(document); - $document.bind('mousemove.mousewidget', $.proxy(this._mouseMove, this)); - $document.bind('touchmove.mousewidget', $.proxy(this._touchMove, this)); - $document.bind('mouseup.mousewidget', $.proxy(this._mouseUp, this)); - $document.bind('touchend.mousewidget', $.proxy(this._touchEnd, this)); - if (this.mouse_delay) { - return this._startMouseDelayTimer(); - } + this.removeDropHint(); + node_element = this.tree_widget._getNodeElementForNode(this.hovered_area.node); + return this.previous_ghost = node_element.addDropHint(this.hovered_area.position); }; - MouseWidget.prototype._startMouseDelayTimer = function() { - if (this._mouse_delay_timer) { - clearTimeout(this._mouse_delay_timer); - } - this._mouse_delay_timer = setTimeout((function(_this) { + DragAndDropHandler.prototype.startOpenFolderTimer = function(folder) { + var openFolder; + openFolder = (function(_this) { return function() { - return _this._is_mouse_delay_met = true; + return _this.tree_widget._openNode(folder, _this.tree_widget.options.slide, function() { + _this.refresh(); + return _this.updateDropHint(); + }); }; - })(this), this.mouse_delay); - return this._is_mouse_delay_met = false; + })(this); + this.stopOpenFolderTimer(); + return this.open_folder_timer = setTimeout(openFolder, this.tree_widget.options.openFolderDelay); }; - MouseWidget.prototype._mouseMove = function(e) { - return this._handleMouseMove(e, this._getPositionInfo(e)); + DragAndDropHandler.prototype.stopOpenFolderTimer = function() { + if (this.open_folder_timer) { + clearTimeout(this.open_folder_timer); + return this.open_folder_timer = null; + } }; - MouseWidget.prototype._handleMouseMove = function(e, position_info) { - if (this.is_mouse_started) { - this._mouseDrag(position_info); - return e.preventDefault(); - } - if (this.mouse_delay && !this._is_mouse_delay_met) { - return true; - } - this.is_mouse_started = this._mouseStart(this.mouse_down_info) !== false; - if (this.is_mouse_started) { - this._mouseDrag(position_info); - } else { - this._handleMouseUp(position_info); + DragAndDropHandler.prototype.moveItem = function(position_info) { + var doMove, event, moved_node, position, previous_parent, target_node; + if (this.hovered_area && this.hovered_area.position !== Position.NONE && this.canMoveToArea(this.hovered_area)) { + moved_node = this.current_item.node; + target_node = this.hovered_area.node; + position = this.hovered_area.position; + previous_parent = moved_node.parent; + if (position === Position.INSIDE) { + this.hovered_area.node.is_open = true; + } + doMove = (function(_this) { + return function() { + _this.tree_widget.tree.moveNode(moved_node, target_node, position); + _this.tree_widget.element.empty(); + return _this.tree_widget._refreshElements(); + }; + })(this); + event = this.tree_widget._triggerEvent('tree.move', { + move_info: { + moved_node: moved_node, + target_node: target_node, + position: Position.getName(position), + previous_parent: previous_parent, + do_move: doMove, + original_event: position_info.original_event + } + }); + if (!event.isDefaultPrevented()) { + return doMove(); + } } - return !this.is_mouse_started; }; - MouseWidget.prototype._getPositionInfo = function(e) { + DragAndDropHandler.prototype.getTreeDimensions = function() { + var offset; + offset = this.tree_widget.element.offset(); return { - page_x: e.pageX, - page_y: e.pageY, - target: e.target, - original_event: e + left: offset.left, + top: offset.top, + right: offset.left + this.tree_widget.element.width(), + bottom: offset.top + this.tree_widget.element.height() + 16 }; }; - MouseWidget.prototype._mouseUp = function(e) { - return this._handleMouseUp(this._getPositionInfo(e)); - }; - - MouseWidget.prototype._handleMouseUp = function(position_info) { - var $document; - $document = $(document); - $document.unbind('mousemove.mousewidget'); - $document.unbind('touchmove.mousewidget'); - $document.unbind('mouseup.mousewidget'); - $document.unbind('touchend.mousewidget'); - if (this.is_mouse_started) { - this.is_mouse_started = false; - this._mouseStop(position_info); - } - }; - - MouseWidget.prototype._mouseCapture = function(position_info) { - return true; - }; + return DragAndDropHandler; - MouseWidget.prototype._mouseStart = function(position_info) { - return null; - }; + })(); - MouseWidget.prototype._mouseDrag = function(position_info) { - return null; - }; + VisibleNodeIterator = (function() { + function VisibleNodeIterator(tree) { + this.tree = tree; + } - MouseWidget.prototype._mouseStop = function(position_info) { - return null; + VisibleNodeIterator.prototype.iterate = function() { + var is_first_node, _iterateNode; + is_first_node = true; + _iterateNode = (function(_this) { + return function(node, next_node) { + var $element, child, children_length, i, must_iterate_inside, _i, _len, _ref; + must_iterate_inside = (node.is_open || !node.element) && node.hasChildren(); + if (node.element) { + $element = $(node.element); + if (!$element.is(':visible')) { + return; + } + if (is_first_node) { + _this.handleFirstNode(node, $element); + is_first_node = false; + } + if (!node.hasChildren()) { + _this.handleNode(node, next_node, $element); + } else if (node.is_open) { + if (!_this.handleOpenFolder(node, $element)) { + must_iterate_inside = false; + } + } else { + _this.handleClosedFolder(node, next_node, $element); + } + } + if (must_iterate_inside) { + children_length = node.children.length; + _ref = node.children; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + child = _ref[i]; + if (i === (children_length - 1)) { + _iterateNode(node.children[i], null); + } else { + _iterateNode(node.children[i], node.children[i + 1]); + } + } + if (node.is_open) { + return _this.handleAfterOpenFolder(node, next_node, $element); + } + } + }; + })(this); + return _iterateNode(this.tree, null); }; - MouseWidget.prototype.setMouseDelay = function(mouse_delay) { - return this.mouse_delay = mouse_delay; - }; + VisibleNodeIterator.prototype.handleNode = function(node, next_node, $element) {}; - MouseWidget.prototype._touchStart = function(e) { - var touch; - if (e.originalEvent.touches.length > 1) { - return; - } - touch = e.originalEvent.changedTouches[0]; - return this._handleMouseDown(e, this._getPositionInfo(touch)); - }; + VisibleNodeIterator.prototype.handleOpenFolder = function(node, $element) {}; - MouseWidget.prototype._touchMove = function(e) { - var touch; - if (e.originalEvent.touches.length > 1) { - return; - } - touch = e.originalEvent.changedTouches[0]; - return this._handleMouseMove(e, this._getPositionInfo(touch)); - }; + VisibleNodeIterator.prototype.handleClosedFolder = function(node, next_node, $element) {}; - MouseWidget.prototype._touchEnd = function(e) { - var touch; - if (e.originalEvent.touches.length > 1) { - return; - } - touch = e.originalEvent.changedTouches[0]; - return this._handleMouseUp(this._getPositionInfo(touch)); - }; + VisibleNodeIterator.prototype.handleAfterOpenFolder = function(node, next_node, $element) {}; - return MouseWidget; + VisibleNodeIterator.prototype.handleFirstNode = function(node, $element) {}; - })(SimpleWidget); + return VisibleNodeIterator; - this.Tree = {}; + })(); - $ = this.jQuery; + HitAreasGenerator = (function(_super) { + __extends(HitAreasGenerator, _super); - Position = { - getName: function(position) { - return Position.strings[position - 1]; - }, - nameToIndex: function(name) { - var i, _i, _ref; - for (i = _i = 1, _ref = Position.strings.length; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) { - if (Position.strings[i - 1] === name) { - return i; - } - } - return 0; + function HitAreasGenerator(tree, current_node, tree_bottom) { + HitAreasGenerator.__super__.constructor.call(this, tree); + this.current_node = current_node; + this.tree_bottom = tree_bottom; } - }; - - Position.BEFORE = 1; - - Position.AFTER = 2; - - Position.INSIDE = 3; - Position.NONE = 4; + HitAreasGenerator.prototype.generate = function() { + this.positions = []; + this.last_top = 0; + this.iterate(); + return this.generateHitAreas(this.positions); + }; - Position.strings = ['before', 'after', 'inside', 'none']; + HitAreasGenerator.prototype.getTop = function($element) { + return $element.offset().top; + }; - this.Tree.Position = Position; + HitAreasGenerator.prototype.addPosition = function(node, position, top) { + var area; + area = { + top: top, + node: node, + position: position + }; + this.positions.push(area); + return this.last_top = top; + }; - Node = (function() { - function Node(o, is_root, node_class) { - if (is_root == null) { - is_root = false; + HitAreasGenerator.prototype.handleNode = function(node, next_node, $element) { + var top; + top = this.getTop($element); + if (node === this.current_node) { + this.addPosition(node, Position.NONE, top); + } else { + this.addPosition(node, Position.INSIDE, top); } - if (node_class == null) { - node_class = Node; + if (next_node === this.current_node || node === this.current_node) { + return this.addPosition(node, Position.NONE, top); + } else { + return this.addPosition(node, Position.AFTER, top); } - this.setData(o); - this.children = []; - this.parent = null; - if (is_root) { - this.id_mapping = {}; - this.tree = this; - this.node_class = node_class; + }; + + HitAreasGenerator.prototype.handleOpenFolder = function(node, $element) { + if (node === this.current_node) { + return false; } - } + if (node.children[0] !== this.current_node) { + this.addPosition(node, Position.INSIDE, this.getTop($element)); + } + return true; + }; - Node.prototype.setData = function(o) { - var key, value, _results; - if (typeof o !== 'object') { - return this.name = o; + HitAreasGenerator.prototype.handleClosedFolder = function(node, next_node, $element) { + var top; + top = this.getTop($element); + if (node === this.current_node) { + return this.addPosition(node, Position.NONE, top); } else { - _results = []; - for (key in o) { - value = o[key]; - if (key === 'label') { - _results.push(this.name = value); - } else { - _results.push(this[key] = value); - } + this.addPosition(node, Position.INSIDE, top); + if (next_node !== this.current_node) { + return this.addPosition(node, Position.AFTER, top); } - return _results; } }; - Node.prototype.initFromData = function(data) { - var addChildren, addNode; - addNode = (function(_this) { - return function(node_data) { - _this.setData(node_data); - if (node_data.children) { - return addChildren(node_data.children); - } - }; - })(this); - addChildren = (function(_this) { - return function(children_data) { - var child, node, _i, _len; - for (_i = 0, _len = children_data.length; _i < _len; _i++) { - child = children_data[_i]; - node = new _this.tree.node_class(''); - node.initFromData(child); - _this.addChild(node); - } - return null; - }; - })(this); - addNode(data); - return null; + HitAreasGenerator.prototype.handleFirstNode = function(node, $element) { + if (node !== this.current_node) { + return this.addPosition(node, Position.BEFORE, this.getTop($(node.element))); + } }; + HitAreasGenerator.prototype.handleAfterOpenFolder = function(node, next_node, $element) { + if (node === this.current_node.node || next_node === this.current_node.node) { + return this.addPosition(node, Position.NONE, this.last_top); + } else { + return this.addPosition(node, Position.AFTER, this.last_top); + } + }; - /* - Create tree from data. - - Structure of data is: - [ - { - label: 'node1', - children: [ - { label: 'child1' }, - { label: 'child2' } - ] - }, - { - label: 'node2' + HitAreasGenerator.prototype.generateHitAreas = function(positions) { + var group, hit_areas, position, previous_top, _i, _len; + previous_top = -1; + group = []; + hit_areas = []; + for (_i = 0, _len = positions.length; _i < _len; _i++) { + position = positions[_i]; + if (position.top !== previous_top && group.length) { + if (group.length) { + this.generateHitAreasForGroup(hit_areas, group, previous_top, position.top); + } + previous_top = position.top; + group = []; } - ] - */ + group.push(position); + } + this.generateHitAreasForGroup(hit_areas, group, previous_top, this.tree_bottom); + return hit_areas; + }; - Node.prototype.loadFromData = function(data) { - var node, o, _i, _len; - this.removeChildren(); - for (_i = 0, _len = data.length; _i < _len; _i++) { - o = data[_i]; - node = new this.tree.node_class(o); - this.addChild(node); - if (typeof o === 'object' && o.children) { - node.loadFromData(o.children); - } + HitAreasGenerator.prototype.generateHitAreasForGroup = function(hit_areas, positions_in_group, top, bottom) { + var area_height, area_top, i, position, position_count; + position_count = Math.min(positions_in_group.length, 4); + area_height = Math.round((bottom - top) / position_count); + area_top = top; + i = 0; + while (i < position_count) { + position = positions_in_group[i]; + hit_areas.push({ + top: area_top, + bottom: area_top + area_height, + node: position.node, + position: position.position + }); + area_top += area_height; + i += 1; } return null; }; + return HitAreasGenerator; - /* - Add child. - - tree.addChild( - new Node('child1') - ); - */ - - Node.prototype.addChild = function(node) { - this.children.push(node); - return node._setParent(this); - }; - + })(VisibleNodeIterator); - /* - Add child at position. Index starts at 0. - - tree.addChildAtPosition( - new Node('abc'), - 1 - ); - */ + DragElement = (function() { + function DragElement(node, offset_x, offset_y, $tree) { + this.offset_x = offset_x; + this.offset_y = offset_y; + this.$element = $("" + node.name + ""); + this.$element.css("position", "absolute"); + $tree.append(this.$element); + } - Node.prototype.addChildAtPosition = function(node, index) { - this.children.splice(index, 0, node); - return node._setParent(this); + DragElement.prototype.move = function(page_x, page_y) { + return this.$element.offset({ + left: page_x - this.offset_x, + top: page_y - this.offset_y + }); }; - Node.prototype._setParent = function(parent) { - this.parent = parent; - this.tree = parent.tree; - return this.tree.addNodeToIndex(this); + DragElement.prototype.remove = function() { + return this.$element.remove(); }; + return DragElement; - /* - Remove child. This also removes the children of the node. - - tree.removeChild(tree.children[0]); - */ + })(); - Node.prototype.removeChild = function(node) { - node.removeChildren(); - return this._removeChild(node); - }; + module.exports = DragAndDropHandler; - Node.prototype._removeChild = function(node) { - this.children.splice(this.getChildIndex(node), 1); - return this.tree.removeNodeFromIndex(node); - }; +}).call(this); +},{"./node":6}],2:[function(require,module,exports){ +(function() { + var ElementsRenderer, NodeElement, html_escape, node_element, util; - /* - Get child index. - - var index = getChildIndex(node); - */ + node_element = require('./node_element'); - Node.prototype.getChildIndex = function(node) { - return $.inArray(node, this.children); - }; + NodeElement = node_element.NodeElement; + util = require('./util'); - /* - Does the tree have children? - - if (tree.hasChildren()) { - // - } - */ + html_escape = util.html_escape; - Node.prototype.hasChildren = function() { - return this.children.length !== 0; - }; + ElementsRenderer = (function() { + function ElementsRenderer(tree_widget) { + this.tree_widget = tree_widget; + this.opened_icon_element = this.createButtonElement(tree_widget.options.openedIcon); + this.closed_icon_element = this.createButtonElement(tree_widget.options.closedIcon); + } - Node.prototype.isFolder = function() { - return this.hasChildren() || this.load_on_demand; + ElementsRenderer.prototype.render = function(from_node) { + if (from_node && from_node.parent) { + return this.renderFromNode(from_node); + } else { + return this.renderFromRoot(); + } }; - - /* - Iterate over all the nodes in the tree. - - Calls callback with (node, level). - - The callback must return true to continue the iteration on current node. - - tree.iterate( - function(node, level) { - console.log(node.name); - - // stop iteration after level 2 - return (level <= 2); - } - ); - */ - - Node.prototype.iterate = function(callback) { - var _iterate; - _iterate = (function(_this) { - return function(node, level) { - var child, result, _i, _len, _ref; - if (node.children) { - _ref = node.children; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - result = callback(child, level); - if (_this.hasChildren() && result) { - _iterate(child, level + 1); - } - } - return null; - } - }; - })(this); - _iterate(this, 0); - return null; - }; - - - /* - Move node relative to another node. - - Argument position: Position.BEFORE, Position.AFTER or Position.Inside - - // move node1 after node2 - tree.moveNode(node1, node2, Position.AFTER); - */ - - Node.prototype.moveNode = function(moved_node, target_node, position) { - if (moved_node.isParentOf(target_node)) { - return; + ElementsRenderer.prototype.renderNode = function(node) { + var li, parent_node_element, previous_node; + $(node.element).remove(); + parent_node_element = new NodeElement(node.parent, this.tree_widget); + li = this.createLi(node); + this.attachNodeData(node, li); + previous_node = node.getPreviousSibling(); + if (previous_node) { + $(previous_node.element).after(li); + } else { + parent_node_element.getUl().prepend(li); } - moved_node.parent._removeChild(moved_node); - if (position === Position.AFTER) { - return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node) + 1); - } else if (position === Position.BEFORE) { - return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node)); - } else if (position === Position.INSIDE) { - return target_node.addChildAtPosition(moved_node, 0); + if (node.children) { + return this.renderFromNode(node); } }; + ElementsRenderer.prototype.renderFromRoot = function() { + var $element; + $element = this.tree_widget.element; + $element.empty(); + return this.createDomElements($element[0], this.tree_widget.tree.children, true, true); + }; - /* - Get the tree as data. - */ - - Node.prototype.getData = function() { - var getDataFromNodes; - getDataFromNodes = (function(_this) { - return function(nodes) { - var data, k, node, tmp_node, v, _i, _len; - data = []; - for (_i = 0, _len = nodes.length; _i < _len; _i++) { - node = nodes[_i]; - tmp_node = {}; - for (k in node) { - v = node[k]; - if ((k !== 'parent' && k !== 'children' && k !== 'element' && k !== 'tree') && Object.prototype.hasOwnProperty.call(node, k)) { - tmp_node[k] = v; - } - } - if (node.hasChildren()) { - tmp_node.children = getDataFromNodes(node.children); - } - data.push(tmp_node); - } - return data; - }; - })(this); - return getDataFromNodes(this.children); + ElementsRenderer.prototype.renderFromNode = function(from_node) { + node_element = this.tree_widget._getNodeElementForNode(from_node); + node_element.getUl().remove(); + return this.createDomElements(node_element.$element[0], from_node.children, false, false); }; - Node.prototype.getNodeByName = function(name) { - var result; - result = null; - this.iterate(function(node) { - if (node.name === name) { - result = node; - return false; - } else { - return true; + ElementsRenderer.prototype.createDomElements = function(element, children, is_root_node, is_open) { + var child, li, ul, _i, _len; + ul = this.createUl(is_root_node); + element.appendChild(ul); + for (_i = 0, _len = children.length; _i < _len; _i++) { + child = children[_i]; + li = this.createLi(child); + ul.appendChild(li); + this.attachNodeData(child, li); + if (child.hasChildren()) { + this.createDomElements(li, child.children, false, child.is_open); } - }); - return result; + } + return null; }; - Node.prototype.addAfter = function(node_info) { - var child_index, node; - if (!this.parent) { - return null; - } else { - node = new this.tree.node_class(node_info); - child_index = this.parent.getChildIndex(this); - this.parent.addChildAtPosition(node, child_index + 1); - return node; - } + ElementsRenderer.prototype.attachNodeData = function(node, li) { + node.element = li; + return $(li).data('node', node); }; - Node.prototype.addBefore = function(node_info) { - var child_index, node; - if (!this.parent) { - return null; + ElementsRenderer.prototype.createUl = function(is_root_node) { + var class_string, ul; + if (is_root_node) { + class_string = 'jqtree-tree'; } else { - node = new this.tree.node_class(node_info); - child_index = this.parent.getChildIndex(this); - this.parent.addChildAtPosition(node, child_index); - return node; + class_string = ''; } + ul = document.createElement('ul'); + ul.className = "jqtree_common " + class_string; + return ul; }; - Node.prototype.addParent = function(node_info) { - var child, new_parent, original_parent, _i, _len, _ref; - if (!this.parent) { - return null; + ElementsRenderer.prototype.createLi = function(node) { + var li; + if (node.isFolder()) { + li = this.createFolderLi(node); } else { - new_parent = new this.tree.node_class(node_info); - new_parent._setParent(this.tree); - original_parent = this.parent; - _ref = original_parent.children; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - new_parent.addChild(child); - } - original_parent.children = []; - original_parent.addChild(new_parent); - return new_parent; + li = this.createNodeLi(node); + } + if (this.tree_widget.options.onCreateLi) { + this.tree_widget.options.onCreateLi(node, $(li)); } + return li; }; - Node.prototype.remove = function() { - if (this.parent) { - this.parent.removeChild(this); - return this.parent = null; + ElementsRenderer.prototype.createFolderLi = function(node) { + var button_classes, button_link, div, escaped_name, folder_classes, icon_element, li, title_span; + button_classes = this.getButtonClasses(node); + folder_classes = this.getFolderClasses(node); + escaped_name = this.escapeIfNecessary(node.name); + if (node.is_open) { + icon_element = this.opened_icon_element; + } else { + icon_element = this.closed_icon_element; } + li = document.createElement('li'); + li.className = "jqtree_common " + folder_classes; + div = document.createElement('div'); + div.className = "jqtree-element jqtree_common"; + li.appendChild(div); + button_link = document.createElement('a'); + button_link.className = "jqtree_common " + button_classes; + button_link.appendChild(icon_element.cloneNode()); + div.appendChild(button_link); + title_span = document.createElement('span'); + title_span.className = "jqtree_common jqtree-title jqtree-title-folder"; + div.appendChild(title_span); + title_span.innerHTML = escaped_name; + return li; }; - Node.prototype.append = function(node_info) { - var node; - node = new this.tree.node_class(node_info); - this.addChild(node); - return node; + ElementsRenderer.prototype.createNodeLi = function(node) { + var class_string, div, escaped_name, li, li_classes, title_span; + li_classes = ['jqtree_common']; + if (this.tree_widget.select_node_handler && this.tree_widget.select_node_handler.isNodeSelected(node)) { + li_classes.push('jqtree-selected'); + } + class_string = li_classes.join(' '); + escaped_name = this.escapeIfNecessary(node.name); + li = document.createElement('li'); + li.className = class_string; + div = document.createElement('div'); + div.className = "jqtree-element jqtree_common"; + li.appendChild(div); + title_span = document.createElement('span'); + title_span.className = "jqtree-title jqtree_common"; + title_span.innerHTML = escaped_name; + div.appendChild(title_span); + return li; }; - Node.prototype.prepend = function(node_info) { - var node; - node = new this.tree.node_class(node_info); - this.addChildAtPosition(node, 0); - return node; - }; - - Node.prototype.isParentOf = function(node) { - var parent; - parent = node.parent; - while (parent) { - if (parent === this) { - return true; - } - parent = parent.parent; - } - return false; - }; - - Node.prototype.getLevel = function() { - var level, node; - level = 0; - node = this; - while (node.parent) { - level += 1; - node = node.parent; - } - return level; - }; - - Node.prototype.getNodeById = function(node_id) { - return this.id_mapping[node_id]; - }; - - Node.prototype.addNodeToIndex = function(node) { - if (node.id != null) { - return this.id_mapping[node.id] = node; - } - }; - - Node.prototype.removeNodeFromIndex = function(node) { - if (node.id != null) { - return delete this.id_mapping[node.id]; - } - }; - - Node.prototype.removeChildren = function() { - this.iterate((function(_this) { - return function(child) { - _this.tree.removeNodeFromIndex(child); - return true; - }; - })(this)); - return this.children = []; - }; - - Node.prototype.getPreviousSibling = function() { - var previous_index; - if (!this.parent) { - return null; - } else { - previous_index = this.parent.getChildIndex(this) - 1; - if (previous_index >= 0) { - return this.parent.children[previous_index]; - } else { - return null; - } - } - }; - - Node.prototype.getNextSibling = function() { - var next_index; - if (!this.parent) { - return null; - } else { - next_index = this.parent.getChildIndex(this) + 1; - if (next_index < this.parent.children.length) { - return this.parent.children[next_index]; - } else { - return null; - } - } - }; - - Node.prototype.getNodesByProperty = function(key, value) { - return this.filter(function(node) { - return node[key] === value; - }); - }; - - Node.prototype.filter = function(f) { - var result; - result = []; - this.iterate(function(node) { - if (f(node)) { - result.push(node); - } - return true; - }); - return result; - }; - - return Node; - - })(); - - this.Tree.Node = Node; - - ElementsRenderer = (function() { - function ElementsRenderer(tree_widget) { - this.tree_widget = tree_widget; - this.opened_icon_element = this.createButtonElement(tree_widget.options.openedIcon); - this.closed_icon_element = this.createButtonElement(tree_widget.options.closedIcon); - } - - ElementsRenderer.prototype.render = function(from_node) { - if (from_node && from_node.parent) { - return this.renderFromNode(from_node); - } else { - return this.renderFromRoot(); - } - }; - - ElementsRenderer.prototype.renderNode = function(node) { - var li, parent_node_element, previous_node; - $(node.element).remove(); - parent_node_element = new NodeElement(node.parent, this.tree_widget); - li = this.createLi(node); - this.attachNodeData(node, li); - previous_node = node.getPreviousSibling(); - if (previous_node) { - $(previous_node.element).after(li); - } else { - parent_node_element.getUl().prepend(li); - } - if (node.children) { - return this.renderFromNode(node); - } - }; - - ElementsRenderer.prototype.renderFromRoot = function() { - var $element; - $element = this.tree_widget.element; - $element.empty(); - return this.createDomElements($element[0], this.tree_widget.tree.children, true, true); - }; - - ElementsRenderer.prototype.renderFromNode = function(from_node) { - var node_element; - node_element = this.tree_widget._getNodeElementForNode(from_node); - node_element.getUl().remove(); - return this.createDomElements(node_element.$element[0], from_node.children, false, false); - }; - - ElementsRenderer.prototype.createDomElements = function(element, children, is_root_node, is_open) { - var child, li, ul, _i, _len; - ul = this.createUl(is_root_node); - element.appendChild(ul); - for (_i = 0, _len = children.length; _i < _len; _i++) { - child = children[_i]; - li = this.createLi(child); - ul.appendChild(li); - this.attachNodeData(child, li); - if (child.hasChildren()) { - this.createDomElements(li, child.children, false, child.is_open); - } - } - return null; - }; - - ElementsRenderer.prototype.attachNodeData = function(node, li) { - node.element = li; - return $(li).data('node', node); - }; - - ElementsRenderer.prototype.createUl = function(is_root_node) { - var class_string, ul; - if (is_root_node) { - class_string = 'jqtree-tree'; - } else { - class_string = ''; - } - ul = document.createElement('ul'); - ul.className = "jqtree_common " + class_string; - return ul; - }; - - ElementsRenderer.prototype.createLi = function(node) { - var li; - if (node.isFolder()) { - li = this.createFolderLi(node); - } else { - li = this.createNodeLi(node); - } - if (this.tree_widget.options.onCreateLi) { - this.tree_widget.options.onCreateLi(node, $(li)); - } - return li; - }; - - ElementsRenderer.prototype.createFolderLi = function(node) { - var button_classes, button_link, div, escaped_name, folder_classes, icon_element, li, title_span; - button_classes = this.getButtonClasses(node); - folder_classes = this.getFolderClasses(node); - escaped_name = this.escapeIfNecessary(node.name); - if (node.is_open) { - icon_element = this.opened_icon_element; - } else { - icon_element = this.closed_icon_element; - } - li = document.createElement('li'); - li.className = "jqtree_common " + folder_classes; - div = document.createElement('div'); - div.className = "jqtree-element jqtree_common"; - li.appendChild(div); - button_link = document.createElement('a'); - button_link.className = "jqtree_common " + button_classes; - button_link.appendChild(icon_element.cloneNode()); - div.appendChild(button_link); - title_span = document.createElement('span'); - title_span.className = "jqtree_common jqtree-title jqtree-title-folder"; - div.appendChild(title_span); - title_span.innerHTML = escaped_name; - return li; - }; - - ElementsRenderer.prototype.createNodeLi = function(node) { - var class_string, div, escaped_name, li, li_classes, title_span; - li_classes = ['jqtree_common']; - if (this.tree_widget.select_node_handler && this.tree_widget.select_node_handler.isNodeSelected(node)) { - li_classes.push('jqtree-selected'); - } - class_string = li_classes.join(' '); - escaped_name = this.escapeIfNecessary(node.name); - li = document.createElement('li'); - li.className = class_string; - div = document.createElement('div'); - div.className = "jqtree-element jqtree_common"; - li.appendChild(div); - title_span = document.createElement('span'); - title_span.className = "jqtree-title jqtree_common"; - title_span.innerHTML = escaped_name; - div.appendChild(title_span); - return li; - }; - - ElementsRenderer.prototype.getButtonClasses = function(node) { - var classes; - classes = ['jqtree-toggler']; - if (!node.is_open) { - classes.push('jqtree-closed'); - } - return classes.join(' '); + ElementsRenderer.prototype.getButtonClasses = function(node) { + var classes; + classes = ['jqtree-toggler']; + if (!node.is_open) { + classes.push('jqtree-closed'); + } + return classes.join(' '); }; ElementsRenderer.prototype.getFolderClasses = function(node) { @@ -974,40 +659,80 @@ })(); + module.exports = ElementsRenderer; - /* - Copyright 2013 Marco Braak - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ +}).call(this); - JqTreeWidget = (function(_super) { - __extends(JqTreeWidget, _super); +},{"./node_element":7,"./util":12}],3:[function(require,module,exports){ - function JqTreeWidget() { - return JqTreeWidget.__super__.constructor.apply(this, arguments); - } +/* +Copyright 2013 Marco Braak - JqTreeWidget.prototype.defaults = { - autoOpen: false, - saveState: false, - dragAndDrop: false, - selectable: true, - useContextMenu: true, - onCanSelectNode: null, - onSetStateFromStorage: null, - onGetStateFromStorage: null, - onCreateLi: null, +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +(function() { + var DragAndDropHandler, ElementsRenderer, FolderElement, JqTreeWidget, KeyHandler, MouseWidget, Node, NodeElement, Position, SaveStateHandler, ScrollHandler, SelectNodeHandler, SimpleWidget, node, node_element, __version__, + __hasProp = {}.hasOwnProperty, + __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; }; + + __version__ = require('./version'); + + DragAndDropHandler = require('./drag_and_drop_handler'); + + ElementsRenderer = require('./elements_renderer'); + + KeyHandler = require('./key_handler'); + + MouseWidget = require('./mouse.widget'); + + SaveStateHandler = require('./save_state_handler'); + + ScrollHandler = require('./scroll_handler'); + + SelectNodeHandler = require('./select_node_handler'); + + SimpleWidget = require('./simple.widget'); + + node = require('./node'); + + Node = node.Node; + + Position = node.Position; + + node_element = require('./node_element'); + + NodeElement = node_element.NodeElement; + + FolderElement = node_element.FolderElement; + + JqTreeWidget = (function(_super) { + __extends(JqTreeWidget, _super); + + function JqTreeWidget() { + return JqTreeWidget.__super__.constructor.apply(this, arguments); + } + + JqTreeWidget.prototype.defaults = { + autoOpen: false, + saveState: false, + dragAndDrop: false, + selectable: true, + useContextMenu: true, + onCanSelectNode: null, + onSetStateFromStorage: null, + onGetStateFromStorage: null, + onCreateLi: null, onIsMoveHandle: null, onCanMove: null, onCanMoveTo: null, @@ -1108,7 +833,11 @@ }; JqTreeWidget.prototype.getSelectedNode = function() { - return this.select_node_handler.getSelectedNode(); + if (this.select_node_handler) { + return this.select_node_handler.getSelectedNode(); + } else { + return null; + } }; JqTreeWidget.prototype.toJson = function() { @@ -1229,10 +958,12 @@ if (!parent_node) { this._initTree(data); } else { - selected_nodes_under_parent = this.select_node_handler.getSelectedNodesUnder(parent_node); - for (_i = 0, _len = selected_nodes_under_parent.length; _i < _len; _i++) { - n = selected_nodes_under_parent[_i]; - this.select_node_handler.removeFromSelection(n); + if (this.select_node_handler) { + selected_nodes_under_parent = this.select_node_handler.getSelectedNodesUnder(parent_node); + for (_i = 0, _len = selected_nodes_under_parent.length; _i < _len; _i++) { + n = selected_nodes_under_parent[_i]; + this.select_node_handler.removeFromSelection(n); + } } parent_node.loadFromData(data); parent_node.load_on_demand = false; @@ -1358,7 +1089,7 @@ }; JqTreeWidget.prototype.appendNode = function(new_node_info, parent_node) { - var is_already_folder_node, node; + var is_already_folder_node; if (!parent_node) { parent_node = this.tree; } @@ -1373,7 +1104,6 @@ }; JqTreeWidget.prototype.prependNode = function(new_node_info, parent_node) { - var node; if (!parent_node) { parent_node = this.tree; } @@ -1459,23 +1189,23 @@ this.mouse_delay = 300; this.is_initialized = false; this.renderer = new ElementsRenderer(this); - if (typeof SaveStateHandler !== "undefined" && SaveStateHandler !== null) { + if (SaveStateHandler != null) { this.save_state_handler = new SaveStateHandler(this); } else { this.options.saveState = false; } - if (typeof SelectNodeHandler !== "undefined" && SelectNodeHandler !== null) { + if (SelectNodeHandler != null) { this.select_node_handler = new SelectNodeHandler(this); } - if (typeof DragAndDropHandler !== "undefined" && DragAndDropHandler !== null) { + if (DragAndDropHandler != null) { this.dnd_handler = new DragAndDropHandler(this); } else { this.options.dragAndDrop = false; } - if (typeof ScrollHandler !== "undefined" && ScrollHandler !== null) { + if (ScrollHandler != null) { this.scroll_handler = new ScrollHandler(this); } - if ((typeof KeyHandler !== "undefined" && KeyHandler !== null) && (typeof SelectNodeHandler !== "undefined" && SelectNodeHandler !== null)) { + if ((KeyHandler != null) && (SelectNodeHandler != null)) { this.key_handler = new KeyHandler(this); } this._initData(); @@ -1489,7 +1219,9 @@ JqTreeWidget.prototype._deinit = function() { this.element.empty(); this.element.unbind(); - this.key_handler.deinit(); + if (this.key_handler) { + this.key_handler.deinit(); + } this.tree = null; return JqTreeWidget.__super__._deinit.call(this); }; @@ -1590,7 +1322,7 @@ }; JqTreeWidget.prototype._click = function(e) { - var click_target, event, node; + var click_target, event; click_target = this._getClickTarget(e.target); if (click_target) { if (click_target.type === 'button') { @@ -1622,7 +1354,7 @@ }; JqTreeWidget.prototype._getClickTarget = function(element) { - var $button, $el, $target, node; + var $button, $el, $target; $target = $(element); $button = $target.closest('.jqtree-toggler'); if ($button.length) { @@ -1667,7 +1399,6 @@ }; JqTreeWidget.prototype._getNodeElement = function($element) { - var node; node = this._getNode($element); if (node) { return this._getNodeElementForNode(node); @@ -1677,7 +1408,7 @@ }; JqTreeWidget.prototype._contextmenu = function(e) { - var $div, node; + var $div; $div = $(e.target).closest('ul.jqtree-tree .jqtree-element'); if ($div.length) { node = this._getNode($div); @@ -1751,7 +1482,6 @@ }; JqTreeWidget.prototype._selectCurrentNode = function() { - var node, node_element; node = this.getSelectedNode(); if (node) { node_element = this._getNodeElementForNode(node); @@ -1762,7 +1492,6 @@ }; JqTreeWidget.prototype._deselectCurrentNode = function() { - var node; node = this.getSelectedNode(); if (node) { return this.removeFromSelection(node); @@ -1775,1307 +1504,1729 @@ SimpleWidget.register(JqTreeWidget, 'tree'); - NodeElement = (function() { - function NodeElement(node, tree_widget) { - this.init(node, tree_widget); - } - - NodeElement.prototype.init = function(node, tree_widget) { - this.node = node; - this.tree_widget = tree_widget; - if (!node.element) { - node.element = this.tree_widget.element; - } - return this.$element = $(node.element); - }; - - NodeElement.prototype.getUl = function() { - return this.$element.children('ul:first'); - }; - - NodeElement.prototype.getSpan = function() { - return this.$element.children('.jqtree-element').find('span.jqtree-title'); - }; - - NodeElement.prototype.getLi = function() { - return this.$element; - }; +}).call(this); - NodeElement.prototype.addDropHint = function(position) { - if (position === Position.INSIDE) { - return new BorderDropHint(this.$element); - } else { - return new GhostDropHint(this.node, this.$element, position); - } - }; +},{"./drag_and_drop_handler":1,"./elements_renderer":2,"./key_handler":4,"./mouse.widget":5,"./node":6,"./node_element":7,"./save_state_handler":8,"./scroll_handler":9,"./select_node_handler":10,"./simple.widget":11,"./version":13}],4:[function(require,module,exports){ +(function() { + var KeyHandler; - NodeElement.prototype.select = function() { - return this.getLi().addClass('jqtree-selected'); - }; + KeyHandler = (function() { + var DOWN, LEFT, RIGHT, UP; - NodeElement.prototype.deselect = function() { - return this.getLi().removeClass('jqtree-selected'); - }; + LEFT = 37; - return NodeElement; + UP = 38; - })(); + RIGHT = 39; - FolderElement = (function(_super) { - __extends(FolderElement, _super); + DOWN = 40; - function FolderElement() { - return FolderElement.__super__.constructor.apply(this, arguments); + function KeyHandler(tree_widget) { + this.tree_widget = tree_widget; + if (tree_widget.options.keyboardSupport) { + $(document).bind('keydown.jqtree', $.proxy(this.handleKeyDown, this)); + } } - FolderElement.prototype.open = function(on_finished, slide) { - var $button, doOpen; - if (slide == null) { - slide = true; + KeyHandler.prototype.deinit = function() { + return $(document).unbind('keydown.jqtree'); + }; + + KeyHandler.prototype.handleKeyDown = function(e) { + var current_node, key, moveDown, moveLeft, moveRight, moveUp, selectNode; + if (!this.tree_widget.options.keyboardSupport) { + return; } - if (!this.node.is_open) { - this.node.is_open = true; - $button = this.getButton(); - $button.removeClass('jqtree-closed'); - $button.html(''); - $button.append(this.tree_widget.renderer.opened_icon_element.cloneNode()); - doOpen = (function(_this) { - return function() { - _this.getLi().removeClass('jqtree-closed'); - if (on_finished) { - on_finished(); + if ($(document.activeElement).is('textarea,input,select')) { + return true; + } + current_node = this.tree_widget.getSelectedNode(); + selectNode = (function(_this) { + return function(node) { + if (node) { + _this.tree_widget.selectNode(node); + if (_this.tree_widget.scroll_handler && (!_this.tree_widget.scroll_handler.isScrolledIntoView($(node.element).find('.jqtree-element')))) { + _this.tree_widget.scrollToNode(node); } - return _this.tree_widget._triggerEvent('tree.open', { - node: _this.node - }); - }; - })(this); - if (slide) { - return this.getUl().slideDown('fast', doOpen); - } else { - this.getUl().show(); - return doOpen(); + return false; + } else { + return true; + } + }; + })(this); + moveDown = (function(_this) { + return function() { + return selectNode(_this.getNextNode(current_node)); + }; + })(this); + moveUp = (function(_this) { + return function() { + return selectNode(_this.getPreviousNode(current_node)); + }; + })(this); + moveRight = (function(_this) { + return function() { + if (current_node.isFolder() && !current_node.is_open) { + _this.tree_widget.openNode(current_node); + return false; + } else { + return true; + } + }; + })(this); + moveLeft = (function(_this) { + return function() { + if (current_node.isFolder() && current_node.is_open) { + _this.tree_widget.closeNode(current_node); + return false; + } else { + return true; + } + }; + })(this); + if (!current_node) { + return true; + } else { + key = e.which; + switch (key) { + case DOWN: + return moveDown(); + case UP: + return moveUp(); + case RIGHT: + return moveRight(); + case LEFT: + return moveLeft(); } } }; - FolderElement.prototype.close = function(slide) { - var $button, doClose; - if (slide == null) { - slide = true; + KeyHandler.prototype.getNextNode = function(node, include_children) { + var next_sibling; + if (include_children == null) { + include_children = true; } - if (this.node.is_open) { - this.node.is_open = false; - $button = this.getButton(); - $button.addClass('jqtree-closed'); - $button.html(''); - $button.append(this.tree_widget.renderer.closed_icon_element.cloneNode()); - doClose = (function(_this) { - return function() { - _this.getLi().addClass('jqtree-closed'); - return _this.tree_widget._triggerEvent('tree.close', { - node: _this.node - }); - }; - })(this); - if (slide) { - return this.getUl().slideUp('fast', doClose); + if (include_children && node.hasChildren() && node.is_open) { + return node.children[0]; + } else { + if (!node.parent) { + return null; } else { - this.getUl().hide(); - return doClose(); + next_sibling = node.getNextSibling(); + if (next_sibling) { + return next_sibling; + } else { + return this.getNextNode(node.parent, false); + } } } }; - FolderElement.prototype.getButton = function() { - return this.$element.children('.jqtree-element').find('a.jqtree-toggler'); + KeyHandler.prototype.getPreviousNode = function(node) { + var previous_sibling; + if (!node.parent) { + return null; + } else { + previous_sibling = node.getPreviousSibling(); + if (previous_sibling) { + if (!previous_sibling.hasChildren() || !previous_sibling.is_open) { + return previous_sibling; + } else { + return this.getLastChild(previous_sibling); + } + } else { + if (node.parent.parent) { + return node.parent; + } else { + return null; + } + } + } }; - FolderElement.prototype.addDropHint = function(position) { - if (!this.node.is_open && position === Position.INSIDE) { - return new BorderDropHint(this.$element); + KeyHandler.prototype.getLastChild = function(node) { + var last_child; + if (!node.hasChildren()) { + return null; } else { - return new GhostDropHint(this.node, this.$element, position); + last_child = node.children[node.children.length - 1]; + if (!last_child.hasChildren() || !last_child.is_open) { + return last_child; + } else { + return this.getLastChild(last_child); + } } }; - return FolderElement; - - })(NodeElement); + return KeyHandler; - html_escape = function(string) { - return ('' + string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/'); - }; + })(); - _indexOf = function(array, item) { - var i, value, _i, _len; - for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) { - value = array[i]; - if (value === item) { - return i; - } - } - return -1; - }; + module.exports = KeyHandler; - indexOf = function(array, item) { - if (array.indexOf) { - return array.indexOf(item); - } else { - return _indexOf(array, item); - } - }; +}).call(this); - this.Tree.indexOf = indexOf; +},{}],5:[function(require,module,exports){ - this.Tree._indexOf = _indexOf; +/* +This widget does the same a the mouse widget in jqueryui. + */ - isInt = function(n) { - return typeof n === 'number' && n % 1 === 0; - }; +(function() { + var MouseWidget, SimpleWidget, + __hasProp = {}.hasOwnProperty, + __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; }; - get_json_stringify_function = function() { - var json_escapable, json_meta, json_quote, json_str, stringify; - json_escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; - json_meta = { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"': '\\"', - '\\': '\\\\' - }; - json_quote = function(string) { - json_escapable.lastIndex = 0; - if (json_escapable.test(string)) { - return '"' + string.replace(json_escapable, function(a) { - var c; - c = json_meta[a]; - return (typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4)); - }) + '"'; - } else { - return '"' + string + '"'; - } - }; - json_str = function(key, holder) { - var i, k, partial, v, value, _i, _len; - value = holder[key]; - switch (typeof value) { - case 'string': - return json_quote(value); - case 'number': - if (isFinite(value)) { - return String(value); - } else { - return 'null'; - } - case 'boolean': - case 'null': - return String(value); - case 'object': - if (!value) { - return 'null'; - } - partial = []; - if (Object.prototype.toString.apply(value) === '[object Array]') { - for (i = _i = 0, _len = value.length; _i < _len; i = ++_i) { - v = value[i]; - partial[i] = json_str(i, value) || 'null'; - } - return (partial.length === 0 ? '[]' : '[' + partial.join(',') + ']'); - } - for (k in value) { - if (Object.prototype.hasOwnProperty.call(value, k)) { - v = json_str(k, value); - if (v) { - partial.push(json_quote(k) + ':' + v); - } - } - } - return (partial.length === 0 ? '{}' : '{' + partial.join(',') + '}'); - } - }; - stringify = function(value) { - return json_str('', { - '': value - }); - }; - return stringify; - }; + SimpleWidget = require('./simple.widget'); - this.Tree.get_json_stringify_function = get_json_stringify_function; + MouseWidget = (function(_super) { + __extends(MouseWidget, _super); - if (!((this.JSON != null) && (this.JSON.stringify != null) && typeof this.JSON.stringify === 'function')) { - if (this.JSON == null) { - this.JSON = {}; + function MouseWidget() { + return MouseWidget.__super__.constructor.apply(this, arguments); } - this.JSON.stringify = get_json_stringify_function(); - } - SaveStateHandler = (function() { - function SaveStateHandler(tree_widget) { - this.tree_widget = tree_widget; - } + MouseWidget.is_mouse_handled = false; - SaveStateHandler.prototype.saveState = function() { - var state; - state = JSON.stringify(this.getState()); - if (this.tree_widget.options.onSetStateFromStorage) { - return this.tree_widget.options.onSetStateFromStorage(state); - } else if (this.supportsLocalStorage()) { - return localStorage.setItem(this.getCookieName(), state); - } else if ($.cookie) { - $.cookie.raw = true; - return $.cookie(this.getCookieName(), state, { - path: '/' - }); + MouseWidget.prototype._init = function() { + this.$el.bind('mousedown.mousewidget', $.proxy(this._mouseDown, this)); + this.$el.bind('touchstart.mousewidget', $.proxy(this._touchStart, this)); + this.is_mouse_started = false; + this.mouse_delay = 0; + this._mouse_delay_timer = null; + this._is_mouse_delay_met = true; + return this.mouse_down_info = null; + }; + + MouseWidget.prototype._deinit = function() { + var $document; + this.$el.unbind('mousedown.mousewidget'); + this.$el.unbind('touchstart.mousewidget'); + $document = $(document); + $document.unbind('mousemove.mousewidget'); + return $document.unbind('mouseup.mousewidget'); + }; + + MouseWidget.prototype._mouseDown = function(e) { + var result; + if (e.which !== 1) { + return; + } + result = this._handleMouseDown(e, this._getPositionInfo(e)); + if (result) { + e.preventDefault(); } + return result; }; - SaveStateHandler.prototype.restoreState = function() { - var state; - state = this.getStateFromStorage(); - if (state) { - this.setState(state); - return true; - } else { - return false; + MouseWidget.prototype._handleMouseDown = function(e, position_info) { + if (MouseWidget.is_mouse_handled) { + return; + } + if (this.is_mouse_started) { + this._handleMouseUp(position_info); + } + this.mouse_down_info = position_info; + if (!this._mouseCapture(position_info)) { + return; } + this._handleStartMouse(); + this.is_mouse_handled = true; + return true; }; - SaveStateHandler.prototype.getStateFromStorage = function() { - var json_data; - json_data = this._loadFromStorage(); - if (json_data) { - return this._parseState(json_data); - } else { - return null; + MouseWidget.prototype._handleStartMouse = function() { + var $document; + $document = $(document); + $document.bind('mousemove.mousewidget', $.proxy(this._mouseMove, this)); + $document.bind('touchmove.mousewidget', $.proxy(this._touchMove, this)); + $document.bind('mouseup.mousewidget', $.proxy(this._mouseUp, this)); + $document.bind('touchend.mousewidget', $.proxy(this._touchEnd, this)); + if (this.mouse_delay) { + return this._startMouseDelayTimer(); } }; - SaveStateHandler.prototype._parseState = function(json_data) { - var state; - state = $.parseJSON(json_data); - if (state && state.selected_node && isInt(state.selected_node)) { - state.selected_node = [state.selected_node]; + MouseWidget.prototype._startMouseDelayTimer = function() { + if (this._mouse_delay_timer) { + clearTimeout(this._mouse_delay_timer); } - return state; + this._mouse_delay_timer = setTimeout((function(_this) { + return function() { + return _this._is_mouse_delay_met = true; + }; + })(this), this.mouse_delay); + return this._is_mouse_delay_met = false; }; - SaveStateHandler.prototype._loadFromStorage = function() { - if (this.tree_widget.options.onGetStateFromStorage) { - return this.tree_widget.options.onGetStateFromStorage(); - } else if (this.supportsLocalStorage()) { - return localStorage.getItem(this.getCookieName()); - } else if ($.cookie) { - $.cookie.raw = true; - return $.cookie(this.getCookieName()); + MouseWidget.prototype._mouseMove = function(e) { + return this._handleMouseMove(e, this._getPositionInfo(e)); + }; + + MouseWidget.prototype._handleMouseMove = function(e, position_info) { + if (this.is_mouse_started) { + this._mouseDrag(position_info); + return e.preventDefault(); + } + if (this.mouse_delay && !this._is_mouse_delay_met) { + return true; + } + this.is_mouse_started = this._mouseStart(this.mouse_down_info) !== false; + if (this.is_mouse_started) { + this._mouseDrag(position_info); } else { - return null; + this._handleMouseUp(position_info); } + return !this.is_mouse_started; }; - SaveStateHandler.prototype.getState = function() { - var getOpenNodeIds, getSelectedNodeIds; - getOpenNodeIds = (function(_this) { - return function() { - var open_nodes; - open_nodes = []; - _this.tree_widget.tree.iterate(function(node) { - if (node.is_open && node.id && node.hasChildren()) { - open_nodes.push(node.id); - } - return true; - }); - return open_nodes; - }; - })(this); - getSelectedNodeIds = (function(_this) { - return function() { - var n; - return (function() { - var _i, _len, _ref, _results; - _ref = this.tree_widget.getSelectedNodes(); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - n = _ref[_i]; - _results.push(n.id); - } - return _results; - }).call(_this); - }; - })(this); + MouseWidget.prototype._getPositionInfo = function(e) { return { - open_nodes: getOpenNodeIds(), - selected_node: getSelectedNodeIds() + page_x: e.pageX, + page_y: e.pageY, + target: e.target, + original_event: e }; }; - SaveStateHandler.prototype.setState = function(state) { - var node_id, open_nodes, selected_node, selected_node_ids, _i, _len, _results; - if (state) { - open_nodes = state.open_nodes; - selected_node_ids = state.selected_node; - this.tree_widget.tree.iterate((function(_this) { - return function(node) { - node.is_open = node.id && node.hasChildren() && (indexOf(open_nodes, node.id) >= 0); - return true; - }; - })(this)); - if (selected_node_ids && this.tree_widget.select_node_handler) { - this.tree_widget.select_node_handler.clear(); - _results = []; - for (_i = 0, _len = selected_node_ids.length; _i < _len; _i++) { - node_id = selected_node_ids[_i]; - selected_node = this.tree_widget.getNodeById(node_id); - if (selected_node) { - _results.push(this.tree_widget.select_node_handler.addToSelection(selected_node)); - } else { - _results.push(void 0); - } - } - return _results; - } - } + MouseWidget.prototype._mouseUp = function(e) { + return this._handleMouseUp(this._getPositionInfo(e)); }; - SaveStateHandler.prototype.getCookieName = function() { - if (typeof this.tree_widget.options.saveState === 'string') { - return this.tree_widget.options.saveState; - } else { - return 'tree'; + MouseWidget.prototype._handleMouseUp = function(position_info) { + var $document; + $document = $(document); + $document.unbind('mousemove.mousewidget'); + $document.unbind('touchmove.mousewidget'); + $document.unbind('mouseup.mousewidget'); + $document.unbind('touchend.mousewidget'); + if (this.is_mouse_started) { + this.is_mouse_started = false; + this._mouseStop(position_info); } }; - SaveStateHandler.prototype.supportsLocalStorage = function() { - var testSupport; - testSupport = function() { - var error, key; - if (typeof localStorage === "undefined" || localStorage === null) { - return false; - } else { - try { - key = '_storage_test'; - sessionStorage.setItem(key, true); - sessionStorage.removeItem(key); - } catch (_error) { - error = _error; - return false; - } - return true; - } - }; - if (this._supportsLocalStorage == null) { - this._supportsLocalStorage = testSupport(); - } - return this._supportsLocalStorage; + MouseWidget.prototype._mouseCapture = function(position_info) { + return true; }; - SaveStateHandler.prototype.getNodeIdToBeSelected = function() { - var state; - state = this.getStateFromStorage(); - if (state && state.selected_node) { - return state.selected_node[0]; - } else { - return null; - } + MouseWidget.prototype._mouseStart = function(position_info) { + return null; }; - return SaveStateHandler; - - })(); + MouseWidget.prototype._mouseDrag = function(position_info) { + return null; + }; - SelectNodeHandler = (function() { - function SelectNodeHandler(tree_widget) { - this.tree_widget = tree_widget; - this.clear(); - } + MouseWidget.prototype._mouseStop = function(position_info) { + return null; + }; - SelectNodeHandler.prototype.getSelectedNode = function() { - var selected_nodes; - selected_nodes = this.getSelectedNodes(); - if (selected_nodes.length) { - return selected_nodes[0]; - } else { - return false; - } + MouseWidget.prototype.setMouseDelay = function(mouse_delay) { + return this.mouse_delay = mouse_delay; }; - SelectNodeHandler.prototype.getSelectedNodes = function() { - var id, node, selected_nodes; - if (this.selected_single_node) { - return [this.selected_single_node]; - } else { - selected_nodes = []; - for (id in this.selected_nodes) { - node = this.tree_widget.getNodeById(id); - if (node) { - selected_nodes.push(node); - } - } - return selected_nodes; + MouseWidget.prototype._touchStart = function(e) { + var touch; + if (e.originalEvent.touches.length > 1) { + return; } + touch = e.originalEvent.changedTouches[0]; + return this._handleMouseDown(e, this._getPositionInfo(touch)); }; - SelectNodeHandler.prototype.getSelectedNodesUnder = function(parent) { - var id, node, selected_nodes; - if (this.selected_single_node) { - if (parent.isParentOf(this.selected_single_node)) { - return [this.selected_single_node]; - } else { - return []; - } - } else { - selected_nodes = []; - for (id in this.selected_nodes) { - node = this.tree_widget.getNodeById(id); - if (node && parent.isParentOf(node)) { - selected_nodes.push(node); - } - } - return selected_nodes; + MouseWidget.prototype._touchMove = function(e) { + var touch; + if (e.originalEvent.touches.length > 1) { + return; } + touch = e.originalEvent.changedTouches[0]; + return this._handleMouseMove(e, this._getPositionInfo(touch)); }; - SelectNodeHandler.prototype.isNodeSelected = function(node) { - if (node.id) { - return this.selected_nodes[node.id]; - } else if (this.selected_single_node) { - return this.selected_single_node.element === node.element; - } else { - return false; + MouseWidget.prototype._touchEnd = function(e) { + var touch; + if (e.originalEvent.touches.length > 1) { + return; } + touch = e.originalEvent.changedTouches[0]; + return this._handleMouseUp(this._getPositionInfo(touch)); }; - SelectNodeHandler.prototype.clear = function() { - this.selected_nodes = {}; - return this.selected_single_node = null; - }; + return MouseWidget; - SelectNodeHandler.prototype.removeFromSelection = function(node, include_children) { - if (include_children == null) { - include_children = false; - } - if (!node.id) { - if (this.selected_single_node && node.element === this.selected_single_node.element) { - return this.selected_single_node = null; - } - } else { - delete this.selected_nodes[node.id]; - if (include_children) { - return node.iterate((function(_this) { - return function(n) { - delete _this.selected_nodes[node.id]; - return true; - }; - })(this)); + })(SimpleWidget); + + module.exports = MouseWidget; + +}).call(this); + +},{"./simple.widget":11}],6:[function(require,module,exports){ +(function() { + var Node, Position; + + Position = { + getName: function(position) { + return Position.strings[position - 1]; + }, + nameToIndex: function(name) { + var i, _i, _ref; + for (i = _i = 1, _ref = Position.strings.length; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) { + if (Position.strings[i - 1] === name) { + return i; } } - }; + return 0; + } + }; - SelectNodeHandler.prototype.addToSelection = function(node) { - if (node.id) { - return this.selected_nodes[node.id] = true; - } else { - return this.selected_single_node = node; - } - }; + Position.BEFORE = 1; - return SelectNodeHandler; + Position.AFTER = 2; - })(); + Position.INSIDE = 3; - DragAndDropHandler = (function() { - function DragAndDropHandler(tree_widget) { - this.tree_widget = tree_widget; - this.hovered_area = null; - this.$ghost = null; - this.hit_areas = []; - this.is_dragging = false; - this.current_item = null; - } + Position.NONE = 4; - DragAndDropHandler.prototype.mouseCapture = function(position_info) { - var $element, node_element; - $element = $(position_info.target); - if (!this.mustCaptureElement($element)) { - return null; - } - if (this.tree_widget.options.onIsMoveHandle && !this.tree_widget.options.onIsMoveHandle($element)) { - return null; + Position.strings = ['before', 'after', 'inside', 'none']; + + Node = (function() { + function Node(o, is_root, node_class) { + if (is_root == null) { + is_root = false; } - node_element = this.tree_widget._getNodeElement($element); - if (node_element && this.tree_widget.options.onCanMove) { - if (!this.tree_widget.options.onCanMove(node_element.node)) { - node_element = null; - } + if (node_class == null) { + node_class = Node; } - this.current_item = node_element; - return this.current_item !== null; - }; - - DragAndDropHandler.prototype.mouseStart = function(position_info) { - var offset; - this.refresh(); - offset = $(position_info.target).offset(); - 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); - this.is_dragging = true; - this.current_item.$element.addClass('jqtree-moving'); - return true; - }; + this.setData(o); + this.children = []; + this.parent = null; + if (is_root) { + this.id_mapping = {}; + this.tree = this; + this.node_class = node_class; + } + } - DragAndDropHandler.prototype.mouseDrag = function(position_info) { - var area, can_move_to; - this.drag_element.move(position_info.page_x, position_info.page_y); - area = this.findHoveredArea(position_info.page_x, position_info.page_y); - can_move_to = this.canMoveToArea(area); - if (can_move_to && area) { - if (!area.node.isFolder()) { - this.stopOpenFolderTimer(); - } - if (this.hovered_area !== area) { - this.hovered_area = area; - if (this.mustOpenFolderTimer(area)) { - this.startOpenFolderTimer(area.node); + Node.prototype.setData = function(o) { + var key, value, _results; + if (typeof o !== 'object') { + return this.name = o; + } else { + _results = []; + for (key in o) { + value = o[key]; + if (key === 'label') { + _results.push(this.name = value); } else { - this.stopOpenFolderTimer(); + _results.push(this[key] = value); } - this.updateDropHint(); } - } else { - this.removeHover(); - this.removeDropHint(); - this.stopOpenFolderTimer(); + return _results; } - return true; }; - DragAndDropHandler.prototype.mustCaptureElement = function($element) { - return !$element.is('input,select'); + Node.prototype.initFromData = function(data) { + var addChildren, addNode; + addNode = (function(_this) { + return function(node_data) { + _this.setData(node_data); + if (node_data.children) { + return addChildren(node_data.children); + } + }; + })(this); + addChildren = (function(_this) { + return function(children_data) { + var child, node, _i, _len; + for (_i = 0, _len = children_data.length; _i < _len; _i++) { + child = children_data[_i]; + node = new _this.tree.node_class(''); + node.initFromData(child); + _this.addChild(node); + } + return null; + }; + })(this); + addNode(data); + return null; }; - DragAndDropHandler.prototype.canMoveToArea = function(area) { - var position_name; - if (!area) { - return false; - } else if (this.tree_widget.options.onCanMoveTo) { - position_name = Position.getName(area.position); - return this.tree_widget.options.onCanMoveTo(this.current_item.node, area.node, position_name); - } else { - return true; - } - }; - DragAndDropHandler.prototype.mouseStop = function(position_info) { - this.moveItem(position_info); - this.clear(); - this.removeHover(); - this.removeDropHint(); - this.removeHitAreas(); - if (this.current_item) { - this.current_item.$element.removeClass('jqtree-moving'); - this.current_item = null; - } - this.is_dragging = false; - return false; - }; + /* + Create tree from data. + + Structure of data is: + [ + { + label: 'node1', + children: [ + { label: 'child1' }, + { label: 'child2' } + ] + }, + { + label: 'node2' + } + ] + */ - DragAndDropHandler.prototype.refresh = function() { - this.removeHitAreas(); - if (this.current_item) { - this.generateHitAreas(); - this.current_item = this.tree_widget._getNodeElementForNode(this.current_item.node); - if (this.is_dragging) { - return this.current_item.$element.addClass('jqtree-moving'); + Node.prototype.loadFromData = function(data) { + var node, o, _i, _len; + this.removeChildren(); + for (_i = 0, _len = data.length; _i < _len; _i++) { + o = data[_i]; + node = new this.tree.node_class(o); + this.addChild(node); + if (typeof o === 'object' && o.children) { + node.loadFromData(o.children); } } + return null; }; - DragAndDropHandler.prototype.removeHitAreas = function() { - return this.hit_areas = []; - }; - DragAndDropHandler.prototype.clear = function() { - this.drag_element.remove(); - return this.drag_element = null; - }; + /* + Add child. + + tree.addChild( + new Node('child1') + ); + */ - DragAndDropHandler.prototype.removeDropHint = function() { - if (this.previous_ghost) { - return this.previous_ghost.remove(); - } + Node.prototype.addChild = function(node) { + this.children.push(node); + return node._setParent(this); }; - DragAndDropHandler.prototype.removeHover = function() { - return this.hovered_area = null; - }; - DragAndDropHandler.prototype.generateHitAreas = function() { - var hit_areas_generator; - hit_areas_generator = new HitAreasGenerator(this.tree_widget.tree, this.current_item.node, this.getTreeDimensions().bottom); - return this.hit_areas = hit_areas_generator.generate(); - }; + /* + Add child at position. Index starts at 0. + + tree.addChildAtPosition( + new Node('abc'), + 1 + ); + */ - DragAndDropHandler.prototype.findHoveredArea = function(x, y) { - var area, dimensions, high, low, mid; - dimensions = this.getTreeDimensions(); - if (x < dimensions.left || y < dimensions.top || x > dimensions.right || y > dimensions.bottom) { - return null; - } - low = 0; - high = this.hit_areas.length; - while (low < high) { - mid = (low + high) >> 1; - area = this.hit_areas[mid]; - if (y < area.top) { - high = mid; - } else if (y > area.bottom) { - low = mid + 1; - } else { - return area; - } - } - return null; + Node.prototype.addChildAtPosition = function(node, index) { + this.children.splice(index, 0, node); + return node._setParent(this); }; - DragAndDropHandler.prototype.mustOpenFolderTimer = function(area) { - var node; - node = area.node; - return node.isFolder() && !node.is_open && area.position === Position.INSIDE; + Node.prototype._setParent = function(parent) { + this.parent = parent; + this.tree = parent.tree; + return this.tree.addNodeToIndex(this); }; - DragAndDropHandler.prototype.updateDropHint = function() { - var node_element; - if (!this.hovered_area) { - return; - } - this.removeDropHint(); - node_element = this.tree_widget._getNodeElementForNode(this.hovered_area.node); - return this.previous_ghost = node_element.addDropHint(this.hovered_area.position); - }; - DragAndDropHandler.prototype.startOpenFolderTimer = function(folder) { - var openFolder; - openFolder = (function(_this) { - return function() { - return _this.tree_widget._openNode(folder, _this.tree_widget.options.slide, function() { - _this.refresh(); - return _this.updateDropHint(); - }); - }; - })(this); - this.stopOpenFolderTimer(); - return this.open_folder_timer = setTimeout(openFolder, this.tree_widget.options.openFolderDelay); - }; + /* + Remove child. This also removes the children of the node. + + tree.removeChild(tree.children[0]); + */ - DragAndDropHandler.prototype.stopOpenFolderTimer = function() { - if (this.open_folder_timer) { - clearTimeout(this.open_folder_timer); - return this.open_folder_timer = null; - } + Node.prototype.removeChild = function(node) { + node.removeChildren(); + return this._removeChild(node); }; - DragAndDropHandler.prototype.moveItem = function(position_info) { - var doMove, event, moved_node, position, previous_parent, target_node; - if (this.hovered_area && this.hovered_area.position !== Position.NONE && this.canMoveToArea(this.hovered_area)) { - moved_node = this.current_item.node; - target_node = this.hovered_area.node; - position = this.hovered_area.position; - previous_parent = moved_node.parent; - if (position === Position.INSIDE) { - this.hovered_area.node.is_open = true; - } - doMove = (function(_this) { - return function() { - _this.tree_widget.tree.moveNode(moved_node, target_node, position); - _this.tree_widget.element.empty(); - return _this.tree_widget._refreshElements(); - }; - })(this); - event = this.tree_widget._triggerEvent('tree.move', { - move_info: { - moved_node: moved_node, - target_node: target_node, - position: Position.getName(position), - previous_parent: previous_parent, - do_move: doMove, - original_event: position_info.original_event - } - }); - if (!event.isDefaultPrevented()) { - return doMove(); - } - } + Node.prototype._removeChild = function(node) { + this.children.splice(this.getChildIndex(node), 1); + return this.tree.removeNodeFromIndex(node); }; - DragAndDropHandler.prototype.getTreeDimensions = function() { - var offset; - offset = this.tree_widget.element.offset(); - return { - left: offset.left, - top: offset.top, - right: offset.left + this.tree_widget.element.width(), - bottom: offset.top + this.tree_widget.element.height() + 16 - }; - }; - return DragAndDropHandler; + /* + Get child index. + + var index = getChildIndex(node); + */ - })(); + Node.prototype.getChildIndex = function(node) { + return $.inArray(node, this.children); + }; - VisibleNodeIterator = (function() { - function VisibleNodeIterator(tree) { - this.tree = tree; + + /* + Does the tree have children? + + if (tree.hasChildren()) { + // } + */ - VisibleNodeIterator.prototype.iterate = function() { - var is_first_node, _iterateNode; - is_first_node = true; - _iterateNode = (function(_this) { - return function(node, next_node) { - var $element, child, children_length, i, must_iterate_inside, _i, _len, _ref; - must_iterate_inside = (node.is_open || !node.element) && node.hasChildren(); - if (node.element) { - $element = $(node.element); - if (!$element.is(':visible')) { - return; - } - if (is_first_node) { - _this.handleFirstNode(node, $element); - is_first_node = false; - } - if (!node.hasChildren()) { - _this.handleNode(node, next_node, $element); - } else if (node.is_open) { - if (!_this.handleOpenFolder(node, $element)) { - must_iterate_inside = false; - } - } else { - _this.handleClosedFolder(node, next_node, $element); - } - } - if (must_iterate_inside) { - children_length = node.children.length; + Node.prototype.hasChildren = function() { + return this.children.length !== 0; + }; + + Node.prototype.isFolder = function() { + return this.hasChildren() || this.load_on_demand; + }; + + + /* + Iterate over all the nodes in the tree. + + Calls callback with (node, level). + + The callback must return true to continue the iteration on current node. + + tree.iterate( + function(node, level) { + console.log(node.name); + + // stop iteration after level 2 + return (level <= 2); + } + ); + */ + + Node.prototype.iterate = function(callback) { + var _iterate; + _iterate = (function(_this) { + return function(node, level) { + var child, result, _i, _len, _ref; + if (node.children) { _ref = node.children; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - child = _ref[i]; - if (i === (children_length - 1)) { - _iterateNode(node.children[i], null); - } else { - _iterateNode(node.children[i], node.children[i + 1]); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + result = callback(child, level); + if (_this.hasChildren() && result) { + _iterate(child, level + 1); } } - if (node.is_open) { - return _this.handleAfterOpenFolder(node, next_node, $element); - } + return null; } }; })(this); - return _iterateNode(this.tree, null); + _iterate(this, 0); + return null; }; - VisibleNodeIterator.prototype.handleNode = function(node, next_node, $element) {}; - - VisibleNodeIterator.prototype.handleOpenFolder = function(node, $element) {}; - - VisibleNodeIterator.prototype.handleClosedFolder = function(node, next_node, $element) {}; - - VisibleNodeIterator.prototype.handleAfterOpenFolder = function(node, next_node, $element) {}; - - VisibleNodeIterator.prototype.handleFirstNode = function(node, $element) {}; - - return VisibleNodeIterator; - })(); + /* + Move node relative to another node. + + Argument position: Position.BEFORE, Position.AFTER or Position.Inside + + // move node1 after node2 + tree.moveNode(node1, node2, Position.AFTER); + */ - HitAreasGenerator = (function(_super) { - __extends(HitAreasGenerator, _super); + Node.prototype.moveNode = function(moved_node, target_node, position) { + if (moved_node.isParentOf(target_node)) { + return; + } + moved_node.parent._removeChild(moved_node); + if (position === Position.AFTER) { + return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node) + 1); + } else if (position === Position.BEFORE) { + return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node)); + } else if (position === Position.INSIDE) { + return target_node.addChildAtPosition(moved_node, 0); + } + }; - function HitAreasGenerator(tree, current_node, tree_bottom) { - HitAreasGenerator.__super__.constructor.call(this, tree); - this.current_node = current_node; - this.tree_bottom = tree_bottom; - } - HitAreasGenerator.prototype.generate = function() { - this.positions = []; - this.last_top = 0; - this.iterate(); - return this.generateHitAreas(this.positions); - }; + /* + Get the tree as data. + */ - HitAreasGenerator.prototype.getTop = function($element) { - return $element.offset().top; + Node.prototype.getData = function() { + var getDataFromNodes; + getDataFromNodes = (function(_this) { + return function(nodes) { + var data, k, node, tmp_node, v, _i, _len; + data = []; + for (_i = 0, _len = nodes.length; _i < _len; _i++) { + node = nodes[_i]; + tmp_node = {}; + for (k in node) { + v = node[k]; + if ((k !== 'parent' && k !== 'children' && k !== 'element' && k !== 'tree') && Object.prototype.hasOwnProperty.call(node, k)) { + tmp_node[k] = v; + } + } + if (node.hasChildren()) { + tmp_node.children = getDataFromNodes(node.children); + } + data.push(tmp_node); + } + return data; + }; + })(this); + return getDataFromNodes(this.children); }; - HitAreasGenerator.prototype.addPosition = function(node, position, top) { - var area; - area = { - top: top, - node: node, - position: position - }; - this.positions.push(area); - return this.last_top = top; + Node.prototype.getNodeByName = function(name) { + var result; + result = null; + this.iterate(function(node) { + if (node.name === name) { + result = node; + return false; + } else { + return true; + } + }); + return result; }; - HitAreasGenerator.prototype.handleNode = function(node, next_node, $element) { - var top; - top = this.getTop($element); - if (node === this.current_node) { - this.addPosition(node, Position.NONE, top); - } else { - this.addPosition(node, Position.INSIDE, top); - } - if (next_node === this.current_node || node === this.current_node) { - return this.addPosition(node, Position.NONE, top); + Node.prototype.addAfter = function(node_info) { + var child_index, node; + if (!this.parent) { + return null; } else { - return this.addPosition(node, Position.AFTER, top); + node = new this.tree.node_class(node_info); + child_index = this.parent.getChildIndex(this); + this.parent.addChildAtPosition(node, child_index + 1); + return node; } }; - HitAreasGenerator.prototype.handleOpenFolder = function(node, $element) { - if (node === this.current_node) { - return false; - } - if (node.children[0] !== this.current_node) { - this.addPosition(node, Position.INSIDE, this.getTop($element)); + Node.prototype.addBefore = function(node_info) { + var child_index, node; + if (!this.parent) { + return null; + } else { + node = new this.tree.node_class(node_info); + child_index = this.parent.getChildIndex(this); + this.parent.addChildAtPosition(node, child_index); + return node; } - return true; }; - HitAreasGenerator.prototype.handleClosedFolder = function(node, next_node, $element) { - var top; - top = this.getTop($element); - if (node === this.current_node) { - return this.addPosition(node, Position.NONE, top); + Node.prototype.addParent = function(node_info) { + var child, new_parent, original_parent, _i, _len, _ref; + if (!this.parent) { + return null; } else { - this.addPosition(node, Position.INSIDE, top); - if (next_node !== this.current_node) { - return this.addPosition(node, Position.AFTER, top); + new_parent = new this.tree.node_class(node_info); + new_parent._setParent(this.tree); + original_parent = this.parent; + _ref = original_parent.children; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + new_parent.addChild(child); } + original_parent.children = []; + original_parent.addChild(new_parent); + return new_parent; } }; - HitAreasGenerator.prototype.handleFirstNode = function(node, $element) { - if (node !== this.current_node) { - return this.addPosition(node, Position.BEFORE, this.getTop($(node.element))); + Node.prototype.remove = function() { + if (this.parent) { + this.parent.removeChild(this); + return this.parent = null; } }; - HitAreasGenerator.prototype.handleAfterOpenFolder = function(node, next_node, $element) { - if (node === this.current_node.node || next_node === this.current_node.node) { - return this.addPosition(node, Position.NONE, this.last_top); - } else { - return this.addPosition(node, Position.AFTER, this.last_top); - } + Node.prototype.append = function(node_info) { + var node; + node = new this.tree.node_class(node_info); + this.addChild(node); + return node; }; - HitAreasGenerator.prototype.generateHitAreas = function(positions) { - var group, hit_areas, position, previous_top, _i, _len; - previous_top = -1; - group = []; - hit_areas = []; - for (_i = 0, _len = positions.length; _i < _len; _i++) { - position = positions[_i]; - if (position.top !== previous_top && group.length) { - if (group.length) { - this.generateHitAreasForGroup(hit_areas, group, previous_top, position.top); - } - previous_top = position.top; - group = []; + Node.prototype.prepend = function(node_info) { + var node; + node = new this.tree.node_class(node_info); + this.addChildAtPosition(node, 0); + return node; + }; + + Node.prototype.isParentOf = function(node) { + var parent; + parent = node.parent; + while (parent) { + if (parent === this) { + return true; } - group.push(position); + parent = parent.parent; } - this.generateHitAreasForGroup(hit_areas, group, previous_top, this.tree_bottom); - return hit_areas; + return false; }; - HitAreasGenerator.prototype.generateHitAreasForGroup = function(hit_areas, positions_in_group, top, bottom) { - var area_height, area_top, i, position, position_count; - position_count = Math.min(positions_in_group.length, 4); - area_height = Math.round((bottom - top) / position_count); - area_top = top; - i = 0; - while (i < position_count) { - position = positions_in_group[i]; - hit_areas.push({ - top: area_top, - bottom: area_top + area_height, - node: position.node, - position: position.position - }); - area_top += area_height; - i += 1; + Node.prototype.getLevel = function() { + var level, node; + level = 0; + node = this; + while (node.parent) { + level += 1; + node = node.parent; } - return null; + return level; }; - return HitAreasGenerator; - - })(VisibleNodeIterator); - - DragElement = (function() { - function DragElement(node, offset_x, offset_y, $tree) { - this.offset_x = offset_x; - this.offset_y = offset_y; - this.$element = $("" + node.name + ""); - this.$element.css("position", "absolute"); - $tree.append(this.$element); - } - - DragElement.prototype.move = function(page_x, page_y) { - return this.$element.offset({ - left: page_x - this.offset_x, - top: page_y - this.offset_y - }); + Node.prototype.getNodeById = function(node_id) { + return this.id_mapping[node_id]; }; - DragElement.prototype.remove = function() { - return this.$element.remove(); + Node.prototype.addNodeToIndex = function(node) { + if (node.id != null) { + return this.id_mapping[node.id] = node; + } }; - return DragElement; + Node.prototype.removeNodeFromIndex = function(node) { + if (node.id != null) { + return delete this.id_mapping[node.id]; + } + }; - })(); + Node.prototype.removeChildren = function() { + this.iterate((function(_this) { + return function(child) { + _this.tree.removeNodeFromIndex(child); + return true; + }; + })(this)); + return this.children = []; + }; - GhostDropHint = (function() { - function GhostDropHint(node, $element, position) { - this.$element = $element; - this.node = node; - this.$ghost = $('
  • '); - if (position === Position.AFTER) { - this.moveAfter(); - } else if (position === Position.BEFORE) { - this.moveBefore(); - } else if (position === Position.INSIDE) { - if (node.isFolder() && node.is_open) { - this.moveInsideOpenFolder(); + Node.prototype.getPreviousSibling = function() { + var previous_index; + if (!this.parent) { + return null; + } else { + previous_index = this.parent.getChildIndex(this) - 1; + if (previous_index >= 0) { + return this.parent.children[previous_index]; } else { - this.moveInside(); + return null; } } - } - - GhostDropHint.prototype.remove = function() { - return this.$ghost.remove(); - }; - - GhostDropHint.prototype.moveAfter = function() { - return this.$element.after(this.$ghost); }; - GhostDropHint.prototype.moveBefore = function() { - return this.$element.before(this.$ghost); + Node.prototype.getNextSibling = function() { + var next_index; + if (!this.parent) { + return null; + } else { + next_index = this.parent.getChildIndex(this) + 1; + if (next_index < this.parent.children.length) { + return this.parent.children[next_index]; + } else { + return null; + } + } }; - GhostDropHint.prototype.moveInsideOpenFolder = function() { - return $(this.node.children[0].element).before(this.$ghost); + Node.prototype.getNodesByProperty = function(key, value) { + return this.filter(function(node) { + return node[key] === value; + }); }; - GhostDropHint.prototype.moveInside = function() { - this.$element.after(this.$ghost); - return this.$ghost.addClass('jqtree-inside'); + Node.prototype.filter = function(f) { + var result; + result = []; + this.iterate(function(node) { + if (f(node)) { + result.push(node); + } + return true; + }); + return result; }; - return GhostDropHint; + return Node; })(); - BorderDropHint = (function() { - function BorderDropHint($element) { - var $div, width; - $div = $element.children('.jqtree-element'); - width = $element.width() - 4; - this.$hint = $(''); - $div.append(this.$hint); - this.$hint.css({ - width: width, - height: $div.height() - 4 - }); - } + module.exports = { + Node: Node, + Position: Position + }; - BorderDropHint.prototype.remove = function() { - return this.$hint.remove(); - }; +}).call(this); - return BorderDropHint; +},{}],7:[function(require,module,exports){ +(function() { + var BorderDropHint, FolderElement, GhostDropHint, NodeElement, Position, node, + __hasProp = {}.hasOwnProperty, + __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; }; - })(); + node = require('./node'); - ScrollHandler = (function() { - function ScrollHandler(tree_widget) { - this.tree_widget = tree_widget; - this.previous_top = -1; - this._initScrollParent(); + Position = node.Position; + + NodeElement = (function() { + function NodeElement(node, tree_widget) { + this.init(node, tree_widget); } - ScrollHandler.prototype._initScrollParent = function() { - var $scroll_parent, getParentWithOverflow, setDocumentAsScrollParent; - getParentWithOverflow = (function(_this) { - return function() { - var css_values, el, hasOverFlow, _i, _len, _ref; - css_values = ['overflow', 'overflow-y']; - hasOverFlow = function(el) { - var css_value, _i, _len, _ref; - for (_i = 0, _len = css_values.length; _i < _len; _i++) { - css_value = css_values[_i]; - if ((_ref = $.css(el, css_value)) === 'auto' || _ref === 'scroll') { - return true; - } - } - return false; - }; - if (hasOverFlow(_this.tree_widget.$el[0])) { - return _this.tree_widget.$el; - } - _ref = _this.tree_widget.$el.parents(); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - el = _ref[_i]; - if (hasOverFlow(el)) { - return $(el); - } - } - return null; - }; - })(this); - setDocumentAsScrollParent = (function(_this) { - return function() { - _this.scroll_parent_top = 0; - return _this.$scroll_parent = null; - }; - })(this); - if (this.tree_widget.$el.css('position') === 'fixed') { - setDocumentAsScrollParent(); + NodeElement.prototype.init = function(node, tree_widget) { + this.node = node; + this.tree_widget = tree_widget; + if (!node.element) { + node.element = this.tree_widget.element; } - $scroll_parent = getParentWithOverflow(); - if ($scroll_parent && $scroll_parent.length && $scroll_parent[0].tagName !== 'HTML') { - this.$scroll_parent = $scroll_parent; - return this.scroll_parent_top = this.$scroll_parent.offset().top; + return this.$element = $(node.element); + }; + + NodeElement.prototype.getUl = function() { + return this.$element.children('ul:first'); + }; + + NodeElement.prototype.getSpan = function() { + return this.$element.children('.jqtree-element').find('span.jqtree-title'); + }; + + NodeElement.prototype.getLi = function() { + return this.$element; + }; + + NodeElement.prototype.addDropHint = function(position) { + if (position === Position.INSIDE) { + return new BorderDropHint(this.$element); } else { - return setDocumentAsScrollParent(); + return new GhostDropHint(this.node, this.$element, position); } }; - ScrollHandler.prototype.checkScrolling = function() { - var hovered_area; - hovered_area = this.tree_widget.dnd_handler.hovered_area; - if (hovered_area && hovered_area.top !== this.previous_top) { - this.previous_top = hovered_area.top; - if (this.$scroll_parent) { - return this._handleScrollingWithScrollParent(hovered_area); + NodeElement.prototype.select = function() { + return this.getLi().addClass('jqtree-selected'); + }; + + NodeElement.prototype.deselect = function() { + return this.getLi().removeClass('jqtree-selected'); + }; + + return NodeElement; + + })(); + + FolderElement = (function(_super) { + __extends(FolderElement, _super); + + function FolderElement() { + return FolderElement.__super__.constructor.apply(this, arguments); + } + + FolderElement.prototype.open = function(on_finished, slide) { + var $button, doOpen; + if (slide == null) { + slide = true; + } + if (!this.node.is_open) { + this.node.is_open = true; + $button = this.getButton(); + $button.removeClass('jqtree-closed'); + $button.html(''); + $button.append(this.tree_widget.renderer.opened_icon_element.cloneNode()); + doOpen = (function(_this) { + return function() { + _this.getLi().removeClass('jqtree-closed'); + if (on_finished) { + on_finished(); + } + return _this.tree_widget._triggerEvent('tree.open', { + node: _this.node + }); + }; + })(this); + if (slide) { + return this.getUl().slideDown('fast', doOpen); } else { - return this._handleScrollingWithDocument(hovered_area); + this.getUl().show(); + return doOpen(); } } }; - ScrollHandler.prototype._handleScrollingWithScrollParent = function(area) { - var distance_bottom; - distance_bottom = this.scroll_parent_top + this.$scroll_parent[0].offsetHeight - area.bottom; - if (distance_bottom < 20) { - this.$scroll_parent[0].scrollTop += 20; - this.tree_widget.refreshHitAreas(); - return this.previous_top = -1; - } else if ((area.top - this.scroll_parent_top) < 20) { - this.$scroll_parent[0].scrollTop -= 20; - this.tree_widget.refreshHitAreas(); - return this.previous_top = -1; + FolderElement.prototype.close = function(slide) { + var $button, doClose; + if (slide == null) { + slide = true; } - }; - - ScrollHandler.prototype._handleScrollingWithDocument = function(area) { - var distance_top; - distance_top = area.top - $(document).scrollTop(); - if (distance_top < 20) { - return $(document).scrollTop($(document).scrollTop() - 20); - } else if ($(window).height() - (area.bottom - $(document).scrollTop()) < 20) { - return $(document).scrollTop($(document).scrollTop() + 20); + if (this.node.is_open) { + this.node.is_open = false; + $button = this.getButton(); + $button.addClass('jqtree-closed'); + $button.html(''); + $button.append(this.tree_widget.renderer.closed_icon_element.cloneNode()); + doClose = (function(_this) { + return function() { + _this.getLi().addClass('jqtree-closed'); + return _this.tree_widget._triggerEvent('tree.close', { + node: _this.node + }); + }; + })(this); + if (slide) { + return this.getUl().slideUp('fast', doClose); + } else { + this.getUl().hide(); + return doClose(); + } } }; - ScrollHandler.prototype.scrollTo = function(top) { - var tree_top; - if (this.$scroll_parent) { - return this.$scroll_parent[0].scrollTop = top; - } else { - tree_top = this.tree_widget.$el.offset().top; - return $(document).scrollTop(top + tree_top); - } + FolderElement.prototype.getButton = function() { + return this.$element.children('.jqtree-element').find('a.jqtree-toggler'); }; - ScrollHandler.prototype.isScrolledIntoView = function(element) { - var $element, element_bottom, element_top, view_bottom, view_top; - $element = $(element); - if (this.$scroll_parent) { - view_top = 0; - view_bottom = this.$scroll_parent.height(); - element_top = $element.offset().top - this.scroll_parent_top; - element_bottom = element_top + $element.height(); + FolderElement.prototype.addDropHint = function(position) { + if (!this.node.is_open && position === Position.INSIDE) { + return new BorderDropHint(this.$element); } else { - view_top = $(window).scrollTop(); - view_bottom = view_top + $(window).height(); - element_top = $element.offset().top; - element_bottom = element_top + $element.height(); + return new GhostDropHint(this.node, this.$element, position); } - return (element_bottom <= view_bottom) && (element_top >= view_top); }; - return ScrollHandler; - - })(); + return FolderElement; - KeyHandler = (function() { - var DOWN, LEFT, RIGHT, UP; + })(NodeElement); - LEFT = 37; + BorderDropHint = (function() { + function BorderDropHint($element) { + var $div, width; + $div = $element.children('.jqtree-element'); + width = $element.width() - 4; + this.$hint = $(''); + $div.append(this.$hint); + this.$hint.css({ + width: width, + height: $div.height() - 4 + }); + } - UP = 38; + BorderDropHint.prototype.remove = function() { + return this.$hint.remove(); + }; - RIGHT = 39; + return BorderDropHint; - DOWN = 40; + })(); - function KeyHandler(tree_widget) { - this.tree_widget = tree_widget; - if (tree_widget.options.keyboardSupport) { - $(document).bind('keydown.jqtree', $.proxy(this.handleKeyDown, this)); + GhostDropHint = (function() { + function GhostDropHint(node, $element, position) { + this.$element = $element; + this.node = node; + this.$ghost = $('
  • '); + if (position === Position.AFTER) { + this.moveAfter(); + } else if (position === Position.BEFORE) { + this.moveBefore(); + } else if (position === Position.INSIDE) { + if (node.isFolder() && node.is_open) { + this.moveInsideOpenFolder(); + } else { + this.moveInside(); + } } } - KeyHandler.prototype.deinit = function() { - return $(document).unbind('keydown.jqtree'); + GhostDropHint.prototype.remove = function() { + return this.$ghost.remove(); }; - KeyHandler.prototype.handleKeyDown = function(e) { - var current_node, key, moveDown, moveLeft, moveRight, moveUp, selectNode; - if (!this.tree_widget.options.keyboardSupport) { - return; - } - if ($(document.activeElement).is('textarea,input,select')) { - return true; - } - current_node = this.tree_widget.getSelectedNode(); - selectNode = (function(_this) { - return function(node) { - if (node) { - _this.tree_widget.selectNode(node); - if (_this.tree_widget.scroll_handler && (!_this.tree_widget.scroll_handler.isScrolledIntoView($(node.element).find('.jqtree-element')))) { - _this.tree_widget.scrollToNode(node); - } - return false; - } else { - return true; - } - }; - })(this); - moveDown = (function(_this) { - return function() { - return selectNode(_this.getNextNode(current_node)); - }; - })(this); - moveUp = (function(_this) { + GhostDropHint.prototype.moveAfter = function() { + return this.$element.after(this.$ghost); + }; + + GhostDropHint.prototype.moveBefore = function() { + return this.$element.before(this.$ghost); + }; + + GhostDropHint.prototype.moveInsideOpenFolder = function() { + return $(this.node.children[0].element).before(this.$ghost); + }; + + GhostDropHint.prototype.moveInside = function() { + this.$element.after(this.$ghost); + return this.$ghost.addClass('jqtree-inside'); + }; + + return GhostDropHint; + + })(); + + module.exports = { + FolderElement: FolderElement, + NodeElement: NodeElement + }; + +}).call(this); + +},{"./node":6}],8:[function(require,module,exports){ +(function() { + var SaveStateHandler, indexOf, isInt, util; + + util = require('./util'); + + indexOf = util.indexOf; + + isInt = util.isInt; + + SaveStateHandler = (function() { + function SaveStateHandler(tree_widget) { + this.tree_widget = tree_widget; + } + + SaveStateHandler.prototype.saveState = function() { + var state; + state = JSON.stringify(this.getState()); + if (this.tree_widget.options.onSetStateFromStorage) { + return this.tree_widget.options.onSetStateFromStorage(state); + } else if (this.supportsLocalStorage()) { + return localStorage.setItem(this.getCookieName(), state); + } else if ($.cookie) { + $.cookie.raw = true; + return $.cookie(this.getCookieName(), state, { + path: '/' + }); + } + }; + + SaveStateHandler.prototype.restoreState = function() { + var state; + state = this.getStateFromStorage(); + if (state) { + this.setState(state); + return true; + } else { + return false; + } + }; + + SaveStateHandler.prototype.getStateFromStorage = function() { + var json_data; + json_data = this._loadFromStorage(); + if (json_data) { + return this._parseState(json_data); + } else { + return null; + } + }; + + SaveStateHandler.prototype._parseState = function(json_data) { + var state; + state = $.parseJSON(json_data); + if (state && state.selected_node && isInt(state.selected_node)) { + state.selected_node = [state.selected_node]; + } + return state; + }; + + SaveStateHandler.prototype._loadFromStorage = function() { + if (this.tree_widget.options.onGetStateFromStorage) { + return this.tree_widget.options.onGetStateFromStorage(); + } else if (this.supportsLocalStorage()) { + return localStorage.getItem(this.getCookieName()); + } else if ($.cookie) { + $.cookie.raw = true; + return $.cookie(this.getCookieName()); + } else { + return null; + } + }; + + SaveStateHandler.prototype.getState = function() { + var getOpenNodeIds, getSelectedNodeIds; + getOpenNodeIds = (function(_this) { return function() { - return selectNode(_this.getPreviousNode(current_node)); + var open_nodes; + open_nodes = []; + _this.tree_widget.tree.iterate(function(node) { + if (node.is_open && node.id && node.hasChildren()) { + open_nodes.push(node.id); + } + return true; + }); + return open_nodes; }; })(this); - moveRight = (function(_this) { + getSelectedNodeIds = (function(_this) { return function() { - if (current_node.isFolder() && !current_node.is_open) { - _this.tree_widget.openNode(current_node); - return false; - } else { - return true; - } + var n; + return (function() { + var _i, _len, _ref, _results; + _ref = this.tree_widget.getSelectedNodes(); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + n = _ref[_i]; + _results.push(n.id); + } + return _results; + }).call(_this); }; })(this); - moveLeft = (function(_this) { - return function() { - if (current_node.isFolder() && current_node.is_open) { - _this.tree_widget.closeNode(current_node); - return false; - } else { + return { + open_nodes: getOpenNodeIds(), + selected_node: getSelectedNodeIds() + }; + }; + + SaveStateHandler.prototype.setState = function(state) { + var node_id, open_nodes, selected_node, selected_node_ids, _i, _len, _results; + if (state) { + open_nodes = state.open_nodes; + selected_node_ids = state.selected_node; + this.tree_widget.tree.iterate((function(_this) { + return function(node) { + node.is_open = node.id && node.hasChildren() && (indexOf(open_nodes, node.id) >= 0); return true; + }; + })(this)); + if (selected_node_ids && this.tree_widget.select_node_handler) { + this.tree_widget.select_node_handler.clear(); + _results = []; + for (_i = 0, _len = selected_node_ids.length; _i < _len; _i++) { + node_id = selected_node_ids[_i]; + selected_node = this.tree_widget.getNodeById(node_id); + if (selected_node) { + _results.push(this.tree_widget.select_node_handler.addToSelection(selected_node)); + } else { + _results.push(void 0); + } } - }; - })(this); - if (!current_node) { - return true; - } else { - key = e.which; - switch (key) { - case DOWN: - return moveDown(); - case UP: - return moveUp(); - case RIGHT: - return moveRight(); - case LEFT: - return moveLeft(); + return _results; } } }; - KeyHandler.prototype.getNextNode = function(node, include_children) { - var next_sibling; - if (include_children == null) { - include_children = true; - } - if (include_children && node.hasChildren() && node.is_open) { - return node.children[0]; + SaveStateHandler.prototype.getCookieName = function() { + if (typeof this.tree_widget.options.saveState === 'string') { + return this.tree_widget.options.saveState; } else { - if (!node.parent) { - return null; - } else { - next_sibling = node.getNextSibling(); - if (next_sibling) { - return next_sibling; - } else { - return this.getNextNode(node.parent, false); - } - } + return 'tree'; } }; - KeyHandler.prototype.getPreviousNode = function(node) { - var previous_sibling; - if (!node.parent) { - return null; - } else { - previous_sibling = node.getPreviousSibling(); - if (previous_sibling) { - if (!previous_sibling.hasChildren() || !previous_sibling.is_open) { - return previous_sibling; - } else { - return this.getLastChild(previous_sibling); - } + SaveStateHandler.prototype.supportsLocalStorage = function() { + var testSupport; + testSupport = function() { + var error, key; + if (typeof localStorage === "undefined" || localStorage === null) { + return false; } else { - if (node.parent.parent) { - return node.parent; - } else { - return null; + try { + key = '_storage_test'; + sessionStorage.setItem(key, true); + sessionStorage.removeItem(key); + } catch (_error) { + error = _error; + return false; } + return true; } + }; + if (this._supportsLocalStorage == null) { + this._supportsLocalStorage = testSupport(); } + return this._supportsLocalStorage; }; - KeyHandler.prototype.getLastChild = function(node) { - var last_child; - if (!node.hasChildren()) { - return null; + SaveStateHandler.prototype.getNodeIdToBeSelected = function() { + var state; + state = this.getStateFromStorage(); + if (state && state.selected_node) { + return state.selected_node[0]; } else { - last_child = node.children[node.children.length - 1]; - if (!last_child.hasChildren() || !last_child.is_open) { - return last_child; - } else { - return this.getLastChild(last_child); - } + return null; } }; - return KeyHandler; + return SaveStateHandler; })(); + module.exports = SaveStateHandler; + }).call(this); + +},{"./util":12}],9:[function(require,module,exports){ +(function() { + var ScrollHandler; + + ScrollHandler = (function() { + function ScrollHandler(tree_widget) { + this.tree_widget = tree_widget; + this.previous_top = -1; + this._initScrollParent(); + } + + ScrollHandler.prototype._initScrollParent = function() { + var $scroll_parent, getParentWithOverflow, setDocumentAsScrollParent; + getParentWithOverflow = (function(_this) { + return function() { + var css_values, el, hasOverFlow, _i, _len, _ref; + css_values = ['overflow', 'overflow-y']; + hasOverFlow = function(el) { + var css_value, _i, _len, _ref; + for (_i = 0, _len = css_values.length; _i < _len; _i++) { + css_value = css_values[_i]; + if ((_ref = $.css(el, css_value)) === 'auto' || _ref === 'scroll') { + return true; + } + } + return false; + }; + if (hasOverFlow(_this.tree_widget.$el[0])) { + return _this.tree_widget.$el; + } + _ref = _this.tree_widget.$el.parents(); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + el = _ref[_i]; + if (hasOverFlow(el)) { + return $(el); + } + } + return null; + }; + })(this); + setDocumentAsScrollParent = (function(_this) { + return function() { + _this.scroll_parent_top = 0; + return _this.$scroll_parent = null; + }; + })(this); + if (this.tree_widget.$el.css('position') === 'fixed') { + setDocumentAsScrollParent(); + } + $scroll_parent = getParentWithOverflow(); + if ($scroll_parent && $scroll_parent.length && $scroll_parent[0].tagName !== 'HTML') { + this.$scroll_parent = $scroll_parent; + return this.scroll_parent_top = this.$scroll_parent.offset().top; + } else { + return setDocumentAsScrollParent(); + } + }; + + ScrollHandler.prototype.checkScrolling = function() { + var hovered_area; + hovered_area = this.tree_widget.dnd_handler.hovered_area; + if (hovered_area && hovered_area.top !== this.previous_top) { + this.previous_top = hovered_area.top; + if (this.$scroll_parent) { + return this._handleScrollingWithScrollParent(hovered_area); + } else { + return this._handleScrollingWithDocument(hovered_area); + } + } + }; + + ScrollHandler.prototype._handleScrollingWithScrollParent = function(area) { + var distance_bottom; + distance_bottom = this.scroll_parent_top + this.$scroll_parent[0].offsetHeight - area.bottom; + if (distance_bottom < 20) { + this.$scroll_parent[0].scrollTop += 20; + this.tree_widget.refreshHitAreas(); + return this.previous_top = -1; + } else if ((area.top - this.scroll_parent_top) < 20) { + this.$scroll_parent[0].scrollTop -= 20; + this.tree_widget.refreshHitAreas(); + return this.previous_top = -1; + } + }; + + ScrollHandler.prototype._handleScrollingWithDocument = function(area) { + var distance_top; + distance_top = area.top - $(document).scrollTop(); + if (distance_top < 20) { + return $(document).scrollTop($(document).scrollTop() - 20); + } else if ($(window).height() - (area.bottom - $(document).scrollTop()) < 20) { + return $(document).scrollTop($(document).scrollTop() + 20); + } + }; + + ScrollHandler.prototype.scrollTo = function(top) { + var tree_top; + if (this.$scroll_parent) { + return this.$scroll_parent[0].scrollTop = top; + } else { + tree_top = this.tree_widget.$el.offset().top; + return $(document).scrollTop(top + tree_top); + } + }; + + ScrollHandler.prototype.isScrolledIntoView = function(element) { + var $element, element_bottom, element_top, view_bottom, view_top; + $element = $(element); + if (this.$scroll_parent) { + view_top = 0; + view_bottom = this.$scroll_parent.height(); + element_top = $element.offset().top - this.scroll_parent_top; + element_bottom = element_top + $element.height(); + } else { + view_top = $(window).scrollTop(); + view_bottom = view_top + $(window).height(); + element_top = $element.offset().top; + element_bottom = element_top + $element.height(); + } + return (element_bottom <= view_bottom) && (element_top >= view_top); + }; + + return ScrollHandler; + + })(); + + module.exports = ScrollHandler; + +}).call(this); + +},{}],10:[function(require,module,exports){ +(function() { + var SelectNodeHandler; + + SelectNodeHandler = (function() { + function SelectNodeHandler(tree_widget) { + this.tree_widget = tree_widget; + this.clear(); + } + + SelectNodeHandler.prototype.getSelectedNode = function() { + var selected_nodes; + selected_nodes = this.getSelectedNodes(); + if (selected_nodes.length) { + return selected_nodes[0]; + } else { + return false; + } + }; + + SelectNodeHandler.prototype.getSelectedNodes = function() { + var id, node, selected_nodes; + if (this.selected_single_node) { + return [this.selected_single_node]; + } else { + selected_nodes = []; + for (id in this.selected_nodes) { + node = this.tree_widget.getNodeById(id); + if (node) { + selected_nodes.push(node); + } + } + return selected_nodes; + } + }; + + SelectNodeHandler.prototype.getSelectedNodesUnder = function(parent) { + var id, node, selected_nodes; + if (this.selected_single_node) { + if (parent.isParentOf(this.selected_single_node)) { + return [this.selected_single_node]; + } else { + return []; + } + } else { + selected_nodes = []; + for (id in this.selected_nodes) { + node = this.tree_widget.getNodeById(id); + if (node && parent.isParentOf(node)) { + selected_nodes.push(node); + } + } + return selected_nodes; + } + }; + + SelectNodeHandler.prototype.isNodeSelected = function(node) { + if (node.id) { + return this.selected_nodes[node.id]; + } else if (this.selected_single_node) { + return this.selected_single_node.element === node.element; + } else { + return false; + } + }; + + SelectNodeHandler.prototype.clear = function() { + this.selected_nodes = {}; + return this.selected_single_node = null; + }; + + SelectNodeHandler.prototype.removeFromSelection = function(node, include_children) { + if (include_children == null) { + include_children = false; + } + if (!node.id) { + if (this.selected_single_node && node.element === this.selected_single_node.element) { + return this.selected_single_node = null; + } + } else { + delete this.selected_nodes[node.id]; + if (include_children) { + return node.iterate((function(_this) { + return function(n) { + delete _this.selected_nodes[node.id]; + return true; + }; + })(this)); + } + } + }; + + SelectNodeHandler.prototype.addToSelection = function(node) { + if (node.id) { + return this.selected_nodes[node.id] = true; + } else { + return this.selected_single_node = node; + } + }; + + return SelectNodeHandler; + + })(); + + module.exports = SelectNodeHandler; + +}).call(this); + +},{}],11:[function(require,module,exports){ + +/* +Copyright 2013 Marco Braak + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +(function() { + var SimpleWidget, + __slice = [].slice; + + SimpleWidget = (function() { + SimpleWidget.prototype.defaults = {}; + + function SimpleWidget(el, options) { + this.$el = $(el); + this.options = $.extend({}, this.defaults, options); + } + + SimpleWidget.prototype.destroy = function() { + return this._deinit(); + }; + + SimpleWidget.prototype._init = function() { + return null; + }; + + SimpleWidget.prototype._deinit = function() { + return null; + }; + + SimpleWidget.register = function(widget_class, widget_name) { + var callFunction, createWidget, destroyWidget, getDataKey, getWidgetData; + getDataKey = function() { + return "simple_widget_" + widget_name; + }; + getWidgetData = function(el, data_key) { + var widget; + widget = $.data(el, data_key); + if (widget && (widget instanceof SimpleWidget)) { + return widget; + } else { + return null; + } + }; + createWidget = function($el, options) { + var data_key, el, existing_widget, widget, _i, _len; + data_key = getDataKey(); + for (_i = 0, _len = $el.length; _i < _len; _i++) { + el = $el[_i]; + existing_widget = getWidgetData(el, data_key); + if (!existing_widget) { + widget = new widget_class(el, options); + if (!$.data(el, data_key)) { + $.data(el, data_key, widget); + } + widget._init(); + } + } + return $el; + }; + destroyWidget = function($el) { + var data_key, el, widget, _i, _len, _results; + data_key = getDataKey(); + _results = []; + for (_i = 0, _len = $el.length; _i < _len; _i++) { + el = $el[_i]; + widget = getWidgetData(el, data_key); + if (widget) { + widget.destroy(); + } + _results.push($.removeData(el, data_key)); + } + return _results; + }; + callFunction = function($el, function_name, args) { + var el, result, widget, widget_function, _i, _len; + result = null; + for (_i = 0, _len = $el.length; _i < _len; _i++) { + el = $el[_i]; + widget = $.data(el, getDataKey()); + if (widget && (widget instanceof SimpleWidget)) { + widget_function = widget[function_name]; + if (widget_function && (typeof widget_function === 'function')) { + result = widget_function.apply(widget, args); + } + } + } + return result; + }; + return $.fn[widget_name] = function() { + var $el, args, argument1, function_name, options; + argument1 = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + $el = this; + if (argument1 === void 0 || typeof argument1 === 'object') { + options = argument1; + return createWidget($el, options); + } else if (typeof argument1 === 'string' && argument1[0] !== '_') { + function_name = argument1; + if (function_name === 'destroy') { + return destroyWidget($el); + } else { + return callFunction($el, function_name, args); + } + } + }; + }; + + return SimpleWidget; + + })(); + + module.exports = SimpleWidget; + +}).call(this); + +},{}],12:[function(require,module,exports){ +(function() { + var get_json_stringify_function, html_escape, indexOf, isInt, _indexOf; + + _indexOf = function(array, item) { + var i, value, _i, _len; + for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) { + value = array[i]; + if (value === item) { + return i; + } + } + return -1; + }; + + indexOf = function(array, item) { + if (array.indexOf) { + return array.indexOf(item); + } else { + return _indexOf(array, item); + } + }; + + isInt = function(n) { + return typeof n === 'number' && n % 1 === 0; + }; + + get_json_stringify_function = function() { + var json_escapable, json_meta, json_quote, json_str, stringify; + json_escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + json_meta = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"': '\\"', + '\\': '\\\\' + }; + json_quote = function(string) { + json_escapable.lastIndex = 0; + if (json_escapable.test(string)) { + return '"' + string.replace(json_escapable, function(a) { + var c; + c = json_meta[a]; + return (typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4)); + }) + '"'; + } else { + return '"' + string + '"'; + } + }; + json_str = function(key, holder) { + var i, k, partial, v, value, _i, _len; + value = holder[key]; + switch (typeof value) { + case 'string': + return json_quote(value); + case 'number': + if (isFinite(value)) { + return String(value); + } else { + return 'null'; + } + case 'boolean': + case 'null': + return String(value); + case 'object': + if (!value) { + return 'null'; + } + partial = []; + if (Object.prototype.toString.apply(value) === '[object Array]') { + for (i = _i = 0, _len = value.length; _i < _len; i = ++_i) { + v = value[i]; + partial[i] = json_str(i, value) || 'null'; + } + return (partial.length === 0 ? '[]' : '[' + partial.join(',') + ']'); + } + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = json_str(k, value); + if (v) { + partial.push(json_quote(k) + ':' + v); + } + } + } + return (partial.length === 0 ? '{}' : '{' + partial.join(',') + '}'); + } + }; + stringify = function(value) { + return json_str('', { + '': value + }); + }; + return stringify; + }; + + if (!((this.JSON != null) && (this.JSON.stringify != null) && typeof this.JSON.stringify === 'function')) { + if (this.JSON == null) { + this.JSON = {}; + } + this.JSON.stringify = get_json_stringify_function(); + } + + html_escape = function(string) { + return ('' + string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/'); + }; + + module.exports = { + _indexOf: _indexOf, + get_json_stringify_function: get_json_stringify_function, + html_escape: html_escape, + indexOf: indexOf, + isInt: isInt + }; + +}).call(this); + +},{}],13:[function(require,module,exports){ +(function() { + module.exports = '0.22.0'; + +}).call(this); + +},{}]},{},[3]) \ No newline at end of file