parlement 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/CHANGES +16 -0
  2. data/README +36 -3
  3. data/Rakefile +8 -12
  4. data/app/controllers/account_controller.rb +2 -0
  5. data/app/controllers/elt_controller.rb +1 -5
  6. data/app/controllers/subscriber_controller.rb +1 -1
  7. data/app/helpers/elt_helper.rb +30 -10
  8. data/app/models/elt.rb +2 -1
  9. data/app/models/mail.rb +41 -41
  10. data/app/models/mail_notify.rb +27 -10
  11. data/app/views/account/_login.rhtml +9 -7
  12. data/app/views/account/_show.rhtml +4 -4
  13. data/app/views/elt/_elt.rhtml +52 -51
  14. data/app/views/elt/_list.rhtml +22 -14
  15. data/app/views/elt/new.rhtml +1 -1
  16. data/app/views/elt/show.rhtml +15 -16
  17. data/app/views/layouts/top.rhtml +13 -1
  18. data/app/views/person/show.rhtml +1 -7
  19. data/config/boot.rb +32 -7
  20. data/config/database.yml +3 -0
  21. data/config/environment.rb +3 -1
  22. data/config/environments/development.rb +1 -1
  23. data/db/ROOT/parlement/ddRing.txt +14 -0
  24. data/db/ROOT/parlement/top-politics.txt +12 -0
  25. data/db/ROOT/perso.txt +1 -1
  26. data/db/development_structure.sql +30 -16
  27. data/db/schema.rb +18 -10
  28. data/db/schema.sql +34 -34
  29. data/public/javascripts/application.js +2 -0
  30. data/public/javascripts/blank.gif +0 -0
  31. data/public/javascripts/borders.js +687 -0
  32. data/public/javascripts/controls.js +95 -30
  33. data/public/javascripts/dragdrop.js +161 -21
  34. data/public/javascripts/effects.js +310 -211
  35. data/public/javascripts/ie7-load.htc +1 -0
  36. data/public/javascripts/prototype.js +228 -28
  37. data/test/fixtures/attachments.yml +3 -0
  38. data/test/fixtures/mail/mail_ruby +1 -0
  39. data/test/fixtures/people.yml +14 -0
  40. data/test/functional/account_controller_test.rb +3 -2
  41. data/test/unit/mail_notify_test.rb +2 -0
  42. data/test/unit/mail_test.rb +59 -6
  43. data/test/unit/person_test.rb +1 -1
  44. data/vendor/plugins/engines/CHANGELOG +92 -0
  45. data/vendor/plugins/engines/MIT-LICENSE +21 -0
  46. data/vendor/plugins/engines/README +325 -39
  47. data/vendor/plugins/engines/generators/engine/USAGE +26 -0
  48. data/vendor/plugins/engines/generators/engine/engine_generator.rb +199 -0
  49. data/vendor/plugins/engines/generators/engine/templates/README +85 -0
  50. data/vendor/plugins/engines/generators/engine/templates/init_engine.erb +13 -0
  51. data/vendor/plugins/engines/generators/engine/templates/install.erb +4 -0
  52. data/vendor/plugins/engines/generators/engine/templates/lib/engine.erb +6 -0
  53. data/vendor/plugins/engines/generators/engine/templates/licenses/GPL +18 -0
  54. data/vendor/plugins/engines/generators/engine/templates/licenses/LGPL +19 -0
  55. data/vendor/plugins/engines/generators/engine/templates/licenses/MIT +22 -0
  56. data/vendor/plugins/engines/generators/engine/templates/licenses/None +1 -0
  57. data/vendor/plugins/engines/generators/engine/templates/public/javascripts/engine.js +0 -0
  58. data/vendor/plugins/engines/generators/engine/templates/public/stylesheets/engine.css +0 -0
  59. data/vendor/plugins/engines/generators/engine/templates/tasks/engine.rake +0 -0
  60. data/vendor/plugins/engines/generators/engine/templates/test/test_helper.erb +13 -0
  61. data/vendor/plugins/engines/init.rb +18 -3
  62. data/vendor/plugins/engines/lib/bundles/require_resource.rb +124 -0
  63. data/vendor/plugins/engines/lib/bundles.rb +77 -0
  64. data/vendor/plugins/engines/lib/{action_mailer_extensions.rb → engines/action_mailer_extensions.rb} +15 -36
  65. data/vendor/plugins/engines/lib/{action_view_extensions.rb → engines/action_view_extensions.rb} +40 -33
  66. data/vendor/plugins/engines/lib/engines/active_record_extensions.rb +19 -0
  67. data/vendor/plugins/engines/lib/engines/dependencies_extensions.rb +118 -0
  68. data/vendor/plugins/engines/lib/engines/migration_extensions.rb +53 -0
  69. data/vendor/plugins/engines/lib/{ruby_extensions.rb → engines/ruby_extensions.rb} +14 -28
  70. data/vendor/plugins/engines/lib/engines/testing_extensions.rb +323 -0
  71. data/vendor/plugins/engines/lib/engines.rb +258 -148
  72. data/vendor/plugins/engines/tasks/engines.rake +161 -0
  73. data/vendor/plugins/engines/test/action_view_extensions_test.rb +9 -0
  74. data/vendor/plugins/engines/test/ruby_extensions_test.rb +24 -3
  75. data/vendor/plugins/guid/README.TXT +14 -4
  76. data/vendor/plugins/guid/init.rb +9 -2
  77. data/vendor/plugins/guid/lib/uuidtools.rb +22 -15
  78. data/vendor/plugins/login_engine/CHANGELOG +14 -0
  79. data/vendor/plugins/login_engine/README +93 -7
  80. data/vendor/plugins/login_engine/app/controllers/user_controller.rb +30 -20
  81. data/vendor/plugins/login_engine/app/helpers/user_helper.rb +1 -1
  82. data/vendor/plugins/login_engine/app/views/user/forgot_password.rhtml +2 -2
  83. data/vendor/plugins/login_engine/db/migrate/001_initial_schema.rb +25 -0
  84. data/vendor/plugins/login_engine/install.rb +4 -0
  85. data/vendor/plugins/login_engine/lib/login_engine/authenticated_system.rb +11 -5
  86. data/vendor/plugins/login_engine/lib/login_engine/authenticated_user.rb +15 -9
  87. data/vendor/plugins/login_engine/lib/login_engine.rb +7 -3
  88. data/vendor/plugins/login_engine/test/functional/user_controller_test.rb +22 -19
  89. data/vendor/plugins/login_engine/test/test_helper.rb +4 -8
  90. data/vendor/plugins/login_engine/test/unit/user_test.rb +31 -11
  91. metadata +60 -57
  92. data/app/models/attachment.rb +0 -6
  93. data/public/attachment/file/architecture.png +0 -0
  94. data/public/attachment/file/architecture.svg +0 -8972
  95. data/public/attachment/file/security.svg +0 -8960
  96. data/public/engine_files/login_engine/stylesheets/login_engine.css +0 -81
  97. data/public/oldREADME +0 -190
  98. data/public/stylesheets/default.css +0 -235
  99. data/public/stylesheets/live_tree.css +0 -62
  100. data/public/stylesheets/scaffold.css +0 -74
  101. data/script/about +0 -3
  102. data/script/benchmarker +0 -19
  103. data/script/breakpointer +0 -3
  104. data/script/console +0 -3
  105. data/script/create_db +0 -7
  106. data/script/destroy +0 -3
  107. data/script/generate +0 -3
  108. data/script/performance/benchmarker +0 -3
  109. data/script/performance/profiler +0 -3
  110. data/script/plugin +0 -3
  111. data/script/process/reaper +0 -3
  112. data/script/process/spawner +0 -3
  113. data/script/process/spinner +0 -3
  114. data/script/profiler +0 -34
  115. data/script/runner +0 -3
  116. data/script/server +0 -3
  117. data/test/unit/user_test.rb +0 -94
  118. data/vendor/plugins/engines/lib/dependencies_extensions.rb +0 -56
  119. data/vendor/plugins/engines/lib/testing_extensions.rb +0 -33
  120. data/vendor/plugins/login_engine/db/schema.rb +0 -25
  121. data/vendor/plugins/login_engine/test/fixtures/templates/users.yml +0 -41
  122. /data/public/images/{eltBackground.png → eltBackground.jng} +0 -0
