fancytree-rails 2.0.0.pre.11.pre.1 → 2.1.0.pre.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/3th-party/jquery-ui.License.txt +2 -0
  3. data/README.md +7 -1
  4. data/Rakefile +21 -5
  5. data/{vendor → app}/assets/images/fancytree/icons.gif +0 -0
  6. data/{vendor → app}/assets/images/fancytree/loading.gif +0 -0
  7. data/app/assets/images/fancytree/skin-lion/icons.gif +0 -0
  8. data/{vendor → app}/assets/images/fancytree/skin-lion/loading.gif +0 -0
  9. data/app/assets/images/fancytree/skin-themeroller/icons.gif +0 -0
  10. data/{vendor → app}/assets/images/fancytree/skin-themeroller/loading.gif +0 -0
  11. data/app/assets/images/fancytree/skin-vista/icons.gif +0 -0
  12. data/{vendor → app}/assets/images/fancytree/skin-vista/loading.gif +0 -0
  13. data/app/assets/images/fancytree/skin-win7/icons.gif +0 -0
  14. data/{vendor → app}/assets/images/fancytree/skin-win7/loading.gif +0 -0
  15. data/{vendor → app}/assets/images/fancytree/skin-win8-xxl/icons.gif +0 -0
  16. data/{vendor → app}/assets/images/fancytree/skin-win8-xxl/loading.gif +0 -0
  17. data/app/assets/images/fancytree/skin-win8/icons.gif +0 -0
  18. data/{vendor → app}/assets/images/fancytree/skin-win8/loading.gif +0 -0
  19. data/{vendor → app}/assets/images/fancytree/skin-xp/icons-rtl.gif +0 -0
  20. data/{vendor → app}/assets/images/fancytree/skin-xp/icons.gif +0 -0
  21. data/{vendor → app}/assets/images/fancytree/skin-xp/loading.gif +0 -0
  22. data/{vendor → app}/assets/images/fancytree/skin-xp/vline-rtl.gif +0 -0
  23. data/{vendor → app}/assets/images/fancytree/skin-xp/vline.gif +0 -0
  24. data/{vendor → app}/assets/javascripts/fancytree.js +0 -0
  25. data/{vendor → app}/assets/javascripts/fancytree/MIT-LICENSE.txt +0 -0
  26. data/{vendor → app}/assets/javascripts/fancytree/jquery.fancytree-all.js +346 -333
  27. data/app/assets/javascripts/fancytree/jquery.fancytree-custom.min.js +41 -0
  28. data/{vendor → app}/assets/javascripts/fancytree/jquery.fancytree.js +109 -66
  29. data/app/assets/javascripts/fancytree/jquery.fancytree.min.js +14 -0
  30. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.childcounter.js +3 -3
  31. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.clones.js +36 -6
  32. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.columnview.js +2 -2
  33. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.debug.js +2 -2
  34. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.dnd.js +35 -51
  35. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.edit.js +5 -9
  36. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.filter.js +54 -66
  37. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.glyph.js +6 -9
  38. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.gridnav.js +2 -2
  39. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.js +109 -66
  40. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.menu.js +2 -2
  41. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.persist.js +106 -112
  42. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.table.js +23 -9
  43. data/{vendor → app}/assets/javascripts/fancytree/src/jquery.fancytree.themeroller.js +3 -6
  44. data/{vendor/assets/stylesheets/fancytree/skin-awesome/ui.fancytree.css → app/assets/stylesheets/fancytree/skin-awesome/ui.fancytree.css.erb} +30 -5
  45. data/app/assets/stylesheets/fancytree/skin-awesome/ui.fancytree.min.css.erb +6 -0
  46. data/{vendor/assets/stylesheets/fancytree/skin-bootstrap/ui.fancytree.css → app/assets/stylesheets/fancytree/skin-bootstrap/ui.fancytree.css.erb} +31 -6
  47. data/app/assets/stylesheets/fancytree/skin-bootstrap/ui.fancytree.min.css.erb +6 -0
  48. data/{vendor/assets/stylesheets/fancytree/skin-lion/ui.fancytree.css → app/assets/stylesheets/fancytree/skin-lion/ui.fancytree.css.erb} +35 -14
  49. data/app/assets/stylesheets/fancytree/skin-lion/ui.fancytree.min.css.erb +6 -0
  50. data/{vendor/assets/stylesheets/fancytree/skin-themeroller/ui.fancytree.css → app/assets/stylesheets/fancytree/skin-themeroller/ui.fancytree.css.erb} +1 -1
  51. data/{vendor/assets/stylesheets/fancytree/skin-themeroller/ui.fancytree.min.css → app/assets/stylesheets/fancytree/skin-themeroller/ui.fancytree.min.css.erb} +0 -0
  52. data/{vendor/assets/stylesheets/fancytree/skin-vista/ui.fancytree.css → app/assets/stylesheets/fancytree/skin-vista/ui.fancytree.css.erb} +35 -14
  53. data/app/assets/stylesheets/fancytree/skin-vista/ui.fancytree.min.css.erb +6 -0
  54. data/{vendor/assets/stylesheets/fancytree/skin-win7/ui.fancytree.css → app/assets/stylesheets/fancytree/skin-win7/ui.fancytree.css.erb} +35 -14
  55. data/app/assets/stylesheets/fancytree/skin-win7/ui.fancytree.min.css.erb +6 -0
  56. data/{vendor/assets/stylesheets/fancytree/skin-win8-xxl/ui.fancytree.css → app/assets/stylesheets/fancytree/skin-win8-xxl/ui.fancytree.css.erb} +37 -16
  57. data/app/assets/stylesheets/fancytree/skin-win8-xxl/ui.fancytree.min.css.erb +11 -0
  58. data/{vendor/assets/stylesheets/fancytree/skin-win8/ui.fancytree.css → app/assets/stylesheets/fancytree/skin-win8/ui.fancytree.css.erb} +37 -16
  59. data/app/assets/stylesheets/fancytree/skin-win8/ui.fancytree.min.css.erb +6 -0
  60. data/{vendor/assets/stylesheets/fancytree/skin-xp/ui.fancytree.css → app/assets/stylesheets/fancytree/skin-xp/ui.fancytree.css.erb} +35 -14
  61. data/app/assets/stylesheets/fancytree/skin-xp/ui.fancytree.min.css.erb +6 -0
  62. data/{vendor → app}/assets/stylesheets/ui.fancytree.css +0 -0
  63. data/lib/fancytree/rails/version.rb +2 -2
  64. metadata +77 -76
  65. data/vendor/assets/images/fancytree/skin-lion/icons.gif +0 -0
  66. data/vendor/assets/images/fancytree/skin-themeroller/icons.gif +0 -0
  67. data/vendor/assets/images/fancytree/skin-vista/icons.gif +0 -0
  68. data/vendor/assets/images/fancytree/skin-win7/icons.gif +0 -0
  69. data/vendor/assets/images/fancytree/skin-win8/icons.gif +0 -0
  70. data/vendor/assets/javascripts/fancytree/jquery.fancytree-custom.min.js +0 -41
  71. data/vendor/assets/javascripts/fancytree/jquery.fancytree.min.js +0 -14
  72. data/vendor/assets/stylesheets/fancytree/skin-awesome/ui.fancytree.min.css +0 -6
  73. data/vendor/assets/stylesheets/fancytree/skin-bootstrap/ui.fancytree.min.css +0 -6
  74. data/vendor/assets/stylesheets/fancytree/skin-lion/ui.fancytree.min.css +0 -6
  75. data/vendor/assets/stylesheets/fancytree/skin-vista/ui.fancytree.min.css +0 -6
  76. data/vendor/assets/stylesheets/fancytree/skin-win7/ui.fancytree.min.css +0 -6
  77. data/vendor/assets/stylesheets/fancytree/skin-win8-xxl/ui.fancytree.min.css +0 -11
  78. data/vendor/assets/stylesheets/fancytree/skin-win8/ui.fancytree.min.css +0 -6
  79. data/vendor/assets/stylesheets/fancytree/skin-xp/ui.fancytree.min.css +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1f8597dbe02db0bcac1ca59245d2b4b1ef806241
4
- data.tar.gz: 6f23c661681871ae96ea0f8e6bf6408c3c8f1031
3
+ metadata.gz: 5a8617873a677ecca45f5f10e1878b044e209a57
4
+ data.tar.gz: d48c2f46d24a79dace0daf77f3e395f0d797ebcf
5
5
  SHA512:
6
- metadata.gz: fd9930807b36cffe63374ee0ecc41dd5d8c334300122d27379ed07136eb7aa099b0f2a2842574e7fc3818338a196e214c0d4eefc6a64cae78484640ab550805a
7
- data.tar.gz: 1d1e2ab886857144211259f04c889765b75ee3b22ad7422b2716754c5cf971ec327ba880cc43aa0149eb03600981e18f4d38e25bcc4c602b5cd0cdc16a172a90
6
+ metadata.gz: 958f86489eb8b3742f11b524c80a513fa64343820821c40ec4ff3bd9bc4b0e7f0da21746980a1ea45cf2ea07b03d8ead4341f531dd10e20313f819797b003016
7
+ data.tar.gz: 6651dc979969d811827f7f1aaa95774600ee234087d73ec82dcf5239c484943f8e81f3b6731e1728ecd84167068d3845c1a2959912016c3bac6a5f599f08ef2b
@@ -0,0 +1,2 @@
1
+ jQuery UI as well as this gem are licensed under the MIT license (see
2
+ jquery-ui/MIT-LICENSE.txt).
data/README.md CHANGED
@@ -53,10 +53,16 @@ Note that for awesome style (extension) to work you to:
53
53
  2. Enable ```awesome``` extension in Fancytree.
54
54
  3. Include extension code (```//= require fancytree/jquery.fancytree.awesome```) to ```app/assets/javascripts/application.js```.
55
55
 
56
+ ## Credits
57
+
58
+ Pice of code of Raikefile copied form joliss/jquery-ui-rails. See
59
+ 3th-party for its license.
60
+
56
61
  ## Contributing
57
62
 
58
63
  1. Fork it
