dynatree-rails 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b85ee13b79b9db238d708d53b203e5f08ec5eb92
4
+ data.tar.gz: 1071ede3e00cf862874cacca0fe4100ed3b8a4c1
5
+ SHA512:
6
+ metadata.gz: 5a1772499731be1feb1de6f7eeb65cf6782f40fee7f4fe992c90d7081eb40e0a32601610315e0b93808c7e14d03c8ecbe4b95fc0a314d030ef3445ad80438869
7
+ data.tar.gz: 0e06e959e02e168e3af81bbe5a3d4584c77a695dfe97da17306a9f45cdd279b5e40104760225e51899cecd303ecf6a8c248ec56c9cc55f46ef56b965a647371e
@@ -1,5 +1,5 @@
1
1
  module Dynatree
2
2
  module Rails
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
@@ -2,15 +2,15 @@
2
2
  jquery.dynatree.js
3
3
  Dynamic tree view control, with support for lazy loading of branches.
4
4
 
5
- Copyright (c) 2006-2012, Martin Wendt (http://wwWendt.de)
5
+ Copyright (c) 2006-2013, Martin Wendt (http://wwWendt.de)
6
6
  Dual licensed under the MIT or GPL Version 2 licenses.
7
7
  http://code.google.com/p/dynatree/wiki/LicenseInfo
8
8
 
9
9
  A current version and some documentation is available at
10
10
  http://dynatree.googlecode.com/
11
11
 
12
- $Version: 1.2.2$
13
- $Revision: 627, 2012-10-07 16:55:00$
12
+ $Version: 1.2.4$
13
+ $Revision: 644, 2013-02-12 21:39:36$
14
14
 
15
15
  @depends: jquery.js
16
16
  @depends: jquery.ui.core.js
@@ -59,10 +59,44 @@ function _log(mode, msg) {
59
59
  } catch(e) {
60
60
  if( !window.console ){
61
61
  _canLog = false; // Permanently disable, when logging is not supported by the browser
62
+ }else if(e.number === -2146827850){
63
+ // fix for IE8, where window.console.log() exists, but does not support .apply()
64
+ window.console.log(args.join(", "));
62
65
  }
63
66
  }
64
67
  }
65
68
 
69
+ /* Check browser version, since $.browser was removed in jQuery 1.9 */
70
+ function _checkBrowser(){
71
+ var matched, browser;
72
+ function uaMatch( ua ) {
73
+ ua = ua.toLowerCase();
74
+ var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
75
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
76
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
77
+ /(msie) ([\w.]+)/.exec( ua ) ||
78
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
79
+ [];
80
+ return {
81
+ browser: match[ 1 ] || "",
82
+ version: match[ 2 ] || "0"
83
+ };
84
+ }
85
+ matched = uaMatch( navigator.userAgent );
86
+ browser = {};
87
+ if ( matched.browser ) {
88
+ browser[ matched.browser ] = true;
89
+ browser.version = matched.version;
90
+ }
91
+ if ( browser.chrome ) {
92
+ browser.webkit = true;
93
+ } else if ( browser.webkit ) {
94
+ browser.safari = true;
95
+ }
96
+ return browser;
97
+ }
98
+ var BROWSER = jQuery.browser || _checkBrowser();
99
+
66
100
  function logMsg(msg) {
67
101
  Array.prototype.unshift.apply(arguments, ["debug"]);
68
102
  _log.apply(this, arguments);
@@ -114,6 +148,39 @@ function getDtNodeFromElement(el) {
114
148
  function noop() {
115
149
  }
116
150
 
151
+ /** Compare two dotted version strings (like '10.2.3').
152
+ * @returns {Integer} 0: v1 == v2, -1: v1 < v2, 1: v1 > v2
153
+ */
154
+ function versionCompare(v1, v2) {
155
+ var v1parts = ("" + v1).split("."),
156
+ v2parts = ("" + v2).split("."),
157
+ minLength = Math.min(v1parts.length, v2parts.length),
158
+ p1, p2, i;
159
+ // Compare tuple pair-by-pair.
160
+ for(i = 0; i < minLength; i++) {
161
+ // Convert to integer if possible, because "8" > "10".
162
+ p1 = parseInt(v1parts[i], 10);
163
+ p2 = parseInt(v2parts[i], 10);
164
+ if (isNaN(p1)){ p1 = v1parts[i]; }
165
+ if (isNaN(p2)){ p2 = v2parts[i]; }
166
+ if (p1 == p2) {
167
+ continue;
168
+ }else if (p1 > p2) {
169
+ return 1;
170
+ }else if (p1 < p2) {
171
+ return -1;
172
+ }
173
+ // one operand is NaN
174
+ return NaN;
175
+ }
176
+ // The longer tuple is always considered 'greater'
177
+ if (v1parts.length === v2parts.length) {
178
+ return 0;
179
+ }
180
+ return (v1parts.length < v2parts.length) ? -1 : 1;
181
+ }
182
+
183
+
117
184
  /*************************************************************************
118
185
  * Class DynaTreeNode
119
186
  */
@@ -129,8 +196,10 @@ DynaTreeNode.prototype = {
129
196
  if ( typeof data === "string" ){
130
197
  data = { title: data };
131
198
  }
132
- if( data.key === undefined ){
199
+ if( !data.key ){
133
200
  data.key = "_" + tree._nodeCount++;
201
+ }else{
202
+ data.key = "" + data.key; // issue 371
134
203
  }
135
204
  this.data = $.extend({}, $.ui.dynatree.nodedatadefaults, data);
136
205
  this.li = null; // not yet created
@@ -220,6 +289,8 @@ DynaTreeNode.prototype = {
220
289
  } else if ( data.icon === false ) {
221
290
  // icon == false means 'no icon'
222
291
  // noop(); // keep JSLint happy
292
+ } else if ( data.iconClass ) {
293
+ res += "<span class='" + " " + data.iconClass + "'></span>";
223
294
  } else {
224
295
  // icon == null means 'default icon'
225
296
  res += cache.tagNodeIcon;
@@ -1168,7 +1239,8 @@ DynaTreeNode.prototype = {
1168
1239
  var aTag = this.span.getElementsByTagName("a");
1169
1240
  if(aTag[0]){
1170
1241
  // issue 154, 313
1171
- if(!($.browser.msie && parseInt($.browser.version, 10) < 9)){
1242
+ // if(!($.browser.msie && parseInt($.browser.version, 10) < 9)){
1243
+ if(!(BROWSER.msie && parseInt(BROWSER.version, 10) < 9)){
1172
1244
  aTag[0].focus();
1173
1245
  }
1174
1246
  }else{
@@ -1377,8 +1449,10 @@ DynaTreeNode.prototype = {
1377
1449
  }
1378
1450
  }
1379
1451
  tn.removeChildren(true);
1380
- // this.div.removeChild(tn.div);
1381
- this.ul.removeChild(tn.li);
1452
+ if(this.ul){
1453
+ // $("li", $(this.ul)).remove(); // issue 399
1454
+ this.ul.removeChild(tn.li); // issue 402
1455
+ }
1382
1456
  for(var i=0, l=ac.length; i<l; i++) {
1383
1457
  if( ac[i] === tn ) {
1384
1458
  this.childList.splice(i, 1);
@@ -2043,7 +2117,7 @@ var DynaTree = Class.create();
2043
2117
 
2044
2118
  // --- Static members ----------------------------------------------------------
2045
2119
 
2046
- DynaTree.version = "$Version: 1.2.2$";
2120
+ DynaTree.version = "$Version: 1.2.4$";
2047
2121
 
2048
2122
  /*
2049
2123
  DynaTree._initTree = function() {
@@ -2365,7 +2439,7 @@ DynaTree.prototype = {
2365
2439
  var match = null;
2366
2440
  this.visit(function(node){
2367
2441
  // window.console.log("%s", node);
2368
- if(node.data.key == key) {
2442
+ if(node.data.key === key) {
2369
2443
  match = node;
2370
2444
  return false;
2371
2445
  }
@@ -2516,7 +2590,7 @@ TODO: better?
2516
2590
  data.tooltip = $li.attr("title"); // overrides <a title='...'>
2517
2591
  }
2518
2592
  if( $li.attr("id") ){
2519
- data.key = $li.attr("id");
2593
+ data.key = "" + $li.attr("id");
2520
2594
  }
2521
2595
  // If a data attribute is present, evaluate as a JavaScript object
2522
2596
  if( $li.attr("data") ) {
@@ -2685,7 +2759,8 @@ TODO: better?
2685
2759
  case "helper":
2686
2760
  // Only event and node argument is available
2687
2761
  var $helper = $("<div class='dynatree-drag-helper'><span class='dynatree-drag-helper-img' /></div>")
2688
- .append($(event.target).closest('a').clone());
2762
+ .append($(event.target).closest(".dynatree-title").clone());
2763
+ // .append($(event.target).closest('a').clone());
2689
2764
  // issue 244: helper should be child of scrollParent
2690
2765
  $("ul.dynatree-container", node.tree.divTree).append($helper);
2691
2766
  // $(node.tree.divTree).append($helper);
@@ -2854,7 +2929,8 @@ $.widget("ui.dynatree", {
2854
2929
  },
2855
2930
  */
2856
2931
  _init: function() {
2857
- if( parseFloat($.ui.version) < 1.8 ) {
2932
+ // if( parseFloat($.ui.version) < 1.8 ) {
2933
+ if(versionCompare($.ui.version, "1.8") < 0){
2858
2934
  // jquery.ui.core 1.8 renamed _init() to _create(): this stub assures backward compatibility
2859
2935
  if(this.options.debugLevel >= 0){
2860
2936
  _log("warn", "ui.dynatree._init() was called; you should upgrade to jquery.ui.core.js v1.8 or higher.");
@@ -2999,14 +3075,15 @@ $.widget("ui.dynatree", {
2999
3075
 
3000
3076
 
3001
3077
  // The following methods return a value (thus breaking the jQuery call chain):
3002
- if( parseFloat($.ui.version) < 1.8 ) {
3078
+ if(versionCompare($.ui.version, "1.8") < 0){
3079
+ //if( parseFloat($.ui.version) < 1.8 ) {
3003
3080
  $.ui.dynatree.getter = "getTree getRoot getActiveNode getSelectedNodes";
3004
3081
  }
3005
3082
 
3006
3083
  /*******************************************************************************
3007
3084
  * Tools in ui.dynatree namespace
3008
3085
  */
3009
- $.ui.dynatree.version = "$Version: 1.2.2$";
3086
+ $.ui.dynatree.version = "$Version: 1.2.4$";
3010
3087
 
3011
3088
  /**
3012
3089
  * Return a DynaTreeNode object for a given DOM element
@@ -3167,7 +3244,8 @@ $.ui.dynatree.prototype.options = {
3167
3244
  lastentry: undefined
3168
3245
  };
3169
3246
  //
3170
- if( parseFloat($.ui.version) < 1.8 ) {
3247
+ if(versionCompare($.ui.version, "1.8") < 0){
3248
+ //if( parseFloat($.ui.version) < 1.8 ) {
3171
3249
  $.ui.dynatree.defaults = $.ui.dynatree.prototype.options;
3172
3250
  }
3173
3251
 
@@ -3259,7 +3337,8 @@ var _registerDnd = function() {
3259
3337
  // Register proxy-functions for draggable.start/drag/stop
3260
3338
  $.ui.plugin.add("draggable", "connectToDynatree", {
3261
3339
  start: function(event, ui) {
3262
- var draggable = $(this).data("draggable"),
3340
+ // issue 386
3341
+ var draggable = $(this).data("ui-draggable") || $(this).data("draggable"),
3263
3342
  sourceNode = ui.helper.data("dtSourceNode") || null;
3264
3343
  // logMsg("draggable-connectToDynatree.start, %s", sourceNode);
3265
3344
  // logMsg(" this: %o", this);
@@ -3281,7 +3360,8 @@ var _registerDnd = function() {
3281
3360
  }
3282
3361
  },
3283
3362
  drag: function(event, ui) {
3284
- var draggable = $(this).data("draggable"),
3363
+ // issue 386
3364
+ var draggable = $(this).data("ui-draggable") || $(this).data("draggable"),
3285
3365
  sourceNode = ui.helper.data("dtSourceNode") || null,
3286
3366
  prevTargetNode = ui.helper.data("dtTargetNode") || null,
3287
3367
  targetNode = $.ui.dynatree.getNode(event.target);
@@ -3320,13 +3400,14 @@ var _registerDnd = function() {
3320
3400
  // else go ahead with standard event handling
3321
3401
  },
3322
3402
  stop: function(event, ui) {
3323
- var draggable = $(this).data("draggable"),
3403
+ // issue 386
3404
+ var draggable = $(this).data("ui-draggable") || $(this).data("draggable"),
3324
3405
  sourceNode = ui.helper.data("dtSourceNode") || null,
3325
3406
  targetNode = ui.helper.data("dtTargetNode") || null,
3326
3407
  mouseDownEvent = draggable._mouseDownEvent,
3327
3408
  eventType = event.type,
3328
3409
  dropped = (eventType == "mouseup" && event.which == 1);
3329
- // logMsg("draggable-connectToDynatree.stop: targetNode(from event): %s, dtTargetNode: %s", targetNode, ui.helper.data("dtTargetNode"));
3410
+ logMsg("draggable-connectToDynatree.stop: targetNode(from event): %s, dtTargetNode: %s", targetNode, ui.helper.data("dtTargetNode"));
3330
3411
  // logMsg("draggable-connectToDynatree.stop, %s", sourceNode);
3331
3412
  // logMsg(" type: %o, downEvent: %o, upEvent: %o", eventType, mouseDownEvent, event);
3332
3413
  // logMsg(" targetNode: %o", targetNode);
@@ -247,7 +247,6 @@ span
247
247
  &.dynatree-focused a:link
248
248
  background-color: #EFEBDE
249
249
  /* gray
250
- &.dynatree-has-children! a, &.dynatree-expanded! a
251
250
  &.dynatree-selected a
252
251
  color: green
253
252
  font-style: italic
@@ -302,22 +301,14 @@ div
302
301
 
303
302
  span
304
303
  &.dynatree-drag-source
305
- /* border: 1px dotted gray;
306
304
  background-color: #e0e0e0
307
305
  a
308
306
  color: gray
309
307
  &.dynatree-drop-target
310
- /*border: 1px solid gray;
311
- a!
312
308
  &.dynatree-drop-accept a
313
- /*border: 1px solid green;
314
309
  background-color: #3169C6 !important
315
310
  color: white !important
316
- /* @ IE6
317
311
  text-decoration: none
318
- &.dynatree-drop-reject
319
- /*border: 1px solid red;
320
- &.dynatree-drop-after! a
321
312
  &.custom1 a
322
313
  background-color: maroon
323
314
  color: yellow
@@ -325,4 +316,4 @@ span
325
316
  /*** Target node while dragging cursor is over it ****************************
326
317
 
327
318
  /*******************************************************************************
328
- * Custom node classes (sample)
319
+ * Custom node classes (sample)
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynatree-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
5
- prerelease:
4
+ version: 0.1.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Gleb Tv
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-01-21 00:00:00.000000000 Z
11
+ date: 2013-07-27 00:00:00.000000000 Z
13
12
  dependencies: []
14
13
  description: ''
15
14
  email:
@@ -29,7 +28,6 @@ files:
29
28
  - lib/dynatree-rails/engine.rb
30
29
  - lib/dynatree-rails/renderer.rb
31
30
  - lib/dynatree-rails/version.rb
32
- - vendor/assets/images/dynatree/jquery.dynatree.js
33
31
  - vendor/assets/images/dynatree/skin-vista/icons.gif
34
32
  - vendor/assets/images/dynatree/skin-vista/loading.gif
35
33
  - vendor/assets/images/dynatree/skin/icons-rtl.gif
@@ -42,26 +40,25 @@ files:
42
40
  - vendor/assets/stylesheets/dynatree/skin.sass
43
41
  homepage: https://github.com/glebtv/dynatree-rails
44
42
  licenses: []
43
+ metadata: {}
45
44
  post_install_message:
46
45
  rdoc_options: []
47
46
  require_paths:
48
47
  - lib
49
48
  required_ruby_version: !ruby/object:Gem::Requirement
50
- none: false
51
49
  requirements:
52
- - - ! '>='
50
+ - - '>='
53
51
  - !ruby/object:Gem::Version
54
52
  version: '0'
55
53
  required_rubygems_version: !ruby/object:Gem::Requirement
56
- none: false
57
54
  requirements:
58
- - - ! '>='
55
+ - - '>='
59
56
  - !ruby/object:Gem::Version
60
57
  version: '0'
61
58
  requirements: []
62
59
  rubyforge_project:
63
- rubygems_version: 1.8.24
60
+ rubygems_version: 2.0.3
64
61
  signing_key:
65
- specification_version: 3
62
+ specification_version: 4
66
63
  summary: Dynatree integration for rails 3.1 asset pipeline
67
64
  test_files: []
@@ -1,3312 +0,0 @@
1
- /*************************************************************************
2
- jquery.dynatree.js
3
- Dynamic tree view control, with support for lazy loading of branches.
4
-
5
- Copyright (c) 2008-2011, Martin Wendt (http://wwWendt.de)
6
- Dual licensed under the MIT or GPL Version 2 licenses.
7
- http://code.google.com/p/dynatree/wiki/LicenseInfo
8
-
9
- A current version and some documentation is available at
10
- http://dynatree.googlecode.com/
11
-
12
- $Version: 1.2.1_rc3$
13
- $Revision: 585, 2012-01-10 00:07:39$
14
-
15
- @depends: jquery.js
16
- @depends: jquery.ui.core.js
17
- @depends: jquery.cookie.js
18
- *************************************************************************/
19
-
20
- // Note: We currently allow eval() to parse the 'data' attribtes, when initializing from HTML.
21
- /*jslint laxbreak: true, browser: true, evil: true, indent: 0, white: false, onevar: false */
22
-
23
- /*************************************************************************
24
- * Debug functions
25
- */
26
-
27
- var _canLog = true;
28
-
29
- function _log(mode, msg) {
30
- /**
31
- * Usage: logMsg("%o was toggled", this);
32
- */
33
- if( !_canLog ){
34
- return;
35
- }
36
- // Remove first argument
37
- var args = Array.prototype.slice.apply(arguments, [1]);
38
- // Prepend timestamp
39
- var dt = new Date();
40
- var tag = dt.getHours()+":"+dt.getMinutes()+":"+dt.getSeconds()+"."+dt.getMilliseconds();
41
- args[0] = tag + " - " + args[0];
42
-
43
- try {
44
- switch( mode ) {
45
- case "info":
46
- window.console.info.apply(window.console, args);
47
- break;
48
- case "warn":
49
- window.console.warn.apply(window.console, args);
50
- break;
51
- default:
52
- window.console.log.apply(window.console, args);
53
- break;
54
- }
55
- } catch(e) {
56
- if( !window.console ){
57
- _canLog = false; // Permanently disable, when logging is not supported by the browser
58
- }
59
- }
60
- }
61
-
62
- function logMsg(msg) {
63
- Array.prototype.unshift.apply(arguments, ["debug"]);
64
- _log.apply(this, arguments);
65
- }
66
-
67
-
68
- // Forward declaration
69
- var getDynaTreePersistData = null;
70
-
71
-
72
-
73
- /*************************************************************************
74
- * Constants
75
- */
76
- var DTNodeStatus_Error = -1;
77
- var DTNodeStatus_Loading = 1;
78
- var DTNodeStatus_Ok = 0;
79
-
80
-
81
- // Start of local namespace
82
- (function($) {
83
-
84
- /*************************************************************************
85
- * Common tool functions.
86
- */
87
-
88
- var Class = {
89
- create: function() {
90
- return function() {
91
- this.initialize.apply(this, arguments);
92
- };
93
- }
94
- };
95
-
96
- // Tool function to get dtnode from the event target:
97
- function getDtNodeFromElement(el) {
98
- alert("getDtNodeFromElement is deprecated");
99
- return $.ui.dynatree.getNode(el);
100
- /*
101
- var iMax = 5;
102
- while( el && iMax-- ) {
103
- if(el.dtnode) { return el.dtnode; }
104
- el = el.parentNode;
105
- }
106
- return null;
107
- */
108
- }
109
-
110
- function noop() {
111
- }
112
-
113
- /*************************************************************************
114
- * Class DynaTreeNode
115
- */
116
- var DynaTreeNode = Class.create();
117
-
118
- DynaTreeNode.prototype = {
119
- initialize: function(parent, tree, data) {
120
- /**
121
- * @constructor
122
- */
123
- this.parent = parent;
124
- this.tree = tree;
125
- if ( typeof data === "string" ){
126
- data = { title: data };
127
- }
128
- if( data.key === undefined ){
129
- data.key = "_" + tree._nodeCount++;
130
- }
131
- this.data = $.extend({}, $.ui.dynatree.nodedatadefaults, data);
132
- this.li = null; // not yet created
133
- this.span = null; // not yet created
134
- this.ul = null; // not yet created
135
- this.childList = null; // no subnodes yet
136
- this._isLoading = false; // Lazy content is being loaded
137
- this.hasSubSel = false;
138
- this.bExpanded = false;
139
- this.bSelected = false;
140
-
141
- },
142
-
143
- toString: function() {
144
- return "DynaTreeNode<" + this.data.key + ">: '" + this.data.title + "'";
145
- },
146
-
147
- toDict: function(recursive, callback) {
148
- var dict = $.extend({}, this.data);
149
- dict.activate = ( this.tree.activeNode === this );
150
- dict.focus = ( this.tree.focusNode === this );
151
- dict.expand = this.bExpanded;
152
- dict.select = this.bSelected;
153
- if( callback ){
154
- callback(dict);
155
- }
156
- if( recursive && this.childList ) {
157
- dict.children = [];
158
- for(var i=0, l=this.childList.length; i<l; i++ ){
159
- dict.children.push(this.childList[i].toDict(true, callback));
160
- }
161
- } else {
162
- delete dict.children;
163
- }
164
- return dict;
165
- },
166
-
167
- fromDict: function(dict) {
168
- /**
169
- * Update node data. If dict contains 'children', then also replace
170
- * the hole sub tree.
171
- */
172
- var children = dict.children;
173
- if(children === undefined){
174
- this.data = $.extend(this.data, dict);
175
- this.render();
176
- return;
177
- }
178
- dict = $.extend({}, dict);
179
- dict.children = undefined;
180
- this.data = $.extend(this.data, dict);
181
- this.removeChildren();
182
- this.addChild(children);
183
- },
184
-
185
- _getInnerHtml: function() {
186
- var tree = this.tree,
187
- opts = tree.options,
188
- cache = tree.cache,
189
- level = this.getLevel(),
190
- data = this.data,
191
- res = "";
192
- // connector (expanded, expandable or simple)
193
- if( level < opts.minExpandLevel ) {
194
- if(level > 1){
195
- res += cache.tagConnector;
196
- }
197
- // .. else (i.e. for root level) skip expander/connector altogether
198
- } else if( this.hasChildren() !== false ) {
199
- res += cache.tagExpander;
200
- } else {
201
- res += cache.tagConnector;
202
- }
203
- // Checkbox mode
204
- if( opts.checkbox && data.hideCheckbox !== true && !data.isStatusNode ) {
205
- res += cache.tagCheckbox;
206
- }
207
- // folder or doctype icon
208
- if ( data.icon ) {
209
- res += "<img src='" + opts.imagePath + data.icon + "' alt='' />";
210
- } else if ( data.icon === false ) {
211
- // icon == false means 'no icon'
212
- noop(); // keep JSLint happy
213
- } else {
214
- // icon == null means 'default icon'
215
- res += cache.tagNodeIcon;
216
- }
217
- // node title
218
- var nodeTitle = "";
219
- if ( opts.onCustomRender ){
220
- nodeTitle = opts.onCustomRender.call(tree, this) || "";
221
- }
222
- if(!nodeTitle){
223
- var tooltip = data.tooltip ? ' title="' + data.tooltip.replace(/\"/g, '&quot;') + '"' : '',
224
- href = data.href || "#";
225
- if( opts.noLink || data.noLink ) {
226
- nodeTitle = '<span style="display:inline-block;" class="' + opts.classNames.title + '"' + tooltip + '>' + data.title + '</span>';
227
- // this.tree.logDebug("nodeTitle: " + nodeTitle);
228
- } else {
229
- nodeTitle = '<a href="' + href + '" class="' + opts.classNames.title + '"' + tooltip + '>' + data.title + '</a>';
230
- }
231
- }
232
- res += nodeTitle;
233
- return res;
234
- },
235
-
236
-
237
- _fixOrder: function() {
238
- /**
239
- * Make sure, that <li> order matches childList order.
240
- */
241
- var cl = this.childList;
242
- if( !cl || !this.ul ){
243
- return;
244
- }
245
- var childLI = this.ul.firstChild;
246
- for(var i=0, l=cl.length-1; i<l; i++) {
247
- var childNode1 = cl[i];
248
- var childNode2 = childLI.dtnode;
249
- if( childNode1 !== childNode2 ) {
250
- this.tree.logDebug("_fixOrder: mismatch at index " + i + ": " + childNode1 + " != " + childNode2);
251
- this.ul.insertBefore(childNode1.li, childNode2.li);
252
- } else {
253
- childLI = childLI.nextSibling;
254
- }
255
- }
256
- },
257
-
258
-
259
- render: function(useEffects, includeInvisible) {
260
- /**
261
- * Create <li><span>..</span> .. </li> tags for this node.
262
- *
263
- * <li id='KEY' dtnode=NODE> // This div contains the node's span and list of child div's.
264
- * <span class='title'>S S S A</span> // Span contains graphic spans and title <a> tag
265
- * <ul> // only present, when node has children
266
- * <li id='KEY' dtnode=NODE>child1</li>
267
- * <li id='KEY' dtnode=NODE>child2</li>
268
- * </ul>
269
- * </li>
270
- */
271
- // this.tree.logDebug("%s.render(%s)", this, useEffects);
272
- // ---
273
- var tree = this.tree,
274
- parent = this.parent,
275
- data = this.data,
276
- opts = tree.options,
277
- cn = opts.classNames,
278
- isLastSib = this.isLastSibling(),
279
- firstTime = false;
280
-
281
- if( !parent && !this.ul ) {
282
- // Root node has only a <ul>
283
- this.li = this.span = null;
284
- this.ul = document.createElement("ul");
285
- if( opts.minExpandLevel > 1 ){
286
- this.ul.className = cn.container + " " + cn.noConnector;
287
- }else{
288
- this.ul.className = cn.container;
289
- }
290
- } else if( parent ) {
291
- // Create <li><span /> </li>
292
- if( ! this.li ) {
293
- firstTime = true;
294
- this.li = document.createElement("li");
295
- this.li.dtnode = this;
296
- if( data.key && opts.generateIds ){
297
- this.li.id = opts.idPrefix + data.key;
298
- }
299
- this.span = document.createElement("span");
300
- this.span.className = cn.title;
301
- this.li.appendChild(this.span);
302
-
303
- if( !parent.ul ) {
304
- // This is the parent's first child: create UL tag
305
- // (Hidden, because it will be
306
- parent.ul = document.createElement("ul");
307
- parent.ul.style.display = "none";
308
- parent.li.appendChild(parent.ul);
309
- // if( opts.minExpandLevel > this.getLevel() ){
310
- // parent.ul.className = cn.noConnector;
311
- // }
312
- }
313
- // set node connector images, links and text
314
- // this.span.innerHTML = this._getInnerHtml();
315
-
316
- parent.ul.appendChild(this.li);
317
- }
318
- // set node connector images, links and text
319
- this.span.innerHTML = this._getInnerHtml();
320
- // Set classes for current status
321
- var cnList = [];
322
- cnList.push(cn.node);
323
- if( data.isFolder ){
324
- cnList.push(cn.folder);
325
- }
326
- if( this.bExpanded ){
327
- cnList.push(cn.expanded);
328
- }
329
- if( this.hasChildren() !== false ){
330
- cnList.push(cn.hasChildren);
331
- }
332
- if( data.isLazy && this.childList === null ){
333
- cnList.push(cn.lazy);
334
- }
335
- if( isLastSib ){
336
- cnList.push(cn.lastsib);
337
- }
338
- if( this.bSelected ){
339
- cnList.push(cn.selected);
340
- }
341
- if( this.hasSubSel ){
342
- cnList.push(cn.partsel);
343
- }
344
- if( tree.activeNode === this ){
345
- cnList.push(cn.active);
346
- }
347
- if( data.addClass ){
348
- cnList.push(data.addClass);
349
- }
350
- // IE6 doesn't correctly evaluate multiple class names,
351
- // so we create combined class names that can be used in the CSS
352
- cnList.push(cn.combinedExpanderPrefix
353
- + (this.bExpanded ? "e" : "c")
354
- + (data.isLazy && this.childList === null ? "d" : "")
355
- + (isLastSib ? "l" : "")
356
- );
357
- cnList.push(cn.combinedIconPrefix
358
- + (this.bExpanded ? "e" : "c")
359
- + (data.isFolder ? "f" : "")
360
- );
361
- this.span.className = cnList.join(" ");
362
-
363
- // TODO: we should not set this in the <span> tag also, if we set it here:
364
- this.li.className = isLastSib ? cn.lastsib : "";
365
-
366
- // Allow tweaking, binding, after node was created for the first time
367
- if(firstTime && opts.onCreate){
368
- opts.onCreate.call(tree, this, this.span);
369
- }
370
- // Hide children, if node is collapsed
371
- // this.ul.style.display = ( this.bExpanded || !parent ) ? "" : "none";
372
- // Allow tweaking after node state was rendered
373
- if(opts.onRender){
374
- opts.onRender.call(tree, this, this.span);
375
- }
376
- }
377
- // Visit child nodes
378
- if( (this.bExpanded || includeInvisible === true) && this.childList ) {
379
- for(var i=0, l=this.childList.length; i<l; i++) {
380
- this.childList[i].render(false, includeInvisible);
381
- }
382
- // Make sure the tag order matches the child array
383
- this._fixOrder();
384
- }
385
- // Hide children, if node is collapsed
386
- if( this.ul ) {
387
- var isHidden = (this.ul.style.display === "none");
388
- var isExpanded = !!this.bExpanded;
389
- // logMsg("isHidden:%s", isHidden);
390
- if( useEffects && opts.fx && (isHidden === isExpanded) ) {
391
- var duration = opts.fx.duration || 200;
392
- $(this.ul).animate(opts.fx, duration);
393
- } else {
394
- this.ul.style.display = ( this.bExpanded || !parent ) ? "" : "none";
395
- }
396
- }
397
- },
398
- /** Return '/id1/id2/id3'. */
399
- getKeyPath: function(excludeSelf) {
400
- var path = [];
401
- this.visitParents(function(node){
402
- if(node.parent){
403
- path.unshift(node.data.key);
404
- }
405
- }, !excludeSelf);
406
- return "/" + path.join(this.tree.options.keyPathSeparator);
407
- },
408
-
409
- getParent: function() {
410
- return this.parent;
411
- },
412
-
413
- getChildren: function() {
414
- if(this.hasChildren() === undefined){
415
- return undefined; // Lazy node: unloaded, currently loading, or load error
416
- }
417
- return this.childList;
418
- },
419
-
420
- /** Check if node has children (returns undefined, if not sure). */
421
- hasChildren: function() {
422
- if(this.data.isLazy){
423
- if(this.childList === null || this.childList === undefined){
424
- // Not yet loaded
425
- return undefined;
426
- }else if(this.childList.length === 0){
427
- // Loaded, but response was empty
428
- return false;
429
- }else if(this.childList.length === 1 && this.childList[0].isStatusNode()){
430
- // Currently loading or load error
431
- return undefined;
432
- }
433
- return true;
434
- }
435
- return !!this.childList;
436
- },
437
-
438
- isFirstSibling: function() {
439
- var p = this.parent;
440
- return !p || p.childList[0] === this;
441
- },
442
-
443
- isLastSibling: function() {
444
- var p = this.parent;
445
- return !p || p.childList[p.childList.length-1] === this;
446
- },
447
-
448
- isLoading: function() {
449
- return !!this._isLoading;
450
- },
451
-
452
- getPrevSibling: function() {
453
- if( !this.parent ){
454
- return null;
455
- }
456
- var ac = this.parent.childList;
457
- for(var i=1, l=ac.length; i<l; i++){ // start with 1, so prev(first) = null
458
- if( ac[i] === this ){
459
- return ac[i-1];
460
- }
461
- }
462
- return null;
463
- },
464
-
465
- getNextSibling: function() {
466
- if( !this.parent ){
467
- return null;
468
- }
469
- var ac = this.parent.childList;
470
- for(var i=0, l=ac.length-1; i<l; i++){ // up to length-2, so next(last) = null
471
- if( ac[i] === this ){
472
- return ac[i+1];
473
- }
474
- }
475
- return null;
476
- },
477
-
478
- isStatusNode: function() {
479
- return (this.data.isStatusNode === true);
480
- },
481
-
482
- isChildOf: function(otherNode) {
483
- return (this.parent && this.parent === otherNode);
484
- },
485
-
486
- isDescendantOf: function(otherNode) {
487
- if(!otherNode){
488
- return false;
489
- }
490
- var p = this.parent;
491
- while( p ) {
492
- if( p === otherNode ){
493
- return true;
494
- }
495
- p = p.parent;
496
- }
497
- return false;
498
- },
499
-
500
- countChildren: function() {
501
- var cl = this.childList;
502
- if( !cl ){
503
- return 0;
504
- }
505
- var n = cl.length;
506
- for(var i=0, l=n; i<l; i++){
507
- var child = cl[i];
508
- n += child.countChildren();
509
- }
510
- return n;
511
- },
512
-
513
- /**Sort child list by title.
514
- * cmd: optional compare function.
515
- * deep: optional: pass true to sort all descendant nodes.
516
- */
517
- sortChildren: function(cmp, deep) {
518
- var cl = this.childList;
519
- if( !cl ){
520
- return;
521
- }
522
- cmp = cmp || function(a, b) {
523
- // return a.data.title === b.data.title ? 0 : a.data.title > b.data.title ? 1 : -1;
524
- var x = a.data.title.toLowerCase(),
525
- y = b.data.title.toLowerCase();
526
- return x === y ? 0 : x > y ? 1 : -1;
527
- };
528
- cl.sort(cmp);
529
- if( deep ){
530
- for(var i=0, l=cl.length; i<l; i++){
531
- if( cl[i].childList ){
532
- cl[i].sortChildren(cmp, "$norender$");
533
- }
534
- }
535
- }
536
- if( deep !== "$norender$" ){
537
- this.render();
538
- }
539
- },
540
-
541
- _setStatusNode: function(data) {
542
- // Create, modify or remove the status child node (pass 'null', to remove it).
543
- var firstChild = ( this.childList ? this.childList[0] : null );
544
- if( !data ) {
545
- if ( firstChild && firstChild.isStatusNode()) {
546
- try{
547
- // I've seen exceptions here with loadKeyPath...
548
- if(this.ul){
549
- this.ul.removeChild(firstChild.li);
550
- firstChild.li = null; // avoid leaks (issue 215)
551
- }
552
- }catch(e){}
553
- if( this.childList.length === 1 ){
554
- this.childList = [];
555
- }else{
556
- this.childList.shift();
557
- }
558
- }
559
- } else if ( firstChild ) {
560
- data.isStatusNode = true;
561
- data.key = "_statusNode";
562
- firstChild.data = data;
563
- firstChild.render();
564
- } else {
565
- data.isStatusNode = true;
566
- data.key = "_statusNode";
567
- firstChild = this.addChild(data);
568
- }
569
- },
570
-
571
- setLazyNodeStatus: function(lts, opts) {
572
- var tooltip = (opts && opts.tooltip) ? opts.tooltip : null,
573
- info = (opts && opts.info) ? " (" + opts.info + ")" : "";
574
- switch( lts ) {
575
- case DTNodeStatus_Ok:
576
- this._setStatusNode(null);
577
- $(this.span).removeClass(this.tree.options.classNames.nodeLoading);
578
- this._isLoading = false;
579
- // this.render();
580
- if( this.tree.options.autoFocus ) {
581
- if( this === this.tree.tnRoot && this.childList && this.childList.length > 0) {
582
- // special case: using ajaxInit
583
- this.childList[0].focus();
584
- } else {
585
- this.focus();
586
- }
587
- }
588
- break;
589
- case DTNodeStatus_Loading:
590
- this._isLoading = true;
591
- $(this.span).addClass(this.tree.options.classNames.nodeLoading);
592
- // The root is hidden, so we set a temporary status child
593
- if(!this.parent){
594
- this._setStatusNode({
595
- title: this.tree.options.strings.loading + info,
596
- tooltip: tooltip,
597
- addClass: this.tree.options.classNames.nodeWait
598
- });
599
- }
600
- break;
601
- case DTNodeStatus_Error:
602
- this._isLoading = false;
603
- // $(this.span).addClass(this.tree.options.classNames.nodeError);
604
- this._setStatusNode({
605
- title: this.tree.options.strings.loadError + info,
606
- tooltip: tooltip,
607
- addClass: this.tree.options.classNames.nodeError
608
- });
609
- break;
610
- default:
611
- throw "Bad LazyNodeStatus: '" + lts + "'.";
612
- }
613
- },
614
-
615
- _parentList: function(includeRoot, includeSelf) {
616
- var l = [];
617
- var dtn = includeSelf ? this : this.parent;
618
- while( dtn ) {
619
- if( includeRoot || dtn.parent ){
620
- l.unshift(dtn);
621
- }
622
- dtn = dtn.parent;
623
- }
624
- return l;
625
- },
626
- getLevel: function() {
627
- /**
628
- * Return node depth. 0: System root node, 1: visible top-level node.
629
- */
630
- var level = 0;
631
- var dtn = this.parent;
632
- while( dtn ) {
633
- level++;
634
- dtn = dtn.parent;
635
- }
636
- return level;
637
- },
638
-
639
- _getTypeForOuterNodeEvent: function(event) {
640
- /** Return the inner node span (title, checkbox or expander) if
641
- * event.target points to the outer span.
642
- * This function should fix issue #93:
643
- * FF2 ignores empty spans, when generating events (returning the parent instead).
644
- */
645
- var cns = this.tree.options.classNames;
646
- var target = event.target;
647
- // Only process clicks on an outer node span (probably due to a FF2 event handling bug)
648
- if( target.className.indexOf(cns.node) < 0 ) {
649
- return null;
650
- }
651
- // Event coordinates, relative to outer node span:
652
- var eventX = event.pageX - target.offsetLeft;
653
- var eventY = event.pageY - target.offsetTop;
654
-
655
- for(var i=0, l=target.childNodes.length; i<l; i++) {
656
- var cn = target.childNodes[i];
657
- var x = cn.offsetLeft - target.offsetLeft;
658
- var y = cn.offsetTop - target.offsetTop;
659
- var nx = cn.clientWidth, ny = cn.clientHeight;
660
- // alert (cn.className + ": " + x + ", " + y + ", s:" + nx + ", " + ny);
661
- if( eventX >= x && eventX <= (x+nx) && eventY >= y && eventY <= (y+ny) ) {
662
- // alert("HIT "+ cn.className);
663
- if( cn.className==cns.title ){
664
- return "title";
665
- }else if( cn.className==cns.expander ){
666
- return "expander";
667
- }else if( cn.className==cns.checkbox ){
668
- return "checkbox";
669
- }else if( cn.className==cns.nodeIcon ){
670
- return "icon";
671
- }
672
- }
673
- }
674
- return "prefix";
675
- },
676
-
677
- getEventTargetType: function(event) {
678
- // Return the part of a node, that a click event occured on.
679
- // Note: there is no check, if the event was fired on THIS node.
680
- var tcn = event && event.target ? event.target.className : "",
681
- cns = this.tree.options.classNames;
682
-
683
- if( tcn === cns.title ){
684
- return "title";
685
- }else if( tcn === cns.expander ){
686
- return "expander";
687
- }else if( tcn === cns.checkbox ){
688
- return "checkbox";
689
- }else if( tcn === cns.nodeIcon ){
690
- return "icon";
691
- }else if( tcn === cns.empty || tcn === cns.vline || tcn === cns.connector ){
692
- return "prefix";
693
- }else if( tcn.indexOf(cns.node) >= 0 ){
694
- // FIX issue #93
695
- return this._getTypeForOuterNodeEvent(event);
696
- }
697
- return null;
698
- },
699
-
700
- isVisible: function() {
701
- // Return true, if all parents are expanded.
702
- var parents = this._parentList(true, false);
703
- for(var i=0, l=parents.length; i<l; i++){
704
- if( ! parents[i].bExpanded ){ return false; }
705
- }
706
- return true;
707
- },
708
-
709
- makeVisible: function() {
710
- // Make sure, all parents are expanded
711
- var parents = this._parentList(true, false);
712
- for(var i=0, l=parents.length; i<l; i++){
713
- parents[i]._expand(true);
714
- }
715
- },
716
-
717
- focus: function() {
718
- // TODO: check, if we already have focus
719
- // this.tree.logDebug("dtnode.focus(): %o", this);
720
- this.makeVisible();
721
- try {
722
- $(this.span).find(">a").focus();
723
- } catch(e) { }
724
- },
725
-
726
- isFocused: function() {
727
- return (this.tree.tnFocused === this);
728
- },
729
-
730
- _activate: function(flag, fireEvents) {
731
- // (De)Activate - but not focus - this node.
732
- this.tree.logDebug("dtnode._activate(%o, fireEvents=%o) - %o", flag, fireEvents, this);
733
- var opts = this.tree.options;
734
- if( this.data.isStatusNode ){
735
- return;
736
- }
737
- if ( fireEvents && opts.onQueryActivate && opts.onQueryActivate.call(this.tree, flag, this) === false ){
738
- return; // Callback returned false
739
- }
740
- if( flag ) {
741
- // Activate
742
- if( this.tree.activeNode ) {
743
- if( this.tree.activeNode === this ){
744
- return;
745
- }
746
- this.tree.activeNode.deactivate();
747
- }
748
- if( opts.activeVisible ){
749
- this.makeVisible();
750
- }
751
- this.tree.activeNode = this;
752
- if( opts.persist ){
753
- $.cookie(opts.cookieId+"-active", this.data.key, opts.cookie);
754
- }
755
- this.tree.persistence.activeKey = this.data.key;
756
- $(this.span).addClass(opts.classNames.active);
757
- if ( fireEvents && opts.onActivate ){
758
- opts.onActivate.call(this.tree, this);
759
- }
760
- } else {
761
- // Deactivate
762
- if( this.tree.activeNode === this ) {
763
- if ( opts.onQueryActivate && opts.onQueryActivate.call(this.tree, false, this) === false ){
764
- return; // Callback returned false
765
- }
766
- $(this.span).removeClass(opts.classNames.active);
767
- if( opts.persist ) {
768
- // Note: we don't pass null, but ''. So the cookie is not deleted.
769
- // If we pass null, we also have to pass a COPY of opts, because $cookie will override opts.expires (issue 84)
770
- $.cookie(opts.cookieId+"-active", "", opts.cookie);
771
- }
772
- this.tree.persistence.activeKey = null;
773
- this.tree.activeNode = null;
774
- if ( fireEvents && opts.onDeactivate ){
775
- opts.onDeactivate.call(this.tree, this);
776
- }
777
- }
778
- }
779
- },
780
-
781
- activate: function() {
782
- // Select - but not focus - this node.
783
- // this.tree.logDebug("dtnode.activate(): %o", this);
784
- this._activate(true, true);
785
- },
786
-
787
- activateSilently: function() {
788
- this._activate(true, false);
789
- },
790
-
791
- deactivate: function() {
792
- // this.tree.logDebug("dtnode.deactivate(): %o", this);
793
- this._activate(false, true);
794
- },
795
-
796
- isActive: function() {
797
- return (this.tree.activeNode === this);
798
- },
799
-
800
- _userActivate: function() {
801
- // Handle user click / [space] / [enter], according to clickFolderMode.
802
- var activate = true;
803
- var expand = false;
804
- if ( this.data.isFolder ) {
805
- switch( this.tree.options.clickFolderMode ) {
806
- case 2:
807
- activate = false;
808
- expand = true;
809
- break;
810
- case 3:
811
- activate = expand = true;
812
- break;
813
- }
814
- }
815
- if( this.parent === null ) {
816
- expand = false;
817
- }
818
- if( expand ) {
819
- this.toggleExpand();
820
- this.focus();
821
- }
822
- if( activate ) {
823
- this.activate();
824
- }
825
- },
826
-
827
- _setSubSel: function(hasSubSel) {
828
- if( hasSubSel ) {
829
- this.hasSubSel = true;
830
- $(this.span).addClass(this.tree.options.classNames.partsel);
831
- } else {
832
- this.hasSubSel = false;
833
- $(this.span).removeClass(this.tree.options.classNames.partsel);
834
- }
835
- },
836
- /**
837
- * Fix selection and partsel status, of parent nodes, according to current status of
838
- * end nodes.
839
- */
840
- _updatePartSelectionState: function() {
841
- // alert("_updatePartSelectionState " + this);
842
- // this.tree.logDebug("_updatePartSelectionState() - %o", this);
843
- var sel;
844
- // Return `true` or `false` for end nodes and remove part-sel flag
845
- if( ! this.hasChildren() ){
846
- sel = (this.bSelected && !this.data.unselectable && !this.data.isStatusNode);
847
- this._setSubSel(false);
848
- return sel;
849
- }
850
- // Return `true`, `false`, or `undefined` for parent nodes
851
- var i, l,
852
- cl = this.childList,
853
- allSelected = true,
854
- allDeselected = true;
855
- for(i=0, l=cl.length; i<l; i++) {
856
- var n = cl[i],
857
- s = n._updatePartSelectionState();
858
- if( s !== false){
859
- allDeselected = false;
860
- }
861
- if( s !== true){
862
- allSelected = false;
863
- }
864
- }
865
- if( allSelected ){
866
- sel = true;
867
- } else if ( allDeselected ){
868
- sel = false;
869
- } else {
870
- sel = undefined;
871
- }
872
- this._setSubSel(sel === undefined);
873
- this.bSelected = (sel === true);
874
- return sel;
875
- },
876
-
877
- /**
878
- * Fix selection status, after this node was (de)selected in multi-hier mode.
879
- * This includes (de)selecting all children.
880
- */
881
- _fixSelectionState: function() {
882
- // alert("_fixSelectionState " + this);
883
- // this.tree.logDebug("_fixSelectionState(%s) - %o", this.bSelected, this);
884
- var p, i, l;
885
- if( this.bSelected ) {
886
- // Select all children
887
- this.visit(function(node){
888
- node.parent._setSubSel(true);
889
- if(!node.data.unselectable){
890
- node._select(true, false, false);
891
- }
892
- });
893
- // Select parents, if all children are selected
894
- p = this.parent;
895
- while( p ) {
896
- p._setSubSel(true);
897
- var allChildsSelected = true;
898
- for(i=0, l=p.childList.length; i<l; i++) {
899
- var n = p.childList[i];
900
- if( !n.bSelected && !n.data.isStatusNode && !n.data.unselectable) {
901
- allChildsSelected = false;
902
- break;
903
- }
904
- }
905
- if( allChildsSelected ){
906
- p._select(true, false, false);
907
- }
908
- p = p.parent;
909
- }
910
- } else {
911
- // Deselect all children
912
- this._setSubSel(false);
913
- this.visit(function(node){
914
- node._setSubSel(false);
915
- node._select(false, false, false);
916
- });
917
- // Deselect parents, and recalc hasSubSel
918
- p = this.parent;
919
- while( p ) {
920
- p._select(false, false, false);
921
- var isPartSel = false;
922
- for(i=0, l=p.childList.length; i<l; i++) {
923
- if( p.childList[i].bSelected || p.childList[i].hasSubSel ) {
924
- isPartSel = true;
925
- break;
926
- }
927
- }
928
- p._setSubSel(isPartSel);
929
- p = p.parent;
930
- }
931
- }
932
- },
933
-
934
- _select: function(sel, fireEvents, deep) {
935
- // Select - but not focus - this node.
936
- // this.tree.logDebug("dtnode._select(%o) - %o", sel, this);
937
- var opts = this.tree.options;
938
- if( this.data.isStatusNode ){
939
- return;
940
- }
941
- //
942
- if( this.bSelected === sel ) {
943
- // this.tree.logDebug("dtnode._select(%o) IGNORED - %o", sel, this);
944
- return;
945
- }
946
- // Allow event listener to abort selection
947
- if ( fireEvents && opts.onQuerySelect && opts.onQuerySelect.call(this.tree, sel, this) === false ){
948
- return; // Callback returned false
949
- }
950
- // Force single-selection
951
- if( opts.selectMode==1 && sel ) {
952
- this.tree.visit(function(node){
953
- if( node.bSelected ) {
954
- // Deselect; assuming that in selectMode:1 there's max. one other selected node
955
- node._select(false, false, false);
956
- return false;
957
- }
958
- });
959
- }
960
-
961
- this.bSelected = sel;
962
- // this.tree._changeNodeList("select", this, sel);
963
-
964
- if( sel ) {
965
- if( opts.persist ){
966
- this.tree.persistence.addSelect(this.data.key);
967
- }
968
- $(this.span).addClass(opts.classNames.selected);
969
-
970
- if( deep && opts.selectMode === 3 ){
971
- this._fixSelectionState();
972
- }
973
- if ( fireEvents && opts.onSelect ){
974
- opts.onSelect.call(this.tree, true, this);
975
- }
976
- } else {
977
- if( opts.persist ){
978
- this.tree.persistence.clearSelect(this.data.key);
979
- }
980
- $(this.span).removeClass(opts.classNames.selected);
981
-
982
- if( deep && opts.selectMode === 3 ){
983
- this._fixSelectionState();
984
- }
985
- if ( fireEvents && opts.onSelect ){
986
- opts.onSelect.call(this.tree, false, this);
987
- }
988
- }
989
- },
990
-
991
- select: function(sel) {
992
- // Select - but not focus - this node.
993
- // this.tree.logDebug("dtnode.select(%o) - %o", sel, this);
994
- if( this.data.unselectable ){
995
- return this.bSelected;
996
- }
997
- return this._select(sel!==false, true, true);
998
- },
999
-
1000
- toggleSelect: function() {
1001
- // this.tree.logDebug("dtnode.toggleSelect() - %o", this);
1002
- return this.select(!this.bSelected);
1003
- },
1004
-
1005
- isSelected: function() {
1006
- return this.bSelected;
1007
- },
1008
-
1009
- isLazy: function() {
1010
- return !!this.data.isLazy;
1011
- },
1012
-
1013
- _loadContent: function() {
1014
- try {
1015
- var opts = this.tree.options;
1016
- this.tree.logDebug("_loadContent: start - %o", this);
1017
- this.setLazyNodeStatus(DTNodeStatus_Loading);
1018
- if( true === opts.onLazyRead.call(this.tree, this) ) {
1019
- // If function returns 'true', we assume that the loading is done:
1020
- this.setLazyNodeStatus(DTNodeStatus_Ok);
1021
- // Otherwise (i.e. if the loading was started as an asynchronous process)
1022
- // the onLazyRead(dtnode) handler is expected to call dtnode.setLazyNodeStatus(DTNodeStatus_Ok/_Error) when done.
1023
- this.tree.logDebug("_loadContent: succeeded - %o", this);
1024
- }
1025
- } catch(e) {
1026
- this.tree.logWarning("_loadContent: failed - %o", e);
1027
- this.setLazyNodeStatus(DTNodeStatus_Error, {tooltip: ""+e});
1028
- }
1029
- },
1030
-
1031
- _expand: function(bExpand, forceSync) {
1032
- if( this.bExpanded === bExpand ) {
1033
- this.tree.logDebug("dtnode._expand(%o) IGNORED - %o", bExpand, this);
1034
- return;
1035
- }
1036
- this.tree.logDebug("dtnode._expand(%o) - %o", bExpand, this);
1037
- var opts = this.tree.options;
1038
- if( !bExpand && this.getLevel() < opts.minExpandLevel ) {
1039
- this.tree.logDebug("dtnode._expand(%o) prevented collapse - %o", bExpand, this);
1040
- return;
1041
- }
1042
- if ( opts.onQueryExpand && opts.onQueryExpand.call(this.tree, bExpand, this) === false ){
1043
- return; // Callback returned false
1044
- }
1045
- this.bExpanded = bExpand;
1046
-
1047
- // Persist expand state
1048
- if( opts.persist ) {
1049
- if( bExpand ){
1050
- this.tree.persistence.addExpand(this.data.key);
1051
- }else{
1052
- this.tree.persistence.clearExpand(this.data.key);
1053
- }
1054
- }
1055
- // Do not apply animations in init phase, or before lazy-loading
1056
- var allowEffects = !(this.data.isLazy && this.childList === null)
1057
- && !this._isLoading
1058
- && !forceSync;
1059
- this.render(allowEffects);
1060
-
1061
- // Auto-collapse mode: collapse all siblings
1062
- if( this.bExpanded && this.parent && opts.autoCollapse ) {
1063
- var parents = this._parentList(false, true);
1064
- for(var i=0, l=parents.length; i<l; i++){
1065
- parents[i].collapseSiblings();
1066
- }
1067
- }
1068
- // If the currently active node is now hidden, deactivate it
1069
- if( opts.activeVisible && this.tree.activeNode && ! this.tree.activeNode.isVisible() ) {
1070
- this.tree.activeNode.deactivate();
1071
- }
1072
- // Expanding a lazy node: set 'loading...' and call callback
1073
- if( bExpand && this.data.isLazy && this.childList === null && !this._isLoading ) {
1074
- this._loadContent();
1075
- return;
1076
- }
1077
- if ( opts.onExpand ){
1078
- opts.onExpand.call(this.tree, bExpand, this);
1079
- }
1080
- },
1081
-
1082
- isExpanded: function() {
1083
- return this.bExpanded;
1084
- },
1085
-
1086
- expand: function(flag) {
1087
- flag = (flag !== false);
1088
- if( !this.childList && !this.data.isLazy && flag ){
1089
- return; // Prevent expanding empty nodes
1090
- } else if( this.parent === null && !flag ){
1091
- return; // Prevent collapsing the root
1092
- }
1093
- this._expand(flag);
1094
- },
1095
-
1096
- scheduleAction: function(mode, ms) {
1097
- /** Schedule activity for delayed execution (cancel any pending request).
1098
- * scheduleAction('cancel') will cancel the request.
1099
- */
1100
- if( this.tree.timer ) {
1101
- clearTimeout(this.tree.timer);
1102
- this.tree.logDebug("clearTimeout(%o)", this.tree.timer);
1103
- }
1104
- var self = this; // required for closures
1105
- switch (mode) {
1106
- case "cancel":
1107
- // Simply made sure that timer was cleared
1108
- break;
1109
- case "expand":
1110
- this.tree.timer = setTimeout(function(){
1111
- self.tree.logDebug("setTimeout: trigger expand");
1112
- self.expand(true);
1113
- }, ms);
1114
- break;
1115
- case "activate":
1116
- this.tree.timer = setTimeout(function(){
1117
- self.tree.logDebug("setTimeout: trigger activate");
1118
- self.activate();
1119
- }, ms);
1120
- break;
1121
- default:
1122
- throw "Invalid mode " + mode;
1123
- }
1124
- this.tree.logDebug("setTimeout(%s, %s): %s", mode, ms, this.tree.timer);
1125
- },
1126
-
1127
- toggleExpand: function() {
1128
- this.expand(!this.bExpanded);
1129
- },
1130
-
1131
- collapseSiblings: function() {
1132
- if( this.parent === null ){
1133
- return;
1134
- }
1135
- var ac = this.parent.childList;
1136
- for (var i=0, l=ac.length; i<l; i++) {
1137
- if ( ac[i] !== this && ac[i].bExpanded ){
1138
- ac[i]._expand(false);
1139
- }
1140
- }
1141
- },
1142
-
1143
- _onClick: function(event) {
1144
- // this.tree.logDebug("dtnode.onClick(" + event.type + "): dtnode:" + this + ", button:" + event.button + ", which: " + event.which);
1145
- var targetType = this.getEventTargetType(event);
1146
- if( targetType === "expander" ) {
1147
- // Clicking the expander icon always expands/collapses
1148
- this.toggleExpand();
1149
- this.focus(); // issue 95
1150
- } else if( targetType === "checkbox" ) {
1151
- // Clicking the checkbox always (de)selects
1152
- this.toggleSelect();
1153
- this.focus(); // issue 95
1154
- } else {
1155
- this._userActivate();
1156
- var aTag = this.span.getElementsByTagName("a");
1157
- if(aTag[0]){
1158
- // issue 154
1159
- // TODO: check if still required on IE 9:
1160
- // Chrome and Safari don't focus the a-tag on click,
1161
- // but calling focus() seem to have problems on IE:
1162
- // http://code.google.com/p/dynatree/issues/detail?id=154
1163
- if(!$.browser.msie){
1164
- aTag[0].focus();
1165
- }
1166
- }else{
1167
- // 'noLink' option was set
1168
- return true;
1169
- }
1170
- }
1171
- // Make sure that clicks stop, otherwise <a href='#'> jumps to the top
1172
- event.preventDefault();
1173
- },
1174
-
1175
- _onDblClick: function(event) {
1176
- // this.tree.logDebug("dtnode.onDblClick(" + event.type + "): dtnode:" + this + ", button:" + event.button + ", which: " + event.which);
1177
- },
1178
-
1179
- _onKeydown: function(event) {
1180
- // this.tree.logDebug("dtnode.onKeydown(" + event.type + "): dtnode:" + this + ", charCode:" + event.charCode + ", keyCode: " + event.keyCode + ", which: " + event.which);
1181
- var handled = true,
1182
- sib;
1183
- // alert("keyDown" + event.which);
1184
-
1185
- switch( event.which ) {
1186
- // charCodes:
1187
- // case 43: // '+'
1188
- case 107: // '+'
1189
- case 187: // '+' @ Chrome, Safari
1190
- if( !this.bExpanded ){ this.toggleExpand(); }
1191
- break;
1192
- // case 45: // '-'
1193
- case 109: // '-'
1194
- case 189: // '+' @ Chrome, Safari
1195
- if( this.bExpanded ){ this.toggleExpand(); }
1196
- break;
1197
- //~ case 42: // '*'
1198
- //~ break;
1199
- //~ case 47: // '/'
1200
- //~ break;
1201
- // case 13: // <enter>
1202
- // <enter> on a focused <a> tag seems to generate a click-event.
1203
- // this._userActivate();
1204
- // break;
1205
- case 32: // <space>
1206
- this._userActivate();
1207
- break;
1208
- case 8: // <backspace>
1209
- if( this.parent ){
1210
- this.parent.focus();
1211
- }
1212
- break;
1213
- case 37: // <left>
1214
- if( this.bExpanded ) {
1215
- this.toggleExpand();
1216
- this.focus();
1217
- // } else if( this.parent && (this.tree.options.rootVisible || this.parent.parent) ) {
1218
- } else if( this.parent && this.parent.parent ) {
1219
- this.parent.focus();
1220
- }
1221
- break;
1222
- case 39: // <right>
1223
- if( !this.bExpanded && (this.childList || this.data.isLazy) ) {
1224
- this.toggleExpand();
1225
- this.focus();
1226
- } else if( this.childList ) {
1227
- this.childList[0].focus();
1228
- }
1229
- break;
1230
- case 38: // <up>
1231
- sib = this.getPrevSibling();
1232
- while( sib && sib.bExpanded && sib.childList ){
1233
- sib = sib.childList[sib.childList.length-1];
1234
- }
1235
- // if( !sib && this.parent && (this.tree.options.rootVisible || this.parent.parent) )
1236
- if( !sib && this.parent && this.parent.parent ){
1237
- sib = this.parent;
1238
- }
1239
- if( sib ){
1240
- sib.focus();
1241
- }
1242
- break;
1243
- case 40: // <down>
1244
- if( this.bExpanded && this.childList ) {
1245
- sib = this.childList[0];
1246
- } else {
1247
- var parents = this._parentList(false, true);
1248
- for(var i=parents.length-1; i>=0; i--) {
1249
- sib = parents[i].getNextSibling();
1250
- if( sib ){ break; }
1251
- }
1252
- }
1253
- if( sib ){
1254
- sib.focus();
1255
- }
1256
- break;
1257
- default:
1258
- handled = false;
1259
- }
1260
- // Return false, if handled, to prevent default processing
1261
- // return !handled;
1262
- if(handled){
1263
- event.preventDefault();
1264
- }
1265
- },
1266
-
1267
- _onKeypress: function(event) {
1268
- // onKeypress is only hooked to allow user callbacks.
1269
- // We don't process it, because IE and Safari don't fire keypress for cursor keys.
1270
- // this.tree.logDebug("dtnode.onKeypress(" + event.type + "): dtnode:" + this + ", charCode:" + event.charCode + ", keyCode: " + event.keyCode + ", which: " + event.which);
1271
- },
1272
-
1273
- _onFocus: function(event) {
1274
- // Handles blur and focus events.
1275
- // this.tree.logDebug("dtnode.onFocus(%o): %o", event, this);
1276
- var opts = this.tree.options;
1277
- if ( event.type == "blur" || event.type == "focusout" ) {
1278
- if ( opts.onBlur ){
1279
- opts.onBlur.call(this.tree, this);
1280
- }
1281
- if( this.tree.tnFocused ){
1282
- $(this.tree.tnFocused.span).removeClass(opts.classNames.focused);
1283
- }
1284
- this.tree.tnFocused = null;
1285
- if( opts.persist ){
1286
- $.cookie(opts.cookieId+"-focus", "", opts.cookie);
1287
- }
1288
- } else if ( event.type=="focus" || event.type=="focusin") {
1289
- // Fix: sometimes the blur event is not generated
1290
- if( this.tree.tnFocused && this.tree.tnFocused !== this ) {
1291
- this.tree.logDebug("dtnode.onFocus: out of sync: curFocus: %o", this.tree.tnFocused);
1292
- $(this.tree.tnFocused.span).removeClass(opts.classNames.focused);
1293
- }
1294
- this.tree.tnFocused = this;
1295
- if ( opts.onFocus ){
1296
- opts.onFocus.call(this.tree, this);
1297
- }
1298
- $(this.tree.tnFocused.span).addClass(opts.classNames.focused);
1299
- if( opts.persist ){
1300
- $.cookie(opts.cookieId+"-focus", this.data.key, opts.cookie);
1301
- }
1302
- }
1303
- // TODO: return anything?
1304
- // return false;
1305
- },
1306
-
1307
- visit: function(fn, includeSelf) {
1308
- // Call fn(node) for all child nodes. Stop iteration, if fn() returns false.
1309
- var res = true;
1310
- if( includeSelf === true ) {
1311
- res = fn(this);
1312
- if( res === false || res == "skip" ){
1313
- return res;
1314
- }
1315
- }
1316
- if(this.childList){
1317
- for(var i=0, l=this.childList.length; i<l; i++){
1318
- res = this.childList[i].visit(fn, true);
1319
- if( res === false ){
1320
- break;
1321
- }
1322
- }
1323
- }
1324
- return res;
1325
- },
1326
-
1327
- visitParents: function(fn, includeSelf) {
1328
- // Visit parent nodes (bottom up)
1329
- if(includeSelf && fn(this) === false){
1330
- return false;
1331
- }
1332
- var p = this.parent;
1333
- while( p ) {
1334
- if(fn(p) === false){
1335
- return false;
1336
- }
1337
- p = p.parent;
1338
- }
1339
- return true;
1340
- },
1341
-
1342
- remove: function() {
1343
- // Remove this node
1344
- // this.tree.logDebug ("%s.remove()", this);
1345
- if ( this === this.tree.root ){
1346
- throw "Cannot remove system root";
1347
- }
1348
- return this.parent.removeChild(this);
1349
- },
1350
-
1351
- removeChild: function(tn) {
1352
- // Remove tn from list of direct children.
1353
- var ac = this.childList;
1354
- if( ac.length == 1 ) {
1355
- if( tn !== ac[0] ){
1356
- throw "removeChild: invalid child";
1357
- }
1358
- return this.removeChildren();
1359
- }
1360
- if( tn === this.tree.activeNode ){
1361
- tn.deactivate();
1362
- }
1363
- if( this.tree.options.persist ) {
1364
- if( tn.bSelected ){
1365
- this.tree.persistence.clearSelect(tn.data.key);
1366
- }
1367
- if ( tn.bExpanded ){
1368
- this.tree.persistence.clearExpand(tn.data.key);
1369
- }
1370
- }
1371
- tn.removeChildren(true);
1372
- // this.div.removeChild(tn.div);
1373
- this.ul.removeChild(tn.li);
1374
- for(var i=0, l=ac.length; i<l; i++) {
1375
- if( ac[i] === tn ) {
1376
- this.childList.splice(i, 1);
1377
- // delete tn; // JSLint complained
1378
- break;
1379
- }
1380
- }
1381
- },
1382
-
1383
- removeChildren: function(isRecursiveCall, retainPersistence) {
1384
- // Remove all child nodes (more efficiently than recursive remove())
1385
- this.tree.logDebug("%s.removeChildren(%o)", this, isRecursiveCall);
1386
- var tree = this.tree;
1387
- var ac = this.childList;
1388
- if( ac ) {
1389
- for(var i=0, l=ac.length; i<l; i++) {
1390
- var tn = ac[i];
1391
- if ( tn === tree.activeNode && !retainPersistence ){
1392
- tn.deactivate();
1393
- }
1394
- if( this.tree.options.persist && !retainPersistence ) {
1395
- if( tn.bSelected ){
1396
- this.tree.persistence.clearSelect(tn.data.key);
1397
- }
1398
- if ( tn.bExpanded ){
1399
- this.tree.persistence.clearExpand(tn.data.key);
1400
- }
1401
- }
1402
- tn.removeChildren(true, retainPersistence);
1403
- if(this.ul){
1404
- // this.ul.removeChild(tn.li);
1405
- $("li", $(this.ul)).remove(); // issue 231
1406
- }
1407
- // delete tn; JSLint complained
1408
- }
1409
- // Set to 'null' which is interpreted as 'not yet loaded' for lazy
1410
- // nodes
1411
- this.childList = null;
1412
- }
1413
- if( ! isRecursiveCall ) {
1414
- // this._expand(false);
1415
- // this.isRead = false;
1416
- this._isLoading = false;
1417
- this.render();
1418
- }
1419
- },
1420
-
1421
- setTitle: function(title) {
1422
- this.fromDict({title: title});
1423
- },
1424
-
1425
- reload: function(force) {
1426
- throw "Use reloadChildren() instead";
1427
- },
1428
-
1429
- reloadChildren: function(callback) {
1430
- // Reload lazy content (expansion state is maintained).
1431
- if( this.parent === null ){
1432
- throw "Use tree.reload() instead";
1433
- }else if( ! this.data.isLazy ){
1434
- throw "node.reloadChildren() requires lazy nodes.";
1435
- }
1436
- // appendAjax triggers 'nodeLoaded' event.
1437
- // We listen to this, if a callback was passed to reloadChildren
1438
- if(callback){
1439
- var self = this;
1440
- var eventType = "nodeLoaded.dynatree." + this.tree.$tree.attr("id")
1441
- + "." + this.data.key;
1442
- this.tree.$tree.bind(eventType, function(e, node, isOk){
1443
- self.tree.$tree.unbind(eventType);
1444
- self.tree.logDebug("loaded %o, %o, %o", e, node, isOk);
1445
- if(node !== self){
1446
- throw "got invalid load event";
1447
- }
1448
- callback.call(self.tree, node, isOk);
1449
- });
1450
- }
1451
- // The expansion state is maintained
1452
- this.removeChildren();
1453
- this._loadContent();
1454
- // if( this.bExpanded ) {
1455
- // // Remove children first, to prevent effects being applied
1456
- // this.removeChildren();
1457
- // // then force re-expand to trigger lazy loading
1458
- //// this.expand(false);
1459
- //// this.expand(true);
1460
- // this._loadContent();
1461
- // } else {
1462
- // this.removeChildren();
1463
- // this._loadContent();
1464
- // }
1465
- },
1466
-
1467
- /**
1468
- * Make sure the node with a given key path is available in the tree.
1469
- */
1470
- _loadKeyPath: function(keyPath, callback) {
1471
- var tree = this.tree;
1472
- tree.logDebug("%s._loadKeyPath(%s)", this, keyPath);
1473
- if(keyPath === ""){
1474
- throw "Key path must not be empty";
1475
- }
1476
- var segList = keyPath.split(tree.options.keyPathSeparator);
1477
- if(segList[0] === ""){
1478
- throw "Key path must be relative (don't start with '/')";
1479
- }
1480
- var seg = segList.shift();
1481
-
1482
- for(var i=0, l=this.childList.length; i < l; i++){
1483
- var child = this.childList[i];
1484
- if( child.data.key === seg ){
1485
- if(segList.length === 0) {
1486
- // Found the end node
1487
- callback.call(tree, child, "ok");
1488
-
1489
- }else if(child.data.isLazy && (child.childList === null || child.childList === undefined)){
1490
- tree.logDebug("%s._loadKeyPath(%s) -> reloading %s...", this, keyPath, child);
1491
- var self = this;
1492
- child.reloadChildren(function(node, isOk){
1493
- // After loading, look for direct child with that key
1494
- if(isOk){
1495
- tree.logDebug("%s._loadKeyPath(%s) -> reloaded %s.", node, keyPath, node);
1496
- callback.call(tree, child, "loaded");
1497
- node._loadKeyPath(segList.join(tree.options.keyPathSeparator), callback);
1498
- }else{
1499
- tree.logWarning("%s._loadKeyPath(%s) -> reloadChildren() failed.", self, keyPath);
1500
- callback.call(tree, child, "error");
1501
- }
1502
- }); // Note: this line gives a JSLint warning (Don't make functions within a loop)
1503
- // we can ignore it, since it will only be exectuted once, the the loop is ended
1504
- // See also http://stackoverflow.com/questions/3037598/how-to-get-around-the-jslint-error-dont-make-functions-within-a-loop
1505
- } else {
1506
- callback.call(tree, child, "loaded");
1507
- // Look for direct child with that key
1508
- child._loadKeyPath(segList.join(tree.options.keyPathSeparator), callback);
1509
- }
1510
- return;
1511
- }
1512
- }
1513
- // Could not find key
1514
- tree.logWarning("Node not found: " + seg);
1515
- return;
1516
- },
1517
-
1518
- resetLazy: function() {
1519
- // Discard lazy content.
1520
- if( this.parent === null ){
1521
- throw "Use tree.reload() instead";
1522
- }else if( ! this.data.isLazy ){
1523
- throw "node.resetLazy() requires lazy nodes.";
1524
- }
1525
- this.expand(false);
1526
- this.removeChildren();
1527
- },
1528
-
1529
- _addChildNode: function(dtnode, beforeNode) {
1530
- /**
1531
- * Internal function to add one single DynatreeNode as a child.
1532
- *
1533
- */
1534
- var tree = this.tree,
1535
- opts = tree.options,
1536
- pers = tree.persistence;
1537
-
1538
- // tree.logDebug("%s._addChildNode(%o)", this, dtnode);
1539
-
1540
- // --- Update and fix dtnode attributes if necessary
1541
- dtnode.parent = this;
1542
- // if( beforeNode && (beforeNode.parent !== this || beforeNode === dtnode ) )
1543
- // throw "<beforeNode> must be another child of <this>";
1544
-
1545
- // --- Add dtnode as a child
1546
- if ( this.childList === null ) {
1547
- this.childList = [];
1548
- } else if( ! beforeNode ) {
1549
- // Fix 'lastsib'
1550
- if(this.childList.length > 0) {
1551
- $(this.childList[this.childList.length-1].span).removeClass(opts.classNames.lastsib);
1552
- }
1553
- }
1554
- if( beforeNode ) {
1555
- var iBefore = $.inArray(beforeNode, this.childList);
1556
- if( iBefore < 0 ){
1557
- throw "<beforeNode> must be a child of <this>";
1558
- }
1559
- this.childList.splice(iBefore, 0, dtnode);
1560
- } else {
1561
- // Append node
1562
- this.childList.push(dtnode);
1563
- }
1564
-
1565
- // --- Handle persistence
1566
- // Initial status is read from cookies, if persistence is active and
1567
- // cookies are already present.
1568
- // Otherwise the status is read from the data attributes and then persisted.
1569
- var isInitializing = tree.isInitializing();
1570
- if( opts.persist && pers.cookiesFound && isInitializing ) {
1571
- // Init status from cookies
1572
- // tree.logDebug("init from cookie, pa=%o, dk=%o", pers.activeKey, dtnode.data.key);
1573
- if( pers.activeKey === dtnode.data.key ){
1574
- tree.activeNode = dtnode;
1575
- }
1576
- if( pers.focusedKey === dtnode.data.key ){
1577
- tree.focusNode = dtnode;
1578
- }
1579
- dtnode.bExpanded = ($.inArray(dtnode.data.key, pers.expandedKeyList) >= 0);
1580
- dtnode.bSelected = ($.inArray(dtnode.data.key, pers.selectedKeyList) >= 0);
1581
- // tree.logDebug(" key=%o, bSelected=%o", dtnode.data.key, dtnode.bSelected);
1582
- } else {
1583
- // Init status from data (Note: we write the cookies after the init phase)
1584
- // tree.logDebug("init from data");
1585
- if( dtnode.data.activate ) {
1586
- tree.activeNode = dtnode;
1587
- if( opts.persist ){
1588
- pers.activeKey = dtnode.data.key;
1589
- }
1590
- }
1591
- if( dtnode.data.focus ) {
1592
- tree.focusNode = dtnode;
1593
- if( opts.persist ){
1594
- pers.focusedKey = dtnode.data.key;
1595
- }
1596
- }
1597
- dtnode.bExpanded = ( dtnode.data.expand === true ); // Collapsed by default
1598
- if( dtnode.bExpanded && opts.persist ){
1599
- pers.addExpand(dtnode.data.key);
1600
- }
1601
- dtnode.bSelected = ( dtnode.data.select === true ); // Deselected by default
1602
- /*
1603
- Doesn't work, cause pers.selectedKeyList may be null
1604
- if( dtnode.bSelected && opts.selectMode==1
1605
- && pers.selectedKeyList && pers.selectedKeyList.length>0 ) {
1606
- tree.logWarning("Ignored multi-selection in single-mode for %o", dtnode);
1607
- dtnode.bSelected = false; // Fixing bad input data (multi selection for mode:1)
1608
- }
1609
- */
1610
- if( dtnode.bSelected && opts.persist ){
1611
- pers.addSelect(dtnode.data.key);
1612
- }
1613
- }
1614
-
1615
- // Always expand, if it's below minExpandLevel
1616
- // tree.logDebug ("%s._addChildNode(%o), l=%o", this, dtnode, dtnode.getLevel());
1617
- if ( opts.minExpandLevel >= dtnode.getLevel() ) {
1618
- // tree.logDebug ("Force expand for %o", dtnode);
1619
- this.bExpanded = true;
1620
- }
1621
-
1622
- // In multi-hier mode, update the parents selection state
1623
- // issue #82: only if not initializing, because the children may not exist yet
1624
- // if( !dtnode.data.isStatusNode && opts.selectMode==3 && !isInitializing )
1625
- // dtnode._fixSelectionState();
1626
-
1627
- // In multi-hier mode, update the parents selection state
1628
- if( dtnode.bSelected && opts.selectMode==3 ) {
1629
- var p = this;
1630
- while( p ) {
1631
- if( !p.hasSubSel ){
1632
- p._setSubSel(true);
1633
- }
1634
- p = p.parent;
1635
- }
1636
- }
1637
- // render this node and the new child
1638
- if ( tree.bEnableUpdate ){
1639
- this.render();
1640
- }
1641
- return dtnode;
1642
- },
1643
-
1644
- addChild: function(obj, beforeNode) {
1645
- /**
1646
- * Add a node object as child.
1647
- *
1648
- * This should be the only place, where a DynaTreeNode is constructed!
1649
- * (Except for the root node creation in the tree constructor)
1650
- *
1651
- * @param obj A JS object (may be recursive) or an array of those.
1652
- * @param {DynaTreeNode} beforeNode (optional) sibling node.
1653
- *
1654
- * Data format: array of node objects, with optional 'children' attributes.
1655
- * [
1656
- * { title: "t1", isFolder: true, ... }
1657
- * { title: "t2", isFolder: true, ...,
1658
- * children: [
1659
- * {title: "t2.1", ..},
1660
- * {..}
1661
- * ]
1662
- * }
1663
- * ]
1664
- * A simple object is also accepted instead of an array.
1665
- *
1666
- */
1667
- // this.tree.logDebug("%s.addChild(%o, %o)", this, obj, beforeNode);
1668
- if(typeof(obj) == "string"){
1669
- throw "Invalid data type for " + obj;
1670
- }else if( !obj || obj.length === 0 ){ // Passed null or undefined or empty array
1671
- return;
1672
- }else if( obj instanceof DynaTreeNode ){
1673
- return this._addChildNode(obj, beforeNode);
1674
- }
1675
-
1676
- if( !obj.length ){ // Passed a single data object
1677
- obj = [ obj ];
1678
- }
1679
- var prevFlag = this.tree.enableUpdate(false);
1680
-
1681
- var tnFirst = null;
1682
- for (var i=0, l=obj.length; i<l; i++) {
1683
- var data = obj[i];
1684
- var dtnode = this._addChildNode(new DynaTreeNode(this, this.tree, data), beforeNode);
1685
- if( !tnFirst ){
1686
- tnFirst = dtnode;
1687
- }
1688
- // Add child nodes recursively
1689
- if( data.children ){
1690
- dtnode.addChild(data.children, null);
1691
- }
1692
- }
1693
- this.tree.enableUpdate(prevFlag);
1694
- return tnFirst;
1695
- },
1696
-
1697
- append: function(obj) {
1698
- this.tree.logWarning("node.append() is deprecated (use node.addChild() instead).");
1699
- return this.addChild(obj, null);
1700
- },
1701
-
1702
- appendAjax: function(ajaxOptions) {
1703
- var self = this;
1704
- this.removeChildren(false, true);
1705
- this.setLazyNodeStatus(DTNodeStatus_Loading);
1706
- // Debug feature: force a delay, to simulate slow loading...
1707
- if(ajaxOptions.debugLazyDelay){
1708
- var ms = ajaxOptions.debugLazyDelay;
1709
- ajaxOptions.debugLazyDelay = 0;
1710
- this.tree.logInfo("appendAjax: waiting for debugLazyDelay " + ms);
1711
- setTimeout(function(){self.appendAjax(ajaxOptions);}, ms);
1712
- return;
1713
- }
1714
- // Ajax option inheritance: $.ajaxSetup < $.ui.dynatree.prototype.options.ajaxDefaults < tree.options.ajaxDefaults < ajaxOptions
1715
- var orgSuccess = ajaxOptions.success,
1716
- orgError = ajaxOptions.error,
1717
- eventType = "nodeLoaded.dynatree." + this.tree.$tree.attr("id") + "." + this.data.key;
1718
- var options = $.extend({}, this.tree.options.ajaxDefaults, ajaxOptions, {
1719
- success: function(data, textStatus, jqXHR){
1720
- // <this> is the request options
1721
- // self.tree.logDebug("appendAjax().success");
1722
- var prevPhase = self.tree.phase;
1723
- self.tree.phase = "init";
1724
- // postProcess is similar to the standard dataFilter hook,
1725
- // but it is also called for JSONP
1726
- if( options.postProcess ){
1727
- data = options.postProcess.call(this, data, this.dataType);
1728
- }
1729
- // Process ASPX WebMethod JSON object inside "d" property
1730
- // http://code.google.com/p/dynatree/issues/detail?id=202
1731
- else if (data && data.hasOwnProperty("d")) {
1732
- data = (typeof data.d) == "string" ? $.parseJSON(data.d) : response.d;
1733
- }
1734
- if(!$.isArray(data) || data.length !== 0){
1735
- self.addChild(data, null);
1736
- }
1737
- self.tree.phase = "postInit";
1738
- if( orgSuccess ){
1739
- orgSuccess.call(options, self, data, textStatus);
1740
- }
1741
- self.tree.logDebug("trigger " + eventType);
1742
- self.tree.$tree.trigger(eventType, [self, true]);
1743
- self.tree.phase = prevPhase;
1744
- // This should be the last command, so node._isLoading is true
1745
- // while the callbacks run
1746
- self.setLazyNodeStatus(DTNodeStatus_Ok);
1747
- if($.isArray(data) && data.length === 0){
1748
- // Set to [] which is interpreted as 'no children' for lazy
1749
- // nodes
1750
- self.childList = [];
1751
- self.render();
1752
- }
1753
- },
1754
- error: function(jqXHR, textStatus, errorThrown){
1755
- // <this> is the request options
1756
- self.tree.logWarning("appendAjax failed:", textStatus, ":\n", jqXHR, "\n", errorThrown);
1757
- if( orgError ){
1758
- orgError.call(options, self, jqXHR, textStatus, errorThrown);
1759
- }
1760
- self.tree.$tree.trigger(eventType, [self, false]);
1761
- self.setLazyNodeStatus(DTNodeStatus_Error, {info: textStatus, tooltip: "" + errorThrown});
1762
- }
1763
- });
1764
- $.ajax(options);
1765
- },
1766
-
1767
- move: function(targetNode, mode) {
1768
- /**Move this node to targetNode.
1769
- * mode 'child': append this node as last child of targetNode.
1770
- * This is the default. To be compatble with the D'n'd
1771
- * hitMode, we also accept 'over'.
1772
- * mode 'before': add this node as sibling before targetNode.
1773
- * mode 'after': add this node as sibling after targetNode.
1774
- */
1775
- var pos;
1776
- if(this === targetNode){
1777
- return;
1778
- }
1779
- if( !this.parent ){
1780
- throw "Cannot move system root";
1781
- }
1782
- if(mode === undefined || mode == "over"){
1783
- mode = "child";
1784
- }
1785
- var prevParent = this.parent;
1786
- var targetParent = (mode === "child") ? targetNode : targetNode.parent;
1787
- if( targetParent.isDescendantOf(this) ){
1788
- throw "Cannot move a node to it's own descendant";
1789
- }
1790
- // Unlink this node from current parent
1791
- if( this.parent.childList.length == 1 ) {
1792
- this.parent.childList = null;
1793
- this.parent.bExpanded = false;
1794
- } else {
1795
- pos = $.inArray(this, this.parent.childList);
1796
- if( pos < 0 ){
1797
- throw "Internal error";
1798
- }
1799
- this.parent.childList.splice(pos, 1);
1800
- }
1801
- // Remove from source DOM parent
1802
- this.parent.ul.removeChild(this.li);
1803
-
1804
- // Insert this node to target parent's child list
1805
- this.parent = targetParent;
1806
- if( targetParent.hasChildren() ) {
1807
- switch(mode) {
1808
- case "child":
1809
- // Append to existing target children
1810
- targetParent.childList.push(this);
1811
- break;
1812
- case "before":
1813
- // Insert this node before target node
1814
- pos = $.inArray(targetNode, targetParent.childList);
1815
- if( pos < 0 ){
1816
- throw "Internal error";
1817
- }
1818
- targetParent.childList.splice(pos, 0, this);
1819
- break;
1820
- case "after":
1821
- // Insert this node after target node
1822
- pos = $.inArray(targetNode, targetParent.childList);
1823
- if( pos < 0 ){
1824
- throw "Internal error";
1825
- }
1826
- targetParent.childList.splice(pos+1, 0, this);
1827
- break;
1828
- default:
1829
- throw "Invalid mode " + mode;
1830
- }
1831
- } else {
1832
- targetParent.childList = [ this ];
1833
- }
1834
- // Parent has no <ul> tag yet:
1835
- if( !targetParent.ul ) {
1836
- // This is the parent's first child: create UL tag
1837
- // (Hidden, because it will be
1838
- targetParent.ul = document.createElement("ul");
1839
- targetParent.ul.style.display = "none";
1840
- targetParent.li.appendChild(targetParent.ul);
1841
- }
1842
- // Add to target DOM parent
1843
- targetParent.ul.appendChild(this.li);
1844
-
1845
- if( this.tree !== targetNode.tree ) {
1846
- // Fix node.tree for all source nodes
1847
- this.visit(function(node){
1848
- node.tree = targetNode.tree;
1849
- }, null, true);
1850
- throw "Not yet implemented.";
1851
- }
1852
- // TODO: fix selection state
1853
- // TODO: fix active state
1854
- if( !prevParent.isDescendantOf(targetParent)) {
1855
- prevParent.render();
1856
- }
1857
- if( !targetParent.isDescendantOf(prevParent) ) {
1858
- targetParent.render();
1859
- }
1860
- // this.tree.redraw();
1861
- /*
1862
- var tree = this.tree;
1863
- var opts = tree.options;
1864
- var pers = tree.persistence;
1865
-
1866
-
1867
- // Always expand, if it's below minExpandLevel
1868
- // tree.logDebug ("%s._addChildNode(%o), l=%o", this, dtnode, dtnode.getLevel());
1869
- if ( opts.minExpandLevel >= dtnode.getLevel() ) {
1870
- // tree.logDebug ("Force expand for %o", dtnode);
1871
- this.bExpanded = true;
1872
- }
1873
-
1874
- // In multi-hier mode, update the parents selection state
1875
- // issue #82: only if not initializing, because the children may not exist yet
1876
- // if( !dtnode.data.isStatusNode && opts.selectMode==3 && !isInitializing )
1877
- // dtnode._fixSelectionState();
1878
-
1879
- // In multi-hier mode, update the parents selection state
1880
- if( dtnode.bSelected && opts.selectMode==3 ) {
1881
- var p = this;
1882
- while( p ) {
1883
- if( !p.hasSubSel )
1884
- p._setSubSel(true);
1885
- p = p.parent;
1886
- }
1887
- }
1888
- // render this node and the new child
1889
- if ( tree.bEnableUpdate )
1890
- this.render();
1891
-
1892
- return dtnode;
1893
-
1894
- */
1895
- },
1896
-
1897
- // --- end of class
1898
- lastentry: undefined
1899
- };
1900
-
1901
- /*************************************************************************
1902
- * class DynaTreeStatus
1903
- */
1904
-
1905
- var DynaTreeStatus = Class.create();
1906
-
1907
-
1908
- DynaTreeStatus._getTreePersistData = function(cookieId, cookieOpts) {
1909
- // Static member: Return persistence information from cookies
1910
- var ts = new DynaTreeStatus(cookieId, cookieOpts);
1911
- ts.read();
1912
- return ts.toDict();
1913
- };
1914
- // Make available in global scope
1915
- getDynaTreePersistData = DynaTreeStatus._getTreePersistData; // TODO: deprecated
1916
-
1917
-
1918
- DynaTreeStatus.prototype = {
1919
- // Constructor
1920
- initialize: function(cookieId, cookieOpts) {
1921
- // this._log("DynaTreeStatus: initialize");
1922
- if( cookieId === undefined ){
1923
- cookieId = $.ui.dynatree.prototype.options.cookieId;
1924
- }
1925
- cookieOpts = $.extend({}, $.ui.dynatree.prototype.options.cookie, cookieOpts);
1926
-
1927
- this.cookieId = cookieId;
1928
- this.cookieOpts = cookieOpts;
1929
- this.cookiesFound = undefined;
1930
- this.activeKey = null;
1931
- this.focusedKey = null;
1932
- this.expandedKeyList = null;
1933
- this.selectedKeyList = null;
1934
- },
1935
- // member functions
1936
- _log: function(msg) {
1937
- // this.logDebug("_changeNodeList(%o): nodeList:%o, idx:%o", mode, nodeList, idx);
1938
- Array.prototype.unshift.apply(arguments, ["debug"]);
1939
- _log.apply(this, arguments);
1940
- },
1941
- read: function() {
1942
- // this._log("DynaTreeStatus: read");
1943
- // Read or init cookies.
1944
- this.cookiesFound = false;
1945
-
1946
- var cookie = $.cookie(this.cookieId + "-active");
1947
- this.activeKey = ( cookie === null ) ? "" : cookie;
1948
- if( cookie !== null ){
1949
- this.cookiesFound = true;
1950
- }
1951
- cookie = $.cookie(this.cookieId + "-focus");
1952
- this.focusedKey = ( cookie === null ) ? "" : cookie;
1953
- if( cookie !== null ){
1954
- this.cookiesFound = true;
1955
- }
1956
- cookie = $.cookie(this.cookieId + "-expand");
1957
- this.expandedKeyList = ( cookie === null ) ? [] : cookie.split(",");
1958
- if( cookie !== null ){
1959
- this.cookiesFound = true;
1960
- }
1961
- cookie = $.cookie(this.cookieId + "-select");
1962
- this.selectedKeyList = ( cookie === null ) ? [] : cookie.split(",");
1963
- if( cookie !== null ){
1964
- this.cookiesFound = true;
1965
- }
1966
- },
1967
- write: function() {
1968
- // this._log("DynaTreeStatus: write");
1969
- $.cookie(this.cookieId + "-active", ( this.activeKey === null ) ? "" : this.activeKey, this.cookieOpts);
1970
- $.cookie(this.cookieId + "-focus", ( this.focusedKey === null ) ? "" : this.focusedKey, this.cookieOpts);
1971
- $.cookie(this.cookieId + "-expand", ( this.expandedKeyList === null ) ? "" : this.expandedKeyList.join(","), this.cookieOpts);
1972
- $.cookie(this.cookieId + "-select", ( this.selectedKeyList === null ) ? "" : this.selectedKeyList.join(","), this.cookieOpts);
1973
- },
1974
- addExpand: function(key) {
1975
- // this._log("addExpand(%o)", key);
1976
- if( $.inArray(key, this.expandedKeyList) < 0 ) {
1977
- this.expandedKeyList.push(key);
1978
- $.cookie(this.cookieId + "-expand", this.expandedKeyList.join(","), this.cookieOpts);
1979
- }
1980
- },
1981
- clearExpand: function(key) {
1982
- // this._log("clearExpand(%o)", key);
1983
- var idx = $.inArray(key, this.expandedKeyList);
1984
- if( idx >= 0 ) {
1985
- this.expandedKeyList.splice(idx, 1);
1986
- $.cookie(this.cookieId + "-expand", this.expandedKeyList.join(","), this.cookieOpts);
1987
- }
1988
- },
1989
- addSelect: function(key) {
1990
- // this._log("addSelect(%o)", key);
1991
- if( $.inArray(key, this.selectedKeyList) < 0 ) {
1992
- this.selectedKeyList.push(key);
1993
- $.cookie(this.cookieId + "-select", this.selectedKeyList.join(","), this.cookieOpts);
1994
- }
1995
- },
1996
- clearSelect: function(key) {
1997
- // this._log("clearSelect(%o)", key);
1998
- var idx = $.inArray(key, this.selectedKeyList);
1999
- if( idx >= 0 ) {
2000
- this.selectedKeyList.splice(idx, 1);
2001
- $.cookie(this.cookieId + "-select", this.selectedKeyList.join(","), this.cookieOpts);
2002
- }
2003
- },
2004
- isReloading: function() {
2005
- return this.cookiesFound === true;
2006
- },
2007
- toDict: function() {
2008
- return {
2009
- cookiesFound: this.cookiesFound,
2010
- activeKey: this.activeKey,
2011
- focusedKey: this.activeKey,
2012
- expandedKeyList: this.expandedKeyList,
2013
- selectedKeyList: this.selectedKeyList
2014
- };
2015
- },
2016
- // --- end of class
2017
- lastentry: undefined
2018
- };
2019
-
2020
-
2021
- /*************************************************************************
2022
- * class DynaTree
2023
- */
2024
-
2025
- var DynaTree = Class.create();
2026
-
2027
- // --- Static members ----------------------------------------------------------
2028
-
2029
- DynaTree.version = "$Version: 1.2.1_rc3$";
2030
-
2031
- /*
2032
- DynaTree._initTree = function() {
2033
- };
2034
-
2035
- DynaTree._bind = function() {
2036
- };
2037
- */
2038
- //--- Class members ------------------------------------------------------------
2039
-
2040
- DynaTree.prototype = {
2041
- // Constructor
2042
- // initialize: function(divContainer, options) {
2043
- initialize: function($widget) {
2044
- // instance members
2045
- this.phase = "init";
2046
- this.$widget = $widget;
2047
- this.options = $widget.options;
2048
- this.$tree = $widget.element;
2049
- this.timer = null;
2050
- // find container element
2051
- this.divTree = this.$tree.get(0);
2052
-
2053
- // var parentPos = $(this.divTree).parent().offset();
2054
- // this.parentTop = parentPos.top;
2055
- // this.parentLeft = parentPos.left;
2056
-
2057
- _initDragAndDrop(this);
2058
- },
2059
-
2060
- // member functions
2061
-
2062
- _load: function(callback) {
2063
- var $widget = this.$widget;
2064
- var opts = this.options,
2065
- self = this;
2066
- this.bEnableUpdate = true;
2067
- this._nodeCount = 1;
2068
- this.activeNode = null;
2069
- this.focusNode = null;
2070
-
2071
- // Some deprecation warnings to help with migration
2072
- if( opts.rootVisible !== undefined ){
2073
- this.logWarning("Option 'rootVisible' is no longer supported.");
2074
- }
2075
- if( opts.minExpandLevel < 1 ) {
2076
- this.logWarning("Option 'minExpandLevel' must be >= 1.");
2077
- opts.minExpandLevel = 1;
2078
- }
2079
- // _log("warn", "jQuery.support.boxModel " + jQuery.support.boxModel);
2080
-
2081
- // If a 'options.classNames' dictionary was passed, still use defaults
2082
- // for undefined classes:
2083
- if( opts.classNames !== $.ui.dynatree.prototype.options.classNames ) {
2084
- opts.classNames = $.extend({}, $.ui.dynatree.prototype.options.classNames, opts.classNames);
2085
- }
2086
- if( opts.ajaxDefaults !== $.ui.dynatree.prototype.options.ajaxDefaults ) {
2087
- opts.ajaxDefaults = $.extend({}, $.ui.dynatree.prototype.options.ajaxDefaults, opts.ajaxDefaults);
2088
- }
2089
- if( opts.dnd !== $.ui.dynatree.prototype.options.dnd ) {
2090
- opts.dnd = $.extend({}, $.ui.dynatree.prototype.options.dnd, opts.dnd);
2091
- }
2092
- // Guess skin path, if not specified
2093
- if(!opts.imagePath) {
2094
- $("script").each( function () {
2095
- var _rexDtLibName = /.*dynatree[^\/]*\.js$/i;
2096
- if( this.src.search(_rexDtLibName) >= 0 ) {
2097
- if( this.src.indexOf("/")>=0 ){ // issue #47
2098
- opts.imagePath = this.src.slice(0, this.src.lastIndexOf("/")) + "/skin/";
2099
- }else{
2100
- opts.imagePath = "skin/";
2101
- }
2102
- self.logDebug("Guessing imagePath from '%s': '%s'", this.src, opts.imagePath);
2103
- return false; // first match
2104
- }
2105
- });
2106
- }
2107
-
2108
- this.persistence = new DynaTreeStatus(opts.cookieId, opts.cookie);
2109
- if( opts.persist ) {
2110
- if( !$.cookie ){
2111
- _log("warn", "Please include jquery.cookie.js to use persistence.");
2112
- }
2113
- this.persistence.read();
2114
- }
2115
- this.logDebug("DynaTree.persistence: %o", this.persistence.toDict());
2116
-
2117
- // Cached tag strings
2118
- this.cache = {
2119
- tagEmpty: "<span class='" + opts.classNames.empty + "'></span>",
2120
- tagVline: "<span class='" + opts.classNames.vline + "'></span>",
2121
- tagExpander: "<span class='" + opts.classNames.expander + "'></span>",
2122
- tagConnector: "<span class='" + opts.classNames.connector + "'></span>",
2123
- tagNodeIcon: "<span class='" + opts.classNames.nodeIcon + "'></span>",
2124
- tagCheckbox: "<span class='" + opts.classNames.checkbox + "'></span>",
2125
- lastentry: undefined
2126
- };
2127
-
2128
- // Clear container, in case it contained some 'waiting' or 'error' text
2129
- // for clients that don't support JS.
2130
- // We don't do this however, if we try to load from an embedded UL element.
2131
- if( opts.children || (opts.initAjax && opts.initAjax.url) || opts.initId ){
2132
- $(this.divTree).empty();
2133
- }
2134
- var $ulInitialize = this.$tree.find(">ul:first").hide();
2135
-
2136
- // Create the root element
2137
- this.tnRoot = new DynaTreeNode(null, this, {});
2138
- this.tnRoot.bExpanded = true;
2139
- this.tnRoot.render();
2140
- this.divTree.appendChild(this.tnRoot.ul);
2141
-
2142
- var root = this.tnRoot;
2143
- var isReloading = ( opts.persist && this.persistence.isReloading() );
2144
- var isLazy = false;
2145
- var prevFlag = this.enableUpdate(false);
2146
-
2147
- this.logDebug("Dynatree._load(): read tree structure...");
2148
-
2149
- // Init tree structure
2150
- if( opts.children ) {
2151
- // Read structure from node array
2152
- root.addChild(opts.children);
2153
-
2154
- } else if( opts.initAjax && opts.initAjax.url ) {
2155
- // Init tree from AJAX request
2156
- isLazy = true;
2157
- root.data.isLazy = true;
2158
- this._reloadAjax(callback);
2159
-
2160
- } else if( opts.initId ) {
2161
- // Init tree from another UL element
2162
- this._createFromTag(root, $("#"+opts.initId));
2163
-
2164
- } else {
2165
- // Init tree from the first UL element inside the container <div>
2166
- // var $ul = this.$tree.find(">ul:first").hide();
2167
- this._createFromTag(root, $ulInitialize);
2168
- $ulInitialize.remove();
2169
- }
2170
-
2171
- this._checkConsistency();
2172
- // Fix part-sel flags
2173
- if(!isLazy && opts.selectMode == 3){
2174
- root._updatePartSelectionState();
2175
- }
2176
- // Render html markup
2177
- this.logDebug("Dynatree._load(): render nodes...");
2178
- this.enableUpdate(prevFlag);
2179
-
2180
- // bind event handlers
2181
- this.logDebug("Dynatree._load(): bind events...");
2182
- this.$widget.bind();
2183
-
2184
- // --- Post-load processing
2185
- this.logDebug("Dynatree._load(): postInit...");
2186
- this.phase = "postInit";
2187
-
2188
- // In persist mode, make sure that cookies are written, even if they are empty
2189
- if( opts.persist ) {
2190
- this.persistence.write();
2191
- }
2192
- // Set focus, if possible (this will also fire an event and write a cookie)
2193
- if( this.focusNode && this.focusNode.isVisible() ) {
2194
- this.logDebug("Focus on init: %o", this.focusNode);
2195
- this.focusNode.focus();
2196
- }
2197
- if( !isLazy ) {
2198
- if( opts.onPostInit ) {
2199
- opts.onPostInit.call(this, isReloading, false);
2200
- }
2201
- if( callback ){
2202
- callback.call(this, "ok");
2203
- }
2204
- }
2205
- this.phase = "idle";
2206
- },
2207
-
2208
- _reloadAjax: function(callback) {
2209
- // Reload
2210
- var opts = this.options;
2211
- if( ! opts.initAjax || ! opts.initAjax.url ){
2212
- throw "tree.reload() requires 'initAjax' mode.";
2213
- }
2214
- var pers = this.persistence;
2215
- var ajaxOpts = $.extend({}, opts.initAjax);
2216
- // Append cookie info to the request
2217
- // this.logDebug("reloadAjax: key=%o, an.key:%o", pers.activeKey, this.activeNode?this.activeNode.data.key:"?");
2218
- if( ajaxOpts.addActiveKey ){
2219
- ajaxOpts.data.activeKey = pers.activeKey;
2220
- }
2221
- if( ajaxOpts.addFocusedKey ){
2222
- ajaxOpts.data.focusedKey = pers.focusedKey;
2223
- }
2224
- if( ajaxOpts.addExpandedKeyList ){
2225
- ajaxOpts.data.expandedKeyList = pers.expandedKeyList.join(",");
2226
- }
2227
- if( ajaxOpts.addSelectedKeyList ){
2228
- ajaxOpts.data.selectedKeyList = pers.selectedKeyList.join(",");
2229
- }
2230
- // Set up onPostInit callback to be called when Ajax returns
2231
- if( ajaxOpts.success ){
2232
- this.logWarning("initAjax: success callback is ignored; use onPostInit instead.");
2233
- }
2234
- if( ajaxOpts.error ){
2235
- this.logWarning("initAjax: error callback is ignored; use onPostInit instead.");
2236
- }
2237
- var isReloading = pers.isReloading();
2238
- ajaxOpts.success = function(dtnode, data, textStatus) {
2239
- if(opts.selectMode == 3){
2240
- dtnode.tree.tnRoot._updatePartSelectionState();
2241
- }
2242
- if(opts.onPostInit){
2243
- opts.onPostInit.call(dtnode.tree, isReloading, false);
2244
- }
2245
- if(callback){
2246
- callback.call(dtnode.tree, "ok");
2247
- }
2248
- };
2249
- ajaxOpts.error = function(dtnode, XMLHttpRequest, textStatus, errorThrown) {
2250
- if(opts.onPostInit){
2251
- opts.onPostInit.call(dtnode.tree, isReloading, true, XMLHttpRequest, textStatus, errorThrown);
2252
- }
2253
- if(callback){
2254
- callback.call(dtnode.tree, "error", XMLHttpRequest, textStatus, errorThrown);
2255
- }
2256
- };
2257
- // }
2258
- this.logDebug("Dynatree._init(): send Ajax request...");
2259
- this.tnRoot.appendAjax(ajaxOpts);
2260
- },
2261
-
2262
- toString: function() {
2263
- // return "DynaTree '" + this.options.title + "'";
2264
- return "Dynatree '" + this.$tree.attr("id") + "'";
2265
- },
2266
-
2267
- toDict: function() {
2268
- return this.tnRoot.toDict(true);
2269
- },
2270
-
2271
- serializeArray: function(stopOnParents) {
2272
- // Return a JavaScript array of objects, ready to be encoded as a JSON
2273
- // string for selected nodes
2274
- var nodeList = this.getSelectedNodes(stopOnParents),
2275
- name = this.$tree.attr("name") || this.$tree.attr("id"),
2276
- arr = [];
2277
- for(var i=0, l=nodeList.length; i<l; i++){
2278
- arr.push({name: name, value: nodeList[i].data.key});
2279
- }
2280
- return arr;
2281
- },
2282
-
2283
- getPersistData: function() {
2284
- return this.persistence.toDict();
2285
- },
2286
-
2287
- logDebug: function(msg) {
2288
- if( this.options.debugLevel >= 2 ) {
2289
- Array.prototype.unshift.apply(arguments, ["debug"]);
2290
- _log.apply(this, arguments);
2291
- }
2292
- },
2293
-
2294
- logInfo: function(msg) {
2295
- if( this.options.debugLevel >= 1 ) {
2296
- Array.prototype.unshift.apply(arguments, ["info"]);
2297
- _log.apply(this, arguments);
2298
- }
2299
- },
2300
-
2301
- logWarning: function(msg) {
2302
- Array.prototype.unshift.apply(arguments, ["warn"]);
2303
- _log.apply(this, arguments);
2304
- },
2305
-
2306
- isInitializing: function() {
2307
- return ( this.phase=="init" || this.phase=="postInit" );
2308
- },
2309
- isReloading: function() {
2310
- return ( this.phase=="init" || this.phase=="postInit" ) && this.options.persist && this.persistence.cookiesFound;
2311
- },
2312
- isUserEvent: function() {
2313
- return ( this.phase=="userEvent" );
2314
- },
2315
-
2316
- redraw: function() {
2317
- // this.logDebug("dynatree.redraw()...");
2318
- this.tnRoot.render(false, false);
2319
- // this.logDebug("dynatree.redraw() done.");
2320
- },
2321
- renderInvisibleNodes: function() {
2322
- this.tnRoot.render(false, true);
2323
- },
2324
- reload: function(callback) {
2325
- this._load(callback);
2326
- },
2327
-
2328
- getRoot: function() {
2329
- return this.tnRoot;
2330
- },
2331
-
2332
- enable: function() {
2333
- this.$widget.enable();
2334
- },
2335
-
2336
- disable: function() {
2337
- this.$widget.disable();
2338
- },
2339
-
2340
- getNodeByKey: function(key) {
2341
- // Search the DOM by element ID (assuming this is faster than traversing all nodes).
2342
- // $("#...") has problems, if the key contains '.', so we use getElementById()
2343
- var el = document.getElementById(this.options.idPrefix + key);
2344
- if( el ){
2345
- return el.dtnode ? el.dtnode : null;
2346
- }
2347
- // Not found in the DOM, but still may be in an unrendered part of tree
2348
- var match = null;
2349
- this.visit(function(node){
2350
- // window.console.log("%s", node);
2351
- if(node.data.key == key) {
2352
- match = node;
2353
- return false;
2354
- }
2355
- }, true);
2356
- return match;
2357
- },
2358
-
2359
- getActiveNode: function() {
2360
- return this.activeNode;
2361
- },
2362
-
2363
- reactivate: function(setFocus) {
2364
- // Re-fire onQueryActivate and onActivate events.
2365
- var node = this.activeNode;
2366
- // this.logDebug("reactivate %o", node);
2367
- if( node ) {
2368
- this.activeNode = null; // Force re-activating
2369
- node.activate();
2370
- if( setFocus ){
2371
- node.focus();
2372
- }
2373
- }
2374
- },
2375
-
2376
- getSelectedNodes: function(stopOnParents) {
2377
- var nodeList = [];
2378
- this.tnRoot.visit(function(node){
2379
- if( node.bSelected ) {
2380
- nodeList.push(node);
2381
- if( stopOnParents === true ){
2382
- return "skip"; // stop processing this branch
2383
- }
2384
- }
2385
- });
2386
- return nodeList;
2387
- },
2388
-
2389
- activateKey: function(key) {
2390
- var dtnode = (key === null) ? null : this.getNodeByKey(key);
2391
- if( !dtnode ) {
2392
- if( this.activeNode ){
2393
- this.activeNode.deactivate();
2394
- }
2395
- this.activeNode = null;
2396
- return null;
2397
- }
2398
- dtnode.focus();
2399
- dtnode.activate();
2400
- return dtnode;
2401
- },
2402
-
2403
- loadKeyPath: function(keyPath, callback) {
2404
- var segList = keyPath.split(this.options.keyPathSeparator);
2405
- // Remove leading '/'
2406
- if(segList[0] === ""){
2407
- segList.shift();
2408
- }
2409
- // Remove leading system root key
2410
- if(segList[0] == this.tnRoot.data.key){
2411
- this.logDebug("Removed leading root key.");
2412
- segList.shift();
2413
- }
2414
- keyPath = segList.join(this.options.keyPathSeparator);
2415
- return this.tnRoot._loadKeyPath(keyPath, callback);
2416
- },
2417
-
2418
- selectKey: function(key, select) {
2419
- var dtnode = this.getNodeByKey(key);
2420
- if( !dtnode ){
2421
- return null;
2422
- }
2423
- dtnode.select(select);
2424
- return dtnode;
2425
- },
2426
-
2427
- enableUpdate: function(bEnable) {
2428
- if ( this.bEnableUpdate==bEnable ){
2429
- return bEnable;
2430
- }
2431
- this.bEnableUpdate = bEnable;
2432
- if ( bEnable ){
2433
- this.redraw();
2434
- }
2435
- return !bEnable; // return previous value
2436
- },
2437
-
2438
- count: function() {
2439
- return this.tnRoot.countChildren();
2440
- },
2441
-
2442
- visit: function(fn, includeRoot) {
2443
- return this.tnRoot.visit(fn, includeRoot);
2444
- },
2445
-
2446
- _createFromTag: function(parentTreeNode, $ulParent) {
2447
- // Convert a <UL>...</UL> list into children of the parent tree node.
2448
- var self = this;
2449
- /*
2450
- TODO: better?
2451
- this.$lis = $("li:has(a[href])", this.element);
2452
- this.$tabs = this.$lis.map(function() { return $("a", this)[0]; });
2453
- */
2454
- $ulParent.find(">li").each(function() {
2455
- var $li = $(this),
2456
- $liSpan = $li.find(">span:first"),
2457
- $liA = $li.find(">a:first"),
2458
- title,
2459
- href = null,
2460
- target = null,
2461
- tooltip;
2462
- if( $liSpan.length ) {
2463
- // If a <li><span> tag is specified, use it literally.
2464
- title = $liSpan.html();
2465
- } else if( $liA.length ) {
2466
- title = $liA.html();
2467
- href = $liA.attr("href");
2468
- target = $liA.attr("target");
2469
- tooltip = $liA.attr("title");
2470
- } else {
2471
- // If only a <li> tag is specified, use the trimmed string up to
2472
- // the next child <ul> tag.
2473
- title = $li.html();
2474
- var iPos = title.search(/<ul/i);
2475
- if( iPos >= 0 ){
2476
- title = $.trim(title.substring(0, iPos));
2477
- }else{
2478
- title = $.trim(title);
2479
- }
2480
- // self.logDebug("%o", title);
2481
- }
2482
- // Parse node options from ID, title and class attributes
2483
- var data = {
2484
- title: title,
2485
- tooltip: tooltip,
2486
- isFolder: $li.hasClass("folder"),
2487
- isLazy: $li.hasClass("lazy"),
2488
- expand: $li.hasClass("expanded"),
2489
- select: $li.hasClass("selected"),
2490
- activate: $li.hasClass("active"),
2491
- focus: $li.hasClass("focused"),
2492
- noLink: $li.hasClass("noLink")
2493
- };
2494
- if( href ){
2495
- data.href = href;
2496
- data.target = target;
2497
- }
2498
- if( $li.attr("title") ){
2499
- data.tooltip = $li.attr("title"); // overrides <a title='...'>
2500
- }
2501
- if( $li.attr("id") ){
2502
- data.key = $li.attr("id");
2503
- }
2504
- // If a data attribute is present, evaluate as a JavaScript object
2505
- if( $li.attr("data") ) {
2506
- var dataAttr = $.trim($li.attr("data"));
2507
- if( dataAttr ) {
2508
- if( dataAttr.charAt(0) != "{" ){
2509
- dataAttr = "{" + dataAttr + "}";
2510
- }
2511
- try {
2512
- $.extend(data, eval("(" + dataAttr + ")"));
2513
- } catch(e) {
2514
- throw ("Error parsing node data: " + e + "\ndata:\n'" + dataAttr + "'");
2515
- }
2516
- }
2517
- }
2518
- var childNode = parentTreeNode.addChild(data);
2519
- // Recursive reading of child nodes, if LI tag contains an UL tag
2520
- var $ul = $li.find(">ul:first");
2521
- if( $ul.length ) {
2522
- self._createFromTag(childNode, $ul); // must use 'self', because 'this' is the each() context
2523
- }
2524
- });
2525
- },
2526
-
2527
- _checkConsistency: function() {
2528
- // this.logDebug("tree._checkConsistency() NOT IMPLEMENTED - %o", this);
2529
- },
2530
-
2531
- _setDndStatus: function(sourceNode, targetNode, helper, hitMode, accept) {
2532
- // hitMode: 'after', 'before', 'over', 'out', 'start', 'stop'
2533
- var $source = sourceNode ? $(sourceNode.span) : null,
2534
- $target = $(targetNode.span);
2535
- if( !this.$dndMarker ) {
2536
- this.$dndMarker = $("<div id='dynatree-drop-marker'></div>")
2537
- .hide()
2538
- .prependTo($(this.divTree).parent());
2539
- // .prependTo("body");
2540
- // logMsg("Creating marker: %o", this.$dndMarker);
2541
- }
2542
- /*
2543
- if(hitMode === "start"){
2544
- }
2545
- if(hitMode === "stop"){
2546
- // sourceNode.removeClass("dynatree-drop-target");
2547
- }
2548
- */
2549
- // this.$dndMarker.attr("class", hitMode);
2550
- if(hitMode === "after" || hitMode === "before" || hitMode === "over"){
2551
- // $source && $source.addClass("dynatree-drag-source");
2552
- var pos = $target.offset();
2553
-
2554
- // $target.addClass("dynatree-drop-target");
2555
-
2556
- switch(hitMode){
2557
- case "before":
2558
- this.$dndMarker.removeClass("dynatree-drop-after dynatree-drop-over");
2559
- this.$dndMarker.addClass("dynatree-drop-before");
2560
- pos.top -= 8;
2561
- break;
2562
- case "after":
2563
- this.$dndMarker.removeClass("dynatree-drop-before dynatree-drop-over");
2564
- this.$dndMarker.addClass("dynatree-drop-after");
2565
- pos.top += 8;
2566
- break;
2567
- default:
2568
- this.$dndMarker.removeClass("dynatree-drop-after dynatree-drop-before");
2569
- this.$dndMarker.addClass("dynatree-drop-over");
2570
- $target.addClass("dynatree-drop-target");
2571
- pos.left += 8;
2572
- }
2573
- // logMsg("Creating marker: %o", this.$dndMarker);
2574
- // logMsg(" $target.offset=%o", $target);
2575
- // logMsg(" pos/$target.offset=%o", pos);
2576
- // logMsg(" $target.position=%o", $target.position());
2577
- // logMsg(" $target.offsetParent=%o, ot:%o", $target.offsetParent(), $target.offsetParent().offset());
2578
- // logMsg(" $(this.divTree).offset=%o", $(this.divTree).offset());
2579
- // logMsg(" $(this.divTree).parent=%o", $(this.divTree).parent());
2580
- // var pos = $target.offset();
2581
- // var parentPos = $target.offsetParent().offset();
2582
- // var bodyPos = $target.offsetParent().offset();
2583
-
2584
- this.$dndMarker //.offset({left: pos.left, top: pos.top})
2585
- .css({
2586
- "left": pos.left,
2587
- "top": pos.top,
2588
- "z-index": 1000
2589
- })
2590
- .show();
2591
- // helper.addClass("dynatree-drop-hover");
2592
- } else {
2593
- // $source && $source.removeClass("dynatree-drag-source");
2594
- $target.removeClass("dynatree-drop-target");
2595
- this.$dndMarker.hide();
2596
- // helper.removeClass("dynatree-drop-hover");
2597
- }
2598
- if(hitMode === "after"){
2599
- $target.addClass("dynatree-drop-after");
2600
- } else {
2601
- $target.removeClass("dynatree-drop-after");
2602
- }
2603
- if(hitMode === "before"){
2604
- $target.addClass("dynatree-drop-before");
2605
- } else {
2606
- $target.removeClass("dynatree-drop-before");
2607
- }
2608
- if(accept === true){
2609
- if($source){
2610
- $source.addClass("dynatree-drop-accept");
2611
- }
2612
- $target.addClass("dynatree-drop-accept");
2613
- helper.addClass("dynatree-drop-accept");
2614
- }else{
2615
- if($source){
2616
- $source.removeClass("dynatree-drop-accept");
2617
- }
2618
- $target.removeClass("dynatree-drop-accept");
2619
- helper.removeClass("dynatree-drop-accept");
2620
- }
2621
- if(accept === false){
2622
- if($source){
2623
- $source.addClass("dynatree-drop-reject");
2624
- }
2625
- $target.addClass("dynatree-drop-reject");
2626
- helper.addClass("dynatree-drop-reject");
2627
- }else{
2628
- if($source){
2629
- $source.removeClass("dynatree-drop-reject");
2630
- }
2631
- $target.removeClass("dynatree-drop-reject");
2632
- helper.removeClass("dynatree-drop-reject");
2633
- }
2634
- },
2635
-
2636
- _onDragEvent: function(eventName, node, otherNode, event, ui, draggable) {
2637
- /**
2638
- * Handles drag'n'drop functionality.
2639
- *
2640
- * A standard jQuery drag-and-drop process may generate these calls:
2641
- *
2642
- * draggable helper():
2643
- * _onDragEvent("helper", sourceNode, null, event, null, null);
2644
- * start:
2645
- * _onDragEvent("start", sourceNode, null, event, ui, draggable);
2646
- * drag:
2647
- * _onDragEvent("leave", prevTargetNode, sourceNode, event, ui, draggable);
2648
- * _onDragEvent("over", targetNode, sourceNode, event, ui, draggable);
2649
- * _onDragEvent("enter", targetNode, sourceNode, event, ui, draggable);
2650
- * stop:
2651
- * _onDragEvent("drop", targetNode, sourceNode, event, ui, draggable);
2652
- * _onDragEvent("leave", targetNode, sourceNode, event, ui, draggable);
2653
- * _onDragEvent("stop", sourceNode, null, event, ui, draggable);
2654
- */
2655
- // if(eventName !== "over"){
2656
- // this.logDebug("tree._onDragEvent(%s, %o, %o) - %o", eventName, node, otherNode, this);
2657
- // }
2658
- var opts = this.options,
2659
- dnd = this.options.dnd,
2660
- res = null,
2661
- nodeTag = $(node.span),
2662
- hitMode;
2663
-
2664
- switch (eventName) {
2665
- case "helper":
2666
- // Only event and node argument is available
2667
- var $helper = $("<div class='dynatree-drag-helper'><span class='dynatree-drag-helper-img' /></div>")
2668
- .append($(event.target).closest('a').clone());
2669
- // issue 244: helper should be child of scrollParent
2670
- $("ul.dynatree-container", node.tree.divTree).append($helper);
2671
- // $(node.tree.divTree).append($helper);
2672
- // Attach node reference to helper object
2673
- $helper.data("dtSourceNode", node);
2674
- // this.logDebug("helper=%o", $helper);
2675
- // this.logDebug("helper.sourceNode=%o", $helper.data("dtSourceNode"));
2676
- res = $helper;
2677
- break;
2678
- case "start":
2679
- if(node.isStatusNode()) {
2680
- res = false;
2681
- } else if(dnd.onDragStart) {
2682
- res = dnd.onDragStart(node);
2683
- }
2684
- if(res === false) {
2685
- this.logDebug("tree.onDragStart() cancelled");
2686
- //draggable._clear();
2687
- // NOTE: the return value seems to be ignored (drag is not canceled, when false is returned)
2688
- ui.helper.trigger("mouseup");
2689
- ui.helper.hide();
2690
- } else {
2691
- nodeTag.addClass("dynatree-drag-source");
2692
- }
2693
- break;
2694
- case "enter":
2695
- res = dnd.onDragEnter ? dnd.onDragEnter(node, otherNode) : null;
2696
- res = {
2697
- over: (res !== false) && ((res === true) || (res === "over") || $.inArray("over", res) >= 0),
2698
- before: (res !== false) && ((res === true) || (res === "before") || $.inArray("before", res) >= 0),
2699
- after: (res !== false) && ((res === true) || (res === "after") || $.inArray("after", res) >= 0)
2700
- };
2701
- ui.helper.data("enterResponse", res);
2702
- // this.logDebug("helper.enterResponse: %o", res);
2703
- break;
2704
- case "over":
2705
- var enterResponse = ui.helper.data("enterResponse");
2706
- hitMode = null;
2707
- if(enterResponse === false){
2708
- // Don't call onDragOver if onEnter returned false.
2709
- break;
2710
- } else if(typeof enterResponse === "string") {
2711
- // Use hitMode from onEnter if provided.
2712
- hitMode = enterResponse;
2713
- } else {
2714
- // Calculate hitMode from relative cursor position.
2715
- var nodeOfs = nodeTag.offset();
2716
- // var relPos = { x: event.clientX - nodeOfs.left,
2717
- // y: event.clientY - nodeOfs.top };
2718
- // nodeOfs.top += this.parentTop;
2719
- // nodeOfs.left += this.parentLeft;
2720
- var relPos = { x: event.pageX - nodeOfs.left,
2721
- y: event.pageY - nodeOfs.top };
2722
- var relPos2 = { x: relPos.x / nodeTag.width(),
2723
- y: relPos.y / nodeTag.height() };
2724
- // this.logDebug("event.page: %s/%s", event.pageX, event.pageY);
2725
- // this.logDebug("event.client: %s/%s", event.clientX, event.clientY);
2726
- // this.logDebug("nodeOfs: %s/%s", nodeOfs.left, nodeOfs.top);
2727
- //// this.logDebug("parent: %s/%s", this.parentLeft, this.parentTop);
2728
- // this.logDebug("relPos: %s/%s", relPos.x, relPos.y);
2729
- // this.logDebug("relPos2: %s/%s", relPos2.x, relPos2.y);
2730
- if( enterResponse.after && relPos2.y > 0.75 ){
2731
- hitMode = "after";
2732
- } else if(!enterResponse.over && enterResponse.after && relPos2.y > 0.5 ){
2733
- hitMode = "after";
2734
- } else if(enterResponse.before && relPos2.y <= 0.25) {
2735
- hitMode = "before";
2736
- } else if(!enterResponse.over && enterResponse.before && relPos2.y <= 0.5) {
2737
- hitMode = "before";
2738
- } else if(enterResponse.over) {
2739
- hitMode = "over";
2740
- }
2741
- // Prevent no-ops like 'before source node'
2742
- // TODO: these are no-ops when moving nodes, but not in copy mode
2743
- if( dnd.preventVoidMoves ){
2744
- if(node === otherNode){
2745
- // this.logDebug(" drop over source node prevented");
2746
- hitMode = null;
2747
- }else if(hitMode === "before" && otherNode && node === otherNode.getNextSibling()){
2748
- // this.logDebug(" drop after source node prevented");
2749
- hitMode = null;
2750
- }else if(hitMode === "after" && otherNode && node === otherNode.getPrevSibling()){
2751
- // this.logDebug(" drop before source node prevented");
2752
- hitMode = null;
2753
- }else if(hitMode === "over" && otherNode
2754
- && otherNode.parent === node && otherNode.isLastSibling() ){
2755
- // this.logDebug(" drop last child over own parent prevented");
2756
- hitMode = null;
2757
- }
2758
- }
2759
- // this.logDebug("hitMode: %s - %s - %s", hitMode, (node.parent === otherNode), node.isLastSibling());
2760
- ui.helper.data("hitMode", hitMode);
2761
- }
2762
- // Auto-expand node (only when 'over' the node, not 'before', or 'after')
2763
- if(hitMode === "over"
2764
- && dnd.autoExpandMS && node.hasChildren() !== false && !node.bExpanded) {
2765
- node.scheduleAction("expand", dnd.autoExpandMS);
2766
- }
2767
- if(hitMode && dnd.onDragOver){
2768
- res = dnd.onDragOver(node, otherNode, hitMode);
2769
- }
2770
- this._setDndStatus(otherNode, node, ui.helper, hitMode, res!==false);
2771
- break;
2772
- case "drop":
2773
- hitMode = ui.helper.data("hitMode");
2774
- if(hitMode && dnd.onDrop){
2775
- dnd.onDrop(node, otherNode, hitMode, ui, draggable);
2776
- }
2777
- break;
2778
- case "leave":
2779
- // Cancel pending expand request
2780
- node.scheduleAction("cancel");
2781
- ui.helper.data("enterResponse", null);
2782
- ui.helper.data("hitMode", null);
2783
- this._setDndStatus(otherNode, node, ui.helper, "out", undefined);
2784
- if(dnd.onDragLeave){
2785
- dnd.onDragLeave(node, otherNode);
2786
- }
2787
- break;
2788
- case "stop":
2789
- nodeTag.removeClass("dynatree-drag-source");
2790
- if(dnd.onDragStop){
2791
- dnd.onDragStop(node);
2792
- }
2793
- break;
2794
- default:
2795
- throw "Unsupported drag event: " + eventName;
2796
- }
2797
- return res;
2798
- },
2799
-
2800
- cancelDrag: function() {
2801
- var dd = $.ui.ddmanager.current;
2802
- if(dd){
2803
- dd.cancel();
2804
- }
2805
- },
2806
-
2807
- // --- end of class
2808
- lastentry: undefined
2809
- };
2810
-
2811
- /*************************************************************************
2812
- * Widget $(..).dynatree
2813
- */
2814
-
2815
- $.widget("ui.dynatree", {
2816
- /*
2817
- init: function() {
2818
- // ui.core 1.6 renamed init() to _init(): this stub assures backward compatibility
2819
- _log("warn", "ui.dynatree.init() was called; you should upgrade to jquery.ui.core.js v1.8 or higher.");
2820
- return this._init();
2821
- },
2822
- */
2823
- _init: function() {
2824
- if( parseFloat($.ui.version) < 1.8 ) {
2825
- // jquery.ui.core 1.8 renamed _init() to _create(): this stub assures backward compatibility
2826
- if(this.options.debugLevel >= 0){
2827
- _log("warn", "ui.dynatree._init() was called; you should upgrade to jquery.ui.core.js v1.8 or higher.");
2828
- }
2829
- return this._create();
2830
- }
2831
- // jquery.ui.core 1.8 still uses _init() to perform "default functionality"
2832
- if(this.options.debugLevel >= 2){
2833
- _log("debug", "ui.dynatree._init() was called; no current default functionality.");
2834
- }
2835
- },
2836
-
2837
- _create: function() {
2838
- var opts = this.options;
2839
- if(opts.debugLevel >= 1){
2840
- logMsg("Dynatree._create(): version='%s', debugLevel=%o.", $.ui.dynatree.version, this.options.debugLevel);
2841
- }
2842
- // The widget framework supplies this.element and this.options.
2843
- this.options.event += ".dynatree"; // namespace event
2844
-
2845
- var divTree = this.element.get(0);
2846
- /* // Clear container, in case it contained some 'waiting' or 'error' text
2847
- // for clients that don't support JS
2848
- if( opts.children || (opts.initAjax && opts.initAjax.url) || opts.initId )
2849
- $(divTree).empty();
2850
- */
2851
- // Create the DynaTree object
2852
- this.tree = new DynaTree(this);
2853
- this.tree._load();
2854
- this.tree.logDebug("Dynatree._init(): done.");
2855
- },
2856
-
2857
- bind: function() {
2858
- // Prevent duplicate binding
2859
- this.unbind();
2860
-
2861
- var eventNames = "click.dynatree dblclick.dynatree";
2862
- if( this.options.keyboard ){
2863
- // Note: leading ' '!
2864
- eventNames += " keypress.dynatree keydown.dynatree";
2865
- }
2866
- this.element.bind(eventNames, function(event){
2867
- var dtnode = $.ui.dynatree.getNode(event.target);
2868
- if( !dtnode ){
2869
- return true; // Allow bubbling of other events
2870
- }
2871
- var tree = dtnode.tree;
2872
- var o = tree.options;
2873
- tree.logDebug("event(%s): dtnode: %s", event.type, dtnode);
2874
- var prevPhase = tree.phase;
2875
- tree.phase = "userEvent";
2876
- try {
2877
- switch(event.type) {
2878
- case "click":
2879
- return ( o.onClick && o.onClick.call(tree, dtnode, event)===false ) ? false : dtnode._onClick(event);
2880
- case "dblclick":
2881
- return ( o.onDblClick && o.onDblClick.call(tree, dtnode, event)===false ) ? false : dtnode._onDblClick(event);
2882
- case "keydown":
2883
- return ( o.onKeydown && o.onKeydown.call(tree, dtnode, event)===false ) ? false : dtnode._onKeydown(event);
2884
- case "keypress":
2885
- return ( o.onKeypress && o.onKeypress.call(tree, dtnode, event)===false ) ? false : dtnode._onKeypress(event);
2886
- }
2887
- } catch(e) {
2888
- var _ = null; // issue 117
2889
- tree.logWarning("bind(%o): dtnode: %o, error: %o", event, dtnode, e);
2890
- } finally {
2891
- tree.phase = prevPhase;
2892
- }
2893
- });
2894
-
2895
- // focus/blur don't bubble, i.e. are not delegated to parent <div> tags,
2896
- // so we use the addEventListener capturing phase.
2897
- // See http://www.howtocreate.co.uk/tutorials/javascript/domevents
2898
- function __focusHandler(event) {
2899
- // Handles blur and focus.
2900
- // Fix event for IE:
2901
- // doesn't pass JSLint:
2902
- // event = arguments[0] = $.event.fix( event || window.event );
2903
- // what jQuery does:
2904
- // var args = jQuery.makeArray( arguments );
2905
- // event = args[0] = jQuery.event.fix( event || window.event );
2906
- event = $.event.fix( event || window.event );
2907
- var dtnode = $.ui.dynatree.getNode(event.target);
2908
- return dtnode ? dtnode._onFocus(event) : false;
2909
- }
2910
- var div = this.tree.divTree;
2911
- if( div.addEventListener ) {
2912
- div.addEventListener("focus", __focusHandler, true);
2913
- div.addEventListener("blur", __focusHandler, true);
2914
- } else {
2915
- div.onfocusin = div.onfocusout = __focusHandler;
2916
- }
2917
- // EVENTS
2918
- // disable click if event is configured to something else
2919
- // if (!(/^click/).test(o.event))
2920
- // this.$tabs.bind("click.tabs", function() { return false; });
2921
-
2922
- },
2923
-
2924
- unbind: function() {
2925
- this.element.unbind(".dynatree");
2926
- },
2927
-
2928
- /* TODO: we could handle option changes during runtime here (maybe to re-render, ...)
2929
- setData: function(key, value) {
2930
- this.tree.logDebug("dynatree.setData('" + key + "', '" + value + "')");
2931
- },
2932
- */
2933
- enable: function() {
2934
- this.bind();
2935
- // Call default disable(): remove -disabled from css:
2936
- $.Widget.prototype.enable.apply(this, arguments);
2937
- },
2938
-
2939
- disable: function() {
2940
- this.unbind();
2941
- // Call default disable(): add -disabled to css:
2942
- $.Widget.prototype.disable.apply(this, arguments);
2943
- },
2944
-
2945
- // --- getter methods (i.e. NOT returning a reference to $)
2946
- getTree: function() {
2947
- return this.tree;
2948
- },
2949
-
2950
- getRoot: function() {
2951
- return this.tree.getRoot();
2952
- },
2953
-
2954
- getActiveNode: function() {
2955
- return this.tree.getActiveNode();
2956
- },
2957
-
2958
- getSelectedNodes: function() {
2959
- return this.tree.getSelectedNodes();
2960
- },
2961
-
2962
- // ------------------------------------------------------------------------
2963
- lastentry: undefined
2964
- });
2965
-
2966
-
2967
- // The following methods return a value (thus breaking the jQuery call chain):
2968
- if( parseFloat($.ui.version) < 1.8 ) {
2969
- $.ui.dynatree.getter = "getTree getRoot getActiveNode getSelectedNodes";
2970
- }
2971
-
2972
- /*******************************************************************************
2973
- * Tools in ui.dynatree namespace
2974
- */
2975
- $.ui.dynatree.version = "$Version: 1.2.1_rc3$";
2976
-
2977
- /**
2978
- * Return a DynaTreeNode object for a given DOM element
2979
- */
2980
- $.ui.dynatree.getNode = function(el) {
2981
- if(el instanceof DynaTreeNode){
2982
- return el; // el already was a DynaTreeNode
2983
- }
2984
- if(el.selector !== undefined){
2985
- el = el[0]; // el was a jQuery object: use the DOM element
2986
- }
2987
- // TODO: for some reason $el.parents("[dtnode]") does not work (jQuery 1.6.1)
2988
- // maybe, because dtnode is a property, not an attribute
2989
- while( el ) {
2990
- if(el.dtnode) {
2991
- return el.dtnode;
2992
- }
2993
- el = el.parentNode;
2994
- }
2995
- return null;
2996
- /*
2997
- var $el = el.selector === undefined ? $(el) : el,
2998
- // parent = $el.closest("[dtnode]"),
2999
- // parent = $el.parents("[dtnode]").first(),
3000
- useProp = (typeof $el.prop == "function"),
3001
- node;
3002
- $el.parents().each(function(){
3003
- node = useProp ? $(this).prop("dtnode") : $(this).attr("dtnode");
3004
- if(node){
3005
- return false;
3006
- }
3007
- });
3008
- return node;
3009
- */
3010
- }
3011
-
3012
- /**Return persistence information from cookies.*/
3013
- $.ui.dynatree.getPersistData = DynaTreeStatus._getTreePersistData;
3014
-
3015
- /*******************************************************************************
3016
- * Plugin default options:
3017
- */
3018
- $.ui.dynatree.prototype.options = {
3019
- title: "Dynatree", // Tree's name (only used for debug output)
3020
- minExpandLevel: 1, // 1: root node is not collapsible
3021
- imagePath: null, // Path to a folder containing icons. Defaults to 'skin/' subdirectory.
3022
- children: null, // Init tree structure from this object array.
3023
- initId: null, // Init tree structure from a <ul> element with this ID.
3024
- initAjax: null, // Ajax options used to initialize the tree strucuture.
3025
- autoFocus: true, // Set focus to first child, when expanding or lazy-loading.
3026
- keyboard: true, // Support keyboard navigation.
3027
- persist: false, // Persist expand-status to a cookie
3028
- autoCollapse: false, // Automatically collapse all siblings, when a node is expanded.
3029
- clickFolderMode: 3, // 1:activate, 2:expand, 3:activate and expand
3030
- activeVisible: true, // Make sure, active nodes are visible (expanded).
3031
- checkbox: false, // Show checkboxes.
3032
- selectMode: 2, // 1:single, 2:multi, 3:multi-hier
3033
- fx: null, // Animations, e.g. null or { height: "toggle", duration: 200 }
3034
- noLink: false, // Use <span> instead of <a> tags for all nodes
3035
- // Low level event handlers: onEvent(dtnode, event): return false, to stop default processing
3036
- onClick: null, // null: generate focus, expand, activate, select events.
3037
- onDblClick: null, // (No default actions.)
3038
- onKeydown: null, // null: generate keyboard navigation (focus, expand, activate).
3039
- onKeypress: null, // (No default actions.)
3040
- onFocus: null, // null: set focus to node.
3041
- onBlur: null, // null: remove focus from node.
3042
-
3043
- // Pre-event handlers onQueryEvent(flag, dtnode): return false, to stop processing
3044
- onQueryActivate: null, // Callback(flag, dtnode) before a node is (de)activated.
3045
- onQuerySelect: null, // Callback(flag, dtnode) before a node is (de)selected.
3046
- onQueryExpand: null, // Callback(flag, dtnode) before a node is expanded/collpsed.
3047
-
3048
- // High level event handlers
3049
- onPostInit: null, // Callback(isReloading, isError) when tree was (re)loaded.
3050
- onActivate: null, // Callback(dtnode) when a node is activated.
3051
- onDeactivate: null, // Callback(dtnode) when a node is deactivated.
3052
- onSelect: null, // Callback(flag, dtnode) when a node is (de)selected.
3053
- onExpand: null, // Callback(flag, dtnode) when a node is expanded/collapsed.
3054
- onLazyRead: null, // Callback(dtnode) when a lazy node is expanded for the first time.
3055
- onCustomRender: null, // Callback(dtnode) before a node is rendered. Return a HTML string to override.
3056
- onCreate: null, // Callback(dtnode, nodeSpan) after a node was rendered for the first time.
3057
- onRender: null, // Callback(dtnode, nodeSpan) after a node was rendered.
3058
-
3059
- // Drag'n'drop support
3060
- dnd: {
3061
- // Make tree nodes draggable:
3062
- onDragStart: null, // Callback(sourceNode), return true, to enable dnd
3063
- onDragStop: null, // Callback(sourceNode)
3064
- // helper: null,
3065
- // Make tree nodes accept draggables
3066
- autoExpandMS: 1000, // Expand nodes after n milliseconds of hovering.
3067
- preventVoidMoves: true, // Prevent dropping nodes 'before self', etc.
3068
- onDragEnter: null, // Callback(targetNode, sourceNode)
3069
- onDragOver: null, // Callback(targetNode, sourceNode, hitMode)
3070
- onDrop: null, // Callback(targetNode, sourceNode, hitMode)
3071
- onDragLeave: null // Callback(targetNode, sourceNode)
3072
- },
3073
- ajaxDefaults: { // Used by initAjax option
3074
- cache: false, // false: Append random '_' argument to the request url to prevent caching.
3075
- timeout: 0, // >0: Make sure we get an ajax error for invalid URLs
3076
- dataType: "json" // Expect json format and pass json object to callbacks.
3077
- },
3078
- strings: {
3079
- loading: "Loading&#8230;",
3080
- loadError: "Load error!"
3081
- },
3082
- generateIds: false, // Generate id attributes like <span id='dynatree-id-KEY'>
3083
- idPrefix: "dynatree-id-", // Used to generate node id's like <span id="dynatree-id-<key>">.
3084
- keyPathSeparator: "/", // Used by node.getKeyPath() and tree.loadKeyPath().
3085
- // cookieId: "dynatree-cookie", // Choose a more unique name, to allow multiple trees.
3086
- cookieId: "dynatree", // Choose a more unique name, to allow multiple trees.
3087
- cookie: {
3088
- expires: null //7, // Days or Date; null: session cookie
3089
- // path: "/", // Defaults to current page
3090
- // domain: "jquery.com",
3091
- // secure: true
3092
- },
3093
- // Class names used, when rendering the HTML markup.
3094
- // Note: if only single entries are passed for options.classNames, all other
3095
- // values are still set to default.
3096
- classNames: {
3097
- container: "dynatree-container",
3098
- node: "dynatree-node",
3099
- folder: "dynatree-folder",
3100
- // document: "dynatree-document",
3101
-
3102
- empty: "dynatree-empty",
3103
- vline: "dynatree-vline",
3104
- expander: "dynatree-expander",
3105
- connector: "dynatree-connector",
3106
- checkbox: "dynatree-checkbox",
3107
- nodeIcon: "dynatree-icon",
3108
- title: "dynatree-title",
3109
- noConnector: "dynatree-no-connector",
3110
-
3111
- nodeError: "dynatree-statusnode-error",
3112
- nodeWait: "dynatree-statusnode-wait",
3113
- hidden: "dynatree-hidden",
3114
- combinedExpanderPrefix: "dynatree-exp-",
3115
- combinedIconPrefix: "dynatree-ico-",
3116
- nodeLoading: "dynatree-loading",
3117
- // disabled: "dynatree-disabled",
3118
- hasChildren: "dynatree-has-children",
3119
- active: "dynatree-active",
3120
- selected: "dynatree-selected",
3121
- expanded: "dynatree-expanded",
3122
- lazy: "dynatree-lazy",
3123
- focused: "dynatree-focused",
3124
- partsel: "dynatree-partsel",
3125
- lastsib: "dynatree-lastsib"
3126
- },
3127
- debugLevel: 1,
3128
-
3129
- // ------------------------------------------------------------------------
3130
- lastentry: undefined
3131
- };
3132
- //
3133
- if( parseFloat($.ui.version) < 1.8 ) {
3134
- $.ui.dynatree.defaults = $.ui.dynatree.prototype.options;
3135
- }
3136
-
3137
- /*******************************************************************************
3138
- * Reserved data attributes for a tree node.
3139
- */
3140
- $.ui.dynatree.nodedatadefaults = {
3141
- title: null, // (required) Displayed name of the node (html is allowed here)
3142
- key: null, // May be used with activate(), select(), find(), ...
3143
- isFolder: false, // Use a folder icon. Also the node is expandable but not selectable.
3144
- isLazy: false, // Call onLazyRead(), when the node is expanded for the first time to allow for delayed creation of children.
3145
- tooltip: null, // Show this popup text.
3146
- href: null, // Added to the generated <a> tag.
3147
- icon: null, // Use a custom image (filename relative to tree.options.imagePath). 'null' for default icon, 'false' for no icon.
3148
- addClass: null, // Class name added to the node's span tag.
3149
- noLink: false, // Use <span> instead of <a> tag for this node
3150
- activate: false, // Initial active status.
3151
- focus: false, // Initial focused status.
3152
- expand: false, // Initial expanded status.
3153
- select: false, // Initial selected status.
3154
- hideCheckbox: false, // Suppress checkbox display for this node.
3155
- unselectable: false, // Prevent selection.
3156
- // disabled: false,
3157
- // The following attributes are only valid if passed to some functions:
3158
- children: null, // Array of child nodes.
3159
- // NOTE: we can also add custom attributes here.
3160
- // This may then also be used in the onActivate(), onSelect() or onLazyTree() callbacks.
3161
- // ------------------------------------------------------------------------
3162
- lastentry: undefined
3163
- };
3164
-
3165
- /*******************************************************************************
3166
- * Drag and drop support
3167
- */
3168
- function _initDragAndDrop(tree) {
3169
- var dnd = tree.options.dnd || null;
3170
- // Register 'connectToDynatree' option with ui.draggable
3171
- if(dnd && (dnd.onDragStart || dnd.onDrop)) {
3172
- _registerDnd();
3173
- }
3174
- // Attach ui.draggable to this Dynatree instance
3175
- if(dnd && dnd.onDragStart ) {
3176
- tree.$tree.draggable({
3177
- addClasses: false,
3178
- appendTo: "body",
3179
- containment: false,
3180
- delay: 0,
3181
- distance: 4,
3182
- revert: false,
3183
- scroll: true, // issue 244: enable scrolling (if ul.dynatree-container)
3184
- scrollSpeed: 7,
3185
- scrollSensitivity: 10,
3186
- // Delegate draggable.start, drag, and stop events to our handler
3187
- connectToDynatree: true,
3188
- // Let source tree create the helper element
3189
- helper: function(event) {
3190
- var sourceNode = $.ui.dynatree.getNode(event.target);
3191
- if(!sourceNode){ // issue 211
3192
- return "<div></div>";
3193
- }
3194
- return sourceNode.tree._onDragEvent("helper", sourceNode, null, event, null, null);
3195
- },
3196
- start: function(event, ui) {
3197
- // var sourceNode = $.ui.dynatree.getNode(event.target);
3198
- // don't return false if sourceNode == null (see issue 268)
3199
- },
3200
- _last: null
3201
- });
3202
- }
3203
- // Attach ui.droppable to this Dynatree instance
3204
- if(dnd && dnd.onDrop) {
3205
- tree.$tree.droppable({
3206
- addClasses: false,
3207
- tolerance: "intersect",
3208
- greedy: false,
3209
- _last: null
3210
- });
3211
- }
3212
- }
3213
-
3214
- //--- Extend ui.draggable event handling --------------------------------------
3215
- var didRegisterDnd = false;
3216
- var _registerDnd = function() {
3217
- if(didRegisterDnd){
3218
- return;
3219
- }
3220
- // Register proxy-functions for draggable.start/drag/stop
3221
- $.ui.plugin.add("draggable", "connectToDynatree", {
3222
- start: function(event, ui) {
3223
- var draggable = $(this).data("draggable"),
3224
- sourceNode = ui.helper.data("dtSourceNode") || null;
3225
- // logMsg("draggable-connectToDynatree.start, %s", sourceNode);
3226
- // logMsg(" this: %o", this);
3227
- // logMsg(" event: %o", event);
3228
- // logMsg(" draggable: %o", draggable);
3229
- // logMsg(" ui: %o", ui);
3230
-
3231
- if(sourceNode) {
3232
- // Adjust helper offset, so cursor is slightly outside top/left corner
3233
- // draggable.offset.click.top -= event.target.offsetTop;
3234
- // draggable.offset.click.left -= event.target.offsetLeft;
3235
- draggable.offset.click.top = -2;
3236
- draggable.offset.click.left = + 16;
3237
- // logMsg(" draggable2: %o", draggable);
3238
- // logMsg(" draggable.offset.click FIXED: %s/%s", draggable.offset.click.left, draggable.offset.click.top);
3239
- // Trigger onDragStart event
3240
- // TODO: when called as connectTo..., the return value is ignored(?)
3241
- return sourceNode.tree._onDragEvent("start", sourceNode, null, event, ui, draggable);
3242
- }
3243
- },
3244
- drag: function(event, ui) {
3245
- var draggable = $(this).data("draggable"),
3246
- sourceNode = ui.helper.data("dtSourceNode") || null,
3247
- prevTargetNode = ui.helper.data("dtTargetNode") || null,
3248
- targetNode = $.ui.dynatree.getNode(event.target);
3249
- // logMsg("$.ui.dynatree.getNode(%o): %s", event.target, targetNode);
3250
- // logMsg("connectToDynatree.drag: helper: %o", ui.helper[0]);
3251
- if(event.target && !targetNode){
3252
- // We got a drag event, but the targetNode could not be found
3253
- // at the event location. This may happen,
3254
- // 1. if the mouse jumped over the drag helper,
3255
- // 2. or if non-dynatree element is dragged
3256
- // We ignore it:
3257
- var isHelper = $(event.target).closest("div.dynatree-drag-helper,#dynatree-drop-marker").length > 0;
3258
- if(isHelper){
3259
- // logMsg("Drag event over helper: ignored.");
3260
- return;
3261
- }
3262
- }
3263
- // logMsg("draggable-connectToDynatree.drag: targetNode(from event): %s, dtTargetNode: %s", targetNode, ui.helper.data("dtTargetNode"));
3264
- ui.helper.data("dtTargetNode", targetNode);
3265
- // Leaving a tree node
3266
- if(prevTargetNode && prevTargetNode !== targetNode ) {
3267
- prevTargetNode.tree._onDragEvent("leave", prevTargetNode, sourceNode, event, ui, draggable);
3268
- }
3269
- if(targetNode){
3270
- if(!targetNode.tree.options.dnd.onDrop) {
3271
- // not enabled as drop target
3272
- noop(); // Keep JSLint happy
3273
- } else if(targetNode === prevTargetNode) {
3274
- // Moving over same node
3275
- targetNode.tree._onDragEvent("over", targetNode, sourceNode, event, ui, draggable);
3276
- }else{
3277
- // Entering this node first time
3278
- targetNode.tree._onDragEvent("enter", targetNode, sourceNode, event, ui, draggable);
3279
- }
3280
- }
3281
- // else go ahead with standard event handling
3282
- },
3283
- stop: function(event, ui) {
3284
- var draggable = $(this).data("draggable"),
3285
- sourceNode = ui.helper.data("dtSourceNode") || null,
3286
- targetNode = ui.helper.data("dtTargetNode") || null,
3287
- mouseDownEvent = draggable._mouseDownEvent,
3288
- eventType = event.type,
3289
- dropped = (eventType == "mouseup" && event.which == 1);
3290
- // logMsg("draggable-connectToDynatree.stop: targetNode(from event): %s, dtTargetNode: %s", targetNode, ui.helper.data("dtTargetNode"));
3291
- // logMsg("draggable-connectToDynatree.stop, %s", sourceNode);
3292
- // logMsg(" type: %o, downEvent: %o, upEvent: %o", eventType, mouseDownEvent, event);
3293
- // logMsg(" targetNode: %o", targetNode);
3294
- if(!dropped){
3295
- logMsg("Drag was cancelled");
3296
- }
3297
- if(targetNode) {
3298
- if(dropped){
3299
- targetNode.tree._onDragEvent("drop", targetNode, sourceNode, event, ui, draggable);
3300
- }
3301
- targetNode.tree._onDragEvent("leave", targetNode, sourceNode, event, ui, draggable);
3302
- }
3303
- if(sourceNode){
3304
- sourceNode.tree._onDragEvent("stop", sourceNode, null, event, ui, draggable);
3305
- }
3306
- }
3307
- });
3308
- didRegisterDnd = true;
3309
- };
3310
-
3311
- // ---------------------------------------------------------------------------
3312
- })(jQuery);