##// END OF EJS Templates
updated prototype (1.50) and script.aculo.us javascripts...
Jean-Philippe Lang -
r238:2e72f2eca8f4
parent child
Show More
@@ -1,12 +1,13
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 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
2 // (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
3 // (c) 2005 Jon Tirsen (http://www.tirsen.com)
3 // (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
4 // Contributors:
4 // Contributors:
5 // Richard Livsey
5 // Richard Livsey
6 // Rahul Bhargava
6 // Rahul Bhargava
7 // Rob Wills
7 // Rob Wills
8 //
8 //
9 // See scriptaculous.js for full license.
9 // script.aculo.us is freely distributable under the terms of an MIT-style license.
10 // For details, see the script.aculo.us web site: http://script.aculo.us/
10
11
11 // Autocompleter.Base handles all the autocompletion functionality
12 // Autocompleter.Base handles all the autocompletion functionality
12 // that's independent of the data source for autocompletion. This
13 // that's independent of the data source for autocompletion. This
@@ -33,6 +34,9
33 // useful when one of the tokens is \n (a newline), as it
34 // useful when one of the tokens is \n (a newline), as it
34 // allows smart autocompletion after linebreaks.
35 // allows smart autocompletion after linebreaks.
35
36
37 if(typeof Effect == 'undefined')
38 throw("controls.js requires including script.aculo.us' effects.js library");
39
36 var Autocompleter = {}
40 var Autocompleter = {}
37 Autocompleter.Base = function() {};
41 Autocompleter.Base = function() {};
38 Autocompleter.Base.prototype = {
42 Autocompleter.Base.prototype = {
@@ -45,7 +49,7 Autocompleter.Base.prototype = {
45 this.index = 0;
49 this.index = 0;
46 this.entryCount = 0;
50 this.entryCount = 0;
47
51
48 if (this.setOptions)
52 if(this.setOptions)
49 this.setOptions(options);
53 this.setOptions(options);
50 else
54 else
51 this.options = options || {};
55 this.options = options || {};
@@ -55,17 +59,20 Autocompleter.Base.prototype = {
55 this.options.frequency = this.options.frequency || 0.4;
59 this.options.frequency = this.options.frequency || 0.4;
56 this.options.minChars = this.options.minChars || 1;
60 this.options.minChars = this.options.minChars || 1;
57 this.options.onShow = this.options.onShow ||
61 this.options.onShow = this.options.onShow ||
58 function(element, update){
62 function(element, update){
59 if(!update.style.position || update.style.position=='absolute') {
63 if(!update.style.position || update.style.position=='absolute') {
60 update.style.position = 'absolute';
64 update.style.position = 'absolute';
61 Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});
65 Position.clone(element, update, {
62 }
66 setHeight: false,
63 Effect.Appear(update,{duration:0.15});
67 offsetTop: element.offsetHeight
64 };
68 });
69 }
70 Effect.Appear(update,{duration:0.15});
71 };
65 this.options.onHide = this.options.onHide ||
72 this.options.onHide = this.options.onHide ||
66 function(element, update){ new Effect.Fade(update,{duration:0.15}) };
73 function(element, update){ new Effect.Fade(update,{duration:0.15}) };
67
74
68 if (typeof(this.options.tokens) == 'string')
75 if(typeof(this.options.tokens) == 'string')
69 this.options.tokens = new Array(this.options.tokens);
76 this.options.tokens = new Array(this.options.tokens);
70
77
71 this.observer = null;
78 this.observer = null;
@@ -94,7 +101,7 Autocompleter.Base.prototype = {
94 },
101 },
95
102
96 fixIEOverlapping: function() {
103 fixIEOverlapping: function() {
97 Position.clone(this.update, this.iefix);
104 Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
98 this.iefix.style.zIndex = 1;
105 this.iefix.style.zIndex = 1;
99 this.update.style.zIndex = 2;
106 this.update.style.zIndex = 2;
100 Element.show(this.iefix);
107 Element.show(this.iefix);
@@ -141,8 +148,8 Autocompleter.Base.prototype = {
141 return;
148 return;
142 }
149 }
143 else
150 else
144 if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)
151 if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
145 return;
152 (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
146
153
147 this.changed = true;
154 this.changed = true;
148 this.hasFocus = true;
155 this.hasFocus = true;
@@ -152,6 +159,12 Autocompleter.Base.prototype = {
152 setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
159 setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
153 },
160 },
154
161
162 activate: function() {
163 this.changed = false;
164 this.hasFocus = true;
165 this.getUpdatedChoices();
166 },
167
155 onHover: function(event) {
168 onHover: function(event) {
156 var element = Event.findElement(event, 'LI');
169 var element = Event.findElement(event, 'LI');
157 if(this.index != element.autocompleteIndex)
170 if(this.index != element.autocompleteIndex)
@@ -196,11 +209,13 Autocompleter.Base.prototype = {
196 markPrevious: function() {
209 markPrevious: function() {
197 if(this.index > 0) this.index--
210 if(this.index > 0) this.index--
198 else this.index = this.entryCount-1;
211 else this.index = this.entryCount-1;
212 this.getEntry(this.index).scrollIntoView(true);
199 },
213 },
200
214
201 markNext: function() {
215 markNext: function() {
202 if(this.index < this.entryCount-1) this.index++
216 if(this.index < this.entryCount-1) this.index++
203 else this.index = 0;
217 else this.index = 0;
218 this.getEntry(this.index).scrollIntoView(false);
204 },
219 },
205
220
206 getEntry: function(index) {
221 getEntry: function(index) {
@@ -221,8 +236,13 Autocompleter.Base.prototype = {
221 this.options.updateElement(selectedElement);
236 this.options.updateElement(selectedElement);
222 return;
237 return;
223 }
238 }
224
239 var value = '';
225 var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
240 if (this.options.select) {
241 var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
242 if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
243 } else
244 value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
245
226 var lastTokenPos = this.findLastToken();
246 var lastTokenPos = this.findLastToken();
227 if (lastTokenPos != -1) {
247 if (lastTokenPos != -1) {
228 var newValue = this.element.value.substr(0, lastTokenPos + 1);
248 var newValue = this.element.value.substr(0, lastTokenPos + 1);
@@ -243,11 +263,11 Autocompleter.Base.prototype = {
243 if(!this.changed && this.hasFocus) {
263 if(!this.changed && this.hasFocus) {
244 this.update.innerHTML = choices;
264 this.update.innerHTML = choices;
245 Element.cleanWhitespace(this.update);
265 Element.cleanWhitespace(this.update);
246 Element.cleanWhitespace(this.update.firstChild);
266 Element.cleanWhitespace(this.update.down());
247
267
248 if(this.update.firstChild && this.update.firstChild.childNodes) {
268 if(this.update.firstChild && this.update.down().childNodes) {
249 this.entryCount =
269 this.entryCount =
250 this.update.firstChild.childNodes.length;
270 this.update.down().childNodes.length;
251 for (var i = 0; i < this.entryCount; i++) {
271 for (var i = 0; i < this.entryCount; i++) {
252 var entry = this.getEntry(i);
272 var entry = this.getEntry(i);
253 entry.autocompleteIndex = i;
273 entry.autocompleteIndex = i;
@@ -258,9 +278,14 Autocompleter.Base.prototype = {
258 }
278 }
259
279
260 this.stopIndicator();
280 this.stopIndicator();
261
262 this.index = 0;
281 this.index = 0;
263 this.render();
282
283 if(this.entryCount==1 && this.options.autoSelect) {
284 this.selectEntry();
285 this.hide();
286 } else {
287 this.render();
288 }
264 }
289 }
265 },
290 },
266
291
@@ -305,7 +330,7 Autocompleter.Base.prototype = {
305 Ajax.Autocompleter = Class.create();
330 Ajax.Autocompleter = Class.create();
306 Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
331 Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
307 initialize: function(element, update, url, options) {
332 initialize: function(element, update, url, options) {
308 this.baseInitialize(element, update, options);
333 this.baseInitialize(element, update, options);
309 this.options.asynchronous = true;
334 this.options.asynchronous = true;
310 this.options.onComplete = this.onComplete.bind(this);
335 this.options.onComplete = this.onComplete.bind(this);
311 this.options.defaultParams = this.options.parameters || null;
336 this.options.defaultParams = this.options.parameters || null;
@@ -448,7 +473,10 Ajax.InPlaceEditor.prototype = {
448 this.element = $(element);
473 this.element = $(element);
449
474
450 this.options = Object.extend({
475 this.options = Object.extend({
476 paramName: "value",
477 okButton: true,
451 okText: "ok",
478 okText: "ok",
479 cancelLink: true,
452 cancelText: "cancel",
480 cancelText: "cancel",
453 savingText: "Saving...",
481 savingText: "Saving...",
454 clickToEditText: "Click to edit",
482 clickToEditText: "Click to edit",
@@ -470,8 +498,10 Ajax.InPlaceEditor.prototype = {
470 formClassName: 'inplaceeditor-form',
498 formClassName: 'inplaceeditor-form',
471 highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
499 highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
472 highlightendcolor: "#FFFFFF",
500 highlightendcolor: "#FFFFFF",
473 externalControl: null,
501 externalControl: null,
474 ajaxOptions: {}
502 submitOnBlur: false,
503 ajaxOptions: {},
504 evalScripts: false
475 }, options || {});
505 }, options || {});
476
506
477 if(!this.options.formId && this.element.id) {
507 if(!this.options.formId && this.element.id) {
@@ -516,7 +546,7 Ajax.InPlaceEditor.prototype = {
516 Element.hide(this.element);
546 Element.hide(this.element);
517 this.createForm();
547 this.createForm();
518 this.element.parentNode.insertBefore(this.form, this.element);
548 this.element.parentNode.insertBefore(this.form, this.element);
519 Field.scrollFreeActivate(this.editField);
549 if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
520 // stop the event to avoid a page refresh in Safari
550 // stop the event to avoid a page refresh in Safari
521 if (evt) {
551 if (evt) {
522 Event.stop(evt);
552 Event.stop(evt);
@@ -536,16 +566,22 Ajax.InPlaceEditor.prototype = {
536 this.form.appendChild(br);
566 this.form.appendChild(br);
537 }
567 }
538
568
539 okButton = document.createElement("input");
569 if (this.options.okButton) {
540 okButton.type = "submit";
570 okButton = document.createElement("input");
541 okButton.value = this.options.okText;
571 okButton.type = "submit";
542 this.form.appendChild(okButton);
572 okButton.value = this.options.okText;
573 okButton.className = 'editor_ok_button';
574 this.form.appendChild(okButton);
575 }
543
576
544 cancelLink = document.createElement("a");
577 if (this.options.cancelLink) {
545 cancelLink.href = "#";
578 cancelLink = document.createElement("a");
546 cancelLink.appendChild(document.createTextNode(this.options.cancelText));
579 cancelLink.href = "#";
547 cancelLink.onclick = this.onclickCancel.bind(this);
580 cancelLink.appendChild(document.createTextNode(this.options.cancelText));
548 this.form.appendChild(cancelLink);
581 cancelLink.onclick = this.onclickCancel.bind(this);
582 cancelLink.className = 'editor_cancel';
583 this.form.appendChild(cancelLink);
584 }
549 },
585 },
550 hasHTMLLineBreaks: function(string) {
586 hasHTMLLineBreaks: function(string) {
551 if (!this.options.handleLineBreaks) return false;
587 if (!this.options.handleLineBreaks) return false;
@@ -561,24 +597,34 Ajax.InPlaceEditor.prototype = {
561 } else {
597 } else {
562 text = this.getText();
598 text = this.getText();
563 }
599 }
600
601 var obj = this;
564
602
565 if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
603 if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
566 this.options.textarea = false;
604 this.options.textarea = false;
567 var textField = document.createElement("input");
605 var textField = document.createElement("input");
606 textField.obj = this;
568 textField.type = "text";
607 textField.type = "text";
569 textField.name = "value";
608 textField.name = this.options.paramName;
570 textField.value = text;
609 textField.value = text;
571 textField.style.backgroundColor = this.options.highlightcolor;
610 textField.style.backgroundColor = this.options.highlightcolor;
611 textField.className = 'editor_field';
572 var size = this.options.size || this.options.cols || 0;
612 var size = this.options.size || this.options.cols || 0;
573 if (size != 0) textField.size = size;
613 if (size != 0) textField.size = size;
614 if (this.options.submitOnBlur)
615 textField.onblur = this.onSubmit.bind(this);
574 this.editField = textField;
616 this.editField = textField;
575 } else {
617 } else {
576 this.options.textarea = true;
618 this.options.textarea = true;
577 var textArea = document.createElement("textarea");
619 var textArea = document.createElement("textarea");
578 textArea.name = "value";
620 textArea.obj = this;
621 textArea.name = this.options.paramName;
579 textArea.value = this.convertHTMLLineBreaks(text);
622 textArea.value = this.convertHTMLLineBreaks(text);
580 textArea.rows = this.options.rows;
623 textArea.rows = this.options.rows;
581 textArea.cols = this.options.cols || 40;
624 textArea.cols = this.options.cols || 40;
625 textArea.className = 'editor_field';
626 if (this.options.submitOnBlur)
627 textArea.onblur = this.onSubmit.bind(this);
582 this.editField = textArea;
628 this.editField = textArea;
583 }
629 }
584
630
@@ -605,6 +651,7 Ajax.InPlaceEditor.prototype = {
605 Element.removeClassName(this.form, this.options.loadingClassName);
651 Element.removeClassName(this.form, this.options.loadingClassName);
606 this.editField.disabled = false;
652 this.editField.disabled = false;
607 this.editField.value = transport.responseText.stripTags();
653 this.editField.value = transport.responseText.stripTags();
654 Field.scrollFreeActivate(this.editField);
608 },
655 },
609 onclickCancel: function() {
656 onclickCancel: function() {
610 this.onComplete();
657 this.onComplete();
@@ -629,19 +676,26 Ajax.InPlaceEditor.prototype = {
629 // to be displayed indefinitely
676 // to be displayed indefinitely
630 this.onLoading();
677 this.onLoading();
631
678
632 new Ajax.Updater(
679 if (this.options.evalScripts) {
633 {
680 new Ajax.Request(
634 success: this.element,
681 this.url, Object.extend({
635 // don't update on failure (this could be an option)
682 parameters: this.options.callback(form, value),
636 failure: null
683 onComplete: this.onComplete.bind(this),
637 },
684 onFailure: this.onFailure.bind(this),
638 this.url,
685 asynchronous:true,
639 Object.extend({
686 evalScripts:true
640 parameters: this.options.callback(form, value),
687 }, this.options.ajaxOptions));
641 onComplete: this.onComplete.bind(this),
688 } else {
642 onFailure: this.onFailure.bind(this)
689 new Ajax.Updater(
643 }, this.options.ajaxOptions)
690 { success: this.element,
644 );
691 // don't update on failure (this could be an option)
692 failure: null },
693 this.url, Object.extend({
694 parameters: this.options.callback(form, value),
695 onComplete: this.onComplete.bind(this),
696 onFailure: this.onFailure.bind(this)
697 }, this.options.ajaxOptions));
698 }
645 // stop the event to avoid a page refresh in Safari
699 // stop the event to avoid a page refresh in Safari
646 if (arguments.length > 1) {
700 if (arguments.length > 1) {
647 Event.stop(arguments[0]);
701 Event.stop(arguments[0]);
@@ -723,6 +777,35 Ajax.InPlaceEditor.prototype = {
723 }
777 }
724 };
778 };
725
779
780 Ajax.InPlaceCollectionEditor = Class.create();
781 Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
782 Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
783 createEditField: function() {
784 if (!this.cached_selectTag) {
785 var selectTag = document.createElement("select");
786 var collection = this.options.collection || [];
787 var optionTag;
788 collection.each(function(e,i) {
789 optionTag = document.createElement("option");
790 optionTag.value = (e instanceof Array) ? e[0] : e;
791 if((typeof this.options.value == 'undefined') &&
792 ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
793 if(this.options.value==optionTag.value) optionTag.selected = true;
794 optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
795 selectTag.appendChild(optionTag);
796 }.bind(this));
797 this.cached_selectTag = selectTag;
798 }
799
800 this.editField = this.cached_selectTag;
801 if(this.options.loadTextURL) this.loadExternalText();
802 this.form.appendChild(this.editField);
803 this.options.callback = function(form, value) {
804 return "value=" + encodeURIComponent(value);
805 }
806 }
807 });
808
726 // Delayed observer, like Form.Element.Observer,
809 // Delayed observer, like Form.Element.Observer,
727 // but waits for delay after last key input
810 // but waits for delay after last key input
728 // Ideal for live-search fields
811 // Ideal for live-search fields
@@ -747,4 +830,4 Form.Element.DelayedObserver.prototype = {
747 this.timer = null;
830 this.timer = null;
748 this.callback(this.element, $F(this.element));
831 this.callback(this.element, $F(this.element));
749 }
832 }
750 }; No newline at end of file
833 };
This diff has been collapsed as it changes many lines, (550 lines changed) Show them Hide them
@@ -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 var Droppables = {
10 var Droppables = {
8 drops: [],
11 drops: [],
@@ -15,7 +18,8 var Droppables = {
15 element = $(element);
18 element = $(element);
16 var options = Object.extend({
19 var options = Object.extend({
17 greedy: true,
20 greedy: true,
18 hoverclass: null
21 hoverclass: null,
22 tree: false
19 }, arguments[1] || {});
23 }, arguments[1] || {});
20
24
21 // cache containers
25 // cache containers
@@ -37,12 +41,27 var Droppables = {
37
41
38 this.drops.push(options);
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 isContained: function(element, drop) {
55 isContained: function(element, drop) {
42 var parentNode = element.parentNode;
56 var containmentNode;
43 return drop._containers.detect(function(c) { return parentNode == c });
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 isAffected: function(point, element, drop) {
65 isAffected: function(point, element, drop) {
47 return (
66 return (
48 (drop.element!=element) &&
67 (drop.element!=element) &&
@@ -68,18 +87,22 var Droppables = {
68
87
69 show: function(point, element) {
88 show: function(point, element) {
70 if(!this.drops.length) return;
89 if(!this.drops.length) return;
90 var affected = [];
71
91
72 if(this.last_active) this.deactivate(this.last_active);
92 if(this.last_active) this.deactivate(this.last_active);
73 this.drops.each( function(drop) {
93 this.drops.each( function(drop) {
74 if(Droppables.isAffected(point, element, drop)) {
94 if(Droppables.isAffected(point, element, drop))
75 if(drop.onHover)
95 affected.push(drop);
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 }
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 fire: function(event, element) {
108 fire: function(event, element) {
@@ -124,11 +147,19 var Draggables = {
124 },
147 },
125
148
126 activate: function(draggable) {
149 activate: function(draggable) {
127 window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
150 if(draggable.options.delay) {
128 this.activeDraggable = draggable;
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 deactivate: function(draggbale) {
162 deactivate: function() {
132 this.activeDraggable = null;
163 this.activeDraggable = null;
133 },
164 },
134
165
@@ -139,13 +170,19 var Draggables = {
139 // the same coordinates, prevent needless redrawing (moz bug?)
170 // the same coordinates, prevent needless redrawing (moz bug?)
140 if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
171 if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
141 this._lastPointer = pointer;
172 this._lastPointer = pointer;
173
142 this.activeDraggable.updateDrag(event, pointer);
174 this.activeDraggable.updateDrag(event, pointer);
143 },
175 },
144
176
145 endDrag: function(event) {
177 endDrag: function(event) {
178 if(this._timeout) {
179 clearTimeout(this._timeout);
180 this._timeout = null;
181 }
146 if(!this.activeDraggable) return;
182 if(!this.activeDraggable) return;
147 this._lastPointer = null;
183 this._lastPointer = null;
148 this.activeDraggable.endDrag(event);
184 this.activeDraggable.endDrag(event);
185 this.activeDraggable = null;
149 },
186 },
150
187
151 keyPress: function(event) {
188 keyPress: function(event) {
@@ -168,6 +205,7 var Draggables = {
168 this.observers.each( function(o) {
205 this.observers.each( function(o) {
169 if(o[eventName]) o[eventName](eventName, draggable, event);
206 if(o[eventName]) o[eventName](eventName, draggable, event);
170 });
207 });
208 if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
171 },
209 },
172
210
173 _cacheObserverCallbacks: function() {
211 _cacheObserverCallbacks: function() {
@@ -182,31 +220,59 var Draggables = {
182 /*--------------------------------------------------------------------------*/
220 /*--------------------------------------------------------------------------*/
183
221
184 var Draggable = Class.create();
222 var Draggable = Class.create();
223 Draggable._dragging = {};
224
185 Draggable.prototype = {
225 Draggable.prototype = {
186 initialize: function(element) {
226 initialize: function(element) {
187 var options = Object.extend({
227 var defaults = {
188 handle: false,
228 handle: false,
189 starteffect: function(element) {
190 new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
191 },
192 reverteffect: function(element, top_offset, left_offset) {
229 reverteffect: function(element, top_offset, left_offset) {
193 var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
230 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});
231 new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
232 queue: {scope:'_draggable', position:'end'}
233 });
195 },
234 },
196 endeffect: function(element) {
235 endeffect: function(element) {
197 new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
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 });
198 },
243 },
199 zindex: 1000,
244 zindex: 1000,
200 revert: false,
245 revert: false,
201 snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
246 scroll: false,
202 }, arguments[1] || {});
247 scrollSensitivity: 20,
248 scrollSpeed: 15,
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] || {});
203
263
204 this.element = $(element);
264 this.element = $(element);
205
265
206 if(options.handle && (typeof options.handle == 'string'))
266 if(options.handle && (typeof options.handle == 'string'))
207 this.handle = Element.childrenWithClassName(this.element, options.handle)[0];
267 this.handle = this.element.down('.'+options.handle, 0);
268
208 if(!this.handle) this.handle = $(options.handle);
269 if(!this.handle) this.handle = $(options.handle);
209 if(!this.handle) this.handle = this.element;
270 if(!this.handle) this.handle = this.element;
271
272 if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
273 options.scroll = $(options.scroll);
274 this._isScrollChild = Element.childOf(this.element, options.scroll);
275 }
210
276
211 Element.makePositioned(this.element); // fix IE
277 Element.makePositioned(this.element); // fix IE
212
278
@@ -227,25 +293,23 Draggable.prototype = {
227
293
228 currentDelta: function() {
294 currentDelta: function() {
229 return([
295 return([
230 parseInt(this.element.style.left || '0'),
296 parseInt(Element.getStyle(this.element,'left') || '0'),
231 parseInt(this.element.style.top || '0')]);
297 parseInt(Element.getStyle(this.element,'top') || '0')]);
232 },
298 },
233
299
234 initDrag: function(event) {
300 initDrag: function(event) {
301 if(typeof Draggable._dragging[this.element] != 'undefined' &&
302 Draggable._dragging[this.element]) return;
235 if(Event.isLeftClick(event)) {
303 if(Event.isLeftClick(event)) {
236 // abort on form elements, fixes a Firefox issue
304 // abort on form elements, fixes a Firefox issue
237 var src = Event.element(event);
305 var src = Event.element(event);
238 if(src.tagName && (
306 if(src.tagName && (
239 src.tagName=='INPUT' ||
307 src.tagName=='INPUT' ||
240 src.tagName=='SELECT' ||
308 src.tagName=='SELECT' ||
309 src.tagName=='OPTION' ||
241 src.tagName=='BUTTON' ||
310 src.tagName=='BUTTON' ||
242 src.tagName=='TEXTAREA')) return;
311 src.tagName=='TEXTAREA')) return;
243
312
244 if(this.element._revert) {
245 this.element._revert.cancel();
246 this.element._revert = null;
247 }
248
249 var pointer = [Event.pointerX(event), Event.pointerY(event)];
313 var pointer = [Event.pointerX(event), Event.pointerY(event)];
250 var pos = Position.cumulativeOffset(this.element);
314 var pos = Position.cumulativeOffset(this.element);
251 this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
315 this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
@@ -269,7 +333,19 Draggable.prototype = {
269 this.element.parentNode.insertBefore(this._clone, this.element);
333 this.element.parentNode.insertBefore(this._clone, this.element);
270 }
334 }
271
335
336 if(this.options.scroll) {
337 if (this.options.scroll == window) {
338 var where = this._getWindowScroll(this.options.scroll);
339 this.originalScrollLeft = where.left;
340 this.originalScrollTop = where.top;
341 } else {
342 this.originalScrollLeft = this.options.scroll.scrollLeft;
343 this.originalScrollTop = this.options.scroll.scrollTop;
344 }
345 }
346
272 Draggables.notify('onStart', this, event);
347 Draggables.notify('onStart', this, event);
348
273 if(this.options.starteffect) this.options.starteffect(this.element);
349 if(this.options.starteffect) this.options.starteffect(this.element);
274 },
350 },
275
351
@@ -278,11 +354,34 Draggable.prototype = {
278 Position.prepare();
354 Position.prepare();
279 Droppables.show(pointer, this.element);
355 Droppables.show(pointer, this.element);
280 Draggables.notify('onDrag', this, event);
356 Draggables.notify('onDrag', this, event);
357
281 this.draw(pointer);
358 this.draw(pointer);
282 if(this.options.change) this.options.change(this);
359 if(this.options.change) this.options.change(this);
283
360
361 if(this.options.scroll) {
362 this.stopScrolling();
363
364 var p;
365 if (this.options.scroll == window) {
366 with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
367 } else {
368 p = Position.page(this.options.scroll);
369 p[0] += this.options.scroll.scrollLeft + Position.deltaX;
370 p[1] += this.options.scroll.scrollTop + Position.deltaY;
371 p.push(p[0]+this.options.scroll.offsetWidth);
372 p.push(p[1]+this.options.scroll.offsetHeight);
373 }
374 var speed = [0,0];
375 if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
376 if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
377 if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
378 if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
379 this.startScrolling(speed);
380 }
381
284 // fix AppleWebKit rendering
382 // fix AppleWebKit rendering
285 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
383 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
384
286 Event.stop(event);
385 Event.stop(event);
287 },
386 },
288
387
@@ -314,33 +413,46 Draggable.prototype = {
314
413
315 if(this.options.endeffect)
414 if(this.options.endeffect)
316 this.options.endeffect(this.element);
415 this.options.endeffect(this.element);
317
416
318 Draggables.deactivate(this);
417 Draggables.deactivate(this);
319 Droppables.reset();
418 Droppables.reset();
320 },
419 },
321
420
322 keyPress: function(event) {
421 keyPress: function(event) {
323 if(!event.keyCode==Event.KEY_ESC) return;
422 if(event.keyCode!=Event.KEY_ESC) return;
324 this.finishDrag(event, false);
423 this.finishDrag(event, false);
325 Event.stop(event);
424 Event.stop(event);
326 },
425 },
327
426
328 endDrag: function(event) {
427 endDrag: function(event) {
329 if(!this.dragging) return;
428 if(!this.dragging) return;
429 this.stopScrolling();
330 this.finishDrag(event, true);
430 this.finishDrag(event, true);
331 Event.stop(event);
431 Event.stop(event);
332 },
432 },
333
433
334 draw: function(point) {
434 draw: function(point) {
335 var pos = Position.cumulativeOffset(this.element);
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
336 var d = this.currentDelta();
441 var d = this.currentDelta();
337 pos[0] -= d[0]; pos[1] -= d[1];
442 pos[0] -= d[0]; pos[1] -= d[1];
338
443
339 var p = [0,1].map(function(i){ return (point[i]-pos[i]-this.offset[i]) }.bind(this));
444 if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
445 pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
446 pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
447 }
448
449 var p = [0,1].map(function(i){
450 return (point[i]-pos[i]-this.offset[i])
451 }.bind(this));
340
452
341 if(this.options.snap) {
453 if(this.options.snap) {
342 if(typeof this.options.snap == 'function') {
454 if(typeof this.options.snap == 'function') {
343 p = this.options.snap(p[0],p[1]);
455 p = this.options.snap(p[0],p[1],this);
344 } else {
456 } else {
345 if(this.options.snap instanceof Array) {
457 if(this.options.snap instanceof Array) {
346 p = p.map( function(v, i) {
458 p = p.map( function(v, i) {
@@ -356,7 +468,80 Draggable.prototype = {
356 style.left = p[0] + "px";
468 style.left = p[0] + "px";
357 if((!this.options.constraint) || (this.options.constraint=='vertical'))
469 if((!this.options.constraint) || (this.options.constraint=='vertical'))
358 style.top = p[1] + "px";
470 style.top = p[1] + "px";
471
359 if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
472 if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
473 },
474
475 stopScrolling: function() {
476 if(this.scrollInterval) {
477 clearInterval(this.scrollInterval);
478 this.scrollInterval = null;
479 Draggables._lastScrollPointer = null;
480 }
481 },
482
483 startScrolling: function(speed) {
484 if(!(speed[0] || speed[1])) return;
485 this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
486 this.lastScrolled = new Date();
487 this.scrollInterval = setInterval(this.scroll.bind(this), 10);
488 },
489
490 scroll: function() {
491 var current = new Date();
492 var delta = current - this.lastScrolled;
493 this.lastScrolled = current;
494 if(this.options.scroll == window) {
495 with (this._getWindowScroll(this.options.scroll)) {
496 if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
497 var d = delta / 1000;
498 this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
499 }
500 }
501 } else {
502 this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
503 this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
504 }
505
506 Position.prepare();
507 Droppables.show(Draggables._lastPointer, this.element);
508 Draggables.notify('onDrag', this);
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 }
519
520 if(this.options.change) this.options.change(this);
521 },
522
523 _getWindowScroll: function(w) {
524 var T, L, W, H;
525 with (w.document) {
526 if (w.document.documentElement && documentElement.scrollTop) {
527 T = documentElement.scrollTop;
528 L = documentElement.scrollLeft;
529 } else if (w.document.body) {
530 T = body.scrollTop;
531 L = body.scrollLeft;
532 }
533 if (w.innerWidth) {
534 W = w.innerWidth;
535 H = w.innerHeight;
536 } else if (w.document.documentElement && documentElement.clientWidth) {
537 W = documentElement.clientWidth;
538 H = documentElement.clientHeight;
539 } else {
540 W = body.offsetWidth;
541 H = body.offsetHeight
542 }
543 }
544 return { top: T, left: L, width: W, height: H };
360 }
545 }
361 }
546 }
362
547
@@ -382,38 +567,55 SortableObserver.prototype = {
382 }
567 }
383
568
384 var Sortable = {
569 var Sortable = {
385 sortables: new Array(),
570 SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
386
571
387 options: function(element){
572 sortables: {},
388 element = $(element);
573
389 return this.sortables.detect(function(s) { return s.element == element });
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];
390 },
585 },
391
586
392 destroy: function(element){
587 destroy: function(element){
393 element = $(element);
588 var s = Sortable.options(element);
394 this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
589
590 if(s) {
395 Draggables.removeObserver(s.element);
591 Draggables.removeObserver(s.element);
396 s.droppables.each(function(d){ Droppables.remove(d) });
592 s.droppables.each(function(d){ Droppables.remove(d) });
397 s.draggables.invoke('destroy');
593 s.draggables.invoke('destroy');
398 });
594
399 this.sortables = this.sortables.reject(function(s) { return s.element == element });
595 delete Sortable.sortables[s.element.id];
596 }
400 },
597 },
401
598
402 create: function(element) {
599 create: function(element) {
403 element = $(element);
600 element = $(element);
404 var options = Object.extend({
601 var options = Object.extend({
405 element: element,
602 element: element,
406 tag: 'li', // assumes li children, override with tag: 'tagname'
603 tag: 'li', // assumes li children, override with tag: 'tagname'
407 dropOnEmpty: false,
604 dropOnEmpty: false,
408 tree: false, // fixme: unimplemented
605 tree: false,
606 treeTag: 'ul',
409 overlap: 'vertical', // one of 'vertical', 'horizontal'
607 overlap: 'vertical', // one of 'vertical', 'horizontal'
410 constraint: 'vertical', // one of 'vertical', 'horizontal', false
608 constraint: 'vertical', // one of 'vertical', 'horizontal', false
411 containment: element, // also takes array of elements (or id's); or false
609 containment: element, // also takes array of elements (or id's); or false
412 handle: false, // or a CSS class
610 handle: false, // or a CSS class
413 only: false,
611 only: false,
612 delay: 0,
414 hoverclass: null,
613 hoverclass: null,
415 ghosting: false,
614 ghosting: false,
416 format: null,
615 scroll: false,
616 scrollSensitivity: 20,
617 scrollSpeed: 15,
618 format: this.SERIALIZE_RULE,
417 onChange: Prototype.emptyFunction,
619 onChange: Prototype.emptyFunction,
418 onUpdate: Prototype.emptyFunction
620 onUpdate: Prototype.emptyFunction
419 }, arguments[1] || {});
621 }, arguments[1] || {});
@@ -424,6 +626,10 var Sortable = {
424 // build options for the draggables
626 // build options for the draggables
425 var options_for_draggable = {
627 var options_for_draggable = {
426 revert: true,
628 revert: true,
629 scroll: options.scroll,
630 scrollSpeed: options.scrollSpeed,
631 scrollSensitivity: options.scrollSensitivity,
632 delay: options.delay,
427 ghosting: options.ghosting,
633 ghosting: options.ghosting,
428 constraint: options.constraint,
634 constraint: options.constraint,
429 handle: options.handle };
635 handle: options.handle };
@@ -449,9 +655,16 var Sortable = {
449 var options_for_droppable = {
655 var options_for_droppable = {
450 overlap: options.overlap,
656 overlap: options.overlap,
451 containment: options.containment,
657 containment: options.containment,
658 tree: options.tree,
452 hoverclass: options.hoverclass,
659 hoverclass: options.hoverclass,
453 onHover: Sortable.onHover,
660 onHover: Sortable.onHover
454 greedy: !options.dropOnEmpty
661 }
662
663 var options_for_tree = {
664 onHover: Sortable.onEmptyHover,
665 overlap: options.overlap,
666 containment: options.containment,
667 hoverclass: options.hoverclass
455 }
668 }
456
669
457 // fix for gecko engine
670 // fix for gecko engine
@@ -460,27 +673,33 var Sortable = {
460 options.draggables = [];
673 options.draggables = [];
461 options.droppables = [];
674 options.droppables = [];
462
675
463 // make it so
464
465 // drop on empty handling
676 // drop on empty handling
466 if(options.dropOnEmpty) {
677 if(options.dropOnEmpty || options.tree) {
467 Droppables.add(element,
678 Droppables.add(element, options_for_tree);
468 {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
469 options.droppables.push(element);
679 options.droppables.push(element);
470 }
680 }
471
681
472 (this.findElements(element, options) || []).each( function(e) {
682 (this.findElements(element, options) || []).each( function(e) {
473 // handles are per-draggable
683 // handles are per-draggable
474 var handle = options.handle ?
684 var handle = options.handle ?
475 Element.childrenWithClassName(e, options.handle)[0] : e;
685 $(e).down('.'+options.handle,0) : e;
476 options.draggables.push(
686 options.draggables.push(
477 new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
687 new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
478 Droppables.add(e, options_for_droppable);
688 Droppables.add(e, options_for_droppable);
689 if(options.tree) e.treeNode = element;
479 options.droppables.push(e);
690 options.droppables.push(e);
480 });
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 }
481
700
482 // keep reference
701 // keep reference
483 this.sortables.push(options);
702 this.sortables[element.id] = options;
484
703
485 // for onupdate
704 // for onupdate
486 Draggables.addObserver(new SortableObserver(element, options.onUpdate));
705 Draggables.addObserver(new SortableObserver(element, options.onUpdate));
@@ -489,23 +708,21 var Sortable = {
489
708
490 // return all suitable-for-sortable elements in a guaranteed order
709 // return all suitable-for-sortable elements in a guaranteed order
491 findElements: function(element, options) {
710 findElements: function(element, options) {
492 if(!element.hasChildNodes()) return null;
711 return Element.findChildren(
493 var elements = [];
712 element, options.only, options.tree ? true : false, options.tag);
494 $A(element.childNodes).each( function(e) {
713 },
495 if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
714
496 (!options.only || (Element.hasClassName(e, options.only))))
715 findTreeElements: function(element, options) {
497 elements.push(e);
716 return Element.findChildren(
498 if(options.tree) {
717 element, options.only, options.tree ? true : false, options.treeTag);
499 var grandchildren = this.findElements(e, options);
500 if(grandchildren) elements.push(grandchildren);
501 }
502 });
503
504 return (elements.length>0 ? elements.flatten() : null);
505 },
718 },
506
719
507 onHover: function(element, dropon, overlap) {
720 onHover: function(element, dropon, overlap) {
508 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) {
509 Sortable.mark(dropon, 'before');
726 Sortable.mark(dropon, 'before');
510 if(dropon.previousSibling != element) {
727 if(dropon.previousSibling != element) {
511 var oldParentNode = element.parentNode;
728 var oldParentNode = element.parentNode;
@@ -528,18 +745,42 var Sortable = {
528 }
745 }
529 }
746 }
530 },
747 },
531
748
532 onEmptyHover: function(element, dropon) {
749 onEmptyHover: function(element, dropon, overlap) {
533 if(element.parentNode!=dropon) {
750 var oldParentNode = element.parentNode;
534 var oldParentNode = element.parentNode;
751 var droponOptions = Sortable.options(dropon);
535 dropon.appendChild(element);
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
536 Sortable.options(oldParentNode).onChange(element);
777 Sortable.options(oldParentNode).onChange(element);
537 Sortable.options(dropon).onChange(element);
778 droponOptions.onChange(element);
538 }
779 }
539 },
780 },
540
781
541 unmark: function() {
782 unmark: function() {
542 if(Sortable._marker) Element.hide(Sortable._marker);
783 if(Sortable._marker) Sortable._marker.hide();
543 },
784 },
544
785
545 mark: function(dropon, position) {
786 mark: function(dropon, position) {
@@ -548,37 +789,154 var Sortable = {
548 if(sortable && !sortable.ghosting) return;
789 if(sortable && !sortable.ghosting) return;
549
790
550 if(!Sortable._marker) {
791 if(!Sortable._marker) {
551 Sortable._marker = $('dropmarker') || document.createElement('DIV');
792 Sortable._marker =
552 Element.hide(Sortable._marker);
793 ($('dropmarker') || Element.extend(document.createElement('DIV'))).
553 Element.addClassName(Sortable._marker, 'dropmarker');
794 hide().addClassName('dropmarker').setStyle({position:'absolute'});
554 Sortable._marker.style.position = 'absolute';
555 document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
795 document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
556 }
796 }
557 var offsets = Position.cumulativeOffset(dropon);
797 var offsets = Position.cumulativeOffset(dropon);
558 Sortable._marker.style.left = offsets[0] + 'px';
798 Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
559 Sortable._marker.style.top = offsets[1] + 'px';
560
799
561 if(position=='after')
800 if(position=='after')
562 if(sortable.overlap == 'horizontal')
801 if(sortable.overlap == 'horizontal')
563 Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
802 Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
564 else
803 else
565 Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
804 Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
566
805
567 Element.show(Sortable._marker);
806 Sortable._marker.show();
568 },
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);
569
814
570 serialize: function(element) {
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) {
571 element = $(element);
837 element = $(element);
572 var sortableOptions = this.options(element);
838 var sortableOptions = this.options(element);
573 var options = Object.extend({
839 var options = Object.extend({
574 tag: sortableOptions.tag,
840 tag: sortableOptions.tag,
841 treeTag: sortableOptions.treeTag,
575 only: sortableOptions.only,
842 only: sortableOptions.only,
576 name: element.id,
843 name: element.id,
577 format: sortableOptions.format || /^[^_]*_(.*)$/
844 format: sortableOptions.format
578 }, arguments[1] || {});
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;
865 },
866
867 sequence: function(element) {
868 element = $(element);
869 var options = Object.extend(this.options(element), arguments[1] || {});
870
579 return $(this.findElements(element, options) || []).map( function(item) {
871 return $(this.findElements(element, options) || []).map( function(item) {
580 return (encodeURIComponent(options.name) + "[]=" +
872 return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
581 encodeURIComponent(item.id.match(options.format) ? item.id.match(options.format)[1] : ''));
873 });
582 }).join("&");
874 },
875
876 setSequence: function(element, new_sequence) {
877 element = $(element);
878 var options = Object.extend(this.options(element), arguments[2] || {});
879
880 var nodeMap = {};
881 this.findElements(element, options).each( function(n) {
882 if (n.id.match(options.format))
883 nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
884 n.parentNode.removeChild(n);
885 });
886
887 new_sequence.each(function(ident) {
888 var n = nodeMap[ident];
889 if (n) {
890 n[1].appendChild(n[0]);
891 delete nodeMap[ident];
892 }
893 });
894 },
895
896 serialize: function(element) {
897 element = $(element);
898 var options = Object.extend(Sortable.options(element), arguments[1] || {});
899 var name = encodeURIComponent(
900 (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
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 }
583 }
912 }
584 } No newline at end of file
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 }
This diff has been collapsed as it changes many lines, (800 lines changed) Show them Hide them
@@ -1,17 +1,16
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 // Contributors:
2 // Contributors:
3 // Justin Palmer (http://encytemedia.com/)
3 // Justin Palmer (http://encytemedia.com/)
4 // Mark Pilgrim (http://diveintomark.org/)
4 // Mark Pilgrim (http://diveintomark.org/)
5 // Martin Bialasinki
5 // Martin Bialasinki
6 //
6 //
7 // See scriptaculous.js for full license.
7 // script.aculo.us is freely distributable under the terms of an MIT-style license.
8 // For details, see the script.aculo.us web site: http://script.aculo.us/
8
9
9 /* ------------- element ext -------------- */
10
11 // converts rgb() and #xxx to #xxxxxx format,
10 // converts rgb() and #xxx to #xxxxxx format,
12 // returns self (or first argument) if not convertable
11 // returns self (or first argument) if not convertable
13 String.prototype.parseColor = function() {
12 String.prototype.parseColor = function() {
14 var color = '#';
13 var color = '#';
15 if(this.slice(0,4) == 'rgb(') {
14 if(this.slice(0,4) == 'rgb(') {
16 var cols = this.slice(4,this.length-1).split(',');
15 var cols = this.slice(4,this.length-1).split(',');
17 var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
16 var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
@@ -22,40 +21,38 String.prototype.parseColor = function() {
22 }
21 }
23 }
22 }
24 return(color.length==7 ? color : (arguments[0] || this));
23 return(color.length==7 ? color : (arguments[0] || this));
25 }
24 }
26
25
27 Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
26 /*--------------------------------------------------------------------------*/
28 var children = $(element).childNodes;
27
29 var text = '';
28 Element.collectTextNodes = function(element) {
30 var classtest = new RegExp('^([^ ]+ )*' + ignoreclass+ '( [^ ]+)*$','i');
29 return $A($(element).childNodes).collect( function(node) {
31
30 return (node.nodeType==3 ? node.nodeValue :
32 for (var i = 0; i < children.length; i++) {
31 (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
33 if(children[i].nodeType==3) {
32 }).flatten().join('');
34 text+=children[i].nodeValue;
35 } else {
36 if((!children[i].className.match(classtest)) && children[i].hasChildNodes())
37 text += Element.collectTextNodesIgnoreClass(children[i], ignoreclass);
38 }
39 }
40
41 return text;
42 }
33 }
43
34
44 Element.setStyle = function(element, style) {
35 Element.collectTextNodesIgnoreClass = function(element, className) {
45 element = $(element);
36 return $A($(element).childNodes).collect( function(node) {
46 for(k in style) element.style[k.camelize()] = style[k];
37 return (node.nodeType==3 ? node.nodeValue :
38 ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
39 Element.collectTextNodesIgnoreClass(node, className) : ''));
40 }).flatten().join('');
47 }
41 }
48
42
49 Element.setContentZoom = function(element, percent) {
43 Element.setContentZoom = function(element, percent) {
50 Element.setStyle(element, {fontSize: (percent/100) + 'em'});
44 element = $(element);
51 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
45 element.setStyle({fontSize: (percent/100) + 'em'});
46 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
47 return element;
52 }
48 }
53
49
54 Element.getOpacity = function(element){
50 Element.getOpacity = function(element){
51 element = $(element);
55 var opacity;
52 var opacity;
56 if (opacity = Element.getStyle(element, 'opacity'))
53 if (opacity = element.getStyle('opacity'))
57 return parseFloat(opacity);
54 return parseFloat(opacity);
58 if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))
55 if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
59 if(opacity[1]) return parseFloat(opacity[1]) / 100;
56 if(opacity[1]) return parseFloat(opacity[1]) / 100;
60 return 1.0;
57 return 1.0;
61 }
58 }
@@ -63,29 +60,36 Element.getOpacity = function(element){
63 Element.setOpacity = function(element, value){
60 Element.setOpacity = function(element, value){
64 element= $(element);
61 element= $(element);
65 if (value == 1){
62 if (value == 1){
66 Element.setStyle(element, { opacity:
63 element.setStyle({ opacity:
67 (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
64 (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
68 0.999999 : null });
65 0.999999 : 1.0 });
69 if(/MSIE/.test(navigator.userAgent))
66 if(/MSIE/.test(navigator.userAgent) && !window.opera)
70 Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
67 element.setStyle({filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
71 } else {
68 } else {
72 if(value < 0.00001) value = 0;
69 if(value < 0.00001) value = 0;
73 Element.setStyle(element, {opacity: value});
70 element.setStyle({opacity: value});
74 if(/MSIE/.test(navigator.userAgent))
71 if(/MSIE/.test(navigator.userAgent) && !window.opera)
75 Element.setStyle(element,
72 element.setStyle(
76 { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
73 { filter: element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
77 'alpha(opacity='+value*100+')' });
74 'alpha(opacity='+value*100+')' });
78 }
75 }
76 return element;
79 }
77 }
80
78
81 Element.getInlineOpacity = function(element){
79 Element.getInlineOpacity = function(element){
82 return $(element).style.opacity || '';
80 return $(element).style.opacity || '';
83 }
81 }
84
82
85 Element.childrenWithClassName = function(element, className) {
83 Element.forceRerendering = function(element) {
86 return $A($(element).getElementsByTagName('*')).select(
84 try {
87 function(c) { return Element.hasClassName(c, className) });
85 element = $(element);
88 }
86 var n = document.createTextNode(' ');
87 element.appendChild(n);
88 element.removeChild(n);
89 } catch(e) { }
90 };
91
92 /*--------------------------------------------------------------------------*/
89
93
90 Array.prototype.call = function() {
94 Array.prototype.call = function() {
91 var args = arguments;
95 var args = arguments;
@@ -95,9 +99,17 Array.prototype.call = function() {
95 /*--------------------------------------------------------------------------*/
99 /*--------------------------------------------------------------------------*/
96
100
97 var Effect = {
101 var Effect = {
102 _elementDoesNotExistError: {
103 name: 'ElementDoesNotExistError',
104 message: 'The specified DOM element does not exist, but is required for this effect to operate'
105 },
98 tagifyText: function(element) {
106 tagifyText: function(element) {
107 if(typeof Builder == 'undefined')
108 throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
109
99 var tagifyStyle = 'position:relative';
110 var tagifyStyle = 'position:relative';
100 if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
111 if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
112
101 element = $(element);
113 element = $(element);
102 $A(element.childNodes).each( function(child) {
114 $A(element.childNodes).each( function(child) {
103 if(child.nodeType==3) {
115 if(child.nodeType==3) {
@@ -129,6 +141,20 var Effect = {
129 $A(elements).each( function(element, index) {
141 $A(elements).each( function(element, index) {
130 new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
142 new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
131 });
143 });
144 },
145 PAIRS: {
146 'slide': ['SlideDown','SlideUp'],
147 'blind': ['BlindDown','BlindUp'],
148 'appear': ['Appear','Fade']
149 },
150 toggle: function(element, effect) {
151 element = $(element);
152 effect = (effect || 'appear').toLowerCase();
153 var options = Object.extend({
154 queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
155 }, arguments[2] || {});
156 Effect[element.visible() ?
157 Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
132 }
158 }
133 };
159 };
134
160
@@ -136,46 +162,54 var Effect2 = Effect; // deprecated
136
162
137 /* ------------- transitions ------------- */
163 /* ------------- transitions ------------- */
138
164
139 Effect.Transitions = {}
165 Effect.Transitions = {
140
166 linear: Prototype.K,
141 Effect.Transitions.linear = function(pos) {
167 sinoidal: function(pos) {
142 return pos;
168 return (-Math.cos(pos*Math.PI)/2) + 0.5;
143 }
169 },
144 Effect.Transitions.sinoidal = function(pos) {
170 reverse: function(pos) {
145 return (-Math.cos(pos*Math.PI)/2) + 0.5;
171 return 1-pos;
146 }
172 },
147 Effect.Transitions.reverse = function(pos) {
173 flicker: function(pos) {
148 return 1-pos;
174 return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
149 }
175 },
150 Effect.Transitions.flicker = function(pos) {
176 wobble: function(pos) {
151 return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
177 return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
152 }
178 },
153 Effect.Transitions.wobble = function(pos) {
179 pulse: function(pos, pulses) {
154 return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
180 pulses = pulses || 5;
155 }
181 return (
156 Effect.Transitions.pulse = function(pos) {
182 Math.round((pos % (1/pulses)) * pulses) == 0 ?
157 return (Math.floor(pos*10) % 2 == 0 ?
183 ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
158 (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
184 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
159 }
185 );
160 Effect.Transitions.none = function(pos) {
186 },
161 return 0;
187 none: function(pos) {
162 }
188 return 0;
163 Effect.Transitions.full = function(pos) {
189 },
164 return 1;
190 full: function(pos) {
165 }
191 return 1;
192 }
193 };
166
194
167 /* ------------- core effects ------------- */
195 /* ------------- core effects ------------- */
168
196
169 Effect.Queue = {
197 Effect.ScopedQueue = Class.create();
170 effects: [],
198 Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
199 initialize: function() {
200 this.effects = [];
201 this.interval = null;
202 },
171 _each: function(iterator) {
203 _each: function(iterator) {
172 this.effects._each(iterator);
204 this.effects._each(iterator);
173 },
205 },
174 interval: null,
175 add: function(effect) {
206 add: function(effect) {
176 var timestamp = new Date().getTime();
207 var timestamp = new Date().getTime();
177
208
178 switch(effect.options.queue) {
209 var position = (typeof effect.options.queue == 'string') ?
210 effect.options.queue : effect.options.queue.position;
211
212 switch(position) {
179 case 'front':
213 case 'front':
180 // move unstarted effects after this effect
214 // move unstarted effects after this effect
181 this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
215 this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
@@ -183,6 +217,9 Effect.Queue = {
183 e.finishOn += effect.finishOn;
217 e.finishOn += effect.finishOn;
184 });
218 });
185 break;
219 break;
220 case 'with-last':
221 timestamp = this.effects.pluck('startOn').max() || timestamp;
222 break;
186 case 'end':
223 case 'end':
187 // start effect after last queued effect has finished
224 // start effect after last queued effect has finished
188 timestamp = this.effects.pluck('finishOn').max() || timestamp;
225 timestamp = this.effects.pluck('finishOn').max() || timestamp;
@@ -191,7 +228,10 Effect.Queue = {
191
228
192 effect.startOn += timestamp;
229 effect.startOn += timestamp;
193 effect.finishOn += timestamp;
230 effect.finishOn += timestamp;
194 this.effects.push(effect);
231
232 if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
233 this.effects.push(effect);
234
195 if(!this.interval)
235 if(!this.interval)
196 this.interval = setInterval(this.loop.bind(this), 40);
236 this.interval = setInterval(this.loop.bind(this), 40);
197 },
237 },
@@ -206,32 +246,45 Effect.Queue = {
206 var timePos = new Date().getTime();
246 var timePos = new Date().getTime();
207 this.effects.invoke('loop', timePos);
247 this.effects.invoke('loop', timePos);
208 }
248 }
249 });
250
251 Effect.Queues = {
252 instances: $H(),
253 get: function(queueName) {
254 if(typeof queueName != 'string') return queueName;
255
256 if(!this.instances[queueName])
257 this.instances[queueName] = new Effect.ScopedQueue();
258
259 return this.instances[queueName];
260 }
261 }
262 Effect.Queue = Effect.Queues.get('global');
263
264 Effect.DefaultOptions = {
265 transition: Effect.Transitions.sinoidal,
266 duration: 1.0, // seconds
267 fps: 25.0, // max. 25fps due to Effect.Queue implementation
268 sync: false, // true for combining
269 from: 0.0,
270 to: 1.0,
271 delay: 0.0,
272 queue: 'parallel'
209 }
273 }
210 Object.extend(Effect.Queue, Enumerable);
211
274
212 Effect.Base = function() {};
275 Effect.Base = function() {};
213 Effect.Base.prototype = {
276 Effect.Base.prototype = {
214 position: null,
277 position: null,
215 setOptions: function(options) {
216 this.options = Object.extend({
217 transition: Effect.Transitions.sinoidal,
218 duration: 1.0, // seconds
219 fps: 25.0, // max. 25fps due to Effect.Queue implementation
220 sync: false, // true for combining
221 from: 0.0,
222 to: 1.0,
223 delay: 0.0,
224 queue: 'parallel'
225 }, options || {});
226 },
227 start: function(options) {
278 start: function(options) {
228 this.setOptions(options || {});
279 this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
229 this.currentFrame = 0;
280 this.currentFrame = 0;
230 this.state = 'idle';
281 this.state = 'idle';
231 this.startOn = this.options.delay*1000;
282 this.startOn = this.options.delay*1000;
232 this.finishOn = this.startOn + (this.options.duration*1000);
283 this.finishOn = this.startOn + (this.options.duration*1000);
233 this.event('beforeStart');
284 this.event('beforeStart');
234 if(!this.options.sync) Effect.Queue.add(this);
285 if(!this.options.sync)
286 Effect.Queues.get(typeof this.options.queue == 'string' ?
287 'global' : this.options.queue.scope).add(this);
235 },
288 },
236 loop: function(timePos) {
289 loop: function(timePos) {
237 if(timePos >= this.startOn) {
290 if(timePos >= this.startOn) {
@@ -269,7 +322,9 Effect.Base.prototype = {
269 }
322 }
270 },
323 },
271 cancel: function() {
324 cancel: function() {
272 if(!this.options.sync) Effect.Queue.remove(this);
325 if(!this.options.sync)
326 Effect.Queues.get(typeof this.options.queue == 'string' ?
327 'global' : this.options.queue.scope).remove(this);
273 this.state = 'finished';
328 this.state = 'finished';
274 },
329 },
275 event: function(eventName) {
330 event: function(eventName) {
@@ -301,53 +356,81 Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
301 }
356 }
302 });
357 });
303
358
359 Effect.Event = Class.create();
360 Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
361 initialize: function() {
362 var options = Object.extend({
363 duration: 0
364 }, arguments[0] || {});
365 this.start(options);
366 },
367 update: Prototype.emptyFunction
368 });
369
304 Effect.Opacity = Class.create();
370 Effect.Opacity = Class.create();
305 Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
371 Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
306 initialize: function(element) {
372 initialize: function(element) {
307 this.element = $(element);
373 this.element = $(element);
374 if(!this.element) throw(Effect._elementDoesNotExistError);
308 // make this work on IE on elements without 'layout'
375 // make this work on IE on elements without 'layout'
309 if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
376 if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
310 Element.setStyle(this.element, {zoom: 1});
377 this.element.setStyle({zoom: 1});
311 var options = Object.extend({
378 var options = Object.extend({
312 from: Element.getOpacity(this.element) || 0.0,
379 from: this.element.getOpacity() || 0.0,
313 to: 1.0
380 to: 1.0
314 }, arguments[1] || {});
381 }, arguments[1] || {});
315 this.start(options);
382 this.start(options);
316 },
383 },
317 update: function(position) {
384 update: function(position) {
318 Element.setOpacity(this.element, position);
385 this.element.setOpacity(position);
319 }
386 }
320 });
387 });
321
388
322 Effect.MoveBy = Class.create();
389 Effect.Move = Class.create();
323 Object.extend(Object.extend(Effect.MoveBy.prototype, Effect.Base.prototype), {
390 Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
324 initialize: function(element, toTop, toLeft) {
391 initialize: function(element) {
325 this.element = $(element);
392 this.element = $(element);
326 this.toTop = toTop;
393 if(!this.element) throw(Effect._elementDoesNotExistError);
327 this.toLeft = toLeft;
394 var options = Object.extend({
328 this.start(arguments[3]);
395 x: 0,
396 y: 0,
397 mode: 'relative'
398 }, arguments[1] || {});
399 this.start(options);
329 },
400 },
330 setup: function() {
401 setup: function() {
331 // Bug in Opera: Opera returns the "real" position of a static element or
402 // Bug in Opera: Opera returns the "real" position of a static element or
332 // relative element that does not have top/left explicitly set.
403 // relative element that does not have top/left explicitly set.
333 // ==> Always set top and left for position relative elements in your stylesheets
404 // ==> Always set top and left for position relative elements in your stylesheets
334 // (to 0 if you do not need them)
405 // (to 0 if you do not need them)
335 Element.makePositioned(this.element);
406 this.element.makePositioned();
336 this.originalTop = parseFloat(Element.getStyle(this.element,'top') || '0');
407 this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
337 this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
408 this.originalTop = parseFloat(this.element.getStyle('top') || '0');
409 if(this.options.mode == 'absolute') {
410 // absolute movement, so we need to calc deltaX and deltaY
411 this.options.x = this.options.x - this.originalLeft;
412 this.options.y = this.options.y - this.originalTop;
413 }
338 },
414 },
339 update: function(position) {
415 update: function(position) {
340 Element.setStyle(this.element, {
416 this.element.setStyle({
341 top: this.toTop * position + this.originalTop + 'px',
417 left: Math.round(this.options.x * position + this.originalLeft) + 'px',
342 left: this.toLeft * position + this.originalLeft + 'px'
418 top: Math.round(this.options.y * position + this.originalTop) + 'px'
343 });
419 });
344 }
420 }
345 });
421 });
346
422
423 // for backwards compatibility
424 Effect.MoveBy = function(element, toTop, toLeft) {
425 return new Effect.Move(element,
426 Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
427 };
428
347 Effect.Scale = Class.create();
429 Effect.Scale = Class.create();
348 Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
430 Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
349 initialize: function(element, percent) {
431 initialize: function(element, percent) {
350 this.element = $(element)
432 this.element = $(element);
433 if(!this.element) throw(Effect._elementDoesNotExistError);
351 var options = Object.extend({
434 var options = Object.extend({
352 scaleX: true,
435 scaleX: true,
353 scaleY: true,
436 scaleY: true,
@@ -361,7 +444,7 Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
361 },
444 },
362 setup: function() {
445 setup: function() {
363 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
446 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
364 this.elementPositioning = Element.getStyle(this.element,'position');
447 this.elementPositioning = this.element.getStyle('position');
365
448
366 this.originalStyle = {};
449 this.originalStyle = {};
367 ['top','left','width','height','fontSize'].each( function(k) {
450 ['top','left','width','height','fontSize'].each( function(k) {
@@ -371,8 +454,8 Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
371 this.originalTop = this.element.offsetTop;
454 this.originalTop = this.element.offsetTop;
372 this.originalLeft = this.element.offsetLeft;
455 this.originalLeft = this.element.offsetLeft;
373
456
374 var fontSize = Element.getStyle(this.element,'font-size') || '100%';
457 var fontSize = this.element.getStyle('font-size') || '100%';
375 ['em','px','%'].each( function(fontSizeType) {
458 ['em','px','%','pt'].each( function(fontSizeType) {
376 if(fontSize.indexOf(fontSizeType)>0) {
459 if(fontSize.indexOf(fontSizeType)>0) {
377 this.fontSize = parseFloat(fontSize);
460 this.fontSize = parseFloat(fontSize);
378 this.fontSizeType = fontSizeType;
461 this.fontSizeType = fontSizeType;
@@ -393,16 +476,16 Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
393 update: function(position) {
476 update: function(position) {
394 var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
477 var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
395 if(this.options.scaleContent && this.fontSize)
478 if(this.options.scaleContent && this.fontSize)
396 Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType });
479 this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
397 this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
480 this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
398 },
481 },
399 finish: function(position) {
482 finish: function(position) {
400 if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle);
483 if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
401 },
484 },
402 setDimensions: function(height, width) {
485 setDimensions: function(height, width) {
403 var d = {};
486 var d = {};
404 if(this.options.scaleX) d.width = width + 'px';
487 if(this.options.scaleX) d.width = Math.round(width) + 'px';
405 if(this.options.scaleY) d.height = height + 'px';
488 if(this.options.scaleY) d.height = Math.round(height) + 'px';
406 if(this.options.scaleFromCenter) {
489 if(this.options.scaleFromCenter) {
407 var topd = (height - this.dims[0])/2;
490 var topd = (height - this.dims[0])/2;
408 var leftd = (width - this.dims[1])/2;
491 var leftd = (width - this.dims[1])/2;
@@ -414,7 +497,7 Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
414 if(this.options.scaleX) d.left = -leftd + 'px';
497 if(this.options.scaleX) d.left = -leftd + 'px';
415 }
498 }
416 }
499 }
417 Element.setStyle(this.element, d);
500 this.element.setStyle(d);
418 }
501 }
419 });
502 });
420
503
@@ -422,30 +505,31 Effect.Highlight = Class.create();
422 Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
505 Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
423 initialize: function(element) {
506 initialize: function(element) {
424 this.element = $(element);
507 this.element = $(element);
508 if(!this.element) throw(Effect._elementDoesNotExistError);
425 var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
509 var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
426 this.start(options);
510 this.start(options);
427 },
511 },
428 setup: function() {
512 setup: function() {
429 // Prevent executing on elements not in the layout flow
513 // Prevent executing on elements not in the layout flow
430 if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; }
514 if(this.element.getStyle('display')=='none') { this.cancel(); return; }
431 // Disable background image during the effect
515 // Disable background image during the effect
432 this.oldStyle = {
516 this.oldStyle = {
433 backgroundImage: Element.getStyle(this.element, 'background-image') };
517 backgroundImage: this.element.getStyle('background-image') };
434 Element.setStyle(this.element, {backgroundImage: 'none'});
518 this.element.setStyle({backgroundImage: 'none'});
435 if(!this.options.endcolor)
519 if(!this.options.endcolor)
436 this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
520 this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
437 if(!this.options.restorecolor)
521 if(!this.options.restorecolor)
438 this.options.restorecolor = Element.getStyle(this.element, 'background-color');
522 this.options.restorecolor = this.element.getStyle('background-color');
439 // init color calculations
523 // init color calculations
440 this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
524 this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
441 this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
525 this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
442 },
526 },
443 update: function(position) {
527 update: function(position) {
444 Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){
528 this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
445 return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
529 return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
446 },
530 },
447 finish: function() {
531 finish: function() {
448 Element.setStyle(this.element, Object.extend(this.oldStyle, {
532 this.element.setStyle(Object.extend(this.oldStyle, {
449 backgroundColor: this.options.restorecolor
533 backgroundColor: this.options.restorecolor
450 }));
534 }));
451 }
535 }
@@ -479,86 +563,93 Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
479 /* ------------- combination effects ------------- */
563 /* ------------- combination effects ------------- */
480
564
481 Effect.Fade = function(element) {
565 Effect.Fade = function(element) {
482 var oldOpacity = Element.getInlineOpacity(element);
566 element = $(element);
567 var oldOpacity = element.getInlineOpacity();
483 var options = Object.extend({
568 var options = Object.extend({
484 from: Element.getOpacity(element) || 1.0,
569 from: element.getOpacity() || 1.0,
485 to: 0.0,
570 to: 0.0,
486 afterFinishInternal: function(effect) { with(Element) {
571 afterFinishInternal: function(effect) {
487 if(effect.options.to!=0) return;
572 if(effect.options.to!=0) return;
488 hide(effect.element);
573 effect.element.hide().setStyle({opacity: oldOpacity});
489 setStyle(effect.element, {opacity: oldOpacity}); }}
574 }}, arguments[1] || {});
490 }, arguments[1] || {});
491 return new Effect.Opacity(element,options);
575 return new Effect.Opacity(element,options);
492 }
576 }
493
577
494 Effect.Appear = function(element) {
578 Effect.Appear = function(element) {
579 element = $(element);
495 var options = Object.extend({
580 var options = Object.extend({
496 from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0),
581 from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
497 to: 1.0,
582 to: 1.0,
498 beforeSetup: function(effect) { with(Element) {
583 // force Safari to render floated elements properly
499 setOpacity(effect.element, effect.options.from);
584 afterFinishInternal: function(effect) {
500 show(effect.element); }}
585 effect.element.forceRerendering();
501 }, arguments[1] || {});
586 },
587 beforeSetup: function(effect) {
588 effect.element.setOpacity(effect.options.from).show();
589 }}, arguments[1] || {});
502 return new Effect.Opacity(element,options);
590 return new Effect.Opacity(element,options);
503 }
591 }
504
592
505 Effect.Puff = function(element) {
593 Effect.Puff = function(element) {
506 element = $(element);
594 element = $(element);
507 var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') };
595 var oldStyle = {
596 opacity: element.getInlineOpacity(),
597 position: element.getStyle('position'),
598 top: element.style.top,
599 left: element.style.left,
600 width: element.style.width,
601 height: element.style.height
602 };
508 return new Effect.Parallel(
603 return new Effect.Parallel(
509 [ new Effect.Scale(element, 200,
604 [ new Effect.Scale(element, 200,
510 { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
605 { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
511 new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
606 new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
512 Object.extend({ duration: 1.0,
607 Object.extend({ duration: 1.0,
513 beforeSetupInternal: function(effect) { with(Element) {
608 beforeSetupInternal: function(effect) {
514 setStyle(effect.effects[0].element, {position: 'absolute'}); }},
609 Position.absolutize(effect.effects[0].element)
515 afterFinishInternal: function(effect) { with(Element) {
610 },
516 hide(effect.effects[0].element);
611 afterFinishInternal: function(effect) {
517 setStyle(effect.effects[0].element, oldStyle); }}
612 effect.effects[0].element.hide().setStyle(oldStyle); }
518 }, arguments[1] || {})
613 }, arguments[1] || {})
519 );
614 );
520 }
615 }
521
616
522 Effect.BlindUp = function(element) {
617 Effect.BlindUp = function(element) {
523 element = $(element);
618 element = $(element);
524 Element.makeClipping(element);
619 element.makeClipping();
525 return new Effect.Scale(element, 0,
620 return new Effect.Scale(element, 0,
526 Object.extend({ scaleContent: false,
621 Object.extend({ scaleContent: false,
527 scaleX: false,
622 scaleX: false,
528 restoreAfterFinish: true,
623 restoreAfterFinish: true,
529 afterFinishInternal: function(effect) { with(Element) {
624 afterFinishInternal: function(effect) {
530 [hide, undoClipping].call(effect.element); }}
625 effect.element.hide().undoClipping();
626 }
531 }, arguments[1] || {})
627 }, arguments[1] || {})
532 );
628 );
533 }
629 }
534
630
535 Effect.BlindDown = function(element) {
631 Effect.BlindDown = function(element) {
536 element = $(element);
632 element = $(element);
537 var oldHeight = Element.getStyle(element, 'height');
633 var elementDimensions = element.getDimensions();
538 var elementDimensions = Element.getDimensions(element);
634 return new Effect.Scale(element, 100, Object.extend({
539 return new Effect.Scale(element, 100,
635 scaleContent: false,
540 Object.extend({ scaleContent: false,
636 scaleX: false,
541 scaleX: false,
637 scaleFrom: 0,
542 scaleFrom: 0,
638 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
543 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
639 restoreAfterFinish: true,
544 restoreAfterFinish: true,
640 afterSetup: function(effect) {
545 afterSetup: function(effect) { with(Element) {
641 effect.element.makeClipping().setStyle({height: '0px'}).show();
546 makeClipping(effect.element);
642 },
547 setStyle(effect.element, {height: '0px'});
643 afterFinishInternal: function(effect) {
548 show(effect.element);
644 effect.element.undoClipping();
549 }},
645 }
550 afterFinishInternal: function(effect) { with(Element) {
646 }, arguments[1] || {}));
551 undoClipping(effect.element);
552 setStyle(effect.element, {height: oldHeight});
553 }}
554 }, arguments[1] || {})
555 );
556 }
647 }
557
648
558 Effect.SwitchOff = function(element) {
649 Effect.SwitchOff = function(element) {
559 element = $(element);
650 element = $(element);
560 var oldOpacity = Element.getInlineOpacity(element);
651 var oldOpacity = element.getInlineOpacity();
561 return new Effect.Appear(element, {
652 return new Effect.Appear(element, Object.extend({
562 duration: 0.4,
653 duration: 0.4,
563 from: 0,
654 from: 0,
564 transition: Effect.Transitions.flicker,
655 transition: Effect.Transitions.flicker,
@@ -566,127 +657,123 Effect.SwitchOff = function(element) {
566 new Effect.Scale(effect.element, 1, {
657 new Effect.Scale(effect.element, 1, {
567 duration: 0.3, scaleFromCenter: true,
658 duration: 0.3, scaleFromCenter: true,
568 scaleX: false, scaleContent: false, restoreAfterFinish: true,
659 scaleX: false, scaleContent: false, restoreAfterFinish: true,
569 beforeSetup: function(effect) { with(Element) {
660 beforeSetup: function(effect) {
570 [makePositioned,makeClipping].call(effect.element);
661 effect.element.makePositioned().makeClipping();
571 }},
662 },
572 afterFinishInternal: function(effect) { with(Element) {
663 afterFinishInternal: function(effect) {
573 [hide,undoClipping,undoPositioned].call(effect.element);
664 effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
574 setStyle(effect.element, {opacity: oldOpacity});
665 }
575 }}
576 })
666 })
577 }
667 }
578 });
668 }, arguments[1] || {}));
579 }
669 }
580
670
581 Effect.DropOut = function(element) {
671 Effect.DropOut = function(element) {
582 element = $(element);
672 element = $(element);
583 var oldStyle = {
673 var oldStyle = {
584 top: Element.getStyle(element, 'top'),
674 top: element.getStyle('top'),
585 left: Element.getStyle(element, 'left'),
675 left: element.getStyle('left'),
586 opacity: Element.getInlineOpacity(element) };
676 opacity: element.getInlineOpacity() };
587 return new Effect.Parallel(
677 return new Effect.Parallel(
588 [ new Effect.MoveBy(element, 100, 0, { sync: true }),
678 [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
589 new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
679 new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
590 Object.extend(
680 Object.extend(
591 { duration: 0.5,
681 { duration: 0.5,
592 beforeSetup: function(effect) { with(Element) {
682 beforeSetup: function(effect) {
593 makePositioned(effect.effects[0].element); }},
683 effect.effects[0].element.makePositioned();
594 afterFinishInternal: function(effect) { with(Element) {
684 },
595 [hide, undoPositioned].call(effect.effects[0].element);
685 afterFinishInternal: function(effect) {
596 setStyle(effect.effects[0].element, oldStyle); }}
686 effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
687 }
597 }, arguments[1] || {}));
688 }, arguments[1] || {}));
598 }
689 }
599
690
600 Effect.Shake = function(element) {
691 Effect.Shake = function(element) {
601 element = $(element);
692 element = $(element);
602 var oldStyle = {
693 var oldStyle = {
603 top: Element.getStyle(element, 'top'),
694 top: element.getStyle('top'),
604 left: Element.getStyle(element, 'left') };
695 left: element.getStyle('left') };
605 return new Effect.MoveBy(element, 0, 20,
696 return new Effect.Move(element,
606 { duration: 0.05, afterFinishInternal: function(effect) {
697 { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
607 new Effect.MoveBy(effect.element, 0, -40,
698 new Effect.Move(effect.element,
608 { duration: 0.1, afterFinishInternal: function(effect) {
699 { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
609 new Effect.MoveBy(effect.element, 0, 40,
700 new Effect.Move(effect.element,
610 { duration: 0.1, afterFinishInternal: function(effect) {
701 { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
611 new Effect.MoveBy(effect.element, 0, -40,
702 new Effect.Move(effect.element,
612 { duration: 0.1, afterFinishInternal: function(effect) {
703 { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
613 new Effect.MoveBy(effect.element, 0, 40,
704 new Effect.Move(effect.element,
614 { duration: 0.1, afterFinishInternal: function(effect) {
705 { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
615 new Effect.MoveBy(effect.element, 0, -20,
706 new Effect.Move(effect.element,
616 { duration: 0.05, afterFinishInternal: function(effect) { with(Element) {
707 { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
617 undoPositioned(effect.element);
708 effect.element.undoPositioned().setStyle(oldStyle);
618 setStyle(effect.element, oldStyle);
709 }}) }}) }}) }}) }}) }});
619 }}}) }}) }}) }}) }}) }});
620 }
710 }
621
711
622 Effect.SlideDown = function(element) {
712 Effect.SlideDown = function(element) {
623 element = $(element);
713 element = $(element).cleanWhitespace();
624 Element.cleanWhitespace(element);
625 // SlideDown need to have the content of the element wrapped in a container element with fixed height!
714 // SlideDown need to have the content of the element wrapped in a container element with fixed height!
626 var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
715 var oldInnerBottom = element.down().getStyle('bottom');
627 var elementDimensions = Element.getDimensions(element);
716 var elementDimensions = element.getDimensions();
628 return new Effect.Scale(element, 100, Object.extend({
717 return new Effect.Scale(element, 100, Object.extend({
629 scaleContent: false,
718 scaleContent: false,
630 scaleX: false,
719 scaleX: false,
631 scaleFrom: 0,
720 scaleFrom: window.opera ? 0 : 1,
632 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
721 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
633 restoreAfterFinish: true,
722 restoreAfterFinish: true,
634 afterSetup: function(effect) { with(Element) {
723 afterSetup: function(effect) {
635 makePositioned(effect.element);
724 effect.element.makePositioned();
636 makePositioned(effect.element.firstChild);
725 effect.element.down().makePositioned();
637 if(window.opera) setStyle(effect.element, {top: ''});
726 if(window.opera) effect.element.setStyle({top: ''});
638 makeClipping(effect.element);
727 effect.element.makeClipping().setStyle({height: '0px'}).show();
639 setStyle(effect.element, {height: '0px'});
728 },
640 show(element); }},
729 afterUpdateInternal: function(effect) {
641 afterUpdateInternal: function(effect) { with(Element) {
730 effect.element.down().setStyle({bottom:
642 setStyle(effect.element.firstChild, {bottom:
731 (effect.dims[0] - effect.element.clientHeight) + 'px' });
643 (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
732 },
644 afterFinishInternal: function(effect) { with(Element) {
733 afterFinishInternal: function(effect) {
645 undoClipping(effect.element);
734 effect.element.undoClipping().undoPositioned();
646 undoPositioned(effect.element.firstChild);
735 effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
647 undoPositioned(effect.element);
648 setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
649 }, arguments[1] || {})
736 }, arguments[1] || {})
650 );
737 );
651 }
738 }
652
739
653 Effect.SlideUp = function(element) {
740 Effect.SlideUp = function(element) {
654 element = $(element);
741 element = $(element).cleanWhitespace();
655 Element.cleanWhitespace(element);
742 var oldInnerBottom = element.down().getStyle('bottom');
656 var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
743 return new Effect.Scale(element, window.opera ? 0 : 1,
657 return new Effect.Scale(element, 0,
658 Object.extend({ scaleContent: false,
744 Object.extend({ scaleContent: false,
659 scaleX: false,
745 scaleX: false,
660 scaleMode: 'box',
746 scaleMode: 'box',
661 scaleFrom: 100,
747 scaleFrom: 100,
662 restoreAfterFinish: true,
748 restoreAfterFinish: true,
663 beforeStartInternal: function(effect) { with(Element) {
749 beforeStartInternal: function(effect) {
664 makePositioned(effect.element);
750 effect.element.makePositioned();
665 makePositioned(effect.element.firstChild);
751 effect.element.down().makePositioned();
666 if(window.opera) setStyle(effect.element, {top: ''});
752 if(window.opera) effect.element.setStyle({top: ''});
667 makeClipping(effect.element);
753 effect.element.makeClipping().show();
668 show(element); }},
754 },
669 afterUpdateInternal: function(effect) { with(Element) {
755 afterUpdateInternal: function(effect) {
670 setStyle(effect.element.firstChild, {bottom:
756 effect.element.down().setStyle({bottom:
671 (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
757 (effect.dims[0] - effect.element.clientHeight) + 'px' });
672 afterFinishInternal: function(effect) { with(Element) {
758 },
673 [hide, undoClipping].call(effect.element);
759 afterFinishInternal: function(effect) {
674 undoPositioned(effect.element.firstChild);
760 effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
675 undoPositioned(effect.element);
761 effect.element.down().undoPositioned();
676 setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
762 }
677 }, arguments[1] || {})
763 }, arguments[1] || {})
678 );
764 );
679 }
765 }
680
766
681 // Bug in opera makes the TD containing this element expand for a instance after finish
767 // Bug in opera makes the TD containing this element expand for a instance after finish
682 Effect.Squish = function(element) {
768 Effect.Squish = function(element) {
683 return new Effect.Scale(element, window.opera ? 1 : 0,
769 return new Effect.Scale(element, window.opera ? 1 : 0, {
684 { restoreAfterFinish: true,
770 restoreAfterFinish: true,
685 beforeSetup: function(effect) { with(Element) {
771 beforeSetup: function(effect) {
686 makeClipping(effect.element); }},
772 effect.element.makeClipping();
687 afterFinishInternal: function(effect) { with(Element) {
773 },
688 hide(effect.element);
774 afterFinishInternal: function(effect) {
689 undoClipping(effect.element); }}
775 effect.element.hide().undoClipping();
776 }
690 });
777 });
691 }
778 }
692
779
@@ -694,7 +781,7 Effect.Grow = function(element) {
694 element = $(element);
781 element = $(element);
695 var options = Object.extend({
782 var options = Object.extend({
696 direction: 'center',
783 direction: 'center',
697 moveTransistion: Effect.Transitions.sinoidal,
784 moveTransition: Effect.Transitions.sinoidal,
698 scaleTransition: Effect.Transitions.sinoidal,
785 scaleTransition: Effect.Transitions.sinoidal,
699 opacityTransition: Effect.Transitions.full
786 opacityTransition: Effect.Transitions.full
700 }, arguments[1] || {});
787 }, arguments[1] || {});
@@ -703,9 +790,9 Effect.Grow = function(element) {
703 left: element.style.left,
790 left: element.style.left,
704 height: element.style.height,
791 height: element.style.height,
705 width: element.style.width,
792 width: element.style.width,
706 opacity: Element.getInlineOpacity(element) };
793 opacity: element.getInlineOpacity() };
707
794
708 var dims = Element.getDimensions(element);
795 var dims = element.getDimensions();
709 var initialMoveX, initialMoveY;
796 var initialMoveX, initialMoveY;
710 var moveX, moveY;
797 var moveX, moveY;
711
798
@@ -737,27 +824,27 Effect.Grow = function(element) {
737 break;
824 break;
738 }
825 }
739
826
740 return new Effect.MoveBy(element, initialMoveY, initialMoveX, {
827 return new Effect.Move(element, {
828 x: initialMoveX,
829 y: initialMoveY,
741 duration: 0.01,
830 duration: 0.01,
742 beforeSetup: function(effect) { with(Element) {
831 beforeSetup: function(effect) {
743 hide(effect.element);
832 effect.element.hide().makeClipping().makePositioned();
744 makeClipping(effect.element);
833 },
745 makePositioned(effect.element);
746 }},
747 afterFinishInternal: function(effect) {
834 afterFinishInternal: function(effect) {
748 new Effect.Parallel(
835 new Effect.Parallel(
749 [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
836 [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
750 new Effect.MoveBy(effect.element, moveY, moveX, { sync: true, transition: options.moveTransition }),
837 new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
751 new Effect.Scale(effect.element, 100, {
838 new Effect.Scale(effect.element, 100, {
752 scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
839 scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
753 sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
840 sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
754 ], Object.extend({
841 ], Object.extend({
755 beforeSetup: function(effect) { with(Element) {
842 beforeSetup: function(effect) {
756 setStyle(effect.effects[0].element, {height: '0px'});
843 effect.effects[0].element.setStyle({height: '0px'}).show();
757 show(effect.effects[0].element); }},
844 },
758 afterFinishInternal: function(effect) { with(Element) {
845 afterFinishInternal: function(effect) {
759 [undoClipping, undoPositioned].call(effect.effects[0].element);
846 effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
760 setStyle(effect.effects[0].element, oldStyle); }}
847 }
761 }, options)
848 }, options)
762 )
849 )
763 }
850 }
@@ -768,7 +855,7 Effect.Shrink = function(element) {
768 element = $(element);
855 element = $(element);
769 var options = Object.extend({
856 var options = Object.extend({
770 direction: 'center',
857 direction: 'center',
771 moveTransistion: Effect.Transitions.sinoidal,
858 moveTransition: Effect.Transitions.sinoidal,
772 scaleTransition: Effect.Transitions.sinoidal,
859 scaleTransition: Effect.Transitions.sinoidal,
773 opacityTransition: Effect.Transitions.none
860 opacityTransition: Effect.Transitions.none
774 }, arguments[1] || {});
861 }, arguments[1] || {});
@@ -777,9 +864,9 Effect.Shrink = function(element) {
777 left: element.style.left,
864 left: element.style.left,
778 height: element.style.height,
865 height: element.style.height,
779 width: element.style.width,
866 width: element.style.width,
780 opacity: Element.getInlineOpacity(element) };
867 opacity: element.getInlineOpacity() };
781
868
782 var dims = Element.getDimensions(element);
869 var dims = element.getDimensions();
783 var moveX, moveY;
870 var moveX, moveY;
784
871
785 switch (options.direction) {
872 switch (options.direction) {
@@ -807,13 +894,13 Effect.Shrink = function(element) {
807 return new Effect.Parallel(
894 return new Effect.Parallel(
808 [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
895 [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
809 new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
896 new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
810 new Effect.MoveBy(element, moveY, moveX, { sync: true, transition: options.moveTransition })
897 new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
811 ], Object.extend({
898 ], Object.extend({
812 beforeStartInternal: function(effect) { with(Element) {
899 beforeStartInternal: function(effect) {
813 [makePositioned, makeClipping].call(effect.effects[0].element) }},
900 effect.effects[0].element.makePositioned().makeClipping();
814 afterFinishInternal: function(effect) { with(Element) {
901 },
815 [hide, undoClipping, undoPositioned].call(effect.effects[0].element);
902 afterFinishInternal: function(effect) {
816 setStyle(effect.effects[0].element, oldStyle); }}
903 effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
817 }, options)
904 }, options)
818 );
905 );
819 }
906 }
@@ -821,13 +908,13 Effect.Shrink = function(element) {
821 Effect.Pulsate = function(element) {
908 Effect.Pulsate = function(element) {
822 element = $(element);
909 element = $(element);
823 var options = arguments[1] || {};
910 var options = arguments[1] || {};
824 var oldOpacity = Element.getInlineOpacity(element);
911 var oldOpacity = element.getInlineOpacity();
825 var transition = options.transition || Effect.Transitions.sinoidal;
912 var transition = options.transition || Effect.Transitions.sinoidal;
826 var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
913 var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
827 reverser.bind(transition);
914 reverser.bind(transition);
828 return new Effect.Opacity(element,
915 return new Effect.Opacity(element,
829 Object.extend(Object.extend({ duration: 3.0, from: 0,
916 Object.extend(Object.extend({ duration: 2.0, from: 0,
830 afterFinishInternal: function(effect) { Element.setStyle(effect.element, {opacity: oldOpacity}); }
917 afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
831 }, options), {transition: reverser}));
918 }, options), {transition: reverser}));
832 }
919 }
833
920
@@ -838,7 +925,7 Effect.Fold = function(element) {
838 left: element.style.left,
925 left: element.style.left,
839 width: element.style.width,
926 width: element.style.width,
840 height: element.style.height };
927 height: element.style.height };
841 Element.makeClipping(element);
928 element.makeClipping();
842 return new Effect.Scale(element, 5, Object.extend({
929 return new Effect.Scale(element, 5, Object.extend({
843 scaleContent: false,
930 scaleContent: false,
844 scaleX: false,
931 scaleX: false,
@@ -846,9 +933,156 Effect.Fold = function(element) {
846 new Effect.Scale(element, 1, {
933 new Effect.Scale(element, 1, {
847 scaleContent: false,
934 scaleContent: false,
848 scaleY: false,
935 scaleY: false,
849 afterFinishInternal: function(effect) { with(Element) {
936 afterFinishInternal: function(effect) {
850 [hide, undoClipping].call(effect.element);
937 effect.element.hide().undoClipping().setStyle(oldStyle);
851 setStyle(effect.element, oldStyle);
938 } });
852 }} });
853 }}, arguments[1] || {}));
939 }}, arguments[1] || {}));
854 }
940 };
941
942 Effect.Morph = Class.create();
943 Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
944 initialize: function(element) {
945 this.element = $(element);
946 if(!this.element) throw(Effect._elementDoesNotExistError);
947 var options = Object.extend({
948 style: ''
949 }, arguments[1] || {});
950 this.start(options);
951 },
952 setup: function(){
953 function parseColor(color){
954 if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
955 color = color.parseColor();
956 return $R(0,2).map(function(i){
957 return parseInt( color.slice(i*2+1,i*2+3), 16 )
958 });
959 }
960 this.transforms = this.options.style.parseStyle().map(function(property){
961 var originalValue = this.element.getStyle(property[0]);
962 return $H({
963 style: property[0],
964 originalValue: property[1].unit=='color' ?
965 parseColor(originalValue) : parseFloat(originalValue || 0),
966 targetValue: property[1].unit=='color' ?
967 parseColor(property[1].value) : property[1].value,
968 unit: property[1].unit
969 });
970 }.bind(this)).reject(function(transform){
971 return (
972 (transform.originalValue == transform.targetValue) ||
973 (
974 transform.unit != 'color' &&
975 (isNaN(transform.originalValue) || isNaN(transform.targetValue))
976 )
977 )
978 });
979 },
980 update: function(position) {
981 var style = $H(), value = null;
982 this.transforms.each(function(transform){
983 value = transform.unit=='color' ?
984 $R(0,2).inject('#',function(m,v,i){
985 return m+(Math.round(transform.originalValue[i]+
986 (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) :
987 transform.originalValue + Math.round(
988 ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
989 style[transform.style] = value;
990 });
991 this.element.setStyle(style);
992 }
993 });
994
995 Effect.Transform = Class.create();
996 Object.extend(Effect.Transform.prototype, {
997 initialize: function(tracks){
998 this.tracks = [];
999 this.options = arguments[1] || {};
1000 this.addTracks(tracks);
1001 },
1002 addTracks: function(tracks){
1003 tracks.each(function(track){
1004 var data = $H(track).values().first();
1005 this.tracks.push($H({
1006 ids: $H(track).keys().first(),
1007 effect: Effect.Morph,
1008 options: { style: data }
1009 }));
1010 }.bind(this));
1011 return this;
1012 },
1013 play: function(){
1014 return new Effect.Parallel(
1015 this.tracks.map(function(track){
1016 var elements = [$(track.ids) || $$(track.ids)].flatten();
1017 return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
1018 }).flatten(),
1019 this.options
1020 );
1021 }
1022 });
1023
1024 Element.CSS_PROPERTIES = ['azimuth', 'backgroundAttachment', 'backgroundColor', 'backgroundImage',
1025 'backgroundPosition', 'backgroundRepeat', 'borderBottomColor', 'borderBottomStyle',
1026 'borderBottomWidth', 'borderCollapse', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth',
1027 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderSpacing', 'borderTopColor',
1028 'borderTopStyle', 'borderTopWidth', 'bottom', 'captionSide', 'clear', 'clip', 'color', 'content',
1029 'counterIncrement', 'counterReset', 'cssFloat', 'cueAfter', 'cueBefore', 'cursor', 'direction',
1030 'display', 'elevation', 'emptyCells', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch',
1031 'fontStyle', 'fontVariant', 'fontWeight', 'height', 'left', 'letterSpacing', 'lineHeight',
1032 'listStyleImage', 'listStylePosition', 'listStyleType', 'marginBottom', 'marginLeft', 'marginRight',
1033 'marginTop', 'markerOffset', 'marks', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'opacity',
1034 'orphans', 'outlineColor', 'outlineOffset', 'outlineStyle', 'outlineWidth', 'overflowX', 'overflowY',
1035 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'page', 'pageBreakAfter', 'pageBreakBefore',
1036 'pageBreakInside', 'pauseAfter', 'pauseBefore', 'pitch', 'pitchRange', 'position', 'quotes',
1037 'richness', 'right', 'size', 'speakHeader', 'speakNumeral', 'speakPunctuation', 'speechRate', 'stress',
1038 'tableLayout', 'textAlign', 'textDecoration', 'textIndent', 'textShadow', 'textTransform', 'top',
1039 'unicodeBidi', 'verticalAlign', 'visibility', 'voiceFamily', 'volume', 'whiteSpace', 'widows',
1040 'width', 'wordSpacing', 'zIndex'];
1041
1042 Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1043
1044 String.prototype.parseStyle = function(){
1045 var element = Element.extend(document.createElement('div'));
1046 element.innerHTML = '<div style="' + this + '"></div>';
1047 var style = element.down().style, styleRules = $H();
1048
1049 Element.CSS_PROPERTIES.each(function(property){
1050 if(style[property]) styleRules[property] = style[property];
1051 });
1052
1053 var result = $H();
1054
1055 styleRules.each(function(pair){
1056 var property = pair[0], value = pair[1], unit = null;
1057
1058 if(value.parseColor('#zzzzzz') != '#zzzzzz') {
1059 value = value.parseColor();
1060 unit = 'color';
1061 } else if(Element.CSS_LENGTH.test(value))
1062 var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
1063 value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
1064
1065 result[property.underscore().dasherize()] = $H({ value:value, unit:unit });
1066 }.bind(this));
1067
1068 return result;
1069 };
1070
1071 Element.morph = function(element, style) {
1072 new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1073 return element;
1074 };
1075
1076 ['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
1077 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
1078 function(f) { Element.Methods[f] = Element[f]; }
1079 );
1080
1081 Element.Methods.visualEffect = function(element, effect, options) {
1082 s = effect.gsub(/_/, '-').camelize();
1083 effect_class = s.charAt(0).toUpperCase() + s.substring(1);
1084 new Effect[effect_class](element, options);
1085 return $(element);
1086 };
1087
1088 Element.addMethods(); No newline at end of file
This diff has been collapsed as it changes many lines, (558 lines changed) Show them Hide them
@@ -1,5 +1,5
1 /* Prototype JavaScript framework, version 1.5.0_rc1
1 /* Prototype JavaScript framework, version 1.5.0
2 * (c) 2005 Sam Stephenson <sam@conio.net>
2 * (c) 2005-2007 Sam Stephenson
3 *
3 *
4 * Prototype is freely distributable under the terms of an MIT-style license.
4 * Prototype is freely distributable under the terms of an MIT-style license.
5 * For details, see the Prototype web site: http://prototype.conio.net/
5 * For details, see the Prototype web site: http://prototype.conio.net/
@@ -7,7 +7,7
7 /*--------------------------------------------------------------------------*/
7 /*--------------------------------------------------------------------------*/
8
8
9 var Prototype = {
9 var Prototype = {
10 Version: '1.5.0_rc1',
10 Version: '1.5.0',
11 BrowserFeatures: {
11 BrowserFeatures: {
12 XPath: !!document.evaluate
12 XPath: !!document.evaluate
13 },
13 },
@@ -100,7 +100,7 var Try = {
100 these: function() {
100 these: function() {
101 var returnValue;
101 var returnValue;
102
102
103 for (var i = 0; i < arguments.length; i++) {
103 for (var i = 0, length = arguments.length; i < length; i++) {
104 var lambda = arguments[i];
104 var lambda = arguments[i];
105 try {
105 try {
106 returnValue = lambda();
106 returnValue = lambda();
@@ -145,6 +145,10 PeriodicalExecuter.prototype = {
145 }
145 }
146 }
146 }
147 }
147 }
148 String.interpret = function(value){
149 return value == null ? '' : String(value);
150 }
151
148 Object.extend(String.prototype, {
152 Object.extend(String.prototype, {
149 gsub: function(pattern, replacement) {
153 gsub: function(pattern, replacement) {
150 var result = '', source = this, match;
154 var result = '', source = this, match;
@@ -153,7 +157,7 Object.extend(String.prototype, {
153 while (source.length > 0) {
157 while (source.length > 0) {
154 if (match = source.match(pattern)) {
158 if (match = source.match(pattern)) {
155 result += source.slice(0, match.index);
159 result += source.slice(0, match.index);
156 result += (replacement(match) || '').toString();
160 result += String.interpret(replacement(match));
157 source = source.slice(match.index + match[0].length);
161 source = source.slice(match.index + match[0].length);
158 } else {
162 } else {
159 result += source, source = '';
163 result += source, source = '';
@@ -218,18 +222,28 Object.extend(String.prototype, {
218 unescapeHTML: function() {
222 unescapeHTML: function() {
219 var div = document.createElement('div');
223 var div = document.createElement('div');
220 div.innerHTML = this.stripTags();
224 div.innerHTML = this.stripTags();
221 return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
225 return div.childNodes[0] ? (div.childNodes.length > 1 ?
226 $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
227 div.childNodes[0].nodeValue) : '';
222 },
228 },
223
229
224 toQueryParams: function() {
230 toQueryParams: function(separator) {
225 var match = this.strip().match(/[^?]*$/)[0];
231 var match = this.strip().match(/([^?#]*)(#.*)?$/);
226 if (!match) return {};
232 if (!match) return {};
227 var pairs = match.split('&');
233
228 return pairs.inject({}, function(params, pairString) {
234 return match[1].split(separator || '&').inject({}, function(hash, pair) {
229 var pair = pairString.split('=');
235 if ((pair = pair.split('='))[0]) {
230 var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
236 var name = decodeURIComponent(pair[0]);
231 params[decodeURIComponent(pair[0])] = value;
237 var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
232 return params;
238
239 if (hash[name] !== undefined) {
240 if (hash[name].constructor != Array)
241 hash[name] = [hash[name]];
242 if (value) hash[name].push(value);
243 }
244 else hash[name] = value;
245 }
246 return hash;
233 });
247 });
234 },
248 },
235
249
@@ -237,20 +251,35 Object.extend(String.prototype, {
237 return this.split('');
251 return this.split('');
238 },
252 },
239
253
254 succ: function() {
255 return this.slice(0, this.length - 1) +
256 String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
257 },
258
240 camelize: function() {
259 camelize: function() {
241 var oStringList = this.split('-');
260 var parts = this.split('-'), len = parts.length;
242 if (oStringList.length == 1) return oStringList[0];
261 if (len == 1) return parts[0];
243
262
244 var camelizedString = this.indexOf('-') == 0
263 var camelized = this.charAt(0) == '-'
245 ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
264 ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
246 : oStringList[0];
265 : parts[0];
247
266
248 for (var i = 1, length = oStringList.length; i < length; i++) {
267 for (var i = 1; i < len; i++)
249 var s = oStringList[i];
268 camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
250 camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
269
251 }
270 return camelized;
271 },
272
273 capitalize: function(){
274 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
275 },
252
276
253 return camelizedString;
277 underscore: function() {
278 return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
279 },
280
281 dasherize: function() {
282 return this.gsub(/_/,'-');
254 },
283 },
255
284
256 inspect: function(useDoubleQuotes) {
285 inspect: function(useDoubleQuotes) {
@@ -282,7 +311,7 Template.prototype = {
282 return this.template.gsub(this.pattern, function(match) {
311 return this.template.gsub(this.pattern, function(match) {
283 var before = match[1];
312 var before = match[1];
284 if (before == '\\') return match[2];
313 if (before == '\\') return match[2];
285 return before + (object[match[3]] || '').toString();
314 return before + String.interpret(object[match[3]]);
286 });
315 });
287 }
316 }
288 }
317 }
@@ -311,7 +340,7 var Enumerable = {
311 var index = -number, slices = [], array = this.toArray();
340 var index = -number, slices = [], array = this.toArray();
312 while ((index += number) < array.length)
341 while ((index += number) < array.length)
313 slices.push(array.slice(index, index+number));
342 slices.push(array.slice(index, index+number));
314 return slices.collect(iterator || Prototype.K);
343 return slices.map(iterator);
315 },
344 },
316
345
317 all: function(iterator) {
346 all: function(iterator) {
@@ -335,7 +364,7 var Enumerable = {
335 collect: function(iterator) {
364 collect: function(iterator) {
336 var results = [];
365 var results = [];
337 this.each(function(value, index) {
366 this.each(function(value, index) {
338 results.push(iterator(value, index));
367 results.push((iterator || Prototype.K)(value, index));
339 });
368 });
340 return results;
369 return results;
341 },
370 },
@@ -382,12 +411,11 var Enumerable = {
382 },
411 },
383
412
384 inGroupsOf: function(number, fillWith) {
413 inGroupsOf: function(number, fillWith) {
385 fillWith = fillWith || null;
414 fillWith = fillWith === undefined ? null : fillWith;
386 var results = this.eachSlice(number);
415 return this.eachSlice(number, function(slice) {
387 if (results.length > 0) (number - results.last().length).times(function() {
416 while(slice.length < number) slice.push(fillWith);
388 results.last().push(fillWith)
417 return slice;
389 });
418 });
390 return results;
391 },
419 },
392
420
393 inject: function(memo, iterator) {
421 inject: function(memo, iterator) {
@@ -399,7 +427,7 var Enumerable = {
399
427
400 invoke: function(method) {
428 invoke: function(method) {
401 var args = $A(arguments).slice(1);
429 var args = $A(arguments).slice(1);
402 return this.collect(function(value) {
430 return this.map(function(value) {
403 return value[method].apply(value, args);
431 return value[method].apply(value, args);
404 });
432 });
405 },
433 },
@@ -451,7 +479,7 var Enumerable = {
451 },
479 },
452
480
453 sortBy: function(iterator) {
481 sortBy: function(iterator) {
454 return this.collect(function(value, index) {
482 return this.map(function(value, index) {
455 return {value: value, criteria: iterator(value, index)};
483 return {value: value, criteria: iterator(value, index)};
456 }).sort(function(left, right) {
484 }).sort(function(left, right) {
457 var a = left.criteria, b = right.criteria;
485 var a = left.criteria, b = right.criteria;
@@ -460,7 +488,7 var Enumerable = {
460 },
488 },
461
489
462 toArray: function() {
490 toArray: function() {
463 return this.collect(Prototype.K);
491 return this.map();
464 },
492 },
465
493
466 zip: function() {
494 zip: function() {
@@ -474,6 +502,10 var Enumerable = {
474 });
502 });
475 },
503 },
476
504
505 size: function() {
506 return this.toArray().length;
507 },
508
477 inspect: function() {
509 inspect: function() {
478 return '#<Enumerable:' + this.toArray().inspect() + '>';
510 return '#<Enumerable:' + this.toArray().inspect() + '>';
479 }
511 }
@@ -524,7 +556,7 Object.extend(Array.prototype, {
524
556
525 compact: function() {
557 compact: function() {
526 return this.select(function(value) {
558 return this.select(function(value) {
527 return value != undefined || value != null;
559 return value != null;
528 });
560 });
529 },
561 },
530
562
@@ -566,17 +598,74 Object.extend(Array.prototype, {
566 return [].concat(this);
598 return [].concat(this);
567 },
599 },
568
600
601 size: function() {
602 return this.length;
603 },
604
569 inspect: function() {
605 inspect: function() {
570 return '[' + this.map(Object.inspect).join(', ') + ']';
606 return '[' + this.map(Object.inspect).join(', ') + ']';
571 }
607 }
572 });
608 });
573
609
574 Array.prototype.toArray = Array.prototype.clone;
610 Array.prototype.toArray = Array.prototype.clone;
575 var Hash = {
611
612 function $w(string){
613 string = string.strip();
614 return string ? string.split(/\s+/) : [];
615 }
616
617 if(window.opera){
618 Array.prototype.concat = function(){
619 var array = [];
620 for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
621 for(var i = 0, length = arguments.length; i < length; i++) {
622 if(arguments[i].constructor == Array) {
623 for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
624 array.push(arguments[i][j]);
625 } else {
626 array.push(arguments[i]);
627 }
628 }
629 return array;
630 }
631 }
632 var Hash = function(obj) {
633 Object.extend(this, obj || {});
634 };
635
636 Object.extend(Hash, {
637 toQueryString: function(obj) {
638 var parts = [];
639
640 this.prototype._each.call(obj, function(pair) {
641 if (!pair.key) return;
642
643 if (pair.value && pair.value.constructor == Array) {
644 var values = pair.value.compact();
645 if (values.length < 2) pair.value = values.reduce();
646 else {
647 key = encodeURIComponent(pair.key);
648 values.each(function(value) {
649 value = value != undefined ? encodeURIComponent(value) : '';
650 parts.push(key + '=' + encodeURIComponent(value));
651 });
652 return;
653 }
654 }
655 if (pair.value == undefined) pair[1] = '';
656 parts.push(pair.map(encodeURIComponent).join('='));
657 });
658
659 return parts.join('&');
660 }
661 });
662
663 Object.extend(Hash.prototype, Enumerable);
664 Object.extend(Hash.prototype, {
576 _each: function(iterator) {
665 _each: function(iterator) {
577 for (var key in this) {
666 for (var key in this) {
578 var value = this[key];
667 var value = this[key];
579 if (typeof value == 'function') continue;
668 if (value && value == Hash.prototype[key]) continue;
580
669
581 var pair = [key, value];
670 var pair = [key, value];
582 pair.key = key;
671 pair.key = key;
@@ -600,12 +689,24 var Hash = {
600 });
689 });
601 },
690 },
602
691
692 remove: function() {
693 var result;
694 for(var i = 0, length = arguments.length; i < length; i++) {
695 var value = this[arguments[i]];
696 if (value !== undefined){
697 if (result === undefined) result = value;
698 else {
699 if (result.constructor != Array) result = [result];
700 result.push(value)
701 }
702 }
703 delete this[arguments[i]];
704 }
705 return result;
706 },
707
603 toQueryString: function() {
708 toQueryString: function() {
604 return this.map(function(pair) {
709 return Hash.toQueryString(this);
605 if (!pair.value && pair.value !== 0) pair[1] = '';
606 if (!pair.key) return;
607 return pair.map(encodeURIComponent).join('=');
608 }).join('&');
609 },
710 },
610
711
611 inspect: function() {
712 inspect: function() {
@@ -613,14 +714,12 var Hash = {
613 return pair.map(Object.inspect).join(': ');
714 return pair.map(Object.inspect).join(': ');
614 }).join(', ') + '}>';
715 }).join(', ') + '}>';
615 }
716 }
616 }
717 });
617
718
618 function $H(object) {
719 function $H(object) {
619 var hash = Object.extend({}, object || {});
720 if (object && object.constructor == Hash) return object;
620 Object.extend(hash, Enumerable);
721 return new Hash(object);
621 Object.extend(hash, Hash);
722 };
622 return hash;
623 }
624 ObjectRange = Class.create();
723 ObjectRange = Class.create();
625 Object.extend(ObjectRange.prototype, Enumerable);
724 Object.extend(ObjectRange.prototype, Enumerable);
626 Object.extend(ObjectRange.prototype, {
725 Object.extend(ObjectRange.prototype, {
@@ -714,8 +813,8 Ajax.Base.prototype = {
714 Object.extend(this.options, options || {});
813 Object.extend(this.options, options || {});
715
814
716 this.options.method = this.options.method.toLowerCase();
815 this.options.method = this.options.method.toLowerCase();
717 this.options.parameters = $H(typeof this.options.parameters == 'string' ?
816 if (typeof this.options.parameters == 'string')
718 this.options.parameters.toQueryParams() : this.options.parameters);
817 this.options.parameters = this.options.parameters.toQueryParams();
719 }
818 }
720 }
819 }
721
820
@@ -724,6 +823,8 Ajax.Request.Events =
724 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
823 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
725
824
726 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
825 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
826 _complete: false,
827
727 initialize: function(url, options) {
828 initialize: function(url, options) {
728 this.transport = Ajax.getTransport();
829 this.transport = Ajax.getTransport();
729 this.setOptions(options);
830 this.setOptions(options);
@@ -731,28 +832,28 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
731 },
832 },
732
833
733 request: function(url) {
834 request: function(url) {
835 this.url = url;
836 this.method = this.options.method;
734 var params = this.options.parameters;
837 var params = this.options.parameters;
735 if (params.any()) params['_'] = '';
736
838
737 if (!['get', 'post'].include(this.options.method)) {
839 if (!['get', 'post'].include(this.method)) {
738 // simulate other verbs over post
840 // simulate other verbs over post
739 params['_method'] = this.options.method;
841 params['_method'] = this.method;
740 this.options.method = 'post';
842 this.method = 'post';
741 }
843 }
742
844
743 this.url = url;
845 params = Hash.toQueryString(params);
846 if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
744
847
745 // when GET, append parameters to URL
848 // when GET, append parameters to URL
746 if (this.options.method == 'get' && params.any())
849 if (this.method == 'get' && params)
747 this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') +
850 this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
748 params.toQueryString();
749
851
750 try {
852 try {
751 Ajax.Responders.dispatch('onCreate', this, this.transport);
853 Ajax.Responders.dispatch('onCreate', this, this.transport);
752
854
753 this.transport.open(this.options.method.toUpperCase(), this.url,
855 this.transport.open(this.method.toUpperCase(), this.url,
754 this.options.asynchronous, this.options.username,
856 this.options.asynchronous);
755 this.options.password);
756
857
757 if (this.options.asynchronous)
858 if (this.options.asynchronous)
758 setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
859 setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
@@ -760,14 +861,14 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
760 this.transport.onreadystatechange = this.onStateChange.bind(this);
861 this.transport.onreadystatechange = this.onStateChange.bind(this);
761 this.setRequestHeaders();
862 this.setRequestHeaders();
762
863
763 var body = this.options.method == 'post' ?
864 var body = this.method == 'post' ? (this.options.postBody || params) : null;
764 (this.options.postBody || params.toQueryString()) : null;
765
865
766 this.transport.send(body);
866 this.transport.send(body);
767
867
768 /* Force Firefox to handle ready state 4 for synchronous requests */
868 /* Force Firefox to handle ready state 4 for synchronous requests */
769 if (!this.options.asynchronous && this.transport.overrideMimeType)
869 if (!this.options.asynchronous && this.transport.overrideMimeType)
770 this.onStateChange();
870 this.onStateChange();
871
771 }
872 }
772 catch (e) {
873 catch (e) {
773 this.dispatchException(e);
874 this.dispatchException(e);
@@ -776,7 +877,7 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
776
877
777 onStateChange: function() {
878 onStateChange: function() {
778 var readyState = this.transport.readyState;
879 var readyState = this.transport.readyState;
779 if (readyState > 1)
880 if (readyState > 1 && !((readyState == 4) && this._complete))
780 this.respondToReadyState(this.transport.readyState);
881 this.respondToReadyState(this.transport.readyState);
781 },
882 },
782
883
@@ -787,7 +888,7 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
787 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
888 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
788 };
889 };
789
890
790 if (this.options.method == 'post') {
891 if (this.method == 'post') {
791 headers['Content-type'] = this.options.contentType +
892 headers['Content-type'] = this.options.contentType +
792 (this.options.encoding ? '; charset=' + this.options.encoding : '');
893 (this.options.encoding ? '; charset=' + this.options.encoding : '');
793
894
@@ -805,7 +906,7 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
805 var extras = this.options.requestHeaders;
906 var extras = this.options.requestHeaders;
806
907
807 if (typeof extras.push == 'function')
908 if (typeof extras.push == 'function')
808 for (var i = 0; i < extras.length; i += 2)
909 for (var i = 0, length = extras.length; i < length; i += 2)
809 headers[extras[i]] = extras[i+1];
910 headers[extras[i]] = extras[i+1];
810 else
911 else
811 $H(extras).each(function(pair) { headers[pair.key] = pair.value });
912 $H(extras).each(function(pair) { headers[pair.key] = pair.value });
@@ -826,12 +927,17 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
826
927
827 if (state == 'Complete') {
928 if (state == 'Complete') {
828 try {
929 try {
930 this._complete = true;
829 (this.options['on' + this.transport.status]
931 (this.options['on' + this.transport.status]
830 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
932 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
831 || Prototype.emptyFunction)(transport, json);
933 || Prototype.emptyFunction)(transport, json);
832 } catch (e) {
934 } catch (e) {
833 this.dispatchException(e);
935 this.dispatchException(e);
834 }
936 }
937
938 if ((this.getHeader('Content-type') || 'text/javascript').strip().
939 match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
940 this.evalResponse();
835 }
941 }
836
942
837 try {
943 try {
@@ -842,10 +948,6 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
842 }
948 }
843
949
844 if (state == 'Complete') {
950 if (state == 'Complete') {
845 if ((this.getHeader('Content-type') || '').strip().
846 match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
847 this.evalResponse();
848
849 // avoid memory leak in MSIE: clean up
951 // avoid memory leak in MSIE: clean up
850 this.transport.onreadystatechange = Prototype.emptyFunction;
952 this.transport.onreadystatechange = Prototype.emptyFunction;
851 }
953 }
@@ -977,10 +1079,10 if (Prototype.BrowserFeatures.XPath) {
977 var results = [];
1079 var results = [];
978 var query = document.evaluate(expression, $(parentElement) || document,
1080 var query = document.evaluate(expression, $(parentElement) || document,
979 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1081 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
980 for (var i = 0, len = query.snapshotLength; i < len; i++)
1082 for (var i = 0, length = query.snapshotLength; i < length; i++)
981 results.push(query.snapshotItem(i));
1083 results.push(query.snapshotItem(i));
982 return results;
1084 return results;
983 }
1085 };
984 }
1086 }
985
1087
986 document.getElementsByClassName = function(className, parentElement) {
1088 document.getElementsByClassName = function(className, parentElement) {
@@ -997,7 +1099,7 document.getElementsByClassName = function(className, parentElement) {
997 }
1099 }
998 return elements;
1100 return elements;
999 }
1101 }
1000 }
1102 };
1001
1103
1002 /*--------------------------------------------------------------------------*/
1104 /*--------------------------------------------------------------------------*/
1003
1105
@@ -1005,8 +1107,7 if (!window.Element)
1005 var Element = new Object();
1107 var Element = new Object();
1006
1108
1007 Element.extend = function(element) {
1109 Element.extend = function(element) {
1008 if (!element) return;
1110 if (!element || _nativeExtensions || element.nodeType == 3) return element;
1009 if (_nativeExtensions || element.nodeType == 3) return element;
1010
1111
1011 if (!element._extended && element.tagName && element != window) {
1112 if (!element._extended && element.tagName && element != window) {
1012 var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
1113 var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
@@ -1016,23 +1117,18 Element.extend = function(element) {
1016 if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
1117 if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
1017 Object.extend(methods, Form.Element.Methods);
1118 Object.extend(methods, Form.Element.Methods);
1018
1119
1019 for (var property in methods) {
1120 Object.extend(methods, Element.Methods.Simulated);
1020 var value = methods[property];
1021 if (typeof value == 'function')
1022 element[property] = cache.findOrStore(value);
1023 }
1024
1121
1025 var methods = Object.clone(Element.Methods.Simulated), cache = Element.extend.cache;
1026 for (var property in methods) {
1122 for (var property in methods) {
1027 var value = methods[property];
1123 var value = methods[property];
1028 if ('function' == typeof value && !(property in element))
1124 if (typeof value == 'function' && !(property in element))
1029 element[property] = cache.findOrStore(value);
1125 element[property] = cache.findOrStore(value);
1030 }
1126 }
1031 }
1127 }
1032
1128
1033 element._extended = true;
1129 element._extended = true;
1034 return element;
1130 return element;
1035 }
1131 };
1036
1132
1037 Element.extend.cache = {
1133 Element.extend.cache = {
1038 findOrStore: function(value) {
1134 findOrStore: function(value) {
@@ -1040,7 +1136,7 Element.extend.cache = {
1040 return value.apply(null, [this].concat($A(arguments)));
1136 return value.apply(null, [this].concat($A(arguments)));
1041 }
1137 }
1042 }
1138 }
1043 }
1139 };
1044
1140
1045 Element.Methods = {
1141 Element.Methods = {
1046 visible: function(element) {
1142 visible: function(element) {
@@ -1078,6 +1174,7 Element.Methods = {
1078
1174
1079 replace: function(element, html) {
1175 replace: function(element, html) {
1080 element = $(element);
1176 element = $(element);
1177 html = typeof html == 'undefined' ? '' : html.toString();
1081 if (element.outerHTML) {
1178 if (element.outerHTML) {
1082 element.outerHTML = html.stripScripts();
1179 element.outerHTML = html.stripScripts();
1083 } else {
1180 } else {
@@ -1115,8 +1212,14 Element.Methods = {
1115 },
1212 },
1116
1213
1117 descendants: function(element) {
1214 descendants: function(element) {
1118 element = $(element);
1215 return $A($(element).getElementsByTagName('*'));
1119 return $A(element.getElementsByTagName('*'));
1216 },
1217
1218 immediateDescendants: function(element) {
1219 if (!(element = $(element).firstChild)) return [];
1220 while (element && element.nodeType != 1) element = element.nextSibling;
1221 if (element) return [element].concat($(element).nextSiblings());
1222 return [];
1120 },
1223 },
1121
1224
1122 previousSiblings: function(element) {
1225 previousSiblings: function(element) {
@@ -1133,10 +1236,9 Element.Methods = {
1133 },
1236 },
1134
1237
1135 match: function(element, selector) {
1238 match: function(element, selector) {
1136 element = $(element);
1137 if (typeof selector == 'string')
1239 if (typeof selector == 'string')
1138 selector = new Selector(selector);
1240 selector = new Selector(selector);
1139 return selector.match(element);
1241 return selector.match($(element));
1140 },
1242 },
1141
1243
1142 up: function(element, expression, index) {
1244 up: function(element, expression, index) {
@@ -1161,13 +1263,27 Element.Methods = {
1161 },
1263 },
1162
1264
1163 getElementsByClassName: function(element, className) {
1265 getElementsByClassName: function(element, className) {
1164 element = $(element);
1165 return document.getElementsByClassName(className, element);
1266 return document.getElementsByClassName(className, element);
1166 },
1267 },
1167
1268
1168 getHeight: function(element) {
1269 readAttribute: function(element, name) {
1169 element = $(element);
1270 element = $(element);
1170 return element.offsetHeight;
1271 if (document.all && !window.opera) {
1272 var t = Element._attributeTranslations;
1273 if (t.values[name]) return t.values[name](element, name);
1274 if (t.names[name]) name = t.names[name];
1275 var attribute = element.attributes[name];
1276 if(attribute) return attribute.nodeValue;
1277 }
1278 return element.getAttribute(name);
1279 },
1280
1281 getHeight: function(element) {
1282 return $(element).getDimensions().height;
1283 },
1284
1285 getWidth: function(element) {
1286 return $(element).getDimensions().width;
1171 },
1287 },
1172
1288
1173 classNames: function(element) {
1289 classNames: function(element) {
@@ -1196,6 +1312,12 Element.Methods = {
1196 return element;
1312 return element;
1197 },
1313 },
1198
1314
1315 toggleClassName: function(element, className) {
1316 if (!(element = $(element))) return;
1317 Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
1318 return element;
1319 },
1320
1199 observe: function() {
1321 observe: function() {
1200 Event.observe.apply(Event, arguments);
1322 Event.observe.apply(Event, arguments);
1201 return $A(arguments).first();
1323 return $A(arguments).first();
@@ -1223,7 +1345,7 Element.Methods = {
1223 return $(element).innerHTML.match(/^\s*$/);
1345 return $(element).innerHTML.match(/^\s*$/);
1224 },
1346 },
1225
1347
1226 childOf: function(element, ancestor) {
1348 descendantOf: function(element, ancestor) {
1227 element = $(element), ancestor = $(ancestor);
1349 element = $(element), ancestor = $(ancestor);
1228 while (element = element.parentNode)
1350 while (element = element.parentNode)
1229 if (element == ancestor) return true;
1351 if (element == ancestor) return true;
@@ -1232,40 +1354,69 Element.Methods = {
1232
1354
1233 scrollTo: function(element) {
1355 scrollTo: function(element) {
1234 element = $(element);
1356 element = $(element);
1235 var x = element.x ? element.x : element.offsetLeft,
1357 var pos = Position.cumulativeOffset(element);
1236 y = element.y ? element.y : element.offsetTop;
1358 window.scrollTo(pos[0], pos[1]);
1237 window.scrollTo(x, y);
1238 return element;
1359 return element;
1239 },
1360 },
1240
1361
1241 getStyle: function(element, style) {
1362 getStyle: function(element, style) {
1242 element = $(element);
1363 element = $(element);
1243 var value = element.style[style.camelize()];
1364 if (['float','cssFloat'].include(style))
1365 style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
1366 style = style.camelize();
1367 var value = element.style[style];
1244 if (!value) {
1368 if (!value) {
1245 if (document.defaultView && document.defaultView.getComputedStyle) {
1369 if (document.defaultView && document.defaultView.getComputedStyle) {
1246 var css = document.defaultView.getComputedStyle(element, null);
1370 var css = document.defaultView.getComputedStyle(element, null);
1247 value = css ? css.getPropertyValue(style) : null;
1371 value = css ? css[style] : null;
1248 } else if (element.currentStyle) {
1372 } else if (element.currentStyle) {
1249 value = element.currentStyle[style.camelize()];
1373 value = element.currentStyle[style];
1250 }
1374 }
1251 }
1375 }
1252
1376
1377 if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
1378 value = element['offset'+style.capitalize()] + 'px';
1379
1253 if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
1380 if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
1254 if (Element.getStyle(element, 'position') == 'static') value = 'auto';
1381 if (Element.getStyle(element, 'position') == 'static') value = 'auto';
1255
1382 if(style == 'opacity') {
1383 if(value) return parseFloat(value);
1384 if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
1385 if(value[1]) return parseFloat(value[1]) / 100;
1386 return 1.0;
1387 }
1256 return value == 'auto' ? null : value;
1388 return value == 'auto' ? null : value;
1257 },
1389 },
1258
1390
1259 setStyle: function(element, style) {
1391 setStyle: function(element, style) {
1260 element = $(element);
1392 element = $(element);
1261 for (var name in style)
1393 for (var name in style) {
1262 element.style[name.camelize()] = style[name];
1394 var value = style[name];
1395 if(name == 'opacity') {
1396 if (value == 1) {
1397 value = (/Gecko/.test(navigator.userAgent) &&
1398 !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
1399 if(/MSIE/.test(navigator.userAgent) && !window.opera)
1400 element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
1401 } else if(value == '') {
1402 if(/MSIE/.test(navigator.userAgent) && !window.opera)
1403 element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
1404 } else {
1405 if(value < 0.00001) value = 0;
1406 if(/MSIE/.test(navigator.userAgent) && !window.opera)
1407 element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
1408 'alpha(opacity='+value*100+')';
1409 }
1410 } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
1411 element.style[name.camelize()] = value;
1412 }
1263 return element;
1413 return element;
1264 },
1414 },
1265
1415
1266 getDimensions: function(element) {
1416 getDimensions: function(element) {
1267 element = $(element);
1417 element = $(element);
1268 if (Element.getStyle(element, 'display') != 'none')
1418 var display = $(element).getStyle('display');
1419 if (display != 'none' && display != null) // Safari bug
1269 return {width: element.offsetWidth, height: element.offsetHeight};
1420 return {width: element.offsetWidth, height: element.offsetHeight};
1270
1421
1271 // All *Width and *Height properties give 0 on elements with display none,
1422 // All *Width and *Height properties give 0 on elements with display none,
@@ -1273,12 +1424,13 Element.Methods = {
1273 var els = element.style;
1424 var els = element.style;
1274 var originalVisibility = els.visibility;
1425 var originalVisibility = els.visibility;
1275 var originalPosition = els.position;
1426 var originalPosition = els.position;
1427 var originalDisplay = els.display;
1276 els.visibility = 'hidden';
1428 els.visibility = 'hidden';
1277 els.position = 'absolute';
1429 els.position = 'absolute';
1278 els.display = '';
1430 els.display = 'block';
1279 var originalWidth = element.clientWidth;
1431 var originalWidth = element.clientWidth;
1280 var originalHeight = element.clientHeight;
1432 var originalHeight = element.clientHeight;
1281 els.display = 'none';
1433 els.display = originalDisplay;
1282 els.position = originalPosition;
1434 els.position = originalPosition;
1283 els.visibility = originalVisibility;
1435 els.visibility = originalVisibility;
1284 return {width: originalWidth, height: originalHeight};
1436 return {width: originalWidth, height: originalHeight};
@@ -1329,21 +1481,68 Element.Methods = {
1329 element._overflow = null;
1481 element._overflow = null;
1330 return element;
1482 return element;
1331 }
1483 }
1332 }
1484 };
1485
1486 Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
1487
1488 Element._attributeTranslations = {};
1489
1490 Element._attributeTranslations.names = {
1491 colspan: "colSpan",
1492 rowspan: "rowSpan",
1493 valign: "vAlign",
1494 datetime: "dateTime",
1495 accesskey: "accessKey",
1496 tabindex: "tabIndex",
1497 enctype: "encType",
1498 maxlength: "maxLength",
1499 readonly: "readOnly",
1500 longdesc: "longDesc"
1501 };
1502
1503 Element._attributeTranslations.values = {
1504 _getAttr: function(element, attribute) {
1505 return element.getAttribute(attribute, 2);
1506 },
1507
1508 _flag: function(element, attribute) {
1509 return $(element).hasAttribute(attribute) ? attribute : null;
1510 },
1511
1512 style: function(element) {
1513 return element.style.cssText.toLowerCase();
1514 },
1515
1516 title: function(element) {
1517 var node = element.getAttributeNode('title');
1518 return node.specified ? node.nodeValue : null;
1519 }
1520 };
1521
1522 Object.extend(Element._attributeTranslations.values, {
1523 href: Element._attributeTranslations.values._getAttr,
1524 src: Element._attributeTranslations.values._getAttr,
1525 disabled: Element._attributeTranslations.values._flag,
1526 checked: Element._attributeTranslations.values._flag,
1527 readonly: Element._attributeTranslations.values._flag,
1528 multiple: Element._attributeTranslations.values._flag
1529 });
1333
1530
1334 Element.Methods.Simulated = {
1531 Element.Methods.Simulated = {
1335 hasAttribute: function(element, attribute) {
1532 hasAttribute: function(element, attribute) {
1533 var t = Element._attributeTranslations;
1534 attribute = t.names[attribute] || attribute;
1336 return $(element).getAttributeNode(attribute).specified;
1535 return $(element).getAttributeNode(attribute).specified;
1337 }
1536 }
1338 }
1537 };
1339
1538
1340 // IE is missing .innerHTML support for TABLE-related elements
1539 // IE is missing .innerHTML support for TABLE-related elements
1341 if(document.all){
1540 if (document.all && !window.opera){
1342 Element.Methods.update = function(element, html) {
1541 Element.Methods.update = function(element, html) {
1343 element = $(element);
1542 element = $(element);
1344 html = typeof html == 'undefined' ? '' : html.toString();
1543 html = typeof html == 'undefined' ? '' : html.toString();
1345 var tagName = element.tagName.toUpperCase();
1544 var tagName = element.tagName.toUpperCase();
1346 if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {
1545 if (['THEAD','TBODY','TR','TD'].include(tagName)) {
1347 var div = document.createElement('div');
1546 var div = document.createElement('div');
1348 switch (tagName) {
1547 switch (tagName) {
1349 case 'THEAD':
1548 case 'THEAD':
@@ -1372,7 +1571,7 if(document.all){
1372 setTimeout(function() {html.evalScripts()}, 10);
1571 setTimeout(function() {html.evalScripts()}, 10);
1373 return element;
1572 return element;
1374 }
1573 }
1375 }
1574 };
1376
1575
1377 Object.extend(Element, Element.Methods);
1576 Object.extend(Element, Element.Methods);
1378
1577
@@ -1428,8 +1627,8 Abstract.Insertion.prototype = {
1428 try {
1627 try {
1429 this.element.insertAdjacentHTML(this.adjacency, this.content);
1628 this.element.insertAdjacentHTML(this.adjacency, this.content);
1430 } catch (e) {
1629 } catch (e) {
1431 var tagName = this.element.tagName.toLowerCase();
1630 var tagName = this.element.tagName.toUpperCase();
1432 if (tagName == 'tbody' || tagName == 'tr') {
1631 if (['TBODY', 'TR'].include(tagName)) {
1433 this.insertContent(this.contentFromAnonymousTable());
1632 this.insertContent(this.contentFromAnonymousTable());
1434 } else {
1633 } else {
1435 throw e;
1634 throw e;
@@ -1539,7 +1738,7 Element.ClassNames.prototype = {
1539 toString: function() {
1738 toString: function() {
1540 return $A(this).join(' ');
1739 return $A(this).join(' ');
1541 }
1740 }
1542 }
1741 };
1543
1742
1544 Object.extend(Element.ClassNames.prototype, Enumerable);
1743 Object.extend(Element.ClassNames.prototype, Enumerable);
1545 var Selector = Class.create();
1744 var Selector = Class.create();
@@ -1586,15 +1785,15 Selector.prototype = {
1586 if (params.wildcard)
1785 if (params.wildcard)
1587 conditions.push('true');
1786 conditions.push('true');
1588 if (clause = params.id)
1787 if (clause = params.id)
1589 conditions.push('element.id == ' + clause.inspect());
1788 conditions.push('element.readAttribute("id") == ' + clause.inspect());
1590 if (clause = params.tagName)
1789 if (clause = params.tagName)
1591 conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
1790 conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
1592 if ((clause = params.classNames).length > 0)
1791 if ((clause = params.classNames).length > 0)
1593 for (var i = 0; i < clause.length; i++)
1792 for (var i = 0, length = clause.length; i < length; i++)
1594 conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
1793 conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
1595 if (clause = params.attributes) {
1794 if (clause = params.attributes) {
1596 clause.each(function(attribute) {
1795 clause.each(function(attribute) {
1597 var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
1796 var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
1598 var splitValueBy = function(delimiter) {
1797 var splitValueBy = function(delimiter) {
1599 return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
1798 return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
1600 }
1799 }
@@ -1607,7 +1806,7 Selector.prototype = {
1607 ); break;
1806 ); break;
1608 case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
1807 case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
1609 case '':
1808 case '':
1610 case undefined: conditions.push(value + ' != null'); break;
1809 case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
1611 default: throw 'Unknown operator ' + attribute.operator + ' in selector';
1810 default: throw 'Unknown operator ' + attribute.operator + ' in selector';
1612 }
1811 }
1613 });
1812 });
@@ -1618,6 +1817,7 Selector.prototype = {
1618
1817
1619 compileMatcher: function() {
1818 compileMatcher: function() {
1620 this.match = new Function('element', 'if (!element.tagName) return false; \
1819 this.match = new Function('element', 'if (!element.tagName) return false; \
1820 element = $(element); \
1621 return ' + this.buildMatchExpression());
1821 return ' + this.buildMatchExpression());
1622 },
1822 },
1623
1823
@@ -1647,7 +1847,7 Selector.prototype = {
1647 Object.extend(Selector, {
1847 Object.extend(Selector, {
1648 matchElements: function(elements, expression) {
1848 matchElements: function(elements, expression) {
1649 var selector = new Selector(expression);
1849 var selector = new Selector(expression);
1650 return elements.select(selector.match.bind(selector)).collect(Element.extend);
1850 return elements.select(selector.match.bind(selector)).map(Element.extend);
1651 },
1851 },
1652
1852
1653 findElement: function(elements, expression, index) {
1853 findElement: function(elements, expression, index) {
@@ -1657,7 +1857,7 Object.extend(Selector, {
1657
1857
1658 findChildElements: function(element, expressions) {
1858 findChildElements: function(element, expressions) {
1659 return expressions.map(function(expression) {
1859 return expressions.map(function(expression) {
1660 return expression.strip().split(/\s+/).inject([null], function(results, expr) {
1860 return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
1661 var selector = new Selector(expr);
1861 var selector = new Selector(expr);
1662 return results.inject([], function(elements, result) {
1862 return results.inject([], function(elements, result) {
1663 return elements.concat(selector.findElements(result || element));
1863 return elements.concat(selector.findElements(result || element));
@@ -1676,18 +1876,28 var Form = {
1676 return form;
1876 return form;
1677 },
1877 },
1678
1878
1679 serializeElements: function(elements) {
1879 serializeElements: function(elements, getHash) {
1680 return elements.inject([], function(queryComponents, element) {
1880 var data = elements.inject({}, function(result, element) {
1681 var queryComponent = Form.Element.serialize(element);
1881 if (!element.disabled && element.name) {
1682 if (queryComponent) queryComponents.push(queryComponent);
1882 var key = element.name, value = $(element).getValue();
1683 return queryComponents;
1883 if (value != undefined) {
1684 }).join('&');
1884 if (result[key]) {
1885 if (result[key].constructor != Array) result[key] = [result[key]];
1886 result[key].push(value);
1887 }
1888 else result[key] = value;
1889 }
1890 }
1891 return result;
1892 });
1893
1894 return getHash ? data : Hash.toQueryString(data);
1685 }
1895 }
1686 };
1896 };
1687
1897
1688 Form.Methods = {
1898 Form.Methods = {
1689 serialize: function(form) {
1899 serialize: function(form, getHash) {
1690 return Form.serializeElements($(form).getElements());
1900 return Form.serializeElements(Form.getElements(form), getHash);
1691 },
1901 },
1692
1902
1693 getElements: function(form) {
1903 getElements: function(form) {
@@ -1704,14 +1914,11 Form.Methods = {
1704 form = $(form);
1914 form = $(form);
1705 var inputs = form.getElementsByTagName('input');
1915 var inputs = form.getElementsByTagName('input');
1706
1916
1707 if (!typeName && !name)
1917 if (!typeName && !name) return $A(inputs).map(Element.extend);
1708 return inputs;
1709
1918
1710 var matchingInputs = new Array();
1919 for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
1711 for (var i = 0, length = inputs.length; i < length; i++) {
1712 var input = inputs[i];
1920 var input = inputs[i];
1713 if ((typeName && input.type != typeName) ||
1921 if ((typeName && input.type != typeName) || (name && input.name != name))
1714 (name && input.name != name))
1715 continue;
1922 continue;
1716 matchingInputs.push(Element.extend(input));
1923 matchingInputs.push(Element.extend(input));
1717 }
1924 }
@@ -1769,30 +1976,21 Form.Element = {
1769 Form.Element.Methods = {
1976 Form.Element.Methods = {
1770 serialize: function(element) {
1977 serialize: function(element) {
1771 element = $(element);
1978 element = $(element);
1772 if (element.disabled) return '';
1979 if (!element.disabled && element.name) {
1773 var method = element.tagName.toLowerCase();
1980 var value = element.getValue();
1774 var parameter = Form.Element.Serializers[method](element);
1981 if (value != undefined) {
1775
1982 var pair = {};
1776 if (parameter) {
1983 pair[element.name] = value;
1777 var key = encodeURIComponent(parameter[0]);
1984 return Hash.toQueryString(pair);
1778 if (key.length == 0) return;
1985 }
1779
1780 if (parameter[1].constructor != Array)
1781 parameter[1] = [parameter[1]];
1782
1783 return parameter[1].map(function(value) {
1784 return key + '=' + encodeURIComponent(value);
1785 }).join('&');
1786 }
1986 }
1987 return '';
1787 },
1988 },
1788
1989
1789 getValue: function(element) {
1990 getValue: function(element) {
1790 element = $(element);
1991 element = $(element);
1791 var method = element.tagName.toLowerCase();
1992 var method = element.tagName.toLowerCase();
1792 var parameter = Form.Element.Serializers[method](element);
1993 return Form.Element.Serializers[method](element);
1793
1794 if (parameter)
1795 return parameter[1];
1796 },
1994 },
1797
1995
1798 clear: function(element) {
1996 clear: function(element) {
@@ -1807,7 +2005,8 Form.Element.Methods = {
1807 activate: function(element) {
2005 activate: function(element) {
1808 element = $(element);
2006 element = $(element);
1809 element.focus();
2007 element.focus();
1810 if (element.select)
2008 if (element.select && ( element.tagName.toLowerCase() != 'input' ||
2009 !['button', 'reset', 'submit'].include(element.type) ) )
1811 element.select();
2010 element.select();
1812 return element;
2011 return element;
1813 },
2012 },
@@ -1828,6 +2027,7 Form.Element.Methods = {
1828
2027
1829 Object.extend(Form.Element, Form.Element.Methods);
2028 Object.extend(Form.Element, Form.Element.Methods);
1830 var Field = Form.Element;
2029 var Field = Form.Element;
2030 var $F = Form.Element.getValue;
1831
2031
1832 /*--------------------------------------------------------------------------*/
2032 /*--------------------------------------------------------------------------*/
1833
2033
@@ -1840,51 +2040,45 Form.Element.Serializers = {
1840 default:
2040 default:
1841 return Form.Element.Serializers.textarea(element);
2041 return Form.Element.Serializers.textarea(element);
1842 }
2042 }
1843 return false;
1844 },
2043 },
1845
2044
1846 inputSelector: function(element) {
2045 inputSelector: function(element) {
1847 if (element.checked)
2046 return element.checked ? element.value : null;
1848 return [element.name, element.value];
1849 },
2047 },
1850
2048
1851 textarea: function(element) {
2049 textarea: function(element) {
1852 return [element.name, element.value];
2050 return element.value;
1853 },
2051 },
1854
2052
1855 select: function(element) {
2053 select: function(element) {
1856 return Form.Element.Serializers[element.type == 'select-one' ?
2054 return this[element.type == 'select-one' ?
1857 'selectOne' : 'selectMany'](element);
2055 'selectOne' : 'selectMany'](element);
1858 },
2056 },
1859
2057
1860 selectOne: function(element) {
2058 selectOne: function(element) {
1861 var value = '', opt, index = element.selectedIndex;
2059 var index = element.selectedIndex;
1862 if (index >= 0) {
2060 return index >= 0 ? this.optionValue(element.options[index]) : null;
1863 opt = Element.extend(element.options[index]);
1864 // Uses the new potential extension if hasAttribute isn't native.
1865 value = opt.hasAttribute('value') ? opt.value : opt.text;
1866 }
1867 return [element.name, value];
1868 },
2061 },
1869
2062
1870 selectMany: function(element) {
2063 selectMany: function(element) {
1871 var value = [];
2064 var values, length = element.length;
1872 for (var i = 0; i < element.length; i++) {
2065 if (!length) return null;
1873 var opt = Element.extend(element.options[i]);
2066
1874 if (opt.selected)
2067 for (var i = 0, values = []; i < length; i++) {
1875 // Uses the new potential extension if hasAttribute isn't native.
2068 var opt = element.options[i];
1876 value.push(opt.hasAttribute('value') ? opt.value : opt.text);
2069 if (opt.selected) values.push(this.optionValue(opt));
1877 }
2070 }
1878 return [element.name, value];
2071 return values;
2072 },
2073
2074 optionValue: function(opt) {
2075 // extend element because hasAttribute may not be native
2076 return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
1879 }
2077 }
1880 }
2078 }
1881
2079
1882 /*--------------------------------------------------------------------------*/
2080 /*--------------------------------------------------------------------------*/
1883
2081
1884 var $F = Form.Element.getValue;
1885
1886 /*--------------------------------------------------------------------------*/
1887
1888 Abstract.TimedObserver = function() {}
2082 Abstract.TimedObserver = function() {}
1889 Abstract.TimedObserver.prototype = {
2083 Abstract.TimedObserver.prototype = {
1890 initialize: function(element, frequency, callback) {
2084 initialize: function(element, frequency, callback) {
@@ -1902,7 +2096,9 Abstract.TimedObserver.prototype = {
1902
2096
1903 onTimerEvent: function() {
2097 onTimerEvent: function() {
1904 var value = this.getValue();
2098 var value = this.getValue();
1905 if (this.lastValue != value) {
2099 var changed = ('string' == typeof this.lastValue && 'string' == typeof value
2100 ? this.lastValue != value : String(this.lastValue) != String(value));
2101 if (changed) {
1906 this.callback(this.element, value);
2102 this.callback(this.element, value);
1907 this.lastValue = value;
2103 this.lastValue = value;
1908 }
2104 }
@@ -2275,10 +2471,10 var Position = {
2275 element._originalHeight = element.style.height;
2471 element._originalHeight = element.style.height;
2276
2472
2277 element.style.position = 'absolute';
2473 element.style.position = 'absolute';
2278 element.style.top = top + 'px';;
2474 element.style.top = top + 'px';
2279 element.style.left = left + 'px';;
2475 element.style.left = left + 'px';
2280 element.style.width = width + 'px';;
2476 element.style.width = width + 'px';
2281 element.style.height = height + 'px';;
2477 element.style.height = height + 'px';
2282 },
2478 },
2283
2479
2284 relativize: function(element) {
2480 relativize: function(element) {
General Comments 0
You need to be logged in to leave comments. Login now