59
- 2. Create your feature branch (`git checkout -b my-new-feature`)
64
+ 2. Create your feature branch (`git checkout -b my-new-feature`). You
65
+ can use rake fancytree:update for semiautomatic update of mar10/fancytree
60
66
  3. Commit your changes (`git commit -am 'Add some feature'`)
61
67
  4. Push to the branch (`git push origin my-new-feature`)
62
68
  5. Create new Pull Request
data/Rakefile CHANGED
@@ -2,6 +2,14 @@ require "bundler/gem_tasks"
2
2
  require 'fileutils'
3
3
  require 'fancytree/rails/version'
4
4
 
5
+ def build_image_dependencies(source_code)
6
+ image_dependencies = Set.new source_code.scan(/url\("?images\/([-_.a-zA-Z0-9]+)"?\)/).map(&:first)
7
+ code = image_dependencies.inject("") do |acc, img|
8
+ acc += " *= depend_on_asset \"jquery-ui/#{img}\"\n"
9
+ end
10
+ end
11
+
12
+
5
13
  namespace :fancytree do
6
14
  desc "Update FancyTree library from current version"
7
15
  task :update => :build do
@@ -9,18 +17,26 @@ namespace :fancytree do
9
17
 
10
18
  cd "dist" do
11
19
  js = FileList['*'].exclude(/\Askip*/)
12
- FileUtils.cp_r(js, '../../../vendor/assets/javascripts/fancytree')
20
+ FileUtils.cp_r(js, '../../../app/assets/javascripts/fancytree')
13
21
 
14
22
  css_files = Dir.glob("skin*/*.css")
15
23
  css_files.each do |file|
16
- mkdir_p "../../../vendor/assets/stylesheets/fancytree/#{File.dirname(file)}"
17
- FileUtils.cp file, "../../../vendor/assets/stylesheets/fancytree/#{file}"
24
+ source_code = File.read(file)
25
+ #source_code.gsub!(/url\("?images\/([-_.a-zA-Z0-9]+)"?\)/, 'url(<%= image_path("fancytree/\1") %>)')
26
+ source_code.gsub!(/url\("icons.gif"\)/, 'url(<%= image_path("fancytree/icons.gif") %>)')
27
+ source_code.gsub!(/\A(\/\*!.+?\*\/\s)/m, "\\1\n/*\n#{build_image_dependencies(source_code)} */\n\n") unless build_image_dependencies(source_code).empty?
28
+
29
+ output_path = "../../../app/assets/stylesheets/fancytree/#{file}.erb"
30
+ mkdir_p File.dirname(output_path)
31
+ File.open(output_path, "w") do |out|
32
+ out.write(source_code)
33
+ end
18
34
  end
19
35
 
20
36
  images_files = Dir.glob("skin*/*.gif")
21
37
  images_files.each do |file|
22
- mkdir_p "../../../vendor/assets/images/fancytree/#{File.dirname(file)}"
23
- FileUtils.cp file, "../../../vendor/assets/images/fancytree/#{file}"
38
+ mkdir_p "../../../app/assets/images/fancytree/#{File.dirname(file)}"
39
+ FileUtils.cp file, "../../../app/assets/images/fancytree/#{file}"
24
40
  end
25
41
  end
26
42
 
File without changes
File without changes
File without changes
@@ -7,8 +7,8 @@
7
7
  * Released under the MIT license
8
8
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
9
9
  *
10
- * @version 2.0.0-11
11
- * @date 2014-04-27T22:28
10
+ * @version 2.1.0
11
+ * @date 2014-05-29T16:44
12
12
  */
13
13
 
14
14
  /** Core Fancytree module.
@@ -61,6 +61,11 @@ function consoleApply(method, args){
61
61
  }
62
62
  }
63
63
 
64
+ /*Return true if x is a FancytreeNode.*/
65
+ function _isNode(x){
66
+ return !!(x.tree && x.statusNodeType !== undefined);
67
+ }
68
+
64
69
  /** Return true if dotted version string is equal or higher than requested version.
65
70
  *
66
71
  * See http://jsfiddle.net/mar10/FjSAN/
@@ -275,6 +280,8 @@ function FancytreeNode(parent, obj){
275
280
  } else {
276
281
  this.key = "_" + (FT._nextNodeKey++);
277
282
  }
283
+ } else {
284
+ this.key = "" + this.key; // Convert to string (#217)
278
285
  }
279
286
 
280
287
  // Fix tree.activeNode
@@ -683,9 +690,8 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
683
690
  // recursively set children and render
684
691
  this.removeChildren();
685
692
  this.addChildren(dict.children);
686
- }else{
687
- this.renderTitle();
688
693
  }
694
+ this.renderTitle();
689
695
  /*
690
696
  var children = dict.children;
691
697
  if(children === undefined){
@@ -1350,79 +1356,93 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1350
1356
  /**
1351
1357
  *
1352
1358
  * @param {boolean | PlainObject} [effects=false] animation options.
1353
- * @param {FancytreeNode} [topNode=null] this node will remain visible in
1359
+ * @param {object} [options=null] {topNode: null, effects: ..., parent: ...} this node will remain visible in
1354
1360
  * any case, even if `this` is outside the scroll pane.
1355
1361
  * @returns {$.Promise}
1356
1362
  */
