fancytree-rails 2.1.0.pre.0 → 2.3.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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +1 -1
  4. data/Rakefile +3 -4
  5. data/app/assets/javascripts/fancytree/jquery.fancytree-all.js +568 -51
  6. data/app/assets/javascripts/fancytree/jquery.fancytree-custom.min.js +9 -6
  7. data/app/assets/javascripts/fancytree/jquery.fancytree.js +63 -27
  8. data/app/assets/javascripts/fancytree/jquery.fancytree.min.js +4 -4
  9. data/app/assets/javascripts/fancytree/src/jquery.fancytree.childcounter.js +2 -2
  10. data/app/assets/javascripts/fancytree/src/jquery.fancytree.clones.js +7 -3
  11. data/app/assets/javascripts/fancytree/src/jquery.fancytree.columnview.js +2 -2
  12. data/app/assets/javascripts/fancytree/src/jquery.fancytree.debug.js +2 -2
  13. data/app/assets/javascripts/fancytree/src/jquery.fancytree.dnd.js +24 -4
  14. data/app/assets/javascripts/fancytree/src/jquery.fancytree.edit.js +3 -2
  15. data/app/assets/javascripts/fancytree/src/jquery.fancytree.filter.js +2 -2
  16. data/app/assets/javascripts/fancytree/src/jquery.fancytree.glyph.js +14 -6
  17. data/app/assets/javascripts/fancytree/src/jquery.fancytree.gridnav.js +2 -2
  18. data/app/assets/javascripts/fancytree/src/jquery.fancytree.js +63 -27
  19. data/app/assets/javascripts/fancytree/src/jquery.fancytree.menu.js +2 -2
  20. data/app/assets/javascripts/fancytree/src/jquery.fancytree.persist.js +2 -2
  21. data/app/assets/javascripts/fancytree/src/jquery.fancytree.table.js +2 -2
  22. data/app/assets/javascripts/fancytree/src/jquery.fancytree.themeroller.js +2 -2
  23. data/app/assets/javascripts/fancytree/src/jquery.fancytree.wide.js +124 -0
  24. data/app/assets/stylesheets/fancytree/skin-lion/ui.fancytree.css.erb +5 -0
  25. data/app/assets/stylesheets/fancytree/skin-vista/ui.fancytree.css.erb +5 -0
  26. data/app/assets/stylesheets/fancytree/skin-win7/ui.fancytree.css.erb +5 -0
  27. data/app/assets/stylesheets/fancytree/skin-win8-xxl/ui.fancytree.css.erb +5 -0
  28. data/app/assets/stylesheets/fancytree/skin-win8/ui.fancytree.css.erb +5 -0
  29. data/app/assets/stylesheets/fancytree/skin-xp/ui.fancytree.css.erb +5 -0
  30. data/lib/fancytree/rails/version.rb +2 -2
  31. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a8617873a677ecca45f5f10e1878b044e209a57
4
- data.tar.gz: d48c2f46d24a79dace0daf77f3e395f0d797ebcf
3
+ metadata.gz: 9763566a5cf99627c6cda44c2570cff3f980333e
4
+ data.tar.gz: 4e79a94a6e0332683b61baf961e5c779045c35a1
5
5
  SHA512:
6
- metadata.gz: 958f86489eb8b3742f11b524c80a513fa64343820821c40ec4ff3bd9bc4b0e7f0da21746980a1ea45cf2ea07b03d8ead4341f531dd10e20313f819797b003016
7
- data.tar.gz: 6651dc979969d811827f7f1aaa95774600ee234087d73ec82dcf5239c484943f8e81f3b6731e1728ecd84167068d3845c1a2959912016c3bac6a5f599f08ef2b
6
+ metadata.gz: 6bb9216bdaad12e45fe5ef4ed0fca43b4e5ccd6eddf54efc6a5c993bb7f6a1637468400c3f3d22cff06d887a510da800b2c58e67659dfa30a5b434164487d038
7
+ data.tar.gz: 60d3f5b403758d2b47e4469eaed31605122448cc043ee6a1c605d61f0e6e6e209e3a59ce7e8171620f5d00e340586fd662b8ecb890b712230c146b57d1c10618
@@ -1,3 +1,7 @@
1
+ ## v2.3.0
2
+
3
+ * use fancytree v. 2.3.0
4
+
1
5
  ## v2.0.0-11-1
2
6
 
3
7
  * use fancytree v. 2.0.0-11
data/README.md CHANGED
@@ -55,7 +55,7 @@ Note that for awesome style (extension) to work you to:
55
55
 
56
56
  ## Credits
57
57
 
58
- Pice of code of Raikefile copied form joliss/jquery-ui-rails. See
58
+ Piece of code of Rakefile copied from joliss/jquery-ui-rails. See
59
59
  3th-party for its license.
60
60
 
61
61
  ## Contributing
data/Rakefile CHANGED
@@ -3,9 +3,9 @@ require 'fileutils'
3
3
  require 'fancytree/rails/version'
4
4
 
5
5
  def build_image_dependencies(source_code)
6
- image_dependencies = Set.new source_code.scan(/url\("?images\/([-_.a-zA-Z0-9]+)"?\)/).map(&:first)
6
+ image_dependencies = Set.new source_code.scan(/url\("(icons.gif)"?\)/).map(&:first)
7
7
  code = image_dependencies.inject("") do |acc, img|
8
- acc += " *= depend_on_asset \"jquery-ui/#{img}\"\n"
8
+ acc += " *= depend_on_asset \"fancytree/#{img}\"\n"
9
9
  end
10
10
  end
11
11
 
@@ -22,9 +22,8 @@ namespace :fancytree do
22
22
  css_files = Dir.glob("skin*/*.css")