@@ -141,8 +141,8 @@ Autocompleter.Base.prototype = {
141
141
  return;
142
142
  }
143
143
  else
144
- if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)
145
- return;
144
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
145
+ (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
146
146
 
147
147
  this.changed = true;
148
148
  this.hasFocus = true;
@@ -152,6 +152,12 @@ Autocompleter.Base.prototype = {
152
152
  setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
153
153
  },
154
154
 
155
+ activate: function() {
156
+ this.changed = false;
157
+ this.hasFocus = true;
158
+ this.getUpdatedChoices();
159
+ },
160
+
155
161
  onHover: function(event) {
156
162
  var element = Event.findElement(event, 'LI');
157
163
  if(this.index != element.autocompleteIndex)
@@ -221,8 +227,13 @@ Autocompleter.Base.prototype = {
221
227
  this.options.updateElement(selectedElement);
222
228
  return;
223
229
  }
224
-
225
- var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
230
+ var value = '';
231
+ if (this.options.select) {
232
+ var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
233
+ if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
234
+ } else
235
+ value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
236
+
226
237
  var lastTokenPos = this.findLastToken();
227
238
  if (lastTokenPos != -1) {
228
239
  var newValue = this.element.value.substr(0, lastTokenPos + 1);
@@ -305,7 +316,7 @@ Autocompleter.Base.prototype = {
305
316
  Ajax.Autocompleter = Class.create();
306
317
  Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
307
318
  initialize: function(element, update, url, options) {
308
- this.baseInitialize(element, update, options);
319
+ this.baseInitialize(element, update, options);
309
320
  this.options.asynchronous = true;
310
321
  this.options.onComplete = this.onComplete.bind(this);
311
322
  this.options.defaultParams = this.options.parameters || null;
@@ -448,7 +459,9 @@ Ajax.InPlaceEditor.prototype = {
448
459
  this.element = $(element);
449
460
 
450
461
  this.options = Object.extend({
462
+ okButton: true,
451
463
  okText: "ok",
464
+ cancelLink: true,
452
465
  cancelText: "cancel",
453
466
  savingText: "Saving...",
454
467
  clickToEditText: "Click to edit",
@@ -470,8 +483,10 @@ Ajax.InPlaceEditor.prototype = {
470
483
  formClassName: 'inplaceeditor-form',
471
484
  highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
472
485
  highlightendcolor: "#FFFFFF",
473
- externalControl: null,
474
- ajaxOptions: {}
486
+ externalControl: null,
487
+ submitOnBlur: false,
488
+ ajaxOptions: {},
489
+ evalScripts: false
475
490
  }, options || {});
476
491
 
477
492
  if(!this.options.formId && this.element.id) {
@@ -536,16 +551,22 @@ Ajax.InPlaceEditor.prototype = {
536
551
  this.form.appendChild(br);
537
552
  }
538
553
 
539
- okButton = document.createElement("input");
540
- okButton.type = "submit";
541
- okButton.value = this.options.okText;
542
- this.form.appendChild(okButton);
554
+ if (this.options.okButton) {
555
+ okButton = document.createElement("input");
556
+ okButton.type = "submit";
557
+ okButton.value = this.options.okText;
558
+ okButton.className = 'editor_ok_button';
559
+ this.form.appendChild(okButton);
560
+ }
543
561
 
544
- cancelLink = document.createElement("a");
545
- cancelLink.href = "#";
546
- cancelLink.appendChild(document.createTextNode(this.options.cancelText));
547
- cancelLink.onclick = this.onclickCancel.bind(this);
548
- this.form.appendChild(cancelLink);
562
+ if (this.options.cancelLink) {
563
+ cancelLink = document.createElement("a");
564
+ cancelLink.href = "#";
565
+ cancelLink.appendChild(document.createTextNode(this.options.cancelText));
566
+ cancelLink.onclick = this.onclickCancel.bind(this);
567
+ cancelLink.className = 'editor_cancel';
568
+ this.form.appendChild(cancelLink);
569
+ }
549
570
  },
550
571
  hasHTMLLineBreaks: function(string) {
551
572
  if (!this.options.handleLineBreaks) return false;
@@ -561,24 +582,34 @@ Ajax.InPlaceEditor.prototype = {
561
582
  } else {
562
583
  text = this.getText();
563
584
  }
585
+
586
+ var obj = this;
564
587
 
565
588
  if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
566
589
  this.options.textarea = false;
567
590
  var textField = document.createElement("input");
591
+ textField.obj = this;
568
592
  textField.type = "text";
569
593
  textField.name = "value";
570
594
  textField.value = text;
571
595
  textField.style.backgroundColor = this.options.highlightcolor;
596
+ textField.className = 'editor_field';
572
597
  var size = this.options.size || this.options.cols || 0;
573
598
  if (size != 0) textField.size = size;
599
+ if (this.options.submitOnBlur)
600
+ textField.onblur = this.onSubmit.bind(this);
574
601
  this.editField = textField;
575
602
  } else {
576
603
  this.options.textarea = true;
577
604
  var textArea = document.createElement("textarea");
605
+ textArea.obj = this;
578
606
  textArea.name = "value";
579
607
  textArea.value = this.convertHTMLLineBreaks(text);
580
608
  textArea.rows = this.options.rows;
581
609
  textArea.cols = this.options.cols || 40;
610
+ textArea.className = 'editor_field';
611
+ if (this.options.submitOnBlur)
612
+ textArea.onblur = this.onSubmit.bind(this);
582
613
  this.editField = textArea;
583
614
  }
584
615
 
@@ -629,19 +660,26 @@ Ajax.InPlaceEditor.prototype = {
629
660
  // to be displayed indefinitely
630
661
  this.onLoading();
631
662
 
632
- new Ajax.Updater(
633
- {
634
- success: this.element,
635
- // don't update on failure (this could be an option)
636
- failure: null
637
- },
638
- this.url,
639
- Object.extend({
640
- parameters: this.options.callback(form, value),
641
- onComplete: this.onComplete.bind(this),
642
- onFailure: this.onFailure.bind(this)
643
- }, this.options.ajaxOptions)
644
- );
663
+ if (this.options.evalScripts) {
664
+ new Ajax.Request(
665
+ this.url, Object.extend({
666
+ parameters: this.options.callback(form, value),
667
+ onComplete: this.onComplete.bind(this),
668
+ onFailure: this.onFailure.bind(this),
669
+ asynchronous:true,
670
+ evalScripts:true
671
+ }, this.options.ajaxOptions));
672
+ } else {
673
+ new Ajax.Updater(
674
+ { success: this.element,
675
+ // don't update on failure (this could be an option)
676
+ failure: null },
677
+ this.url, Object.extend({
678
+ parameters: this.options.callback(form, value),
679
+ onComplete: this.onComplete.bind(this),
680
+ onFailure: this.onFailure.bind(this)
681
+ }, this.options.ajaxOptions));
682
+ }
645
683
  // stop the event to avoid a page refresh in Safari
646
684
  if (arguments.length > 1) {
647
685
  Event.stop(arguments[0]);
@@ -723,6 +761,33 @@ Ajax.InPlaceEditor.prototype = {
723
761
  }
724
762
  };
725
763
 
764
+ Ajax.InPlaceCollectionEditor = Class.create();
765
+ Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
766
+ Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
767
+ createEditField: function() {
768
+ if (!this.cached_selectTag) {
769
+ var selectTag = document.createElement("select");
770
+ var collection = this.options.collection || [];
771
+ var optionTag;
772
+ collection.each(function(e,i) {
773
+ optionTag = document.createElement("option");
774
+ optionTag.value = (e instanceof Array) ? e[0] : e;
775
+ if(this.options.value==optionTag.value) optionTag.selected = true;
776
+ optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
777
+ selectTag.appendChild(optionTag);
778
+ }.bind(this));
779
+ this.cached_selectTag = selectTag;
780
+ }
781
+
782
+ this.editField = this.cached_selectTag;
783
+ if(this.options.loadTextURL) this.loadExternalText();
784
+ this.form.appendChild(this.editField);
785
+ this.options.callback = function(form, value) {
786
+ return "value=" + encodeURIComponent(value);
787
+ }
788
+ }
789
+ });
790
+
726
791
  // Delayed observer, like Form.Element.Observer,
727
792
  // but waits for delay after last key input
728
793
  // Ideal for live-search fields
@@ -747,4 +812,4 @@ Form.Element.DelayedObserver.prototype = {
747
812
  this.timer = null;
748
813
  this.callback(this.element, $F(this.element));
749
814
  }
750
- };
815
+ };
@@ -128,7 +128,7 @@ var Draggables = {
128
128
  this.activeDraggable = draggable;
129
129
  },
130
130
 
131
- deactivate: function(draggbale) {
131
+ deactivate: function() {
132
132
  this.activeDraggable = null;
133
133
  },
134
134
 
@@ -146,6 +146,7 @@ var Draggables = {
146
146
  if(!this.activeDraggable) return;
147
147
  this._lastPointer = null;
148
148
  this.activeDraggable.endDrag(event);
149
+ this.activeDraggable = null;
149
150
  },
150
151
 
151
152
  keyPress: function(event) {
@@ -191,22 +192,28 @@ Draggable.prototype = {
191
192
  },
192
193
  reverteffect: function(element, top_offset, left_offset) {
193
194
  var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
194
- element._revert = new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur});
195
+ element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur});
195
196
  },
196
197
  endeffect: function(element) {
197
198
  new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
198
199
  },
199
200
  zindex: 1000,
200
201
  revert: false,
202
+ scroll: false,
203
+ scrollSensitivity: 20,
204
+ scrollSpeed: 15,
201
205
  snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
202
206
  }, arguments[1] || {});