1357
- scrollIntoView: function(effects, topNode) {
1358
- effects = (effects === true) ? {duration: 200, queue: false} : effects;
1359
- var topNodeY,
1363
+ scrollIntoView: function(effects, options) {
1364
+ if( options !== undefined && _isNode(options) ) {
1365
+ this.warn("scrollIntoView() with 'topNode' option is deprecated since 2014-05-08. Use 'options.topNode' instead.");
1366
+ options = {topNode: options};
1367
+ }
1368
+ // this.$scrollParent = (this.options.scrollParent === "auto") ? $ul.scrollParent() : $(this.options.scrollParent);
1369
+ // this.$scrollParent = this.$scrollParent.length ? this.$scrollParent || this.$container;
1370
+
1371
+ var topNodeY, nodeY, horzScrollbarHeight, containerOffsetTop,
1372
+ opts = $.extend({
1373
+ effects: (effects === true) ? {duration: 200, queue: false} : effects,
1374
+ scrollOfs: this.tree.options.scrollOfs,
1375
+ scrollParent: this.tree.options.scrollParent || this.tree.$container,
1376
+ topNode: null
1377
+ }, options),
1360
1378
  dfd = new $.Deferred(),
1361
1379
  that = this,
1362
- nodeY = $(this.span).position().top,
1363
1380
  nodeHeight = $(this.span).height(),
1364
- $container = this.tree.$container,
1365
- scrollTop = $container[0].scrollTop,
1366
- horzScrollHeight = Math.max(0, ($container.innerHeight() - $container[0].clientHeight)),
1367
- // containerHeight = $container.height(),
1368
- containerHeight = $container.height() - horzScrollHeight,
1381
+ $container = $(opts.scrollParent),
1382
+ topOfs = opts.scrollOfs.top || 0,
1383
+ bottomOfs = opts.scrollOfs.bottom || 0,
1384
+ containerHeight = $container.height(),// - topOfs - bottomOfs,
1385
+ scrollTop = $container.scrollTop(),
1386
+ $animateTarget = $container,
1387
+ isParentWindow = $container[0] === window,
1388
+ topNode = opts.topNode || null,
1369
1389
  newScrollTop = null;
1370
1390
 
1371
- // console.log("horzScrollHeight: " + horzScrollHeight);
1372
- // console.log("$container[0].scrollTop: " + $container[0].scrollTop);
1373
- // console.log("$container[0].scrollHeight: " + $container[0].scrollHeight);
1374
- // console.log("$container[0].clientHeight: " + $container[0].clientHeight);
1375
- // console.log("$container.innerHeight(): " + $container.innerHeight());
1376
- // console.log("$container.height(): " + $container.height());
1377
-
1378
- if(nodeY < 0){
1379
- newScrollTop = scrollTop + nodeY;
1380
- }else if((nodeY + nodeHeight) > containerHeight){
1381
- newScrollTop = scrollTop + nodeY - containerHeight + nodeHeight;
1391
+ // this.debug("scrollIntoView(), scrollTop=", scrollTop, opts.scrollOfs);
1392
+ _assert($(this.span).is(":visible"), "scrollIntoView node is invisible"); // otherwise we cannot calc offsets
1393
+
1394
+ if( isParentWindow ) {
1395
+ nodeY = $(this.span).offset().top;
1396
+ topNodeY = topNode ? $(topNode.span).offset().top : 0;
1397
+ $animateTarget = $("html,body");
1398
+
1399
+ } else {
1400
+ _assert($container[0] !== document && $container[0] !== document.body, "scrollParent should be an simple element or `window`, not document or body.");
1401
+
1402
+ containerOffsetTop = $container.offset().top,
1403
+ nodeY = $(this.span).offset().top - containerOffsetTop + scrollTop; // relative to scroll parent
1404
+ topNodeY = topNode ? $(topNode.span).offset().top - containerOffsetTop + scrollTop : 0;
1405
+ horzScrollbarHeight = Math.max(0, ($container.innerHeight() - $container[0].clientHeight));
1406
+ containerHeight -= horzScrollbarHeight;
1407
+ }
1408
+
1409
+ // this.debug(" scrollIntoView(), nodeY=", nodeY, "containerHeight=", containerHeight);
1410
+ if( nodeY < (scrollTop + topOfs) ){
1411
+ // Node is above visible container area
1412
+ newScrollTop = nodeY - topOfs;
1413
+ // this.debug(" scrollIntoView(), UPPER newScrollTop=", newScrollTop);
1414
+
1415
+ }else if((nodeY + nodeHeight) > (scrollTop + containerHeight - bottomOfs)){
1416
+ newScrollTop = nodeY + nodeHeight - containerHeight + bottomOfs;
1417
+ // this.debug(" scrollIntoView(), LOWER newScrollTop=", newScrollTop);
1382
1418
  // If a topNode was passed, make sure that it is never scrolled
1383
1419
  // outside the upper border
1384
1420
  if(topNode){
1385
- topNodeY = topNode ? $(topNode.span).position().top : 0;
1386
- if((nodeY - topNodeY) > containerHeight){
1387
- newScrollTop = scrollTop + topNodeY;
1421
+ _assert($(topNode.span).is(":visible"));
1422
+ if( topNodeY < newScrollTop ){
1423
+ newScrollTop = topNodeY - topOfs;
1424
+ // this.debug(" scrollIntoView(), TOP newScrollTop=", newScrollTop);
1388
1425
  }
1389
1426
  }
1390
1427
  }
1428
+
1391
1429
  if(newScrollTop !== null){
1392
- if(effects){
1393
- // TODO: resolve dfd after animation
1394
- // var that = this;
1395
- effects.complete = function(){
1430
+ // this.debug(" scrollIntoView(), SET newScrollTop=", newScrollTop);
1431
+ if(opts.effects){
1432
+ opts.effects.complete = function(){
1396
1433
  dfd.resolveWith(that);
1397
1434
  };
1398
- $container.animate({
1435
+ $animateTarget.stop(true).animate({
1399
1436
  scrollTop: newScrollTop
1400
- }, effects);
1437
+ }, opts.effects);
1401
1438
  }else{
1402
- $container[0].scrollTop = newScrollTop;
1439
+ $animateTarget[0].scrollTop = newScrollTop;
1403
1440
  dfd.resolveWith(this);
1404
1441
  }
1405
1442
  }else{
1406
1443
  dfd.resolveWith(this);
1407
1444
  }
1408
1445
  return dfd.promise();
1409
- /* from jQuery.menu:
1410
- var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
1411
- if ( this._hasScroll() ) {
1412
- borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
1413
- paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
1414
- offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
1415
- scroll = this.activeMenu.scrollTop();
1416
- elementHeight = this.activeMenu.height();
1417
- itemHeight = item.height();
1418
-
1419
- if ( offset < 0 ) {
1420
- this.activeMenu.scrollTop( scroll + offset );
1421
- } else if ( offset + itemHeight > elementHeight ) {
1422
- this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
1423
- }
1424
- }
1425
- */
1426
1446
  },
1427
1447
 
1428
1448
  /**Activate this node.
@@ -2817,8 +2837,8 @@ $.extend(Fancytree.prototype,
2817
2837
  // folder or doctype icon
2818
2838
  role = aria ? " role='img'" : "";
2819
2839
  if ( icon && typeof icon === "string" ) {
2820
- imageSrc = (icon.charAt(0) === "/") ? icon : (opts.imagePath + icon);
2821
- ares.push("<img src='" + imageSrc + "' alt='' />");
2840
+ imageSrc = (icon.charAt(0) === "/") ? icon : ((opts.imagePath || "") + icon);
2841
+ ares.push("<img src='" + imageSrc + "' class='fancytree-icon' alt='' />");
2822
2842
  } else if ( node.data.iconclass ) {
2823
2843
  // TODO: review and test and document
2824
2844
  ares.push("<span " + role + " class='fancytree-custom-icon" + " " + node.data.iconclass + "'></span>");
@@ -2834,7 +2854,6 @@ $.extend(Fancytree.prototype,
2834
2854
  nodeTitle = opts.renderTitle.call(tree, {type: "renderTitle"}, ctx) || "";
2835
2855
  }
2836
2856
  if(!nodeTitle){
2837
- // TODO: escape tooltip string
2838
2857
  tooltip = node.tooltip ? " title='" + FT.escapeHtml(node.tooltip) + "'" : "";
2839
2858
  id = aria ? " id='ftal_" + node.key + "'" : "";
2840
2859
  role = aria ? " role='treeitem'" : "";
@@ -2979,7 +2998,6 @@ $.extend(Fancytree.prototype,
2979
2998
  node = ctx.node,
2980
2999
  tree = ctx.tree,
2981
3000
  opts = ctx.options,
2982
- // userEvent = !!ctx.originalEvent,
2983
3001
  noEvents = (callOpts.noEvents === true),
2984
3002
  isActive = (node === tree.activeNode);
2985
3003
 
@@ -3003,7 +3021,7 @@ $.extend(Fancytree.prototype,
3003
3021
  }
3004
3022
  if(opts.activeVisible){
3005
3023
  // tree.nodeMakeVisible(ctx);
3006
- node.makeVisible();
3024
+ node.makeVisible({scrollIntoView: false}); // nodeSetFocus will scroll
3007
3025
  }
3008
3026
  tree.activeNode = node;
3009
3027
  tree.nodeRenderStatus(ctx);
@@ -3080,9 +3098,9 @@ $.extend(Fancytree.prototype,
3080
3098
  }
3081
3099
  // Trigger expand/collapse after expanding
3082
3100
  dfd.done(function(){
3083
- if( opts.autoScroll && !noAnimation ) {
3101
+ if( flag && opts.autoScroll && !noAnimation ) {
3084
3102
  // Scroll down to last child, but keep current node visible
3085
- node.getLastChild().scrollIntoView(true, node).always(function(){
3103
+ node.getLastChild().scrollIntoView(true, {topNode: node}).always(function(){
3086
3104
  if( !noEvents ) {
3087
3105
  ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx);
3088
3106
  }
@@ -3093,7 +3111,6 @@ $.extend(Fancytree.prototype,
3093
3111
  }
3094
3112
  }
3095
3113
  });
3096
-
3097
3114
  // vvv Code below is executed after loading finished:
3098
3115
  _afterLoad = function(callback){
3099
3116
  var duration, easing, isVisible, isExpanded;
@@ -3201,7 +3218,7 @@ $.extend(Fancytree.prototype,
3201
3218
  this._callHook("treeSetFocus", ctx, true, true);
3202
3219
  }
3203
3220
  // this.nodeMakeVisible(ctx);
3204
- node.makeVisible();
3221
+ node.makeVisible({scrollIntoView: false});
3205
3222
  tree.focusNode = node;
3206
3223
  // node.debug("FOCUS...");
3207
3224
  // $(node.span).find(".fancytree-title").focus();
@@ -3512,6 +3529,8 @@ $.widget("ui.fancytree",
3512
3529
  keyboard: true,
3513
3530
  keyPathSeparator: "/",
3514
3531
  minExpandLevel: 1,
3532
+ scrollOfs: {top: 0, bottom: 0},
3533
+ scrollParent: null,
3515
3534
  selectMode: 2,
3516
3535
  strings: {
3517
3536
  loading: "Loading&#8230;",
@@ -3772,7 +3791,7 @@ $.extend($.ui.fancytree,
3772
3791
  /** @lends Fancytree_Static# */
3773
3792
  {
3774
3793
  /** @type {string} */
3775
- version: "2.0.0-11", // Set to semver by 'grunt release'
3794
+ version: "2.1.0", // Set to semver by 'grunt release'
3776
3795
  /** @type {string} */
3777
3796
  buildType: "production", // Set to 'production' by 'grunt build'
3778
3797
  /** @type {int} */
@@ -3800,6 +3819,29 @@ $.extend($.ui.fancytree,
3800
3819
  assert: function(cond, msg){
3801
3820
  return _assert(cond, msg);
3802
3821
  },
3822
+ /** Return a function that executes *fn* at most every *timeout* ms.
3823
+ * @param {integer} timeout
3824
+ * @param {function} fn
3825
+ * @param {boolean} [invokeAsap=false]
3826
+ * @param {any} [ctx]
3827
+ */
3828
+ debounce : function(timeout, fn, invokeAsap, ctx) {
3829
+ var timer;
3830
+ if(arguments.length === 3 && typeof invokeAsap !== "boolean") {
3831
+ ctx = invokeAsap;
3832
+ invokeAsap = false;
3833
+ }
3834
+ return function() {
3835
+ var args = arguments;
3836
+ ctx = ctx || this;
3837
+ invokeAsap && !timer && fn.apply(ctx, args);
3838
+ clearTimeout(timer);
3839
+ timer = setTimeout(function() {
3840
+ invokeAsap || fn.apply(ctx, args);
3841
+ timer = null;
3842
+ }, timeout);
3843
+ };
3844
+ },
3803
3845
  /** Write message to console if debugLevel >= 2
3804
3846
  * @param {string} msg
3805
3847
  */
@@ -3850,8 +3892,7 @@ $.extend($.ui.fancytree,
3850
3892
  getEventTarget: function(event){
3851
3893
  var tcn = event && event.target ? event.target.className : "",
3852
3894
  res = {node: this.getNode(event.target), type: undefined};
3853
- // tcn may contains UI themeroller or Font Awesome classes, so we use
3854
- // a fast version of $(res.node).hasClass()
3895
+ // We use a fast version of $(res.node).hasClass()
3855
3896
  // See http://jsperf.com/test-for-classname/2
3856
3897
  if( /\bfancytree-title\b/.test(tcn) ){
3857
3898
  res.type = "title";
@@ -3862,8 +3903,10 @@ $.extend($.ui.fancytree,
3862
3903
  }else if( /\bfancytree-icon\b/.test(tcn) ){
3863
3904
  res.type = "icon";
3864
3905
  }else if( /\bfancytree-node\b/.test(tcn) ){
3865
- // TODO: (http://code.google.com/p/dynatree/issues/detail?id=93)
3866
- // res.type = this._getTypeForOuterNodeEvent(event);
3906
+ // Somewhere near the title
3907
+ res.type = "title";
3908
+ }else if( event && event.target && $(event.target).closest(".fancytree-title").length ) {
3909
+ // #228: clicking an embedded element inside a title
3867
3910
  res.type = "title";
3868
3911
  }
3869
3912
  return res;
@@ -4047,8 +4090,8 @@ $.extend($.ui.fancytree,
4047
4090
  * Released under the MIT license
4048
4091
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
4049
4092
  *
4050
- * @version 2.0.0-11
4051
- * @date 2014-04-27T22:28
4093
+ * @version 2.1.0
4094
+ * @date 2014-05-29T16:44
4052
4095
  */
4053
4096
 
4054
4097
  // To keep the global namespace clean, we wrap everything in a closure
@@ -4170,7 +4213,7 @@ $.ui.fancytree.registerExtension({
4170
4213
  opts = ctx.options,
4171
4214
  extOpts = ctx.options.childcounter;
4172
4215
  // Optionally check for dependencies with other extensions
4173
- // this._requireExtension("glyph", false, false);
4216
+ /* this._requireExtension("glyph", false, false); */
4174
4217
  // Call the base implementation
4175
4218
  this._super(ctx);
4176
4219
  // Add a class to the tree container
@@ -4223,8 +4266,8 @@ $.ui.fancytree.registerExtension({
4223
4266
  * Released under the MIT license
4224
4267
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
4225
4268
  *
4226
- * @version 2.0.0-11
4227
- * @date 2014-04-27T22:28
4269
+ * @version 2.1.0
4270
+ * @date 2014-05-29T16:44
4228
4271
  */
4229
4272
 
4230
4273
  ;(function($, window, document, undefined) {
@@ -4287,8 +4330,7 @@ function _initDragAndDrop(tree) {
4287
4330
  addClasses: false,
4288
4331
  tolerance: "intersect",
4289
4332
  greedy: false
4290
- /*
4291
- ,
4333
+ /*
4292
4334
  activate: function(event, ui) {
4293
4335
  logMsg("droppable - activate", event, ui, this);
4294
4336
  },
@@ -4326,32 +4368,24 @@ function _registerDnd() {
4326
4368
  // 'draggable' was renamed to 'ui-draggable' since jQueryUI 1.10
4327
4369
  var draggable = $(this).data("ui-draggable") || $(this).data("draggable"),
4328
4370
  sourceNode = ui.helper.data("ftSourceNode") || null;
4329
- // logMsg("draggable-connectToFancytree.start, %s", sourceNode);
4330
- // logMsg(" this: %o", this);
4331
- // logMsg(" event: %o", event);
4332
- // logMsg(" draggable: %o", draggable);
4333
- // logMsg(" ui: %o", ui);
4334
4371
 
4335
4372
  if(sourceNode) {
4336
4373
  // Adjust helper offset, so cursor is slightly outside top/left corner
4337
4374
  draggable.offset.click.top = -2;
4338
4375
  draggable.offset.click.left = + 16;
4339
- // logMsg(" draggable2: %o", draggable);
4340
- // logMsg(" draggable.offset.click FIXED: %s/%s", draggable.offset.click.left, draggable.offset.click.top);
4341
4376
  // Trigger dragStart event
4342
4377
  // TODO: when called as connectTo..., the return value is ignored(?)
4343
4378
  return sourceNode.tree.ext.dnd._onDragEvent("start", sourceNode, null, event, ui, draggable);
4344
4379
  }
4345
4380
  },
4346
4381
  drag: function(event, ui) {
4347
- // 'draggable' was renamed to 'ui-draggable' since jQueryUI 1.10
4348
4382
  var isHelper,
4383
+ // 'draggable' was renamed to 'ui-draggable' since jQueryUI 1.10
4349
4384
  draggable = $(this).data("ui-draggable") || $(this).data("draggable"),
4350
4385
  sourceNode = ui.helper.data("ftSourceNode") || null,
4351
4386
  prevTargetNode = ui.helper.data("ftTargetNode") || null,
4352
4387
  targetNode = $.ui.fancytree.getNode(event.target);
4353
- // logMsg("$.ui.fancytree.getNode(%o): %s", event.target, targetNode);
4354
- // logMsg("connectToFancytree.drag: helper: %o", ui.helper[0]);
4388
+
4355
4389
  if(event.target && !targetNode){
4356
4390
  // We got a drag event, but the targetNode could not be found
4357
4391
  // at the event location. This may happen,
@@ -4364,7 +4398,6 @@ function _registerDnd() {
4364
4398
  return;
4365
4399
  }
4366
4400
  }
4367
- // logMsg("draggable-connectToFancytree.drag: targetNode(from event): %s, ftTargetNode: %s", targetNode, ui.helper.data("ftTargetNode"));
4368
4401
  ui.helper.data("ftTargetNode", targetNode);
4369
4402
  // Leaving a tree node
4370
4403
  if(prevTargetNode && prevTargetNode !== targetNode ) {
@@ -4391,10 +4424,7 @@ function _registerDnd() {
4391
4424
  // mouseDownEvent = draggable._mouseDownEvent,
4392
4425
  eventType = event.type,
4393
4426
  dropped = (eventType === "mouseup" && event.which === 1);
4394
- // logMsg("draggable-connectToFancytree.stop: targetNode(from event): %s, ftTargetNode: %s", targetNode, ui.helper.data("ftTargetNode"));
4395
- // logMsg("draggable-connectToFancytree.stop, %s", sourceNode);
4396
- // logMsg(" type: %o, downEvent: %o, upEvent: %o", eventType, mouseDownEvent, event);
4397
- // logMsg(" targetNode: %o", targetNode);
4427
+
4398
4428
  if(!dropped){
4399
4429
  logMsg("Drag was cancelled");
4400
4430
  }
@@ -4418,8 +4448,7 @@ function _registerDnd() {
4418
4448
  *
4419
4449
  */
4420
4450
 
4421
- $.ui.fancytree.registerExtension(
4422
- {
4451
+ $.ui.fancytree.registerExtension({
4423
4452
  name: "dnd",
4424
4453
  version: "0.1.0",
4425
4454
  // Default options for this extension.
@@ -4440,9 +4469,7 @@ $.ui.fancytree.registerExtension(
4440
4469
  draggable: null, // Additional options passed to jQuery draggable
4441
4470
  droppable: null // Additional options passed to jQuery droppable
4442
4471
  },
4443
- // Override virtual methods for this extension.
4444
- // `this` : Fancytree instance
4445
- // `this._super`: the virtual function that was overriden (member of prev. extension or Fancytree)
4472
+
4446
4473
  treeInit: function(ctx){
4447
4474
  var tree = ctx.tree;
4448
4475
  this._super(ctx);
@@ -4471,15 +4498,7 @@ $.ui.fancytree.registerExtension(
4471
4498
  .css({"z-index": 1000})
4472
4499
  .prependTo($(this.$div).parent());
4473
4500
  // .prependTo("body");
4474
- // logMsg("Creating marker: %o", this.$dropMarker);
4475
- }
4476
- /*
4477
- if(hitMode === "start"){
4478
4501
  }
4479
- if(hitMode === "stop"){
4480
- // sourceNode.removeClass("fancytree-drop-target");
4481
- }
4482
- */
4483
4502
  // this.$dropMarker.attr("class", hitMode);
4484
4503
  if(hitMode === "after" || hitMode === "before" || hitMode === "over"){
4485
4504
  // $source && $source.addClass("fancytree-drag-source");
@@ -4488,18 +4507,19 @@ $.ui.fancytree.registerExtension(
4488
4507
 
4489
4508
  switch(hitMode){
4490
4509
  case "before":
4491
- instData.$dropMarker.removeClass("fancytree-drop-after fancytree-drop-over");
4492
- instData.$dropMarker.addClass("fancytree-drop-before");
4510
+ instData
4511
+ .$dropMarker.removeClass("fancytree-drop-after fancytree-drop-over")
4512
+ .addClass("fancytree-drop-before");
4493
4513
  markerAt = "top";
4494
4514
  break;
4495
4515
  case "after":
4496
- instData.$dropMarker.removeClass("fancytree-drop-before fancytree-drop-over");
4497
- instData.$dropMarker.addClass("fancytree-drop-after");
4516
+ instData.$dropMarker.removeClass("fancytree-drop-before fancytree-drop-over")
4517
+ .addClass("fancytree-drop-after");
4498
4518
  markerAt = "bottom";
4499
4519
  break;
4500
4520
  default:
4501
- instData.$dropMarker.removeClass("fancytree-drop-after fancytree-drop-before");
4502
- instData.$dropMarker.addClass("fancytree-drop-over");
4521
+ instData.$dropMarker.removeClass("fancytree-drop-after fancytree-drop-before")
4522
+ .addClass("fancytree-drop-over");
4503
4523
  $target.addClass("fancytree-drop-target");
4504
4524
  markerOffsetX = 8;
4505
4525
  }
@@ -4594,15 +4614,15 @@ $.ui.fancytree.registerExtension(
4594
4614
  dnd = opts.dnd,
4595
4615
  ctx = this._makeHookContext(node, event, {otherNode: otherNode, ui: ui, draggable: draggable}),
4596
4616
  res = null,
4597
- nodeTag = $(node.span);
4617
+ $nodeTag = $(node.span);
4598
4618
 
4599
4619
  switch (eventName) {
4600
4620
  case "helper":
4601
4621
  // Only event and node argument is available
4602
4622
  $helper = $("<div class='fancytree-drag-helper'><span class='fancytree-drag-helper-img' /></div>")
4603
- // .append($(event.target).closest("span.fancytree-node").find("span.fancytree-title").clone());
4604
- .append(nodeTag.find("span.fancytree-title").clone());
4605
- // issue 244: helper should be child of scrollParent
4623
+ .css({zIndex: 3, position: "relative"}) // so it appears above ext-wide selection bar
4624
+ .append($nodeTag.find("span.fancytree-title").clone());
4625
+ // DT issue 244: helper should be child of scrollParent
4606
4626
  $("ul.fancytree-container", node.tree.$div).append($helper);
4607
4627
  // Attach node reference to helper object
4608
4628
  $helper.data("ftSourceNode", node);
@@ -4610,6 +4630,7 @@ $.ui.fancytree.registerExtension(
4610
4630
  // logMsg("helper.sourceNode=%o", $helper.data("ftSourceNode"));
4611
4631
  res = $helper;
4612
4632
  break;
4633
+
4613
4634
  case "start":
4614
4635
  if( node.isStatusNode() ) {
4615
4636
  res = false;
@@ -4621,12 +4642,13 @@ $.ui.fancytree.registerExtension(
4621
4642
  //draggable._clear();
4622
4643
  // NOTE: the return value seems to be ignored (drag is not canceled, when false is returned)
4623
4644
  // TODO: call this._cancelDrag()?
4624
- ui.helper.trigger("mouseup");
4625
- ui.helper.hide();
4645
+ ui.helper.trigger("mouseup")
4646
+ .hide();
4626
4647
  } else {
4627
- nodeTag.addClass("fancytree-drag-source");
4648
+ $nodeTag.addClass("fancytree-drag-source");
4628
4649
  }
4629
4650
  break;
4651
+
4630
4652
  case "enter":
4631
4653
  if(dnd.preventRecursiveMoves && node.isDescendantOf(otherNode)){
4632
4654
  r = false;
@@ -4653,6 +4675,7 @@ $.ui.fancytree.registerExtension(
4653
4675
  ui.helper.data("enterResponse", res);
4654
4676
  logMsg("helper.enterResponse: %o", res);
4655
4677
  break;
4678
+
4656
4679
  case "over":
4657
4680
  enterResponse = ui.helper.data("enterResponse");
4658
4681
  hitMode = null;
@@ -4664,11 +4687,11 @@ $.ui.fancytree.registerExtension(
4664
4687
  hitMode = enterResponse;
4665
4688
  } else {
4666
4689
  // Calculate hitMode from relative cursor position.
4667
- nodeOfs = nodeTag.offset();
4690
+ nodeOfs = $nodeTag.offset();
4668
4691
  relPos = { x: event.pageX - nodeOfs.left,
4669
4692
  y: event.pageY - nodeOfs.top };
4670
- relPos2 = { x: relPos.x / nodeTag.width(),
4671
- y: relPos.y / nodeTag.height() };
4693
+ relPos2 = { x: relPos.x / $nodeTag.width(),
4694
+ y: relPos.y / $nodeTag.height() };
4672
4695
 
4673
4696
  if( enterResponse.after && relPos2.y > 0.75 ){
4674
4697
  hitMode = "after";
@@ -4710,10 +4733,11 @@ $.ui.fancytree.registerExtension(
4710
4733
  ctx.hitMode = hitMode;
4711
4734
  res = dnd.dragOver(node, ctx);
4712
4735
  }
4713
- // issue 332
4736
+ // DT issue 332
4714
4737
  // this._setDndStatus(otherNode, node, ui.helper, hitMode, res!==false);
4715
4738
  this._local._setDndStatus(otherNode, node, ui.helper, hitMode, res!==false && hitMode !== null);
4716
4739
  break;
4740
+
4717
4741
  case "drop":
4718
4742
  hitMode = ui.helper.data("hitMode");
4719
4743
  if(hitMode && dnd.dragDrop){
@@ -4721,6 +4745,7 @@ $.ui.fancytree.registerExtension(
4721
4745
  dnd.dragDrop(node, ctx);
4722
4746
  }
4723
4747
  break;
4748
+
4724
4749
  case "leave":
4725
4750
  // Cancel pending expand request
4726
4751
  node.scheduleAction("cancel");
@@ -4731,14 +4756,16 @@ $.ui.fancytree.registerExtension(
4731
4756
  dnd.dragLeave(node, ctx);
4732
4757
  }
4733
4758
  break;
4759
+
4734
4760
  case "stop":
4735
- nodeTag.removeClass("fancytree-drag-source");
4761
+ $nodeTag.removeClass("fancytree-drag-source");
4736
4762
  if(dnd.dragStop){
4737
4763
  dnd.dragStop(node, ctx);
4738
4764
  }
4739
4765
  break;
4766
+
4740
4767
  default:
4741
- throw "Unsupported drag event: " + eventName;
4768
+ $.error("Unsupported drag event: " + eventName);
4742
4769
  }
4743
4770
  return res;
4744
4771
  },
@@ -4763,8 +4790,8 @@ $.ui.fancytree.registerExtension(
4763
4790
  * Released under the MIT license
4764
4791
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
4765
4792
  *
4766
- * @version 2.0.0-11
4767
- * @date 2014-04-27T22:28
4793
+ * @version 2.1.0
4794
+ * @date 2014-05-29T16:44
4768
4795
  */
4769
4796
 
4770
4797
  ;(function($, window, document, undefined) {
@@ -4985,7 +5012,7 @@ $.ui.fancytree._FancytreeNodeClass.prototype.endEdit = function(){
4985
5012
  * [ext-edit] Check if any node in this tree in edit mode.
4986
5013
  *
4987
5014
  * @returns {FancytreeNode | null}
4988
- * @lends Fancytree.prototype
5015
+ * @alias Fancytree#isEditing
4989
5016
  * @requires jquery.fancytree.edit.js
4990
5017
  */
4991
5018
  $.ui.fancytree._FancytreeClass.prototype.isEditing = function(){
@@ -4996,7 +5023,7 @@ $.ui.fancytree._FancytreeClass.prototype.isEditing = function(){
4996
5023
  /**
4997
5024
  * [ext-edit] Check if this node is in edit mode.
4998
5025
  * @returns {Boolean} true if node is currently beeing edited
4999
- * @lends FancytreeNode.prototype
5026
+ * @alias FancytreeNode#isEditing
5000
5027
  * @requires jquery.fancytree.edit.js
5001
5028
  */
5002
5029
  $.ui.fancytree._FancytreeNodeClass.prototype.isEditing = function(){
@@ -5027,10 +5054,6 @@ $.ui.fancytree.registerExtension({
5027
5054
  // Local attributes
5028
5055
  currentNode: null,
5029
5056
 
5030
- // Override virtual methods for this extension.
5031
- // `this` : the Fancytree instance
5032
- // `this._local`: the namespace that contains extension attributes and private methods (same as this.ext.EXTNAME)
5033
- // `this._super`: the virtual function that was overridden (member of previous extension or Fancytree)
5034
5057
  treeInit: function(ctx){
5035
5058
  this._super(ctx);
5036
5059
  this.$container.addClass("fancytree-ext-edit");
@@ -5042,7 +5065,7 @@ $.ui.fancytree.registerExtension({
5042
5065
  return false;
5043
5066
  }
5044
5067
  }
5045
- this._super(ctx);
5068
+ return this._super(ctx);
5046
5069
  },
5047
5070
  nodeDblclick: function(ctx) {
5048
5071
  if( $.inArray("dblclick", ctx.options.edit.triggerStart) >= 0 ){
@@ -5082,8 +5105,8 @@ $.ui.fancytree.registerExtension({
5082
5105
  * Released under the MIT license
5083
5106
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5084
5107
  *
5085
- * @version 2.0.0-11
5086
- * @date 2014-04-27T22:28
5108
+ * @version 2.1.0
5109
+ * @date 2014-05-29T16:44
5087
5110
  */
5088
5111
 
5089
5112
  ;(function($, window, document, undefined) {
@@ -5100,33 +5123,12 @@ function _escapeRegex(str){
5100
5123
  return (str + "").replace(/([.?*+\^\$\[\]\\(){}|-])/g, "\\$1");
5101
5124
  }
5102
5125
 
5103
- /* EXT-TABLE: Show/hide all rows that are structural descendants of `parent`. */
5104
- // function setChildRowVisibility(parent, flag) {
5105
- // parent.visit(function(node){
5106
- // var tr = node.tr;
5107
- // if(tr){
5108
- // tr.style.display = flag ? "" : "none";
5109
- // }
5110
- // node.debug(flag ? "SHOW" : "HIDE");
5111
- // if(!node.expanded){
5112
- // return "skip";
5113
- // }
5114
- // });
5115
- // }
5116
-
5117
- /**
5118
- * [ext-filter] Dimm or hide nodes.
5119
- *
5120
- * @param {function | string} filter
5121
- * @returns {integer} count
5122
- * @alias Fancytree#applyFilter
5123
- * @requires jquery.fancytree.filter.js
5124
- */
5125
- $.ui.fancytree._FancytreeClass.prototype.applyFilter = function(filter){
5126
+ $.ui.fancytree._FancytreeClass.prototype._applyFilterImpl = function(filter, branchMode, leavesOnly){
5126
5127
  var match, re,
5127
5128
  count = 0,
5128
- hideMode = this.options.filter.mode === "hide",
5129
- leavesOnly = this.options.filter.leavesOnly;
5129
+ hideMode = this.options.filter.mode === "hide";
5130
+ // leavesOnly = !branchMode && this.options.filter.leavesOnly;
5131
+ leavesOnly = !!leavesOnly && !branchMode;
5130
5132
 
5131
5133
  // Default to 'match title substring (not case sensitive)'
5132
5134
  if(typeof filter === "string"){
@@ -5146,7 +5148,6 @@ $.ui.fancytree._FancytreeClass.prototype.applyFilter = function(filter){
5146
5148
  }
5147
5149
  // Reset current filter
5148
5150
  this.visit(function(node){
5149
- // node.hide = hideMode && true;
5150
5151
  delete node.match;
5151
5152
  delete node.subMatch;
5152
5153
  });
@@ -5154,12 +5155,16 @@ $.ui.fancytree._FancytreeClass.prototype.applyFilter = function(filter){
5154
5155
  this.visit(function(node){
5155
5156
  if ((!leavesOnly || node.children == null) && filter(node)) {
5156
5157
  count++;
5157
- // node.hide = false;
5158
5158
  node.match = true;
5159
5159
  node.visitParents(function(p){
5160
- // p.hide = false;
5161
5160
  p.subMatch = true;
5162
5161
  });
5162
+ if( branchMode ) {
5163
+ node.visit(function(p){
5164
+ p.match = true;
5165
+ });
5166
+ return "skip";
5167
+ }
5163
5168
  }
5164
5169
  });
5165
5170
  // Redraw
@@ -5167,15 +5172,45 @@ $.ui.fancytree._FancytreeClass.prototype.applyFilter = function(filter){
5167
5172
  return count;
5168
5173
  };
5169
5174
 
5175
+ /**
5176
+ * [ext-filter] Dimm or hide nodes.
5177
+ *
5178
+ * @param {function | string} filter
5179
+ * @param {boolean} [leavesOnly=false]
5180
+ * @returns {integer} count
5181
+ * @alias Fancytree#filterNodes
5182
+ * @requires jquery.fancytree.filter.js
5183
+ */
5184
+ $.ui.fancytree._FancytreeClass.prototype.filterNodes = function(filter, leavesOnly){
5185
+ return this._applyFilterImpl(filter, false, leavesOnly);
5186
+ };
5187
+
5188
+ $.ui.fancytree._FancytreeClass.prototype.applyFilter = function(filter){
5189
+ this.warn("Fancytree.applyFilter() is deprecated since 2014-05-10. Use .filterNodes() instead.");
5190
+ return this.filterNodes.apply(this, arguments);
5191
+ };
5192
+
5193
+ /**
5194
+ * [ext-filter] Dimm or hide whole branches.
5195
+ *
5196
+ * @param {function | string} filter
5197
+ * @returns {integer} count
5198
+ * @alias Fancytree#filterBranches
5199
+ * @requires jquery.fancytree.filter.js
5200
+ */
5201
+ $.ui.fancytree._FancytreeClass.prototype.filterBranches = function(filter){
5202
+ return this._applyFilterImpl(filter, true, null);
5203
+ };
5204
+
5205
+
5170
5206
  /**
5171
5207
  * [ext-filter] Reset the filter.
5172
5208
  *
5173
- * @alias Fancytree#applyFilter
5209
+ * @alias Fancytree#clearFilter
5174
5210
  * @requires jquery.fancytree.filter.js
5175
5211
  */
5176
5212
  $.ui.fancytree._FancytreeClass.prototype.clearFilter = function(){
5177
5213
  this.visit(function(node){
5178
- // delete node.hide;
5179
5214
  delete node.match;
5180
5215
  delete node.subMatch;
5181
5216
  });
@@ -5190,22 +5225,14 @@ $.ui.fancytree._FancytreeClass.prototype.clearFilter = function(){
5190
5225
  */
5191
5226
  $.ui.fancytree.registerExtension({
5192
5227
  name: "filter",
5193
- version: "0.0.2",
5228
+ version: "0.2.0",
5194
5229
  // Default options for this extension.
5195
5230
  options: {
5196
- mode: "dimm",
5197
- leavesOnly: false
5231
+ mode: "dimm"
5232
+ // leavesOnly: false
5198
5233
  },
5199
- // Override virtual methods for this extension.
5200
- // `this` : is this extension object
5201
- // `this._base` : the Fancytree instance
5202
- // `this._super`: the virtual function that was overriden (member of prev. extension or Fancytree)
5203
5234
  treeInit: function(ctx){
5204
5235
  this._super(ctx);
5205
- // ctx.tree.filter = false;
5206
- },
5207
- treeDestroy: function(ctx){
5208
- this._super(ctx);
5209
5236
  },
5210
5237
  nodeRenderStatus: function(ctx) {
5211
5238
  // Set classes for current status
@@ -5215,31 +5242,15 @@ $.ui.fancytree.registerExtension({
5215
5242
  $span = $(node[tree.statusClassPropName]);
5216
5243
 
5217
5244
  res = this._super(ctx);
5218
-
5219
- if(!$span.length){
5220
- return res; // nothing to do, if node was not yet rendered
5221
- }
5222
- if(!tree.enableFilter){
5245
+ // nothing to do, if node was not yet rendered
5246
+ if( !$span.length || !tree.enableFilter ) {
5223
5247
  return res;
5224
5248
  }
5225
- $span.toggleClass("fancytree-match", !!node.match);
5226
- $span.toggleClass("fancytree-submatch", !!node.subMatch);
5227
- $span.toggleClass("fancytree-hide", !(node.match || node.subMatch));
5228
-
5229
- // if(opts.filter.mode === "hide"){
5230
- // // visible = !!(node.match || node.subMatch);
5231
- // visible = !node.hide;
5232
- // node.debug(node.title + ": visible=" + visible);
5233
- // if( node.li ) {
5234
- // $(node.li).toggle(visible);
5235
- // } else if( node.tr ) {
5236
- // // Show/hide all rows that are structural descendants of `parent`
5237
- // $(node.tr).toggle(visible);
5238
- // // if( !visible ) {
5239
- // // setChildRowVisibility(node, visible);
5240
- // // }
5241
- // }
5242
- // }
5249
+ $span
5250
+ .toggleClass("fancytree-match", !!node.match)
5251
+ .toggleClass("fancytree-submatch", !!node.subMatch)
5252
+ .toggleClass("fancytree-hide", !(node.match || node.subMatch));
5253
+
5243
5254
  return res;
5244
5255
  }
5245
5256
  });
@@ -5256,8 +5267,8 @@ $.ui.fancytree.registerExtension({
5256
5267
  * Released under the MIT license
5257
5268
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5258
5269
  *
5259
- * @version 2.0.0-11
5260
- * @date 2014-04-27T22:28
5270
+ * @version 2.1.0
5271
+ * @date 2014-05-29T16:44
5261
5272
  */
5262
5273
 
5263
5274
  ;(function($, window, document, undefined) {
@@ -5274,7 +5285,7 @@ function _getIcon(opts, type){
5274
5285
 
5275
5286
  $.ui.fancytree.registerExtension({
5276
5287
  name: "glyph",
5277
- version: "0.0.2",
5288
+ version: "0.1.0",
5278
5289
  // Default options for this extension.
5279
5290
  options: {
5280
5291
  prefix: "icon-",
@@ -5288,19 +5299,15 @@ $.ui.fancytree.registerExtension({
5288
5299
  error: "icon-exclamation-sign",
5289
5300
  expanderClosed: "icon-caret-right",
5290
5301
  expanderLazy: "icon-angle-right",
5291
- // expanderLazy: "icon-refresh icon-spin",
5292
5302
  expanderOpen: "icon-caret-down",
5293
5303
  folder: "icon-folder-close-alt",
5294
5304
  folderOpen: "icon-folder-open-alt",
5295
5305
  loading: "icon-refresh icon-spin",
5296
- // loading: "icon-spinner icon-spin"
5297
5306
  noExpander: ""
5298
5307
  },
5299
5308
  icon: null // TODO: allow callback here
5300
5309
  },
5301
- // Overide virtual methods for this extension.
5302
- // `this` : is this extension object
5303
- // `this._super`: the virtual function that was overriden (member of prev. extension or Fancytree)
5310
+
5304
5311
  treeInit: function(ctx){
5305
5312
  var tree = ctx.tree;
5306
5313
  this._super(ctx);
@@ -5364,7 +5371,8 @@ $.ui.fancytree.registerExtension({
5364
5371
  if(node.parent){
5365
5372
  span = $("span.fancytree-expander", node.span).get(0);
5366
5373
  }else{
5367
- span = $(".fancytree-statusnode-wait, .fancytree-statusnode-error", node[this.nodeContainerAttrName]).find("span.fancytree-expander").get(0);
5374
+ span = $(".fancytree-statusnode-wait, .fancytree-statusnode-error", node[this.nodeContainerAttrName])
5375
+ .find("span.fancytree-expander").get(0);
5368
5376
  }
5369
5377
  if( status === "loading"){
5370
5378
  // $("span.fancytree-expander", ctx.node.span).addClass(_getIcon(opts, "loading"));
@@ -5387,8 +5395,8 @@ $.ui.fancytree.registerExtension({
5387
5395
  * Released under the MIT license
5388
5396
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5389
5397
  *
5390
- * @version 2.0.0-11
5391
- * @date 2014-04-27T22:28
5398
+ * @version 2.1.0
5399
+ * @date 2014-05-29T16:44
5392
5400
  */
5393
5401
 
5394
5402
  ;(function($, window, document, undefined) {
@@ -5589,8 +5597,8 @@ $.ui.fancytree.registerExtension({
5589
5597
  * Released under the MIT license
5590
5598
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5591
5599
  *
5592
- * @version 2.0.0-11
5593
- * @date 2014-04-27T22:28
5600
+ * @version 2.1.0
5601
+ * @date 2014-05-29T16:44
5594
5602
  */
5595
5603
 
5596
5604
  ;(function($, window, document, undefined) {
@@ -5617,15 +5625,13 @@ var ACTIVE = "active",
5617
5625
  /* Recursively load lazy nodes
5618
5626
  * @param {string} mode 'load', 'expand', false
5619
5627
  */
5620
- function _loadLazyNodes(tree, instData, keyList, mode, dfd) {
5628
+ function _loadLazyNodes(tree, local, keyList, mode, dfd) {
5621
5629
  var i, key, l, node,
5622
5630
  foundOne = false,
5623
5631
  deferredList = [],
5624
- // lazyNodeList = [],
5625
- missingKeyList = []; //keyList.slice(0),
5632
+ missingKeyList = [];
5626
5633
 
5627
5634
  keyList = keyList || [];
5628
- // expand = expand !== false;
5629
5635
  dfd = dfd || $.Deferred();
5630
5636
 
5631
5637
  for( i=0, l=keyList.length; i<l; i++ ) {
@@ -5633,7 +5639,6 @@ function _loadLazyNodes(tree, instData, keyList, mode, dfd) {
5633
5639
  node = tree.getNodeByKey(key);
5634
5640
  if( node ) {
5635
5641
  if( mode && node.isUndefined() ) {
5636
- // lazyNodeList.push(node);
5637
5642
  foundOne = true;
5638
5643
  tree.debug("_loadLazyNodes: " + node + " is lazy: loading...");
5639
5644
  if( mode === "expand" ) {
@@ -5644,8 +5649,6 @@ function _loadLazyNodes(tree, instData, keyList, mode, dfd) {
5644
5649
  } else {
5645
5650
  tree.debug("_loadLazyNodes: " + node + " already loaded.");
5646
5651
  node.setExpanded();
5647
- // node.expanded = true;
5648
- // node.render();
5649
5652
  }
5650
5653
  } else {
5651
5654
  missingKeyList.push(key);
@@ -5657,13 +5660,13 @@ function _loadLazyNodes(tree, instData, keyList, mode, dfd) {
5657
5660
  // All lazy-expands have finished
5658
5661
  if( foundOne && missingKeyList.length > 0 ) {
5659
5662
  // If we read new nodes from server, try to resolve yet-missing keys
5660
- _loadLazyNodes(tree, instData, missingKeyList, mode, dfd);
5663
+ _loadLazyNodes(tree, local, missingKeyList, mode, dfd);
5661
5664
  } else {
5662
5665
  if( missingKeyList.length ) {
5663
5666
  tree.warn("_loadLazyNodes: could not load those keys: ", missingKeyList);
5664
5667
  for( i=0, l=missingKeyList.length; i<l; i++ ) {
5665
5668
  key = keyList[i];
5666
- instData._setKey(EXPANDED, keyList[i], false);
5669
+ local._appendKey(EXPANDED, keyList[i], false);
5667
5670
  }
5668
5671
  }
5669
5672
  dfd.resolve();
@@ -5682,26 +5685,21 @@ function _loadLazyNodes(tree, instData, keyList, mode, dfd) {
5682
5685
  * @requires jquery.fancytree.persist.js
5683
5686
  */
5684
5687
  $.ui.fancytree._FancytreeClass.prototype.clearCookies = function(types){
5685
- var inst = this.ext.persist,
5686
- cookiePrefix = inst.cookiePrefix;
5688
+ var local = this.ext.persist,
5689
+ prefix = local.cookiePrefix;
5687
5690
 
5688
5691
  types = types || "active expanded focus selected";
5689
- // TODO: optimize
5690
5692
  if(types.indexOf(ACTIVE) >= 0){
5691
- // $.cookie(cookiePrefix + ACTIVE, null);
5692
- $.removeCookie(cookiePrefix + ACTIVE);
5693
+ local._data(prefix + ACTIVE, null);
5693
5694
  }
5694
5695
  if(types.indexOf(EXPANDED) >= 0){
5695
- // $.cookie(cookiePrefix + EXPANDED, null);
5696
- $.removeCookie(cookiePrefix + EXPANDED);
5696
+ local._data(prefix + EXPANDED, null);
5697
5697
  }
5698
5698
  if(types.indexOf(FOCUS) >= 0){
5699
- // $.cookie(cookiePrefix + FOCUS, null);
5700
- $.removeCookie(cookiePrefix + FOCUS);
5699
+ local._data(prefix + FOCUS, null);
5701
5700
  }
5702
5701
  if(types.indexOf(SELECTED) >= 0){
5703
- // $.cookie(cookiePrefix + SELECTED, null);
5704
- $.removeCookie(cookiePrefix + SELECTED);
5702
+ local._data(prefix + SELECTED, null);
5705
5703
  }
5706
5704
  };
5707
5705
 
@@ -5716,15 +5714,15 @@ $.ui.fancytree._FancytreeClass.prototype.clearCookies = function(types){
5716
5714
  * @requires jquery.fancytree.persist.js
5717
5715
  */
5718
5716
  $.ui.fancytree._FancytreeClass.prototype.getPersistData = function(){
5719
- var inst = this.ext.persist,
5720
- instOpts= this.options.persist,
5721
- delim = instOpts.cookieDelimiter,
5717
+ var local = this.ext.persist,
5718
+ prefix = local.cookiePrefix,
5719
+ delim = local.cookieDelimiter,
5722
5720
  res = {};
5723
5721
 
5724
- res[ACTIVE] = $.cookie(inst.cookiePrefix + ACTIVE);
5725
- res[EXPANDED] = ($.cookie(inst.cookiePrefix + EXPANDED) || "").split(delim);
5726
- res[SELECTED] = ($.cookie(inst.cookiePrefix + SELECTED) || "").split(delim);
5727
- res[FOCUS] = $.cookie(inst.cookiePrefix + FOCUS);
5722
+ res[ACTIVE] = local._data(prefix + ACTIVE);
5723
+ res[EXPANDED] = (local._data(prefix + EXPANDED) || "").split(delim);
5724
+ res[SELECTED] = (local._data(prefix + SELECTED) || "").split(delim);
5725
+ res[FOCUS] = local._data(prefix + FOCUS);
5728
5726
  return res;
5729
5727
  };
5730
5728
 
@@ -5734,10 +5732,9 @@ $.ui.fancytree._FancytreeClass.prototype.getPersistData = function(){
5734
5732
  */
5735
5733
  $.ui.fancytree.registerExtension({
5736
5734
  name: "persist",
5737
- version: "0.2.0",
5735
+ version: "0.3.0",
5738
5736
  // Default options for this extension.
5739
5737
  options: {
5740
- // appendRequestInfo: false,
5741
5738
  cookieDelimiter: "~",
5742
5739
  cookiePrefix: undefined, // 'fancytree-<treeId>-' by default
5743
5740
  cookie: {
@@ -5747,89 +5744,96 @@ $.ui.fancytree.registerExtension({
5747
5744
  domain: "",
5748
5745
  secure: false
5749
5746
  },
5750
- expandLazy: false, // true: recursively expand and load lazy nodes
5751
- overrideSource: false, // true: cookie takes precedence over `source` data attributes.
5747
+ expandLazy: false, // true: recursively expand and load lazy nodes
5748
+ overrideSource: false, // true: cookie takes precedence over `source` data attributes.
5749
+ store: "auto", // 'cookie': force cookie, 'local': force localStore, 'session': force sessionStore
5752
5750
  types: "active expanded focus selected"
5753
5751
  },
5754
5752
 
5753
+ /* Generic read/write string data to cookie, sessionStorage or localStorage. */
5754
+ _data: function(key, value){
5755
+ var ls = this._local.localStorage; // null, sessionStorage, or localStorage
5756
+
5757
+ if( value === undefined ) {
5758
+ return ls ? ls.getItem(key) : $.cookie(key);
5759
+ } else if ( value === null ) {
5760
+ if( ls ) {
5761
+ ls.removeItem(key);
5762
+ } else {
5763
+ $.removeCookie(key);
5764
+ }
5765
+ } else {
5766
+ if( ls ) {
5767
+ ls.setItem(key, value);
5768
+ } else {
5769
+ $.cookie(key, value, this.options.persist.cookie);
5770
+ }
5771
+ }
5772
+ },
5773
+
5755
5774
  /* Append `key` to a cookie. */
5756
- _setKey: function(type, key, flag){
5775
+ _appendKey: function(type, key, flag){
5757
5776
  key = "" + key; // #90
5758
- var instData = this._local,
5777
+ var local = this._local,
5759
5778
  instOpts = this.options.persist,
5760
- cookieName = instData.cookiePrefix + type,
5761
- cookie = $.cookie(cookieName),
5762
- cookieList = cookie ? cookie.split(instOpts.cookieDelimiter) : [],
5763
- idx = $.inArray(key, cookieList);
5779
+ delim = instOpts.cookieDelimiter,
5780
+ cookieName = local.cookiePrefix + type,
5781
+ data = local._data(cookieName),
5782
+ keyList = data ? data.split(delim) : [],
5783
+ idx = $.inArray(key, keyList);
5764
5784
  // Remove, even if we add a key, so the key is always the last entry
5765
5785
  if(idx >= 0){
5766
- cookieList.splice(idx, 1);
5786
+ keyList.splice(idx, 1);
5767
5787
  }
5768
5788
  // Append key to cookie
5769
5789
  if(flag){
5770
- cookieList.push(key);
5790
+ keyList.push(key);
5771
5791
  }
5772
- $.cookie(cookieName, cookieList.join(instOpts.cookieDelimiter), instOpts.cookie);
5792
+ local._data(cookieName, keyList.join(delim));
5773
5793
  },
5774
- // Overide virtual methods for this extension.
5775
- // `this` : is this Fancytree object
5776
- // `this._super`: the virtual function that was overridden (member of prev. extension or Fancytree)
5794
+
5777
5795
  treeInit: function(ctx){
5778
5796
  var tree = ctx.tree,
5779
5797
  opts = ctx.options,
5780
- instData = this._local,
5798
+ local = this._local,
5781
5799
  instOpts = this.options.persist;
5782
5800
 
5783
- _assert($.cookie, "Missing required plugin for 'persist' extension: jquery.cookie.js");
5801
+ // For 'auto' or 'cookie' mode, the cookie plugin must be available
5802
+ _assert(instOpts.store === "localStore" || $.cookie, "Missing required plugin for 'persist' extension: jquery.cookie.js");
5784
5803
 
5785
- instData.cookiePrefix = instOpts.cookiePrefix || ("fancytree-" + tree._id + "-");
5786
- instData.storeActive = instOpts.types.indexOf(ACTIVE) >= 0;
5787
- instData.storeExpanded = instOpts.types.indexOf(EXPANDED) >= 0;
5788
- instData.storeSelected = instOpts.types.indexOf(SELECTED) >= 0;
5789
- instData.storeFocus = instOpts.types.indexOf(FOCUS) >= 0;
5804
+ local.cookiePrefix = instOpts.cookiePrefix || ("fancytree-" + tree._id + "-");
5805
+ local.storeActive = instOpts.types.indexOf(ACTIVE) >= 0;
5806
+ local.storeExpanded = instOpts.types.indexOf(EXPANDED) >= 0;
5807
+ local.storeSelected = instOpts.types.indexOf(SELECTED) >= 0;
5808
+ local.storeFocus = instOpts.types.indexOf(FOCUS) >= 0;
5809
+ if( instOpts.store === "cookie" || !window.localStorage ) {
5810
+ local.localStorage = null;
5811
+ } else {
5812
+ local.localStorage = (instOpts.store === "local") ? window.localStorage : window.sessionStorage;
5813
+ }
5790
5814
 
5791
5815
  // Bind init-handler to apply cookie state
5792
5816
  tree.$div.bind("fancytreeinit", function(event){
5793
5817
  var cookie, dfd, i, keyList, node,
5794
- prevFocus = $.cookie(instData.cookiePrefix + FOCUS); // record this before node.setActive() overrides it;
5818
+ prevFocus = $.cookie(local.cookiePrefix + FOCUS); // record this before node.setActive() overrides it;
5795
5819
 
5796
5820
  tree.debug("COOKIE " + document.cookie);
5797
5821
 
5798
- cookie = $.cookie(instData.cookiePrefix + EXPANDED);
5822
+ cookie = local._data(local.cookiePrefix + EXPANDED);
5799
5823
  keyList = cookie && cookie.split(instOpts.cookieDelimiter);
5800
5824
 
5801
- if( instData.storeExpanded ) {
5825
+ if( local.storeExpanded ) {
5802
5826
  // Recursively load nested lazy nodes if expandLazy is 'expand' or 'load'
5803
5827
  // Also remove expand-cookies for unmatched nodes
5804
- dfd = _loadLazyNodes(tree, instData, keyList, instOpts.expandLazy ? "expand" : false , null);
5828
+ dfd = _loadLazyNodes(tree, local, keyList, instOpts.expandLazy ? "expand" : false , null);
5805
5829
  } else {
5806
5830
  // nothing to do
5807
5831
  dfd = new $.Deferred().resolve();
5808
5832
  }
5809
5833
 
5810
5834
  dfd.done(function(){
5811
- // alert("persistent expand done");
5812
- // if(instData.storeExpanded){
5813
- // cookie = $.cookie(instData.cookiePrefix + EXPANDED);
5814
- // if(cookie){
5815
- // keyList = cookie.split(instOpts.cookieDelimiter);
5816
- // for(i=0; i<keyList.length; i++){
5817
- // node = tree.getNodeByKey(keyList[i]);
5818
- // if(node){
5819
- // if(node.expanded === undefined || instOpts.overrideSource && (node.expanded === false)){
5820
- // // node.setExpanded();
5821
- // node.expanded = true;
5822
- // node.render();
5823
- // }
5824
- // }else{
5825
- // // node is no longer member of the tree: remove from cookie
5826
- // instData._setKey(EXPANDED, keyList[i], false);
5827
- // }
5828
- // }
5829
- // }
5830
- // }
5831
- if(instData.storeSelected){
5832
- cookie = $.cookie(instData.cookiePrefix + SELECTED);
5835
+ if(local.storeSelected){
5836
+ cookie = local._data(local.cookiePrefix + SELECTED);
5833
5837
  if(cookie){
5834
5838
  keyList = cookie.split(instOpts.cookieDelimiter);
5835
5839
  for(i=0; i<keyList.length; i++){
@@ -5842,13 +5846,13 @@ $.ui.fancytree.registerExtension({
5842
5846
  }
5843
5847
  }else{
5844
5848
  // node is no longer member of the tree: remove from cookie also
5845
- instData._setKey(SELECTED, keyList[i], false);
5849
+ local._appendKey(SELECTED, keyList[i], false);
5846
5850
  }
5847
5851
  }
5848
5852
  }
5849
5853
  }
5850
- if(instData.storeActive){
5851
- cookie = $.cookie(instData.cookiePrefix + ACTIVE);
5854
+ if(local.storeActive){
5855
+ cookie = local._data(local.cookiePrefix + ACTIVE);
5852
5856
  if(cookie && (opts.persist.overrideSource || !tree.activeNode)){
5853
5857
  node = tree.getNodeByKey(cookie);
5854
5858
  if(node){
@@ -5856,7 +5860,7 @@ $.ui.fancytree.registerExtension({
5856
5860
  }
5857
5861
  }
5858
5862
  }
5859
- if(instData.storeFocus && prevFocus){
5863
+ if(local.storeFocus && prevFocus){
5860
5864
  node = tree.getNodeByKey(prevFocus);
5861
5865
  if(node){
5862
5866
  node.setFocus();
@@ -5865,59 +5869,57 @@ $.ui.fancytree.registerExtension({
5865
5869
  });
5866
5870
  });
5867
5871
  // Init the tree
5868
- this._super(ctx);
5872
+ return this._super(ctx);
5869
5873
  },
5870
- // treeDestroy: function(ctx){
5871
- // this._super(ctx);
5872
- // },
5873
5874
  nodeSetActive: function(ctx, flag, opts) {
5874
- var instData = this._local,
5875
- instOpts = this.options.persist;
5875
+ var res,
5876
+ local = this._local;
5876
5877
 
5877
- flag = flag !== false;
5878
- this._super(ctx, flag, opts);
5878
+ flag = (flag !== false);
5879
+ res = this._super(ctx, flag, opts);
5879
5880
 
5880
- if(instData.storeActive){
5881
- $.cookie(instData.cookiePrefix + ACTIVE,
5882
- this.activeNode ? this.activeNode.key : null,
5883
- instOpts.cookie);
5881
+ if(local.storeActive){
5882
+ local._data(local.cookiePrefix + ACTIVE, this.activeNode ? this.activeNode.key : null);
5884
5883
  }
5884
+ return res;
5885
5885
  },
5886
5886
  nodeSetExpanded: function(ctx, flag, opts) {
5887
5887
  var res,
5888
5888
  node = ctx.node,
5889
- instData = this._local;
5889
+ local = this._local;
5890
5890
 
5891
- flag = flag !== false;
5891
+ flag = (flag !== false);
5892
5892
  res = this._super(ctx, flag, opts);
5893
5893
 
5894
- if(instData.storeExpanded){
5895
- instData._setKey(EXPANDED, node.key, flag);
5894
+ if(local.storeExpanded){
5895
+ local._appendKey(EXPANDED, node.key, flag);
5896
5896
  }
5897
5897
  return res;
5898
5898
  },
5899
- nodeSetFocus: function(ctx) {
5900
- var instData = this._local,
5901
- instOpts = this.options.persist;
5899
+ nodeSetFocus: function(ctx, flag) {
5900
+ var res,
5901
+ local = this._local;
5902
5902
 
5903
- this._super(ctx);
5903
+ flag = (flag !== false);
5904
+ res = this._super(ctx, flag);
5904
5905
 
5905
- if(instData.storeFocus){
5906
- $.cookie(instData.cookiePrefix + FOCUS,
5907
- this.focusNode ? this.focusNode.key : null,
5908
- instOpts.cookie);
5906
+ if(flag && local.storeFocus){
5907
+ local._data(local.cookiePrefix + FOCUS, this.focusNode ? this.focusNode.key : null);
5909
5908
  }
5909
+ return res;
5910
5910
  },
5911
5911
  nodeSetSelected: function(ctx, flag) {
5912
- var node = ctx.node,
5913
- instData = this._local;
5912
+ var res,
5913
+ node = ctx.node,
5914
+ local = this._local;
5914
5915
 
5915
- flag = flag !== false;
5916
- this._super(ctx, flag);
5916
+ flag = (flag !== false);
5917
+ res = this._super(ctx, flag);
5917
5918
 
5918
- if(instData.storeSelected){
5919
- instData._setKey(SELECTED, node.key, flag);
5919
+ if(local.storeSelected){
5920
+ local._appendKey(SELECTED, node.key, flag);
5920
5921
  }
5922
+ return res;
5921
5923
  }
5922
5924
  });
5923
5925
  }(jQuery, window, document));
@@ -5933,8 +5935,8 @@ $.ui.fancytree.registerExtension({
5933
5935
  * Released under the MIT license
5934
5936
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5935
5937
  *
5936
- * @version 2.0.0-11
5937
- * @date 2014-04-27T22:28
5938
+ * @version 2.1.0
5939
+ * @date 2014-05-29T16:44
5938
5940
  */
5939
5941
 
5940
5942
  ;(function($, window, document, undefined) {
@@ -6222,23 +6224,37 @@ $.ui.fancytree.registerExtension({
6222
6224
  /* Expand node, return Deferred.promise. */
6223
6225
  nodeSetExpanded: function(ctx, flag, opts) {
6224
6226
  var dfd = new $.Deferred(),
6225
- prevOpts = opts || {};
6227
+ subOpts = $.extend({}, opts, {noEvents: true, noAnimation: true});
6226
6228
 
6227
- opts = $.extend({}, opts, {noEvents: true, noAnimation: true});
6229
+ opts = opts || {};
6228
6230
 
6229
6231
  function _afterExpand(ok) {
6230
6232
  flag = (flag !== false);
6231
6233
  setChildRowVisibility(ctx.node, flag);
6232
- if( !prevOpts.noEvents ) {
6233
- ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx);
6234
- }
6235
6234
  if( ok ) {
6236
- dfd.resolveWith(ctx.node);
6235
+ if( flag && ctx.options.autoScroll && !opts.noAnimation && ctx.node.hasChildren() ) {
6236
+ // Scroll down to last child, but keep current node visible
6237
+ ctx.node.getLastChild().scrollIntoView(true, {topNode: ctx.node}).always(function(){
6238
+ if( !opts.noEvents ) {
6239
+ ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx);
6240
+ }
6241
+ dfd.resolveWith(ctx.node);
6242
+ });
6243
+ } else {
6244
+ if( !opts.noEvents ) {
6245
+ ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx);
6246
+ }
6247
+ dfd.resolveWith(ctx.node);
6248
+ }
6237
6249
  } else {
6250
+ if( !opts.noEvents ) {
6251
+ ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx);
6252
+ }
6238
6253
  dfd.rejectWith(ctx.node);
6239
6254
  }
6240
6255
  }
6241
- this._super(ctx, flag, opts).done(function () {
6256
+ // Call base-expand with disabled events and animation
6257
+ this._super(ctx, flag, subOpts).done(function () {
6242
6258
  _afterExpand(true);
6243
6259
  }).fail(function () {
6244
6260
  _afterExpand(false);
@@ -6281,8 +6297,8 @@ $.ui.fancytree.registerExtension({
6281
6297
  * Released under the MIT license
6282
6298
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
6283
6299
  *
6284
- * @version 2.0.0-11
6285
- * @date 2014-04-27T22:28
6300
+ * @version 2.1.0
6301
+ * @date 2014-05-29T16:44
6286
6302
  */
6287
6303
 
6288
6304
  ;(function($, window, document, undefined) {
@@ -6302,10 +6318,7 @@ $.ui.fancytree.registerExtension({
6302
6318
  hoverClass: "ui-state-hover",
6303
6319
  selectedClass: "ui-state-highlight"
6304
6320
  },
6305
- // Overide virtual methods for this extension.
6306
- // `this` : is this extension object
6307
- // `this._base` : the Fancytree instance
6308
- // `this._super`: the virtual function that was overriden (member of prev. extension or Fancytree)
6321
+
6309
6322
  treeInit: function(ctx){
6310
6323
  this._super(ctx);
6311
6324
  var $el = ctx.widget.element;