23
23
  css_files.each do |file|
24
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
25
  source_code.gsub!(/\A(\/\*!.+?\*\/\s)/m, "\\1\n/*\n#{build_image_dependencies(source_code)} */\n\n") unless build_image_dependencies(source_code).empty?
26
+ source_code.gsub!(/url\("icons.gif"\)/, 'url(<%= image_path("fancytree/icons.gif") %>)')
28
27
 
29
28
  output_path = "../../../app/assets/stylesheets/fancytree/#{file}.erb"
30
29
  mkdir_p File.dirname(output_path)
@@ -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.1.0
11
- * @date 2014-05-29T16:44
10
+ * @version 2.3.0
11
+ * @date 2014-08-17T10:39
12
12
  */
13
13
 
14
14
  /** Core Fancytree module.
@@ -614,7 +614,7 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
614
614
  var i, l, child, s, state, allSelected,someSelected,
615
615
  children = node.children;
616
616
 
617
- if( children ){
617
+ if( children && children.length ){
618
618
  // check all children recursively
619
619
  allSelected = true;
620
620
  someSelected = false;
@@ -852,6 +852,16 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
852
852
  hasFocus: function() {
853
853
  return (this.tree.hasFocus() && this.tree.focusNode === this);
854
854
  },
855
+ /** Write to browser console if debugLevel >= 1 (prepending node info)
856
+ *
857
+ * @param {*} msg string or object or array of such
858
+ */
859
+ info: function(msg){
860
+ if( this.tree.options.debugLevel >= 1 ) {
861
+ Array.prototype.unshift.call(arguments, this.toString());
862
+ consoleApply("info", arguments);
863
+ }
864
+ },
855
865
  /** Return true if node is active (see also FancytreeNode#isSelected).
856
866
  * @returns {boolean}
857
867
  */
@@ -1063,6 +1073,9 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1063
1073
  }
1064
1074
  // Unlink this node from current parent
