parlement 0.10 → 0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/CHANGES +11 -0
  2. data/MEMORY +9 -1
  3. data/README +5 -4
  4. data/app/controllers/account_controller.rb +10 -13
  5. data/app/controllers/application.rb +4 -5
  6. data/app/controllers/elt_controller.rb +9 -7
  7. data/app/controllers/person_controller.rb +1 -3
  8. data/app/controllers/subscriber_controller.rb +10 -10
  9. data/app/helpers/elt_helper.rb +2 -0
  10. data/app/models/elt.rb +28 -19
  11. data/app/models/mail.rb +26 -14
  12. data/app/models/mail_notify.rb +5 -4
  13. data/app/models/person.rb +11 -2
  14. data/app/views/account/_login.rhtml +3 -3
  15. data/app/views/account/_show.rhtml +12 -14
  16. data/app/views/elt/_choice.rhtml +3 -3
  17. data/app/views/elt/_elt.rhtml +4 -4
  18. data/app/views/elt/_list.rhtml +2 -2
  19. data/app/views/elt/_listByDate.rhtml +1 -1
  20. data/app/views/elt/_listByVote.rhtml +1 -1
  21. data/app/views/elt/new.rhtml +3 -3
  22. data/app/views/elt/show.rhtml +2 -2
  23. data/app/views/layouts/top.rhtml +6 -0
  24. data/app/views/mail_notify/publish.text.html.rhtml +1 -1
  25. data/app/views/person/_listElts.rhtml +5 -3
  26. data/app/views/person/show.rhtml +1 -2
  27. data/config/boot.rb +5 -4
  28. data/config/environment.rb +6 -4
  29. data/config/routes.rb +3 -2
  30. data/db/development_structure.sql +15 -4
  31. data/db/migrate/006_last_activity.rb +10 -0
  32. data/db/schema.rb +67 -49
  33. data/public/dispatch.fcgi +1 -0
  34. data/public/javascripts/controls.js +41 -23
  35. data/public/javascripts/dragdrop.js +317 -99
  36. data/public/javascripts/effects.js +301 -166
  37. data/public/javascripts/prototype.js +932 -402
  38. data/public/stylesheets/default.css +3 -2
  39. data/test/unit/elt_test.rb +13 -0
  40. data/test/unit/mail_test.rb +3 -1
  41. data/vendor/plugins/engines/CHANGELOG +203 -99
  42. data/vendor/plugins/engines/MIT-LICENSE +1 -1
  43. data/vendor/plugins/engines/README +32 -384
  44. data/vendor/plugins/engines/Rakefile +14 -0
  45. data/vendor/plugins/engines/UPGRADING +93 -0
  46. data/vendor/plugins/engines/about.yml +7 -0
  47. data/vendor/plugins/engines/generators/plugin_migration/USAGE +45 -0
  48. data/vendor/plugins/engines/generators/plugin_migration/plugin_migration_generator.rb +79 -0
  49. data/vendor/plugins/engines/generators/plugin_migration/templates/plugin_migration.erb +13 -0
  50. data/vendor/plugins/engines/init.rb +34 -47
  51. data/vendor/plugins/engines/install.rb +32 -0
  52. data/vendor/plugins/engines/lib/engines/{ruby_extensions.rb → deprecated_config_support.rb} +135 -113
  53. data/vendor/plugins/engines/lib/engines/plugin.rb +214 -0
  54. data/vendor/plugins/engines/lib/engines/plugin_list.rb +31 -0
  55. data/vendor/plugins/engines/lib/engines/plugin_migrator.rb +60 -0
  56. data/vendor/plugins/engines/lib/engines/rails_extensions/active_record.rb +19 -0
  57. data/vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb +143 -0
  58. data/vendor/plugins/engines/lib/engines/rails_extensions/migrations.rb +155 -0
  59. data/vendor/plugins/engines/lib/engines/rails_extensions/public_asset_helpers.rb +116 -0
  60. data/vendor/plugins/engines/lib/engines/rails_extensions/rails.rb +20 -0
  61. data/vendor/plugins/engines/lib/engines/rails_extensions/rails_initializer.rb +86 -0
  62. data/vendor/plugins/engines/lib/engines/rails_extensions/routing.rb +77 -0
  63. data/vendor/plugins/engines/lib/engines/rails_extensions/templates.rb +140 -0
  64. data/vendor/plugins/engines/lib/engines/rails_extensions.rb +6 -0
  65. data/vendor/plugins/engines/lib/engines/testing.rb +88 -0
  66. data/vendor/plugins/engines/lib/engines.rb +281 -425
  67. data/vendor/plugins/engines/tasks/engines.rake +108 -137
  68. metadata +218 -250
  69. data/db/ROOT/perso.txt +0 -214
  70. data/public/images/indicator.gif +0 -0
  71. data/public/images/orange_by_darren_Hester_350o.jpg +0 -0
  72. data/public/images/smile.png +0 -0
  73. data/vendor/plugins/engines/generators/engine/USAGE +0 -26
  74. data/vendor/plugins/engines/generators/engine/engine_generator.rb +0 -199
  75. data/vendor/plugins/engines/generators/engine/templates/README +0 -85
  76. data/vendor/plugins/engines/generators/engine/templates/init_engine.erb +0 -15
  77. data/vendor/plugins/engines/generators/engine/templates/install.erb +0 -4
  78. data/vendor/plugins/engines/generators/engine/templates/lib/engine.erb +0 -6
  79. data/vendor/plugins/engines/generators/engine/templates/licenses/GPL +0 -18
  80. data/vendor/plugins/engines/generators/engine/templates/licenses/LGPL +0 -19
  81. data/vendor/plugins/engines/generators/engine/templates/licenses/MIT +0 -22
  82. data/vendor/plugins/engines/generators/engine/templates/licenses/None +0 -1
  83. data/vendor/plugins/engines/generators/engine/templates/public/javascripts/engine.js +0 -0
  84. data/vendor/plugins/engines/generators/engine/templates/public/stylesheets/engine.css +0 -0
  85. data/vendor/plugins/engines/generators/engine/templates/tasks/engine.rake +0 -0
  86. data/vendor/plugins/engines/generators/engine/templates/test/test_helper.erb +0 -17
  87. data/vendor/plugins/engines/lib/bundles/require_resource.rb +0 -124
  88. data/vendor/plugins/engines/lib/bundles.rb +0 -77
  89. data/vendor/plugins/engines/lib/engines/action_mailer_extensions.rb +0 -140
  90. data/vendor/plugins/engines/lib/engines/action_view_extensions.rb +0 -141
  91. data/vendor/plugins/engines/lib/engines/active_record_extensions.rb +0 -21
  92. data/vendor/plugins/engines/lib/engines/dependencies_extensions.rb +0 -129
  93. data/vendor/plugins/engines/lib/engines/migration_extensions.rb +0 -53
  94. data/vendor/plugins/engines/lib/engines/routing_extensions.rb +0 -28
  95. data/vendor/plugins/engines/lib/engines/testing_extensions.rb +0 -327
  96. data/vendor/plugins/engines/tasks/deprecated_engines.rake +0 -7
  97. data/vendor/plugins/engines/test/action_view_extensions_test.rb +0 -9
  98. data/vendor/plugins/engines/test/ruby_extensions_test.rb +0 -115
  99. data/vendor/plugins/guid/README.TXT +0 -29
  100. data/vendor/plugins/guid/init.rb +0 -30
  101. data/vendor/plugins/guid/lib/usesguid.rb +0 -37
  102. data/vendor/plugins/guid/lib/uuid22.rb +0 -43
  103. data/vendor/plugins/guid/lib/uuidtools.rb +0 -572
  104. data/vendor/plugins/responds_to_parent/MIT-LICENSE +0 -20
  105. data/vendor/plugins/responds_to_parent/README +0 -42
  106. data/vendor/plugins/responds_to_parent/Rakefile +0 -22
  107. data/vendor/plugins/responds_to_parent/init.rb +0 -1
  108. data/vendor/plugins/responds_to_parent/lib/responds_to_parent.rb +0 -46
  109. data/vendor/plugins/responds_to_parent/test/responds_to_parent_test.rb +0 -115