203
207
 
204
208
  this.element = $(element);
205
209
 
206
210
  if(options.handle && (typeof options.handle == 'string'))
207
- this.handle = Element.childrenWithClassName(this.element, options.handle)[0];
211
+ this.handle = Element.childrenWithClassName(this.element, options.handle, true)[0];
208
212
  if(!this.handle) this.handle = $(options.handle);
209
213
  if(!this.handle) this.handle = this.element;
214
+
215
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML)
216
+ options.scroll = $(options.scroll);
210
217
 
211
218
  Element.makePositioned(this.element); // fix IE
212
219
 
@@ -227,8 +234,8 @@ Draggable.prototype = {
227
234
 
228
235
  currentDelta: function() {
229
236
  return([
230
- parseInt(this.element.style.left || '0'),
231
- parseInt(this.element.style.top || '0')]);
237
+ parseInt(Element.getStyle(this.element,'left') || '0'),
238
+ parseInt(Element.getStyle(this.element,'top') || '0')]);
232
239
  },
233
240
 
234
241
  initDrag: function(event) {
@@ -238,6 +245,7 @@ Draggable.prototype = {
238
245
  if(src.tagName && (
239
246
  src.tagName=='INPUT' ||
240
247
  src.tagName=='SELECT' ||
248
+ src.tagName=='OPTION' ||
241
249
  src.tagName=='BUTTON' ||
242
250
  src.tagName=='TEXTAREA')) return;
243
251
 
@@ -269,6 +277,17 @@ Draggable.prototype = {
269
277
  this.element.parentNode.insertBefore(this._clone, this.element);
270
278
  }
271
279
 
280
+ if(this.options.scroll) {
281
+ if (this.options.scroll == window) {
282
+ var where = this._getWindowScroll(this.options.scroll);
283
+ this.originalScrollLeft = where.left;
284
+ this.originalScrollTop = where.top;
285
+ } else {
286
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
287
+ this.originalScrollTop = this.options.scroll.scrollTop;
288
+ }
289
+ }
290
+
272
291
  Draggables.notify('onStart', this, event);
273
292
  if(this.options.starteffect) this.options.starteffect(this.element);
274
293
  },
@@ -281,8 +300,30 @@ Draggable.prototype = {
281
300
  this.draw(pointer);
282
301
  if(this.options.change) this.options.change(this);
283
302
 
303
+ if(this.options.scroll) {
304
+ this.stopScrolling();
305
+
306
+ var p;
307
+ if (this.options.scroll == window) {
308
+ with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
309
+ } else {
310
+ p = Position.page(this.options.scroll);
311
+ p[0] += this.options.scroll.scrollLeft;
312
+ p[1] += this.options.scroll.scrollTop;
313
+ p.push(p[0]+this.options.scroll.offsetWidth);
314
+ p.push(p[1]+this.options.scroll.offsetHeight);
315
+ }
316
+ var speed = [0,0];
317
+ if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
318
+ if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
319
+ if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
320
+ if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
321
+ this.startScrolling(speed);
322
+ }
323
+
284
324
  // fix AppleWebKit rendering
285
325
  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
326
+
286
327
  Event.stop(event);
287
328
  },
288
329
 
@@ -320,13 +361,14 @@ Draggable.prototype = {
320
361
  },
321
362
 
322
363
  keyPress: function(event) {
323
- if(!event.keyCode==Event.KEY_ESC) return;
364
+ if(event.keyCode!=Event.KEY_ESC) return;
324
365
  this.finishDrag(event, false);
325
366
  Event.stop(event);
326
367
  },
327
368
 
328
369
  endDrag: function(event) {
329
370
  if(!this.dragging) return;
371
+ this.stopScrolling();
330
372
  this.finishDrag(event, true);
331
373
  Event.stop(event);
332
374
  },
@@ -336,7 +378,14 @@ Draggable.prototype = {
336
378
  var d = this.currentDelta();
337
379
  pos[0] -= d[0]; pos[1] -= d[1];
338
380
 
339
- var p = [0,1].map(function(i){ return (point[i]-pos[i]-this.offset[i]) }.bind(this));
381
+ if(this.options.scroll && (this.options.scroll != window)) {
382
+ pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
383
+ pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
384
+ }
385
+
386
+ var p = [0,1].map(function(i){
387
+ return (point[i]-pos[i]-this.offset[i])
388
+ }.bind(this));
340
389
 
341
390
  if(this.options.snap) {
342
391
  if(typeof this.options.snap == 'function') {
@@ -357,6 +406,67 @@ Draggable.prototype = {
357
406
  if((!this.options.constraint) || (this.options.constraint=='vertical'))
358
407
  style.top = p[1] + "px";
359
408
  if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
409
+ },
410
+
411
+ stopScrolling: function() {
412
+ if(this.scrollInterval) {
413
+ clearInterval(this.scrollInterval);
414
+ this.scrollInterval = null;
415
+ }
416
+ },
417
+
418
+ startScrolling: function(speed) {
419
+ this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
420
+ this.lastScrolled = new Date();
421
+ this.scrollInterval = setInterval(this.scroll.bind(this), 10);
422
+ },
423
+
424
+ scroll: function() {
425
+ var current = new Date();
426
+ var delta = current - this.lastScrolled;
427
+ this.lastScrolled = current;
428
+ if(this.options.scroll == window) {
429
+ with (this._getWindowScroll(this.options.scroll)) {
430
+ if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
431
+ var d = delta / 1000;
432
+ this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
433
+ }
434
+ }
435
+ } else {
436
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
437
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
438
+ }
439
+
440
+ Position.prepare();
441
+ Droppables.show(Draggables._lastPointer, this.element);
442
+ Draggables.notify('onDrag', this);
443
+ this.draw(Draggables._lastPointer);
444
+
445
+ if(this.options.change) this.options.change(this);
446
+ },
447
+
448
+ _getWindowScroll: function(w) {
449
+ var T, L, W, H;
450
+ with (w.document) {
451
+ if (w.document.documentElement && documentElement.scrollTop) {
452
+ T = documentElement.scrollTop;
453
+ L = documentElement.scrollLeft;
454
+ } else if (w.document.body) {
455
+ T = body.scrollTop;
456
+ L = body.scrollLeft;
457
+ }
458
+ if (w.innerWidth) {
459
+ W = w.innerWidth;
460
+ H = w.innerHeight;
461
+ } else if (w.document.documentElement && documentElement.clientWidth) {
462
+ W = documentElement.clientWidth;
463
+ H = documentElement.clientHeight;
464
+ } else {
465
+ W = body.offsetWidth;
466
+ H = body.offsetHeight
467
+ }
468
+ }
469
+ return { top: T, left: L, width: W, height: H };
360
470
  }
361
471
  }
362
472
 
@@ -413,7 +523,10 @@ var Sortable = {
413
523
  only: false,
414
524
  hoverclass: null,
415
525
  ghosting: false,
416
- format: null,
526
+ scroll: false,
527
+ scrollSensitivity: 20,
528
+ scrollSpeed: 15,
529
+ format: /^[^_]*_(.*)$/,
417
530
  onChange: Prototype.emptyFunction,
418
531
  onUpdate: Prototype.emptyFunction
419
532
  }, arguments[1] || {});
@@ -424,6 +537,9 @@ var Sortable = {
424
537
  // build options for the draggables
425
538
  var options_for_draggable = {
426
539
  revert: true,
540
+ scroll: options.scroll,
541
+ scrollSpeed: options.scrollSpeed,
542
+ scrollSensitivity: options.scrollSensitivity,
427
543
  ghosting: options.ghosting,
428
544
  constraint: options.constraint,
429
545
  handle: options.handle };
@@ -491,9 +607,10 @@ var Sortable = {
491
607
  findElements: function(element, options) {
492
608
  if(!element.hasChildNodes()) return null;
493
609
  var elements = [];
610
+ var only = options.only ? [options.only].flatten() : null;
494
611
  $A(element.childNodes).each( function(e) {
495
612
  if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
496
- (!options.only || (Element.hasClassName(e, options.only))))
613
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
497
614
  elements.push(e);
498
615
  if(options.tree) {
499
616
  var grandchildren = this.findElements(e, options);
@@ -567,18 +684,41 @@ var Sortable = {
567
684
  Element.show(Sortable._marker);
568
685
  },
569
686
 
570
- serialize: function(element) {
687
+ sequence: function(element) {
571
688
  element = $(element);
572
- var sortableOptions = this.options(element);
573
- var options = Object.extend({
574
- tag: sortableOptions.tag,
575
- only: sortableOptions.only,
576
- name: element.id,
577
- format: sortableOptions.format || /^[^_]*_(.*)$/
578
- }, arguments[1] || {});
689
+ var options = Object.extend(this.options(element), arguments[1] || {});
690
+
579
691
  return $(this.findElements(element, options) || []).map( function(item) {
580
- return (encodeURIComponent(options.name) + "[]=" +
581
- encodeURIComponent(item.id.match(options.format) ? item.id.match(options.format)[1] : ''));
582
- }).join("&");
692
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
693
+ });
694
+ },
695
+
696
+ setSequence: function(element, new_sequence) {
697
+ element = $(element);
698
+ var options = Object.extend(this.options(element), arguments[2] || {});
699
+
700
+ var nodeMap = {};
701
+ this.findElements(element, options).each( function(n) {
702
+ if (n.id.match(options.format))
703
+ nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
704
+ n.parentNode.removeChild(n);
705
+ });
706
+
707
+ new_sequence.each(function(ident) {
708
+ var n = nodeMap[ident];
709
+ if (n) {
710
+ n[1].appendChild(n[0]);
711
+ delete nodeMap[ident];
712
+ }
713
+ });
714
+ },
715
+
716
+ serialize: function(element) {
717
+ element = $(element);
718
+ var name = encodeURIComponent(
719
+ (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('&');
583
723
  }
584
- }
724
+ }