rails 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rails might be problematic. Click here for more details.

Files changed (46) hide show
  1. data/CHANGELOG +59 -10
  2. data/Rakefile +23 -11
  3. data/bin/console +6 -5
  4. data/bin/console_sandbox +0 -6
  5. data/bin/listener +86 -0
  6. data/bin/profiler +27 -10
  7. data/bin/rails +3 -1
  8. data/bin/runner +24 -0
  9. data/bin/server +1 -0
  10. data/bin/tracker +69 -0
  11. data/configs/database.yml +3 -0
  12. data/dispatches/dispatch.fcgi +22 -25
  13. data/dispatches/gateway.cgi +97 -0
  14. data/environments/development.rb +2 -0
  15. data/environments/environment.rb +1 -0
  16. data/environments/test.rb +2 -0
  17. data/fresh_rakefile +9 -4
  18. data/helpers/test_helper.rb +16 -5
  19. data/html/404.html +2 -0
  20. data/html/500.html +2 -0
  21. data/html/index.html +3 -0
  22. data/html/javascripts/controls.js +261 -0
  23. data/html/javascripts/dragdrop.js +476 -0
  24. data/html/javascripts/effects.js +570 -0
  25. data/html/javascripts/prototype.js +633 -371
  26. data/lib/console_sandbox.rb +6 -0
  27. data/lib/dispatcher.rb +13 -11
  28. data/lib/fcgi_handler.rb +166 -0
  29. data/lib/rails_generator/generators/applications/app/app_generator.rb +16 -12
  30. data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +2 -2
  31. data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +3 -1
  32. data/lib/rails_generator/generators/components/migration/USAGE +14 -0
  33. data/lib/rails_generator/generators/components/migration/migration_generator.rb +9 -0
  34. data/lib/rails_generator/generators/components/migration/templates/migration.rb +7 -0
  35. data/lib/rails_generator/generators/components/model/model_generator.rb +1 -1
  36. data/lib/rails_generator/generators/components/scaffold/USAGE +1 -1
  37. data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +11 -11
  38. data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +38 -20
  39. data/lib/rails_generator/generators/components/scaffold/templates/layout.rhtml +2 -0
  40. data/lib/rails_generator/generators/components/scaffold/templates/style.css +22 -1
  41. data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +2 -2
  42. data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +5 -5
  43. data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +1 -1
  44. data/lib/rubyprof_ext.rb +35 -0
  45. data/lib/webrick_server.rb +84 -43
  46. metadata +22 -8
@@ -1,4 +1,4 @@
1
- /* Prototype: an object-oriented Javascript library, version 1.2.1
1
+ /* Prototype JavaScript framework, version 1.3.0
2
2
  * (c) 2005 Sam Stephenson <sam@conio.net>
3
3
  *
4
4
  * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
@@ -11,7 +11,8 @@
11
11
  /*--------------------------------------------------------------------------*/
12
12
 
13
13
  var Prototype = {
14
- Version: '1.2.1'
14
+ Version: '1.3.0',
15
+ emptyFunction: function() {}
15
16
  }
16
17
 