@@ -1,8 +1,11 @@
1
- // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
1
+ // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
+ // (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
2
3
  //
3
- // See scriptaculous.js for full license.
4
+ // script.aculo.us is freely distributable under the terms of an MIT-style license.
5
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
4
6
 
5
- /*--------------------------------------------------------------------------*/
7
+ if(typeof Effect == 'undefined')
8
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
6
9
 
7
10
  var Droppables = {
8
11
  drops: [],
@@ -15,7 +18,8 @@ var Droppables = {
15
18
  element = $(element);
16
19
  var options = Object.extend({
17
20
  greedy: true,
18
- hoverclass: null
21
+ hoverclass: null,
22
+ tree: false
19
23
  }, arguments[1] || {});
20
24
 
21
25
  // cache containers
@@ -37,12 +41,27 @@ var Droppables = {
37
41
 
38
42
  this.drops.push(options);
39
43
  },
44
+
45
+ findDeepestChild: function(drops) {
46
+ deepest = drops[0];
47
+
48
+ for (i = 1; i < drops.length; ++i)
49
+ if (Element.isParent(drops[i].element, deepest.element))
50
+ deepest = drops[i];
51
+
52
+ return deepest;
53
+ },
40
54
 
41
55
  isContained: function(element, drop) {
42
- var parentNode = element.parentNode;
43
- return drop._containers.detect(function(c) { return parentNode == c });
56
+ var containmentNode;
57
+ if(drop.tree) {
58
+ containmentNode = element.treeNode;
59
+ } else {
60
+ containmentNode = element.parentNode;
61
+ }
62
+ return drop._containers.detect(function(c) { return containmentNode == c });
44
63
  },
45
-
64
+
46
65
  isAffected: function(point, element, drop) {
47
66
  return (
48
67
  (drop.element!=element) &&
@@ -68,18 +87,22 @@ var Droppables = {
68
87
 
69
88
  show: function(point, element) {
70
89
  if(!this.drops.length) return;
90
+ var affected = [];
71
91
 
72
92
  if(this.last_active) this.deactivate(this.last_active);
73
93
  this.drops.each( function(drop) {
74
- if(Droppables.isAffected(point, element, drop)) {
75
- if(drop.onHover)
76
- drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
77
- if(drop.greedy) {
78
- Droppables.activate(drop);
79
- throw $break;
80
- }
81
- }
94
+ if(Droppables.isAffected(point, element, drop))
95
+ affected.push(drop);
82
96
  });
97
+
98
+ if(affected.length>0) {
99
+ drop = Droppables.findDeepestChild(affected);
100
+ Position.within(drop.element, point[0], point[1]);
101
+ if(drop.onHover)
102
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
103
+
104
+ Droppables.activate(drop);
105
+ }
83
106
  },
84
107
 
85
108
  fire: function(event, element) {
@@ -124,8 +147,16 @@ var Draggables = {
124
147
  },
125
148
 
126
149
  activate: function(draggable) {
127
- window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
128
- this.activeDraggable = draggable;
150
+ if(draggable.options.delay) {
151
+ this._timeout = setTimeout(function() {
152
+ Draggables._timeout = null;
153
+ window.focus();
154
+ Draggables.activeDraggable = draggable;
155
+ }.bind(this), draggable.options.delay);
156
+ } else {
157
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
158
+ this.activeDraggable = draggable;
159
+ }
129
160
  },
130
161
 
131
162
  deactivate: function() {
@@ -139,10 +170,15 @@ var Draggables = {
139
170
  // the same coordinates, prevent needless redrawing (moz bug?)
140
171
  if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
141
172
  this._lastPointer = pointer;
173
+
142
174
  this.activeDraggable.updateDrag(event, pointer);
143
175
  },
144
176
 
145
177
  endDrag: function(event) {
178
+ if(this._timeout) {
179
+ clearTimeout(this._timeout);
180
+ this._timeout = null;
181
+ }
146
182
  if(!this.activeDraggable) return;
147
183
  this._lastPointer = null;
148
184
  this.activeDraggable.endDrag(event);
@@ -169,6 +205,7 @@ var Draggables = {
169
205
  this.observers.each( function(o) {
170
206
  if(o[eventName]) o[eventName](eventName, draggable, event);
171
207
  });
208
+ if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
172
209
  },
173
210
 
174
211
  _cacheObserverCallbacks: function() {
@@ -183,37 +220,59 @@ var Draggables = {
183
220
  /*--------------------------------------------------------------------------*/
184
221
 
185
222
  var Draggable = Class.create();
223
+ Draggable._dragging = {};
224
+
186
225
  Draggable.prototype = {
187
226
  initialize: function(element) {
188
- var options = Object.extend({
227
+ var defaults = {
189
228
  handle: false,
190
- starteffect: function(element) {
191
- new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
192
- },
193
229
  reverteffect: function(element, top_offset, left_offset) {
194
230
  var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
195
- element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur});
231
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
232
+ queue: {scope:'_draggable', position:'end'}
233
+ });
196
234
  },
197
- endeffect: function(element) {
198
- new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
235
+ endeffect: function(element) {
236
+ var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
237
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
238
+ queue: {scope:'_draggable', position:'end'},
239
+ afterFinish: function(){
240
+ Draggable._dragging[element] = false
241
+ }
242
+ });
199
243
  },
200
244
  zindex: 1000,
201
245
  revert: false,
202
246
  scroll: false,
203
247
  scrollSensitivity: 20,
204
248
  scrollSpeed: 15,
205
- snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
206
- }, arguments[1] || {});
249
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
250
+ delay: 0
251
+ };
252
+
253
+ if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
254
+ Object.extend(defaults, {
255
+ starteffect: function(element) {
256
+ element._opacity = Element.getOpacity(element);
257
+ Draggable._dragging[element] = true;
258
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
259
+ }
260
+ });
261
+
262
+ var options = Object.extend(defaults, arguments[1] || {});
207
263
 
208
264
  this.element = $(element);
209
265
 
210
266
  if(options.handle && (typeof options.handle == 'string'))
211
- this.handle = Element.childrenWithClassName(this.element, options.handle, true)[0];
267
+ this.handle = this.element.down('.'+options.handle, 0);
268
+
212
269
  if(!this.handle) this.handle = $(options.handle);
213
270
  if(!this.handle) this.handle = this.element;
214
271
 
215
- if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML)
272
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
216
273
  options.scroll = $(options.scroll);
274
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
275
+ }
217
276
 
218
277
  Element.makePositioned(this.element); // fix IE
219
278
 
@@ -239,6 +298,8 @@ Draggable.prototype = {
239
298
  },
240
299
 
241
300
  initDrag: function(event) {
301
+ if(typeof Draggable._dragging[this.element] != 'undefined' &&
302
+ Draggable._dragging[this.element]) return;
242
303
  if(Event.isLeftClick(event)) {
243
304
  // abort on form elements, fixes a Firefox issue
244
305
  var src = Event.element(event);
@@ -249,11 +310,6 @@ Draggable.prototype = {
249
310
  src.tagName=='BUTTON' ||
250
311
  src.tagName=='TEXTAREA')) return;
251
312
 
252
- if(this.element._revert) {
253
- this.element._revert.cancel();
254
- this.element._revert = null;
255
- }
256
-
257
313
  var pointer = [Event.pointerX(event), Event.pointerY(event)];
258
314
  var pos = Position.cumulativeOffset(this.element);
259
315
  this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
@@ -289,6 +345,7 @@ Draggable.prototype = {
289
345
  }
290
346
 
291
347
  Draggables.notify('onStart', this, event);
348
+
292
349
  if(this.options.starteffect) this.options.starteffect(this.element);
293
350
  },
294
351
 
@@ -297,6 +354,7 @@ Draggable.prototype = {
297
354
  Position.prepare();
298
355
  Droppables.show(pointer, this.element);
299
356
  Draggables.notify('onDrag', this, event);
357
+
300
358
  this.draw(pointer);
301
359
  if(this.options.change) this.options.change(this);
302
360
 
@@ -308,8 +366,8 @@ Draggable.prototype = {
308
366
  with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
309
367
  } else {
310
368
  p = Position.page(this.options.scroll);
311
- p[0] += this.options.scroll.scrollLeft;
312
- p[1] += this.options.scroll.scrollTop;
369
+ p[0] += this.options.scroll.scrollLeft + Position.deltaX;
370
+ p[1] += this.options.scroll.scrollTop + Position.deltaY;
313
371
  p.push(p[0]+this.options.scroll.offsetWidth);
314
372
  p.push(p[1]+this.options.scroll.offsetHeight);
315
373
  }
@@ -355,7 +413,7 @@ Draggable.prototype = {
355
413
 
356
414
  if(this.options.endeffect)
357
415
  this.options.endeffect(this.element);
358
-
416
+
359
417
  Draggables.deactivate(this);
360
418
  Droppables.reset();
361
419
  },
@@ -375,10 +433,15 @@ Draggable.prototype = {
375
433
 
376
434
  draw: function(point) {
377
435
  var pos = Position.cumulativeOffset(this.element);
436
+ if(this.options.ghosting) {
437
+ var r = Position.realOffset(this.element);
438
+ pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
439
+ }
440
+
378
441
  var d = this.currentDelta();
379
442
  pos[0] -= d[0]; pos[1] -= d[1];
380
443
 
381
- if(this.options.scroll && (this.options.scroll != window)) {
444
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
382
445
  pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
383
446
  pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
384
447
  }
@@ -389,7 +452,7 @@ Draggable.prototype = {
389
452
 
390
453
  if(this.options.snap) {
391
454
  if(typeof this.options.snap == 'function') {
392
- p = this.options.snap(p[0],p[1]);
455
+ p = this.options.snap(p[0],p[1],this);
393
456
  } else {
394
457
  if(this.options.snap instanceof Array) {
395
458
  p = p.map( function(v, i) {
@@ -405,6 +468,7 @@ Draggable.prototype = {
405
468
  style.left = p[0] + "px";
406
469
  if((!this.options.constraint) || (this.options.constraint=='vertical'))
407
470
  style.top = p[1] + "px";
471
+
408
472
  if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
409
473
  },
410
474
 
@@ -412,10 +476,12 @@ Draggable.prototype = {
412
476
  if(this.scrollInterval) {
413
477
  clearInterval(this.scrollInterval);
414
478
  this.scrollInterval = null;
479
+ Draggables._lastScrollPointer = null;
415
480
  }
416
481
  },
417
482
 
418
483
  startScrolling: function(speed) {
484
+ if(!(speed[0] || speed[1])) return;
419
485
  this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
420
486
  this.lastScrolled = new Date();
421
487
  this.scrollInterval = setInterval(this.scroll.bind(this), 10);
@@ -440,7 +506,16 @@ Draggable.prototype = {
440
506
  Position.prepare();
441
507
  Droppables.show(Draggables._lastPointer, this.element);
442
508
  Draggables.notify('onDrag', this);
443
- this.draw(Draggables._lastPointer);
509
+ if (this._isScrollChild) {
510
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
511
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
512
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
513
+ if (Draggables._lastScrollPointer[0] < 0)
514
+ Draggables._lastScrollPointer[0] = 0;
515
+ if (Draggables._lastScrollPointer[1] < 0)
516
+ Draggables._lastScrollPointer[1] = 0;
517
+ this.draw(Draggables._lastScrollPointer);
518
+ }
444
519
 
445
520
  if(this.options.change) this.options.change(this);
446
521
  },
@@ -492,41 +567,55 @@ SortableObserver.prototype = {
492
567
  }
493
568
 
494
569
  var Sortable = {
495
- sortables: new Array(),
570
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
496
571
 
497
- options: function(element){
498
- element = $(element);
499
- return this.sortables.detect(function(s) { return s.element == element });
572
+ sortables: {},
573
+
574
+ _findRootElement: function(element) {
575
+ while (element.tagName != "BODY") {
576
+ if(element.id && Sortable.sortables[element.id]) return element;
577
+ element = element.parentNode;
578
+ }
579
+ },
580
+
581
+ options: function(element) {
582
+ element = Sortable._findRootElement($(element));
583
+ if(!element) return;
584
+ return Sortable.sortables[element.id];
500
585
  },
501
586
 
502
587
  destroy: function(element){
503
- element = $(element);
504
- this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
588
+ var s = Sortable.options(element);
589
+
590
+ if(s) {
505
591
  Draggables.removeObserver(s.element);
506
592
  s.droppables.each(function(d){ Droppables.remove(d) });
507
593
  s.draggables.invoke('destroy');
508
- });
509
- this.sortables = this.sortables.reject(function(s) { return s.element == element });
594
+
595
+ delete Sortable.sortables[s.element.id];
596
+ }
510
597
  },
511
-
598
+
512
599
  create: function(element) {
513
600
  element = $(element);
514
601
  var options = Object.extend({
515
602
  element: element,
516
603
  tag: 'li', // assumes li children, override with tag: 'tagname'
517
604
  dropOnEmpty: false,
518
- tree: false, // fixme: unimplemented
605
+ tree: false,
606
+ treeTag: 'ul',
519
607
  overlap: 'vertical', // one of 'vertical', 'horizontal'
520
608
  constraint: 'vertical', // one of 'vertical', 'horizontal', false
521
609
  containment: element, // also takes array of elements (or id's); or false
522
610
  handle: false, // or a CSS class
523
611
  only: false,
612
+ delay: 0,
524
613
  hoverclass: null,
525
614
  ghosting: false,
526
615
  scroll: false,
527
616
  scrollSensitivity: 20,
528
617
  scrollSpeed: 15,
529
- format: /^[^_]*_(.*)$/,
618
+ format: this.SERIALIZE_RULE,
530
619
  onChange: Prototype.emptyFunction,
531
620
  onUpdate: Prototype.emptyFunction
532
621
  }, arguments[1] || {});
@@ -540,6 +629,7 @@ var Sortable = {
540
629
  scroll: options.scroll,
541
630
  scrollSpeed: options.scrollSpeed,
542
631
  scrollSensitivity: options.scrollSensitivity,
632
+ delay: options.delay,
543
633
  ghosting: options.ghosting,
544
634
  constraint: options.constraint,
545
635
  handle: options.handle };
@@ -565,9 +655,16 @@ var Sortable = {
565
655
  var options_for_droppable = {
566
656
  overlap: options.overlap,
567
657
  containment: options.containment,
658
+ tree: options.tree,
568
659
  hoverclass: options.hoverclass,
569
- onHover: Sortable.onHover,
570
- greedy: !options.dropOnEmpty
660
+ onHover: Sortable.onHover
661
+ }
662
+
663
+ var options_for_tree = {
664
+ onHover: Sortable.onEmptyHover,
665
+ overlap: options.overlap,
666
+ containment: options.containment,
667
+ hoverclass: options.hoverclass
571
668
  }
572
669
 
573
670
  // fix for gecko engine
@@ -576,27 +673,33 @@ var Sortable = {
576
673
  options.draggables = [];
577
674
  options.droppables = [];
578
675
 
579
- // make it so
580
-
581
676
  // drop on empty handling
582
- if(options.dropOnEmpty) {
583
- Droppables.add(element,
584
- {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
677
+ if(options.dropOnEmpty || options.tree) {
678
+ Droppables.add(element, options_for_tree);
585
679
  options.droppables.push(element);
586
680
  }
587
681
 
588
682
  (this.findElements(element, options) || []).each( function(e) {
589
683
  // handles are per-draggable
590
684
  var handle = options.handle ?
591
- Element.childrenWithClassName(e, options.handle)[0] : e;
685
+ $(e).down('.'+options.handle,0) : e;
592
686
  options.draggables.push(
593
687
  new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
594
688
  Droppables.add(e, options_for_droppable);
689
+ if(options.tree) e.treeNode = element;
595
690
  options.droppables.push(e);
596
691
  });
692
+
693
+ if(options.tree) {
694
+ (Sortable.findTreeElements(element, options) || []).each( function(e) {
695
+ Droppables.add(e, options_for_tree);
696
+ e.treeNode = element;
697
+ options.droppables.push(e);
698
+ });
699
+ }
597
700
 
598
701
  // keep reference
599
- this.sortables.push(options);
702
+ this.sortables[element.id] = options;
600
703
 
601
704
  // for onupdate
602
705
  Draggables.addObserver(new SortableObserver(element, options.onUpdate));
@@ -605,24 +708,21 @@ var Sortable = {
605
708
 
606
709
  // return all suitable-for-sortable elements in a guaranteed order
607
710
  findElements: function(element, options) {
608
- if(!element.hasChildNodes()) return null;
609
- var elements = [];
610
- var only = options.only ? [options.only].flatten() : null;
611
- $A(element.childNodes).each( function(e) {
612
- if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
613
- (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
614
- elements.push(e);
615
- if(options.tree) {
616
- var grandchildren = this.findElements(e, options);
617
- if(grandchildren) elements.push(grandchildren);
618
- }
619
- });
620
-
621
- return (elements.length>0 ? elements.flatten() : null);
711
+ return Element.findChildren(
712
+ element, options.only, options.tree ? true : false, options.tag);
713
+ },
714
+
715
+ findTreeElements: function(element, options) {
716
+ return Element.findChildren(
717
+ element, options.only, options.tree ? true : false, options.treeTag);
622
718
  },
623
719
 
624
720
  onHover: function(element, dropon, overlap) {
625
- if(overlap>0.5) {
721
+ if(Element.isParent(dropon, element)) return;
722
+
723
+ if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
724
+ return;
725
+ } else if(overlap>0.5) {
626
726
  Sortable.mark(dropon, 'before');
627
727
  if(dropon.previousSibling != element) {
628
728
  var oldParentNode = element.parentNode;
@@ -645,18 +745,42 @@ var Sortable = {
645
745
  }
646
746
  }
647
747
  },
648
-
649
- onEmptyHover: function(element, dropon) {
650
- if(element.parentNode!=dropon) {
651
- var oldParentNode = element.parentNode;
652
- dropon.appendChild(element);
748
+
749
+ onEmptyHover: function(element, dropon, overlap) {
750
+ var oldParentNode = element.parentNode;
751
+ var droponOptions = Sortable.options(dropon);
752
+
753
+ if(!Element.isParent(dropon, element)) {
754
+ var index;
755
+
756
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
757
+ var child = null;
758
+
759
+ if(children) {
760
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
761
+
762
+ for (index = 0; index < children.length; index += 1) {
763
+ if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
764
+ offset -= Element.offsetSize (children[index], droponOptions.overlap);
765
+ } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
766
+ child = index + 1 < children.length ? children[index + 1] : null;
767
+ break;
768
+ } else {
769
+ child = children[index];
770
+ break;
771
+ }
772
+ }
773
+ }
774
+
775
+ dropon.insertBefore(element, child);
776
+
653
777
  Sortable.options(oldParentNode).onChange(element);
654
- Sortable.options(dropon).onChange(element);
778
+ droponOptions.onChange(element);
655
779
  }
656
780
  },
657
781
 
658
782
  unmark: function() {
659
- if(Sortable._marker) Element.hide(Sortable._marker);
783
+ if(Sortable._marker) Sortable._marker.hide();
660
784
  },
661
785
 
662
786
  mark: function(dropon, position) {
@@ -665,23 +789,79 @@ var Sortable = {
665
789
  if(sortable && !sortable.ghosting) return;
666
790
 
667
791
  if(!Sortable._marker) {
668
- Sortable._marker = $('dropmarker') || document.createElement('DIV');
669
- Element.hide(Sortable._marker);
670
- Element.addClassName(Sortable._marker, 'dropmarker');
671
- Sortable._marker.style.position = 'absolute';
792
+ Sortable._marker =
793
+ ($('dropmarker') || Element.extend(document.createElement('DIV'))).
794
+ hide().addClassName('dropmarker').setStyle({position:'absolute'});
672
795
  document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
673
796
  }
674
797
  var offsets = Position.cumulativeOffset(dropon);
675
- Sortable._marker.style.left = offsets[0] + 'px';
676
- Sortable._marker.style.top = offsets[1] + 'px';
798
+ Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
677
799
 
678
800
  if(position=='after')
679
801
  if(sortable.overlap == 'horizontal')
680
- Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
802
+ Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
681
803
  else
682
- Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
804
+ Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
683
805
 
684
- Element.show(Sortable._marker);
806
+ Sortable._marker.show();
807
+ },
808
+
809
+ _tree: function(element, options, parent) {
810
+ var children = Sortable.findElements(element, options) || [];
811
+
812
+ for (var i = 0; i < children.length; ++i) {
813
+ var match = children[i].id.match(options.format);
814
+
815
+ if (!match) continue;
816
+
817
+ var child = {
818
+ id: encodeURIComponent(match ? match[1] : null),
819
+ element: element,
820
+ parent: parent,
821
+ children: [],
822
+ position: parent.children.length,
823
+ container: $(children[i]).down(options.treeTag)
824
+ }
825
+
826
+ /* Get the element containing the children and recurse over it */
827
+ if (child.container)
828
+ this._tree(child.container, options, child)
829
+
830
+ parent.children.push (child);
831
+ }
832
+
833
+ return parent;
834
+ },
835
+
836
+ tree: function(element) {
837
+ element = $(element);
838
+ var sortableOptions = this.options(element);
839
+ var options = Object.extend({
840
+ tag: sortableOptions.tag,
841
+ treeTag: sortableOptions.treeTag,
842
+ only: sortableOptions.only,
843
+ name: element.id,
844
+ format: sortableOptions.format
845
+ }, arguments[1] || {});
846
+
847
+ var root = {
848
+ id: null,
849
+ parent: null,
850
+ children: [],
851
+ container: element,
852
+ position: 0
853
+ }
854
+
855
+ return Sortable._tree(element, options, root);
856
+ },
857
+
858
+ /* Construct a [i] index for a particular node */
859
+ _constructIndex: function(node) {
860
+ var index = '';
861
+ do {
862
+ if (node.id) index = '[' + node.position + ']' + index;
863
+ } while ((node = node.parent) != null);
864
+ return index;
685
865
  },
686
866
 
687
867
  sequence: function(element) {
@@ -705,20 +885,58 @@ var Sortable = {
705
885
  });
706
886
 
707
887
  new_sequence.each(function(ident) {
708
- var n = nodeMap[ident];
709
- if (n) {
710
- n[1].appendChild(n[0]);
711
- delete nodeMap[ident];
712
- }
888
+ var n = nodeMap[ident];
889
+ if (n) {
890
+ n[1].appendChild(n[0]);
891
+ delete nodeMap[ident];
892
+ }
713
893
  });
714
894
  },
715
-
895
+
716
896
  serialize: function(element) {
717
897
  element = $(element);
898
+ var options = Object.extend(Sortable.options(element), arguments[1] || {});
718
899
  var name = encodeURIComponent(
719
900
  (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
720
- return Sortable.sequence(element, arguments[1]).map( function(item) {
721
- return name + "[]=" + encodeURIComponent(item);
722
- }).join('&');
901
+
902
+ if (options.tree) {
903
+ return Sortable.tree(element, arguments[1]).children.map( function (item) {
904
+ return [name + Sortable._constructIndex(item) + "[id]=" +
905
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
906
+ }).flatten().join('&');
907
+ } else {
908
+ return Sortable.sequence(element, arguments[1]).map( function(item) {
909
+ return name + "[]=" + encodeURIComponent(item);
910
+ }).join('&');
911
+ }
723
912
  }
724
913
  }
914
+
915
+ // Returns true if child is contained within element
916
+ Element.isParent = function(child, element) {
917
+ if (!child.parentNode || child == element) return false;
918
+ if (child.parentNode == element) return true;
919
+ return Element.isParent(child.parentNode, element);
920
+ }
921
+
922
+ Element.findChildren = function(element, only, recursive, tagName) {
923
+ if(!element.hasChildNodes()) return null;
924
+ tagName = tagName.toUpperCase();
925
+ if(only) only = [only].flatten();
926
+ var elements = [];
927
+ $A(element.childNodes).each( function(e) {
928
+ if(e.tagName && e.tagName.toUpperCase()==tagName &&
929
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
930
+ elements.push(e);
931
+ if(recursive) {
932
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
933
+ if(grandchildren) elements.push(grandchildren);
934
+ }
935
+ });
936
+
937
+ return (elements.length>0 ? elements.flatten() : []);
938
+ }
939
+
940
+ Element.offsetSize = function (element, type) {
941
+ return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
942
+ }