From ca47a8c7fd5eb9f34ac00a2f1a843859d6123dd8 Mon Sep 17 00:00:00 2001 From: wei <> Date: Mon, 16 Jan 2006 02:43:30 +0000 Subject: --- .gitattributes | 23 +- framework/Web/Javascripts/base/ajax.js | 425 ------------- framework/Web/Javascripts/base/controls.js | 194 ------ framework/Web/Javascripts/base/date.js | 147 ----- framework/Web/Javascripts/base/datepicker.js | 656 -------------------- framework/Web/Javascripts/base/effects.js | 22 - framework/Web/Javascripts/base/focus.js | 99 --- framework/Web/Javascripts/base/json.js | 340 ---------- framework/Web/Javascripts/base/postback.js | 66 -- framework/Web/Javascripts/base/prado.js | 2 - framework/Web/Javascripts/base/rico.js | 175 ------ framework/Web/Javascripts/base/scroll.js | 0 framework/Web/Javascripts/base/util.js | 92 --- framework/Web/Javascripts/base/validation.js | 751 ----------------------- framework/Web/Javascripts/base/validators.js | 225 ------- framework/Web/Javascripts/extended/array.js | 465 -------------- framework/Web/Javascripts/extended/base.js | 12 +- framework/Web/Javascripts/extended/event.js | 23 +- framework/Web/Javascripts/extended/functional.js | 171 ------ framework/Web/Javascripts/extended/util.js | 95 +++ framework/Web/Javascripts/extra/tp_template.js | 315 ---------- framework/Web/Javascripts/prado/ajax.js | 425 +++++++++++++ framework/Web/Javascripts/prado/controls.js | 167 +++++ framework/Web/Javascripts/prado/datepicker.js | 656 ++++++++++++++++++++ framework/Web/Javascripts/prado/prado.js | 51 ++ framework/Web/Javascripts/prado/validation.js | 751 +++++++++++++++++++++++ framework/Web/Javascripts/prado/validators.js | 225 +++++++ 27 files changed, 2409 insertions(+), 4164 deletions(-) delete mode 100644 framework/Web/Javascripts/base/ajax.js delete mode 100644 framework/Web/Javascripts/base/controls.js delete mode 100644 framework/Web/Javascripts/base/date.js delete mode 100644 framework/Web/Javascripts/base/datepicker.js delete mode 100644 framework/Web/Javascripts/base/effects.js delete mode 100644 framework/Web/Javascripts/base/focus.js delete mode 100644 framework/Web/Javascripts/base/json.js delete mode 100644 framework/Web/Javascripts/base/postback.js delete mode 100644 framework/Web/Javascripts/base/prado.js delete mode 100644 framework/Web/Javascripts/base/rico.js delete mode 100644 framework/Web/Javascripts/base/scroll.js delete mode 100644 framework/Web/Javascripts/base/util.js delete mode 100644 framework/Web/Javascripts/base/validation.js delete mode 100644 framework/Web/Javascripts/base/validators.js delete mode 100644 framework/Web/Javascripts/extended/array.js delete mode 100644 framework/Web/Javascripts/extended/functional.js delete mode 100644 framework/Web/Javascripts/extra/tp_template.js create mode 100644 framework/Web/Javascripts/prado/ajax.js create mode 100644 framework/Web/Javascripts/prado/controls.js create mode 100644 framework/Web/Javascripts/prado/datepicker.js create mode 100644 framework/Web/Javascripts/prado/prado.js create mode 100644 framework/Web/Javascripts/prado/validation.js create mode 100644 framework/Web/Javascripts/prado/validators.js diff --git a/.gitattributes b/.gitattributes index ae96c4a9..1ceba79a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -441,20 +441,6 @@ framework/Security/TUserManager.php -text framework/TApplication.php -text framework/TComponent.php -text framework/TODO.txt -text -framework/Web/Javascripts/base/ajax.js -text -framework/Web/Javascripts/base/controls.js -text -framework/Web/Javascripts/base/date.js -text -framework/Web/Javascripts/base/datepicker.js -text -framework/Web/Javascripts/base/effects.js -text -framework/Web/Javascripts/base/focus.js -text -framework/Web/Javascripts/base/json.js -text -framework/Web/Javascripts/base/postback.js -text -framework/Web/Javascripts/base/prado.js -text -framework/Web/Javascripts/base/rico.js -text -framework/Web/Javascripts/base/scroll.js -text -framework/Web/Javascripts/base/util.js -text -framework/Web/Javascripts/base/validation.js -text -framework/Web/Javascripts/base/validators.js -text framework/Web/Javascripts/effects/CHANGELOG -text framework/Web/Javascripts/effects/MIT-LICENSE -text framework/Web/Javascripts/effects/README -text @@ -465,23 +451,26 @@ framework/Web/Javascripts/effects/effects.js -text framework/Web/Javascripts/effects/rico.js -text framework/Web/Javascripts/effects/slider.js -text framework/Web/Javascripts/effects/util.js -text -framework/Web/Javascripts/extended/array.js -text framework/Web/Javascripts/extended/base.js -text framework/Web/Javascripts/extended/dom.js -text framework/Web/Javascripts/extended/event.js -text -framework/Web/Javascripts/extended/functional.js -text framework/Web/Javascripts/extended/string.js -text framework/Web/Javascripts/extended/util.js -text framework/Web/Javascripts/extra/behaviour.js -text framework/Web/Javascripts/extra/getElementsBySelector.js -text framework/Web/Javascripts/extra/logger.js -text -framework/Web/Javascripts/extra/tp_template.js -text framework/Web/Javascripts/js/ajax.js -text framework/Web/Javascripts/js/base.js -text framework/Web/Javascripts/js/clientscripts.php -text framework/Web/Javascripts/js/dom.js -text framework/Web/Javascripts/js/logger.js -text framework/Web/Javascripts/js/validator.js -text +framework/Web/Javascripts/prado/ajax.js -text +framework/Web/Javascripts/prado/controls.js -text +framework/Web/Javascripts/prado/datepicker.js -text +framework/Web/Javascripts/prado/prado.js -text +framework/Web/Javascripts/prado/validation.js -text +framework/Web/Javascripts/prado/validators.js -text framework/Web/Javascripts/prototype/AUTHORS -text framework/Web/Javascripts/prototype/LICENSE -text framework/Web/Javascripts/prototype/README -text diff --git a/framework/Web/Javascripts/base/ajax.js b/framework/Web/Javascripts/base/ajax.js deleted file mode 100644 index 06c3d741..00000000 --- a/framework/Web/Javascripts/base/ajax.js +++ /dev/null @@ -1,425 +0,0 @@ -/** - * Prado AJAX service. The default service provider is JPSpan. - */ -Prado.AJAX = { Service : 'Prototype' }; - -/** - * Parse and execute javascript embedded in html. - */ -Prado.AJAX.EvalScript = function(output) -{ - - var match = new RegExp(Ajax.Updater.ScriptFragment, 'img'); - var scripts = output.match(match); - if (scripts) - { - match = new RegExp(Ajax.Updater.ScriptFragment, 'im'); - setTimeout((function() - { - for (var i = 0; i < scripts.length; i++) - eval(scripts[i].match(match)[1]); - }).bind(this), 50); - } -} - - -/** - * AJAX service request using Prototype's AJAX request class. - */ -Prado.AJAX.Request = Class.create(); -Prado.AJAX.Request.prototype = Object.extend(Ajax.Request.prototype, -{ - /** - * Evaluate the respond JSON data, override parent implementing. - * If default eval fails, try parsing the JSON data (slower). - */ - evalJSON: function() - { - try - { - var json = this.transport.getResponseHeader('X-JSON'), object; - object = eval(json); - return object; - } - catch (e) - { - if(isString(json)) - { - return Prado.AJAX.JSON.parse(json); - } - } - }, - - respondToReadyState: function(readyState) { - var event = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); - - - if(event == 'Complete' && transport.status) - Ajax.Responders.dispatch('on' + transport.status, this, transport, json); - - (this.options['on' + event] || Prototype.emptyFunction)(transport, json); - Ajax.Responders.dispatch('on' + event, this, transport, json); - - if (event == 'Complete') - (this.options['on' + this.transport.status] - || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(transport, json); - - - /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ - if (event == 'Complete') - this.transport.onreadystatechange = Prototype.emptyFunction; - } - -}); - -Prado.AJAX.Error = function(e, code) -{ - e.name = 'Prado.AJAX.Error'; - e.code = code; - return e; -} - -/** - * Post data builder, serialize the data using JSON. - */ -Prado.AJAX.RequestBuilder = Class.create(); -Prado.AJAX.RequestBuilder.prototype = -{ - initialize : function() - { - this.body = ''; - this.data = []; - }, - encode : function(data) - { - return Prado.AJAX.JSON.stringify(data); - }, - build : function(data) - { - var sep = ''; - for ( var argName in data) - { - if(isFunction(data[argName])) continue; - try - { - this.body += sep + argName + '='; - this.body += encodeURIComponent(this.encode(data[argName])); - } catch (e) { - throw Prado.AJAX.Error(e, 1006); - } - sep = '&'; - } - }, - - getAll : function() - { - this.build(this.data); - return this.body; - } -} - - -Prado.AJAX.RemoteObject = function(){}; - -/** - * AJAX service request for Prado RemoteObjects - */ -Prado.AJAX.RemoteObject.Request = Class.create(); -Prado.AJAX.RemoteObject.Request.prototype = Object.extend(Prado.AJAX.Request.prototype, -{ - /** - * Initialize the RemoteObject Request, overrides parent - * implementation by delaying the request to invokeRemoteObject. - */ - initialize : function(options) - { - this.transport = Ajax.getTransport(); - this.setOptions(options); - this.post = new Prado.AJAX.RequestBuilder(); - }, - - /** - * Call the remote object, - * @param string the remote server url - * @param array additional arguments - */ - invokeRemoteObject : function(url, args) - { - this.initParameters(args); - this.options.postBody = this.post.getAll(); - this.request(url); - }, - - /** - * Set the additional arguments as post data with key '__parameters' - */ - initParameters : function(args) - { - this.post.data['__parameters'] = []; - for(var i = 0; i - * var TestObject1 = Class.create(); - * TestObject1.prototype = Object.extend(new Prado.AJAX.RemoteObject(), - * { - * initialize : function(handlers, options) - * { - * this.__serverurl = 'http://127.0.0.1/.....'; - * this.baseInitialize(handlers, options); - * } - * - * method1 : function() - * { - * return this.__call(this.__serverurl, 'method1', arguments); - * } - * }); - * - * And client usage, - * - * var test1 = new TestObject1(); //create new remote object - * test1.method1(); //call the method, no onComplete hook - * - * var onComplete = { method1 : function(result){ alert(result) } }; - * //create new remote object with onComplete callback - * var test2 = new TestObject1(onComplete); - * test2.method1(); //call it, on success, onComplete's method1 is called. - * - */ -Prado.AJAX.RemoteObject.prototype = -{ - baseInitialize : function(handlers, options) - { - this.__handlers = handlers || {}; - this.__service = new Prado.AJAX.RemoteObject.Request(options); - }, - - __call : function(url, method, args) - { - this.__service.options.onSuccess = this.__onSuccess.bind(this); - this.__callback = method; - return this.__service.invokeRemoteObject(url+"/"+method, args); - }, - - __onSuccess : function(transport, json) - { - if(this.__handlers[this.__callback]) - this.__handlers[this.__callback](json, transport.responseText); - } -}; - -/** - * Respond to Prado AJAX request exceptions. - */ -Prado.AJAX.Exception = -{ - /** - * Server returns 505 exception. Just log it. - */ - "on505" : function(request, transport, e) - { - var msg = 'HTTP '+transport.status+" with response"; - Logger.error(msg, transport.responseText); - Logger.exception(e); - }, - - onComplete : function(request, transport, e) - { - if(transport.status != 505) - { - var msg = 'HTTP '+transport.status+" with response : \n"; - msg += transport.responseText + "\n"; - msg += "Data : \n"+inspect(e); - Logger.warn(msg); - } - }, - - format : function(e) - { - var msg = e.type + " with message \""+e.message+"\""; - msg += " in "+e.file+"("+e.line+")\n"; - msg += "Stack trace:\n"; - var trace = e.trace; - for(var i = 0; i"+trace[i]["function"]+"()"+"\n"; - } - return msg; - }, - - logException : function(e) - { - var msg = Prado.AJAX.Exception.format(e); - Logger.error("Server Error "+e.code, msg); - } -} - -//Add HTTP exception respones when logger is enabled. -Event.OnLoad(function() -{ - if(typeof Logger != "undefined") - { - Logger.exception = Prado.AJAX.Exception.logException; - Ajax.Responders.register(Prado.AJAX.Exception); - } -}); - -/** - * Prado Callback service that provides component intergration, - * viewstate (read only), and automatic form data serialization. - * Usage: new Prado.AJAX.Callback('MyPage.MyComponentID.raiseCallbackEvent', options) - * These classes should be called by the components developers. - * For inline callback service, use Prado.Callback(callbackID, params). - */ -Prado.AJAX.Callback = Class.create(); -Prado.AJAX.Callback.prototype = Object.extend(new Prado.AJAX.RemoteObject(), -{ - - /** - * Create and request a new Prado callback service. - * @param string|element the callback ID, must be of the form, ClassName.ComponentID.MethodName - * @param list options with list key onCallbackReturn, and more. - * - */ - initialize : function(ID, options) - { - if(!isString(ID) && typeof(ID.id) != "undefined") - ID = ID.id; - if(!isString(ID)) - throw new Error('A Control ID must be specified'); - this.baseInitialize(this, options); - this.options = options || []; - this.__service.post.data['__ID'] = ID; - this.requestCallback(); - }, - - /** - * Get form data for components that implements IPostBackHandler. - */ - collectPostData : function() - { - var IDs = Prado.AJAX.Callback.IDs; - this.__service.post.data['__data'] = {}; - for(var i = 0; i -1) - this.__service.post.data['__data'][id] = - this.collectArrayPostData(id); - else if(isObject($(id))) - this.__service.post.data['__data'][id] = $F(id); - } - }, - - collectArrayPostData : function(name) - { - var elements = document.getElementsByName(name); - var data = []; - $A(elements).each(function(el) - { - if($F(el)) data.push($F(el)); - }); - return data; - }, - - /** - * Prepares and calls the AJAX request. - * Collects the data from components that implements IPostBackHandler - * and the viewstate as part of the request payload. - */ - requestCallback : function() - { - this.collectPostData(); - if(Prado.AJAX.Validate(this.options)) - return this.__call(Prado.AJAX.Callback.Server, 'handleCallback', this.options.params); - }, - - /** - * On callback request return, call the onSuccess function. - */ - handleCallback : function(result, output) - { - if(typeof(result) != "undefined" && !isNull(result)) - { - this.options.onSuccess(result['data'], output); - if(result['actions']) - result.actions.each(Prado.AJAX.Callback.Action.__run); - } - } -}); - -/** - * Prase and evaluate Callback clien-side actions. - */ -Prado.AJAX.Callback.Action = -{ - __run : function(command) - { - for(var name in command) - { - //first parameter must be a valid element or begins with '@' - if(command[name][0] && ($(command[name][0]) || command[name][0].indexOf("[]") > -1)) - { - name.toFunction().apply(this,command[name]); - } - } - } -}; - - -/** - * Returns false if validation required and validates to false, - * returns true otherwise. - * @return boolean true if validation passes. - */ -Prado.AJAX.Validate = function(options) -{ - if(options.CausesValidation) - { - if(options.ValidatorGroup) - return Prado.Validation.ValidateValidatorGroup(options.ValidatorGroup); - else if(options.ValidationGroup) - return Prado.Validation.ValidateValidationGroup(options.ValidationGroup); - else - return Prado.Validation.ValidateNonGroup(options.ValidationForm); - } - else - return true; -}; - - -//Available callback service -Prado.AJAX.Callback.Server = ''; - -//List of IDs that implements IPostBackHandler -Prado.AJAX.Callback.IDs = []; - -/** - * Simple AJAX callback interface, suitable for inline javascript. - * e.g., Click me - * @param string callback ID - * @param array parameters to pass to the callback service - */ -Prado.Callback = function(ID, params, onSuccess, options) -{ - var callback = - { - 'params' : [params] || [], - 'onSuccess' : onSuccess || Prototype.emptyFunction, - 'CausesValidation' : true - }; - - Object.extend(callback, options || {}); - - new Prado.AJAX.Callback(ID, callback); - return false; -} \ No newline at end of file diff --git a/framework/Web/Javascripts/base/controls.js b/framework/Web/Javascripts/base/controls.js deleted file mode 100644 index ad5b8abe..00000000 --- a/framework/Web/Javascripts/base/controls.js +++ /dev/null @@ -1,194 +0,0 @@ -/** - * Auto complete textbox via AJAX. - */ -Prado.AutoCompleter = Class.create(); - - -/** - * Overrides parent implementation of updateElement by trimming the value. - */ -Prado.AutoCompleter.Base = function(){}; -Prado.AutoCompleter.Base.prototype = Object.extend(Autocompleter.Base.prototype, -{ - updateElement: function(selectedElement) - { - if (this.options.updateElement) { - this.options.updateElement(selectedElement); - return; - } - - var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); - var lastTokenPos = this.findLastToken(); - if (lastTokenPos != -1) { - var newValue = this.element.value.substr(0, lastTokenPos + 1); - var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); - if (whitespace) - newValue += whitespace[0]; - this.element.value = (newValue + value).trim(); - } else { - this.element.value = value.trim(); - } - this.element.focus(); - - if (this.options.afterUpdateElement) - this.options.afterUpdateElement(this.element, selectedElement); - } -}); - -/** - * Based on the Prototype Autocompleter class. - * This client-side component should be instantiated from a Prado component. - * Usage: new Prado.AutoCompleter('textboxID', 'updateDivID', {callbackID : '...'}); - */ -Prado.AutoCompleter.prototype = Object.extend(new Autocompleter.Base(), -{ - /** - * This component is initialized by - * new Prado.AutoCompleter(...) - * @param string the ID of the textbox element to observe - * @param string the ID of the div to display the auto-complete options - * @param array a hash of options, e.g. auto-completion token separator. - */ - initialize : function(element, update, options) - { - this.baseInitialize(element, update, options); - }, - - /** - * The callback function, i.e., function called on successful AJAX return. - * Calls update choices in the Autocompleter. - * @param string new auto-complete options for display - */ - onUpdateReturn : function(result) - { - if(isString(result) && result.length > 0) - this.updateChoices(result); - }, - - /** - * Requesting new choices using Prado's client-side callback scheme. - */ - getUpdatedChoices : function() - { - Prado.Callback(this.element.id, this.getToken(), this.onUpdateReturn.bind(this)); - } -}); - -/** - * Prado TActivePanel client javascript. Usage - * - * Prado.ActivePanel.register("id", options); - * Prado.ActivePanel.update("id", "hello"); - * - */ -Prado.ActivePanel = -{ - callbacks : {}, - - register : function(id, options) - { - Prado.ActivePanel.callbacks[id] = options; - }, - - update : function(id, param) - { - var request = new Prado.ActivePanel.Request(id, - Prado.ActivePanel.callbacks[id]); - request.callback(param); - } -} - -/** - * Client-script for TActivePanel. Uses Callback to notify the server - * for updates, if update option is set, the innerHTML of the update ID - * is set to the returned output. - */ -Prado.ActivePanel.Request = Class.create(); -Prado.ActivePanel.Request.prototype = -{ - initialize : function(element, options) - { - this.element = element; - this.setOptions(options); - }, - - /** - * Set some options. - */ - setOptions : function(options) - { - this.options = - { - onSuccess : this.onSuccess.bind(this) - } - Object.extend(this.options, options || {}); - }, - - /** - * Make the callback request - */ - callback : function(param) - { - this.options.params = [param]; - new Prado.AJAX.Callback(this.element, this.options); - }, - - /** - * Callback onSuccess handler, update the element innerHTML if necessary - */ - onSuccess : function(result, output) - { - if(this.options.update) - { - if (!this.options.evalScripts) - output = output.stripScripts(); - Element.update(this.options.update, output); - } - } -} - -/** - * Drop container to accept draggable component drops. - */ -Prado.DropContainer = Class.create(); -Prado.DropContainer.prototype = Object.extend(new Prado.ActivePanel.Request(), -{ - initialize : function(element, options) - { - this.element = element; - this.setOptions(options); - Object.extend(this.options, - { - onDrop : this.onDrop.bind(this), - evalScripts : true, - onSuccess : options.onSuccess || this.onSuccess.bind(this) - }); - Droppables.add(element, this.options); - }, - - onDrop : function(draggable, droppable) - { - this.callback(draggable.id) - } -}); - -Prado.ActiveImageButton = Class.create(); -Prado.ActiveImageButton.prototype = -{ - initialize : function(element, options) - { - this.element = $(element); - this.options = options; - Event.observe(this.element, "click", this.click.bind(this)); - }, - - click : function(e) - { - var el = $('{$this->ClientID}'); - var imagePos = Position.cumulativeOffset(this.element); - var clickedPos = [e.clientX, e.clientY]; - var param = (clickedPos[0]-imagePos[0]+1)+","+(clickedPos[1]-imagePos[1]+1); - Prado.Callback(this.element, param, null, this.options); - Event.stop(e); - } -} \ No newline at end of file diff --git a/framework/Web/Javascripts/base/date.js b/framework/Web/Javascripts/base/date.js deleted file mode 100644 index 375c59df..00000000 --- a/framework/Web/Javascripts/base/date.js +++ /dev/null @@ -1,147 +0,0 @@ - -Object.extend(Date.prototype, -{ - SimpleFormat: function(format) - { - var bits = new Array(); - bits['d'] = this.getDate(); - bits['dd'] = Prado.Util.pad(this.getDate(),2); - - bits['M'] = this.getMonth()+1; - bits['MM'] = Prado.Util.pad(this.getMonth()+1,2); - - var yearStr = "" + this.getFullYear(); - yearStr = (yearStr.length == 2) ? '19' + yearStr: yearStr; - bits['yyyy'] = yearStr; - bits['yy'] = bits['yyyy'].toString().substr(2,2); - - // do some funky regexs to replace the format string - // with the real values - var frm = new String(format); - for (var sect in bits) - { - var reg = new RegExp("\\b"+sect+"\\b" ,"g"); - frm = frm.replace(reg, bits[sect]); - } - return frm; - }, - - toISODate : function() - { - var y = this.getFullYear(); - var m = Prado.Util.pad(this.getMonth() + 1); - var d = Prado.Util.pad(this.getDate()); - return String(y) + String(m) + String(d); - } -}); - -Object.extend(Date, -{ - SimpleParse: function(value, format) - { - val=String(value); - format=String(format); - - if(val.length <= 0) return null; - - if(format.length <= 0) return new Date(value); - - var isInteger = function (val) - { - var digits="1234567890"; - for (var i=0; i < val.length; i++) - { - if (digits.indexOf(val.charAt(i))==-1) { return false; } - } - return true; - }; - - var getInt = function(str,i,minlength,maxlength) - { - for (var x=maxlength; x>=minlength; x--) - { - var token=str.substring(i,i+x); - if (token.length < minlength) { return null; } - if (isInteger(token)) { return token; } - } - return null; - }; - - var i_val=0; - var i_format=0; - var c=""; - var token=""; - var token2=""; - var x,y; - var now=new Date(); - var year=now.getFullYear(); - var month=now.getMonth()+1; - var date=1; - - while (i_format < format.length) - { - // Get next token from format string - c=format.charAt(i_format); - token=""; - while ((format.charAt(i_format)==c) && (i_format < format.length)) - { - token += format.charAt(i_format++); - } - - // Extract contents of value based on format token - if (token=="yyyy" || token=="yy" || token=="y") - { - if (token=="yyyy") { x=4;y=4; } - if (token=="yy") { x=2;y=2; } - if (token=="y") { x=2;y=4; } - year=getInt(val,i_val,x,y); - if (year==null) { return null; } - i_val += year.length; - if (year.length==2) - { - if (year > 70) { year=1900+(year-0); } - else { year=2000+(year-0); } - } - } - - else if (token=="MM"||token=="M") - { - month=getInt(val,i_val,token.length,2); - if(month==null||(month<1)||(month>12)){return null;} - i_val+=month.length; - } - else if (token=="dd"||token=="d") - { - date=getInt(val,i_val,token.length,2); - if(date==null||(date<1)||(date>31)){return null;} - i_val+=date.length; - } - else - { - if (val.substring(i_val,i_val+token.length)!=token) {return null;} - else {i_val+=token.length;} - } - } - - // If there are any trailing characters left in the value, it doesn't match - if (i_val != val.length) { return null; } - - // Is date valid for month? - if (month==2) - { - // Check for leap year - if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year - if (date > 29){ return null; } - } - else { if (date > 28) { return null; } } - } - - if ((month==4)||(month==6)||(month==9)||(month==11)) - { - if (date > 30) { return null; } - } - - var newdate=new Date(year,month-1,date, 0, 0, 0); - return newdate; - } -}); \ No newline at end of file diff --git a/framework/Web/Javascripts/base/datepicker.js b/framework/Web/Javascripts/base/datepicker.js deleted file mode 100644 index 68e63168..00000000 --- a/framework/Web/Javascripts/base/datepicker.js +++ /dev/null @@ -1,656 +0,0 @@ -Prado.Calendar = Class.create(); - -Prado.Calendar.Util = Class.create(); - -Object.extend(Prado.Calendar.Util, -{ - IsLeapYear : function (year) - { - return ((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))); - }, - - yearLength : function(year) - { - if (this.isLeapYear(year)) - return 366; - else - return 365; - }, - - dayOfYear : function(date) - { - var a = this.isLeapYear(date.getFullYear()) ? - Calendar.LEAP_NUM_DAYS : Calendar.NUM_DAYS; - return a[date.getMonth()] + date.getDate(); - }, - - browser : function() - { - var info = { Version : "1.0" }; - var is_major = parseInt( navigator.appVersion ); - info.nver = is_major; - info.ver = navigator.appVersion; - info.agent = navigator.userAgent; - info.dom = document.getElementById ? 1 : 0; - info.opera = window.opera ? 1 : 0; - info.ie5 = ( info.ver.indexOf( "MSIE 5" ) > -1 && info.dom && !info.opera ) ? 1 : 0; - info.ie6 = ( info.ver.indexOf( "MSIE 6" ) > -1 && info.dom && !info.opera ) ? 1 : 0; - info.ie4 = ( document.all && !info.dom && !info.opera ) ? 1 : 0; - info.ie = info.ie4 || info.ie5 || info.ie6; - info.mac = info.agent.indexOf( "Mac" ) > -1; - info.ns6 = ( info.dom && parseInt( info.ver ) >= 5 ) ? 1 : 0; - info.ie3 = ( info.ver.indexOf( "MSIE" ) && ( is_major < 4 ) ); - info.hotjava = ( info.agent.toLowerCase().indexOf( 'hotjava' ) != -1 ) ? 1 : 0; - info.ns4 = ( document.layers && !info.dom && !info.hotjava ) ? 1 : 0; - info.bw = ( info.ie6 || info.ie5 || info.ie4 || info.ns4 || info.ns6 || info.opera ); - info.ver3 = ( info.hotjava || info.ie3 ); - info.opera7 = ( ( info.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( info.agent.toLowerCase().indexOf( 'opera/7' ) > -1 ) ); - info.operaOld = info.opera && !info.opera7; - return info; - }, - - ImportCss : function(doc, css_file) - { - if (this.browser().ie) - var styleSheet = doc.createStyleSheet(css_file); - else - { - var elm = doc.createElement("link"); - - elm.rel = "stylesheet"; - elm.href = css_file; - - if (headArr = doc.getElementsByTagName("head")) - headArr[0].appendChild(elm); - } - } -}); - -Object.extend(Prado.Calendar, -{ - // Accumulated days per month, for normal and for leap years. - // Used in week number calculations. - NUM_DAYS : [0,31,59,90,120,151,181,212,243,273,304,334], - LEAP_NUM_DAYS : [0,31,60,91,121,152,182,213,244,274,305,335] -}); - -Prado.Calendar.prototype = -{ - monthNames : [ "January", "February", "March", "April", - "May", "June", "July", "August", - "September", "October", "November", "December" - ], - - shortWeekDayNames : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], - - format : "yyyy-MM-dd", - - css : "calendar_system.css", - - initialize : function(control, attr) - { - this.attr = attr || []; - this.control = $(control); - this.dateSlot = new Array(42); - this.weekSlot = new Array(6); - this.firstDayOfWeek = 1; - this.minimalDaysInFirstWeek = 4; - this.currentDate = new Date(); - this.selectedDate = null; - this.className = "Prado_Calendar"; - - //which element to trigger to show the calendar - this.trigger = this.attr.trigger ? $(this.attr.trigger) : this.control; - Event.observe(this.trigger, "click", this.show.bind(this)); - - Prado.Calendar.Util.ImportCss(document, this.css); - - if(this.attr.format) this.format = this.attr.format; - - //create it - this.create(); - this.hookEvents(); - }, - - create : function() - { - var div; - var table; - var tbody; - var tr; - var td; - - // Create the top-level div element - this._calDiv = document.createElement("div"); - this._calDiv.className = this.className; - this._calDiv.style.display = "none"; - - // header div - div = document.createElement("div"); - div.className = "calendarHeader"; - this._calDiv.appendChild(div); - - table = document.createElement("table"); - table.style.cellSpacing = 0; - div.appendChild(table); - - tbody = document.createElement("tbody"); - table.appendChild(tbody); - - tr = document.createElement("tr"); - tbody.appendChild(tr); - - // Previous Month Button - td = document.createElement("td"); - td.className = "prevMonthButton"; - this._previousMonth = document.createElement("button"); - this._previousMonth.appendChild(document.createTextNode("<<")); - td.appendChild(this._previousMonth); - tr.appendChild(td); - - - - // - // Create the month drop down - // - td = document.createElement("td"); - td.className = "labelContainer"; - tr.appendChild(td); - this._monthSelect = document.createElement("select"); - for (var i = 0 ; i < this.monthNames.length ; i++) { - var opt = document.createElement("option"); - opt.innerHTML = this.monthNames[i]; - opt.value = i; - if (i == this.currentDate.getMonth()) { - opt.selected = true; - } - this._monthSelect.appendChild(opt); - } - td.appendChild(this._monthSelect); - - - // - // Create the year drop down - // - td = document.createElement("td"); - td.className = "labelContainer"; - tr.appendChild(td); - this._yearSelect = document.createElement("select"); - for(var i=1920; i < 2050; ++i) { - var opt = document.createElement("option"); - opt.innerHTML = i; - opt.value = i; - if (i == this.currentDate.getFullYear()) { - opt.selected = false; - } - this._yearSelect.appendChild(opt); - } - td.appendChild(this._yearSelect); - - - td = document.createElement("td"); - td.className = "nextMonthButton"; - this._nextMonth = document.createElement("button"); - this._nextMonth.appendChild(document.createTextNode(">>")); - td.appendChild(this._nextMonth); - tr.appendChild(td); - - // Calendar body - div = document.createElement("div"); - div.className = "calendarBody"; - this._calDiv.appendChild(div); - this._table = div; - - // Create the inside of calendar body - - var text; - table = document.createElement("table"); - //table.style.width="100%"; - table.className = "grid"; - - div.appendChild(table); - var thead = document.createElement("thead"); - table.appendChild(thead); - tr = document.createElement("tr"); - thead.appendChild(tr); - - for(i=0; i < 7; ++i) { - td = document.createElement("th"); - text = document.createTextNode(this.shortWeekDayNames[(i+this.firstDayOfWeek)%7]); - td.appendChild(text); - td.className = "weekDayHead"; - tr.appendChild(td); - } - - // Date grid - tbody = document.createElement("tbody"); - table.appendChild(tbody); - - for(week=0; week<6; ++week) { - tr = document.createElement("tr"); - tbody.appendChild(tr); - - for(day=0; day<7; ++day) { - td = document.createElement("td"); - td.className = "calendarDate"; - text = document.createTextNode(String.fromCharCode(160)); - td.appendChild(text); - - tr.appendChild(td); - var tmp = new Object(); - tmp.tag = "DATE"; - tmp.value = -1; - tmp.data = text; - this.dateSlot[(week*7)+day] = tmp; - - Event.observe(td, "mouseover", this.hover.bind(this)); - Event.observe(td, "mouseout", this.hover.bind(this)); - - } - } - - // Calendar Footer - div = document.createElement("div"); - div.className = "calendarFooter"; - this._calDiv.appendChild(div); - - table = document.createElement("table"); - //table.style.width="100%"; - table.className = "footerTable"; - //table.cellSpacing = 0; - div.appendChild(table); - - tbody = document.createElement("tbody"); - table.appendChild(tbody); - - tr = document.createElement("tr"); - tbody.appendChild(tr); - - // - // The TODAY button - // - td = document.createElement("td"); - td.className = "todayButton"; - this._todayButton = document.createElement("button"); - var today = new Date(); - var buttonText = today.getDate() + " " + this.monthNames[today.getMonth()] + ", " + today.getFullYear(); - this._todayButton.appendChild(document.createTextNode(buttonText)); - td.appendChild(this._todayButton); - tr.appendChild(td); - - // - // The CLEAR button - // - td = document.createElement("td"); - td.className = "clearButton"; - this._clearButton = document.createElement("button"); - var today = new Date(); - buttonText = "Clear"; - this._clearButton.appendChild(document.createTextNode(buttonText)); - td.appendChild(this._clearButton); - tr.appendChild(td); - - document.body.appendChild(this._calDiv); - - this.update(); - this.updateHeader(); - - return this._calDiv; - }, - - hookEvents : function() - { - // IE55+ extension - this._previousMonth.hideFocus = true; - this._nextMonth.hideFocus = true; - this._todayButton.hideFocus = true; - // end IE55+ extension - - // hook up events - Event.observe(this._previousMonth, "click", this.prevMonth.bind(this)); - Event.observe(this._nextMonth, "click", this.nextMonth.bind(this)); - Event.observe(this._todayButton, "click", this.selectToday.bind(this)); - Event.observe(this._clearButton, "click", this.clearSelection.bind(this)); - - Event.observe(this._monthSelect, "change", this.monthSelect.bind(this)); - Event.observe(this._yearSelect, "change", this.yearSelect.bind(this)); - - // ie6 extension - Event.observe(this._calDiv, "mousewheel", this.mouseWheelChange.bind(this)); - - Event.observe(this._table, "click", this.selectDate.bind(this)); - - Event.observe(this._calDiv,"keydown", this.keyPressed.bind(this)); - - /* - this._calDiv.onkeydown = function (e) { - if (e == null) e = document.parentWindow.event; - var kc = e.keyCode != null ? e.keyCode : e.charCode; - - if(kc == 13) { - var d = new Date(dp._currentDate).valueOf(); - dp.setSelectedDate(d); - - if (!dp._alwaysVisible && dp._hideOnSelect) { - dp.hide(); - } - return false; - } - - - if (kc < 37 || kc > 40) return true; - - var d = new Date(dp._currentDate).valueOf(); - if (kc == 37) // left - d -= 24 * 60 * 60 * 1000; - else if (kc == 39) // right - d += 24 * 60 * 60 * 1000; - else if (kc == 38) // up - d -= 7 * 24 * 60 * 60 * 1000; - else if (kc == 40) // down - d += 7 * 24 * 60 * 60 * 1000; - - dp.setCurrentDate(new Date(d)); - return false; - }*/ - - - }, - - keyPressed : function(ev) - { - if (!ev) ev = document.parentWindow.event; - var kc = ev.keyCode != null ? ev.keyCode : ev.charCode; - - if(kc = Event.KEY_RETURN) - { - //var d = new Date(this.currentDate); - this.setSelectedDate(this.currentDate); - this.hide(); - return false; - } - - if(kc < 37 || kc > 40) return true; - - var d = new Date(this.currentDate).valueOf(); - if(kc == Event.KEY_LEFT) - d -= 86400000; //-1 day - else if (kc == Event.KEY_RIGHT) - d += 86400000; //+1 day - else if (kc == Event.KEY_UP) - d -= 604800000; // -7 days - else if (kc == Event.KEY_DOWN) - d += 604800000; // +7 days - this.setCurrentDate(new Date(d)); - return false; - }, - - selectDate : function(ev) - { - var el = Event.element(ev); - while (el.nodeType != 1) - el = el.parentNode; - - while (el != null && el.tagName && el.tagName.toLowerCase() != "td") - el = el.parentNode; - - // if no td found, return - if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td") - return; - - var d = new Date(this.currentDate); - var n = Number(el.firstChild.data); - if (isNaN(n) || n <= 0 || n == null) - return; - - d.setDate(n); - this.setSelectedDate(d); - this.hide(); - }, - - selectToday : function() - { - this.setSelectedDate(new Date()); - this.hide(); - }, - - clearSelection : function() - { - this.selectedDate = null; - if (isFunction(this.onchange)) - this.onchange(); - this.hide(); - }, - - monthSelect : function(ev) - { - this.setMonth(Form.Element.getValue(Event.element(ev))); - }, - - yearSelect : function(ev) - { - this.setYear(Form.Element.getValue(Event.element(ev))); - }, - - // ie6 extension - mouseWheelChange : function (e) - { - if (e == null) e = document.parentWindow.event; - var n = - e.wheelDelta / 120; - var d = new Date(this.currentDate); - var m = this.getMonth() + n; - this.setMonth(m); - this.setCurrentDate(d); - - return false; - }, - - onchange : function() - { - this.control.value = this.formatDate(); - }, - - formatDate : function() - { - return Prado.Calendar.Util.FormatDate(this.selectedDate, this.format); - }, - - setCurrentDate : function(date) - { - if (date == null) - return; - - // if string or number create a Date object - if (isString(date) || isNumber(date)) - date = new Date(date); - - // do not update if not really changed - if (this.currentDate.getDate() != date.getDate() || - this.currentDate.getMonth() != date.getMonth() || - this.currentDate.getFullYear() != date.getFullYear()) - { - - this.currentDate = new Date(date); - - this.updateHeader(); - this.update(); - } - - }, - - setSelectedDate : function(date) - { - this.selectedDate = new Date(date); - this.setCurrentDate(this.selectedDate); - if (isFunction(this.onchange)) - this.onchange(); - }, - - getElement : function() - { - return this._calDiv; - }, - - getSelectedDate : function () - { - return isNull(this.selectedDate) ? null : new Date(this.selectedDate); - }, - - setYear : function(year) - { - var d = new Date(this.currentDate); - d.setFullYear(year); - this.setCurrentDate(d); - }, - - setMonth : function (month) - { - var d = new Date(this.currentDate); - d.setMonth(month); - this.setCurrentDate(d); - }, - - nextMonth : function () - { - this.setMonth(this.currentDate.getMonth()+1); - }, - - prevMonth : function () - { - this.setMonth(this.currentDate.getMonth()-1); - }, - - show : function() - { - if(!this.showing) - { - var pos = Position.cumulativeOffset(this.control); - pos[1] += this.control.offsetHeight; - this._calDiv.style.display = "block"; - this._calDiv.style.top = pos[1] + "px"; - this._calDiv.style.left = pos[0] + "px"; - Event.observe(document.body, "click", this.hideOnClick.bind(this)); - var date = Prado.Calendar.Util.ParseDate(Form.Element.getValue(this.control), this.format); - if(!isNull(date)) - { - this.selectedDate = date; - this.setCurrentDate(date); - } - this.showing = true; - } - }, - - //hide the calendar when clicked outside any calendar - hideOnClick : function(ev) - { - if(!this.showing) return; - var el = Event.element(ev); - var within = false; - do - { - within = within || el.className == this.className; - within = within || el == this.trigger; - within = within || el == this.control; - if(within) break; - el = el.parentNode; - } - while(el); - if(!within) this.hide(); - }, - - hide : function() - { - if(this.showing) - { - this._calDiv.style.display = "none"; - this.showing = false; - Event.stopObserving(document.body, "click", this.hideOnClick.bind(this)); - } - }, - - update : function() - { - var Util = Prado.Calendar.Util; - - // Calculate the number of days in the month for the selected date - var date = this.currentDate; - var today = Util.ISODate(new Date()); - - var selected = isNull(this.selectedDate) ? "" : Util.ISODate(this.selectedDate); - var current = Util.ISODate(date); - var d1 = new Date(date.getFullYear(), date.getMonth(), 1); - var d2 = new Date(date.getFullYear(), date.getMonth()+1, 1); - var monthLength = Math.round((d2 - d1) / (24 * 60 * 60 * 1000)); - - // Find out the weekDay index for the first of this month - var firstIndex = (d1.getDay() - this.firstDayOfWeek) % 7 ; - if (firstIndex < 0) - firstIndex += 7; - - var index = 0; - while (index < firstIndex) { - this.dateSlot[index].value = -1; - this.dateSlot[index].data.data = String.fromCharCode(160); - this.dateSlot[index].data.parentNode.className = "empty"; - index++; - } - - for (i = 1; i <= monthLength; i++, index++) { - var slot = this.dateSlot[index]; - var slotNode = slot.data.parentNode; - slot.value = i; - slot.data.data = i; - slotNode.className = "date"; - if (Util.ISODate(d1) == today) { - slotNode.className += " today"; - } - if (Util.ISODate(d1) == current) { - slotNode.className += " current"; - } - if (Util.ISODate(d1) == selected) { - slotNode.className += " selected"; - } - d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+1); - } - - var lastDateIndex = index; - - while(index < 42) { - this.dateSlot[index].value = -1; - this.dateSlot[index].data.data = String.fromCharCode(160); - this.dateSlot[index].data.parentNode.className = "empty"; - ++index; - } - - }, - - hover : function(ev) - { - //conditionally add the hover class to the event target element. - Element.condClassName(Event.element(ev), "hover", ev.type=="mouseover"); - }, - - updateHeader : function () { - - var options = this._monthSelect.options; - var m = this.currentDate.getMonth(); - for(var i=0; i < options.length; ++i) { - options[i].selected = false; - if (options[i].value == m) { - options[i].selected = true; - } - } - - options = this._yearSelect.options; - var year = this.currentDate.getFullYear(); - for(var i=0; i < options.length; ++i) { - options[i].selected = false; - if (options[i].value == year) { - options[i].selected = true; - } - } - - } - - -}; \ No newline at end of file diff --git a/framework/Web/Javascripts/base/effects.js b/framework/Web/Javascripts/base/effects.js deleted file mode 100644 index cc31d00e..00000000 --- a/framework/Web/Javascripts/base/effects.js +++ /dev/null @@ -1,22 +0,0 @@ -Prado.Effect = -{ - Highlight : function(element, duration) - { - new Effect.Highlight(element, {'duration':duration}); - }, - - Scale : function(element, percent) - { - new Effect.Scale(element, percent); - }, - - MoveBy : function(element, toTop, toLeft) - { - new Effect.MoveBy(element, toTop, toLeft); - }, - - ScrollTo : function(element, duration) - { - new Effect.ScrollTo(element, {'duration':duration}); - } -} \ No newline at end of file diff --git a/framework/Web/Javascripts/base/focus.js b/framework/Web/Javascripts/base/focus.js deleted file mode 100644 index 6c1359cd..00000000 --- a/framework/Web/Javascripts/base/focus.js +++ /dev/null @@ -1,99 +0,0 @@ -Prado.Focus = Class.create(); - -Prado.Focus.setFocus = function(id) -{ - var target = document.getElementById ? document.getElementById(id) : document.all[id]; - if(target && !Prado.Focus.canFocusOn(target)) - { - target = Prado.Focus.findTarget(target); - } - if(target) - { - try - { - target.focus(); - target.scrollIntoView(false); - if (window.__smartNav) - { - window.__smartNav.ae = target.id; - } - } - catch (e) - { - } - } -} - -Prado.Focus.canFocusOn = function(element) -{ - if(!element || !(element.tagName)) - return false; - var tagName = element.tagName.toLowerCase(); - return !element.disabled && (!element.type || element.type.toLowerCase() != "hidden") && Prado.Focus.isFocusableTag(tagName) && Prado.Focus.isVisible(element); -} - -Prado.Focus.isFocusableTag = function(tagName) -{ - return (tagName == "input" || tagName == "textarea" || tagName == "select" || tagName == "button" || tagName == "a"); -} - - -Prado.Focus.findTarget = function(element) -{ - if(!element || !(element.tagName)) - { - return null; - } - var tagName = element.tagName.toLowerCase(); - if (tagName == "undefined") - { - return null; - } - var children = element.childNodes; - if (children) - { - for(var i=0;i= ' ') { - if (c == '\\' || c == '"') { - s += '\\'; - } - s += c; - } else { - switch (c) { - case '\b': - s += '\\b'; - break; - case '\f': - s += '\\f'; - break; - case '\n': - s += '\\n'; - break; - case '\r': - s += '\\r'; - break; - case '\t': - s += '\\t'; - break; - default: - c = c.charCodeAt(); - s += '\\u00' + Math.floor(c / 16).toString(16) + - (c % 16).toString(16); - } - } - } - return s + '"'; - case 'boolean': - return String(arg); - default: - return 'null'; - } - }, - parse: function (text) { - var at = 0; - var ch = ' '; - - function error(m) { - throw { - name: 'JSONError', - message: m, - at: at - 1, - text: text - }; - } - - function next() { - ch = text.charAt(at); - at += 1; - return ch; - } - - function white() { - while (ch) { - if (ch <= ' ') { - next(); - } else if (ch == '/') { - switch (next()) { - case '/': - while (next() && ch != '\n' && ch != '\r') {} - break; - case '*': - next(); - for (;;) { - if (ch) { - if (ch == '*') { - if (next() == '/') { - next(); - break; - } - } else { - next(); - } - } else { - error("Unterminated comment"); - } - } - break; - default: - error("Syntax error"); - } - } else { - break; - } - } - } - - function string() { - var i, s = '', t, u; - - if (ch == '"') { -outer: while (next()) { - if (ch == '"') { - next(); - return s; - } else if (ch == '\\') { - switch (next()) { - case 'b': - s += '\b'; - break; - case 'f': - s += '\f'; - break; - case 'n': - s += '\n'; - break; - case 'r': - s += '\r'; - break; - case 't': - s += '\t'; - break; - case 'u': - u = 0; - for (i = 0; i < 4; i += 1) { - t = parseInt(next(), 16); - if (!isFinite(t)) { - break outer; - } - u = u * 16 + t; - } - s += String.fromCharCode(u); - break; - default: - s += ch; - } - } else { - s += ch; - } - } - } - error("Bad string"); - } - - function array() { - var a = []; - - if (ch == '[') { - next(); - white(); - if (ch == ']') { - next(); - return a; - } - while (ch) { - a.push(value()); - white(); - if (ch == ']') { - next(); - return a; - } else if (ch != ',') { - break; - } - next(); - white(); - } - } - error("Bad array"); - } - - function object() { - var k, o = {}; - - if (ch == '{') { - next(); - white(); - if (ch == '}') { - next(); - return o; - } - while (ch) { - k = string(); - white(); - if (ch != ':') { - break; - } - next(); - o[k] = value(); - white(); - if (ch == '}') { - next(); - return o; - } else if (ch != ',') { - break; - } - next(); - white(); - } - } - error("Bad object"); - } - - function number() { - var n = '', v; - if (ch == '-') { - n = '-'; - next(); - } - while (ch >= '0' && ch <= '9') { - n += ch; - next(); - } - if (ch == '.') { - n += '.'; - while (next() && ch >= '0' && ch <= '9') { - n += ch; - } - } - if (ch == 'e' || ch == 'E') { - n += 'e'; - next(); - if (ch == '-' || ch == '+') { - n += ch; - next(); - } - while (ch >= '0' && ch <= '9') { - n += ch; - next(); - } - } - v = +n; - if (!isFinite(v)) { - ////error("Bad number"); - } else { - return v; - } - } - - function word() { - switch (ch) { - case 't': - if (next() == 'r' && next() == 'u' && next() == 'e') { - next(); - return true; - } - break; - case 'f': - if (next() == 'a' && next() == 'l' && next() == 's' && - next() == 'e') { - next(); - return false; - } - break; - case 'n': - if (next() == 'u' && next() == 'l' && next() == 'l') { - next(); - return null; - } - break; - } - error("Syntax error"); - } - - function value() { - white(); - switch (ch) { - case '{': - return object(); - case '[': - return array(); - case '"': - return string(); - case '-': - return number(); - default: - return ch >= '0' && ch <= '9' ? number() : word(); - } - } - - return value(); - } -}; \ No newline at end of file diff --git a/framework/Web/Javascripts/base/postback.js b/framework/Web/Javascripts/base/postback.js deleted file mode 100644 index 186495cc..00000000 --- a/framework/Web/Javascripts/base/postback.js +++ /dev/null @@ -1,66 +0,0 @@ -Prado.doPostBack = function(formID, eventTarget, eventParameter, performValidation, validationGroup, actionUrl, trackFocus, clientSubmit) -{ - if (typeof(performValidation) == 'undefined') - { - var performValidation = false; - var validationGroup = ''; - var actionUrl = null; - var trackFocus = false; - var clientSubmit = true; - } - var theForm = document.getElementById ? document.getElementById(formID) : document.forms[formID]; - var canSubmit = true; - if (performValidation) - { - //canSubmit = Prado.Validation.validate(validationGroup); - /* Prado.Validation.ActiveTarget = theForm; - Prado.Validation.CurrentTargetGroup = null; - Prado.Validation.IsGroupValidation = false; - canSubmit = Prado.Validation.IsValid(theForm); - Logger.debug(canSubmit);*/ - canSubmit = Prado.Validation.IsValid(theForm); - } - if (canSubmit) - { - if (actionUrl != null && (actionUrl.length > 0)) - { - theForm.action = actionUrl; - } - if (trackFocus) - { - var lastFocus = theForm.elements['PRADO_LASTFOCUS']; - if ((typeof(lastFocus) != 'undefined') && (lastFocus != null)) - { - var active = document.activeElement; - if (typeof(active) == 'undefined') - { - lastFocus.value = eventTarget; - } - else - { - if ((active != null) && (typeof(active.id) != 'undefined')) - { - if (active.id.length > 0) - { - lastFocus.value = active.id; - } - else if (typeof(active.name) != 'undefined') - { - lastFocus.value = active.name; - } - } - } - } - } - if (!clientSubmit) - { - canSubmit = false; - } - } - if (canSubmit && (!theForm.onsubmit || theForm.onsubmit())) - { - theForm.PRADO_POSTBACK_TARGET.value = eventTarget; - theForm.PRADO_POSTBACK_PARAMETER.value = eventParameter; - theForm.submit(); - } -} \ No newline at end of file diff --git a/framework/Web/Javascripts/base/prado.js b/framework/Web/Javascripts/base/prado.js deleted file mode 100644 index 95600f09..00000000 --- a/framework/Web/Javascripts/base/prado.js +++ /dev/null @@ -1,2 +0,0 @@ -var Prado = { Version: 2.0 }; - diff --git a/framework/Web/Javascripts/base/rico.js b/framework/Web/Javascripts/base/rico.js deleted file mode 100644 index d3df3a9b..00000000 --- a/framework/Web/Javascripts/base/rico.js +++ /dev/null @@ -1,175 +0,0 @@ -Prado.RicoLiveGrid = Class.create(); -Prado.RicoLiveGrid.prototype = Object.extend(Rico.LiveGrid.prototype, -{ - initialize : function(tableId, options) - { - this.options = { - tableClass: $(tableId).className || '', - loadingClass: $(tableId).className || '', - scrollerBorderRight: '1px solid #ababab', - bufferTimeout: 20000, - sortAscendImg: 'images/sort_asc.gif', - sortDescendImg: 'images/sort_desc.gif', - sortImageWidth: 9, - sortImageHeight: 5, - ajaxSortURLParms: [], - onRefreshComplete: null, - requestParameters: null, - inlineStyles: true, - visibleRows: 10, - totalRows: 0, - initialOffset: 0 - }; - Object.extend(this.options, options || {}); - - //this.ajaxOptions = {parameters: null}; - //Object.extend(this.ajaxOptions, ajaxOptions || {}); - - this.tableId = tableId; - this.table = $(tableId); - - this.addLiveGridHtml(); - - var columnCount = this.table.rows[0].cells.length; - this.metaData = new Rico.LiveGridMetaData(this.options.visibleRows, this.options.totalRows, columnCount, options); - this.buffer = new Rico.LiveGridBuffer(this.metaData); - - var rowCount = this.table.rows.length; - this.viewPort = new Rico.GridViewPort(this.table, - this.table.offsetHeight/rowCount, - this.options.visibleRows, - this.buffer, this); - this.scroller = new Rico.LiveGridScroller(this,this.viewPort); - this.options.sortHandler = this.sortHandler.bind(this); - - if ( $(tableId + '_header') ) - this.sort = new Rico.LiveGridSort(tableId + '_header', this.options) - - this.processingRequest = null; - this.unprocessedRequest = null; - - //this.initAjax(url); - if (this.options.initialOffset >= 0) - { - var offset = this.options.initialOffset; - this.scroller.moveScroll(offset); - this.viewPort.scrollTo(this.scroller.rowToPixel(offset)); - if (this.options.sortCol) { - this.sortCol = options.sortCol; - this.sortDir = options.sortDir; - } - var grid = this; - setTimeout(function(){ - grid.requestContentRefresh(offset); - },100); - } - }, - - fetchBuffer: function(offset) - { - if ( this.buffer.isInRange(offset) && - !this.buffer.isNearingLimit(offset)) { - return; - } - if (this.processingRequest) { - this.unprocessedRequest = new Rico.LiveGridRequest(offset); - return; - } - var bufferStartPos = this.buffer.getFetchOffset(offset); - this.processingRequest = new Rico.LiveGridRequest(offset); - this.processingRequest.bufferOffset = bufferStartPos; - var fetchSize = this.buffer.getFetchSize(offset); - var partialLoaded = false; - - // var queryString - // if (this.options.requestParameters) - // queryString = this._createQueryString(this.options.requestParameters, 0); - var param = - { - 'page_size' : fetchSize, - 'offset' : bufferStartPos - }; - if(this.sortCol) - { - Object.extend(param, - { - 'sort_col': this.sortCol, - 'sort_dir': this.sortDir - }); - } - /*queryString = (queryString == null) ? '' : queryString+'&'; - queryString = queryString+'id='+this.tableId+'&page_size='+fetchSize+'&offset='+bufferStartPos; - if (this.sortCol) - queryString = queryString+'&sort_col='+escape(this.sortCol)+'&sort_dir='+this.sortDir; - - this.ajaxOptions.parameters = queryString; - - ajaxEngine.sendRequest( this.tableId + '_request', this.ajaxOptions ); - */ - Prado.Callback(this.tableId, param, this.ajaxUpdate.bind(this), this.options); - this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout); - - }, - - ajaxUpdate: function(result, output) - { - try { - clearTimeout( this.timeoutHandler ); - this.buffer.update(result,this.processingRequest.bufferOffset); - this.viewPort.bufferChanged(); - } - catch(err) {} - finally {this.processingRequest = null; } - this.processQueuedRequest(); - } -}); - -Object.extend(Rico.LiveGridBuffer.prototype, -{ - update: function(newRows, start) - { - if (this.rows.length == 0) { // initial load - this.rows = newRows; - this.size = this.rows.length; - this.startPos = start; - return; - } - if (start > this.startPos) { //appending - if (this.startPos + this.rows.length < start) { - this.rows = newRows; - this.startPos = start;// - } else { - this.rows = this.rows.concat( newRows.slice(0, newRows.length)); - if (this.rows.length > this.maxBufferSize) { - var fullSize = this.rows.length; - this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length) - this.startPos = this.startPos + (fullSize - this.rows.length); - } - } - } else { //prepending - if (start + newRows.length < this.startPos) { - this.rows = newRows; - } else { - this.rows = newRows.slice(0, this.startPos).concat(this.rows); - if (this.rows.length > this.maxBufferSize) - this.rows = this.rows.slice(0, this.maxBufferSize) - } - this.startPos = start; - } - this.size = this.rows.length; - } -}); - - -Object.extend(Rico.GridViewPort.prototype, -{ - populateRow: function(htmlRow, row) - { - if(isdef(htmlRow)) - { - for (var j=0; j < row.length; j++) { - htmlRow.cells[j].innerHTML = row[j] - } - } - } -}); \ No newline at end of file diff --git a/framework/Web/Javascripts/base/scroll.js b/framework/Web/Javascripts/base/scroll.js deleted file mode 100644 index e69de29b..00000000 diff --git a/framework/Web/Javascripts/base/util.js b/framework/Web/Javascripts/base/util.js deleted file mode 100644 index 61b7d646..00000000 --- a/framework/Web/Javascripts/base/util.js +++ /dev/null @@ -1,92 +0,0 @@ -Prado.Util = {} - -/** - * Pad a number with zeros from the left. - * @param integer number - * @param integer total string length - * @return string zero padded number - */ -Prado.Util.pad = function(number, X) -{ - X = (!X ? 2 : X); - number = ""+number; - while (number.length < X) - number = "0" + number; - return number; -} - -/** - * Convert a string into integer, returns null if not integer. - * @param {string} the string to convert to integer - * @type {integer|null} null if string does not represent an integer. - */ -Prado.Util.toInteger = function(value) -{ - var exp = /^\s*[-\+]?\d+\s*$/; - if (value.match(exp) == null) - return null; - var num = parseInt(value, 10); - return (isNaN(num) ? null : num); -} - -/** - * Convert a string into a double/float value. Internationalization - * is not supported - * @param {string} the string to convert to double/float - * @param {string} the decimal character - * @return {float|null} null if string does not represent a float value - */ -Prado.Util.toDouble = function(value, decimalchar) -{ - decimalchar = undef(decimalchar) ? "." : decimalchar; - var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$"); - var m = value.match(exp); - if (m == null) - return null; - var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4]; - var num = parseFloat(cleanInput); - return (isNaN(num) ? null : num); -} - -/** - * Convert strings that represent a currency value (e.g. a float with grouping - * characters) to float. E.g. "10,000.50" will become "10000.50". The number - * of dicimal digits, grouping and decimal characters can be specified. - * The currency input format is very strict, null will be returned if - * the pattern does not match. - * @param {string} the currency value - * @param {string} the grouping character, default is "," - * @param {int} number of decimal digits - * @param {string} the decimal character, default is "." - * @type {float|null} the currency value as float. - */ -Prado.Util.toCurrency = function(value, groupchar, digits, decimalchar) -{ - groupchar = undef(groupchar) ? "," : groupchar; - decimalchar = undef(decimalchar) ? "." : decimalchar; - digits = undef(digits) ? 2 : digits; - - var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)" - + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "") - + "\\s*$"); - var m = value.match(exp); - if (m == null) - return null; - var intermed = m[2] + m[5] ; - var cleanInput = m[1] + intermed.replace( - new RegExp("(\\" + groupchar + ")", "g"), "") - + ((digits > 0) ? "." + m[7] : ""); - var num = parseFloat(cleanInput); - return (isNaN(num) ? null : num); -} - -/** - * Trim the value, if the value is undefined, empty string is return. - * @param {string} string to be trimmed. - * @type {string} trimmed string. - */ -Prado.Util.trim = function(value) -{ - if(!isString(value)) return ""; - return value.replace(/^\s+|\s+$/g, ""); -} \ No newline at end of file diff --git a/framework/Web/Javascripts/base/validation.js b/framework/Web/Javascripts/base/validation.js deleted file mode 100644 index 33d5411d..00000000 --- a/framework/Web/Javascripts/base/validation.js +++ /dev/null @@ -1,751 +0,0 @@ - -/** - * Prado client-side javascript validation class. - */ -Prado.Validation = Class.create(); - -/** - * Utilities for validation. Static class. - */ -Prado.Validation.Util = Class.create(); - -/** - * Convert a string into integer, returns null if not integer. - * @param {string} the string to convert to integer - * @type {integer|null} null if string does not represent an integer. - */ -Prado.Validation.Util.toInteger = function(value) -{ - var exp = /^\s*[-\+]?\d+\s*$/; - if (value.match(exp) == null) - return null; - var num = parseInt(value, 10); - return (isNaN(num) ? null : num); -} - -/** - * Convert a string into a double/float value. Internationalization - * is not supported - * @param {string} the string to convert to double/float - * @param {string} the decimal character - * @return {float|null} null if string does not represent a float value - */ -Prado.Validation.Util.toDouble = function(value, decimalchar) -{ - decimalchar = undef(decimalchar) ? "." : decimalchar; - var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$"); - var m = value.match(exp); - if (m == null) - return null; - var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4]; - var num = parseFloat(cleanInput); - return (isNaN(num) ? null : num); -} - -/** - * Convert strings that represent a currency value (e.g. a float with grouping - * characters) to float. E.g. "10,000.50" will become "10000.50". The number - * of dicimal digits, grouping and decimal characters can be specified. - * The currency input format is very strict, null will be returned if - * the pattern does not match. - * @param {string} the currency value - * @param {string} the grouping character, default is "," - * @param {int} number of decimal digits - * @param {string} the decimal character, default is "." - * @type {float|null} the currency value as float. - */ -Prado.Validation.Util.toCurrency = function(value, groupchar, digits, decimalchar) -{ - groupchar = undef(groupchar) ? "," : groupchar; - decimalchar = undef(decimalchar) ? "." : decimalchar; - digits = undef(digits) ? 2 : digits; - - var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)" - + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "") - + "\\s*$"); - var m = value.match(exp); - if (m == null) - return null; - var intermed = m[2] + m[5] ; - var cleanInput = m[1] + intermed.replace( - new RegExp("(\\" + groupchar + ")", "g"), "") - + ((digits > 0) ? "." + m[7] : ""); - var num = parseFloat(cleanInput); - return (isNaN(num) ? null : num); -} - -/** - * Get the date from string using the prodivided date format string. - * The format notations are - * # day -- %d or %e - * # month -- %m - * # year -- %y or %Y - * # hour -- %H, %I, %k, or %l - * # minutes -- %M - * # P.M. -- %p or %P - * @param {string} the formatted date string - * @param {string} the date format - * @type {Date} the date represented in the string - */ -Prado.Validation.Util.toDate = function(value, format) -{ - var y = 0; - var m = -1; - var d = 0; - var a = value.split(/\W+/); - var b = format.match(/%./g); - var i = 0, j = 0; - var hr = 0; - var min = 0; - for (i = 0; i < a.length; ++i) { - if (!a[i]) - continue; - switch (b[i]) { - case "%d": - case "%e": - d = parseInt(a[i], 10); - break; - - case "%m": - m = parseInt(a[i], 10) - 1; - break; - - case "%Y": - case "%y": - y = parseInt(a[i], 10); - (y < 100) && (y += (y > 29) ? 1900 : 2000); - break; - - case "%H": - case "%I": - case "%k": - case "%l": - hr = parseInt(a[i], 10); - break; - - case "%P": - case "%p": - if (/pm/i.test(a[i]) && hr < 12) - hr += 12; - break; - - case "%M": - min = parseInt(a[i], 10); - break; - } - } - if (y != 0 && m != -1 && d != 0) - { - var date = new Date(y, m, d, hr, min, 0); - return (isObject(date) - && y == date.getFullYear() - && m == date.getMonth() - && d == date.getDate()) ? date.valueOf() : null; - } - return null; -} - -/** - * Trim the value, if the value is undefined, empty string is return. - * @param {string} string to be trimmed. - * @type {string} trimmed string. - */ -Prado.Validation.Util.trim = function(value) -{ - if(undef(value)) return ""; - return value.replace(/^\s+|\s+$/g, ""); -} - -/** - * A delayed focus on a particular element - * @param {element} element to apply focus() - */ -Prado.Validation.Util.focus = function(element) -{ - var obj = $(element); - if(isObject(obj) && isdef(obj.focus)) - setTimeout(function(){ obj.focus(); }, 100); - return false; -} - -/** - * List of validator instances. - */ -Prado.Validation.validators = []; - -/** - * List of forms. - * @type {int} - */ -Prado.Validation.forms = []; - -/** - * List of summary controls. - */ -Prado.Validation.summaries = []; - -/** - * Validation groups. - */ -Prado.Validation.groups = []; - - -/** - * Second type of grouping. - */ -Prado.Validation.TargetGroups = {}; - - -/** - * Current Target group. - */ -Prado.Validation.CurrentTargetGroup = null; - -Prado.Validation.HasTargetGroup = false; - -/** - * Targets that can cause validation. - */ -Prado.Validation.ActiveTarget = null; - - -/** - * Determine if group validation is active. - */ -Prado.Validation.IsGroupValidation = false; - -/** - * Add a form for validation. - * @param {string} form ID - */ -Prado.Validation.AddForm = function(id) -{ - Prado.Validation.forms.push($(id)); -} - -/** - * Add a target that causes validation. Only elements that have been added - * can cause validation. - * @param {string} target id - */ -Prado.Validation.AddTarget = function(id, group) -{ - var target = $(id); - Event.observe(target, "click", function() - { - Prado.Validation.ActiveTarget = target; - Prado.Validation.CurrentTargetGroup = Prado.Validation.TargetGroups[id]; - }); - if(group) - { - Prado.Validation.TargetGroups[id] = group; - Prado.Validation.HasTargetGroup = true; - } -} - -/** - * Associate a list of validators to a particular control element. - * This essentially allows a set of validators to be grouped to a particular button. - * @param {list} group array show have, {group : "id", target : "target button"} - * @param {array} validator ids - */ -Prado.Validation.AddGroup = function(group, validators) -{ - group.active = false; //default active status is false. - group.target = $(group.target); - group.validators = validators; - Prado.Validation.groups.push(group); - - //update the active group when the button is clicked. - Event.observe(group.target, "click", Prado.Validation.UpdateActiveGroup); -} - -/** - * Update the active group, if call manually it will deactivate all groups. - * @param {string} - * @type {int} - */ -Prado.Validation.UpdateActiveGroup = function(ev) -{ - var groups = Prado.Validation.groups; - for (var i = 0; i < groups.length; i++) - { - groups[i].active = (isdef(ev) && groups[i].target == Event.element(ev)); - } - Prado.Validation.IsGroupValidation = isdef(ev); -} - -/** - * Determine if validation is sucessful. Iterate through the list - * of validator instances and call validate(). Only validators that - * for a particular form are evaluated. Other validators will be disabled. - * If performing group validation, only active validators are visible. - * @param {element} the form for the controls to validate. - * @type {boolean} true is all validators are valid, false otherwise. - */ -Prado.Validation.IsValid = function(form) -{ - var valid = true; - var validators = Prado.Validation.validators; - - for(var i = 0; i < validators.length; i++) - { - //prevent validating multiple forms - validators[i].enabled = !validators[i].control || undef(validators[i].control.form) || validators[i].control.form == form; - //when group validation, only validators in the active group are visible. - validators[i].visible = Prado.Validation.IsGroupValidation ? validators[i].inActiveGroup() : true; - - if(Prado.Validation.HasTargetGroup) - { - if(validators[i].group != Prado.Validation.CurrentTargetGroup) - validators[i].enabled = false; - } - - valid &= validators[i].validate(); - } - - //show the summary including the alert box - Prado.Validation.ShowSummary(form); - //reset all the group active status to false - Prado.Validation.UpdateActiveGroup(); - return valid; -} - -/** - * Base validator class. Supply a different validation function - * to obtain a different validator. E.g. to use the RequiredFieldValidator - * new Prado.Validation(Prado.Validation.RequiredFieldValidator, options); - * or to use the CustomValidator, - * new Prado.Validation(Prado.Validation.CustomValidator, options); - */ -Prado.Validation.prototype = -{ - /** - * Initialize the validator. - * @param {function} the function to call to evaluate if - * the validator is valid - * @param {string|element} the control ID or element - * @param {array} the list of attributes for the validator - */ - initialize : function(validator, attr) - { - this.evaluateIsValid = validator; - this.attr = undef(attr) ? [] : attr; - this.message = $(attr.id); - this.control = $(attr.controltovalidate); - this.enabled = isdef(attr.enabled) ? attr.enabled : true; - this.visible = isdef(attr.visible) ? attr.visible : true; - this.group = isdef(attr.validationgroup) ? attr.validationgroup : null; - this.isValid = true; - Prado.Validation.validators.push(this); - if(this.evaluateIsValid) - this.evaluateIsValid.bind(this); - }, - - /** - * Evaluate the validator only when visible and enabled. - * @type {boolean} true if valid, false otherwise. - */ - validate : function() - { - if(this.visible && this.enabled && this.evaluateIsValid) - this.isValid = this.evaluateIsValid(); - else - this.isValid = true; - - this.observe(); //watch for changes to the control values - this.update(); //update the validation messages - return this.isValid; - }, - - /** - * Hide or show the error messages for "Dynamic" displays. - */ - update : function() - { - if(this.attr.display == "Dynamic") - this.isValid ? Element.hide(this.message) : Element.show(this.message); - - if(this.message) - this.message.style.visibility = this.isValid ? "hidden" : "visible"; - - //update the control css class name - var className = this.attr.controlcssclass; - if(this.control && isString(className) && className.length>0) - Element.condClassName(this.control, className, !this.isValid); - Prado.Validation.ShowSummary(); - - var focus = this.attr.focusonerror; - var hasGroup = Prado.Validation.HasTargetGroup; - var inGroup = this.group == Prado.Validation.CurrentTargetGroup; - - if(focus && (!hasGroup || (hasGroup && inGroup))) - Prado.Element.focus(this.attr.focuselementid); - }, - - /** - * Change the validity of the validator, calls update(). - * @param {boolean} change the isValid state of the validator. - */ - setValid : function(valid) - { - this.isValid = valid; - this.update(); - }, - - /** - * Observe changes to the control values, add "onchange" event to the control once. - */ - observe : function() - { - if(undef(this.observing)) - { - if(this.control && this.control.form) - Event.observe(this.control, "change", this.validate.bind(this)); - this.observing = true; - } - }, - - /** - * Convert the value of the control to a specific data type. - * @param {string} the data type, "Integer", "Double", "Currency" or "Date". - * @param {string} the value to convert, null to get the value from the control. - * @type {mixed|null} the converted data value. - */ - convert : function(dataType, value) - { - if(undef(value)) - value = Form.Element.getValue(this.control); - switch(dataType) - { - case "Integer": - return Prado.Validation.Util.toInteger(value); - case "Double" : - case "Float" : - return Prado.Validation.Util.toDouble(value, this.attr.decimalchar); - case "Currency" : - return Prado.Validation.Util.toCurrency( - value, this.attr.groupchar, this.attr.digits, this.attr.decimalchar); - case "Date": - return Prado.Validation.Util.toDate(value, this.attr.dateformat); - } - return value.toString(); - }, - - /** - * Determine if the current validator is part of a active validation group. - * @type {boolean} true if part of active validation group, false otherwise. - */ - inActiveGroup : function() - { - var groups = Prado.Validation.groups; - for (var i = 0; i < groups.length; i++) - { - if(groups[i].active && groups[i].validators.contains(this.attr.id)) - return true; - } - return false; - } -} - -/** - * Validation summary class. - */ -Prado.Validation.Summary = Class.create(); -Prado.Validation.Summary.prototype = -{ - /** - * Initialize a validation summary. - * @param {array} summary options. - */ - initialize : function(attr) - { - this.attr = attr; - this.div = $(attr.id); - this.visible = false; - this.enabled = false; - this.group = isdef(attr.validationgroup) ? attr.validationgroup : null; - Prado.Validation.summaries.push(this); - }, - - /** - * Show the validation summary. - * @param {boolean} true to allow alert message - */ - show : function(warn) - { - var refresh = warn || this.attr.refresh == "1"; - var messages = this.getMessages(); - if(messages.length <= 0 || !this.visible || !this.enabled) - { - if(refresh) - Element.hide(this.div); - return; - } - - if(Prado.Validation.HasTargetGroup) - { - if(Prado.Validation.CurrentTargetGroup != this.group) - { - if(refresh) - Element.hide(this.div); - return; - } - } - - if(this.attr.showsummary != "False" && refresh) - { - //Element.show(this.div); - this.div.style.display = "block"; - while(this.div.childNodes.length > 0) - this.div.removeChild(this.div.lastChild); - new Insertion.Bottom(this.div, this.formatSummary(messages)); - } - - if(warn) - window.scrollTo(this.div.offsetLeft-20, this.div.offsetTop-20); - - var summary = this; - if(warn && this.attr.showmessagebox == "True" && refresh) - setTimeout(function(){alert(summary.formatMessageBox(messages));},20); - }, - - /** - * Get a list of error messages from the validators. - * @type {array} list of messages - */ - getMessages : function() - { - var validators = Prado.Validation.validators; - var messages = []; - for(var i = 0; i < validators.length; i++) - { - if(validators[i].isValid == false - && isString(validators[i].attr.errormessage) - && validators[i].attr.errormessage.length > 0) - { - - messages.push(validators[i].attr.errormessage); - } - } - return messages; - }, - - /** - * 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 : "
  • ", post : "
  • ", last : "
"}; - } - }, - - /** - * Format the message summary. - * @param {array} list of error messages. - * @type {string} formatted message - */ - formatSummary : function(messages) - { - var format = this.formats(this.attr.displaymode); - var output = isdef(this.attr.headertext) ? this.attr.headertext + format.header : ""; - output += format.first; - 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 = isdef(this.attr.headertext) ? this.attr.headertext + "\n" : ""; - for(var i = 0; i < messages.length; i++) - { - switch(this.attr.displaymode) - { - case "List": - output += messages[i] + "\n"; - break; - case "BulletList": - default: - output += " - " + messages[i] + "\n"; - break; - case "SingleParagraph": - output += messages[i] + " "; - break; - } - } - return output; - }, - - /** - * Determine if this summary belongs to an active group. - * @type {boolean} true if belongs to an active group. - */ - inActiveGroup : function() - { - var groups = Prado.Validation.groups; - for (var i = 0; i < groups.length; i++) - { - if(groups[i].active && groups[i].id == this.attr.group) - return true; - } - return false; - } -} - -/** - * Show the validation error message summary. - * @param {element} the form that activated the summary call. - */ -Prado.Validation.ShowSummary = function(form) -{ - var summary = Prado.Validation.summaries; - for(var i = 0; i < summary.length; i++) - { - if(isdef(form)) - { - if(Prado.Validation.IsGroupValidation) - { - summary[i].visible = summary[i].inActiveGroup(); - } - else - { - summary[i].visible = undef(summary[i].attr.group); - } - - summary[i].enabled = $(summary[i].attr.form) == form; - } - summary[i].show(form); - } -} - - - -/** - * When a form is try to submit, check the validators, submit - * the form only when all validators are valid. - * @param {event} form submit event. - */ -Prado.Validation.OnSubmit = function(ev) -{ - //HTML text editor, tigger save first. - //alert(tinyMCE); - if(typeof tinyMCE != "undefined") - tinyMCE.triggerSave(); - - //no active target? - if(!Prado.Validation.ActiveTarget) return true; - var valid = Prado.Validation.IsValid(Event.element(ev) || ev); - - //not valid? do not submit the form - if(Event.element(ev) && !valid) - Event.stop(ev); - - //reset the target - Prado.Validation.ActiveTarget = null; - //Prado.Validation.CurrentTargetGroup = null; - - return valid; -} - -/** - * During window onload event, attach onsubmit event for each of the - * forms in Prado.Validation.forms. - */ -Prado.Validation.OnLoad = function() -{ - Event.observe(Prado.Validation.forms,"submit", Prado.Validation.OnSubmit); -} - - -/** - * Validate Validator Groups. - * @param string ValidatorGroup - * @return boolean true if valid, false otherwise - */ -Prado.Validation.ValidateValidatorGroup = function(groupId) -{ - var groups = Prado.Validation.groups; - var group = null; - for(var i = 0; i < groups.length; i++) - { - if(groups[i].id == groupId) - { - group = groups[i]; - Prado.Validation.groups[i].active = true; - Prado.Validation.CurrentTargetGroup = null; - Prado.Validation.IsGroupValidation = true; - } - else - { - Prado.Validation.groups[i].active = false; - } - } - if(group) - { - return Prado.Validation.IsValid(group.target.form); - } - return true; -}; - -/** - * Validate ValidationGroup - * @param string ValidationGroup - * @return boolean true if valid, false otherwise. - */ -Prado.Validation.ValidateValidationGroup= function(groupId) -{ - var groups = Prado.Validation.TargetGroups; - for(var id in groups) - { - if(groups[id] == groupId) - { - var target = $(id); - Prado.Validation.ActiveTarget = target; - Prado.Validation.CurrentTargetGroup = groupId; - Prado.Validation.IsGroupValidation = false; - return Prado.Validation.IsValid(target.form); - } - } - return true; -}; - -/** - * Validate the page - * @return boolean true if valid, false otherwise. - */ -Prado.Validation.ValidateNonGroup= function(formId) -{ - if(Prado.Validation) - { - var form = $(formId); - form = form || document.forms[0]; - Prado.Validation.ActiveTarget = form; - Prado.Validation.CurrentTargetGroup = null; - Prado.Validation.IsGroupValidation = false; - return Prado.Validation.IsValid(form); - } - return true; -}; - - - -/** - * Register Prado.Validation.Onload() for window.onload event. - */ -Event.OnLoad(Prado.Validation.OnLoad); \ No newline at end of file diff --git a/framework/Web/Javascripts/base/validators.js b/framework/Web/Javascripts/base/validators.js deleted file mode 100644 index 427b46fc..00000000 --- a/framework/Web/Javascripts/base/validators.js +++ /dev/null @@ -1,225 +0,0 @@ - -Prado.Validation.TRequiredFieldValidator=function(){ - var inputType = this.control.getAttribute("type"); - if(inputType == 'file'){ - return true; - } - else{ - var trim=Prado.Util.trim; - var a=trim(Form.Element.getValue(this.control)); - var b=trim(this.attr.initialvalue); - return(a!=b); - } -} - - -Prado.Validation.TRegularExpressionValidator = function() -{ - var trim = Prado.Util.trim; - var value = trim(Form.Element.getValue(this.control)); - if (value == "") return true; - var rx = new RegExp(this.attr.validationexpression); - var matches = rx.exec(value); - return (matches != null && value == matches[0]); -} - -Prado.Validation.TEmailAddressValidator = Prado.Validation.TRegularExpressionValidator; - -Prado.Validation.TCustomValidator = function() -{ - var value = isNull(this.control) ? null : $F(this.control); - var func = this.attr.clientvalidationfunction; - eval("var validate = "+func); - return validate && isFunction(validate) ? validate(this, value) : true; -} - -Prado.Validation.TRangeValidator = function() -{ - var trim = Prado.Util.trim; - var value = trim(Form.Element.getValue(this.control)); - if (value == "") return true; - - var minval = this.attr.minimumvalue; - var maxval = this.attr.maximumvalue; - - if (undef(minval) && undef(maxval)) - return true; - - if (minval == "") minval = 0; - if (maxval == "") maxval = 0; - - var dataType = this.attr.type; - - if(undef(dataType)) - return (parseFloat(value) >= parseFloat(minval)) && (parseFloat(value) <= parseFloat(maxval)); - - //now do datatype range check. - var min = this.convert(dataType, minval); - var max = this.convert(dataType, maxval); - value = this.convert(dataType, value); - return value >= min && value <= max; -} - -Prado.Validation.TCompareValidator = function() -{ - var trim = Prado.Util.trim; - var value = trim(Form.Element.getValue(this.control)); - if (value.length == 0) return true; - - var compareTo; - - var comparee = $(this.attr.controlhookup);; - - if(comparee) - compareTo = trim(Form.Element.getValue(comparee)); - else - { - compareTo = isString(this.attr.valuetocompare) ? this.attr.valuetocompare : ""; - } - - var compare = Prado.Validation.TCompareValidator.compare; - - var isValid = compare.bind(this)(value, compareTo); - - //update the comparee control css class name and add onchange event once. - if(comparee) - { - var className = this.attr.controlcssclass; - if(isString(className) && className.length>0) - Element.condClassName(comparee, className, !isValid); - if(undef(this.observingComparee)) - { - Event.observe(comparee, "change", this.validate.bind(this)); - this.observingComparee = true; - } - } - return isValid; -} - -/** - * Compare the two values, also performs data type check. - * @param {string} value to compare with - * @param {string} value to compare - * @type {boolean} true if comparison or type check is valid, false otherwise. - */ -Prado.Validation.TCompareValidator.compare = function(operand1, operand2) -{ - var op1, op2; - if ((op1 = this.convert(this.attr.type, operand1)) == null) - return false; - if (this.attr.operator == "DataTypeCheck") - return true; - if ((op2 = this.convert(this.attr.type, operand2)) == null) - return true; - switch (this.attr.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); - } -} - -Prado.Validation.TRequiredListValidator = function() -{ - var min = undef(this.attr.min) ? Number.NEGATIVE_INFINITY : parseInt(this.attr.min); - var max = undef(this.attr.max) ? Number.POSITIVE_INFINITY : parseInt(this.attr.max); - - var elements = document.getElementsByName(this.attr.selector); - - if(elements.length <= 0) - elements = document.getElementsBySelector(this.attr.selector); - - if(elements.length <= 0) - return true; - - var required = new Array(); - if(isString(this.attr.required) && this.attr.required.length > 0) - required = this.attr.required.split(/,\s* /); - - var isValid = true; - - var validator = Prado.Validation.TRequiredListValidator; - - switch(elements[0].type) - { - case 'radio': - case 'checkbox': - isValid = validator.IsValidRadioList(elements, min, max, required); - break; - case 'select-multiple': - isValid = validator.IsValidSelectMultipleList(elements, min, max, required); - break; - } - - var className = this.attr.elementcssclass; - if(isString(className) && className.length>0) - map(elements, function(element){ condClass(element, className, !isValid); }); - if(undef(this.observingRequiredList)) - { - Event.observe(elements, "change", this.validate.bind(this)); - this.observingRequiredList = true; - } - return isValid; -} - -//radio group selection -Prado.Validation.TRequiredListValidator.IsValidRadioList = function(elements, min, max, required) -{ - var checked = 0; - var values = new Array(); - for(var i = 0; i < elements.length; i++) - { - if(elements[i].checked) - { - checked++; - values.push(elements[i].value); - } - } - return Prado.Validation.TRequiredListValidator.IsValidList(checked, values, min, max, required); -} - -//multiple selection check -Prado.Validation.TRequiredListValidator.IsValidSelectMultipleList = function(elements, min, max, required) -{ - var checked = 0; - var values = new Array(); - for(var i = 0; i < elements.length; i++) - { - var selection = elements[i]; - for(var j = 0; j < selection.options.length; j++) - { - if(selection.options[j].selected) - { - checked++; - values.push(selection.options[j].value); - } - } - } - return Prado.Validation.TRequiredListValidator.IsValidList(checked, values, min, max, required); -} - -//check if the list was valid -Prado.Validation.TRequiredListValidator.IsValidList = function(checkes, values, min, max, required) -{ - var exists = true; - - if(required.length > 0) - { - //required and the values must at least be have same lengths - if(values.length < required.length) - return false; - for(var k = 0; k < required.length; k++) - exists = exists && values.contains(required[k]); - } - - return exists && checkes >= min && checkes <= max; -} diff --git a/framework/Web/Javascripts/extended/array.js b/framework/Web/Javascripts/extended/array.js deleted file mode 100644 index 2aeb9084..00000000 --- a/framework/Web/Javascripts/extended/array.js +++ /dev/null @@ -1,465 +0,0 @@ -/** -ARRAY EXTENSIONS -by Caio Chassot (http://v2studio.com/k/code/) -*/ - -//function v2studio_com_code() -//{ - - -/** - * Searches Array for value. - * returns the index of the first item - * which matches value, or -1 if not found. - * searching starts at index 0, or at start, if specified. - * - * Here are the rules for an item to match value - * if strict is false or not specified (default): - * if value is a: - * # function -> value(item) must be true - * # RegExp -> value.test(item) must be true - * # anything else -> item == value must be true - * @param value the value (function, regexp) to search - * @param start where to start the search - * @param strict use strict comparison (===) for everything - */ -Array.prototype.indexOf = function(value, start, strict) { - start = start || 0; - for (var i=start; ivalue returns the first matched item, or null if not found - * Parameters work the same as indexOf - * @see #indexOf - */ -Array.prototype.find = function(value, start, strict) { - var i = this.indexOf(value, start, strict); - if (i != -1) return this[i]; - return null -} - - - -/* A.contains(value [, strict]) -/** - * aliases: has, include - * returns true if value is found in Array, otherwise false; - * relies on indexOf, see its doc for details on value and strict - * @see #indexOf - */ -Array.prototype.contains = function(value,strict) { - return this.indexOf(value,0,strict) !== -1; -} - - -Array.prototype.has = Array.prototype.contains; - -Array.prototype.include = Array.prototype.contains; - - -/** - * counts occurences of value in Array - * relies on indexOf, see its doc for details on value and strict - * @see #indexOf - */ -Array.prototype.count = function(value, strict) { - var pos, start = 0, count = 0; - while ((pos = this.indexOf(value, start, strict)) !== -1) { - start = pos + 1; - count++; - } - return count; -} - - -/** - * if all is false or not provied: - * removes first occurence of value from Array - * if all is provided and true: - * removes all occurences of value from Array - * returns the array - * relies on indexOf, see its doc for details on value and strict - * @see #indexOf - */ -Array.prototype.remove = function(value,all,strict) { - while (this.contains(value,strict)) { - this.splice(this.indexOf(value,0,strict),1); - if (!all) break - } - return this; -} - - - -/* A.merge(a [, a]*) - Append the contents of provided arrays into the current - takes: one or more arrays - returns: current array (modified) -*/ -Array.prototype.merge = function() { - var a = []; - for (var i=0; i -*/ -Array.prototype.min = function() { - if (!this.length) return; - var n = this[0]; - for (var i=1; ithis[i]) n=this[i]; - return n; -} - - - -/* A.min() - returns the graetest item in array by comparing them with < -*/ -Array.prototype.max = function() { - if (!this.length) return; - var n = this[0]; - for (var i=1; i 0; -} - - - -/* A.each(fn) - method form of each function -*/ -Array.prototype.each = function(fn) { return each(this, fn) } - - - -/* A.map([fn]) - method form of map function -*/ -Array.prototype.map = function(fn) { return map(this, fn) } - - - -/* A.filter([fn]) - method form of filter function -*/ -Array.prototype.filter = function(fn) { return filter(this, fn) } - - -Array.prototype.select = Array.prototype.filter - - -/* A.reduce([initial,] fn) - method form of filter function -*/ -Array.prototype.reduce = function() { - var args = map(arguments); - fn = args.pop(); - d = args.pop(); - return reduce(this, d, fn); -} - - -Array.prototype.inject = Array.prototype.reduce - - - -/* A.reject(fn) - deletes items in A *in place* for which fn(item) is true - returns a -*/ -Array.prototype.reject = function(fn) { - if (typeof(fn)=='string') fn = __strfn('item,idx,list', fn); - var self = this; - var itemsToRemove = []; - fn = fn || function(v) {return v}; - map(self, function(item,idx,list) { if (fn(item,idx,list)) itemsToRemove.push(idx) } ); - itemsToRemove.reverse().each(function(idx) { self.splice(idx,1) }); - return self; -} - - - -/* __strfn(args, fn) - this is used internally by each, map, combine, filter and reduce to accept - strings as functions. - - takes: - `args` -> a string of comma separated names of the function arguments - `fn` -> the function body - - if `fn` does not contain a return statement, a return keyword will be added - before the last statement. the last statement is determined by removing the - trailing semicolon (';') (if it exists) and then searching for the last - semicolon, hence, caveats may apply (i.e. if the last statement has a - string or regex containing the ';' character things will go wrong) -*/ -function __strfn(args, fn) { - function quote(s) { return '"' + s.replace(/"/g,'\\"') + '"' } - if (!/\breturn\b/.test(fn)) { - fn = fn.replace(/;\s*$/, ''); - fn = fn.insert(fn.lastIndexOf(';')+1, ' return '); - } - return eval('new Function(' - + map(args.split(/\s*,\s*/), quote).join() - + ',' - + quote(fn) - + ')' - ); -} - - - -/* each(list, fn) - traverses `list`, applying `fn` to each item of `list` - takes: - `list` -> anything that can be indexed and has a `length` property. - usually an array. - `fn` -> either a function, or a string containing a function body, - in which case the name of the paremeters passed to it will be - 'item', 'idx' and 'list'. - se doc for `__strfn` for peculiarities about passing strings - for `fn` - - `each` provides a safe way for traversing only an array's indexed items, - ignoring its other properties. (as opposed to how for-in works) -*/ -function each(list, fn) { - if (typeof(fn)=='string') return each(list, __strfn('item,idx,list', fn)); - for (var i=0; i < list.length; i++) fn(list[i], i, list); -} - - -/* map(list [, fn]) - traverses `list`, applying `fn` to each item of `list`, returning an array - of values returned by `fn` - - parameters work the same as for `each`, same `__strfn` caveats apply - - if `fn` is not provided, the list item is returned itself. this is an easy - way to transform fake arrays (e.g. the arguments object of a function or - nodeList objects) into real javascript arrays. - e.g.: args = map(arguments) - - If you don't care about map's return value, you should use `each` - - this is a simplified version of python's map. parameter order is different, - only a single list (array) is accepted, and the parameters passed to [fn] - are different: - [fn] takes the current item, then, optionally, the current index and a - reference to the list (so that [fn] can modify list) - see `combine` if you want to pass multiple lists -*/ -function map(list, fn) { - if (typeof(fn)=='string') return map(list, __strfn('item,idx,list', fn)); - - var result = []; - fn = fn || function(v) {return v}; - for (var i=0; i < list.length; i++) result.push(fn(list[i], i, list)); - return result; -} - - -/* combine(list [, list]* [, fn]) - - takes: - `list`s -> one or more lists (see `each` for definition of a list) - `fn` -> Similar s `each` or `map`, a function or a string containing - a function body. - if a string is used, the name of parameters passed to the - created function will be the lowercase alphabet letters, in - order: a,b,c... - same `__strfn` caveats apply - - combine will traverse all lists concurrently, passing each row if items as - parameters to `fn` - if `fn` is not provided, a function that returns a list containing each - item in the row is used. - if a list is smaller than the other, `null` is used in place of its missing - items - - returns: - an array of the values returned by calling `fn` for each row of items -*/ -function combine() { - var args = map(arguments); - var lists = map(args.slice(0,-1),'map(item)'); - var fn = args.last(); - var toplen = map(lists, "item.length").max(); - var vals = []; - - if (!fn) fn = function(){return map(arguments)}; - if (typeof fn == 'string') { - if (lists.length > 26) throw 'string functions can take at most 26 lists'; - var a = 'a'.charCodeAt(0); - fn = __strfn(map(range(a, a+lists.length),'String.fromCharCode(item)').join(','), fn); - } - - map(lists, function(li) { - while (li.length < toplen) li.push(null); - map(li, function(item,ix){ - if (ix < vals.length) vals[ix].push(item); - else vals.push([item]); - }); - }); - - return map(vals, function(val) { return fn.apply(fn, val) }); -} - - - -/* filter(list [, fn]) - returns an array of items in `list` for which `fn(item)` is true - - parameters work the same as for `each`, same `__strfn` caveats apply - - if `fn` is not specified the items are evaluated themselves, that is, - filter will return an array of the items in `list` which evaluate to true - - this is a similar to python's filter, but parameter order is inverted -*/ -function filter(list, fn) { - if (typeof(fn)=='string') return filter(list, __strfn('item,idx,list', fn)); - - var result = []; - fn = fn || function(v) {return v}; - map(list, function(item,idx,list) { if (fn(item,idx,list)) result.push(item) } ); - return result; -} - - - -/* reduce(list [, initial], fn) - similar to python's reduce. paremeter onder inverted... - - TODO: document this properly - - takes: - `list` -> see doc for `each` to learn more about it - `inirial -> TODO: doc` - `fn` -> similar to `each` too, but in the case where it's a string, - the name of the paremeters passed to it will be 'a' and 'b' - same `__strfn` caveats apply - -*/ -function reduce(list, initial, fn) { - if (undef(fn)) { - fn = initial; - initial = window.undefined; // explicit `window` object so browsers that do not have an `undefined` keyword will evaluate to the (hopefully) undefined parameter `undefined` of `window` - } - if (typeof(fn)=='string') return reduce(list, initial, __strfn('a,b', fn)); - if (isdef(initial)) list.splice(0,0,initial); - if (list.length===0) return false; - if (list.length===1) return list[0]; - var result = list[0]; - var i = 1; - while(ifn does not contain a return statement, a return keyword will be added - * before the last statement. the last statement is determined by removing the - * trailing semicolon (';') (if it exists) and then searching for the last - * semicolon, hence, caveats may apply (i.e. if the last statement has a - * string or regex containing the ';' character things will go wrong) - * @param args a string of comma separated names of the function arguments - * @param fn the function body - */ -function __strfn(args, fn) { - /** - * Internal function. Do not call it directly. - */ - function quote(s) { return '"' + s.replace(/"/g,'\\"') + '"' } - if (!/\breturn\b/.test(fn)) { - fn = fn.replace(/;\s*$/, ''); - fn = fn.insert(fn.lastIndexOf(';')+1, ' return '); - } - return eval('new Function(' - + map(args.split(/\s*,\s*/), quote).join() - + ',' - + quote(fn) - + ')' - ); -} - - -/** - * traverses list, applying fn to each item of list. - * see doc for __strfn for peculiarities about passing strings for fn - * - * each provides a safe way for traversing only an array's indexed items, - * ignoring its other properties. (as opposed to how for-in works) - * @param list anything that can be indexed and has a length property. usually an array. - * @param fn either a function, or a string containing a function body, - * in which case the name of the paremeters passed to it will be - * 'item', 'idx' and 'list'. - * @see #__strfn - */ -function each(list, fn) { - if (typeof(fn)=='string') return each(list, __strfn('item,idx,list', fn)); - for (var i=0; i < list.length; i++) fn(list[i], i, list); -} - - -/** - * traverses list, applying fn to each item of list, returning an array - of values returned by fn - - parameters work the same as for each, same __strfn caveats apply - - if fn is not provided, the list item is returned itself. this is an easy - way to transform fake arrays (e.g. the arguments object of a function or - nodeList objects) into real javascript arrays. - e.g.: args = map(arguments) - - If you don't care about map's return value, you should use each - - this is a simplified version of python's map. parameter order is different, - only a single list (array) is accepted, and the parameters passed to [fn] - are different: - [fn] takes the current item, then, optionally, the current index and a - reference to the list (so that [fn] can modify list) - see combine if you want to pass multiple lists - */ -function map(list, fn) { - if (typeof(fn)=='string') return map(list, __strfn('item,idx,list', fn)); - - var result = []; - fn = fn || function(v) {return v}; - for (var i=0; i < list.length; i++) result.push(fn(list[i], i, list)); - return result; -} - - -/** - * combine will traverse all lists concurrently, passing each row if items as - parameters to fn - if fn is not provided, a function that returns a list containing each - item in the row is used. - if a list is smaller than the other, null is used in place of its missing - items - * @param list one or more lists (see each for definition of a list) - * @param fn Similar s each or map, a function or a string containing - a function body. - if a string is used, the name of parameters passed to the - created function will be the lowercase alphabet letters, in - order: a,b,c... - same __strfn caveats apply - * @see #each - * @see #__strfn - * @return an array of the values returned by calling fn for each row of items - *//* -function combine() { - var args = map(arguments); - var lists = map(args.slice(0,-1),'map(item)'); - var fn = args.last(); - var toplen = map(lists, "item.length").max(); - var vals = []; - - if (!fn) fn = function(){return map(arguments)}; - if (typeof fn == 'string') { - if (lists.length > 26) throw 'string functions can take at most 26 lists'; - var a = 'a'.charCodeAt(0); - fn = __strfn(map(range(a, a+lists.length),'String.fromCharCode(item)').join(','), fn); - } - - map(lists, function(li) { - while (li.length < toplen) li.push(null); - map(li, function(item,ix){ - if (ix < vals.length) vals[ix].push(item); - else vals.push([item]); - }); - }); - - return map(vals, function(val) { return fn.apply(fn, val) }); -} - -/** - * returns an array of items in list for which fn(item) is true - - parameters work the same as for each, same __strfn caveats apply - - if fn is not specified the items are evaluated themselves, that is, - filter will return an array of the items in list which evaluate to true - - this is a similar to python's filter, but parameter order is inverted - *//* -function filter(list, fn) { - if (typeof(fn)=='string') return filter(list, __strfn('item,idx,list', fn)); - - var result = []; - fn = fn || function(v) {return v}; - map(list, function(item,idx,list) { if (fn(item,idx,list)) result.push(item) } ); - return result; -} - -/** - * similar to python's reduce. paremeter order inverted... - * @param list see doc for each to learn more about it - * @param initial TODO - * @param fn similar to each too, but in the case where it's a string, - the name of the paremeters passed to it will be 'a' and 'b' - same __strfn caveats apply - *//* -function reduce(list, initial, fn) { - if (undef(fn)) { - fn = initial; - // explicit window object so browsers that do not have an undefined - //keyword will evaluate to the (hopefully) undefined parameter - //undefined of window - initial = window.undefined; - } - if (typeof(fn)=='string') return reduce(list, initial, __strfn('a,b', fn)); - if (isdef(initial)) list.splice(0,0,initial); - if (list.length===0) return false; - if (list.length===1) return list[0]; - var result = list[0]; - var i = 1; - while(iInternationalization + * is not supported + * @param {string} the string to convert to double/float + * @param {string} the decimal character + * @return {float|null} null if string does not represent a float value + */ +Prado.Util.toDouble = function(value, decimalchar) +{ + decimalchar = undef(decimalchar) ? "." : decimalchar; + var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$"); + var m = value.match(exp); + if (m == null) + return null; + var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4]; + var num = parseFloat(cleanInput); + return (isNaN(num) ? null : num); +} + +/** + * Convert strings that represent a currency value (e.g. a float with grouping + * characters) to float. E.g. "10,000.50" will become "10000.50". The number + * of dicimal digits, grouping and decimal characters can be specified. + * The currency input format is very strict, null will be returned if + * the pattern does not match. + * @param {string} the currency value + * @param {string} the grouping character, default is "," + * @param {int} number of decimal digits + * @param {string} the decimal character, default is "." + * @type {float|null} the currency value as float. + */ +Prado.Util.toCurrency = function(value, groupchar, digits, decimalchar) +{ + groupchar = undef(groupchar) ? "," : groupchar; + decimalchar = undef(decimalchar) ? "." : decimalchar; + digits = undef(digits) ? 2 : digits; + + var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)" + + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "") + + "\\s*$"); + var m = value.match(exp); + if (m == null) + return null; + var intermed = m[2] + m[5] ; + var cleanInput = m[1] + intermed.replace( + new RegExp("(\\" + groupchar + ")", "g"), "") + + ((digits > 0) ? "." + m[7] : ""); + var num = parseFloat(cleanInput); + return (isNaN(num) ? null : num); +} + +/** + * Trim the value, if the value is undefined, empty string is return. + * @param {string} string to be trimmed. + * @type {string} trimmed string. + */ +Prado.Util.trim = function(value) +{ + if(!isString(value)) return ""; + return value.replace(/^\s+|\s+$/g, ""); +} diff --git a/framework/Web/Javascripts/extra/tp_template.js b/framework/Web/Javascripts/extra/tp_template.js deleted file mode 100644 index 6015034c..00000000 --- a/framework/Web/Javascripts/extra/tp_template.js +++ /dev/null @@ -1,315 +0,0 @@ -/** - * TrimPath Template. Release 1.0.16. - * Copyright (C) 2004, 2005 Metaha. - * - * TrimPath Template is licensed under the GNU General Public License - * and the Apache License, Version 2.0, as follows: - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed WITHOUT ANY WARRANTY; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -var TrimPath; - -// TODO: Debugging mode vs stop-on-error mode - runtime flag. -// TODO: Handle || (or) characters and backslashes. -// TODO: Add more modifiers. - -(function() { // Using a closure to keep global namespace clean. - var theEval = eval; // Security, to ensure eval cleanliness. - if (TrimPath == null) - TrimPath = new Object(); - if (TrimPath.evalEx == null) - TrimPath.evalEx = function(src) { return theEval(src); }; - - TrimPath.parseTemplate = function(tmplContent, optTmplName, optEtc) { - if (optEtc == null) - optEtc = TrimPath.parseTemplate_etc; - var funcSrc = parse(tmplContent, optTmplName, optEtc); - var func = TrimPath.evalEx(funcSrc, optTmplName, 1); - if (func != null) - return new optEtc.Template(optTmplName, tmplContent, funcSrc, func, optEtc); - return null; - } - - try { - String.prototype.process = function(context, optFlags) { - var template = TrimPath.parseTemplate(this, null); - if (template != null) - return template.process(context, optFlags); - return this; - } - } catch (e) { // Swallow exception, such as when String.prototype is sealed. - } - - TrimPath.parseTemplate_etc = {}; // Exposed for extensibility. - TrimPath.parseTemplate_etc.statementTag = "forelse|for|if|elseif|else|var|macro"; - TrimPath.parseTemplate_etc.statementDef = { // Lookup table for statement tags. - "if" : { delta: 1, prefix: "if (", suffix: ") {", paramMin: 1 }, - "else" : { delta: 0, prefix: "} else {" }, - "elseif" : { delta: 0, prefix: "} else { if (", suffix: ") {", paramDefault: "true" }, - "/if" : { delta: -1, prefix: "}" }, - "for" : { delta: 1, paramMin: 3, - prefixFunc : function(stmtParts, state, tmplName, etc) { - if (stmtParts[2] != "in") - throw new etc.ParseError(tmplName, state.line, "bad for loop statement: " + stmtParts.join(' ')); - var iterVar = stmtParts[1]; - var listVar = "__LIST__" + iterVar; - return [ "var ", listVar, " = ", stmtParts[3], ";", - "if ((", listVar, ") != null && (", listVar, ").length > 0) { for (var ", - iterVar, "_index in ", listVar, ") { var ", - iterVar, " = ", listVar, "[", iterVar, "_index];" ].join(""); - } }, - "forelse" : { delta: 0, prefix: "} } else { if (", suffix: ") {", paramDefault: "true" }, - "/for" : { delta: -1, prefix: "} }" }, - "var" : { delta: 0, prefix: "var ", suffix: ";" }, - "macro" : { delta: 1, prefix: "function ", suffix: "{ var _OUT_arr = []; var _OUT = { write: function(m) { if (m) _OUT_arr.push(m); }, }; " }, - "/macro" : { delta: -1, prefix: " return _OUT_arr.join(''); }" } - } - TrimPath.parseTemplate_etc.modifierDef = { - "eat" : function(v) { return ""; }, - "escape" : function(s) { return String(s).replace(/&/g, "&").replace(//g, ">"); }, - "capitalize" : function(s) { return String(s).toUpperCase(); }, - "default" : function(s, d) { return s != null ? s : d; } - } - TrimPath.parseTemplate_etc.modifierDef.h = TrimPath.parseTemplate_etc.modifierDef.escape; - - TrimPath.parseTemplate_etc.Template = function(tmplName, tmplContent, funcSrc, func, etc) { - this.process = function(context, flags) { - if (context == null) - context = {}; - if (context._MODIFIERS == null) - context._MODIFIERS = {}; - for (var k in etc.modifierDef) { - if (context._MODIFIERS[k] == null) - context._MODIFIERS[k] = etc.modifierDef[k]; - } - if (flags == null) - flags = {}; - var resultArr = []; - var resultOut = { write: function(m) { if (m) resultArr.push(m); } }; - try { - func(resultOut, context, flags); - } catch (e) { - if (flags.throwExceptions == true) - throw e; - var result = new String(resultArr.join("") + "[ERROR: " + e.toString() + "]"); - result["exception"] = e; - return result; - } - return resultArr.join(""); - } - this.name = tmplName; - this.source = tmplContent; - this.sourceFunc = funcSrc; - this.toString = function() { return "TrimPath.Template [" + tmplName + "]"; } - } - TrimPath.parseTemplate_etc.ParseError = function(name, line, message) { - this.name = name; - this.line = line; - this.message = message; - } - TrimPath.parseTemplate_etc.ParseError.prototype.toString = function() { - return ("TrimPath template ParseError in " + this.name + ": line " + this.line + ", " + this.msg); - } - - var parse = function(body, tmplName, etc) { - body = cleanWhiteSpace(body); - var funcText = [ "var TrimPath_Template_TEMP = function(_OUT, _CONTEXT, _FLAGS) { with (_CONTEXT) {" ]; - var state = { stack: [], line: 1 }; // TODO: Fix line number counting. - var endStmtPrev = -1; - while (endStmtPrev + 1 < body.length) { - var begStmt = endStmtPrev; - // Scan until we find some statement markup. - begStmt = body.indexOf("{", begStmt + 1); - while (begStmt >= 0) { - if (body.charAt(begStmt - 1) != '$' && // Not an expression or backslashed, - body.charAt(begStmt - 1) != '\\') { // so we assume it must be a statement tag. - var offset = (body.charAt(begStmt + 1) == '/' ? 2 : 1); // Close tags offset of 2 skips '/'. - // 10 is larger than maximum statement tag length. - if (body.substring(begStmt + offset, begStmt + 10 + offset).search(TrimPath.parseTemplate_etc.statementTag) == 0) - break; // Found a match. - } - begStmt = body.indexOf("{", begStmt + 1); - } - if (begStmt < 0) // In "a{for}c", begStmt will be 1. - break; - var endStmt = body.indexOf("}", begStmt + 1); // In "a{for}c", endStmt will be 5. - if (endStmt < 0) - break; - emitSectionText(body.substring(endStmtPrev + 1, begStmt), funcText); - emitStatement(body.substring(begStmt, endStmt +1), state, funcText, tmplName, etc); - endStmtPrev = endStmt; - } - emitSectionText(body.substring(endStmtPrev + 1), funcText); - if (state.stack.length != 0) - throw new etc.ParseError(tmplName, state.line, "unclosed, unmatched statement(s): " + state.stack.join(",")); - funcText.push("}}; TrimPath_Template_TEMP"); - return funcText.join(""); - } - - var emitStatement = function(stmtStr, state, funcText, tmplName, etc) { - var parts = stmtStr.slice(1, -1).split(' '); - var stmt = etc.statementDef[parts[0]]; // Here, parts[0] == for/if/else/... - if (stmt == null) { // Not a real statement. - emitSectionText(stmtStr, funcText); - return; - } - if (stmt.delta < 0) { - if (state.stack.length <= 0) - throw new etc.ParseError(tmplName, state.line, "close tag does not match any previous statement: " + stmtStr); - state.stack.pop(); - } - if (stmt.delta > 0) - state.stack.push(stmtStr); - - if (stmt.paramMin != null && - stmt.paramMin >= parts.length) - throw new etc.ParseError(tmplName, state.line, "statement needs more parameters: " + stmtStr); - if (stmt.prefixFunc != null) - funcText.push(stmt.prefixFunc(parts, state, tmplName, etc)); - else - funcText.push(stmt.prefix); - if (stmt.suffix != null) { - if (parts.length <= 1) { - if (stmt.paramDefault != null) - funcText.push(stmt.paramDefault); - } else { - for (var i = 1; i < parts.length; i++) { - if (i > 1) - funcText.push(' '); - funcText.push(parts[i]); - } - } - funcText.push(stmt.suffix); - } - } - - var emitSectionText = function(text, funcText) { - if (text.length <= 0) - return; - var nlPrefix = 0; // Index to first non-newline in prefix. - var nlSuffix = text.length - 1; // Index to first non-space/tab in suffix. - while (nlPrefix < text.length && (text.charAt(nlPrefix) == '\n')) - nlPrefix++; - while (nlSuffix >= 0 && (text.charAt(nlSuffix) == ' ' || text.charAt(nlSuffix) == '\t')) - nlSuffix--; - if (nlSuffix < nlPrefix) - nlSuffix = nlPrefix; - if (nlPrefix > 0) { - funcText.push('if (_FLAGS.keepWhitespace == true) _OUT.write("'); - funcText.push(text.substring(0, nlPrefix).replace('\n', '\\n')); - funcText.push('");'); - } - var lines = text.substring(nlPrefix, nlSuffix + 1).split('\n'); - for (var i = 0; i < lines.length; i++) { - emitSectionTextLine(lines[i], funcText); - if (i < lines.length - 1) - funcText.push('_OUT.write("\\n");\n'); - } - if (nlSuffix + 1 < text.length) { - funcText.push('if (_FLAGS.keepWhitespace == true) _OUT.write("'); - funcText.push(text.substring(nlSuffix + 1).replace('\n', '\\n')); - funcText.push('");'); - } - } - - var emitSectionTextLine = function(line, funcText) { - var endExprPrev = -1; - while (endExprPrev + 1 < line.length) { - var begExpr = line.indexOf("${", endExprPrev + 1); // In "a${b}c", begExpr == 1 - if (begExpr < 0) - break; - var endExpr = line.indexOf("}", begExpr + 2); // In "a${b}c", endExpr == 4; 2 == "${".length - if (endExpr < 0) - break; - emitText(line.substring(endExprPrev + 1, begExpr), funcText); - // Example: exprs == 'firstName|default:"John Doe"|capitalize'.split('|') - var exprArr = line.substring(begExpr + 2, endExpr).replace(/\|\|/g, "#@@#").split('|'); - for (var k in exprArr) - exprArr[k] = exprArr[k].replace(/#@@#/g, '||'); - funcText.push('_OUT.write('); - emitExpression(exprArr, exprArr.length - 1, funcText); - funcText.push(');'); - endExprPrev = endExpr; - } - emitText(line.substring(endExprPrev + 1), funcText); - } - - var emitText = function(text, funcText) { - if (text == null || - text.length <= 0) - return; - text = text.replace(/\\/g, '\\\\'); - text = text.replace(/"/g, '\\"'); - funcText.push('_OUT.write("'); - funcText.push(text); - funcText.push('");'); - } - - var emitExpression = function(exprArr, index, funcText) { - // Ex: foo|a:x|b:y1,y2|c:z1,z2 is emitted as c(b(a(foo,x),y1,y2),z1,z2) - var expr = exprArr[index]; // Ex: exprArr == [firstName,capitalize,default:"John Doe"] - if (index <= 0) { // Ex: expr == 'default:"John Doe"' - funcText.push(expr); - return; - } - var parts = expr.split(':'); - funcText.push('_MODIFIERS["'); - funcText.push(parts[0]); // The parts[0] is a modifier function name, like capitalize. - funcText.push('"]('); - emitExpression(exprArr, index - 1, funcText); - if (parts.length > 1) { - funcText.push(','); - funcText.push(parts[1]); - } - funcText.push(')'); - } - - var cleanWhiteSpace = function(result) { - result = result.replace(/\t/g, " "); - result = result.replace(/\r\n/g, "\n"); - result = result.replace(/\r/g, "\n"); - result = result.replace(/^(.*\S)[ \t]+$/gm, "$1"); // Right trim. - return result; - } - - // The DOM helper functions depend on DOM/DHTML, so they only work in a browser. - // However, these are not considered core to the engine. - // - TrimPath.parseDOMTemplate = function(elementId, optDocument, optEtc) { - if (optDocument == null) - optDocument = document; - var element = optDocument.getElementById(elementId); - var content = element.value; // Like textarea.value. - if (content == null) - content = element.innerHTML; // Like textarea.innerHTML. - content = content.replace(/</g, "<").replace(/>/g, ">"); - return TrimPath.parseTemplate(content, elementId, optEtc); - } - - TrimPath.processDOMTemplate = function(elementId, context, optFlags, optDocument, optEtc) { - return TrimPath.parseDOMTemplate(elementId, optDocument, optEtc).process(context, optFlags); - } -}) (); diff --git a/framework/Web/Javascripts/prado/ajax.js b/framework/Web/Javascripts/prado/ajax.js new file mode 100644 index 00000000..06c3d741 --- /dev/null +++ b/framework/Web/Javascripts/prado/ajax.js @@ -0,0 +1,425 @@ +/** + * Prado AJAX service. The default service provider is JPSpan. + */ +Prado.AJAX = { Service : 'Prototype' }; + +/** + * Parse and execute javascript embedded in html. + */ +Prado.AJAX.EvalScript = function(output) +{ + + var match = new RegExp(Ajax.Updater.ScriptFragment, 'img'); + var scripts = output.match(match); + if (scripts) + { + match = new RegExp(Ajax.Updater.ScriptFragment, 'im'); + setTimeout((function() + { + for (var i = 0; i < scripts.length; i++) + eval(scripts[i].match(match)[1]); + }).bind(this), 50); + } +} + + +/** + * AJAX service request using Prototype's AJAX request class. + */ +Prado.AJAX.Request = Class.create(); +Prado.AJAX.Request.prototype = Object.extend(Ajax.Request.prototype, +{ + /** + * Evaluate the respond JSON data, override parent implementing. + * If default eval fails, try parsing the JSON data (slower). + */ + evalJSON: function() + { + try + { + var json = this.transport.getResponseHeader('X-JSON'), object; + object = eval(json); + return object; + } + catch (e) + { + if(isString(json)) + { + return Prado.AJAX.JSON.parse(json); + } + } + }, + + respondToReadyState: function(readyState) { + var event = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + + if(event == 'Complete' && transport.status) + Ajax.Responders.dispatch('on' + transport.status, this, transport, json); + + (this.options['on' + event] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + event, this, transport, json); + + if (event == 'Complete') + (this.options['on' + this.transport.status] + || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + + + /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ + if (event == 'Complete') + this.transport.onreadystatechange = Prototype.emptyFunction; + } + +}); + +Prado.AJAX.Error = function(e, code) +{ + e.name = 'Prado.AJAX.Error'; + e.code = code; + return e; +} + +/** + * Post data builder, serialize the data using JSON. + */ +Prado.AJAX.RequestBuilder = Class.create(); +Prado.AJAX.RequestBuilder.prototype = +{ + initialize : function() + { + this.body = ''; + this.data = []; + }, + encode : function(data) + { + return Prado.AJAX.JSON.stringify(data); + }, + build : function(data) + { + var sep = ''; + for ( var argName in data) + { + if(isFunction(data[argName])) continue; + try + { + this.body += sep + argName + '='; + this.body += encodeURIComponent(this.encode(data[argName])); + } catch (e) { + throw Prado.AJAX.Error(e, 1006); + } + sep = '&'; + } + }, + + getAll : function() + { + this.build(this.data); + return this.body; + } +} + + +Prado.AJAX.RemoteObject = function(){}; + +/** + * AJAX service request for Prado RemoteObjects + */ +Prado.AJAX.RemoteObject.Request = Class.create(); +Prado.AJAX.RemoteObject.Request.prototype = Object.extend(Prado.AJAX.Request.prototype, +{ + /** + * Initialize the RemoteObject Request, overrides parent + * implementation by delaying the request to invokeRemoteObject. + */ + initialize : function(options) + { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.post = new Prado.AJAX.RequestBuilder(); + }, + + /** + * Call the remote object, + * @param string the remote server url + * @param array additional arguments + */ + invokeRemoteObject : function(url, args) + { + this.initParameters(args); + this.options.postBody = this.post.getAll(); + this.request(url); + }, + + /** + * Set the additional arguments as post data with key '__parameters' + */ + initParameters : function(args) + { + this.post.data['__parameters'] = []; + for(var i = 0; i + * var TestObject1 = Class.create(); + * TestObject1.prototype = Object.extend(new Prado.AJAX.RemoteObject(), + * { + * initialize : function(handlers, options) + * { + * this.__serverurl = 'http://127.0.0.1/.....'; + * this.baseInitialize(handlers, options); + * } + * + * method1 : function() + * { + * return this.__call(this.__serverurl, 'method1', arguments); + * } + * }); + * + * And client usage, + * + * var test1 = new TestObject1(); //create new remote object + * test1.method1(); //call the method, no onComplete hook + * + * var onComplete = { method1 : function(result){ alert(result) } }; + * //create new remote object with onComplete callback + * var test2 = new TestObject1(onComplete); + * test2.method1(); //call it, on success, onComplete's method1 is called. + * + */ +Prado.AJAX.RemoteObject.prototype = +{ + baseInitialize : function(handlers, options) + { + this.__handlers = handlers || {}; + this.__service = new Prado.AJAX.RemoteObject.Request(options); + }, + + __call : function(url, method, args) + { + this.__service.options.onSuccess = this.__onSuccess.bind(this); + this.__callback = method; + return this.__service.invokeRemoteObject(url+"/"+method, args); + }, + + __onSuccess : function(transport, json) + { + if(this.__handlers[this.__callback]) + this.__handlers[this.__callback](json, transport.responseText); + } +}; + +/** + * Respond to Prado AJAX request exceptions. + */ +Prado.AJAX.Exception = +{ + /** + * Server returns 505 exception. Just log it. + */ + "on505" : function(request, transport, e) + { + var msg = 'HTTP '+transport.status+" with response"; + Logger.error(msg, transport.responseText); + Logger.exception(e); + }, + + onComplete : function(request, transport, e) + { + if(transport.status != 505) + { + var msg = 'HTTP '+transport.status+" with response : \n"; + msg += transport.responseText + "\n"; + msg += "Data : \n"+inspect(e); + Logger.warn(msg); + } + }, + + format : function(e) + { + var msg = e.type + " with message \""+e.message+"\""; + msg += " in "+e.file+"("+e.line+")\n"; + msg += "Stack trace:\n"; + var trace = e.trace; + for(var i = 0; i"+trace[i]["function"]+"()"+"\n"; + } + return msg; + }, + + logException : function(e) + { + var msg = Prado.AJAX.Exception.format(e); + Logger.error("Server Error "+e.code, msg); + } +} + +//Add HTTP exception respones when logger is enabled. +Event.OnLoad(function() +{ + if(typeof Logger != "undefined") + { + Logger.exception = Prado.AJAX.Exception.logException; + Ajax.Responders.register(Prado.AJAX.Exception); + } +}); + +/** + * Prado Callback service that provides component intergration, + * viewstate (read only), and automatic form data serialization. + * Usage: new Prado.AJAX.Callback('MyPage.MyComponentID.raiseCallbackEvent', options) + * These classes should be called by the components developers. + * For inline callback service, use Prado.Callback(callbackID, params). + */ +Prado.AJAX.Callback = Class.create(); +Prado.AJAX.Callback.prototype = Object.extend(new Prado.AJAX.RemoteObject(), +{ + + /** + * Create and request a new Prado callback service. + * @param string|element the callback ID, must be of the form, ClassName.ComponentID.MethodName + * @param list options with list key onCallbackReturn, and more. + * + */ + initialize : function(ID, options) + { + if(!isString(ID) && typeof(ID.id) != "undefined") + ID = ID.id; + if(!isString(ID)) + throw new Error('A Control ID must be specified'); + this.baseInitialize(this, options); + this.options = options || []; + this.__service.post.data['__ID'] = ID; + this.requestCallback(); + }, + + /** + * Get form data for components that implements IPostBackHandler. + */ + collectPostData : function() + { + var IDs = Prado.AJAX.Callback.IDs; + this.__service.post.data['__data'] = {}; + for(var i = 0; i -1) + this.__service.post.data['__data'][id] = + this.collectArrayPostData(id); + else if(isObject($(id))) + this.__service.post.data['__data'][id] = $F(id); + } + }, + + collectArrayPostData : function(name) + { + var elements = document.getElementsByName(name); + var data = []; + $A(elements).each(function(el) + { + if($F(el)) data.push($F(el)); + }); + return data; + }, + + /** + * Prepares and calls the AJAX request. + * Collects the data from components that implements IPostBackHandler + * and the viewstate as part of the request payload. + */ + requestCallback : function() + { + this.collectPostData(); + if(Prado.AJAX.Validate(this.options)) + return this.__call(Prado.AJAX.Callback.Server, 'handleCallback', this.options.params); + }, + + /** + * On callback request return, call the onSuccess function. + */ + handleCallback : function(result, output) + { + if(typeof(result) != "undefined" && !isNull(result)) + { + this.options.onSuccess(result['data'], output); + if(result['actions']) + result.actions.each(Prado.AJAX.Callback.Action.__run); + } + } +}); + +/** + * Prase and evaluate Callback clien-side actions. + */ +Prado.AJAX.Callback.Action = +{ + __run : function(command) + { + for(var name in command) + { + //first parameter must be a valid element or begins with '@' + if(command[name][0] && ($(command[name][0]) || command[name][0].indexOf("[]") > -1)) + { + name.toFunction().apply(this,command[name]); + } + } + } +}; + + +/** + * Returns false if validation required and validates to false, + * returns true otherwise. + * @return boolean true if validation passes. + */ +Prado.AJAX.Validate = function(options) +{ + if(options.CausesValidation) + { + if(options.ValidatorGroup) + return Prado.Validation.ValidateValidatorGroup(options.ValidatorGroup); + else if(options.ValidationGroup) + return Prado.Validation.ValidateValidationGroup(options.ValidationGroup); + else + return Prado.Validation.ValidateNonGroup(options.ValidationForm); + } + else + return true; +}; + + +//Available callback service +Prado.AJAX.Callback.Server = ''; + +//List of IDs that implements IPostBackHandler +Prado.AJAX.Callback.IDs = []; + +/** + * Simple AJAX callback interface, suitable for inline javascript. + * e.g., Click me + * @param string callback ID + * @param array parameters to pass to the callback service + */ +Prado.Callback = function(ID, params, onSuccess, options) +{ + var callback = + { + 'params' : [params] || [], + 'onSuccess' : onSuccess || Prototype.emptyFunction, + 'CausesValidation' : true + }; + + Object.extend(callback, options || {}); + + new Prado.AJAX.Callback(ID, callback); + return false; +} \ No newline at end of file diff --git a/framework/Web/Javascripts/prado/controls.js b/framework/Web/Javascripts/prado/controls.js new file mode 100644 index 00000000..bc902178 --- /dev/null +++ b/framework/Web/Javascripts/prado/controls.js @@ -0,0 +1,167 @@ +Prado.Focus = Class.create(); + +Prado.Focus.setFocus = function(id) +{ + var target = document.getElementById ? document.getElementById(id) : document.all[id]; + if(target && !Prado.Focus.canFocusOn(target)) + { + target = Prado.Focus.findTarget(target); + } + if(target) + { + try + { + target.focus(); + target.scrollIntoView(false); + if (window.__smartNav) + { + window.__smartNav.ae = target.id; + } + } + catch (e) + { + } + } +} + +Prado.Focus.canFocusOn = function(element) +{ + if(!element || !(element.tagName)) + return false; + var tagName = element.tagName.toLowerCase(); + return !element.disabled && (!element.type || element.type.toLowerCase() != "hidden") && Prado.Focus.isFocusableTag(tagName) && Prado.Focus.isVisible(element); +} + +Prado.Focus.isFocusableTag = function(tagName) +{ + return (tagName == "input" || tagName == "textarea" || tagName == "select" || tagName == "button" || tagName == "a"); +} + + +Prado.Focus.findTarget = function(element) +{ + if(!element || !(element.tagName)) + { + return null; + } + var tagName = element.tagName.toLowerCase(); + if (tagName == "undefined") + { + return null; + } + var children = element.childNodes; + if (children) + { + for(var i=0;i 0)) + { + theForm.action = actionUrl; + } + if (trackFocus) + { + var lastFocus = theForm.elements['PRADO_LASTFOCUS']; + if ((typeof(lastFocus) != 'undefined') && (lastFocus != null)) + { + var active = document.activeElement; + if (typeof(active) == 'undefined') + { + lastFocus.value = eventTarget; + } + else + { + if ((active != null) && (typeof(active.id) != 'undefined')) + { + if (active.id.length > 0) + { + lastFocus.value = active.id; + } + else if (typeof(active.name) != 'undefined') + { + lastFocus.value = active.name; + } + } + } + } + } + if (!clientSubmit) + { + canSubmit = false; + } + } + if (canSubmit && (!theForm.onsubmit || theForm.onsubmit())) + { + theForm.PRADO_POSTBACK_TARGET.value = eventTarget; + theForm.PRADO_POSTBACK_PARAMETER.value = eventParameter; + theForm.submit(); + } +} \ No newline at end of file diff --git a/framework/Web/Javascripts/prado/datepicker.js b/framework/Web/Javascripts/prado/datepicker.js new file mode 100644 index 00000000..68e63168 --- /dev/null +++ b/framework/Web/Javascripts/prado/datepicker.js @@ -0,0 +1,656 @@ +Prado.Calendar = Class.create(); + +Prado.Calendar.Util = Class.create(); + +Object.extend(Prado.Calendar.Util, +{ + IsLeapYear : function (year) + { + return ((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))); + }, + + yearLength : function(year) + { + if (this.isLeapYear(year)) + return 366; + else + return 365; + }, + + dayOfYear : function(date) + { + var a = this.isLeapYear(date.getFullYear()) ? + Calendar.LEAP_NUM_DAYS : Calendar.NUM_DAYS; + return a[date.getMonth()] + date.getDate(); + }, + + browser : function() + { + var info = { Version : "1.0" }; + var is_major = parseInt( navigator.appVersion ); + info.nver = is_major; + info.ver = navigator.appVersion; + info.agent = navigator.userAgent; + info.dom = document.getElementById ? 1 : 0; + info.opera = window.opera ? 1 : 0; + info.ie5 = ( info.ver.indexOf( "MSIE 5" ) > -1 && info.dom && !info.opera ) ? 1 : 0; + info.ie6 = ( info.ver.indexOf( "MSIE 6" ) > -1 && info.dom && !info.opera ) ? 1 : 0; + info.ie4 = ( document.all && !info.dom && !info.opera ) ? 1 : 0; + info.ie = info.ie4 || info.ie5 || info.ie6; + info.mac = info.agent.indexOf( "Mac" ) > -1; + info.ns6 = ( info.dom && parseInt( info.ver ) >= 5 ) ? 1 : 0; + info.ie3 = ( info.ver.indexOf( "MSIE" ) && ( is_major < 4 ) ); + info.hotjava = ( info.agent.toLowerCase().indexOf( 'hotjava' ) != -1 ) ? 1 : 0; + info.ns4 = ( document.layers && !info.dom && !info.hotjava ) ? 1 : 0; + info.bw = ( info.ie6 || info.ie5 || info.ie4 || info.ns4 || info.ns6 || info.opera ); + info.ver3 = ( info.hotjava || info.ie3 ); + info.opera7 = ( ( info.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( info.agent.toLowerCase().indexOf( 'opera/7' ) > -1 ) ); + info.operaOld = info.opera && !info.opera7; + return info; + }, + + ImportCss : function(doc, css_file) + { + if (this.browser().ie) + var styleSheet = doc.createStyleSheet(css_file); + else + { + var elm = doc.createElement("link"); + + elm.rel = "stylesheet"; + elm.href = css_file; + + if (headArr = doc.getElementsByTagName("head")) + headArr[0].appendChild(elm); + } + } +}); + +Object.extend(Prado.Calendar, +{ + // Accumulated days per month, for normal and for leap years. + // Used in week number calculations. + NUM_DAYS : [0,31,59,90,120,151,181,212,243,273,304,334], + LEAP_NUM_DAYS : [0,31,60,91,121,152,182,213,244,274,305,335] +}); + +Prado.Calendar.prototype = +{ + monthNames : [ "January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December" + ], + + shortWeekDayNames : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], + + format : "yyyy-MM-dd", + + css : "calendar_system.css", + + initialize : function(control, attr) + { + this.attr = attr || []; + this.control = $(control); + this.dateSlot = new Array(42); + this.weekSlot = new Array(6); + this.firstDayOfWeek = 1; + this.minimalDaysInFirstWeek = 4; + this.currentDate = new Date(); + this.selectedDate = null; + this.className = "Prado_Calendar"; + + //which element to trigger to show the calendar + this.trigger = this.attr.trigger ? $(this.attr.trigger) : this.control; + Event.observe(this.trigger, "click", this.show.bind(this)); + + Prado.Calendar.Util.ImportCss(document, this.css); + + if(this.attr.format) this.format = this.attr.format; + + //create it + this.create(); + this.hookEvents(); + }, + + create : function() + { + var div; + var table; + var tbody; + var tr; + var td; + + // Create the top-level div element + this._calDiv = document.createElement("div"); + this._calDiv.className = this.className; + this._calDiv.style.display = "none"; + + // header div + div = document.createElement("div"); + div.className = "calendarHeader"; + this._calDiv.appendChild(div); + + table = document.createElement("table"); + table.style.cellSpacing = 0; + div.appendChild(table); + + tbody = document.createElement("tbody"); + table.appendChild(tbody); + + tr = document.createElement("tr"); + tbody.appendChild(tr); + + // Previous Month Button + td = document.createElement("td"); + td.className = "prevMonthButton"; + this._previousMonth = document.createElement("button"); + this._previousMonth.appendChild(document.createTextNode("<<")); + td.appendChild(this._previousMonth); + tr.appendChild(td); + + + + // + // Create the month drop down + // + td = document.createElement("td"); + td.className = "labelContainer"; + tr.appendChild(td); + this._monthSelect = document.createElement("select"); + for (var i = 0 ; i < this.monthNames.length ; i++) { + var opt = document.createElement("option"); + opt.innerHTML = this.monthNames[i]; + opt.value = i; + if (i == this.currentDate.getMonth()) { + opt.selected = true; + } + this._monthSelect.appendChild(opt); + } + td.appendChild(this._monthSelect); + + + // + // Create the year drop down + // + td = document.createElement("td"); + td.className = "labelContainer"; + tr.appendChild(td); + this._yearSelect = document.createElement("select"); + for(var i=1920; i < 2050; ++i) { + var opt = document.createElement("option"); + opt.innerHTML = i; + opt.value = i; + if (i == this.currentDate.getFullYear()) { + opt.selected = false; + } + this._yearSelect.appendChild(opt); + } + td.appendChild(this._yearSelect); + + + td = document.createElement("td"); + td.className = "nextMonthButton"; + this._nextMonth = document.createElement("button"); + this._nextMonth.appendChild(document.createTextNode(">>")); + td.appendChild(this._nextMonth); + tr.appendChild(td); + + // Calendar body + div = document.createElement("div"); + div.className = "calendarBody"; + this._calDiv.appendChild(div); + this._table = div; + + // Create the inside of calendar body + + var text; + table = document.createElement("table"); + //table.style.width="100%"; + table.className = "grid"; + + div.appendChild(table); + var thead = document.createElement("thead"); + table.appendChild(thead); + tr = document.createElement("tr"); + thead.appendChild(tr); + + for(i=0; i < 7; ++i) { + td = document.createElement("th"); + text = document.createTextNode(this.shortWeekDayNames[(i+this.firstDayOfWeek)%7]); + td.appendChild(text); + td.className = "weekDayHead"; + tr.appendChild(td); + } + + // Date grid + tbody = document.createElement("tbody"); + table.appendChild(tbody); + + for(week=0; week<6; ++week) { + tr = document.createElement("tr"); + tbody.appendChild(tr); + + for(day=0; day<7; ++day) { + td = document.createElement("td"); + td.className = "calendarDate"; + text = document.createTextNode(String.fromCharCode(160)); + td.appendChild(text); + + tr.appendChild(td); + var tmp = new Object(); + tmp.tag = "DATE"; + tmp.value = -1; + tmp.data = text; + this.dateSlot[(week*7)+day] = tmp; + + Event.observe(td, "mouseover", this.hover.bind(this)); + Event.observe(td, "mouseout", this.hover.bind(this)); + + } + } + + // Calendar Footer + div = document.createElement("div"); + div.className = "calendarFooter"; + this._calDiv.appendChild(div); + + table = document.createElement("table"); + //table.style.width="100%"; + table.className = "footerTable"; + //table.cellSpacing = 0; + div.appendChild(table); + + tbody = document.createElement("tbody"); + table.appendChild(tbody); + + tr = document.createElement("tr"); + tbody.appendChild(tr); + + // + // The TODAY button + // + td = document.createElement("td"); + td.className = "todayButton"; + this._todayButton = document.createElement("button"); + var today = new Date(); + var buttonText = today.getDate() + " " + this.monthNames[today.getMonth()] + ", " + today.getFullYear(); + this._todayButton.appendChild(document.createTextNode(buttonText)); + td.appendChild(this._todayButton); + tr.appendChild(td); + + // + // The CLEAR button + // + td = document.createElement("td"); + td.className = "clearButton"; + this._clearButton = document.createElement("button"); + var today = new Date(); + buttonText = "Clear"; + this._clearButton.appendChild(document.createTextNode(buttonText)); + td.appendChild(this._clearButton); + tr.appendChild(td); + + document.body.appendChild(this._calDiv); + + this.update(); + this.updateHeader(); + + return this._calDiv; + }, + + hookEvents : function() + { + // IE55+ extension + this._previousMonth.hideFocus = true; + this._nextMonth.hideFocus = true; + this._todayButton.hideFocus = true; + // end IE55+ extension + + // hook up events + Event.observe(this._previousMonth, "click", this.prevMonth.bind(this)); + Event.observe(this._nextMonth, "click", this.nextMonth.bind(this)); + Event.observe(this._todayButton, "click", this.selectToday.bind(this)); + Event.observe(this._clearButton, "click", this.clearSelection.bind(this)); + + Event.observe(this._monthSelect, "change", this.monthSelect.bind(this)); + Event.observe(this._yearSelect, "change", this.yearSelect.bind(this)); + + // ie6 extension + Event.observe(this._calDiv, "mousewheel", this.mouseWheelChange.bind(this)); + + Event.observe(this._table, "click", this.selectDate.bind(this)); + + Event.observe(this._calDiv,"keydown", this.keyPressed.bind(this)); + + /* + this._calDiv.onkeydown = function (e) { + if (e == null) e = document.parentWindow.event; + var kc = e.keyCode != null ? e.keyCode : e.charCode; + + if(kc == 13) { + var d = new Date(dp._currentDate).valueOf(); + dp.setSelectedDate(d); + + if (!dp._alwaysVisible && dp._hideOnSelect) { + dp.hide(); + } + return false; + } + + + if (kc < 37 || kc > 40) return true; + + var d = new Date(dp._currentDate).valueOf(); + if (kc == 37) // left + d -= 24 * 60 * 60 * 1000; + else if (kc == 39) // right + d += 24 * 60 * 60 * 1000; + else if (kc == 38) // up + d -= 7 * 24 * 60 * 60 * 1000; + else if (kc == 40) // down + d += 7 * 24 * 60 * 60 * 1000; + + dp.setCurrentDate(new Date(d)); + return false; + }*/ + + + }, + + keyPressed : function(ev) + { + if (!ev) ev = document.parentWindow.event; + var kc = ev.keyCode != null ? ev.keyCode : ev.charCode; + + if(kc = Event.KEY_RETURN) + { + //var d = new Date(this.currentDate); + this.setSelectedDate(this.currentDate); + this.hide(); + return false; + } + + if(kc < 37 || kc > 40) return true; + + var d = new Date(this.currentDate).valueOf(); + if(kc == Event.KEY_LEFT) + d -= 86400000; //-1 day + else if (kc == Event.KEY_RIGHT) + d += 86400000; //+1 day + else if (kc == Event.KEY_UP) + d -= 604800000; // -7 days + else if (kc == Event.KEY_DOWN) + d += 604800000; // +7 days + this.setCurrentDate(new Date(d)); + return false; + }, + + selectDate : function(ev) + { + var el = Event.element(ev); + while (el.nodeType != 1) + el = el.parentNode; + + while (el != null && el.tagName && el.tagName.toLowerCase() != "td") + el = el.parentNode; + + // if no td found, return + if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td") + return; + + var d = new Date(this.currentDate); + var n = Number(el.firstChild.data); + if (isNaN(n) || n <= 0 || n == null) + return; + + d.setDate(n); + this.setSelectedDate(d); + this.hide(); + }, + + selectToday : function() + { + this.setSelectedDate(new Date()); + this.hide(); + }, + + clearSelection : function() + { + this.selectedDate = null; + if (isFunction(this.onchange)) + this.onchange(); + this.hide(); + }, + + monthSelect : function(ev) + { + this.setMonth(Form.Element.getValue(Event.element(ev))); + }, + + yearSelect : function(ev) + { + this.setYear(Form.Element.getValue(Event.element(ev))); + }, + + // ie6 extension + mouseWheelChange : function (e) + { + if (e == null) e = document.parentWindow.event; + var n = - e.wheelDelta / 120; + var d = new Date(this.currentDate); + var m = this.getMonth() + n; + this.setMonth(m); + this.setCurrentDate(d); + + return false; + }, + + onchange : function() + { + this.control.value = this.formatDate(); + }, + + formatDate : function() + { + return Prado.Calendar.Util.FormatDate(this.selectedDate, this.format); + }, + + setCurrentDate : function(date) + { + if (date == null) + return; + + // if string or number create a Date object + if (isString(date) || isNumber(date)) + date = new Date(date); + + // do not update if not really changed + if (this.currentDate.getDate() != date.getDate() || + this.currentDate.getMonth() != date.getMonth() || + this.currentDate.getFullYear() != date.getFullYear()) + { + + this.currentDate = new Date(date); + + this.updateHeader(); + this.update(); + } + + }, + + setSelectedDate : function(date) + { + this.selectedDate = new Date(date); + this.setCurrentDate(this.selectedDate); + if (isFunction(this.onchange)) + this.onchange(); + }, + + getElement : function() + { + return this._calDiv; + }, + + getSelectedDate : function () + { + return isNull(this.selectedDate) ? null : new Date(this.selectedDate); + }, + + setYear : function(year) + { + var d = new Date(this.currentDate); + d.setFullYear(year); + this.setCurrentDate(d); + }, + + setMonth : function (month) + { + var d = new Date(this.currentDate); + d.setMonth(month); + this.setCurrentDate(d); + }, + + nextMonth : function () + { + this.setMonth(this.currentDate.getMonth()+1); + }, + + prevMonth : function () + { + this.setMonth(this.currentDate.getMonth()-1); + }, + + show : function() + { + if(!this.showing) + { + var pos = Position.cumulativeOffset(this.control); + pos[1] += this.control.offsetHeight; + this._calDiv.style.display = "block"; + this._calDiv.style.top = pos[1] + "px"; + this._calDiv.style.left = pos[0] + "px"; + Event.observe(document.body, "click", this.hideOnClick.bind(this)); + var date = Prado.Calendar.Util.ParseDate(Form.Element.getValue(this.control), this.format); + if(!isNull(date)) + { + this.selectedDate = date; + this.setCurrentDate(date); + } + this.showing = true; + } + }, + + //hide the calendar when clicked outside any calendar + hideOnClick : function(ev) + { + if(!this.showing) return; + var el = Event.element(ev); + var within = false; + do + { + within = within || el.className == this.className; + within = within || el == this.trigger; + within = within || el == this.control; + if(within) break; + el = el.parentNode; + } + while(el); + if(!within) this.hide(); + }, + + hide : function() + { + if(this.showing) + { + this._calDiv.style.display = "none"; + this.showing = false; + Event.stopObserving(document.body, "click", this.hideOnClick.bind(this)); + } + }, + + update : function() + { + var Util = Prado.Calendar.Util; + + // Calculate the number of days in the month for the selected date + var date = this.currentDate; + var today = Util.ISODate(new Date()); + + var selected = isNull(this.selectedDate) ? "" : Util.ISODate(this.selectedDate); + var current = Util.ISODate(date); + var d1 = new Date(date.getFullYear(), date.getMonth(), 1); + var d2 = new Date(date.getFullYear(), date.getMonth()+1, 1); + var monthLength = Math.round((d2 - d1) / (24 * 60 * 60 * 1000)); + + // Find out the weekDay index for the first of this month + var firstIndex = (d1.getDay() - this.firstDayOfWeek) % 7 ; + if (firstIndex < 0) + firstIndex += 7; + + var index = 0; + while (index < firstIndex) { + this.dateSlot[index].value = -1; + this.dateSlot[index].data.data = String.fromCharCode(160); + this.dateSlot[index].data.parentNode.className = "empty"; + index++; + } + + for (i = 1; i <= monthLength; i++, index++) { + var slot = this.dateSlot[index]; + var slotNode = slot.data.parentNode; + slot.value = i; + slot.data.data = i; + slotNode.className = "date"; + if (Util.ISODate(d1) == today) { + slotNode.className += " today"; + } + if (Util.ISODate(d1) == current) { + slotNode.className += " current"; + } + if (Util.ISODate(d1) == selected) { + slotNode.className += " selected"; + } + d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+1); + } + + var lastDateIndex = index; + + while(index < 42) { + this.dateSlot[index].value = -1; + this.dateSlot[index].data.data = String.fromCharCode(160); + this.dateSlot[index].data.parentNode.className = "empty"; + ++index; + } + + }, + + hover : function(ev) + { + //conditionally add the hover class to the event target element. + Element.condClassName(Event.element(ev), "hover", ev.type=="mouseover"); + }, + + updateHeader : function () { + + var options = this._monthSelect.options; + var m = this.currentDate.getMonth(); + for(var i=0; i < options.length; ++i) { + options[i].selected = false; + if (options[i].value == m) { + options[i].selected = true; + } + } + + options = this._yearSelect.options; + var year = this.currentDate.getFullYear(); + for(var i=0; i < options.length; ++i) { + options[i].selected = false; + if (options[i].value == year) { + options[i].selected = true; + } + } + + } + + +}; \ No newline at end of file diff --git a/framework/Web/Javascripts/prado/prado.js b/framework/Web/Javascripts/prado/prado.js new file mode 100644 index 00000000..52bf2b89 --- /dev/null +++ b/framework/Web/Javascripts/prado/prado.js @@ -0,0 +1,51 @@ +var Prado = { Version: '3.0a' }; + +Prado.Button = Class.create(); + +/** + * Usage: Event.observe("panelID", "keypress", Prado.fireButton.bindEvent($("panelID"), "targetButtonID")); + */ +Object.extend(Prado.Button, +{ + buttonFired : false, + fireButton : function(e, target) + { + var eventFired = !this.buttonFired && Event.keyCode(e) == Event.KEY_RETURN; + var isTextArea = Event.element(e).targName.toLowerCase() == "textarea"; + if (eventFired && !isTextArea) + { + var defaultButton = $(target); + if (defaultButton) + { + Prado.Button.buttonFired = true; + Event.fireEvent(defaultButton,"click"); + Event.stop(e); + return false; + } + } + return true; + } +}); + +Prado.TextBox = Class.create(); + +/** + * Usage: Event.observe("textboxID", "keypress", Prado.fireButton.bindEvent($("textboxID"))); + */ +Object.extend(Prado.TextBox, +{ + handleReturnKey = function(e) + { + if(Event.keyCode(e) == Event.KEY_RETURN) + { + var target = Event.element(e); + if(target) + { + Event.fireEvent(target, "change"); + Event.stop(e); + return false; + } + } + return true; + } +}); diff --git a/framework/Web/Javascripts/prado/validation.js b/framework/Web/Javascripts/prado/validation.js new file mode 100644 index 00000000..33d5411d --- /dev/null +++ b/framework/Web/Javascripts/prado/validation.js @@ -0,0 +1,751 @@ + +/** + * Prado client-side javascript validation class. + */ +Prado.Validation = Class.create(); + +/** + * Utilities for validation. Static class. + */ +Prado.Validation.Util = Class.create(); + +/** + * Convert a string into integer, returns null if not integer. + * @param {string} the string to convert to integer + * @type {integer|null} null if string does not represent an integer. + */ +Prado.Validation.Util.toInteger = function(value) +{ + var exp = /^\s*[-\+]?\d+\s*$/; + if (value.match(exp) == null) + return null; + var num = parseInt(value, 10); + return (isNaN(num) ? null : num); +} + +/** + * Convert a string into a double/float value. Internationalization + * is not supported + * @param {string} the string to convert to double/float + * @param {string} the decimal character + * @return {float|null} null if string does not represent a float value + */ +Prado.Validation.Util.toDouble = function(value, decimalchar) +{ + decimalchar = undef(decimalchar) ? "." : decimalchar; + var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$"); + var m = value.match(exp); + if (m == null) + return null; + var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4]; + var num = parseFloat(cleanInput); + return (isNaN(num) ? null : num); +} + +/** + * Convert strings that represent a currency value (e.g. a float with grouping + * characters) to float. E.g. "10,000.50" will become "10000.50". The number + * of dicimal digits, grouping and decimal characters can be specified. + * The currency input format is very strict, null will be returned if + * the pattern does not match. + * @param {string} the currency value + * @param {string} the grouping character, default is "," + * @param {int} number of decimal digits + * @param {string} the decimal character, default is "." + * @type {float|null} the currency value as float. + */ +Prado.Validation.Util.toCurrency = function(value, groupchar, digits, decimalchar) +{ + groupchar = undef(groupchar) ? "," : groupchar; + decimalchar = undef(decimalchar) ? "." : decimalchar; + digits = undef(digits) ? 2 : digits; + + var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)" + + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "") + + "\\s*$"); + var m = value.match(exp); + if (m == null) + return null; + var intermed = m[2] + m[5] ; + var cleanInput = m[1] + intermed.replace( + new RegExp("(\\" + groupchar + ")", "g"), "") + + ((digits > 0) ? "." + m[7] : ""); + var num = parseFloat(cleanInput); + return (isNaN(num) ? null : num); +} + +/** + * Get the date from string using the prodivided date format string. + * The format notations are + * # day -- %d or %e + * # month -- %m + * # year -- %y or %Y + * # hour -- %H, %I, %k, or %l + * # minutes -- %M + * # P.M. -- %p or %P + * @param {string} the formatted date string + * @param {string} the date format + * @type {Date} the date represented in the string + */ +Prado.Validation.Util.toDate = function(value, format) +{ + var y = 0; + var m = -1; + var d = 0; + var a = value.split(/\W+/); + var b = format.match(/%./g); + var i = 0, j = 0; + var hr = 0; + var min = 0; + for (i = 0; i < a.length; ++i) { + if (!a[i]) + continue; + switch (b[i]) { + case "%d": + case "%e": + d = parseInt(a[i], 10); + break; + + case "%m": + m = parseInt(a[i], 10) - 1; + break; + + case "%Y": + case "%y": + y = parseInt(a[i], 10); + (y < 100) && (y += (y > 29) ? 1900 : 2000); + break; + + case "%H": + case "%I": + case "%k": + case "%l": + hr = parseInt(a[i], 10); + break; + + case "%P": + case "%p": + if (/pm/i.test(a[i]) && hr < 12) + hr += 12; + break; + + case "%M": + min = parseInt(a[i], 10); + break; + } + } + if (y != 0 && m != -1 && d != 0) + { + var date = new Date(y, m, d, hr, min, 0); + return (isObject(date) + && y == date.getFullYear() + && m == date.getMonth() + && d == date.getDate()) ? date.valueOf() : null; + } + return null; +} + +/** + * Trim the value, if the value is undefined, empty string is return. + * @param {string} string to be trimmed. + * @type {string} trimmed string. + */ +Prado.Validation.Util.trim = function(value) +{ + if(undef(value)) return ""; + return value.replace(/^\s+|\s+$/g, ""); +} + +/** + * A delayed focus on a particular element + * @param {element} element to apply focus() + */ +Prado.Validation.Util.focus = function(element) +{ + var obj = $(element); + if(isObject(obj) && isdef(obj.focus)) + setTimeout(function(){ obj.focus(); }, 100); + return false; +} + +/** + * List of validator instances. + */ +Prado.Validation.validators = []; + +/** + * List of forms. + * @type {int} + */ +Prado.Validation.forms = []; + +/** + * List of summary controls. + */ +Prado.Validation.summaries = []; + +/** + * Validation groups. + */ +Prado.Validation.groups = []; + + +/** + * Second type of grouping. + */ +Prado.Validation.TargetGroups = {}; + + +/** + * Current Target group. + */ +Prado.Validation.CurrentTargetGroup = null; + +Prado.Validation.HasTargetGroup = false; + +/** + * Targets that can cause validation. + */ +Prado.Validation.ActiveTarget = null; + + +/** + * Determine if group validation is active. + */ +Prado.Validation.IsGroupValidation = false; + +/** + * Add a form for validation. + * @param {string} form ID + */ +Prado.Validation.AddForm = function(id) +{ + Prado.Validation.forms.push($(id)); +} + +/** + * Add a target that causes validation. Only elements that have been added + * can cause validation. + * @param {string} target id + */ +Prado.Validation.AddTarget = function(id, group) +{ + var target = $(id); + Event.observe(target, "click", function() + { + Prado.Validation.ActiveTarget = target; + Prado.Validation.CurrentTargetGroup = Prado.Validation.TargetGroups[id]; + }); + if(group) + { + Prado.Validation.TargetGroups[id] = group; + Prado.Validation.HasTargetGroup = true; + } +} + +/** + * Associate a list of validators to a particular control element. + * This essentially allows a set of validators to be grouped to a particular button. + * @param {list} group array show have, {group : "id", target : "target button"} + * @param {array} validator ids + */ +Prado.Validation.AddGroup = function(group, validators) +{ + group.active = false; //default active status is false. + group.target = $(group.target); + group.validators = validators; + Prado.Validation.groups.push(group); + + //update the active group when the button is clicked. + Event.observe(group.target, "click", Prado.Validation.UpdateActiveGroup); +} + +/** + * Update the active group, if call manually it will deactivate all groups. + * @param {string} + * @type {int} + */ +Prado.Validation.UpdateActiveGroup = function(ev) +{ + var groups = Prado.Validation.groups; + for (var i = 0; i < groups.length; i++) + { + groups[i].active = (isdef(ev) && groups[i].target == Event.element(ev)); + } + Prado.Validation.IsGroupValidation = isdef(ev); +} + +/** + * Determine if validation is sucessful. Iterate through the list + * of validator instances and call validate(). Only validators that + * for a particular form are evaluated. Other validators will be disabled. + * If performing group validation, only active validators are visible. + * @param {element} the form for the controls to validate. + * @type {boolean} true is all validators are valid, false otherwise. + */ +Prado.Validation.IsValid = function(form) +{ + var valid = true; + var validators = Prado.Validation.validators; + + for(var i = 0; i < validators.length; i++) + { + //prevent validating multiple forms + validators[i].enabled = !validators[i].control || undef(validators[i].control.form) || validators[i].control.form == form; + //when group validation, only validators in the active group are visible. + validators[i].visible = Prado.Validation.IsGroupValidation ? validators[i].inActiveGroup() : true; + + if(Prado.Validation.HasTargetGroup) + { + if(validators[i].group != Prado.Validation.CurrentTargetGroup) + validators[i].enabled = false; + } + + valid &= validators[i].validate(); + } + + //show the summary including the alert box + Prado.Validation.ShowSummary(form); + //reset all the group active status to false + Prado.Validation.UpdateActiveGroup(); + return valid; +} + +/** + * Base validator class. Supply a different validation function + * to obtain a different validator. E.g. to use the RequiredFieldValidator + * new Prado.Validation(Prado.Validation.RequiredFieldValidator, options); + * or to use the CustomValidator, + * new Prado.Validation(Prado.Validation.CustomValidator, options); + */ +Prado.Validation.prototype = +{ + /** + * Initialize the validator. + * @param {function} the function to call to evaluate if + * the validator is valid + * @param {string|element} the control ID or element + * @param {array} the list of attributes for the validator + */ + initialize : function(validator, attr) + { + this.evaluateIsValid = validator; + this.attr = undef(attr) ? [] : attr; + this.message = $(attr.id); + this.control = $(attr.controltovalidate); + this.enabled = isdef(attr.enabled) ? attr.enabled : true; + this.visible = isdef(attr.visible) ? attr.visible : true; + this.group = isdef(attr.validationgroup) ? attr.validationgroup : null; + this.isValid = true; + Prado.Validation.validators.push(this); + if(this.evaluateIsValid) + this.evaluateIsValid.bind(this); + }, + + /** + * Evaluate the validator only when visible and enabled. + * @type {boolean} true if valid, false otherwise. + */ + validate : function() + { + if(this.visible && this.enabled && this.evaluateIsValid) + this.isValid = this.evaluateIsValid(); + else + this.isValid = true; + + this.observe(); //watch for changes to the control values + this.update(); //update the validation messages + return this.isValid; + }, + + /** + * Hide or show the error messages for "Dynamic" displays. + */ + update : function() + { + if(this.attr.display == "Dynamic") + this.isValid ? Element.hide(this.message) : Element.show(this.message); + + if(this.message) + this.message.style.visibility = this.isValid ? "hidden" : "visible"; + + //update the control css class name + var className = this.attr.controlcssclass; + if(this.control && isString(className) && className.length>0) + Element.condClassName(this.control, className, !this.isValid); + Prado.Validation.ShowSummary(); + + var focus = this.attr.focusonerror; + var hasGroup = Prado.Validation.HasTargetGroup; + var inGroup = this.group == Prado.Validation.CurrentTargetGroup; + + if(focus && (!hasGroup || (hasGroup && inGroup))) + Prado.Element.focus(this.attr.focuselementid); + }, + + /** + * Change the validity of the validator, calls update(). + * @param {boolean} change the isValid state of the validator. + */ + setValid : function(valid) + { + this.isValid = valid; + this.update(); + }, + + /** + * Observe changes to the control values, add "onchange" event to the control once. + */ + observe : function() + { + if(undef(this.observing)) + { + if(this.control && this.control.form) + Event.observe(this.control, "change", this.validate.bind(this)); + this.observing = true; + } + }, + + /** + * Convert the value of the control to a specific data type. + * @param {string} the data type, "Integer", "Double", "Currency" or "Date". + * @param {string} the value to convert, null to get the value from the control. + * @type {mixed|null} the converted data value. + */ + convert : function(dataType, value) + { + if(undef(value)) + value = Form.Element.getValue(this.control); + switch(dataType) + { + case "Integer": + return Prado.Validation.Util.toInteger(value); + case "Double" : + case "Float" : + return Prado.Validation.Util.toDouble(value, this.attr.decimalchar); + case "Currency" : + return Prado.Validation.Util.toCurrency( + value, this.attr.groupchar, this.attr.digits, this.attr.decimalchar); + case "Date": + return Prado.Validation.Util.toDate(value, this.attr.dateformat); + } + return value.toString(); + }, + + /** + * Determine if the current validator is part of a active validation group. + * @type {boolean} true if part of active validation group, false otherwise. + */ + inActiveGroup : function() + { + var groups = Prado.Validation.groups; + for (var i = 0; i < groups.length; i++) + { + if(groups[i].active && groups[i].validators.contains(this.attr.id)) + return true; + } + return false; + } +} + +/** + * Validation summary class. + */ +Prado.Validation.Summary = Class.create(); +Prado.Validation.Summary.prototype = +{ + /** + * Initialize a validation summary. + * @param {array} summary options. + */ + initialize : function(attr) + { + this.attr = attr; + this.div = $(attr.id); + this.visible = false; + this.enabled = false; + this.group = isdef(attr.validationgroup) ? attr.validationgroup : null; + Prado.Validation.summaries.push(this); + }, + + /** + * Show the validation summary. + * @param {boolean} true to allow alert message + */ + show : function(warn) + { + var refresh = warn || this.attr.refresh == "1"; + var messages = this.getMessages(); + if(messages.length <= 0 || !this.visible || !this.enabled) + { + if(refresh) + Element.hide(this.div); + return; + } + + if(Prado.Validation.HasTargetGroup) + { + if(Prado.Validation.CurrentTargetGroup != this.group) + { + if(refresh) + Element.hide(this.div); + return; + } + } + + if(this.attr.showsummary != "False" && refresh) + { + //Element.show(this.div); + this.div.style.display = "block"; + while(this.div.childNodes.length > 0) + this.div.removeChild(this.div.lastChild); + new Insertion.Bottom(this.div, this.formatSummary(messages)); + } + + if(warn) + window.scrollTo(this.div.offsetLeft-20, this.div.offsetTop-20); + + var summary = this; + if(warn && this.attr.showmessagebox == "True" && refresh) + setTimeout(function(){alert(summary.formatMessageBox(messages));},20); + }, + + /** + * Get a list of error messages from the validators. + * @type {array} list of messages + */ + getMessages : function() + { + var validators = Prado.Validation.validators; + var messages = []; + for(var i = 0; i < validators.length; i++) + { + if(validators[i].isValid == false + && isString(validators[i].attr.errormessage) + && validators[i].attr.errormessage.length > 0) + { + + messages.push(validators[i].attr.errormessage); + } + } + return messages; + }, + + /** + * 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 : "
  • ", post : "
  • ", last : "
"}; + } + }, + + /** + * Format the message summary. + * @param {array} list of error messages. + * @type {string} formatted message + */ + formatSummary : function(messages) + { + var format = this.formats(this.attr.displaymode); + var output = isdef(this.attr.headertext) ? this.attr.headertext + format.header : ""; + output += format.first; + 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 = isdef(this.attr.headertext) ? this.attr.headertext + "\n" : ""; + for(var i = 0; i < messages.length; i++) + { + switch(this.attr.displaymode) + { + case "List": + output += messages[i] + "\n"; + break; + case "BulletList": + default: + output += " - " + messages[i] + "\n"; + break; + case "SingleParagraph": + output += messages[i] + " "; + break; + } + } + return output; + }, + + /** + * Determine if this summary belongs to an active group. + * @type {boolean} true if belongs to an active group. + */ + inActiveGroup : function() + { + var groups = Prado.Validation.groups; + for (var i = 0; i < groups.length; i++) + { + if(groups[i].active && groups[i].id == this.attr.group) + return true; + } + return false; + } +} + +/** + * Show the validation error message summary. + * @param {element} the form that activated the summary call. + */ +Prado.Validation.ShowSummary = function(form) +{ + var summary = Prado.Validation.summaries; + for(var i = 0; i < summary.length; i++) + { + if(isdef(form)) + { + if(Prado.Validation.IsGroupValidation) + { + summary[i].visible = summary[i].inActiveGroup(); + } + else + { + summary[i].visible = undef(summary[i].attr.group); + } + + summary[i].enabled = $(summary[i].attr.form) == form; + } + summary[i].show(form); + } +} + + + +/** + * When a form is try to submit, check the validators, submit + * the form only when all validators are valid. + * @param {event} form submit event. + */ +Prado.Validation.OnSubmit = function(ev) +{ + //HTML text editor, tigger save first. + //alert(tinyMCE); + if(typeof tinyMCE != "undefined") + tinyMCE.triggerSave(); + + //no active target? + if(!Prado.Validation.ActiveTarget) return true; + var valid = Prado.Validation.IsValid(Event.element(ev) || ev); + + //not valid? do not submit the form + if(Event.element(ev) && !valid) + Event.stop(ev); + + //reset the target + Prado.Validation.ActiveTarget = null; + //Prado.Validation.CurrentTargetGroup = null; + + return valid; +} + +/** + * During window onload event, attach onsubmit event for each of the + * forms in Prado.Validation.forms. + */ +Prado.Validation.OnLoad = function() +{ + Event.observe(Prado.Validation.forms,"submit", Prado.Validation.OnSubmit); +} + + +/** + * Validate Validator Groups. + * @param string ValidatorGroup + * @return boolean true if valid, false otherwise + */ +Prado.Validation.ValidateValidatorGroup = function(groupId) +{ + var groups = Prado.Validation.groups; + var group = null; + for(var i = 0; i < groups.length; i++) + { + if(groups[i].id == groupId) + { + group = groups[i]; + Prado.Validation.groups[i].active = true; + Prado.Validation.CurrentTargetGroup = null; + Prado.Validation.IsGroupValidation = true; + } + else + { + Prado.Validation.groups[i].active = false; + } + } + if(group) + { + return Prado.Validation.IsValid(group.target.form); + } + return true; +}; + +/** + * Validate ValidationGroup + * @param string ValidationGroup + * @return boolean true if valid, false otherwise. + */ +Prado.Validation.ValidateValidationGroup= function(groupId) +{ + var groups = Prado.Validation.TargetGroups; + for(var id in groups) + { + if(groups[id] == groupId) + { + var target = $(id); + Prado.Validation.ActiveTarget = target; + Prado.Validation.CurrentTargetGroup = groupId; + Prado.Validation.IsGroupValidation = false; + return Prado.Validation.IsValid(target.form); + } + } + return true; +}; + +/** + * Validate the page + * @return boolean true if valid, false otherwise. + */ +Prado.Validation.ValidateNonGroup= function(formId) +{ + if(Prado.Validation) + { + var form = $(formId); + form = form || document.forms[0]; + Prado.Validation.ActiveTarget = form; + Prado.Validation.CurrentTargetGroup = null; + Prado.Validation.IsGroupValidation = false; + return Prado.Validation.IsValid(form); + } + return true; +}; + + + +/** + * Register Prado.Validation.Onload() for window.onload event. + */ +Event.OnLoad(Prado.Validation.OnLoad); \ No newline at end of file diff --git a/framework/Web/Javascripts/prado/validators.js b/framework/Web/Javascripts/prado/validators.js new file mode 100644 index 00000000..427b46fc --- /dev/null +++ b/framework/Web/Javascripts/prado/validators.js @@ -0,0 +1,225 @@ + +Prado.Validation.TRequiredFieldValidator=function(){ + var inputType = this.control.getAttribute("type"); + if(inputType == 'file'){ + return true; + } + else{ + var trim=Prado.Util.trim; + var a=trim(Form.Element.getValue(this.control)); + var b=trim(this.attr.initialvalue); + return(a!=b); + } +} + + +Prado.Validation.TRegularExpressionValidator = function() +{ + var trim = Prado.Util.trim; + var value = trim(Form.Element.getValue(this.control)); + if (value == "") return true; + var rx = new RegExp(this.attr.validationexpression); + var matches = rx.exec(value); + return (matches != null && value == matches[0]); +} + +Prado.Validation.TEmailAddressValidator = Prado.Validation.TRegularExpressionValidator; + +Prado.Validation.TCustomValidator = function() +{ + var value = isNull(this.control) ? null : $F(this.control); + var func = this.attr.clientvalidationfunction; + eval("var validate = "+func); + return validate && isFunction(validate) ? validate(this, value) : true; +} + +Prado.Validation.TRangeValidator = function() +{ + var trim = Prado.Util.trim; + var value = trim(Form.Element.getValue(this.control)); + if (value == "") return true; + + var minval = this.attr.minimumvalue; + var maxval = this.attr.maximumvalue; + + if (undef(minval) && undef(maxval)) + return true; + + if (minval == "") minval = 0; + if (maxval == "") maxval = 0; + + var dataType = this.attr.type; + + if(undef(dataType)) + return (parseFloat(value) >= parseFloat(minval)) && (parseFloat(value) <= parseFloat(maxval)); + + //now do datatype range check. + var min = this.convert(dataType, minval); + var max = this.convert(dataType, maxval); + value = this.convert(dataType, value); + return value >= min && value <= max; +} + +Prado.Validation.TCompareValidator = function() +{ + var trim = Prado.Util.trim; + var value = trim(Form.Element.getValue(this.control)); + if (value.length == 0) return true; + + var compareTo; + + var comparee = $(this.attr.controlhookup);; + + if(comparee) + compareTo = trim(Form.Element.getValue(comparee)); + else + { + compareTo = isString(this.attr.valuetocompare) ? this.attr.valuetocompare : ""; + } + + var compare = Prado.Validation.TCompareValidator.compare; + + var isValid = compare.bind(this)(value, compareTo); + + //update the comparee control css class name and add onchange event once. + if(comparee) + { + var className = this.attr.controlcssclass; + if(isString(className) && className.length>0) + Element.condClassName(comparee, className, !isValid); + if(undef(this.observingComparee)) + { + Event.observe(comparee, "change", this.validate.bind(this)); + this.observingComparee = true; + } + } + return isValid; +} + +/** + * Compare the two values, also performs data type check. + * @param {string} value to compare with + * @param {string} value to compare + * @type {boolean} true if comparison or type check is valid, false otherwise. + */ +Prado.Validation.TCompareValidator.compare = function(operand1, operand2) +{ + var op1, op2; + if ((op1 = this.convert(this.attr.type, operand1)) == null) + return false; + if (this.attr.operator == "DataTypeCheck") + return true; + if ((op2 = this.convert(this.attr.type, operand2)) == null) + return true; + switch (this.attr.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); + } +} + +Prado.Validation.TRequiredListValidator = function() +{ + var min = undef(this.attr.min) ? Number.NEGATIVE_INFINITY : parseInt(this.attr.min); + var max = undef(this.attr.max) ? Number.POSITIVE_INFINITY : parseInt(this.attr.max); + + var elements = document.getElementsByName(this.attr.selector); + + if(elements.length <= 0) + elements = document.getElementsBySelector(this.attr.selector); + + if(elements.length <= 0) + return true; + + var required = new Array(); + if(isString(this.attr.required) && this.attr.required.length > 0) + required = this.attr.required.split(/,\s* /); + + var isValid = true; + + var validator = Prado.Validation.TRequiredListValidator; + + switch(elements[0].type) + { + case 'radio': + case 'checkbox': + isValid = validator.IsValidRadioList(elements, min, max, required); + break; + case 'select-multiple': + isValid = validator.IsValidSelectMultipleList(elements, min, max, required); + break; + } + + var className = this.attr.elementcssclass; + if(isString(className) && className.length>0) + map(elements, function(element){ condClass(element, className, !isValid); }); + if(undef(this.observingRequiredList)) + { + Event.observe(elements, "change", this.validate.bind(this)); + this.observingRequiredList = true; + } + return isValid; +} + +//radio group selection +Prado.Validation.TRequiredListValidator.IsValidRadioList = function(elements, min, max, required) +{ + var checked = 0; + var values = new Array(); + for(var i = 0; i < elements.length; i++) + { + if(elements[i].checked) + { + checked++; + values.push(elements[i].value); + } + } + return Prado.Validation.TRequiredListValidator.IsValidList(checked, values, min, max, required); +} + +//multiple selection check +Prado.Validation.TRequiredListValidator.IsValidSelectMultipleList = function(elements, min, max, required) +{ + var checked = 0; + var values = new Array(); + for(var i = 0; i < elements.length; i++) + { + var selection = elements[i]; + for(var j = 0; j < selection.options.length; j++) + { + if(selection.options[j].selected) + { + checked++; + values.push(selection.options[j].value); + } + } + } + return Prado.Validation.TRequiredListValidator.IsValidList(checked, values, min, max, required); +} + +//check if the list was valid +Prado.Validation.TRequiredListValidator.IsValidList = function(checkes, values, min, max, required) +{ + var exists = true; + + if(required.length > 0) + { + //required and the values must at least be have same lengths + if(values.length < required.length) + return false; + for(var k = 0; k < required.length; k++) + exists = exists && values.contains(required[k]); + } + + return exists && checkes >= min && checkes <= max; +} -- cgit v1.2.3