17
18
  var Class = {
@@ -24,24 +25,28 @@ var Class = {
24
25
 
25
26
  var Abstract = new Object();
26
27
 
27
- Object.prototype.extend = function(object) {
28
- for (property in object) {
29
- this[property] = object[property];
28
+ Object.extend = function(destination, source) {
29
+ for (property in source) {
30
+ destination[property] = source[property];
30
31
  }
31
- return this;
32
+ return destination;
33
+ }
34
+
35
+ Object.prototype.extend = function(object) {
36
+ return Object.extend.apply(this, [this, object]);
32
37
  }
33
38
 
34
39
  Function.prototype.bind = function(object) {
35
- var method = this;
40
+ var __method = this;
36
41
  return function() {
37
- method.apply(object, arguments);
42
+ __method.apply(object, arguments);
38
43
  }
39
44
  }
40
45
 
41
46
  Function.prototype.bindAsEventListener = function(object) {
42
- var method = this;
47
+ var __method = this;
43
48
  return function(event) {
44
- method.call(object, event || window.event);
49
+ __method.call(object, event || window.event);
45
50
  }
46
51
  }
47
52
 
@@ -54,7 +59,7 @@ Number.prototype.toColorPart = function() {
54
59
  var Try = {
55
60
  these: function() {
56
61
  var returnValue;
57
-
62
+
58
63
  for (var i = 0; i < arguments.length; i++) {
59
64
  var lambda = arguments[i];
60
65
  try {
@@ -62,7 +67,7 @@ var Try = {
62
67
  break;
63
68
  } catch (e) {}
64
69
  }
65
-
70
+
66
71
  return returnValue;
67
72
  }
68
73
  }
@@ -75,14 +80,14 @@ PeriodicalExecuter.prototype = {
75
80
  this.callback = callback;
76
81
  this.frequency = frequency;
77
82
  this.currentlyExecuting = false;
78
-
83
+
79
84
  this.registerCallback();
80
85
  },
81
-
86
+
82
87
  registerCallback: function() {
83
- setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);
88
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
84
89
  },
85
-
90
+
86
91
  onTimerEvent: function() {
87
92
  if (!this.currentlyExecuting) {
88
93
  try {
@@ -92,8 +97,6 @@ PeriodicalExecuter.prototype = {
92
97
  this.currentlyExecuting = false;
93
98
  }
94
99
  }
95
-
96
- this.registerCallback();
97
100
  }
98
101
  }
99
102
 
@@ -101,7 +104,7 @@ PeriodicalExecuter.prototype = {
101
104
 
102
105
  function $() {
103
106
  var elements = new Array();
104
-
107
+
105
108
  for (var i = 0; i < arguments.length; i++) {
106
109
  var element = arguments[i];
107
110
  if (typeof element == 'string')
@@ -109,15 +112,13 @@ function $() {
109
112
 
110
113
  if (arguments.length == 1)
111
114
  return element;
112
-
115
+
113
116
  elements.push(element);
114
117
  }
115
-
118
+
116
119
  return elements;
117
120
  }
118
121
 
119
- /*--------------------------------------------------------------------------*/
120
-
121
122
  if (!Array.prototype.push) {
122
123
  Array.prototype.push = function() {
123
124
  var startLength = this.length;
@@ -135,10 +136,10 @@ if (!Function.prototype.apply) {
135
136
  if (!parameters) parameters = new Array();
136
137
 
137
138
  for (var i = 0; i < parameters.length; i++)
138
- parameterStrings[i] = 'x[' + i + ']';
139
+ parameterStrings[i] = 'parameters[' + i + ']';
139
140
 
140
141
  object.__apply__ = this;
141
- var result = eval('obj.__apply__(' +
142
+ var result = eval('object.__apply__(' +
142
143
  parameterStrings[i].join(', ') + ')');
143
144
  object.__apply__ = null;
144
145
 
@@ -146,7 +147,24 @@ if (!Function.prototype.apply) {
146
147
  }
147
148
  }
148
149
 
149
- /*--------------------------------------------------------------------------*/
150
+ String.prototype.extend({
151
+ stripTags: function() {
152
+ return this.replace(/<\/?[^>]+>/gi, '');
153
+ },
154
+
155
+ escapeHTML: function() {
156
+ var div = document.createElement('div');
157
+ var text = document.createTextNode(this);
158
+ div.appendChild(text);
159
+ return div.innerHTML;
160
+ },
161
+
162
+ unescapeHTML: function() {
163
+ var div = document.createElement('div');
164
+ div.innerHTML = this.stripTags();
165
+ return div.childNodes[0].nodeValue;
166
+ }
167
+ });
150
168
 
151
169
  var Ajax = {
152
170
  getTransport: function() {
@@ -155,9 +173,7 @@ var Ajax = {
155
173
  function() {return new ActiveXObject('Microsoft.XMLHTTP')},
156
174
  function() {return new XMLHttpRequest()}
157
175
  ) || false;
158
- },
159
-
160
- emptyFunction: function() {}
176
+ }
161
177
  }
162
178
 
163
179
  Ajax.Base = function() {};
@@ -168,6 +184,16 @@ Ajax.Base.prototype = {
168
184
  asynchronous: true,
169
185
  parameters: ''
170
186
  }.extend(options || {});
187
+ },
188
+
189
+ responseIsSuccess: function() {
190
+ return this.transport.status == undefined
191
+ || this.transport.status == 0
192
+ || (this.transport.status >= 200 && this.transport.status < 300);
193
+ },
194
+
195
+ responseIsFailure: function() {
196
+ return !this.responseIsSuccess();
171
197
  }
172
198
  }
173
199
 
@@ -179,80 +205,350 @@ Ajax.Request.prototype = (new Ajax.Base()).extend({
179
205
  initialize: function(url, options) {
180
206
  this.transport = Ajax.getTransport();
181
207
  this.setOptions(options);
182
-
208
+ this.request(url);
209
+ },
210
+
211
+ request: function(url) {
212
+ var parameters = this.options.parameters || '';
213
+ if (parameters.length > 0) parameters += '&_=';
214
+
183
215
  try {
184
216
  if (this.options.method == 'get')
185
- url += '?' + this.options.parameters + '&_=';
186
-
217
+ url += '?' + parameters;
218
+
187
219
  this.transport.open(this.options.method, url,
188
220
  this.options.asynchronous);
189
-
221
+
190
222
  if (this.options.asynchronous) {
191
223
  this.transport.onreadystatechange = this.onStateChange.bind(this);
192
224
  setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
193
225
  }
194
-
195
- this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
196
- this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version);
197
-
198
- if (this.options.method == 'post') {
199
- this.transport.setRequestHeader('Connection', 'close');
200
- this.transport.setRequestHeader('Content-type',
201
- 'application/x-www-form-urlencoded');
202
- }
203
-
204
- this.transport.send(this.options.method == 'post' ?
205
- this.options.parameters + '&_=' : null);
206
-
226
+
227
+ this.setRequestHeaders();
228
+
229
+ var body = this.options.postBody ? this.options.postBody : parameters;
230
+ this.transport.send(this.options.method == 'post' ? body : null);
231
+
207
232
  } catch (e) {
208
- }
233
+ }
209
234
  },
210
-
235
+
236
+ setRequestHeaders: function() {
237
+ var requestHeaders =
238
+ ['X-Requested-With', 'XMLHttpRequest',
239
+ 'X-Prototype-Version', Prototype.Version];
240
+
241
+ if (this.options.method == 'post') {
242
+ requestHeaders.push('Content-type',
243
+ 'application/x-www-form-urlencoded');
244
+
245
+ /* Force "Connection: close" for Mozilla browsers to work around
246
+ * a bug where XMLHttpReqeuest sends an incorrect Content-length
247
+ * header. See Mozilla Bugzilla #246651.
248
+ */
249
+ if (this.transport.overrideMimeType)
250
+ requestHeaders.push('Connection', 'close');
251
+ }
252
+
253
+ if (this.options.requestHeaders)
254
+ requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
255
+
256
+ for (var i = 0; i < requestHeaders.length; i += 2)
257
+ this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
258
+ },
259
+
211
260
  onStateChange: function() {
212
261
  var readyState = this.transport.readyState;
213
262
  if (readyState != 1)
214
263
  this.respondToReadyState(this.transport.readyState);
215
264
  },
216
-
265
+
217
266
  respondToReadyState: function(readyState) {
218
267
  var event = Ajax.Request.Events[readyState];
219
- (this.options['on' + event] || Ajax.emptyFunction)(this.transport);
268
+
269
+ if (event == 'Complete' && this.responseIsFailure())
270
+ (this.options['on' + this.transport.status]
271
+ || this.options.onFailure
272
+ || Prototype.emptyFunction)(this.transport);
273
+
274
+ (this.options['on' + event] || Prototype.emptyFunction)(this.transport);
220
275
  }
221
276
  });
222
277
 
223
278
  Ajax.Updater = Class.create();
224
- Ajax.Updater.prototype = (new Ajax.Base()).extend({
279
+ Ajax.Updater.ScriptFragment = '(?:<script.*?>)((\n|.)*?)(?:<\/script>)';
280
+
281
+ Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({
225
282
  initialize: function(container, url, options) {
226
- this.container = $(container);
227
- this.setOptions(options);
228
-
229
- if (this.options.asynchronous) {
230
- this.onComplete = this.options.onComplete;
231
- this.options.onComplete = this.updateContent.bind(this);
283
+ this.containers = {
284
+ success: container.success ? $(container.success) : $(container),
285
+ failure: container.failure ? $(container.failure) :
286
+ (container.success ? null : $(container))
232
287
  }
233
-
234
- this.request = new Ajax.Request(url, this.options);
235
-
236
- if (!this.options.asynchronous)
288
+
289
+ this.transport = Ajax.getTransport();
290
+ this.setOptions(options);
291
+
292
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
293
+ this.options.onComplete = (function() {
237
294
  this.updateContent();
295
+ onComplete(this.transport);
296
+ }).bind(this);
297
+
298
+ this.request(url);
238
299
  },
239
-
300
+
240
301
  updateContent: function() {
241
- if (this.options.insertion) {
242
- new this.options.insertion(this.container,
243
- this.request.transport.responseText);
244
- } else {
245
- this.container.innerHTML = this.request.transport.responseText;
302
+ var receiver = this.responseIsSuccess() ?
303
+ this.containers.success : this.containers.failure;
304
+
305
+ var match = new RegExp(Ajax.Updater.ScriptFragment, 'img');
306
+ var response = this.transport.responseText.replace(match, '');
307
+ var scripts = this.transport.responseText.match(match);
308
+
309
+ if (receiver) {
310
+ if (this.options.insertion) {
311
+ new this.options.insertion(receiver, response);
312
+ } else {
313
+ receiver.innerHTML = response;
314
+ }
315
+ }
316
+
317
+ if (this.responseIsSuccess()) {
318
+ if (this.onComplete)
319
+ setTimeout((function() {this.onComplete(
320
+ this.transport)}).bind(this), 10);
321
+ }
322
+
323
+ if (this.options.evalScripts && scripts) {
324
+ match = new RegExp(Ajax.Updater.ScriptFragment, 'im');
325
+ setTimeout((function() {
326
+ for (var i = 0; i < scripts.length; i++)
327
+ eval(scripts[i].match(match)[1]);
328
+ }).bind(this), 10);
329
+ }
330
+ }
331
+ });
332
+
333
+ Ajax.PeriodicalUpdater = Class.create();
334
+ Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({
335
+ initialize: function(container, url, options) {
336
+ this.setOptions(options);
337
+ this.onComplete = this.options.onComplete;
338
+
339
+ this.frequency = (this.options.frequency || 2);
340
+ this.decay = 1;
341
+
342
+ this.updater = {};
343
+ this.container = container;
344
+ this.url = url;
345
+
346
+ this.start();
347
+ },
348
+
349
+ start: function() {
350
+ this.options.onComplete = this.updateComplete.bind(this);
351
+ this.onTimerEvent();
352
+ },
353
+
354
+ stop: function() {
355
+ this.updater.onComplete = undefined;
356
+ clearTimeout(this.timer);
357
+ (this.onComplete || Ajax.emptyFunction).apply(this, arguments);
358
+ },
359
+
360
+ updateComplete: function(request) {
361
+ if (this.options.decay) {
362
+ this.decay = (request.responseText == this.lastText ?
363
+ this.decay * this.options.decay : 1);
364
+
365
+ this.lastText = request.responseText;
366
+ }
367
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
368
+ this.decay * this.frequency * 1000);
369
+ },
370
+
371
+ onTimerEvent: function() {
372
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
373
+ }
374
+ });
375
+
376
+ document.getElementsByClassName = function(className) {
377
+ var children = document.getElementsByTagName('*') || document.all;
378
+ var elements = new Array();
379
+
380
+ for (var i = 0; i < children.length; i++) {
381
+ var child = children[i];
382
+ var classNames = child.className.split(' ');
383
+ for (var j = 0; j < classNames.length; j++) {
384
+ if (classNames[j] == className) {
385
+ elements.push(child);
386
+ break;
387
+ }
246
388
  }
389
+ }
390
+
391
+ return elements;
392
+ }
393
+
394
+ /*--------------------------------------------------------------------------*/
247
395
 
248
- if (this.onComplete) {
249
- setTimeout((function() {this.onComplete(this.request)}).bind(this), 10);
396
+ if (!window.Element) {
397
+ var Element = new Object();
398
+ }
399
+
400
+ Object.extend(Element, {
401
+ toggle: function() {
402
+ for (var i = 0; i < arguments.length; i++) {
403
+ var element = $(arguments[i]);
404
+ element.style.display =
405
+ (element.style.display == 'none' ? '' : 'none');
406
+ }
407
+ },
408
+
409
+ hide: function() {
410
+ for (var i = 0; i < arguments.length; i++) {
411
+ var element = $(arguments[i]);
412
+ element.style.display = 'none';
413
+ }
414
+ },
415
+
416
+ show: function() {
417
+ for (var i = 0; i < arguments.length; i++) {
418
+ var element = $(arguments[i]);
419
+ element.style.display = '';
420
+ }
421
+ },
422
+
423
+ remove: function(element) {
424
+ element = $(element);
425
+ element.parentNode.removeChild(element);
426
+ },
427
+
428
+ getHeight: function(element) {
429
+ element = $(element);
430
+ return element.offsetHeight;
431
+ },
432
+
433
+ hasClassName: function(element, className) {
434
+ element = $(element);
435
+ if (!element)
436
+ return;
437
+ var a = element.className.split(' ');
438
+ for (var i = 0; i < a.length; i++) {
439
+ if (a[i] == className)
440
+ return true;
441
+ }
442
+ return false;
443
+ },
444
+
445
+ addClassName: function(element, className) {
446
+ element = $(element);
447
+ Element.removeClassName(element, className);
448
+ element.className += ' ' + className;
449
+ },
450
+
451
+ removeClassName: function(element, className) {
452
+ element = $(element);
453
+ if (!element)
454
+ return;
455
+ var newClassName = '';
456
+ var a = element.className.split(' ');
457
+ for (var i = 0; i < a.length; i++) {
458
+ if (a[i] != className) {
459
+ if (i > 0)
460
+ newClassName += ' ';
461
+ newClassName += a[i];
462
+ }
463
+ }
464
+ element.className = newClassName;
465
+ },
466
+
467
+ // removes whitespace-only text node children
468
+ cleanWhitespace: function(element) {
469
+ var element = $(element);
470
+ for (var i = 0; i < element.childNodes.length; i++) {
471
+ var node = element.childNodes[i];
472
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
473
+ Element.remove(node);
250
474
  }
251
475
  }
252
476
  });
253
477
 
478
+ var Toggle = new Object();
479
+ Toggle.display = Element.toggle;
480
+
254
481
  /*--------------------------------------------------------------------------*/
255
482
 
483
+ Abstract.Insertion = function(adjacency) {
484
+ this.adjacency = adjacency;
485
+ }
486
+
487
+ Abstract.Insertion.prototype = {
488
+ initialize: function(element, content) {
489
+ this.element = $(element);
490
+ this.content = content;
491
+
492
+ if (this.adjacency && this.element.insertAdjacentHTML) {
493
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
494
+ } else {
495
+ this.range = this.element.ownerDocument.createRange();
496
+ if (this.initializeRange) this.initializeRange();
497
+ this.fragment = this.range.createContextualFragment(this.content);
498
+ this.insertContent();
499
+ }
500
+ }
501
+ }
502
+
503
+ var Insertion = new Object();
504
+
505
+ Insertion.Before = Class.create();
506
+ Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
507
+ initializeRange: function() {
508
+ this.range.setStartBefore(this.element);
509
+ },
510
+
511
+ insertContent: function() {
512
+ this.element.parentNode.insertBefore(this.fragment, this.element);
513
+ }
514
+ });
515
+
516
+ Insertion.Top = Class.create();
517
+ Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
518
+ initializeRange: function() {
519
+ this.range.selectNodeContents(this.element);
520
+ this.range.collapse(true);
521
+ },
522
+
523
+ insertContent: function() {
524
+ this.element.insertBefore(this.fragment, this.element.firstChild);
525
+ }
526
+ });
527
+
528
+ Insertion.Bottom = Class.create();
529
+ Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
530
+ initializeRange: function() {
531
+ this.range.selectNodeContents(this.element);
532
+ this.range.collapse(this.element);
533
+ },
534
+
535
+ insertContent: function() {
536
+ this.element.appendChild(this.fragment);
537
+ }
538
+ });
539
+
540
+ Insertion.After = Class.create();
541
+ Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
542
+ initializeRange: function() {
543
+ this.range.setStartAfter(this.element);
544
+ },
545
+
546
+ insertContent: function() {
547
+ this.element.parentNode.insertBefore(this.fragment,
548
+ this.element.nextSibling);
549
+ }
550
+ });
551
+
256
552
  var Field = {
257
553
  clear: function() {
258
554
  for (var i = 0; i < arguments.length; i++)
@@ -296,7 +592,7 @@ var Form = {
296
592
  },
297
593
 
298
594
  getElements: function(form) {
299
- form = $(form);
595
+ var form = $(form);
300
596
  var elements = new Array();
301
597
 
302
598
  for (tagName in Form.Element.Serializers) {
@@ -307,17 +603,44 @@ var Form = {
307
603
  return elements;
308
604
  },
309
605
 
606
+ getInputs: function(form, typeName, name) {
607
+ var form = $(form);
608
+ var inputs = form.getElementsByTagName('input');
609
+
610
+ if (!typeName && !name)
611
+ return inputs;
612
+
613
+ var matchingInputs = new Array();
614
+ for (var i = 0; i < inputs.length; i++) {
615
+ var input = inputs[i];
616
+ if ((typeName && input.type != typeName) ||
617
+ (name && input.name != name))
618
+ continue;
619
+ matchingInputs.push(input);
620
+ }
621
+
622
+ return matchingInputs;
623
+ },
624
+
310
625
  disable: function(form) {
311
626
  var elements = Form.getElements(form);
312
627
  for (var i = 0; i < elements.length; i++) {
313
628
  var element = elements[i];
314
629
  element.blur();
315
- element.disable = 'true';
630
+ element.disabled = 'true';
631
+ }
632
+ },
633
+
634
+ enable: function(form) {
635
+ var elements = Form.getElements(form);
636
+ for (var i = 0; i < elements.length; i++) {
637
+ var element = elements[i];
638
+ element.disabled = '';
316
639
  }
317
640
  },
318
641
 
319
642
  focusFirstElement: function(form) {
320
- form = $(form);
643
+ var form = $(form);
321
644
  var elements = Form.getElements(form);
322
645
  for (var i = 0; i < elements.length; i++) {
323
646
  var element = elements[i];
@@ -335,7 +658,7 @@ var Form = {
335
658
 
336
659
  Form.Element = {
337
660
  serialize: function(element) {
338
- element = $(element);
661
+ var element = $(element);
339
662
  var method = element.tagName.toLowerCase();
340
663
  var parameter = Form.Element.Serializers[method](element);
341
664
 
@@ -345,7 +668,7 @@ Form.Element = {
345
668
  },
346
669
 
347
670
  getValue: function(element) {
348
- element = $(element);
671
+ var element = $(element);
349
672
  var method = element.tagName.toLowerCase();
350
673
  var parameter = Form.Element.Serializers[method](element);
351
674
 
@@ -357,6 +680,7 @@ Form.Element = {
357
680
  Form.Element.Serializers = {
358
681
  input: function(element) {
359
682
  switch (element.type.toLowerCase()) {
683
+ case 'submit':
360
684
  case 'hidden':
361
685
  case 'password':
362
686
  case 'text':
@@ -378,9 +702,20 @@ Form.Element.Serializers = {
378
702
  },
379
703
 
380
704
  select: function(element) {
381
- var index = element.selectedIndex;
382
- var value = element.options[index].value || element.options[index].text;
383
- return [element.name, (index >= 0) ? value : ''];
705
+ var value = '';
706
+ if (element.type == 'select-one') {
707
+ var index = element.selectedIndex;
708
+ if (index >= 0)
709
+ value = element.options[index].value || element.options[index].text;
710
+ } else {
711
+ value = new Array();
712
+ for (var i = 0; i < element.length; i++) {
713
+ var opt = element.options[i];
714
+ if (opt.selected)
715
+ value.push(opt.value || opt.text);
716
+ }
717
+ }
718
+ return [element.name, value];
384
719
  }
385
720
  }
386
721
 
@@ -402,7 +737,7 @@ Abstract.TimedObserver.prototype = {
402
737
  },
403
738
 
404
739
  registerCallback: function() {
405
- setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);
740
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
406
741
  },
407
742
 
408
743
  onTimerEvent: function() {
@@ -411,8 +746,6 @@ Abstract.TimedObserver.prototype = {
411
746
  this.callback(this.element, value);
412
747
  this.lastValue = value;
413
748
  }
414
-
415
- this.registerCallback();
416
749
  }
417
750
  }
418
751
 
@@ -430,336 +763,265 @@ Form.Observer.prototype = (new Abstract.TimedObserver()).extend({
430
763
  }
431
764
  });
432
765
 
433
-
434
766
  /*--------------------------------------------------------------------------*/
435
767
 
436
- document.getElementsByClassName = function(className) {
437
- var children = document.getElementsByTagName('*') || document.all;
438
- var elements = new Array();
439
-
440
- for (var i = 0; i < children.length; i++) {
441
- var child = children[i];
442
- var classNames = child.className.split(' ');
443
- for (var j = 0; j < classNames.length; j++) {
444
- if (classNames[j] == className) {
445
- elements.push(child);
446
- break;
447
- }
448
- }
449
- }
450
-
451
- return elements;
452
- }
453
-
454
- /*--------------------------------------------------------------------------*/
455
-
456
- var Element = {
457
- toggle: function() {
458
- for (var i = 0; i < arguments.length; i++) {
459
- var element = $(arguments[i]);
460
- element.style.display =
461
- (element.style.display == 'none' ? '' : 'none');
462
- }
463
- },
464
-
465
- hide: function() {
466
- for (var i = 0; i < arguments.length; i++) {
467
- var element = $(arguments[i]);
468
- element.style.display = 'none';
469
- }
470
- },
471
-
472
- show: function() {
473
- for (var i = 0; i < arguments.length; i++) {
474
- var element = $(arguments[i]);
475
- element.style.display = '';
476
- }
477
- },
478
-
479
- remove: function(element) {
480
- element = $(element);
481
- element.parentNode.removeChild(element);
482
- },
483
-
484
- getHeight: function(element) {
485
- element = $(element);
486
- return element.offsetHeight;
487
- }
488
- }
489
-
490
- var Toggle = new Object();
491
- Toggle.display = Element.toggle;
492
-
493
- /*--------------------------------------------------------------------------*/
494
-
495
- Abstract.Insertion = function(adjacency) {
496
- this.adjacency = adjacency;
497
- }
498
-
499
- Abstract.Insertion.prototype = {
500
- initialize: function(element, content) {
501
- this.element = $(element);
502
- this.content = content;
768
+ Abstract.EventObserver = function() {}
769
+ Abstract.EventObserver.prototype = {
770
+ initialize: function(element, callback) {
771
+ this.element = $(element);
772
+ this.callback = callback;
503
773
 
504
- if (this.adjacency && this.element.insertAdjacentHTML) {
505
- this.element.insertAdjacentHTML(this.adjacency, this.content);
506
- } else {
507
- this.range = this.element.ownerDocument.createRange();
508
- if (this.initializeRange) this.initializeRange();
509
- this.fragment = this.range.createContextualFragment(this.content);
510
- this.insertContent();
774
+ this.lastValue = this.getValue();
775
+ if (this.element.tagName.toLowerCase() == 'form')
776
+ this.registerFormCallbacks();
777
+ else
778
+ this.registerCallback(this.element);
779
+ },
780
+
781
+ onElementEvent: function() {
782
+ var value = this.getValue();
783
+ if (this.lastValue != value) {
784
+ this.callback(this.element, value);
785
+ this.lastValue = value;
511
786
  }
512
- }
513
- }
514
-
515
- var Insertion = new Object();
516
-
517
- Insertion.Before = Class.create();
518
- Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
519
- initializeRange: function() {
520
- this.range.setStartBefore(this.element);
521
787
  },
522
788
 
523
- insertContent: function() {
524
- this.element.parentNode.insertBefore(this.fragment, this.element);
525
- }
526
- });
527
-
528
- Insertion.Top = Class.create();
529
- Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
530
- initializeRange: function() {
531
- this.range.selectNodeContents(this.element);
532
- this.range.collapse(true);
789
+ registerFormCallbacks: function() {
790
+ var elements = Form.getElements(this.element);
791
+ for (var i = 0; i < elements.length; i++)
792
+ this.registerCallback(elements[i]);
533
793
  },
534
794
 
535
- insertContent: function() {
536
- this.element.insertBefore(this.fragment, this.element.firstChild);
795
+ registerCallback: function(element) {
796
+ if (element.type) {
797
+ switch (element.type.toLowerCase()) {
798
+ case 'checkbox':
799
+ case 'radio':
800
+ element.target = this;
801
+ element.prev_onclick = element.onclick || Prototype.emptyFunction;
802
+ element.onclick = function() {
803
+ this.prev_onclick();
804
+ this.target.onElementEvent();
805
+ }
806
+ break;
807
+ case 'password':
808
+ case 'text':
809
+ case 'textarea':
810
+ case 'select-one':
811
+ case 'select-multiple':
812
+ element.target = this;
813
+ element.prev_onchange = element.onchange || Prototype.emptyFunction;
814
+ element.onchange = function() {
815
+ this.prev_onchange();
816
+ this.target.onElementEvent();
817
+ }
818
+ break;
819
+ }
820
+ }
537
821
  }
538
- });
822
+ }
539
823
 
540
- Insertion.Bottom = Class.create();
541
- Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
542
- initializeRange: function() {
543
- this.range.selectNodeContents(this.element);
544
- this.range.collapse(this.element);
545
- },
546
-
547
- insertContent: function() {
548
- this.element.appendChild(this.fragment);
824
+ Form.Element.EventObserver = Class.create();
825
+ Form.Element.EventObserver.prototype = (new Abstract.EventObserver()).extend({
826
+ getValue: function() {
827
+ return Form.Element.getValue(this.element);
549
828
  }
550
829
  });
551
830
 
552
- Insertion.After = Class.create();
553
- Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
554
- initializeRange: function() {
555
- this.range.setStartAfter(this.element);
556
- },
557
-
558
- insertContent: function() {
559
- this.element.parentNode.insertBefore(this.fragment,
560
- this.element.nextSibling);
831
+ Form.EventObserver = Class.create();
832
+ Form.EventObserver.prototype = (new Abstract.EventObserver()).extend({
833
+ getValue: function() {
834
+ return Form.serialize(this.element);
561
835
  }
562
836
  });
563
837
 
564
- /*--------------------------------------------------------------------------*/
565
838
 
566
- var Effect = new Object();
839
+ if (!window.Event) {
840
+ var Event = new Object();
841
+ }
567
842
 
568
- Effect.Highlight = Class.create();
569
- Effect.Highlight.prototype = {
570
- initialize: function(element) {
571
- this.element = $(element);
572
- this.start = 153;
573
- this.finish = 255;
574
- this.current = this.start;
575
- this.fade();
843
+ Object.extend(Event, {
844
+ KEY_BACKSPACE: 8,
845
+ KEY_TAB: 9,
846
+ KEY_RETURN: 13,
847
+ KEY_ESC: 27,
848
+ KEY_LEFT: 37,
849
+ KEY_UP: 38,
850
+ KEY_RIGHT: 39,
851
+ KEY_DOWN: 40,
852
+ KEY_DELETE: 46,
853
+
854
+ element: function(event) {
855
+ return event.target || event.srcElement;
576
856
  },
577
-
578
- fade: function() {
579
- if (this.isFinished()) return;
580
- if (this.timer) clearTimeout(this.timer);
581
- this.highlight(this.element, this.current);
582
- this.current += 17;
583
- this.timer = setTimeout(this.fade.bind(this), 250);
584
- },
585
-
586
- isFinished: function() {
587
- return this.current > this.finish;
857
+
858
+ isLeftClick: function(event) {
859
+ return (((event.which) && (event.which == 1)) ||
860
+ ((event.button) && (event.button == 1)));
588
861
  },
589
-
590
- highlight: function(element, current) {
591
- element.style.backgroundColor = "#ffff" + current.toColorPart();
592
- }
593
- }
594
862
 
863
+ pointerX: function(event) {
864
+ return event.pageX || (event.clientX +
865
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
866
+ },
595
867
 
596
- Effect.Fade = Class.create();
597
- Effect.Fade.prototype = {
598
- initialize: function(element) {
599
- this.element = $(element);
600
- this.start = 100;
601
- this.finish = 0;
602
- this.current = this.start;
603
- this.fade();
868
+ pointerY: function(event) {
869
+ return event.pageY || (event.clientY +
870
+ (document.documentElement.scrollTop || document.body.scrollTop));
604
871
  },
605
-
606
- fade: function() {
607
- if (this.isFinished()) { this.element.style.display = 'none'; return; }
608
- if (this.timer) clearTimeout(this.timer);
609
- this.setOpacity(this.element, this.current);
610
- this.current -= 10;
611
- this.timer = setTimeout(this.fade.bind(this), 50);
872
+
873
+ stop: function(event) {
874
+ if (event.preventDefault) {
875
+ event.preventDefault();
876
+ event.stopPropagation();
877
+ } else {
878
+ event.returnValue = false;
879
+ }
612
880
  },
613
-
614
- isFinished: function() {
615
- return this.current <= this.finish;
881
+
882
+ // find the first node with the given tagName, starting from the
883
+ // node the event was triggered on; traverses the DOM upwards
884
+ findElement: function(event, tagName) {
885
+ var element = Event.element(event);
886
+ while (element.parentNode && (!element.tagName ||
887
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
888
+ element = element.parentNode;
889
+ return element;
616
890
  },
617
-
618
- setOpacity: function(element, opacity) {
619
- opacity = (opacity == 100) ? 99.999 : opacity;
620
- element.style.filter = "alpha(opacity:"+opacity+")";
621
- element.style.opacity = opacity/100 /*//*/;
622
- }
623
- }
624
891
 
625
- Effect.Scale = Class.create();
626
- Effect.Scale.prototype = {
627
- initialize: function(element, percent) {
628
- this.element = $(element);
629
- this.startScale = 1.0;
630
- this.startHeight = this.element.offsetHeight;
631
- this.startWidth = this.element.offsetWidth;
632
- this.currentHeight = this.startHeight;
633
- this.currentWidth = this.startWidth;
634
- this.finishScale = (percent/100) /*//*/;
635
- if (this.element.style.fontSize=="") this.sizeEm = 1.0;
636
- if (this.element.style.fontSize.indexOf("em")>0)
637
- this.sizeEm = parseFloat(this.element.style.fontSize);
638
- if(this.element.effect_scale) {
639
- clearTimeout(this.element.effect_scale.timer);
640
- this.startScale = this.element.effect_scale.currentScale;
641
- this.startHeight = this.element.effect_scale.startHeight;
642
- this.startWidth = this.element.effect_scale.startWidth;
643
- if(this.element.effect_scale.sizeEm)
644
- this.sizeEm = this.element.effect_scale.sizeEm;
892
+ observe: function(element, name, observer, useCapture) {
893
+ var element = $(element);
894
+ useCapture = useCapture || false;
895
+
896
+ if (name == 'keypress') {
897
+ if (navigator.appVersion.indexOf('AppleWebKit') > 0) {
898
+ element.addEventListener('keydown', observer, useCapture);
899
+ return;
900
+ }
901
+ if (element.addEventListener) {
902
+ element.addEventListener('keypress', observer, useCapture);
903
+ } else if (element.attachEvent) {
904
+ element.attachEvent('onkeydown', observer);
905
+ }
906
+ } else {
907
+ if (element.addEventListener) {
908
+ element.addEventListener(name, observer, useCapture);
909
+ } else if (element.attachEvent) {
910
+ element.attachEvent('on' + name, observer);
911
+ }
645
912
  }
646
- this.element.effect_scale = this;
647
- this.currentScale = this.startScale;
648
- this.factor = this.finishScale - this.startScale;
649
- this.options = arguments[2] || {};
650
- this.scale();
651
913
  },
652
-
653
- scale: function() {
654
- if (this.isFinished()) {
655
- this.setDimensions(this.element, this.startWidth*this.finishScale, this.startHeight*this.finishScale);
656
- if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.finishScale + "em";
657
- if(this.options.complete) this.options.complete(this);
658
- return;
914
+
915
+ stopObserving: function(element, name, observer, useCapture) {
916
+ var element = $(element);
917
+ useCapture = useCapture || false;
918
+
919
+ if (name == 'keypress') {
920
+ if (navigator.appVersion.indexOf('AppleWebKit') > 0) {
921
+ element.removeEventListener('keydown', observer, useCapture);
922
+ return;
923
+ }
924
+ if (element.removeEventListener) {
925
+ element.removeEventListener('keypress', observer, useCapture);
926
+ } else if (element.detachEvent) {
927
+ element.detachEvent('onkeydown', observer);
928
+ }
929
+ } else {
930
+ if (element.removeEventListener) {
931
+ element.removeEventListener(name, observer, useCapture);
932
+ } else if (element.detachEvent) {
933
+ element.detachEvent('on' + name, observer);
934
+ }
659
935
  }
660
- if (this.timer) clearTimeout(this.timer);
661
- if (this.options.step) this.options.step(this);
662
- this.setDimensions(this.element, this.currentWidth, this.currentHeight);
663
- if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.currentScale + "em";
664
- this.currentScale += (this.factor/10) /*//*/;
665
- this.currentWidth = this.startWidth * this.currentScale;
666
- this.currentHeight = this.startHeight * this.currentScale;
667
- this.timer = setTimeout(this.scale.bind(this), 50);
668
- },
669
-
670
- isFinished: function() {
671
- return (this.factor < 0) ?
672
- this.currentScale <= this.finishScale : this.currentScale >= this.finishScale;
673
- },
674
-
675
- setDimensions: function(element, width, height) {
676
- element.style.width = width + 'px';
677
- element.style.height = height + 'px';
678
936
  }
679
- }
937
+ });
680
938
 
681
- Effect.Squish = Class.create();
682
- Effect.Squish.prototype = {
683
- initialize: function(element) {
684
- this.element = $(element);
685
- new Effect.Scale(this.element, 1, { complete: this.hide.bind(this) } );
939
+ var Position = {
940
+
941
+ // set to true if needed, warning: firefox performance problems
942
+ // NOT neeeded for page scrolling, only if draggable contained in
943
+ // scrollable elements
944
+ includeScrollOffsets: false,
945
+
946
+ // must be called before calling withinIncludingScrolloffset, every time the
947
+ // page is scrolled
948
+ prepare: function() {
949
+ this.deltaX = window.pageXOffset
950
+ || document.documentElement.scrollLeft
951
+ || document.body.scrollLeft
952
+ || 0;
953
+ this.deltaY = window.pageYOffset
954
+ || document.documentElement.scrollTop
955
+ || document.body.scrollTop
956
+ || 0;
686
957
  },
687
- hide: function() {
688
- this.element.style.display = 'none';
689
- }
690
- }
691
958
 
692
- Effect.Puff = Class.create();
693
- Effect.Puff.prototype = {
694
- initialize: function(element) {
695
- this.element = $(element);
696
- this.opacity = 100;
697
- this.startTop = this.element.top || this.element.offsetTop;
698
- this.startLeft = this.element.left || this.element.offsetLeft;
699
- new Effect.Scale(this.element, 200, { step: this.fade.bind(this), complete: this.hide.bind(this) } );
700
- },
701
- fade: function(effect) {
702
- topd = (((effect.currentScale)*effect.startHeight) - effect.startHeight)/2;
703
- leftd = (((effect.currentScale)*effect.startWidth) - effect.startWidth)/2;
704
- this.element.style.position='absolute';
705
- this.element.style.top = this.startTop-topd + "px";
706
- this.element.style.left = this.startLeft-leftd + "px";
707
- this.opacity -= 10;
708
- this.setOpacity(this.element, this.opacity);
709
- if(navigator.appVersion.indexOf('AppleWebKit')>0) this.element.innerHTML += ''; //force redraw on safari
959
+ realOffset: function(element) {
960
+ var valueT = 0, valueL = 0;
961
+ do {
962
+ valueT += element.scrollTop || 0;
963
+ valueL += element.scrollLeft || 0;
964
+ element = element.parentNode;
965
+ } while (element);
966
+ return [valueL, valueT];
710
967
  },
711
- hide: function() {
712
- this.element.style.display = 'none';
968
+
969
+ cumulativeOffset: function(element) {
970
+ var valueT = 0, valueL = 0;
971
+ do {
972
+ valueT += element.offsetTop || 0;
973
+ valueL += element.offsetLeft || 0;
974
+ element = element.offsetParent;
975
+ } while (element);
976
+ return [valueL, valueT];
713
977
  },
714
- setOpacity: function(element, opacity) {
715
- opacity = (opacity == 100) ? 99.999 : opacity;
716
- element.style.filter = "alpha(opacity:"+opacity+")";
717
- element.style.opacity = opacity/100 /*//*/;
718
- }
719
- }
720
978
 
721
- Effect.Appear = Class.create();
722
- Effect.Appear.prototype = {
723
- initialize: function(element) {
724
- this.element = $(element);
725
- this.start = 0;
726
- this.finish = 100;
727
- this.current = this.start;
728
- this.fade();
979
+ // caches x/y coordinate pair to use with overlap
980
+ within: function(element, x, y) {
981
+ if (this.includeScrollOffsets)
982
+ return this.withinIncludingScrolloffsets(element, x, y);
983
+ this.xcomp = x;
984
+ this.ycomp = y;
985
+ this.offset = this.cumulativeOffset(element);
986
+
987
+ return (y >= this.offset[1] &&
988
+ y < this.offset[1] + element.offsetHeight &&
989
+ x >= this.offset[0] &&
990
+ x < this.offset[0] + element.offsetWidth);
729
991
  },
730
-
731
- fade: function() {
732
- if (this.isFinished()) return;
733
- if (this.timer) clearTimeout(this.timer);
734
- this.setOpacity(this.element, this.current);
735
- this.current += 10;
736
- this.timer = setTimeout(this.fade.bind(this), 50);
992
+
993
+ withinIncludingScrolloffsets: function(element, x, y) {
994
+ var offsetcache = this.realOffset(element);
995
+
996
+ this.xcomp = x + offsetcache[0] - this.deltaX;
997
+ this.ycomp = y + offsetcache[1] - this.deltaY;
998
+ this.offset = this.cumulativeOffset(element);
999
+
1000
+ return (this.ycomp >= this.offset[1] &&
1001
+ this.ycomp < this.offset[1] + element.offsetHeight &&
1002
+ this.xcomp >= this.offset[0] &&
1003
+ this.xcomp < this.offset[0] + element.offsetWidth);
737
1004
  },
738
-
739
- isFinished: function() {
740
- return this.current > this.finish;
1005
+
1006
+ // within must be called directly before
1007
+ overlap: function(mode, element) {
1008
+ if (!mode) return 0;
1009
+ if (mode == 'vertical')
1010
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
1011
+ element.offsetHeight;
1012
+ if (mode == 'horizontal')
1013
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
1014
+ element.offsetWidth;
741
1015
  },
742
-
743
- setOpacity: function(element, opacity) {
744
- opacity = (opacity == 100) ? 99.999 : opacity;
745
- element.style.filter = "alpha(opacity:"+opacity+")";
746
- element.style.opacity = opacity/100 /*//*/;
747
- element.style.display = '';
748
- }
749
- }
750
1016
 
751
- Effect.ContentZoom = Class.create();
752
- Effect.ContentZoom.prototype = {
753
- initialize: function(element, percent) {
754
- this.element = $(element);
755
- if (this.element.style.fontSize=="") this.sizeEm = 1.0;
756
- if (this.element.style.fontSize.indexOf("em")>0)
757
- this.sizeEm = parseFloat(this.element.style.fontSize);
758
- if(this.element.effect_contentzoom) {
759
- this.sizeEm = this.element.effect_contentzoom.sizeEm;
760
- }
761
- this.element.effect_contentzoom = this;
762
- this.element.style.fontSize = this.sizeEm*(percent/100) + "em" /*//*/;
763
- if(navigator.appVersion.indexOf('AppleWebKit')>0) { this.element.scrollTop -= 1; };
1017
+ clone: function(source, target) {
1018
+ source = $(source);
1019
+ target = $(target);
1020
+ target.style.position = 'absolute';
1021
+ var offsets = this.cumulativeOffset(source);
1022
+ target.style.top = offsets[1] + 'px';
1023
+ target.style.left = offsets[0] + 'px';
1024
+ target.style.width = source.offsetWidth + 'px';
1025
+ target.style.height = source.offsetHeight + 'px';
764
1026
  }
765
1027
  }