- * var link1_clicked = function()
- * {
- * alert("Clicked!");
- * };
- * Event.observe("link1", "click", link1_clicked);
- *
- *
- * @param {Object} element id string, DOM Element, or an Array
- * of element ids or elements.
- * @param {String} The type of event for which the event listener
- * is to be invoked. For example, "load", "click", or "mousedown".
- * @param {Function} The event listener function that will be
- * invoked when an event of the specified type is dispatched to
- * this Document node.
- * @param {Boolean} If true, the specified listener is to be
- * invoked only during the capturing phase of event propagation.
- * The more common value of false means that the listener
- * will not be invoked during the capturing phase but instead will
- * be invoked when this node is the actual event target or when the
- * event bubbles up to this node from its original target.
- */
- observe: function(elements, name, observer, useCapture)
- {
- if(!isList(elements))
- return this.__observe(elements, name, observer, useCapture);
- for(var i=0; i/gi,"");
-},createEditField:function(){
+},
+hasHTMLLineBreaks: function(string) {
+if (!this.options.handleLineBreaks) return false;
+return string.match(/
/i);
+},
+convertHTMLLineBreaks: function(string) {
+return string.replace(/
/gi, "\n").replace(/
/gi, "\n").replace(/<\/p>/gi, "\n").replace(/
/gi, "");
+},
+createEditField: function() {
var text;
-if(this.options.loadTextURL){
-text=this.options.loadingText;
-}else{
-text=this.getText();
-}
-var obj=this;
-if(this.options.rows==1&&!this.hasHTMLLineBreaks(text)){
-this.options.textarea=false;
-var _138=document.createElement("input");
-_138.obj=this;
-_138.type="text";
-_138.name="value";
-_138.value=text;
-_138.style.backgroundColor=this.options.highlightcolor;
-var size=this.options.size||this.options.cols||0;
-if(size!=0){
-_138.size=size;
-}
-if(this.options.submitOnBlur){
-_138.onblur=this.onSubmit.bind(this);
-}
-this.editField=_138;
-}else{
-this.options.textarea=true;
-var _140=document.createElement("textarea");
-_140.obj=this;
-_140.name="value";
-_140.value=this.convertHTMLLineBreaks(text);
-_140.rows=this.options.rows;
-_140.cols=this.options.cols||40;
-if(this.options.submitOnBlur){
-_140.onblur=this.onSubmit.bind(this);
-}
-this.editField=_140;
-}
-if(this.options.loadTextURL){
+if(this.options.loadTextURL) {
+text = this.options.loadingText;
+} else {
+text = this.getText();
+}
+var obj = this;
+if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
+this.options.textarea = false;
+var textField = document.createElement("input");
+textField.obj = this;
+textField.type = "text";
+textField.name = "value";
+textField.value = text;
+textField.style.backgroundColor = this.options.highlightcolor;
+textField.className = 'editor_field';
+var size = this.options.size || this.options.cols || 0;
+if (size != 0) textField.size = size;
+if (this.options.submitOnBlur)
+textField.onblur = this.onSubmit.bind(this);
+this.editField = textField;
+} else {
+this.options.textarea = true;
+var textArea = document.createElement("textarea");
+textArea.obj = this;
+textArea.name = "value";
+textArea.value = this.convertHTMLLineBreaks(text);
+textArea.rows = this.options.rows;
+textArea.cols = this.options.cols || 40;
+textArea.className = 'editor_field';
+if (this.options.submitOnBlur)
+textArea.onblur = this.onSubmit.bind(this);
+this.editField = textArea;
+}
+if(this.options.loadTextURL) {
this.loadExternalText();
}
this.form.appendChild(this.editField);
-},getText:function(){
+},
+getText: function() {
return this.element.innerHTML;
-},loadExternalText:function(){
-Element.addClassName(this.form,this.options.loadingClassName);
-this.editField.disabled=true;
-new Ajax.Request(this.options.loadTextURL,Object.extend({asynchronous:true,onComplete:this.onLoadedExternalText.bind(this)},this.options.ajaxOptions));
-},onLoadedExternalText:function(_141){
-Element.removeClassName(this.form,this.options.loadingClassName);
-this.editField.disabled=false;
-this.editField.value=_141.responseText.stripTags();
-},onclickCancel:function(){
+},
+loadExternalText: function() {
+Element.addClassName(this.form, this.options.loadingClassName);
+this.editField.disabled = true;
+new Ajax.Request(
+this.options.loadTextURL,
+Object.extend({
+asynchronous: true,
+onComplete: this.onLoadedExternalText.bind(this)
+}, this.options.ajaxOptions)
+);
+},
+onLoadedExternalText: function(transport) {
+Element.removeClassName(this.form, this.options.loadingClassName);
+this.editField.disabled = false;
+this.editField.value = transport.responseText.stripTags();
+},
+onclickCancel: function() {
this.onComplete();
this.leaveEditMode();
return false;
-},onFailure:function(_142){
-this.options.onFailure(_142);
-if(this.oldInnerHTML){
-this.element.innerHTML=this.oldInnerHTML;
-this.oldInnerHTML=null;
+},
+onFailure: function(transport) {
+this.options.onFailure(transport);
+if (this.oldInnerHTML) {
+this.element.innerHTML = this.oldInnerHTML;
+this.oldInnerHTML = null;
}
return false;
-},onSubmit:function(){
-var form=this.form;
-var _143=this.editField.value;
+},
+onSubmit: function() {
+ var form = this.form;
+var value = this.editField.value;
this.onLoading();
-new Ajax.Updater({success:this.element,failure:null},this.url,Object.extend({parameters:this.options.callback(form,_143),onComplete:this.onComplete.bind(this),onFailure:this.onFailure.bind(this)},this.options.ajaxOptions));
-if(arguments.length>1){
+if (this.options.evalScripts) {
+new Ajax.Request(
+this.url, Object.extend({
+parameters: this.options.callback(form, value),
+onComplete: this.onComplete.bind(this),
+onFailure: this.onFailure.bind(this),
+asynchronous:true,
+evalScripts:true
+}, this.options.ajaxOptions));
+} else{
+new Ajax.Updater(
+{ success: this.element,
+ failure: null },
+this.url, Object.extend({
+parameters: this.options.callback(form, value),
+onComplete: this.onComplete.bind(this),
+onFailure: this.onFailure.bind(this)
+}, this.options.ajaxOptions));
+}
+ if (arguments.length > 1) {
Event.stop(arguments[0]);
}
return false;
-},onLoading:function(){
-this.saving=true;
+},
+onLoading: function() {
+this.saving = true;
this.removeForm();
this.leaveHover();
this.showSaving();
-},showSaving:function(){
-this.oldInnerHTML=this.element.innerHTML;
-this.element.innerHTML=this.options.savingText;
-Element.addClassName(this.element,this.options.savingClassName);
-this.element.style.backgroundColor=this.originalBackground;
+},
+showSaving: function() {
+this.oldInnerHTML = this.element.innerHTML;
+this.element.innerHTML = this.options.savingText;
+Element.addClassName(this.element, this.options.savingClassName);
+this.element.style.backgroundColor = this.originalBackground;
Element.show(this.element);
-},removeForm:function(){
-if(this.form){
-if(this.form.parentNode){
-Element.remove(this.form);
-}
-this.form=null;
-}
-},enterHover:function(){
-if(this.saving){
-return;
-}
-this.element.style.backgroundColor=this.options.highlightcolor;
-if(this.effect){
+},
+removeForm: function() {
+if(this.form) {
+if (this.form.parentNode) Element.remove(this.form);
+this.form = null;
+}
+},
+enterHover: function() {
+if (this.saving) return;
+this.element.style.backgroundColor = this.options.highlightcolor;
+if (this.effect) {
this.effect.cancel();
}
-Element.addClassName(this.element,this.options.hoverClassName);
-},leaveHover:function(){
-if(this.options.backgroundColor){
-this.element.style.backgroundColor=this.oldBackground;
-}
-Element.removeClassName(this.element,this.options.hoverClassName);
-if(this.saving){
-return;
-}
-this.effect=new Effect.Highlight(this.element,{startcolor:this.options.highlightcolor,endcolor:this.options.highlightendcolor,restorecolor:this.originalBackground});
-},leaveEditMode:function(){
-Element.removeClassName(this.element,this.options.savingClassName);
+Element.addClassName(this.element, this.options.hoverClassName)
+},
+leaveHover: function() {
+if (this.options.backgroundColor) {
+this.element.style.backgroundColor = this.oldBackground;
+}
+Element.removeClassName(this.element, this.options.hoverClassName)
+if (this.saving) return;
+this.effect = new Effect.Highlight(this.element, {
+startcolor: this.options.highlightcolor,
+endcolor: this.options.highlightendcolor,
+restorecolor: this.originalBackground
+});
+},
+leaveEditMode: function() {
+Element.removeClassName(this.element, this.options.savingClassName);
this.removeForm();
this.leaveHover();
-this.element.style.backgroundColor=this.originalBackground;
+this.element.style.backgroundColor = this.originalBackground;
Element.show(this.element);
-if(this.options.externalControl){
+if (this.options.externalControl) {
Element.show(this.options.externalControl);
}
-this.editing=false;
-this.saving=false;
-this.oldInnerHTML=null;
+this.editing = false;
+this.saving = false;
+this.oldInnerHTML = null;
this.onLeaveEditMode();
-},onComplete:function(_144){
+},
+onComplete: function(transport) {
this.leaveEditMode();
-this.options.onComplete.bind(this)(_144,this.element);
-},onEnterEditMode:function(){
-},onLeaveEditMode:function(){
-},dispose:function(){
-if(this.oldInnerHTML){
-this.element.innerHTML=this.oldInnerHTML;
+this.options.onComplete.bind(this)(transport, this.element);
+},
+onEnterEditMode: function() {},
+onLeaveEditMode: function() {},
+dispose: function() {
+if (this.oldInnerHTML) {
+this.element.innerHTML = this.oldInnerHTML;
}
this.leaveEditMode();
-Event.stopObserving(this.element,"click",this.onclickListener);
-Event.stopObserving(this.element,"mouseover",this.mouseoverListener);
-Event.stopObserving(this.element,"mouseout",this.mouseoutListener);
-if(this.options.externalControl){
-Event.stopObserving(this.options.externalControl,"click",this.onclickListener);
-Event.stopObserving(this.options.externalControl,"mouseover",this.mouseoverListener);
-Event.stopObserving(this.options.externalControl,"mouseout",this.mouseoutListener);
-}
-}};
-Form.Element.DelayedObserver=Class.create();
-Form.Element.DelayedObserver.prototype={initialize:function(_145,_146,_147){
-this.delay=_146||0.5;
-this.element=$(_145);
-this.callback=_147;
-this.timer=null;
-this.lastValue=$F(this.element);
-Event.observe(this.element,"keyup",this.delayedListener.bindAsEventListener(this));
-},delayedListener:function(_148){
-if(this.lastValue==$F(this.element)){
-return;
+Event.stopObserving(this.element, 'click', this.onclickListener);
+Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
+Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
+if (this.options.externalControl) {
+Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
+Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
+Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
}
-if(this.timer){
-clearTimeout(this.timer);
}
-this.timer=setTimeout(this.onTimerEvent.bind(this),this.delay*1000);
-this.lastValue=$F(this.element);
-},onTimerEvent:function(){
-this.timer=null;
-this.callback(this.element,$F(this.element));
-}};
-var Droppables={drops:[],remove:function(_149){
-this.drops=this.drops.reject(function(d){
-return d.element==$(_149);
-});
-},add:function(_151){
-_151=$(_151);
-var _152=Object.extend({greedy:true,hoverclass:null},arguments[1]||{});
-if(_152.containment){
-_152._containers=[];
-var _153=_152.containment;
-if((typeof _153=="object")&&(_153.constructor==Array)){
-_153.each(function(c){
-_152._containers.push($(c));
-});
-}else{
-_152._containers.push($(_153));
+};
+Ajax.InPlaceCollectionEditor = Class.create();
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
+createEditField: function() {
+if (!this.cached_selectTag) {
+var selectTag = document.createElement("select");
+var collection = this.options.collection || [];
+var optionTag;
+collection.each(function(e,i) {
+optionTag = document.createElement("option");
+optionTag.value = (e instanceof Array) ? e[0] : e;
+if(this.options.value==optionTag.value) optionTag.selected = true;
+optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
+selectTag.appendChild(optionTag);
+}.bind(this));
+this.cached_selectTag = selectTag;
}
+this.editField = this.cached_selectTag;
+if(this.options.loadTextURL) this.loadExternalText();
+this.form.appendChild(this.editField);
+this.options.callback = function(form, value) {
+return "value=" + encodeURIComponent(value);
}
-if(_152.accept){
-_152.accept=[_152.accept].flatten();
}
-Element.makePositioned(_151);
-_152.element=_151;
-this.drops.push(_152);
-},isContained:function(_154,drop){
-var _156=_154.parentNode;
-return drop._containers.detect(function(c){
-return _156==c;
});
-},isAffected:function(_157,_158,drop){
-return ((drop.element!=_158)&&((!drop._containers)||this.isContained(_158,drop))&&((!drop.accept)||(Element.classNames(_158).detect(function(v){
-return drop.accept.include(v);
-})))&&Position.within(drop.element,_157[0],_157[1]));
-},deactivate:function(drop){
-if(drop.hoverclass){
-Element.removeClassName(drop.element,drop.hoverclass);
-}
-this.last_active=null;
-},activate:function(drop){
-if(drop.hoverclass){
-Element.addClassName(drop.element,drop.hoverclass);
-}
-this.last_active=drop;
-},show:function(_160,_161){
-if(!this.drops.length){
-return;
-}
-if(this.last_active){
-this.deactivate(this.last_active);
-}
-this.drops.each(function(drop){
-if(Droppables.isAffected(_160,_161,drop)){
-if(drop.onHover){
-drop.onHover(_161,drop.element,Position.overlap(drop.overlap,drop.element));
-}
-if(drop.greedy){
-Droppables.activate(drop);
-throw $break;
-}
+Form.Element.DelayedObserver = Class.create();
+Form.Element.DelayedObserver.prototype = {
+initialize: function(element, delay, callback) {
+this.delay = delay || 0.5;
+this.element = $(element);
+this.callback= callback;
+this.timer = null;
+this.lastValue = $F(this.element);
+Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
+},
+delayedListener: function(event) {
+if(this.lastValue == $F(this.element)) return;
+if(this.timer) clearTimeout(this.timer);
+this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+this.lastValue = $F(this.element);
+},
+onTimerEvent: function() {
+this.timer = null;
+this.callback(this.element, $F(this.element));
}
+};
+var Droppables = {
+drops: [],
+remove: function(element) {
+this.drops = this.drops.reject(function(d) { return d.element==$(element) });
+},
+add: function(element) {
+element = $(element);
+var options = Object.extend({
+greedy: true,
+hoverclass: null,
+tree: false
+}, arguments[1] || {});
+if(options.containment) {
+options._containers = [];
+var containment = options.containment;
+if((typeof containment == 'object') &&
+(containment.constructor == Array)) {
+containment.each( function(c) { options._containers.push($(c)) });
+} else {
+options._containers.push($(containment));
+}
+}
+if(options.accept) options.accept = [options.accept].flatten();
+Element.makePositioned(element);options.element = element;
+this.drops.push(options);
+},
+findDeepestChild: function(drops) {
+deepest = drops[0];
+for (i = 1; i < drops.length; ++i)
+if (Element.isParent(drops[i].element, deepest.element))
+deepest = drops[i];
+return deepest;
+},
+isContained: function(element, drop) {
+var containmentNode;
+if(drop.tree) {
+containmentNode = element.treeNode;
+} else {
+containmentNode = element.parentNode;
+}
+return drop._containers.detect(function(c) { return containmentNode == c });
+},
+isAffected: function(point, element, drop) {
+return (
+(drop.element!=element) &&
+((!drop._containers) ||
+this.isContained(element, drop)) &&
+((!drop.accept) ||
+(Element.classNames(element).detect(
+function(v) { return drop.accept.include(v) } ) )) &&
+Position.within(drop.element, point[0], point[1]) );
+},
+deactivate: function(drop) {
+if(drop.hoverclass)
+Element.removeClassName(drop.element, drop.hoverclass);
+this.last_active = null;
+},
+activate: function(drop) {
+if(drop.hoverclass)
+Element.addClassName(drop.element, drop.hoverclass);
+this.last_active = drop;
+},
+show: function(point, element) {
+if(!this.drops.length) return;
+var affected = [];
+if(this.last_active) this.deactivate(this.last_active);
+this.drops.each( function(drop) {
+if(Droppables.isAffected(point, element, drop))
+affected.push(drop);
});
-},fire:function(_162,_163){
-if(!this.last_active){
-return;
+if(affected.length>0) {
+drop = Droppables.findDeepestChild(affected);
+Position.within(drop.element, point[0], point[1]);
+if(drop.onHover)
+drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+Droppables.activate(drop);
}
+},
+fire: function(event, element) {
+if(!this.last_active) return;
Position.prepare();
-if(this.isAffected([Event.pointerX(_162),Event.pointerY(_162)],_163,this.last_active)){
-if(this.last_active.onDrop){
-this.last_active.onDrop(_163,this.last_active.element,_162);
-}
-}
-},reset:function(){
-if(this.last_active){
+if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
+if (this.last_active.onDrop)
+this.last_active.onDrop(element, this.last_active.element, event);
+},
+reset: function() {
+if(this.last_active)
this.deactivate(this.last_active);
}
-}};
-var Draggables={drags:[],observers:[],register:function(_164){
-if(this.drags.length==0){
-this.eventMouseUp=this.endDrag.bindAsEventListener(this);
-this.eventMouseMove=this.updateDrag.bindAsEventListener(this);
-this.eventKeypress=this.keyPress.bindAsEventListener(this);
-Event.observe(document,"mouseup",this.eventMouseUp);
-Event.observe(document,"mousemove",this.eventMouseMove);
-Event.observe(document,"keypress",this.eventKeypress);
-}
-this.drags.push(_164);
-},unregister:function(_165){
-this.drags=this.drags.reject(function(d){
-return d==_165;
-});
-if(this.drags.length==0){
-Event.stopObserving(document,"mouseup",this.eventMouseUp);
-Event.stopObserving(document,"mousemove",this.eventMouseMove);
-Event.stopObserving(document,"keypress",this.eventKeypress);
-}
-},activate:function(_166){
-window.focus();
-this.activeDraggable=_166;
-},deactivate:function(_167){
-this.activeDraggable=null;
-},updateDrag:function(_168){
-if(!this.activeDraggable){
-return;
}
-var _169=[Event.pointerX(_168),Event.pointerY(_168)];
-if(this._lastPointer&&(this._lastPointer.inspect()==_169.inspect())){
-return;
-}
-this._lastPointer=_169;
-this.activeDraggable.updateDrag(_168,_169);
-},endDrag:function(_170){
-if(!this.activeDraggable){
-return;
-}
-this._lastPointer=null;
-this.activeDraggable.endDrag(_170);
-this.activeDraggable=null;
-},keyPress:function(_171){
-if(this.activeDraggable){
-this.activeDraggable.keyPress(_171);
-}
-},addObserver:function(_172){
-this.observers.push(_172);
+var Draggables = {
+drags: [],
+observers: [],
+register: function(draggable) {
+if(this.drags.length == 0) {
+this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+this.eventKeypress= this.keyPress.bindAsEventListener(this);
+Event.observe(document, "mouseup", this.eventMouseUp);
+Event.observe(document, "mousemove", this.eventMouseMove);
+Event.observe(document, "keypress", this.eventKeypress);
+}
+this.drags.push(draggable);
+},
+unregister: function(draggable) {
+this.drags = this.drags.reject(function(d) { return d==draggable });
+if(this.drags.length == 0) {
+Event.stopObserving(document, "mouseup", this.eventMouseUp);
+Event.stopObserving(document, "mousemove", this.eventMouseMove);
+Event.stopObserving(document, "keypress", this.eventKeypress);
+}
+},
+activate: function(draggable) {
+window.focus();this.activeDraggable = draggable;
+},
+deactivate: function() {
+this.activeDraggable = null;
+},
+updateDrag: function(event) {
+if(!this.activeDraggable) return;
+var pointer = [Event.pointerX(event), Event.pointerY(event)];
+if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
+this._lastPointer = pointer;
+this.activeDraggable.updateDrag(event, pointer);
+},
+endDrag: function(event) {
+if(!this.activeDraggable) return;
+this._lastPointer = null;
+this.activeDraggable.endDrag(event);
+this.activeDraggable = null;
+},
+keyPress: function(event) {
+if(this.activeDraggable)
+this.activeDraggable.keyPress(event);
+},
+addObserver: function(observer) {
+this.observers.push(observer);
this._cacheObserverCallbacks();
-},removeObserver:function(_173){
-this.observers=this.observers.reject(function(o){
-return o.element==_173;
-});
+},
+removeObserver: function(element) { this.observers = this.observers.reject( function(o) { return o.element==element });
this._cacheObserverCallbacks();
-},notify:function(_175,_176,_177){
-if(this[_175+"Count"]>0){
-this.observers.each(function(o){
-if(o[_175]){
-o[_175](_175,_176,_177);
-}
+},
+notify: function(eventName, draggable, event) { if(this[eventName+'Count'] > 0)
+this.observers.each( function(o) {
+if(o[eventName]) o[eventName](eventName, draggable, event);
});
-}
-},_cacheObserverCallbacks:function(){
-["onStart","onEnd","onDrag"].each(function(_178){
-Draggables[_178+"Count"]=Draggables.observers.select(function(o){
-return o[_178];
-}).length;
+},
+_cacheObserverCallbacks: function() {
+['onStart','onEnd','onDrag'].each( function(eventName) {
+Draggables[eventName+'Count'] = Draggables.observers.select(
+function(o) { return o[eventName]; }
+).length;
});
-}};
-var Draggable=Class.create();
-Draggable.prototype={initialize:function(_179){
-var _180=Object.extend({handle:false,starteffect:function(_179){
-new Effect.Opacity(_179,{duration:0.2,from:1,to:0.7});
-},reverteffect:function(_181,_182,_183){
-var dur=Math.sqrt(Math.abs(_182^2)+Math.abs(_183^2))*0.02;
-_181._revert=new Effect.Move(_181,{x:-_183,y:-_182,duration:dur});
-},endeffect:function(_185){
-new Effect.Opacity(_185,{duration:0.2,from:0.7,to:1});
-},zindex:1000,revert:false,snap:false},arguments[1]||{});
-this.element=$(element);
-if(_180.handle&&(typeof _180.handle=="string")){
-this.handle=Element.childrenWithClassName(this.element,_180.handle)[0];
-}
-if(!this.handle){
-this.handle=$(_180.handle);
-}
-if(!this.handle){
-this.handle=this.element;
}
+}
+var Draggable = Class.create();
+Draggable.prototype = {
+initialize: function(element) {
+var options = Object.extend({
+handle: false,
+starteffect: function(element) {
+element._opacity = Element.getOpacity(element);
+new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
+},
+reverteffect: function(element, top_offset, left_offset) {
+var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur});
+},
+endeffect: function(element) {
+var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0
+new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity});
+},
+zindex: 1000,
+revert: false,
+scroll: false,
+scrollSensitivity: 20,
+scrollSpeed: 15,
+snap: false}, arguments[1] || {});
+this.element = $(element);
+if(options.handle && (typeof options.handle == 'string')) {
+var h = Element.childrenWithClassName(this.element, options.handle, true);
+if(h.length>0) this.handle = h[0];
+}
+if(!this.handle) this.handle = $(options.handle);
+if(!this.handle) this.handle = this.element;
+if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML)
+options.scroll = $(options.scroll);
Element.makePositioned(this.element);
-this.delta=this.currentDelta();
-this.options=_180;
-this.dragging=false;
-this.eventMouseDown=this.initDrag.bindAsEventListener(this);
-Event.observe(this.handle,"mousedown",this.eventMouseDown);
+this.delta= this.currentDelta();
+this.options= options;
+this.dragging = false;
+this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+Event.observe(this.handle, "mousedown", this.eventMouseDown);
Draggables.register(this);
-},destroy:function(){
-Event.stopObserving(this.handle,"mousedown",this.eventMouseDown);
+},
+destroy: function() {
+Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
Draggables.unregister(this);
-},currentDelta:function(){
-return ([parseInt(Element.getStyle(this.element,"left")||"0"),parseInt(Element.getStyle(this.element,"top")||"0")]);
-},initDrag:function(_186){
-if(Event.isLeftClick(_186)){
-var src=Event.element(_186);
-if(src.tagName&&(src.tagName=="INPUT"||src.tagName=="SELECT"||src.tagName=="BUTTON"||src.tagName=="TEXTAREA")){
-return;
-}
-if(this.element._revert){
+},
+currentDelta: function() {
+return([
+parseInt(Element.getStyle(this.element,'left') || '0'),
+parseInt(Element.getStyle(this.element,'top') || '0')]);
+},
+initDrag: function(event) {
+if(Event.isLeftClick(event)) {
+ var src = Event.element(event);
+if(src.tagName && (
+src.tagName=='INPUT' ||
+src.tagName=='SELECT' ||
+src.tagName=='OPTION' ||
+src.tagName=='BUTTON' ||
+src.tagName=='TEXTAREA')) return;
+if(this.element._revert) {
this.element._revert.cancel();
-this.element._revert=null;
+this.element._revert = null;
}
-var _188=[Event.pointerX(_186),Event.pointerY(_186)];
-var pos=Position.cumulativeOffset(this.element);
-this.offset=[0,1].map(function(i){
-return (_188[i]-pos[i]);
-});
+var pointer = [Event.pointerX(event), Event.pointerY(event)];
+var pos = Position.cumulativeOffset(this.element);
+this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
Draggables.activate(this);
-Event.stop(_186);
+Event.stop(event);
}
-},startDrag:function(_190){
-this.dragging=true;
-if(this.options.zindex){
-this.originalZ=parseInt(Element.getStyle(this.element,"z-index")||0);
-this.element.style.zIndex=this.options.zindex;
+},
+startDrag: function(event) {
+this.dragging = true;
+if(this.options.zindex) {
+this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+this.element.style.zIndex = this.options.zindex;
}
-if(this.options.ghosting){
-this._clone=this.element.cloneNode(true);
+if(this.options.ghosting) {
+this._clone = this.element.cloneNode(true);
Position.absolutize(this.element);
-this.element.parentNode.insertBefore(this._clone,this.element);
-}
-Draggables.notify("onStart",this,_190);
-if(this.options.starteffect){
-this.options.starteffect(this.element);
-}
-},updateDrag:function(_191,_192){
-if(!this.dragging){
-this.startDrag(_191);
-}
+this.element.parentNode.insertBefore(this._clone, this.element);
+}
+if(this.options.scroll) {
+if (this.options.scroll == window) {
+var where = this._getWindowScroll(this.options.scroll);
+this.originalScrollLeft = where.left;
+this.originalScrollTop = where.top;
+} else {
+this.originalScrollLeft = this.options.scroll.scrollLeft;
+this.originalScrollTop = this.options.scroll.scrollTop;
+}
+}
+Draggables.notify('onStart', this, event);
+if(this.options.starteffect) this.options.starteffect(this.element);
+},
+updateDrag: function(event, pointer) {
+if(!this.dragging) this.startDrag(event);
Position.prepare();
-Droppables.show(_192,this.element);
-Draggables.notify("onDrag",this,_191);
-this.draw(_192);
-if(this.options.change){
-this.options.change(this);
-}
-if(navigator.appVersion.indexOf("AppleWebKit")>0){
-window.scrollBy(0,0);
-}
-Event.stop(_191);
-},finishDrag:function(_193,_194){
-this.dragging=false;
-if(this.options.ghosting){
+Droppables.show(pointer, this.element);
+Draggables.notify('onDrag', this, event);
+this.draw(pointer);
+if(this.options.change) this.options.change(this);
+if(this.options.scroll) {
+this.stopScrolling();
+var p;
+if (this.options.scroll == window) {
+with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
+} else {
+p = Position.page(this.options.scroll);
+p[0] += this.options.scroll.scrollLeft;
+p[1] += this.options.scroll.scrollTop;
+p.push(p[0]+this.options.scroll.offsetWidth);
+p.push(p[1]+this.options.scroll.offsetHeight);
+}
+var speed = [0,0];
+if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
+if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
+if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
+if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
+this.startScrolling(speed);
+}
+if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+Event.stop(event);
+},
+finishDrag: function(event, success) {
+this.dragging = false;
+if(this.options.ghosting) {
Position.relativize(this.element);
Element.remove(this._clone);
-this._clone=null;
-}
-if(_194){
-Droppables.fire(_193,this.element);
-}
-Draggables.notify("onEnd",this,_193);
-var _195=this.options.revert;
-if(_195&&typeof _195=="function"){
-_195=_195(this.element);
-}
-var d=this.currentDelta();
-if(_195&&this.options.reverteffect){
-this.options.reverteffect(this.element,d[1]-this.delta[1],d[0]-this.delta[0]);
-}else{
-this.delta=d;
-}
-if(this.options.zindex){
-this.element.style.zIndex=this.originalZ;
-}
-if(this.options.endeffect){
+this._clone = null;
+}
+if(success) Droppables.fire(event, this.element);
+Draggables.notify('onEnd', this, event);
+var revert = this.options.revert;
+if(revert && typeof revert == 'function') revert = revert(this.element);
+var d = this.currentDelta();
+if(revert && this.options.reverteffect) {
+this.options.reverteffect(this.element,
+d[1]-this.delta[1], d[0]-this.delta[0]);
+} else {
+this.delta = d;
+}
+if(this.options.zindex)
+this.element.style.zIndex = this.originalZ;
+if(this.options.endeffect)
this.options.endeffect(this.element);
-}
Draggables.deactivate(this);
Droppables.reset();
-},keyPress:function(_196){
-if(!_196.keyCode==Event.KEY_ESC){
-return;
-}
-this.finishDrag(_196,false);
-Event.stop(_196);
-},endDrag:function(_197){
-if(!this.dragging){
-return;
-}
-this.finishDrag(_197,true);
-Event.stop(_197);
-},draw:function(_198){
-var pos=Position.cumulativeOffset(this.element);
-var d=this.currentDelta();
-pos[0]-=d[0];
-pos[1]-=d[1];
-var p=[0,1].map(function(i){
-return (_198[i]-pos[i]-this.offset[i]);
-}.bind(this));
-if(this.options.snap){
-if(typeof this.options.snap=="function"){
-p=this.options.snap(p[0],p[1]);
-}else{
-if(this.options.snap instanceof Array){
-p=p.map(function(v,i){
-return Math.round(v/this.options.snap[i])*this.options.snap[i];
-}.bind(this));
-}else{
-p=p.map(function(v){
-return Math.round(v/this.options.snap)*this.options.snap;
+},
+keyPress: function(event) {
+if(event.keyCode!=Event.KEY_ESC) return;
+this.finishDrag(event, false);
+Event.stop(event);
+},
+endDrag: function(event) {
+if(!this.dragging) return;
+this.stopScrolling();
+this.finishDrag(event, true);
+Event.stop(event);
+},
+draw: function(point) {
+var pos = Position.cumulativeOffset(this.element);
+var d = this.currentDelta();
+pos[0] -= d[0]; pos[1] -= d[1];
+if(this.options.scroll && (this.options.scroll != window)) {
+pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+}
+var p = [0,1].map(function(i){
+return (point[i]-pos[i]-this.offset[i])
}.bind(this));
+if(this.options.snap) {
+if(typeof this.options.snap == 'function') {
+p = this.options.snap(p[0],p[1],this);
+} else {
+if(this.options.snap instanceof Array) {
+p = p.map( function(v, i) {
+return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
+} else {
+p = p.map( function(v) {
+return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
+}
+}}
+var style = this.element.style;
+if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+style.left = p[0] + "px";
+if((!this.options.constraint) || (this.options.constraint=='vertical'))
+style.top= p[1] + "px";
+if(style.visibility=="hidden") style.visibility = "";},
+stopScrolling: function() {
+if(this.scrollInterval) {
+clearInterval(this.scrollInterval);
+this.scrollInterval = null;
+Draggables._lastScrollPointer = null;
+}
+},
+startScrolling: function(speed) {
+this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
+this.lastScrolled = new Date();
+this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+},
+scroll: function() {
+var current = new Date();
+var delta = current - this.lastScrolled;
+this.lastScrolled = current;
+if(this.options.scroll == window) {
+with (this._getWindowScroll(this.options.scroll)) {
+if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+var d = delta / 1000;
+this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
+}
+}
+} else {
+this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+this.options.scroll.scrollTop+= this.scrollSpeed[1] * delta / 1000;
}
-}
-}
-var _200=this.element.style;
-if((!this.options.constraint)||(this.options.constraint=="horizontal")){
-_200.left=p[0]+"px";
-}
-if((!this.options.constraint)||(this.options.constraint=="vertical")){
-_200.top=p[1]+"px";
-}
-if(_200.visibility=="hidden"){
-_200.visibility="";
-}
-}};
-var SortableObserver=Class.create();
-SortableObserver.prototype={initialize:function(_201,_202){
-this.element=$(_201);
-this.observer=_202;
-this.lastValue=Sortable.serialize(this.element);
-},onStart:function(){
-this.lastValue=Sortable.serialize(this.element);
-},onEnd:function(){
+Position.prepare();
+Droppables.show(Draggables._lastPointer, this.element);
+Draggables.notify('onDrag', this);
+Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+if (Draggables._lastScrollPointer[0] < 0)
+Draggables._lastScrollPointer[0] = 0;
+if (Draggables._lastScrollPointer[1] < 0)
+Draggables._lastScrollPointer[1] = 0;
+this.draw(Draggables._lastScrollPointer);
+if(this.options.change) this.options.change(this);
+},
+_getWindowScroll: function(w) {
+var T, L, W, H;
+with (w.document) {
+if (w.document.documentElement && documentElement.scrollTop) {
+T = documentElement.scrollTop;
+L = documentElement.scrollLeft;
+} else if (w.document.body) {
+T = body.scrollTop;
+L = body.scrollLeft;
+}
+if (w.innerWidth) {
+W = w.innerWidth;
+H = w.innerHeight;
+} else if (w.document.documentElement && documentElement.clientWidth) {
+W = documentElement.clientWidth;
+H = documentElement.clientHeight;
+} else {
+W = body.offsetWidth;
+H = body.offsetHeight
+}
+}
+return { top: T, left: L, width: W, height: H };
+}
+}
+var SortableObserver = Class.create();
+SortableObserver.prototype = {
+initialize: function(element, observer) {
+this.element = $(element);
+this.observer= observer;
+this.lastValue = Sortable.serialize(this.element);
+},
+onStart: function() {
+this.lastValue = Sortable.serialize(this.element);
+},
+onEnd: function() {
Sortable.unmark();
-if(this.lastValue!=Sortable.serialize(this.element)){
-this.observer(this.element);
-}
-}};
-var Sortable={sortables:new Array(),options:function(_203){
-_203=$(_203);
-return this.sortables.detect(function(s){
-return s.element==_203;
-});
-},destroy:function(_205){
-_205=$(_205);
-this.sortables.findAll(function(s){
-return s.element==_205;
-}).each(function(s){
+if(this.lastValue != Sortable.serialize(this.element))
+this.observer(this.element)
+}
+}
+var Sortable = {
+sortables: {},
+_findRootElement: function(element) {
+while (element.tagName != "BODY") {
+if(element.id && Sortable.sortables[element.id]) return element;
+element = element.parentNode;
+}
+},
+options: function(element) {
+element = Sortable._findRootElement($(element));
+if(!element) return;
+return Sortable.sortables[element.id];
+},
+destroy: function(element){
+var s = Sortable.options(element);
+if(s) {
Draggables.removeObserver(s.element);
-s.droppables.each(function(d){
-Droppables.remove(d);
-});
-s.draggables.invoke("destroy");
-});
-this.sortables=this.sortables.reject(function(s){
-return s.element==_205;
-});
-},create:function(_206){
-_206=$(_206);
-var _207=Object.extend({element:_206,tag:"li",dropOnEmpty:false,tree:false,overlap:"vertical",constraint:"vertical",containment:_206,handle:false,only:false,hoverclass:null,ghosting:false,format:null,onChange:Prototype.emptyFunction,onUpdate:Prototype.emptyFunction},arguments[1]||{});
-this.destroy(_206);
-var _208={revert:true,ghosting:_207.ghosting,constraint:_207.constraint,handle:_207.handle};
-if(_207.starteffect){
-_208.starteffect=_207.starteffect;
-}
-if(_207.reverteffect){
-_208.reverteffect=_207.reverteffect;
-}else{
-if(_207.ghosting){
-_208.reverteffect=function(_206){
-_206.style.top=0;
-_206.style.left=0;
+s.droppables.each(function(d){ Droppables.remove(d) });
+s.draggables.invoke('destroy');
+delete Sortable.sortables[s.element.id];
+}
+},
+create: function(element) {
+element = $(element);
+var options = Object.extend({
+element: element,
+tag: 'li',dropOnEmpty: false,
+tree:false,
+treeTag: 'ul',
+overlap: 'vertical',constraint:'vertical',containment: element, handle:false, only:false,
+hoverclass:null,
+ghosting:false,
+scroll:false,
+scrollSensitivity: 20,
+scrollSpeed: 15,
+format:/^[^_]*_(.*)$/,
+onChange:Prototype.emptyFunction,
+onUpdate:Prototype.emptyFunction
+}, arguments[1] || {});
+this.destroy(element);
+var options_for_draggable = {
+revert:true,
+scroll:options.scroll,
+scrollSpeed: options.scrollSpeed,
+scrollSensitivity: options.scrollSensitivity,
+ghosting:options.ghosting,
+constraint:options.constraint,
+handle:options.handle };
+if(options.starteffect)
+options_for_draggable.starteffect = options.starteffect;
+if(options.reverteffect)
+options_for_draggable.reverteffect = options.reverteffect;
+else
+if(options.ghosting) options_for_draggable.reverteffect = function(element) {
+element.style.top= 0;
+element.style.left = 0;
};
-}
-}
-if(_207.endeffect){
-_208.endeffect=_207.endeffect;
-}
-if(_207.zindex){
-_208.zindex=_207.zindex;
-}
-var _209={overlap:_207.overlap,containment:_207.containment,hoverclass:_207.hoverclass,onHover:Sortable.onHover,greedy:!_207.dropOnEmpty};
-Element.cleanWhitespace(element);
-_207.draggables=[];
-_207.droppables=[];
-if(_207.dropOnEmpty){
-Droppables.add(element,{containment:_207.containment,onHover:Sortable.onEmptyHover,greedy:false});
-_207.droppables.push(element);
-}
-(this.findElements(element,_207)||[]).each(function(e){
-var _210=_207.handle?Element.childrenWithClassName(e,_207.handle)[0]:e;
-_207.draggables.push(new Draggable(e,Object.extend(_208,{handle:_210})));
-Droppables.add(e,_209);
-_207.droppables.push(e);
+if(options.endeffect)
+options_for_draggable.endeffect = options.endeffect;
+if(options.zindex)
+options_for_draggable.zindex = options.zindex;
+var options_for_droppable = {
+overlap: options.overlap,
+containment: options.containment,
+tree:options.tree,
+hoverclass:options.hoverclass,
+onHover: Sortable.onHover
+ }
+var options_for_tree = {
+onHover:Sortable.onEmptyHover,
+overlap:options.overlap,
+containment:options.containment,
+hoverclass: options.hoverclass
+}
+Element.cleanWhitespace(element);
+options.draggables = [];
+options.droppables = [];
+if(options.dropOnEmpty || options.tree) {
+Droppables.add(element, options_for_tree);
+options.droppables.push(element);
+}
+(this.findElements(element, options) || []).each( function(e) {
+ var handle = options.handle ?
+Element.childrenWithClassName(e, options.handle)[0] : e;
+options.draggables.push(
+new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+Droppables.add(e, options_for_droppable);
+if(options.tree) e.treeNode = element;
+options.droppables.push(e);
+});
+if(options.tree) {
+(Sortable.findTreeElements(element, options) || []).each( function(e) {
+Droppables.add(e, options_for_tree);
+e.treeNode = element;
+options.droppables.push(e);
});
-this.sortables.push(_207);
-Draggables.addObserver(new SortableObserver(element,_207.onUpdate));
-},findElements:function(_211,_212){
-if(!_211.hasChildNodes()){
-return null;
-}
-var _213=[];
-$A(_211.childNodes).each(function(e){
-if(e.tagName&&e.tagName.toUpperCase()==_212.tag.toUpperCase()&&(!_212.only||(Element.hasClassName(e,_212.only)))){
-_213.push(e);
}
-if(_212.tree){
-var _214=this.findElements(e,_212);
-if(_214){
-_213.push(_214);
+this.sortables[element.id] = options;
+Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+},
+findElements: function(element, options) {
+return Element.findChildren(
+element, options.only, options.tree ? true : false, options.tag);
+},
+findTreeElements: function(element, options) {
+return Element.findChildren(
+element, options.only, options.tree ? true : false, options.treeTag);
+},
+onHover: function(element, dropon, overlap) {
+if(Element.isParent(dropon, element)) return;
+if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
+return;
+} else if(overlap>0.5) {
+Sortable.mark(dropon, 'before');
+if(dropon.previousSibling != element) {
+var oldParentNode = element.parentNode;
+element.style.visibility = "hidden";dropon.parentNode.insertBefore(element, dropon);
+if(dropon.parentNode!=oldParentNode)
+Sortable.options(oldParentNode).onChange(element);
+Sortable.options(dropon.parentNode).onChange(element);
+}
+} else {
+Sortable.mark(dropon, 'after');
+var nextElement = dropon.nextSibling || null;
+if(nextElement != element) {
+var oldParentNode = element.parentNode;
+element.style.visibility = "hidden";dropon.parentNode.insertBefore(element, nextElement);
+if(dropon.parentNode!=oldParentNode)
+Sortable.options(oldParentNode).onChange(element);
+Sortable.options(dropon.parentNode).onChange(element);
+}
+}
+},
+onEmptyHover: function(element, dropon, overlap) {
+var oldParentNode = element.parentNode;
+var droponOptions = Sortable.options(dropon);
+if(!Element.isParent(dropon, element)) {
+var index;
+var children = Sortable.findElements(dropon, {tag: droponOptions.tag});
+var child = null;
+if(children) {
+var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+for (index = 0; index < children.length; index += 1) {
+if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
+offset -= Element.offsetSize (children[index], droponOptions.overlap);
+} else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+child = index + 1 < children.length ? children[index + 1] : null;
+break;
+} else {
+child = children[index];
+break;
}
}
-});
-return (_213.length>0?_213.flatten():null);
-},onHover:function(_215,_216,_217){
-if(_217>0.5){
-Sortable.mark(_216,"before");
-if(_216.previousSibling!=_215){
-var _218=_215.parentNode;
-_215.style.visibility="hidden";
-_216.parentNode.insertBefore(_215,_216);
-if(_216.parentNode!=_218){
-Sortable.options(_218).onChange(_215);
-}
-Sortable.options(_216.parentNode).onChange(_215);
-}
-}else{
-Sortable.mark(_216,"after");
-var _219=_216.nextSibling||null;
-if(_219!=_215){
-var _218=_215.parentNode;
-_215.style.visibility="hidden";
-_216.parentNode.insertBefore(_215,_219);
-if(_216.parentNode!=_218){
-Sortable.options(_218).onChange(_215);
-}
-Sortable.options(_216.parentNode).onChange(_215);
-}
-}
-},onEmptyHover:function(_220,_221){
-if(_220.parentNode!=_221){
-var _222=_220.parentNode;
-_221.appendChild(_220);
-Sortable.options(_222).onChange(_220);
-Sortable.options(_221).onChange(_220);
-}
-},unmark:function(){
-if(Sortable._marker){
-Element.hide(Sortable._marker);
}
-},mark:function(_223,_224){
-var _225=Sortable.options(_223.parentNode);
-if(_225&&!_225.ghosting){
-return;
+dropon.insertBefore(element, child);
+Sortable.options(oldParentNode).onChange(element);
+droponOptions.onChange(element);
}
-if(!Sortable._marker){
-Sortable._marker=$("dropmarker")||document.createElement("DIV");
+},
+unmark: function() {
+if(Sortable._marker) Element.hide(Sortable._marker);
+},
+mark: function(dropon, position) {
+ var sortable = Sortable.options(dropon.parentNode);
+if(sortable && !sortable.ghosting) return;
+if(!Sortable._marker) {
+Sortable._marker = $('dropmarker') || document.createElement('DIV');
Element.hide(Sortable._marker);
-Element.addClassName(Sortable._marker,"dropmarker");
-Sortable._marker.style.position="absolute";
+Element.addClassName(Sortable._marker, 'dropmarker');
+Sortable._marker.style.position = 'absolute';
document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
}
-var _226=Position.cumulativeOffset(_223);
-Sortable._marker.style.left=_226[0]+"px";
-Sortable._marker.style.top=_226[1]+"px";
-if(_224=="after"){
-if(_225.overlap=="horizontal"){
-Sortable._marker.style.left=(_226[0]+_223.clientWidth)+"px";
-}else{
-Sortable._marker.style.top=(_226[1]+_223.clientHeight)+"px";
-}
-}
+var offsets = Position.cumulativeOffset(dropon);
+Sortable._marker.style.left = offsets[0] + 'px';
+Sortable._marker.style.top = offsets[1] + 'px';
+if(position=='after')
+if(sortable.overlap == 'horizontal')
+Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
+else
+Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
Element.show(Sortable._marker);
-},serialize:function(_227){
-_227=$(_227);
-var _228=this.options(_227);
-var _229=Object.extend({tag:_228.tag,only:_228.only,name:_227.id,format:_228.format||/^[^_]*_(.*)$/},arguments[1]||{});
-return $(this.findElements(_227,_229)||[]).map(function(item){
-return (encodeURIComponent(_229.name)+"[]="+encodeURIComponent(item.id.match(_229.format)?item.id.match(_229.format)[1]:""));
-}).join("&");
-}};
-if(!Control){
-var Control={};
-}
-Control.Slider=Class.create();
-Control.Slider.prototype={initialize:function(_231,_232,_233){
-var _234=this;
-if(_231 instanceof Array){
-this.handles=_231.collect(function(e){
-return $(e);
+},
+_tree: function(element, options, parent) {
+var children = Sortable.findElements(element, options) || [];
+for (var i = 0; i < children.length; ++i) {
+var match = children[i].id.match(options.format);
+if (!match) continue;
+var child = {
+id: encodeURIComponent(match ? match[1] : null),
+element: element,
+parent: parent,
+children: new Array,
+position: parent.children.length,
+container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase())
+}
+if (child.container)
+this._tree(child.container, options, child)
+parent.children.push (child);
+}
+return parent;
+},
+_findChildrenElement: function (element, containerTag) {
+if (element && element.hasChildNodes)
+for (var i = 0; i < element.childNodes.length; ++i)
+if (element.childNodes[i].tagName == containerTag)
+return element.childNodes[i];
+return null;
+},
+tree: function(element) {
+element = $(element);
+var sortableOptions = this.options(element);
+var options = Object.extend({
+tag: sortableOptions.tag,
+treeTag: sortableOptions.treeTag,
+only: sortableOptions.only,
+name: element.id,
+format: sortableOptions.format
+}, arguments[1] || {});
+var root = {
+id: null,
+parent: null,
+children: new Array,
+container: element,
+position: 0
+}
+return Sortable._tree (element, options, root);
+},
+_constructIndex: function(node) {
+var index = '';
+do {
+if (node.id) index = '[' + node.position + ']' + index;
+} while ((node = node.parent) != null);
+return index;
+},
+sequence: function(element) {
+element = $(element);
+var options = Object.extend(this.options(element), arguments[1] || {});
+return $(this.findElements(element, options) || []).map( function(item) {
+return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
});
-}else{
-this.handles=[$(_231)];
-}
-this.track=$(_232);
-this.options=_233||{};
-this.axis=this.options.axis||"horizontal";
-this.increment=this.options.increment||1;
-this.step=parseInt(this.options.step||"1");
-this.range=this.options.range||$R(0,1);
-this.value=0;
-this.values=this.handles.map(function(){
-return 0;
+},
+setSequence: function(element, new_sequence) {
+element = $(element);
+var options = Object.extend(this.options(element), arguments[2] || {});
+var nodeMap = {};
+this.findElements(element, options).each( function(n) {
+if (n.id.match(options.format))
+nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+n.parentNode.removeChild(n);
});
-this.spans=this.options.spans?this.options.spans.map(function(s){
-return $(s);
-}):false;
-this.options.startSpan=$(this.options.startSpan||null);
-this.options.endSpan=$(this.options.endSpan||null);
-this.restricted=this.options.restricted||false;
-this.maximum=this.options.maximum||this.range.end;
-this.minimum=this.options.minimum||this.range.start;
-this.alignX=parseInt(this.options.alignX||"0");
-this.alignY=parseInt(this.options.alignY||"0");
-this.trackLength=this.maximumOffset()-this.minimumOffset();
-this.handleLength=this.isVertical()?this.handles[0].offsetHeight:this.handles[0].offsetWidth;
-this.active=false;
-this.dragging=false;
-this.disabled=false;
-if(this.options.disabled){
-this.setDisabled();
-}
-this.allowedValues=this.options.values?this.options.values.sortBy(Prototype.K):false;
-if(this.allowedValues){
-this.minimum=this.allowedValues.min();
-this.maximum=this.allowedValues.max();
-}
-this.eventMouseDown=this.startDrag.bindAsEventListener(this);
-this.eventMouseUp=this.endDrag.bindAsEventListener(this);
-this.eventMouseMove=this.update.bindAsEventListener(this);
-this.handles.each(function(h,i){
-i=_234.handles.length-1-i;
-_234.setValue(parseFloat((_234.options.sliderValue instanceof Array?_234.options.sliderValue[i]:_234.options.sliderValue)||_234.range.start),i);
-Element.makePositioned(h);
-Event.observe(h,"mousedown",_234.eventMouseDown);
+new_sequence.each(function(ident) {
+var n = nodeMap[ident];
+if (n) {
+n[1].appendChild(n[0]);
+delete nodeMap[ident];
+}
+});
+},
+serialize: function(element) {
+element = $(element);
+var options = Object.extend(Sortable.options(element), arguments[1] || {});
+var name = encodeURIComponent(
+(arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+if (options.tree) {
+return Sortable.tree(element, arguments[1]).children.map( function (item) {
+return [name + Sortable._constructIndex(item) + "=" +
+encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+}).flatten().join('&');
+} else {
+return Sortable.sequence(element, arguments[1]).map( function(item) {
+return name + "[]=" + encodeURIComponent(item);
+}).join('&');
+}
+}
+}
+Element.isParent = function(child, element) {
+if (!child.parentNode || child == element) return false;
+if (child.parentNode == element) return true;
+return Element.isParent(child.parentNode, element);
+}
+Element.findChildren = function(element, only, recursive, tagName) {
+if(!element.hasChildNodes()) return null;
+tagName = tagName.toUpperCase();
+if(only) only = [only].flatten();
+var elements = [];
+$A(element.childNodes).each( function(e) {
+if(e.tagName && e.tagName.toUpperCase()==tagName &&
+(!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
+elements.push(e);
+if(recursive) {
+var grandchildren = Element.findChildren(e, only, recursive, tagName);
+if(grandchildren) elements.push(grandchildren);
+}
+});
+return (elements.length>0 ? elements.flatten() : []);
+}
+Element.offsetSize = function (element, type) {
+if (type == 'vertical' || type == 'height')
+return element.offsetHeight;
+else
+return element.offsetWidth;
+}
+if(!Control) var Control = {};
+Control.Slider = Class.create();
+Control.Slider.prototype = {
+initialize: function(handle, track, options) {
+var slider = this;
+if(handle instanceof Array) {
+this.handles = handle.collect( function(e) { return $(e) });
+} else {
+this.handles = [$(handle)];
+}
+this.track = $(track);
+this.options = options || {};
+this.axis= this.options.axis || 'horizontal';
+this.increment = this.options.increment || 1;
+this.step= parseInt(this.options.step || '1');
+this.range = this.options.range || $R(0,1);
+this.value = 0;this.values= this.handles.map( function() { return 0 });
+this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
+this.options.startSpan = $(this.options.startSpan || null);
+this.options.endSpan = $(this.options.endSpan || null);
+this.restricted = this.options.restricted || false;
+this.maximum = this.options.maximum || this.range.end;
+this.minimum = this.options.minimum || this.range.start;
+this.alignX = parseInt(this.options.alignX || '0');
+this.alignY = parseInt(this.options.alignY || '0');
+this.trackLength = this.maximumOffset() - this.minimumOffset();
+this.handleLength = this.isVertical() ? this.handles[0].offsetHeight : this.handles[0].offsetWidth;
+this.active = false;
+this.dragging = false;
+this.disabled = false;
+if(this.options.disabled) this.setDisabled();
+this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
+if(this.allowedValues) {
+this.minimum = this.allowedValues.min();
+this.maximum = this.allowedValues.max();
+}
+this.eventMouseDown = this.startDrag.bindAsEventListener(this);
+this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+this.eventMouseMove = this.update.bindAsEventListener(this);
+this.handles.each( function(h,i) {
+i = slider.handles.length-1-i;
+slider.setValue(parseFloat(
+(slider.options.sliderValue instanceof Array ?
+slider.options.sliderValue[i] : slider.options.sliderValue) ||
+ slider.range.start), i);
+Element.makePositioned(h);Event.observe(h, "mousedown", slider.eventMouseDown);
});
-Event.observe(this.track,"mousedown",this.eventMouseDown);
-Event.observe(document,"mouseup",this.eventMouseUp);
-Event.observe(document,"mousemove",this.eventMouseMove);
-this.initialized=true;
-},dispose:function(){
-var _236=this;
-Event.stopObserving(this.track,"mousedown",this.eventMouseDown);
-Event.stopObserving(document,"mouseup",this.eventMouseUp);
-Event.stopObserving(document,"mousemove",this.eventMouseMove);
-this.handles.each(function(h){
-Event.stopObserving(h,"mousedown",_236.eventMouseDown);
+Event.observe(this.track, "mousedown", this.eventMouseDown);
+Event.observe(document, "mouseup", this.eventMouseUp);
+Event.observe(document, "mousemove", this.eventMouseMove);
+this.initialized = true;
+},
+dispose: function() {
+var slider = this;
+Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
+Event.stopObserving(document, "mouseup", this.eventMouseUp);
+Event.stopObserving(document, "mousemove", this.eventMouseMove);
+this.handles.each( function(h) {
+Event.stopObserving(h, "mousedown", slider.eventMouseDown);
});
-},setDisabled:function(){
-this.disabled=true;
-},setEnabled:function(){
-this.disabled=false;
-},getNearestValue:function(_237){
+},
+setDisabled: function(){
+this.disabled = true;
+},
+setEnabled: function(){
+this.disabled = false;
+},
+getNearestValue: function(value){
if(this.allowedValues){
-if(_237>=this.allowedValues.max()){
-return (this.allowedValues.max());
-}
-if(_237<=this.allowedValues.min()){
-return (this.allowedValues.min());
-}
-var _238=Math.abs(this.allowedValues[0]-_237);
-var _239=this.allowedValues[0];
-this.allowedValues.each(function(v){
-var _240=Math.abs(v-_237);
-if(_240<=_238){
-_239=v;
-_238=_240;
-}
+if(value >= this.allowedValues.max()) return(this.allowedValues.max());
+if(value <= this.allowedValues.min()) return(this.allowedValues.min());
+var offset = Math.abs(this.allowedValues[0] - value);
+var newValue = this.allowedValues[0];
+this.allowedValues.each( function(v) {
+var currentOffset = Math.abs(v - value);
+if(currentOffset <= offset){
+newValue = v;
+offset = currentOffset;
+}
});
-return _239;
-}
-if(_237>this.range.end){
-return this.range.end;
-}
-if(_237"+_36+"
";
-if(_38){
-this.outputElement.scrollTop=this.outputElement.scrollHeight;
-}
-},updateTags:function(){
-var _39=this.tagFilterElement.value;
-if(this.tagPattern==_39){
-return;
-}
-try{
-new RegExp(_39);
-}
-catch(e){
-return;
-}
-this.tagPattern=_39;
-Cookie.set("tagPattern",this.tagPattern);
-this.outputElement.innerHTML="";
-this.outputCount=0;
-for(var i=0;i" + message + "
"
+if (shouldScroll) {
+this.outputElement.scrollTop = this.outputElement.scrollHeight
+}
+},
+updateTags : function() {
+var pattern = this.tagFilterElement.value
+if (this.tagPattern == pattern) return
+try {
+new RegExp(pattern)
+}
+catch (e) {
+return
+}
+this.tagPattern = pattern
+Cookie.set('tagPattern', this.tagPattern)
+this.outputElement.innerHTML = ""
+this.outputCount = 0;
+for (var i = 0; i < Logger.logEntries.length; i++) {
+this.logUpdate(Logger.logEntries[i])
+}
+},
+repositionWindow : function() {
+var offset = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
+var pageHeight = self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
+this.logElement.style.top = (offset + pageHeight - Element.getHeight(this.logElement)) + "px"
+},
+logUpdate : function(logEntry) {
+if (logEntry.tag.search(new RegExp(this.tagPattern, 'igm')) == -1) return
+var style = ''
+if (logEntry.tag.search(/error/) != -1) style += 'color:red'
+else if (logEntry.tag.search(/warning/) != -1) style += 'color:orange'
+else if (logEntry.tag.search(/debug/) != -1) style += 'color:green'
+ else if (logEntry.tag.search(/info/) != -1) style += 'color:white'
+else style += 'color:yellow'
+this.output(logEntry.message, style)
+},
+clear : function(e) {
+this.outputElement.innerHTML = ""
+},
+handleInput : function(e) {
+if (e.keyCode == Event.KEY_RETURN ) {
+var command = this.inputElement.value
+switch(command) {
case "clear":
-Logger.clear();
-break;
+Logger.clear()
+break
default:
-var _46="";
-try{
-_46=eval(this.inputElement.value);
+var consoleOutput = ""
+try {
+consoleOutput = eval(this.inputElement.value)
}
-catch(e){
-Logger.error("Problem parsing input <"+_45+">",e);
-break;
+catch (e) {
+Logger.error("Problem parsing input <" + command + ">", e)
+break
}
-Logger.log(_46);
-break;
+Logger.log(consoleOutput)
+break
}
-if(this.inputElement.value!=""&&this.inputElement.value!=this.commandHistory[0]){
-this.commandHistory.unshift(this.inputElement.value);
+if (this.inputElement.value != "" && this.inputElement.value != this.commandHistory[0]) {
+this.commandHistory.unshift(this.inputElement.value)
}
-this.commandIndex=0;
-this.inputElement.value="";
-}else{
-if(e.keyCode==Event.KEY_UP&&this.commandHistory.length>0){
-this.inputElement.value=this.commandHistory[this.commandIndex];
-if(this.commandIndex";
+},
+show : function(objID) {
+this.d.getElementById(objID).style.display=this.hidden[objID]?"none":"block";
+this.hidden[objID]=this.hidden[objID]?0:1;
+},
+changeSpan : function(spanID) {
+if(this.d.getElementById(spanID).innerHTML.indexOf("+")>-1){
+this.d.getElementById(spanID).innerHTML="[-]";
+} else {
+this.d.getElementById(spanID).innerHTML="[+]";
+}
+},
+buildInspectionLevel : function()
+{
+var display = this.displaying;
+var list = display.split(".");
+var links = ["[object Window]"];
+var name = '';
+if(display.indexOf("[object ") >= 0) return links.join(".");
+for(var i = 0; i < list.length; i++)
+{
+name += (name.length ? "." : "") + list[i];
+links[i+1] = ""+list[i]+"";
+}
+return links.join(".");
+},
+buildTree : function() {
+mHTML = "
";
this.types.sort();
-var _68=0;
-for(i=0;i
Javascript Object Tree V2.0, more info.";
+cObj.innerHTML = "[esc] to close
Javascript Object Tree V2.0.";
window.scrollTo(0,0);
-},style:"#so_mContainer { position:absolute; top:5px; left:5px; background-color:#E3EBED; text-align:left; font:9pt verdana; width:85%; border:2px solid #000; padding:5px; z-index:1000; color:#000; } "+"#so_mContainer ul { padding-left:20px; } "+"#so_mContainer ul li { display:block; list-style-type:none; list-style-image:url(); line-height:2em; -moz-border-radius:.75em; font:10px verdana; padding:0; margin:2px; color:#000; } "+"#so_mContainer li:hover { background-color:#E3EBED; } "+"#so_mContainer ul li span { position:relative; width:15px; height:15px; margin-right:4px; } "+"#so_mContainer pre { background-color:#F9FAFB; border:1px solid #638DA1; height:auto; padding:5px; font:9px verdana; color:#000; } "+"#so_mContainer .topLevel { margin:0; padding:0; } "+"#so_mContainer .credits { float:left; width:200px; font:6.5pt verdana; color:#000; padding:2px; margin-left:5px; text-align:left; border-top:1px solid #000; margin-top:15px; width:75%; } "+"#so_mContainer .credits a { font:9px verdana; font-weight:bold; color:#004465; text-decoration:none; background-color:transparent; }"};
-function var_dump(obj){
+},
+style : "#so_mContainer { position:absolute; top:5px; left:5px; background-color:#E3EBED; text-align:left; font:9pt verdana; width:85%; border:2px solid #000; padding:5px; z-index:1000;color:#000; } " +
+"#so_mContainer ul { padding-left:20px; } " +
+"#so_mContainer ul li { display:block; list-style-type:none; list-style-image:url(); line-height:2em; -moz-border-radius:.75em; font:10px verdana; padding:0; margin:2px; color:#000; } " +
+"#so_mContainer li:hover { background-color:#E3EBED; } " +
+"#so_mContainer ul li span { position:relative; width:15px; height:15px; margin-right:4px; } " +
+"#so_mContainer pre { background-color:#F9FAFB; border:1px solid #638DA1; height:auto; padding:5px; font:9px verdana; color:#000; } " +
+"#so_mContainer .topLevel { margin:0; padding:0; } " +
+"#so_mContainer .credits { float:left; width:200px; font:6.5pt verdana; color:#000; padding:2px; margin-left:5px; text-align:left; border-top:1px solid #000; margin-top:15px; width:75%; } " +
+"#so_mContainer .credits a { font:9px verdana; font-weight:bold; color:#004465; text-decoration:none; background-color:transparent; }"
+}
+function var_dump(obj)
+{
Prado.Inspector.inspect(obj);
}
-var print_r=inspect;
-
+var print_r = inspect;
diff --git a/framework/Web/Javascripts/js/prado.js b/framework/Web/Javascripts/js/prado.js
index 794114d9..6737d4ce 100644
--- a/framework/Web/Javascripts/js/prado.js
+++ b/framework/Web/Javascripts/js/prado.js
@@ -1,2016 +1,2259 @@
-var Prototype={Version:"1.4.0",ScriptFragment:"(?:' + this.content + '
';
return $A(div.childNodes[0].childNodes[0].childNodes);
-}};
-var Insertion=new Object();
-Insertion.Before=Class.create();
-Insertion.Before.prototype=Object.extend(new Abstract.Insertion("beforeBegin"),{initializeRange:function(){
+}
+}
+var Insertion = new Object();
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+initializeRange: function() {
this.range.setStartBefore(this.element);
-},insertContent:function(_193){
-_193.each((function(_194){
-this.element.parentNode.insertBefore(_194,this.element);
+},
+insertContent: function(fragments) {
+fragments.each((function(fragment) {
+this.element.parentNode.insertBefore(fragment, this.element);
}).bind(this));
-}});
-Insertion.Top=Class.create();
-Insertion.Top.prototype=Object.extend(new Abstract.Insertion("afterBegin"),{initializeRange:function(){
+}
+});
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(true);
-},insertContent:function(_195){
-_195.reverse(false).each((function(_196){
-this.element.insertBefore(_196,this.element.firstChild);
+},
+insertContent: function(fragments) {
+fragments.reverse(false).each((function(fragment) {
+this.element.insertBefore(fragment, this.element.firstChild);
}).bind(this));
-}});
-Insertion.Bottom=Class.create();
-Insertion.Bottom.prototype=Object.extend(new Abstract.Insertion("beforeEnd"),{initializeRange:function(){
+}
+});
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(this.element);
-},insertContent:function(_197){
-_197.each((function(_198){
-this.element.appendChild(_198);
+},
+insertContent: function(fragments) {
+fragments.each((function(fragment) {
+this.element.appendChild(fragment);
}).bind(this));
-}});
-Insertion.After=Class.create();
-Insertion.After.prototype=Object.extend(new Abstract.Insertion("afterEnd"),{initializeRange:function(){
+}
+});
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+initializeRange: function() {
this.range.setStartAfter(this.element);
-},insertContent:function(_199){
-_199.each((function(_200){
-this.element.parentNode.insertBefore(_200,this.element.nextSibling);
+},
+insertContent: function(fragments) {
+fragments.each((function(fragment) {
+this.element.parentNode.insertBefore(fragment,
+this.element.nextSibling);
}).bind(this));
-}});
-Element.ClassNames=Class.create();
-Element.ClassNames.prototype={initialize:function(_201){
-this.element=$(_201);
-},_each:function(_202){
-this.element.className.split(/\s+/).select(function(name){
-return name.length>0;
-})._each(_202);
-},set:function(_204){
-this.element.className=_204;
-},add:function(_205){
-if(this.include(_205)){
-return;
-}
-this.set(this.toArray().concat(_205).join(" "));
-},remove:function(_206){
-if(!this.include(_206)){
-return;
-}
-this.set(this.select(function(_207){
-return _207!=_206;
-}).join(" "));
-},toString:function(){
-return this.toArray().join(" ");
-}};
-Object.extend(Element.ClassNames.prototype,Enumerable);
-Object.extend(Element,{condClassName:function(_208,_209,cond){
-(cond?Element.addClassName:Element.removeClassName)(_208,_209);
-}});
-var Field={clear:function(){
-for(var i=0;i
",first:"",pre:"",post:"
",last:""};
+return { header : "
", first : "", pre : "", post : "
", last : ""};
case "SingleParagraph":
-return {header:" ",first:"",pre:"",post:" ",last:"
"};
+return { header : " ", first : "", pre : "", post : " ", last : "
"};
case "BulletList":
default:
-return {header:"",first:"",pre:"
"};
-}
-},formatSummary:function(_61){
-var _62=this.formats(this.attr.displaymode);
-var _63=isdef(this.attr.headertext)?this.attr.headertext+_62.header:"";
-_63+=_62.first;
-for(var i=0;i<_61.length;i++){
-_63+=(_61[i].length>0)?_62.pre+_61[i]+_62.post:"";
-}
-_63+=_62.last;
-return _63;
-},formatMessageBox:function(_64){
-var _65=isdef(this.attr.headertext)?this.attr.headertext+"\n":"";
-for(var i=0;i<_64.length;i++){
-switch(this.attr.displaymode){
+return { header : "", first : "", pre : "
"};
+}
+},
+formatSummary : function(messages)
+{
+var format = this.formats(this.options.DisplayMode);
+var output = this.options.HeaderText ? this.options.HeaderText + format.header : "";
+output += format.first;
+messages.each(function(message)
+{
+output += message.length > 0 ? format.pre + message + format.post : "";
+});
+output += format.last;
+return output;
+},
+formatMessageBox : function(messages)
+{
+var output = this.options.HeaderText ? this.options.HeaderText + "\n" : "";
+for(var i = 0; i < messages.length; i++)
+{
+switch(this.options.DisplayMode)
+{
case "List":
-_65+=_64[i]+"\n";
+output += messages[i] + "\n";
break;
case "BulletList":
default:
-_65+=" - "+_64[i]+"\n";
+output += "- " + messages[i] + "\n";
break;
case "SingleParagraph":
-_65+=_64[i]+" ";
+output += messages[i] + " ";
break;
}
}
-return _65;
-},inActiveGroup:function(){
-var _66=Prado.Validation.groups;
-for(var i=0;i<_66.length;i++){
-if(_66[i].active&&_66[i].id==this.attr.group){
-return true;
-}
-}
-return false;
-}};
-Prado.Validation.ShowSummary=function(_67){
-var _68=Prado.Validation.summaries;
-for(var i=0;i<_68.length;i++){
-if(isdef(_67)){
-if(Prado.Validation.IsGroupValidation){
-_68[i].visible=_68[i].inActiveGroup();
-}else{
-_68[i].visible=undef(_68[i].attr.group);
-}
-_68[i].enabled=$(_68[i].attr.form)==_67;
-}
-_68[i].show(_67);
-}
-};
-Prado.Validation.OnSubmit=function(ev){
-if(typeof tinyMCE!="undefined"){
-tinyMCE.triggerSave();
-}
-if(!Prado.Validation.ActiveTarget){
-return true;
-}
-var _69=Prado.Validation.IsValid(Event.element(ev)||ev);
-if(Event.element(ev)&&!_69){
-Event.stop(ev);
+return output;
}
-Prado.Validation.ActiveTarget=null;
-return _69;
};
-Prado.Validation.OnLoad=function(){
-Event.observe(Prado.Validation.forms,"submit",Prado.Validation.OnSubmit);
-};
-Prado.Validation.ValidateValidatorGroup=function(_70){
-var _71=Prado.Validation.groups;
-var _72=null;
-for(var i=0;i<_71.length;i++){
-if(_71[i].id==_70){
-_72=_71[i];
-Prado.Validation.groups[i].active=true;
-Prado.Validation.CurrentTargetGroup=null;
-Prado.Validation.IsGroupValidation=true;
-}else{
-Prado.Validation.groups[i].active=false;
-}
-}
-if(_72){
-return Prado.Validation.IsValid(_72.target.form);
-}
-return true;
-};
-Prado.Validation.ValidateValidationGroup=function(_73){
-var _74=Prado.Validation.TargetGroups;
-for(var id in _74){
-if(_74[id]==_73){
-var _75=$(id);
-Prado.Validation.ActiveTarget=_75;
-Prado.Validation.CurrentTargetGroup=_73;
-Prado.Validation.IsGroupValidation=false;
-return Prado.Validation.IsValid(_75.form);
-}
-}
-return true;
-};
-Prado.Validation.ValidateNonGroup=function(_76){
-if(Prado.Validation){
-var _77=$(_76);
-_77=_77||document.forms[0];
-Prado.Validation.ActiveTarget=_77;
-Prado.Validation.CurrentTargetGroup=null;
-Prado.Validation.IsGroupValidation=false;
-return Prado.Validation.IsValid(_77);
+Prado.WebUI.TBaseValidator = Class.create();
+Prado.WebUI.TBaseValidator.prototype =
+{
+enabled : true,
+visible : false,
+isValid : true,
+options : {},
+_isObserving : false,
+group : null,
+initialize : function(options)
+{
+options.OnValidate = options.OnValidate || Prototype.emptyFunction;
+options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
+options.OnError = options.OnError || Prototype.emptyFunction;
+this.options = options;
+this.control = $(options.ControlToValidate);
+this.message = $(options.ID);
+this.group = options.ValidationGroup;
+Prado.Validation.addValidator(options.FormID, this);
+},
+getErrorMessage : function()
+{
+return this.options.ErrorMessage;
+},
+updateControl: function()
+{
+if(this.message)
+{
+if(this.options.Display == "Dynamic")
+this.isValid ? this.message.hide() : this.message.show();
+this.message.style.visibility = this.isValid ? "hidden" : "visible";
+}
+this.updateControlCssClass(this.control, this.isValid);
+if(this.options.FocusOnError && !this.isValid)
+Prado.Element.focus(this.options.FocusElementID);
+this.visible = true;
+},
+updateControlCssClass : function(control, valid)
+{
+var CssClass = this.options.ControlCssClass;
+if(typeof(CssClass) == "string" && CssClass.length > 0)
+{
+if(valid)
+control.removeClassName(CssClass);
+else
+control.addClassName(CssClass);
+}
+},
+hide : function()
+{
+this.isValid = true;
+this.updateControl();
+this.visible = false;
+},
+validate : function(manager)
+{
+if(this.enabled)
+this.isValid = this.evaluateIsValid(manager);
+this.options.OnValidate(this, manager);
+this.updateControl();
+if(this.isValid)
+this.options.OnSuccess(this, manager);
+else
+this.options.OnError(this, manager);
+this.observeChanges(manager);
+return this.isValid;
+},
+observeChanges : function(manager)
+{
+if(this.options.ObserveChanges != false && !this._isObserving)
+{
+var validator = this;
+Event.observe(this.control, 'change', function()
+{
+if(validator.visible)
+{
+validator.validate(manager);
+manager.updateSummary(validator.group);
}
-return true;
-};
-Event.OnLoad(Prado.Validation.OnLoad);
-Prado.Validation.TRequiredFieldValidator=function(){
-var _78=this.control.getAttribute("type");
-if(_78=="file"){
-return true;
-}else{
-var a=Prado.Validation.trim($F(this.control));
-var b=Prado.Validation.trim(this.attr.initialvalue);
-return (a!=b);
+});
+this._isObserving = true;
+}
+},
+trim : function(value)
+{
+return typeof(value) == "string" ? value.trim() : "";
+},
+convert : function(dataType, value)
+{
+if(typeof(value) == "undefined")
+value = $F(this.control);
+var string = new String(value);
+switch(dataType)
+{
+case "Integer":
+return string.toInteger();
+case "Double" :
+case "Float" :
+return string.toDouble(this.options.DecimalChar);
+case "Currency" :
+return string.toCurrency(this.options.GroupChar, this.options.Digits, this.options.DecimalChar);
+case "Date":
+var value = string.toDate(this.options.DateFormat);
+if(value && typeof(value.getTime) == "function")
+return value.getTime();
+else
+return null;
+case "String":
+return string.toString();
}
-};
-Prado.Validation.TRegularExpressionValidator=function(){
-var _79=Prado.Validation.trim($F(this.control));
-if(_79==""){
-return true;
+return value;
}
-var rx=new RegExp(this.attr.validationexpression);
-var _81=rx.exec(_79);
-return (_81!=null&&_79==_81[0]);
-};
-Prado.Validation.TEmailAddressValidator=Prado.Validation.TRegularExpressionValidator;
-Prado.Validation.TCustomValidator=function(){
-var _82=isNull(this.control)?null:$F(this.control);
-var _83=this.attr.clientvalidationfunction;
-eval("var validate = "+_83);
-return validate&&isFunction(validate)?validate(this,_82):true;
-};
-Prado.Validation.TRangeValidator=function(){
-var _84=Prado.Validation.trim($F(this.control));
-if(_84==""){
-return true;
}
-var _85=this.attr.minimumvalue;
-var _86=this.attr.maximumvalue;
-if(undef(_85)&&undef(_86)){
+Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+evaluateIsValid : function()
+{
+var inputType = this.control.getAttribute("type");
+if(inputType == 'file')
+{
return true;
}
-if(_85==""){
-_85=0;
+else
+{
+var a = this.trim($F(this.control));
+var b = this.trim(this.options.InitialValue);
+return(a != b);
}
-if(_86==""){
-_86=0;
}
-var _87=this.attr.type;
-if(undef(_87)){
-return (parseFloat(_84)>=parseFloat(_85))&&(parseFloat(_84)<=parseFloat(_86));
-}
-var min=this.convert(_87,_85);
-var max=this.convert(_87,_86);
-_84=this.convert(_87,_84);
-return _84>=min&&_84<=max;
-};
-Prado.Validation.TCompareValidator=function(){
-var _89=Prado.Validation.trim($F(this.control));
-if(_89.length==0){
+});
+Prado.WebUI.TCompareValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+_observingComparee : false,
+evaluateIsValid : function(manager)
+{
+var value = this.trim($F(this.control));
+if (value.length <= 0)
return true;
+var comparee = $(this.options.ControlToCompare);
+if(comparee)
+var compareTo = this.trim($F(comparee));
+else
+var compareTo = this.options.ValueToCompare || "";
+var isValid =this.compare(value, compareTo);
+if(comparee)
+{
+this.updateControlCssClass(comparee, isValid);
+this.observeComparee(comparee, manager);
+}
+return isValid;
+},
+observeComparee : function(comparee, manager)
+{
+if(this.options.ObserveChanges != false && !this._observingComparee)
+{
+var validator = this;
+Event.observe(comparee, "change", function()
+{
+if(validator.visible)
+{
+validator.validate(manager);
+manager.updateSummary(validator.group);
}
-var _90;
-var _91=$(this.attr.controlhookup);
-if(_91){
-_90=Prado.Validation.trim($F(_91));
-}else{
-_90=isString(this.attr.valuetocompare)?this.attr.valuetocompare:"";
-}
-var _92=Prado.Validation.TCompareValidator.compare;
-var _93=_92.bind(this)(_89,_90);
-if(_91){
-var _94=this.attr.controlcssclass;
-if(isString(_94)&&_94.length>0){
-Element.condClassName(_91,_94,!_93);
-}
-if(undef(this.observingComparee)){
-Event.observe(_91,"change",this.validate.bind(this));
-this.observingComparee=true;
-}
+});
+this._observingComparee = true;
}
-return _93;
-};
-Prado.Validation.TCompareValidator.compare=function(_95,_96){
-var op1,op2;
-if((op1=this.convert(this.attr.type,_95))==null){
+},
+compare : function(operand1, operand2)
+{
+var op1, op2;
+if((op1 = this.convert(this.options.DataType, operand1)) == null)
return false;
-}
-if(this.attr.operator=="DataTypeCheck"){
-return true;
-}
-if((op2=this.convert(this.attr.type,_96))==null){
+if ((op2 = this.convert(this.options.DataType, operand2)) == null)
return true;
-}
-switch(this.attr.operator){
+switch (this.options.Operator)
+{
case "NotEqual":
-return (op1!=op2);
+return (op1 != op2);
case "GreaterThan":
-return (op1>op2);
+return (op1 > op2);
case "GreaterThanEqual":
-return (op1>=op2);
+return (op1 >= op2);
case "LessThan":
-return (op1Prado.Validation.validate(formID, groupID)
+ * where formID is the HTML form ID, and the optional
+ * groupID if present will only validate the validators
+ * in a particular group.
+ */
+Object.extend(Prado.Validation,
+{
+ managers : {},
+
+ /**
+ * Validate the validators (those that DO NOT
+ * belong to a particular group) the form specified by the
+ * formID parameter. If groupID is specified
+ * then only validators belonging to that group will be validated.
+ * @param string ID of the form to validate
+ * @param string ID of the group to validate.
+ */
+ validate : function(formID, groupID)
+ {
+ if(this.managers[formID])
+ {
+ return this.managers[formID].validate(groupID);
+ }
+ else
+ {
+ throw new Error("Form '"+form+"' is not registered with Prado.Validation");
+ }
+ },
+
+ /**
+ * Check if the validators are valid for a particular form (and group).
+ * The validators states will not be changed.
+ * The validate function should be called first.
+ * @param string ID of the form to validate
+ * @param string ID of the group to validate.
+ */
+ isValid : function(formID, groupID)
+ {
+ if(this.managers[formID])
+ return this.managers[formID].isValid(groupID);
+ return true;
+ },
+
+ /**
+ * Add a new validator to a particular form.
+ * @param string the form that the validator belongs.
+ * @param object a validator
+ */
+ addValidator : function(formID, validator)
+ {
+ if(this.managers[formID])
+ this.managers[formID].addValidator(validator);
+ else
+ throw new Error("A validation manager for form '"+formID+"' needs to be created first.");
+ },
+
+ /**
+ * Add a new validation summary.
+ * @param string the form that the validation summary belongs.
+ * @param object a validation summary
+ */
+ addSummary : function(formID, validator)
+ {
+ if(this.managers[formID])
+ this.managers[formID].addSummary(validator);
+ else
+ throw new Error("A validation manager for form '"+formID+"' needs to be created first.");
+ }
+});
+
+/**
+ * Validation manager instances. Manages validators for a particular
+ * HTML form.
+ */
+Prado.Validation.prototype =
+{
+ validators : [], // list of validators
+ summaries : [], // validation summaries
+ groups : [], // validation groups
+ options : {},
+
+ /**
+ *
+ * options['FormID']* The ID of HTML form to manage.
+ *
+ */
+ initialize : function(options)
+ {
+ this.options = options;
+ Prado.Validation.managers[options.FormID] = this;
+ },
+
+ /**
+ * Validate the validators managed by this validation manager.
+ * @param string only validate validators belonging to a group (optional)
+ * @return boolean true if all validators are valid, false otherwise.
+ */
+ validate : function(group)
+ {
+ if(group)
+ return this._validateGroup(group);
+ else
+ return this._validateNonGroup();
+ },
+
+ /**
+ * Validate a particular group of validators.
+ * @param string ID of the form
+ * @return boolean false if group is not valid, true otherwise.
+ */
+ _validateGroup: function(groupID)
+ {
+ var valid = true;
+ var manager = this;
+ if(this.groups.include(groupID))
+ {
+ this.validators.each(function(validator)
+ {
+ if(validator.group == groupID)
+ valid = valid & validator.validate(manager);
+ else
+ validator.hide();
+ });
+ }
+ this.updateSummary(groupID, true);
+ return valid;
+ },
+
+ /**
+ * Validate validators that doesn't belong to any group.
+ * @return boolean false if not valid, true otherwise.
+ */
+ _validateNonGroup : function()
+ {
+ var valid = true;
+ var manager = this;
+ this.validators.each(function(validator)
+ {
+ if(!validator.group)
+ valid = valid & validator.validate(manager);
+ else
+ validator.hide();
+ });
+ this.updateSummary(null, true);
+ return valid;
+ },
+
+ /**
+ * Gets the state of all the validators, true if they are all valid.
+ * @return boolean true if the validators are valid.
+ */
+ isValid : function(group)
+ {
+ if(group)
+ return this._isValidGroup(group);
+ else
+ return this._isValidNonGroup();
+ },
+
+ /**
+ * @return boolean true if all validators not belonging to a group are valid.
+ */
+ _isValidNonGroup : function()
+ {
+ var valid = true;
+ this.validators.each(function(validator)
+ {
+ if(!validator.group)
+ valid = valid & validator.isValid;
+ });
+ return valid;
+ },
+
+ /**
+ * @return boolean true if all validators belonging to the group are valid.
+ */
+ _isValidGroup : function(groupID)
+ {
+ var valid = true;
+ if(this.groups.include(groupID))
+ {
+ this.validators.each(function(validator)
+ {
+ if(validator.group == groupID)
+ valid = valid & validator.isValid;
+ });
+ }
+ return valid;
+ },
+
+ /**
+ * Add a validator to this manager.
+ * @param Prado.WebUI.TBaseValidator a new validator
+ */
+ addValidator : function(validator)
+ {
+ this.validators.push(validator);
+ if(validator.group && !this.groups.include(validator.group))
+ this.groups.push(validator.group);
+ },
+
+ /**
+ * Add a validation summary.
+ * @param Prado.WebUI.TValidationSummary validation summary.
+ */
+ addSummary : function(summary)
+ {
+ this.summaries.push(summary);
+ },
+
+ /**
+ * Gets all validators that belong to a group or that the validator
+ * group is null and the validator validation was false.
+ * @return array list of validators with error.
+ */
+ getValidatorsWithError : function(group)
+ {
+ var validators = this.validators.findAll(function(validator)
+ {
+ var notValid = !validator.isValid;
+ var inGroup = group && validator.group == group;
+ var noGroup = validator.group == null;
+ return notValid && (inGroup || noGroup);
+ });
+ return validators;
+ },
+
+ /**
+ * Update the summary of a particular group.
+ * @param string validation group to update.
+ */
+ updateSummary : function(group, refresh)
+ {
+ var validators = this.getValidatorsWithError(group);
+ this.summaries.each(function(summary)
+ {
+ var inGroup = group && summary.group == group;
+ var noGroup = !group && !summary.group;
+ if(inGroup || noGroup)
+ summary.updateSummary(validators, refresh);
+ else
+ summary.hideSummary(true);
+ });
+ }
+};
+
+/**
+ * TValidationSummary displays a summary of validation errors inline on a Web page,
+ * in a message box, or both. By default, a validation summary will collect
+ * ErrorMessage of all failed validators on the page. If
+ * ValidationGroup is not empty, only those validators who belong
+ * to the group will show their error messages in the summary.
+ *
+ * The summary can be displayed as a list, as a bulleted list, or as a single
+ * paragraph based on the DisplayMode option.
+ * The messages shown can be prefixed with HeaderText.
+ *
+ * The summary can be displayed on the Web page and in a message box by setting
+ * the ShowSummary and ShowMessageBox
+ * options, respectively.
+ */
+Prado.WebUI.TValidationSummary = Class.create();
+Prado.WebUI.TValidationSummary.prototype =
+{
+ group : null,
+ options : {},
+ visible : false,
+ summary : null,
+
+ /**
+ *
+ * options['ID']* Validation summary ID, i.e., an HTML element ID
+ * options['FormID']* HTML form that this summary belongs.
+ * options['ShowMessageBox'] True to show the summary in an alert box.
+ * options['ShowSummary'] True to show the inline summary.
+ * options['HeaderText'] Summary header text
+ * options['DisplayMode'] Summary display style, 'BulletList', 'List', 'SingleParagraph'
+ * options['Refresh'] True to update the summary upon validator state change.
+ * options['ValidationGroup'] Validation summary group
+ * options['Display'] Display mode, 'None', 'Static', 'Dynamic'.
+ * options['ScrollToSummary'] True to scroll to the validation summary upon refresh.
+ *
+ */
+ initialize : function(options)
+ {
+ this.options = options;
+ this.group = options.ValidationGroup;
+ this.summary = $(options.ID);
+ this.visible = this.summary.style.visibility != "hidden"
+ this.visible = this.visible && this.summary.style.display != "none";
+ Prado.Validation.addSummary(options.FormID, this);
+ },
+
+ /**
+ * Update the validation summary to show the error message from
+ * validators that failed validation.
+ * @param array list of validators that failed validation.
+ * @param boolean update the summary;
+ */
+ updateSummary : function(validators, update)
+ {
+ if(validators.length <= 0)
+ return this.hideSummary(update);
+
+ var refresh = update || this.visible == false || this.options.Refresh != false;
+
+ if(this.options.ShowSummary != false && refresh)
+ {
+ this.displayHTMLMessages(this.getMessages(validators));
+ this.visible = true;
+ }
+
+ if(this.options.ScrollToSummary != false)
+ window.scrollTo(this.summary.offsetLeft-20, this.summary.offsetTop-20);
+
+ if(this.options.ShowMessageBox == true && refresh)
+ {
+ this.alertMessages(this.getMessages(validators));
+ this.visible = true;
+ }
+ },
+
+ /**
+ * Display the validator error messages as inline HTML.
+ */
+ displayHTMLMessages : function(messages)
+ {
+ this.summary.show();
+ this.summary.style.visibility = "visible";
+ while(this.summary.childNodes.length > 0)
+ this.summary.removeChild(this.summary.lastChild);
+ new Insertion.Bottom(this.summary, this.formatSummary(messages));
+ },
+
+ /**
+ * Display the validator error messages as an alert box.
+ */
+ alertMessages : function(messages)
+ {
+ var text = this.formatMessageBox(messages);
+ setTimeout(function(){ alert(text); },20);
+ },
+
+ /**
+ * @return array list of validator error messages.
+ */
+ getMessages : function(validators)
+ {
+ var messages = [];
+ validators.each(function(validator)
+ {
+ var message = validator.getErrorMessage();
+ if(typeof(message) == 'string' && message.length > 0)
+ messages.push(message);
+ })
+ return messages;
+ },
+
+ /**
+ * Hides the validation summary if options['Refresh'] is not false.
+ * @param boolean true to always hide the summary
+ */
+ hideSummary : function(refresh)
+ {
+ if(refresh || this.options.Refresh != false)
+ {
+ if(this.options.Display == "None" || this.options.Display == "Dynamic")
+ this.summary.hide();
+ this.summary.style.visibility="hidden";
+ this.visible = false;
+ }
+ },
+
+ /**
+ * Return the format parameters for the summary.
+ * @param string format type, "List", "SingleParagraph" or "BulletList"
+ * @type array formatting parameters
+ */
+ formats : function(type)
+ {
+ switch(type)
+ {
+ case "List":
+ return { header : "
", first : "", pre : "", post : "
", last : ""};
+ case "SingleParagraph":
+ return { header : " ", first : "", pre : "", post : " ", last : "
"};
+ case "BulletList":
+ default:
+ return { header : "", first : "", pre : "
"};
+ }
+ },
+
+ /**
+ * Format the message summary.
+ * @param array list of error messages.
+ * @type string formatted message
+ */
+ formatSummary : function(messages)
+ {
+ var format = this.formats(this.options.DisplayMode);
+ var output = this.options.HeaderText ? this.options.HeaderText + format.header : "";
+ output += format.first;
+ messages.each(function(message)
+ {
+ output += message.length > 0 ? format.pre + message + format.post : "";
+ });
+// for(var i = 0; i < messages.length; i++)
+ // output += (messages[i].length>0) ? format.pre + messages[i] + format.post : "";
+ output += format.last;
+ return output;
+ },
+ /**
+ * Format the message alert box.
+ * @param array a list of error messages.
+ * @type string format message for alert.
+ */
+ formatMessageBox : function(messages)
+ {
+ var output = this.options.HeaderText ? this.options.HeaderText + "\n" : "";
+ for(var i = 0; i < messages.length; i++)
+ {
+ switch(this.options.DisplayMode)
+ {
+ case "List":
+ output += messages[i] + "\n";
+ break;
+ case "BulletList":
+ default:
+ output += " - " + messages[i] + "\n";
+ break;
+ case "SingleParagraph":
+ output += messages[i] + " ";
+ break;
+ }
+ }
+ return output;
+ }
+};
+
+/**
+ * TBaseValidator serves as the base class for validator controls.
+ *
+ * Validation is performed when a postback control, such as a TButton,
+ * a TLinkButton or a TTextBox (under AutoPostBack mode) is submitting
+ * the page and its CausesValidation option is true.
+ * The input control to be validated is specified by ControlToValidate
+ * option.
+ */
+Prado.WebUI.TBaseValidator = Class.create();
+Prado.WebUI.TBaseValidator.prototype =
+{
+ enabled : true,
+ visible : false,
+ isValid : true,
+ options : {},
+ _isObserving : false,
+ group : null,
+
+ /**
+ *
+ * options['ID']* Validator ID, e.g. span with message
+ * options['FormID']* HTML form that the validator belongs
+ * options['ControlToValidate']*HTML form input to validate
+ * options['Display'] Display mode, 'None', 'Static', 'Dynamic'
+ * options['ErrorMessage'] Validation error message
+ * options['FocusOnError'] True to focus on validation error
+ * options['FocusElementID'] Element to focus on error
+ * options['ValidationGroup'] Validation group
+ * options['ControlCssClass'] Css class to use on the input upon error
+ * options['OnValidate'] Function to call immediately after validation
+ * options['OnSuccess'] Function to call upon after successful validation
+ * options['OnError'] Function to call upon after error in validation.
+ * options['ObserveChanges'] True to observe changes in input
+ *
+ */
+ initialize : function(options)
+ {
+ options.OnValidate = options.OnValidate || Prototype.emptyFunction;
+ options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
+ options.OnError = options.OnError || Prototype.emptyFunction;
+
+ this.options = options;
+ this.control = $(options.ControlToValidate);
+ this.message = $(options.ID);
+ this.group = options.ValidationGroup;
+
+ Prado.Validation.addValidator(options.FormID, this);
+ },
+
+ /**
+ * @return string validation error message.
+ */
+ getErrorMessage : function()
+ {
+ return this.options.ErrorMessage;
+ },
+
+ /**
+ * Update the validator span, input CSS class, and focus particular
+ * element. Updating the validator control will set the validator
+ * visible property to true.
+ */
+ updateControl: function()
+ {
+ if(this.message)
+ {
+ if(this.options.Display == "Dynamic")
+ this.isValid ? this.message.hide() : this.message.show();
+ this.message.style.visibility = this.isValid ? "hidden" : "visible";
+ }
+
+ this.updateControlCssClass(this.control, this.isValid);
+
+ if(this.options.FocusOnError && !this.isValid)
+ Prado.Element.focus(this.options.FocusElementID);
+
+ this.visible = true;
+ },
+
+ /**
+ * Add a css class to the input control if validator is invalid,
+ * removes the css class if valid.
+ * @param object html control element
+ * @param boolean true to remove the css class, false to add.
+ */
+ updateControlCssClass : function(control, valid)
+ {
+ var CssClass = this.options.ControlCssClass;
+ if(typeof(CssClass) == "string" && CssClass.length > 0)
+ {
+ if(valid)
+ control.removeClassName(CssClass);
+ else
+ control.addClassName(CssClass);
+ }
+ },
+
+ /**
+ * Hides the validator messages and remove any validation changes.
+ */
+ hide : function()
+ {
+ this.isValid = true;
+ this.updateControl();
+ this.visible = false;
+ },
+
+ /**
+ * Calls evaluateIsValid() function to set the value of isValid property.
+ * Triggers onValidate event and onSuccess or onError event.
+ * @param Validation manager
+ * @return boolean true if valid.
+ */
+ validate : function(manager)
+ {
+ if(this.enabled)
+ this.isValid = this.evaluateIsValid(manager);
+
+ this.options.OnValidate(this, manager);
+
+ this.updateControl();
+
+ if(this.isValid)
+ this.options.OnSuccess(this, manager);
+ else
+ this.options.OnError(this, manager);
+
+ this.observeChanges(manager);
+
+ return this.isValid;
+ },
+
+ /**
+ * Observe changes to the control input, re-validate upon change. If
+ * the validator is not visible, no updates are propagated.
+ */
+ observeChanges : function(manager)
+ {
+ if(this.options.ObserveChanges != false && !this._isObserving)
+ {
+ var validator = this;
+ Event.observe(this.control, 'change', function()
+ {
+ if(validator.visible)
+ {
+ validator.validate(manager);
+ manager.updateSummary(validator.group);
+ }
+ });
+ this._isObserving = true;
+ }
+ },
+
+ /**
+ * @return string trims the string value, empty string if value is not string.
+ */
+ trim : function(value)
+ {
+ return typeof(value) == "string" ? value.trim() : "";
+ },
+
+ /**
+ * Convert the value to a specific data type.
+ * @param {string} the data type, "Integer", "Double", "Currency", "Date" or "String"
+ * @param {string} the value to convert.
+ * @type {mixed|null} the converted data value.
+ */
+ convert : function(dataType, value)
+ {
+ if(typeof(value) == "undefined")
+ value = $F(this.control);
+ var string = new String(value);
+ switch(dataType)
+ {
+ case "Integer":
+ return string.toInteger();
+ case "Double" :
+ case "Float" :
+ return string.toDouble(this.options.DecimalChar);
+ case "Currency" :
+ return string.toCurrency(this.options.GroupChar, this.options.Digits, this.options.DecimalChar);
+ case "Date":
+ var value = string.toDate(this.options.DateFormat);
+ if(value && typeof(value.getTime) == "function")
+ return value.getTime();
+ else
+ return null;
+ case "String":
+ return string.toString();
+ }
+ return value;
+ }
+}
+
+
+/**
+ * TRequiredFieldValidator makes the associated input control a required field.
+ * The input control fails validation if its value does not change from
+ * the InitialValue option upon losing focus.
+ *
+ * options['InitialValue'] Validation fails if control input equals initial value.
+ *
+ */
+Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * @return boolean true if the input value is not empty nor equal to the initial value.
+ */
+ evaluateIsValid : function()
+ {
+ var inputType = this.control.getAttribute("type");
+ if(inputType == 'file')
+ {
+ return true;
+ }
+ else
+ {
+ var a = this.trim($F(this.control));
+ var b = this.trim(this.options.InitialValue);
+ return(a != b);
+ }
+ }
+});
+
+
+/**
+ * TCompareValidator compares the value entered by the user into an input
+ * control with the value entered into another input control or a constant value.
+ * To compare the associated input control with another input control,
+ * set the ControlToCompare option to the ID path
+ * of the control to compare with. To compare the associated input control with
+ * a constant value, specify the constant value to compare with by setting the
+ * ValueToCompare option.
+ *
+ * The DataType property is used to specify the data type
+ * of both comparison values. Both values are automatically converted to this data
+ * type before the comparison operation is performed. The following value types are supported:
+ * - Integer A 32-bit signed integer data type.
+ * - Float A double-precision floating point number data type.
+ * - Currency A decimal data type that can contain currency symbols.
+ * - Date A date data type. The format can be by the DateFormat option.
+ * - String A string data type.
+ *
+ * Use the Operator property to specify the type of comparison
+ * to perform. Valid operators include Equal, NotEqual, GreaterThan, GreaterThanEqual,
+ * LessThan and LessThanEqual.
+ *
+ * options['ControlToCompare']
+ * options['ValueToCompare']
+ * options['Operator']
+ * options['Type']
+ * options['DateFormat']
+ *
+ */
+Prado.WebUI.TCompareValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ _observingComparee : false,
+
+ /**
+ * Compares the input to another input or a given value.
+ */
+ evaluateIsValid : function(manager)
+ {
+ var value = this.trim($F(this.control));
+ if (value.length <= 0)
+ return true;
+
+ var comparee = $(this.options.ControlToCompare);
+
+ if(comparee)
+ var compareTo = this.trim($F(comparee));
+ else
+ var compareTo = this.options.ValueToCompare || "";
+
+ var isValid = this.compare(value, compareTo);
+
+ if(comparee)
+ {
+ this.updateControlCssClass(comparee, isValid);
+ this.observeComparee(comparee, manager);
+ }
+ return isValid;
+ },
+
+ /**
+ * Observe the comparee input element for changes.
+ * @param object HTML input element to observe
+ * @param object Validation manager.
+ */
+ observeComparee : function(comparee, manager)
+ {
+ if(this.options.ObserveChanges != false && !this._observingComparee)
+ {
+ var validator = this;
+ Event.observe(comparee, "change", function()
+ {
+ if(validator.visible)
+ {
+ validator.validate(manager);
+ manager.updateSummary(validator.group);
+ }
+ });
+ this._observingComparee = true;
+ }
+ },
+
+ /**
+ * Compares two values, their values are casted to type defined
+ * by DataType option. False is returned if the first
+ * operand converts to null. Returns true if the second operand
+ * converts to null. The comparision is done based on the
+ * Operator option.
+ */
+ compare : function(operand1, operand2)
+ {
+ var op1, op2;
+ if((op1 = this.convert(this.options.DataType, operand1)) == null)
+ return false;
+ if ((op2 = this.convert(this.options.DataType, operand2)) == null)
+ return true;
+ switch (this.options.Operator)
+ {
+ case "NotEqual":
+ return (op1 != op2);
+ case "GreaterThan":
+ return (op1 > op2);
+ case "GreaterThanEqual":
+ return (op1 >= op2);
+ case "LessThan":
+ return (op1 < op2);
+ case "LessThanEqual":
+ return (op1 <= op2);
+ default:
+ return (op1 == op2);
+ }
+ }
+});
+
+/**
+ * TCustomValidator performs user-defined client-side validation on an
+ * input component.
+ *
+ * To create a client-side validation function, add the client-side
+ * validation javascript function to the page template.
+ * The function should have the following signature:
+ *
+ *
+ *
+ * Use the ClientValidationFunction option
+ * to specify the name of the client-side validation script function associated
+ * with the TCustomValidator.
+ *
+ * options['ClientValidationFunction'] custom validation function.
+ *
+ */
+Prado.WebUI.TCustomValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Calls custom validation function.
+ */
+ evaluateIsValid : function(manager)
+ {
+ var value = $F(this.control);
+ var clientFunction = this.options.ClientValidationFunction;
+ if(typeof(clientFunction) == "string" && clientFunction.length > 0)
+ {
+ validate = clientFunction.toFunction();
+ return validate(this, value);
+ }
+ return true;
+ }
+});
+
+/**
+ * TRangeValidator tests whether an input value is within a specified range.
+ *
+ * TRangeValidator uses three key properties to perform its validation.
+ * The MinValue and MaxValue options specify the minimum
+ * and maximum values of the valid range. The DataType option is
+ * used to specify the data type of the value and the minimum and maximum range values.
+ * These values are converted to this data type before the validation
+ * operation is performed. The following value types are supported:
+ * - Integer A 32-bit signed integer data type.
+ * - Float A double-precision floating point number data type.
+ * - Currency A decimal data type that can contain currency symbols.
+ * - Date A date data type. The date format can be specified by
+ * setting DateFormat option, which must be recognizable
+ * by Date.SimpleParse javascript function.
+ * - String A string data type.
+ *
+ * options['MinValue'] Minimum range value
+ * options['MaxValue'] Maximum range value
+ * options['DataType'] Value data type
+ * options['DateFormat'] Date format for date data type.
+ *
+ */
+Prado.WebUI.TRangeValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Compares the input value with a minimum and/or maximum value.
+ * Returns true if the value is empty, returns false if conversion fails.
+ */
+ evaluateIsValid : function(manager)
+ {
+ var value = this.trim($F(this.control));
+ if(value.length <= 0)
+ return true;
+ if(typeof(this.options.DataType) == "undefined")
+ this.options.DataType = "String";
+
+ var min = this.convert(this.options.DataType, this.options.MinValue || null);
+ var max = this.convert(this.options.DataType, this.options.MaxValue || null);
+ value = this.convert(this.options.DataType, value);
+
+ Logger.warn(min+" <= "+value+" <= "+max);
+
+ if(value == null)
+ return false;
+
+ var valid = true;
+
+ if(min != null)
+ valid = valid && value >= min;
+ if(max != null)
+ valid = valid && value <= max;
+ return valid;
+ }
+});
+
+/**
+ * TRegularExpressionValidator validates whether the value of an associated
+ * input component matches the pattern specified by a regular expression.
+ *
+ * options['ValidationExpression'] regular expression to match against.
+ *
+ */
+Prado.WebUI.TRegularExpressionValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Compare the control input against a regular expression.
+ */
+ evaluateIsValid : function(master)
+ {
+ var value = this.trim($F(this.control));
+ if (value.length <= 0)
+ return true;
+
+ var rx = new RegExp(this.options.ValidationExpression);
+ var matches = rx.exec(value);
+ return (matches != null && value == matches[0]);
+ }
+});
+
+/**
+ * TEmailAddressValidator validates whether the value of an associated
+ * input component is a valid email address.
+ */
+Prado.WebUI.TEmailAddressValidator = Prado.WebUI.TRegularExpressionValidator;
+
+
diff --git a/framework/Web/Javascripts/prototype/ajax.js b/framework/Web/Javascripts/prototype/ajax.js
index e3d442a4..7ec7716c 100644
--- a/framework/Web/Javascripts/prototype/ajax.js
+++ b/framework/Web/Javascripts/prototype/ajax.js
@@ -1,9 +1,9 @@
var Ajax = {
getTransport: function() {
return Try.these(
+ function() {return new XMLHttpRequest()},
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
- function() {return new ActiveXObject('Microsoft.XMLHTTP')},
- function() {return new XMLHttpRequest()}
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
) || false;
},
@@ -55,6 +55,7 @@ Ajax.Base.prototype = {
this.options = {
method: 'post',
asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
parameters: ''
}
Object.extend(this.options, options || {});
@@ -114,11 +115,11 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
setRequestHeaders: function() {
var requestHeaders =
['X-Requested-With', 'XMLHttpRequest',
- 'X-Prototype-Version', Prototype.Version];
+ 'X-Prototype-Version', Prototype.Version,
+ 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
if (this.options.method == 'post') {
- requestHeaders.push('Content-type',
- 'application/x-www-form-urlencoded');
+ requestHeaders.push('Content-type', this.options.contentType);
/* Force "Connection: close" for Mozilla browsers to work around
* a bug where XMLHttpReqeuest sends an incorrect Content-length
@@ -149,7 +150,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
evalJSON: function() {
try {
- return eval(this.header('X-JSON'));
+ return eval('(' + this.header('X-JSON') + ')');
} catch (e) {}
},
diff --git a/framework/Web/Javascripts/prototype/array.js b/framework/Web/Javascripts/prototype/array.js
index 51ad864b..02731141 100644
--- a/framework/Web/Javascripts/prototype/array.js
+++ b/framework/Web/Javascripts/prototype/array.js
@@ -12,7 +12,8 @@ var $A = Array.from = function(iterable) {
Object.extend(Array.prototype, Enumerable);
-//Array.prototype._reverse = Array.prototype.reverse;
+if (!Array.prototype._reverse)
+ Array.prototype._reverse = Array.prototype.reverse;
Object.extend(Array.prototype, {
_each: function(iterator) {
@@ -41,7 +42,7 @@ Object.extend(Array.prototype, {
flatten: function() {
return this.inject([], function(array, value) {
- return array.concat(value.constructor == Array ?
+ return array.concat(value && value.constructor == Array ?
value.flatten() : [value]);
});
},
@@ -58,20 +59,11 @@ Object.extend(Array.prototype, {
if (this[i] == object) return i;
return -1;
},
-
-/*
+
reverse: function(inline) {
return (inline !== false ? this : this.toArray())._reverse();
},
-*/
- shift: function() {
- var result = this[0];
- for (var i = 0; i < this.length - 1; i++)
- this[i] = this[i + 1];
- this.length--;
- return result;
- },
-
+
inspect: function() {
return '[' + this.map(Object.inspect).join(', ') + ']';
}
diff --git a/framework/Web/Javascripts/prototype/base.js b/framework/Web/Javascripts/prototype/base.js
index 8d46d0ef..41b1d904 100644
--- a/framework/Web/Javascripts/prototype/base.js
+++ b/framework/Web/Javascripts/prototype/base.js
@@ -9,7 +9,7 @@ var Class = {
var Abstract = new Object();
Object.extend = function(destination, source) {
- for (property in source) {
+ for (var property in source) {
destination[property] = source[property];
}
return destination;
@@ -100,22 +100,3 @@ PeriodicalExecuter.prototype = {
}
}
}
-
-/*--------------------------------------------------------------------------*/
-
-function $() {
- var elements = new Array();
-
- for (var i = 0; i < arguments.length; i++) {
- var element = arguments[i];
- if (typeof element == 'string')
- element = document.getElementById(element);
-
- if (arguments.length == 1)
- return element;
-
- elements.push(element);
- }
-
- return elements;
-}
diff --git a/framework/Web/Javascripts/prototype/dom.js b/framework/Web/Javascripts/prototype/dom.js
index ade0451b..2d7438d5 100644
--- a/framework/Web/Javascripts/prototype/dom.js
+++ b/framework/Web/Javascripts/prototype/dom.js
@@ -1,19 +1,54 @@
+function $() {
+ var results = [], element;
+ for (var i = 0; i < arguments.length; i++) {
+ element = arguments[i];
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+ results.push(Element.extend(element));
+ }
+ return results.length < 2 ? results[0] : results;
+}
+
document.getElementsByClassName = function(className, parentElement) {
var children = ($(parentElement) || document.body).getElementsByTagName('*');
return $A(children).inject([], function(elements, child) {
if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
- elements.push(child);
+ elements.push(Element.extend(child));
return elements;
});
}
/*--------------------------------------------------------------------------*/
-if (!window.Element) {
+if (!window.Element)
var Element = new Object();
+
+Element.extend = function(element) {
+ if (!element) return;
+ if (_nativeExtensions) return element;
+
+ if (!element._extended && element.tagName && element != window) {
+ var methods = Element.Methods, cache = Element.extend.cache;
+ for (property in methods) {
+ var value = methods[property];
+ if (typeof value == 'function')
+ element[property] = cache.findOrStore(value);
+ }
+ }
+
+ element._extended = true;
+ return element;
}
-Object.extend(Element, {
+Element.extend.cache = {
+ findOrStore: function(value) {
+ return this[value] = this[value] || function() {
+ return value.apply(null, [this].concat($A(arguments)));
+ }
+ }
+}
+
+Element.Methods = {
visible: function(element) {
return $(element).style.display != 'none';
},
@@ -49,6 +84,19 @@ Object.extend(Element, {
setTimeout(function() {html.evalScripts()}, 10);
},
+ replace: function(element, html) {
+ element = $(element);
+ if (element.outerHTML) {
+ element.outerHTML = html.stripScripts();
+ } else {
+ var range = element.ownerDocument.createRange();
+ range.selectNodeContents(element);
+ element.parentNode.replaceChild(
+ range.createContextualFragment(html.stripScripts()), element);
+ }
+ setTimeout(function() {html.evalScripts()}, 10);
+ },
+
getHeight: function(element) {
element = $(element);
return element.offsetHeight;
@@ -87,6 +135,13 @@ Object.extend(Element, {
return $(element).innerHTML.match(/^\s*$/);
},
+ childOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ while (element = element.parentNode)
+ if (element == ancestor) return true;
+ return false;
+ },
+
scrollTo: function(element) {
element = $(element);
var x = element.x ? element.x : element.offsetLeft,
@@ -114,7 +169,7 @@ Object.extend(Element, {
setStyle: function(element, style) {
element = $(element);
- for (name in style)
+ for (var name in style)
element.style[name.camelize()] = style[name];
},
@@ -180,7 +235,32 @@ Object.extend(Element, {
element.style.overflow = element._overflow;
element._overflow = undefined;
}
-});
+}
+
+Object.extend(Element, Element.Methods);
+
+var _nativeExtensions = false;
+
+if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ var HTMLElement = {}
+ HTMLElement.prototype = document.createElement('div').__proto__;
+}
+
+Element.addMethods = function(methods) {
+ Object.extend(Element.Methods, methods || {});
+
+ if(typeof HTMLElement != 'undefined') {
+ var methods = Element.Methods, cache = Element.extend.cache;
+ for (property in methods) {
+ var value = methods[property];
+ if (typeof value == 'function')
+ HTMLElement.prototype[property] = cache.findOrStore(value);
+ }
+ _nativeExtensions = true;
+ }
+}
+
+Element.addMethods();
var Toggle = new Object();
Toggle.display = Element.toggle;
@@ -200,7 +280,8 @@ Abstract.Insertion.prototype = {
try {
this.element.insertAdjacentHTML(this.adjacency, this.content);
} catch (e) {
- if (this.element.tagName.toLowerCase() == 'tbody') {
+ var tagName = this.element.tagName.toLowerCase();
+ if (tagName == 'tbody' || tagName == 'tr') {
this.insertContent(this.contentFromAnonymousTable());
} else {
throw e;
diff --git a/framework/Web/Javascripts/prototype/enumerable.js b/framework/Web/Javascripts/prototype/enumerable.js
index 79cb8b3f..c3535b81 100644
--- a/framework/Web/Javascripts/prototype/enumerable.js
+++ b/framework/Web/Javascripts/prototype/enumerable.js
@@ -102,7 +102,7 @@ var Enumerable = {
var result;
this.each(function(value, index) {
value = (iterator || Prototype.K)(value, index);
- if (value >= (result || value))
+ if (result == undefined || value >= result)
result = value;
});
return result;
@@ -112,7 +112,7 @@ var Enumerable = {
var result;
this.each(function(value, index) {
value = (iterator || Prototype.K)(value, index);
- if (value <= (result || value))
+ if (result == undefined || value < result)
result = value;
});
return result;
@@ -164,8 +164,7 @@ var Enumerable = {
var collections = [this].concat(args).map($A);
return this.map(function(value, index) {
- iterator(value = collections.pluck(index));
- return value;
+ return iterator(collections.pluck(index));
});
},
diff --git a/framework/Web/Javascripts/prototype/event.js b/framework/Web/Javascripts/prototype/event.js
index 591b8d93..51b9010e 100644
--- a/framework/Web/Javascripts/prototype/event.js
+++ b/framework/Web/Javascripts/prototype/event.js
@@ -104,4 +104,5 @@ Object.extend(Event, {
});
/* prevent memory leaks in IE */
-Event.observe(window, 'unload', Event.unloadCache, false);
+if (navigator.appVersion.match(/\bMSIE\b/))
+ Event.observe(window, 'unload', Event.unloadCache, false);
diff --git a/framework/Web/Javascripts/prototype/form.js b/framework/Web/Javascripts/prototype/form.js
index 6d1b31ff..590f7f9f 100644
--- a/framework/Web/Javascripts/prototype/form.js
+++ b/framework/Web/Javascripts/prototype/form.js
@@ -46,7 +46,7 @@ var Form = {
form = $(form);
var elements = new Array();
- for (tagName in Form.Element.Serializers) {
+ for (var tagName in Form.Element.Serializers) {
var tagElements = form.getElementsByTagName(tagName);
for (var j = 0; j < tagElements.length; j++)
elements.push(tagElements[j]);
@@ -168,23 +168,17 @@ Form.Element.Serializers = {
var value = '', opt, index = element.selectedIndex;
if (index >= 0) {
opt = element.options[index];
- value = opt.value;
- if (!value && !('value' in opt))
- value = opt.text;
+ value = opt.value || opt.text;
}
return [element.name, value];
},
selectMany: function(element) {
- var value = new Array();
+ var value = [];
for (var i = 0; i < element.length; i++) {
var opt = element.options[i];
- if (opt.selected) {
- var optValue = opt.value;
- if (!optValue && !('value' in opt))
- optValue = opt.text;
- value.push(optValue);
- }
+ if (opt.selected)
+ value.push(opt.value || opt.text);
}
return [element.name, value];
}
diff --git a/framework/Web/Javascripts/prototype/hash.js b/framework/Web/Javascripts/prototype/hash.js
index a6da11c8..7e8c6f5d 100644
--- a/framework/Web/Javascripts/prototype/hash.js
+++ b/framework/Web/Javascripts/prototype/hash.js
@@ -1,6 +1,6 @@
var Hash = {
_each: function(iterator) {
- for (key in this) {
+ for (var key in this) {
var value = this[key];
if (typeof value == 'function') continue;
diff --git a/framework/Web/Javascripts/prototype/prototype.js b/framework/Web/Javascripts/prototype/prototype.js
index 6ae99602..16701d70 100644
--- a/framework/Web/Javascripts/prototype/prototype.js
+++ b/framework/Web/Javascripts/prototype/prototype.js
@@ -1,19 +1,24 @@
-/* Prototype JavaScript framework, version 1.4.0
- * (c) 2005 Sam Stephenson