1065
1075
  if( this.parent.children.length === 1 ) {
1076
+ if( this.parent === targetParent ){
1077
+ return; // #258
1078
+ }
1066
1079
  this.parent.children = this.parent.lazy ? [] : null;
1067
1080
  this.parent.expanded = false;
1068
1081
  } else {
@@ -1196,7 +1209,7 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1196
1209
  // Navigate to node
1197
1210
  function _goto(n){
1198
1211
  if( n ){
1199
- n.makeVisible();
1212
+ try { n.makeVisible(); } catch(e) {} // #272
1200
1213
  // Node may still be hidden by a filter
1201
1214
  if( ! $(n.span).is(":visible") ) {
1202
1215
  n.debug("Navigate: skipping hidden node");
@@ -1467,13 +1480,20 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1467
1480
  setFocus: function(flag){
1468
1481
  return this.tree._callHook("nodeSetFocus", this, flag);
1469
1482
  },
1470
- // TODO: setLazyNodeStatus
1471
1483
  /**Select this node, i.e. check the checkbox.
1472
1484
  * @param {boolean} [flag=true] pass false to deselect
1473
1485
  */
1474
1486
  setSelected: function(flag){
1475
1487
  return this.tree._callHook("nodeSetSelected", this, flag);
1476
1488
  },
1489
+ /**Mark a lazy node as 'error', 'loading', or 'ok'.
1490
+ * @param {string} status 'error', 'ok'
1491
+ * @param {string} [message]
1492
+ * @param {string} [details]
1493
+ */
1494
+ setStatus: function(status, message, details){
1495
+ return this.tree._callHook("nodeSetStatus", this, status, message, details);
1496
+ },
1477
1497
  /**Rename this node.
1478
1498
  * @param {string} title
1479
1499
  */
@@ -1666,6 +1686,9 @@ function Fancytree(widget) {
1666
1686
  };
1667
1687
  }
1668
1688
  }
1689
+ if( this.options && $.isFunction(this.options.loaderror) ) {
1690
+ $.error("The 'loaderror' event was renamed since 2014-07-03. Use 'loadError' (with uppercase E) instead.");
1691
+ }
1669
1692
  this.ext = {}; // Active extension instances
1670
1693
  // allow to init tree.data.foo from <div data-foo=''>
1671
1694
  this.data = _getElementDataAsDict(this.$div);
@@ -1883,17 +1906,17 @@ Fancytree.prototype = /** @lends Fancytree# */{
1883
1906
  generateFormElements: function(selected, active) {
1884
1907
  // TODO: test case
1885
1908
  var nodeList,
1886
- selectedName = (selected !== false) ? "ft_" + this._id : selected,
1909
+ selectedName = (selected !== false) ? "ft_" + this._id + "[]" : selected,
1887
1910
  activeName = (active !== false) ? "ft_" + this._id + "_active" : active,
1888
1911
  id = "fancytree_result_" + this._id,
1889
- $result = this.$container.find("div#" + id);
1912
+ $result = $("#" + id);
1890
1913
 
1891
1914
  if($result.length){
1892
1915
  $result.empty();
1893
1916
  }else{
1894
1917
  $result = $("<div>", {
1895
1918
  id: id
1896
- }).hide().appendTo(this.$container);
1919
+ }).hide().insertAfter(this.$container);
1897
1920
  }
1898
1921
  if(selectedName){
1899
1922
  nodeList = this.getSelectedNodes( this.options.selectMode === 3 );
@@ -1967,7 +1990,12 @@ Fancytree.prototype = /** @lends Fancytree# */{
1967
1990
  }, true);
1968
1991
  return match;
1969
1992
  },
1970
- // TODO: getRoot()
1993
+ /** Return the invisible system root node.
1994
+ * @returns {FancytreeNode}
1995
+ */
1996
+ getRootNode: function() {
1997
+ return this.rootNode;
1998
+ },
1971
1999
  /**
1972
2000
  * Return an array of selected nodes.
1973
2001
  * @param {boolean} [stopOnParents=false] only return the topmost selected
@@ -2373,7 +2401,7 @@ $.extend(Fancytree.prototype,
2373
2401
  * data was rendered.
2374
2402
  */
2375
2403
  nodeLoadChildren: function(ctx, source) {
2376
- var ajax, delay,
2404
+ var ajax, delay, dfd,
2377
2405
  tree = ctx.tree,
2378
2406
  node = ctx.node;
2379
2407
 
@@ -2393,7 +2421,7 @@ $.extend(Fancytree.prototype,
2393
2421
 
2394
2422
  node.debug("nodeLoadChildren waiting debug delay " + Math.round(delay) + "ms");
2395
2423
  ajax.debugDelay = false;
2396
- source = $.Deferred(function (dfd) {
2424
+ dfd = $.Deferred(function (dfd) {
2397
2425
  setTimeout(function () {
2398
2426
  $.ajax(ajax)
2399
2427
  .done(function () { dfd.resolveWith(this, arguments); })
@@ -2401,33 +2429,42 @@ $.extend(Fancytree.prototype,
2401
2429
  }, delay);
2402
2430
  });
2403
2431
  }else{
2404
- source = $.ajax(ajax);
2432
+ dfd = $.ajax(ajax);
2405
2433
  }
2406
2434
 
2407
- // TODO: change 'pipe' to 'then' for jQuery 1.8
2408
- // $.pipe returns a new Promise with filtered results
2409
- source = source.pipe(function (data, textStatus, jqXHR) {
2410
- var res;
2435
+ // Defer the deferred: we want to be able to reject, even if ajax
2436
+ // resolved ok.
2437
+ source = new $.Deferred();
2438
+ dfd.done(function (data, textStatus, jqXHR) {
2439
+ var errorObj, res;
2411
2440
  if(typeof data === "string"){
2412
2441
  $.error("Ajax request returned a string (did you get the JSON dataType wrong?).");
2413
2442
  }
2414
- // postProcess is similar to the standard dataFilter hook,
2443
+ // postProcess is similar to the standard ajax dataFilter hook,
2415
2444
  // but it is also called for JSONP
2416
2445
  if( ctx.options.postProcess ){
2417
- res = tree._triggerNodeEvent("postProcess", ctx, ctx.originalEvent, {response: data, dataType: this.dataType});
2446
+ res = tree._triggerNodeEvent("postProcess", ctx, ctx.originalEvent, {response: data, error: null, dataType: this.dataType});
2447
+ if( res.error ) {
2448
+ errorObj = $.isPlainObject(res.error) ? res.error : {message: res.error};
2449
+ errorObj = tree._makeHookContext(node, null, errorObj);
2450
+ source.rejectWith(this, [errorObj]);
2451
+ return;
2452
+ }
2418
2453
  data = $.isArray(res) ? res : data;
2454
+
2419
2455
  } else if (data && data.hasOwnProperty("d") && ctx.options.enableAspx ) {
2420
2456
  // Process ASPX WebMethod JSON object inside "d" property
2421
2457
  data = (typeof data.d === "string") ? $.parseJSON(data.d) : data.d;
2422
2458
  }
2423
- return data;
2424
- }, function (jqXHR, textStatus, errorThrown) {
2425
- return tree._makeHookContext(node, null, {
2459
+ source.resolveWith(this, [data]);
2460
+ }).fail(function (jqXHR, textStatus, errorThrown) {
2461
+ var errorObj = tree._makeHookContext(node, null, {
2426
2462
  error: jqXHR,
2427
2463
  args: Array.prototype.slice.call(arguments),
2428
2464
  message: errorThrown,
2429
2465
  details: jqXHR.status + ": " + errorThrown
2430
2466
  });
2467
+ source.rejectWith(this, [errorObj]);
2431
2468
  });
2432
2469
  }
2433
2470
 
@@ -2437,7 +2474,7 @@ $.extend(Fancytree.prototype,
2437
2474
  // node._isLoading = true;
2438
2475
  tree.nodeSetStatus(ctx, "loading");
2439
2476
 
2440
- source.done(function () {
2477
+ source.done(function (children) {
2441
2478
  tree.nodeSetStatus(ctx, "ok");
2442
2479
  }).fail(function(error){
2443
2480
  var ctxErr;
@@ -2451,8 +2488,9 @@ $.extend(Fancytree.prototype,
2451
2488
  message: error ? (error.message || error.toString()) : ""
2452
2489
  });
2453
2490
  }
2454
- tree._triggerNodeEvent("loaderror", ctxErr, null);
2455
- tree.nodeSetStatus(ctx, "error", ctxErr.message, ctxErr.details);
2491
+ if( tree._triggerNodeEvent("loadError", ctxErr, null) !== false ) {
2492
+ tree.nodeSetStatus(ctx, "error", ctxErr.message, ctxErr.details);
2493
+ }
2456
2494
  });
2457
2495
  }
2458
2496
  // $.when(source) resolves also for non-deferreds
@@ -2472,9 +2510,7 @@ $.extend(Fancytree.prototype,
2472
2510
  _assert($.isArray(children), "expected array of children");
2473
2511
  node._setChildren(children);
2474
2512
  // trigger fancytreeloadchildren
2475
- // if( node.parent ) {
2476
2513
  tree._triggerNodeEvent("loadChildren", node);
2477
- // }
2478
2514
  // }).always(function(){
2479
2515
  // node._isLoading = false;
2480
2516
  });
@@ -3791,7 +3827,7 @@ $.extend($.ui.fancytree,
3791
3827
  /** @lends Fancytree_Static# */
3792
3828
  {
3793
3829
  /** @type {string} */
3794
- version: "2.1.0", // Set to semver by 'grunt release'
3830
+ version: "2.3.0", // Set to semver by 'grunt release'
3795
3831
  /** @type {string} */
3796
3832
  buildType: "production", // Set to 'production' by 'grunt build'
3797
3833
  /** @type {int} */
@@ -4090,8 +4126,8 @@ $.extend($.ui.fancytree,
4090
4126
  * Released under the MIT license
4091
4127
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
4092
4128
  *
4093
- * @version 2.1.0
4094
- * @date 2014-05-29T16:44
4129
+ * @version 2.3.0
4130
+ * @date 2014-08-17T10:39
4095
4131
  */
4096
4132
 
4097
4133
  // To keep the global namespace clean, we wrap everything in a closure
@@ -4255,6 +4291,458 @@ $.ui.fancytree.registerExtension({
4255
4291
  // End of namespace closure
4256
4292
  }(jQuery));
4257
4293
 
4294
+ /*!
4295
+ *
4296
+ * jquery.fancytree.clones.js
4297
+ * Support faster lookup of nodes by key and shared ref-ids.
4298
+ * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
4299
+ *
4300
+ * Copyright (c) 2014, Martin Wendt (http://wwWendt.de)
4301
+ *
4302
+ * Released under the MIT license
4303
+ * https://github.com/mar10/fancytree/wiki/LicenseInfo
4304
+ *
4305
+ * @version 2.3.0
4306
+ * @date 2014-08-17T10:39
4307
+ */
4308
+
4309
+ ;(function($, window, document, undefined) {
4310
+
4311
+ "use strict";
4312
+
4313
+ /*******************************************************************************
4314
+ * Private functions and variables
4315
+ */
4316
+ function _assert(cond, msg){
4317
+ // TODO: see qunit.js extractStacktrace()
4318
+ if(!cond){
4319
+ msg = msg ? ": " + msg : "";
4320
+ $.error("Assertion failed" + msg);
4321
+ }
4322
+ }
4323
+
4324
+
4325
+ /* Return first occurrence of member from array. */
4326
+ function _removeArrayMember(arr, elem) {
4327
+ // TODO: use Array.indexOf for IE >= 9
4328
+ var i;
4329
+ for (i = arr.length - 1; i >= 0; i--) {
4330
+ if (arr[i] === elem) {
4331
+ arr.splice(i, 1);
4332
+ return true;
4333
+ }
4334
+ }
4335
+ return false;
4336
+ }
4337
+
4338
+
4339
+ // /**
4340
+ // * Calculate a 32 bit FNV-1a hash
4341
+ // * Found here: https://gist.github.com/vaiorabbit/5657561
4342
+ // * Ref.: http://isthe.com/chongo/tech/comp/fnv/
4343
+ // *
4344
+ // * @param {string} str the input value
4345
+ // * @param {boolean} [asString=false] set to true to return the hash value as
4346
+ // * 8-digit hex string instead of an integer
4347
+ // * @param {integer} [seed] optionally pass the hash of the previous chunk
4348
+ // * @returns {integer | string}
4349
+ // */
4350
+ // function hashFnv32a(str, asString, seed) {
4351
+ // /*jshint bitwise:false */
4352
+ // var i, l,
4353
+ // hval = (seed === undefined) ? 0x811c9dc5 : seed;
4354
+
4355
+ // for (i = 0, l = str.length; i < l; i++) {
4356
+ // hval ^= str.charCodeAt(i);
4357
+ // hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
4358
+ // }
4359
+ // if( asString ){
4360
+ // // Convert to 8 digit hex string
4361
+ // return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
4362
+ // }
4363
+ // return hval >>> 0;
4364
+ // }
4365
+
4366
+
4367
+ /**
4368
+ * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
4369
+ *
4370
+ * @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
4371
+ * @see http://github.com/garycourt/murmurhash-js
4372
+ * @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
4373
+ * @see http://sites.google.com/site/murmurhash/
4374
+ *
4375
+ * @param {string} key ASCII only
4376
+ * @param {boolean} [asString=false]
4377
+ * @param {number} seed Positive integer only
4378
+ * @return {number} 32-bit positive integer hash
4379
+ */
4380
+ function hashMurmur3(key, asString, seed) {
4381
+ /*jshint bitwise:false */
4382
+ var h1b, k1,
4383
+ remainder = key.length & 3,
4384
+ bytes = key.length - remainder,
4385
+ h1 = seed,
4386
+ c1 = 0xcc9e2d51,
4387
+ c2 = 0x1b873593,
4388
+ i = 0;
4389
+
4390
+ while (i < bytes) {
4391
+ k1 =
4392
+ ((key.charCodeAt(i) & 0xff)) |
4393
+ ((key.charCodeAt(++i) & 0xff) << 8) |
4394
+ ((key.charCodeAt(++i) & 0xff) << 16) |
4395
+ ((key.charCodeAt(++i) & 0xff) << 24);
4396
+ ++i;
4397
+
4398
+ k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
4399
+ k1 = (k1 << 15) | (k1 >>> 17);
4400
+ k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
4401
+
4402
+ h1 ^= k1;
4403
+ h1 = (h1 << 13) | (h1 >>> 19);
4404
+ h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
4405
+ h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
4406
+ }
4407
+
4408
+ k1 = 0;
4409
+
4410
+ switch (remainder) {
4411
+ /*jshint -W086:true */
4412
+ case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
4413
+ case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
4414
+ case 1: k1 ^= (key.charCodeAt(i) & 0xff);
4415
+
4416
+ k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
4417
+ k1 = (k1 << 15) | (k1 >>> 17);
4418
+ k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
4419
+ h1 ^= k1;
4420
+ }
4421
+
4422
+ h1 ^= key.length;
4423
+
4424
+ h1 ^= h1 >>> 16;
4425
+ h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
4426
+ h1 ^= h1 >>> 13;
4427
+ h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
4428
+ h1 ^= h1 >>> 16;
4429
+
4430
+ if( asString ){
4431
+ // Convert to 8 digit hex string
4432
+ return ("0000000" + (h1 >>> 0).toString(16)).substr(-8);
4433
+ }
4434
+ return h1 >>> 0;
4435
+ }
4436
+
4437
+ // console.info(hashMurmur3("costarring"));
4438
+ // console.info(hashMurmur3("costarring", true));
4439
+ // console.info(hashMurmur3("liquid"));
4440
+ // console.info(hashMurmur3("liquid", true));
4441
+
4442
+
4443
+ /*
4444
+ * Return a unique key for node by calculationg the hash of the parents refKey-list
4445
+ */
4446
+ function calcUniqueKey(node) {
4447
+ var key,
4448
+ path = $.map(node.getParentList(false, true), function(e){ return e.refKey || e.key; });
4449
+ path = path.join("/");
4450
+ key = "id_" + hashMurmur3(path, true);
4451
+ node.debug(path + " -> " + key);
4452
+ return key;
4453
+ }
4454
+
4455
+
4456
+ /**
4457
+ * [ext-clones] Return a list of clone-nodes or null.
4458
+ * @param {boolean} [includeSelf=false]
4459
+ * @returns {FancytreeNode[] | null}
4460
+ *
4461
+ * @alias FancytreeNode#getCloneList
4462
+ * @requires jquery.fancytree.clones.js
4463
+ */
4464
+ $.ui.fancytree._FancytreeNodeClass.prototype.getCloneList = function(includeSelf){
4465
+ var key,
4466
+ tree = this.tree,
4467
+ refList = tree.refMap[this.refKey] || null,
4468
+ keyMap = tree.keyMap;
4469
+
4470
+ if( refList ) {
4471
+ key = this.key;
4472
+ // Convert key list to node list
4473
+ if( includeSelf ) {
4474
+ refList = $.map(refList, function(val){ return keyMap[val]; });
4475
+ } else {
4476
+ refList = $.map(refList, function(val){ return val === key ? null : keyMap[val]; });
4477
+ if( refList.length < 1 ) {
4478
+ refList = null;
4479
+ }
4480
+ }
4481
+ }
4482
+ return refList;
4483
+ };
4484
+
4485
+
4486
+ /**
4487
+ * [ext-clones] Return true if this node has at least another clone with same refKey.
4488
+ * @returns {boolean}
4489
+ *
4490
+ * @alias FancytreeNode#isClone
4491
+ * @requires jquery.fancytree.clones.js
4492
+ */
4493
+ $.ui.fancytree._FancytreeNodeClass.prototype.isClone = function(){
4494
+ var refKey = this.refKey || null,
4495
+ refList = refKey && this.tree.refMap[refKey] || null;
4496
+ return !!(refList && refList.length > 1);
4497
+ };
4498
+
4499
+
4500
+ /**
4501
+ * [ext-clones] Update key and/or refKey for an existing node.
4502
+ * @param {string} key
4503
+ * @param {string} refKey
4504
+ * @returns {boolean}
4505
+ *
4506
+ * @alias FancytreeNode#reRegister
4507
+ * @requires jquery.fancytree.clones.js
4508
+ */
4509
+ $.ui.fancytree._FancytreeNodeClass.prototype.reRegister = function(key, refKey){
4510
+ key = (key == null) ? null : "" + key;
4511
+ refKey = (refKey == null) ? null : "" + refKey;
4512
+ this.debug("reRegister", key, refKey);
4513
+
4514
+ var tree = this.tree,
4515
+ prevKey = this.key,
4516
+ prevRefKey = this.refKey,
4517
+ keyMap = tree.keyMap,
4518
+ refMap = tree.refMap,
4519
+ refList = refMap[prevRefKey] || null,
4520
+ // curCloneKeys = refList ? node.getCloneList(true),
4521
+ modified = false;
4522
+
4523
+ // Key has changed: update all references
4524
+ if( key != null && key !== this.key ) {
4525
+ if( keyMap[key] ) {
4526
+ $.error("[ext-clones] reRegister(" + key + "): already exists.");
4527
+ }
4528
+ // Update keyMap
4529
+ delete keyMap[prevKey];
4530
+ keyMap[key] = this;
4531
+ // Update refMap
4532
+ if( refList ) {
4533
+ refMap[prevRefKey] = $.map(refList, function(e){
4534
+ return e === prevKey ? key : e;
4535
+ });
4536
+ }
4537
+ this.key = key;
4538
+ modified = true;
4539
+ }
4540
+
4541
+ // refKey has changed
4542
+ if( refKey != null && refKey !== this.refKey ) {
4543
+ // Remove previous refKeys
4544
+ if( refList ){
4545
+ if( refList.length === 1 ){
4546
+ delete refMap[prevRefKey];
4547
+ }else{
4548
+ refMap[prevRefKey] = $.map(refList, function(e){
4549
+ return e === prevKey ? null : e;
4550
+ });
4551
+ }
4552
+ }
4553
+ // Add refKey
4554
+ if( refMap[refKey] ) {
4555
+ refMap[refKey].append(key);
4556
+ }else{
4557
+ refMap[refKey] = [ this.key ];
4558
+ }
4559
+ this.refKey = refKey;
4560
+ modified = true;
4561
+ }
4562
+ return modified;
4563
+ };
4564
+
4565
+
4566
+ /**
4567
+ * [ext-clones] Return all nodes with a given refKey (null if not found).
4568
+ * @param {string} refKey
4569
+ * @param {FancytreeNode} [rootNode] optionally restrict results to descendants of this node
4570
+ * @returns {FancytreeNode[] | null}
4571
+ * @alias Fancytree#getNodesByRef
4572
+ * @requires jquery.fancytree.clones.js
4573
+ */
4574
+ $.ui.fancytree._FancytreeClass.prototype.getNodesByRef = function(refKey, rootNode){
4575
+ var keyMap = this.keyMap,
4576
+ refList = this.refMap[refKey] || null;
4577
+
4578
+ if( refList ) {
4579
+ // Convert key list to node list
4580
+ if( rootNode ) {
4581
+ refList = $.map(refList, function(val){
4582
+ var node = keyMap[val];
4583
+ return node.isDescendantOf(rootNode) ? node : null;
4584
+ });
4585
+ }else{
4586
+ refList = $.map(refList, function(val){ return keyMap[val]; });
4587
+ }
4588
+ if( refList.length < 1 ) {
4589
+ refList = null;
4590
+ }
4591
+ }
4592
+ return refList;
4593
+ };
4594
+
4595
+
4596
+ /**
4597
+ * [ext-clones] Replace a refKey with a new one.
4598
+ * @param {string} oldRefKey
4599
+ * @param {string} newRefKey
4600
+ * @alias Fancytree#changeRefKey
4601
+ * @requires jquery.fancytree.clones.js
4602
+ */
4603
+ $.ui.fancytree._FancytreeClass.prototype.changeRefKey = function(oldRefKey, newRefKey) {
4604
+ var i, node,
4605
+ keyMap = this.keyMap,
4606
+ refList = this.refMap[oldRefKey] || null;
4607
+
4608
+ if (refList) {
4609
+ for (i = 0; i < refList.length; i++) {
4610
+ node = keyMap[refList[i]];
4611
+ node.refKey = newRefKey;
4612
+ }
4613
+ delete this.refMap[oldRefKey];
4614
+ this.refMap[newRefKey] = refList;
4615
+ }
4616
+ };
4617
+
4618
+
4619
+ /*******************************************************************************
4620
+ * Extension code
4621
+ */
4622
+ $.ui.fancytree.registerExtension({
4623
+ name: "clones",
4624
+ version: "0.0.3",
4625
+ // Default options for this extension.
4626
+ options: {
4627
+ highlightActiveClones: true, // set 'fancytree-active-clone' on active clones and all peers
4628
+ highlightClones: false // set 'fancytree-clone' class on any node that has at least one clone
4629
+ },
4630
+
4631
+ treeCreate: function(ctx){
4632
+ this._super(ctx);
4633
+ ctx.tree.refMap = {};
4634
+ ctx.tree.keyMap = {};
4635
+ },
4636
+ treeInit: function(ctx){
4637
+ this.$container.addClass("fancytree-ext-clones");
4638
+ _assert(ctx.options.defaultKey == null);
4639
+ // Generate unique / reproducible default keys
4640
+ ctx.options.defaultKey = function(node){
4641
+ return calcUniqueKey(node);
4642
+ };
4643
+ // The default implementation loads initial data
4644
+ this._super(ctx);
4645
+ },
4646
+ treeClear: function(ctx){
4647
+ ctx.tree.refMap = {};
4648
+ ctx.tree.keyMap = {};
4649
+ return this._super(ctx);
4650
+ },
4651
+ treeRegisterNode: function(ctx, add, node) {
4652
+ var refList, len,
4653
+ tree = ctx.tree,
4654
+ keyMap = tree.keyMap,
4655
+ refMap = tree.refMap,
4656
+ key = node.key,
4657
+ refKey = (node && node.refKey != null) ? "" + node.refKey : null;
4658
+
4659
+ // ctx.tree.debug("clones.treeRegisterNode", add, node);
4660
+
4661
+ if( key === "_statusNode" ){
4662
+ return this._super(ctx, add, node);
4663
+ }
4664
+
4665
+ if( add ) {
4666
+ if( keyMap[node.key] != null ) {
4667
+ $.error("clones.treeRegisterNode: node.key already exists: " + node.key);
4668
+ }
4669
+ keyMap[key] = node;
4670
+ if( refKey ) {
4671
+ refList = refMap[refKey];
4672
+ if( refList ) {
4673
+ refList.push(key);
4674
+ if( refList.length === 2 && ctx.options.clones.highlightClones ) {
4675
+ // Mark peer node, if it just became a clone (no need to
4676
+ // mark current node, since it will be rendered later anyway)
4677
+ keyMap[refList[0]].renderStatus();
4678
+ }
4679
+ } else {
4680
+ refMap[refKey] = [key];
4681
+ }
4682
+ node.debug("clones.treeRegisterNode: add clone =>", refMap[refKey]);
4683
+ }
4684
+ }else {
4685
+ if( keyMap[key] == null ) {
4686
+ $.error("clones.treeRegisterNode: node.key not registered: " + node.key);
4687
+ }
4688
+ delete keyMap[key];
4689
+ if( refKey ) {
4690
+ refList = refMap[refKey];
4691
+ node.debug("clones.treeRegisterNode: remove clone BEFORE =>", refMap[refKey]);
4692
+ if( refList ) {
4693
+ len = refList.length;
4694
+ if( len <= 1 ){
4695
+ _assert(len === 1);
4696
+ _assert(refList[0] === key);
4697
+ delete refMap[refKey];
4698
+ }else{
4699
+ _removeArrayMember(refList, key);
4700
+ // Unmark peer node, if this was the only clone
4701
+ if( len === 2 && ctx.options.clones.highlightClones ) {
4702
+ // node.debug("clones.treeRegisterNode: last =>", node.getCloneList());
4703
+ keyMap[refList[0]].renderStatus();
4704
+ }
4705
+ }
4706
+ node.debug("clones.treeRegisterNode: remove clone =>", refMap[refKey]);
4707
+ }
4708
+ }
4709
+ }
4710
+ return this._super(ctx, add, node);
4711
+ },
4712
+ nodeRenderStatus: function(ctx) {
4713
+ var $span, res,
4714
+ node = ctx.node;
4715
+
4716
+ res = this._super(ctx);
4717
+
4718
+ if( ctx.options.clones.highlightClones ) {
4719
+ $span = $(node[ctx.tree.statusClassPropName]);
4720
+ // Only if span already exists
4721
+ if( $span.length && node.isClone() ){
4722
+ // node.debug("clones.nodeRenderStatus: ", ctx.options.clones.highlightClones);
4723
+ $span.addClass("fancytree-clone");
4724
+ }
4725
+ }
4726
+ return res;
4727
+ },
4728
+ nodeSetActive: function(ctx, flag) {
4729
+ var res,
4730
+ scpn = ctx.tree.statusClassPropName,
4731
+ node = ctx.node;
4732
+
4733
+ res = this._super(ctx, flag);
4734
+
4735
+ if( ctx.options.clones.highlightActiveClones && node.isClone() ) {
4736
+ $.each(node.getCloneList(true), function(idx, n){
4737
+ n.debug("clones.nodeSetActive: ", flag !== false);
4738
+ $(n[scpn]).toggleClass("fancytree-active-clone", flag !== false);
4739
+ });
4740
+ }
4741
+ return res;
4742
+ }
4743
+ });
4744
+ }(jQuery, window, document));
4745
+
4258
4746
  /*!
4259
4747
  * jquery.fancytree.dnd.js
4260
4748
  *
@@ -4266,8 +4754,8 @@ $.ui.fancytree.registerExtension({
4266
4754
  * Released under the MIT license
4267
4755
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
4268
4756
  *
4269
- * @version 2.1.0
4270
- * @date 2014-05-29T16:44
4757
+ * @version 2.3.0
4758
+ * @date 2014-08-17T10:39
4271
4759
  */
4272
4760
 
4273
4761
  ;(function($, window, document, undefined) {
@@ -4302,9 +4790,8 @@ function _initDragAndDrop(tree) {
4302
4790
  containment: false,
4303
4791
  delay: 0,
4304
4792
  distance: 4,
4305
- // TODO: merge Dynatree issue 419
4306
4793
  revert: false,
4307
- scroll: true, // issue 244: enable scrolling (if ul.fancytree-container)
4794
+ scroll: true, // to disable, also set css 'position: inherit' on ul.fancytree-container
4308
4795
  scrollSpeed: 7,
4309
4796
  scrollSensitivity: 10,
4310
4797
  // Delegate draggable.start, drag, and stop events to our handler
@@ -4461,6 +4948,7 @@ $.ui.fancytree.registerExtension({
4461
4948
  autoExpandMS: 1000, // Expand nodes after n milliseconds of hovering.
4462
4949
  preventVoidMoves: true, // Prevent dropping nodes 'before self', etc.
4463
4950
  preventRecursiveMoves: true, // Prevent dropping nodes on own descendants
4951
+ focusOnClick: false, // Focus, although draggable cancels mousedown event (#270)
4464
4952
  dragEnter: null, // Callback(targetNode, data)
4465
4953
  dragOver: null, // Callback(targetNode, data)
4466
4954
  dragDrop: null, // Callback(targetNode, data)
@@ -4473,6 +4961,20 @@ $.ui.fancytree.registerExtension({
4473
4961
  treeInit: function(ctx){
4474
4962
  var tree = ctx.tree;
4475
4963
  this._super(ctx);
4964
+ // issue #270: draggable eats mousedown events
4965
+ if( tree.options.dnd.dragStart ){
4966
+ tree.$container.on("mousedown", function(event){
4967
+ if( !tree.hasFocus() && ctx.options.dnd.focusOnClick ) {
4968
+ var node = $.ui.fancytree.getNode(event);
4969
+ node.debug("Re-enable focus that was prevented by jQuery UI draggable.");
4970
+ // node.setFocus();
4971
+ // $(node.span).closest(":tabbable").focus();
4972
+ // $(event.target).trigger("focus");
4973
+ // $(event.target).closest(":tabbable").trigger("focus");
4974
+ $(event.target).closest(":tabbable").focus();
4975
+ }
4976
+ });
4977
+ }
4476
4978
  _initDragAndDrop(tree);
4477
4979
  },
4478
4980
  /* Override key handler in order to cancel dnd on escape.*/
@@ -4483,6 +4985,12 @@ $.ui.fancytree.registerExtension({
4483
4985
  }
4484
4986
  return this._super(ctx);
4485
4987
  },
4988
+ nodeClick: function(ctx) {
4989
+ // if( ctx.options.dnd.dragStart ){
4990
+ // ctx.tree.$container.focus();
4991
+ // }
4992
+ return this._super(ctx);
4993
+ },
4486
4994
  /* Display drop marker according to hitMode ('after', 'before', 'over', 'out', 'start', 'stop'). */
4487
4995
  _setDndStatus: function(sourceNode, targetNode, helper, hitMode, accept) {
4488
4996
  var posOpts,
@@ -4790,8 +5298,8 @@ $.ui.fancytree.registerExtension({
4790
5298
  * Released under the MIT license
4791
5299
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
4792
5300
  *
4793
- * @version 2.1.0
4794
- * @date 2014-05-29T16:44
5301
+ * @version 2.3.0
5302
+ * @date 2014-08-17T10:39
4795
5303
  */
4796
5304
 
4797
5305
  ;(function($, window, document, undefined) {
@@ -4898,6 +5406,7 @@ $.ui.fancytree._FancytreeNodeClass.prototype.editStart = function(){
4898
5406
  node.editEnd(true, event);
4899
5407
  return false; // so we don't start editmode on Mac
4900
5408
  }
5409
+ event.stopPropagation();
4901
5410
  }).blur(function(event){
4902
5411
  return node.editEnd(true, event);
4903
5412
  });
@@ -5105,8 +5614,8 @@ $.ui.fancytree.registerExtension({
5105
5614
  * Released under the MIT license
5106
5615
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5107
5616
  *
5108
- * @version 2.1.0
5109
- * @date 2014-05-29T16:44
5617
+ * @version 2.3.0
5618
+ * @date 2014-08-17T10:39
5110
5619
  */
5111
5620
 
5112
5621
  ;(function($, window, document, undefined) {
@@ -5267,8 +5776,8 @@ $.ui.fancytree.registerExtension({
5267
5776
  * Released under the MIT license
5268
5777
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5269
5778
  *
5270
- * @version 2.1.0
5271
- * @date 2014-05-29T16:44
5779
+ * @version 2.3.0
5780
+ * @date 2014-08-17T10:39
5272
5781
  */
5273
5782
 
5274
5783
  ;(function($, window, document, undefined) {
@@ -5316,6 +5825,7 @@ $.ui.fancytree.registerExtension({
5316
5825
  nodeRenderStatus: function(ctx) {
5317
5826
  var icon, span,
5318
5827
  node = ctx.node,
5828
+ $span = $(node.span),
5319
5829
  opts = ctx.options.glyph,
5320
5830
  // callback = opts.icon,
5321
5831
  map = opts.map
@@ -5328,8 +5838,9 @@ $.ui.fancytree.registerExtension({
5328
5838
  if( node.isRoot() ){
5329
5839
  return;
5330
5840
  }
5331
-
5332
- span = $("span.fancytree-expander", node.span).get(0);
5841
+ // #257: only search one level deep:
5842
+ // span = $("span.fancytree-expander", node.span).get(0);
5843
+ span = $span.children("span.fancytree-expander").get(0);
5333
5844
  if( span ){
5334
5845
  if( node.isLoading() ){
5335
5846
  icon = "loading";
@@ -5342,16 +5853,22 @@ $.ui.fancytree.registerExtension({
5342
5853
  }else{
5343
5854
  icon = "noExpander";
5344
5855
  }
5856
+ // node.debug(icon, map[icon], span);
5345
5857
  span.className = "fancytree-expander " + map[icon];
5346
5858
  }
5347
5859
 
5348
- span = $("span.fancytree-checkbox", node.tr || node.span).get(0);
5860
+ if( node.tr ){
5861
+ span = $(node.tr).children("span.fancytree-checkbox").get(0);
5862
+ }else{
5863
+ span = $span.children("span.fancytree-checkbox").get(0);
5864
+ }
5349
5865
  if( span ){
5350
5866
  icon = node.selected ? "checkboxSelected" : (node.partsel ? "checkboxUnknown" : "checkbox");
5351
5867
  span.className = "fancytree-checkbox " + map[icon];
5352
5868
  }
5353
5869
 
5354
- span = $("span.fancytree-icon", node.span).get(0);
5870
+ // span = $("span.fancytree-icon", node.span).get(0);
5871
+ span = $span.children("span.fancytree-icon").get(0);
5355
5872
  if( span ){
5356
5873
  if( node.folder ){
5357
5874
  icon = node.expanded ? _getIcon(opts, "folderOpen") : _getIcon(opts, "folder");
@@ -5395,8 +5912,8 @@ $.ui.fancytree.registerExtension({
5395
5912
  * Released under the MIT license
5396
5913
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5397
5914
  *
5398
- * @version 2.1.0
5399
- * @date 2014-05-29T16:44
5915
+ * @version 2.3.0
5916
+ * @date 2014-08-17T10:39
5400
5917
  */
5401
5918
 
5402
5919
  ;(function($, window, document, undefined) {
@@ -5597,8 +6114,8 @@ $.ui.fancytree.registerExtension({
5597
6114
  * Released under the MIT license
5598
6115
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5599
6116
  *
5600
- * @version 2.1.0
5601
- * @date 2014-05-29T16:44
6117
+ * @version 2.3.0
6118
+ * @date 2014-08-17T10:39
5602
6119
  */
5603
6120
 
5604
6121
  ;(function($, window, document, undefined) {
@@ -5935,8 +6452,8 @@ $.ui.fancytree.registerExtension({
5935
6452
  * Released under the MIT license
5936
6453
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
5937
6454
  *
5938
- * @version 2.1.0
5939
- * @date 2014-05-29T16:44
6455
+ * @version 2.3.0
6456
+ * @date 2014-08-17T10:39
5940
6457
  */
5941
6458
 
5942
6459
  ;(function($, window, document, undefined) {
@@ -6297,8 +6814,8 @@ $.ui.fancytree.registerExtension({
6297
6814
  * Released under the MIT license
6298
6815
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
6299
6816
  *
6300
- * @version 2.1.0
6301
- * @date 2014-05-29T16:44
6817
+ * @version 2.3.0
6818
+ * @date 2014-08-17T10:39
6302
6819
  */
6303
6820
 
6304
6821
  ;(function($, window, document, undefined) {