2 * Polyfill for ECMAScript5's bind() function.
4 * Adds compatible .bind() function; needed for Internet Explorer < 9
5 * Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
8 if (!Function.prototype.bind) {
9 Function.prototype.bind = function (oThis) {
10 if (typeof this !== "function") {
11 // closest thing possible to the ECMAScript 5 internal IsCallable function
12 throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
15 var aArgs = Array.prototype.slice.call(arguments, 1),
17 fNOP = function () {},
18 fBound = function () {
19 return fToBind.apply(this instanceof fNOP && oThis
22 aArgs.concat(Array.prototype.slice.call(arguments)));
25 fNOP.prototype = this.prototype;
26 fBound.prototype = new fNOP();
36 * Author: Dan Webb (dan@danwebb.net)
37 * GIT: github.com:danwrong/low-pro-for-jquery.git
38 * Download: http://github.com/danwrong/low-pro-for-jquery/tree/master/src/lowpro.jquery.js?raw=true
40 * A jQuery port of the Low Pro behavior framework that was originally written for Prototype.
42 * Prado actually uses it as a base to emulate OOP subclassing, inheritance and contructor events.
43 * The "behaviour" and the "Remote" bits are not used and have been commented out.
48 var addMethods = function(source) {
49 var ancestor = this.superclass && this.superclass.prototype;
50 var properties = $.keys(source);
52 if (!$.keys({ toString: true }).length) properties.push("toString", "valueOf");
54 for (var i = 0, length = properties.length; i < length; i++) {
55 var property = properties[i], value = source[property];
56 if (ancestor && $.isFunction(value) && $.argumentNames(value)[0] == "$super") {
58 var method = value, value = $.extend($.wrap((function(m) {
59 return function() { return ancestor[m].apply(this, arguments) };
60 })(property), method), {
61 valueOf: function() { return method },
62 toString: function() { return method.toString() }
65 this.prototype[property] = value;
74 for (var key in obj) keys.push(key);
78 argumentNames: function(func) {
79 var names = func.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(/, ?/);
80 return names.length == 1 && !names[0] ? [] : names;
83 bind: function(func, scope) {
85 return func.apply(scope, $.makeArray(arguments));
89 wrap: function(func, wrapper) {
92 return wrapper.apply(this, [$.bind(__method, this)].concat($.makeArray(arguments)));
97 var parent = null, properties = $.makeArray(arguments);
98 if ($.isFunction(properties[0])) parent = properties.shift();
100 var klass = function() {
101 this.initialize.apply(this, arguments);
104 klass.superclass = parent;
105 klass.subclasses = [];
106 klass.addMethods = addMethods;
109 var subclass = function() { };
110 subclass.prototype = parent.prototype;
111 klass.prototype = new subclass;
112 parent.subclasses.push(klass);
115 for (var i = 0; i < properties.length; i++)
116 klass.addMethods(properties[i]);
118 if (!klass.prototype.initialize)
119 klass.prototype.initialize = function() {};
121 klass.prototype.constructor = klass;
125 delegate: function(rules) {
127 var target = $(e.target), parent = null;
128 for (var selector in rules) {
129 if (target.is(selector) || ((parent = target.parents(selector)) && parent.length > 0)) {
130 return rules[selector].apply(this, [parent || target].concat($.makeArray(arguments)));
138 var bindEvents = function(instance) {
139 for (var member in instance) {
140 if (member.match(/^on(.+)/) && typeof instance[member] == 'function') {
141 instance.element.live(RegExp.$1, {'behavior': instance}, instance[member]);
146 var behaviorWrapper = function(behavior) {
147 return $.klass(behavior, {
148 initialize: function($super, element, args) {
149 this.element = element;
150 if ($super) $super.apply(this, args);
152 trigger: function(eventType, extraParameters) {
153 var parameters = [this].concat(extraParameters);
154 this.element.trigger(eventType, parameters);
159 var attachBehavior = function(el, behavior, args) {
160 var wrapper = behaviorWrapper(behavior);
161 var instance = new wrapper(el, args);
163 bindEvents(instance);
165 if (!behavior.instances) behavior.instances = [];
167 behavior.instances.push(instance);
175 var args = $.makeArray(arguments), behavior = args.shift();
176 attachBehavior(this, behavior, args);
179 delegate: function(type, rules) {
180 return this.bind(type, $.delegate(rules));
182 attached: function(behavior) {
185 if (!behavior.instances) return instances;
187 this.each(function(i, element) {
188 $.each(behavior.instances, function(i, instance) {
189 if (instance.element.get(0) == element) instances.push(instance);
195 firstAttached: function(behavior) {
196 return this.attached(behavior)[0];
201 initialize: function(options) {
202 if (this.element.attr('nodeName') == 'FORM') this.element.attach(Remote.Form, options);
203 else this.element.attach(Remote.Link, options);
207 Remote.Base = $.klass({
208 initialize : function(options) {
209 this.options = $.extend(true, {}, options || {});
211 _makeRequest : function(options) {
217 Remote.Link = $.klass(Remote.Base, {
218 onclick: function(e) {
219 var options = $.extend({
220 url: $(this).attr('href'),
223 return e.data.behavior._makeRequest(e.data.behavior.options);
227 Remote.Form = $.klass(Remote.Base, {
228 onclick: function(e) {
229 var target = e.target;
231 if ($.inArray(target.nodeName.toLowerCase(), ['input', 'button']) >= 0 && target.type.match(/submit|image/))
232 e.data.behavior._submitButton = target;
234 onsubmit: function(e) {
235 var elm = $(this), data = elm.serializeArray();
237 if (e.data.behavior._submitButton) data.push({
238 name: e.data.behavior._submitButton.name,
239 value: e.data.behavior._submitButton.value
242 var options = $.extend({
243 url : elm.attr('action'),
244 type : elm.attr('method') || 'GET',
246 }, e.data.behavior.options);
248 e.data.behavior._makeRequest(options);
255 beforeSend: function(xhr) {
257 xhr.setRequestHeader("Accept", "text/javascript, text/html, application/xml, text/xml, *\/*");
265 * Prado base namespace
271 * Version of Prado clientscripts
277 * Registry for Prado components
283 Prado.RequestManager =
285 FIELD_POSTBACK_TARGET : 'PRADO_POSTBACK_TARGET',
287 FIELD_POSTBACK_PARAMETER : 'PRADO_POSTBACK_PARAMETER'
290 * Performs a PostBack using javascript.
291 * @function Prado.PostBack
292 * @param options - Postback options
293 * @param event - Event that triggered this postback
294 * @... {string} FormID - Form that should be posted back
295 * @... {optional boolean} CausesValidation - Validate before PostBack if true
296 * @... {optional string} ValidationGroup - Group to Validate
297 * @... {optional string} ID - Validation ID
298 * @... {optional string} PostBackUrl - Postback URL
299 * @... {optional boolean} TrackFocus - Keep track of focused element if true
300 * @... {string} EventTarget - Id of element that triggered PostBack
301 * @... {string} EventParameter - EventParameter for PostBack
303 Prado.PostBack = jQuery.klass(
307 initialize: function(options, event)
309 jQuery.extend(this.options, options || {});
316 return jQuery("#" + this.options['FormID']).get(0);
319 doPostBack : function()
321 var form = this.getForm();
322 if(this.options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
324 if(!Prado.Validation.validate(this.options['FormID'], this.options['ValidationGroup'], jQuery("#" + this.options['ID'])))
325 return this.event.preventDefault();
328 if(this.options['PostBackUrl'] && this.options['PostBackUrl'].length > 0)
329 form.action = this.options['PostBackUrl'];
331 if(this.options['TrackFocus'])
333 var lastFocus = jQuery('#PRADO_LASTFOCUS');
336 var active = document.activeElement; //where did this come from
338 lastFocus.value = active.id;
340 lastFocus.value = this.options['EventTarget'];
345 if(this.options.EventTarget)
347 input = document.createElement("input");
348 input.setAttribute("type", "hidden");
349 input.setAttribute("name", Prado.RequestManager.FIELD_POSTBACK_TARGET);
350 input.setAttribute("value", this.options.EventTarget);
351 form.appendChild(input);
353 if(this.options.EventParameter)
355 input = document.createElement("input");
356 input.setAttribute("type", "hidden");
357 input.setAttribute("name", Prado.RequestManager.FIELD_POSTBACK_PARAMETER);
358 input.setAttribute("value", this.options.EventParameter);
359 form.appendChild(input);
362 jQuery(form).trigger('submit');
367 * Prado utilities to manipulate DOM elements.
368 * @object Prado.Element
373 * Executes a jQuery method on a particular element.
375 * @param {string} element - Element id
376 * @param {string} method - method name
377 * @param {array} value - method parameters
379 j: function(element, method, params)
381 var obj=jQuery("#" + element);
382 obj[method].apply(obj, params);
386 * Select options from a selectable element.
388 * @param {string} element - Element id
389 * @param {string} method - Name of any {@link Prado.Element.Selection} method
390 * @param {array|boolean|string} value - Values that should be selected
391 * @param {int} total - Number of elements
393 select : function(element, method, value, total)
395 var el = jQuery("#" + element).get(0);
397 var selection = Prado.Element.Selection;
398 if(typeof(selection[method]) == "function")
400 var control = selection.isSelectable(el) ? [el] : selection.getListElements(element,total);
401 selection[method](control, value);
406 * Sets an attribute of a DOM element.
408 * @param {string} element - Element id
409 * @param {string} attribute - Name of attribute
410 * @param {string} value - Value of attribute
412 setAttribute : function(element, attribute, value)
414 var el = jQuery("#" + element);
416 if((attribute == "disabled" || attribute == "multiple" || attribute == "readonly" || attribute == "href") && value==false)
417 el.removeAttr(attribute);
418 else if(attribute.match(/^on/i)) //event methods
422 eval("(func = function(event){"+value+"})");
423 el.get(0)[attribute] = func;
428 throw "Error in evaluating '"+value+"' for attribute "+attribute+" for element "+element;
432 el.attr(attribute, value);
435 scrollTo : function(element, options)
441 jQuery.extend(op, options || {});
442 jQuery('html, body').animate({
443 scrollTop: jQuery("#"+element).offset().top - op.offset
447 focus : function(element)
449 jQuery(document).ajaxStop(function () {
450 setTimeout(function(){
451 jQuery("#"+element).focus();
457 * Sets the options for a select element.
459 * @param {string} element - Element id
460 * @param {array[]} options - Array of options, each an array of structure
461 * [ "optionText" , "optionValue" , "optionGroup" ]
463 setOptions : function(element, options)
465 var el = jQuery("#" + element).get(0);
466 var previousGroup = null;
468 if(el && el.tagName.toLowerCase() == "select")
470 while(el.childNodes.length > 0)
471 el.removeChild(el.lastChild);
473 var optDom = Prado.Element.createOptions(options);
474 for(var i = 0; i < optDom.length; i++)
475 el.appendChild(optDom[i]);
480 * Create opt-group options from an array of options.
481 * @function {array} ?
482 * @param {array[]} options - Array of options, each an array of structure
483 * [ "optionText" , "optionValue" , "optionGroup" ]
484 * @returns Array of option DOM elements
486 createOptions : function(options)
488 var previousGroup = null;
491 for(var i = 0; i<options.length; i++)
493 var option = options[i];
494 if(option.length > 2)
496 var group = option[2];
497 if(group!=previousGroup)
499 if(previousGroup!=null && optgroup!=null)
501 result.push(optgroup);
505 optgroup = document.createElement('optgroup');
506 optgroup.label = group;
507 previousGroup = group;
510 var opt = document.createElement('option');
511 opt.text = option[0];
512 opt.innerHTML = option[0];
513 opt.value = option[1];
515 optgroup.appendChild(opt);
520 result.push(optgroup);
525 * Replace a DOM element either with given content or
526 * with content from a CallBack response boundary
527 * using a replacement method.
529 * @param {string|element} element - DOM element or element id
530 * @param {optional string} content - New content of element
531 * @param {optional string} boundary - Boundary of new content
532 * @param {optional boolean} self - Whether to replace itself or just the inner content
534 replace : function(element, content, boundary, self)
538 var result = this.extractContent(boundary);
543 jQuery('#'+element).replaceWith(content);
545 jQuery('#'+element).html(content);
549 * Appends a javascript block to the document.
551 * @param {string} boundary - Boundary containing the javascript code
553 appendScriptBlock : function(boundary)
555 var content = this.extractContent(boundary);
559 var el = document.createElement("script");
560 el.type = "text/javascript";
561 el.id = 'inline_' + boundary;
564 (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(el);
565 el.parentNode.removeChild(el);
569 * Evaluate a javascript snippet from a string.
571 * @param {string} content - String containing the script
572 * @param {string} boundary - Boundary containing the script
574 evaluateScript : function(content, boundary)
578 var result = this.extractContent(boundary);
585 jQuery.globalEval(content);
589 if(typeof(Logger) != "undefined")
590 Logger.error('Error during evaluation of script "'+content+'"');
599 * Utilities for selections.
600 * @object Prado.Element.Selection
602 Prado.Element.Selection =
605 * Check if an DOM element can be selected.
606 * @function {boolean} ?
607 * @param {element} el - DOM elemet
608 * @returns true if element is selectable
610 isSelectable : function(el)
614 switch(el.type.toLowerCase())
619 case 'select-multiple':
628 * Set checked attribute of a checkbox or radiobutton to value.
629 * @function {boolean} ?
630 * @param {element} el - DOM element
631 * @param {boolean} value - New value of checked attribute
632 * @returns New value of checked attribute
634 inputValue : function(el, value)
636 switch(el.type.toLowerCase())
640 return el.checked = value;
645 * Set selected attribute for elements options by value.
646 * If value is boolean, all elements options selected attribute will be set
647 * to value. Otherwhise all options that have the given value will be selected.
649 * @param {element[]} elements - Array of selectable DOM elements
650 * @param {boolean|string} value - Value of options that should be selected or boolean value of selection status
652 selectValue : function(elements, value)
654 jQuery.each(elements, function(idx, el)
656 jQuery.each(el.options, function(idx, option)
658 if(typeof(value) == "boolean")
659 option.selected = value;
660 else if(option.value == value)
661 option.selected = true;
667 * Set selected attribute for elements options by array of values.
669 * @param {element[]} elements - Array of selectable DOM elements
670 * @param {string[]} value - Array of values to select
672 selectValues : function(elements, values)
674 var selection = this;
675 jQuery.each(values, function(idx, value)
677 selection.selectValue(elements,value);
682 * Set selected attribute for elements options by option index.
684 * @param {element[]} elements - Array of selectable DOM elements
685 * @param {int} index - Index of option to select
687 selectIndex : function(elements, index)
689 jQuery.each(elements, function(idx, el)
691 if(el.type.toLowerCase() == 'select-one')
692 el.selectedIndex = index;
695 for(var i = 0; i<el.length; i++)
698 el.options[i].selected = true;
705 * Set selected attribute to true for all elements options.
707 * @param {element[]} elements - Array of selectable DOM elements
709 selectAll : function(elements)
711 jQuery.each(elements, function(idx, el)
713 if(el.type.toLowerCase() != 'select-one')
715 jQuery.each(el.options, function(idx, option)
717 option.selected = true;
724 * Toggle the selected attribute for elements options.
726 * @param {element[]} elements - Array of selectable DOM elements
728 selectInvert : function(elements)
730 jQuery.each(elements, function(idx, el)
732 if(el.type.toLowerCase() != 'select-one')
734 jQuery.each(el.options, function(idx, option)
736 option.selected = !option.selected;
743 * Set selected attribute for elements options by array of option indices.
745 * @param {element[]} elements - Array of selectable DOM elements
746 * @param {int[]} indices - Array of option indices to select
748 selectIndices : function(elements, indices)
750 var selection = this;
751 jQuery.each(indices, function(idx, index)
753 selection.selectIndex(elements,index);
760 * @param {element[]} elements - Array of selectable DOM elements
762 selectClear : function(elements)
764 jQuery.each(elements, function(idx, el)
766 el.selectedIndex = -1;
771 * Get list elements of an element.
772 * @function {element[]} ?
773 * @param {element[]} elements - Array of selectable DOM elements
774 * @param {int} total - Number of list elements to return
775 * @returns Array of list DOM elements
777 getListElements : function(element, total)
779 var elements = new Array();
781 for(var i = 0; i < total; i++)
783 el = jQuery("#"+element+"_c"+i).get(0);
791 * Set checked attribute of elements by value.
792 * If value is boolean, checked attribute will be set to value.
793 * Otherwhise all elements that have the given value will be checked.
795 * @param {element[]} elements - Array of checkable DOM elements
796 * @param {boolean|String} value - Value that should be checked or boolean value of checked status
799 checkValue : function(elements, value)
801 jQuery.each(elements, function(idx, el)
803 if(typeof(value) == "boolean")
805 else if(el.value == value)
811 * Set checked attribute of elements by array of values.
813 * @param {element[]} elements - Array of checkable DOM elements
814 * @param {string[]} values - Values that should be checked
817 checkValues : function(elements, values)
819 var selection = this;
820 jQuery(values).each(function(idx, value)
822 selection.checkValue(elements, value);
827 * Set checked attribute of elements by list index.
829 * @param {element[]} elements - Array of checkable DOM elements
830 * @param {int} index - Index of element to set checked
832 checkIndex : function(elements, index)
834 for(var i = 0; i<elements.length; i++)
837 elements[i].checked = true;
842 * Set checked attribute of elements by array of list indices.
844 * @param {element[]} elements - Array of selectable DOM elements
845 * @param {int[]} indices - Array of list indices to set checked
847 checkIndices : function(elements, indices)
849 var selection = this;
850 jQuery.each(indices, function(idx, index)
852 selection.checkIndex(elements, index);
859 * @param {element[]} elements - Array of checkable DOM elements
861 checkClear : function(elements)
863 jQuery.each(elements, function(idx, el)
870 * Set checked attribute of all elements to true.
872 * @param {element[]} elements - Array of checkable DOM elements
874 checkAll : function(elements)
876 jQuery.each(elements, function(idx, el)
883 * Toggle the checked attribute of elements.
885 * @param {element[]} elements - Array of selectable DOM elements
887 checkInvert : function(elements)
889 jQuery.each(elements, function(idx, el)
891 el.checked = !el.checked;
896 jQuery.extend(String.prototype, {
899 * Add padding to string
900 * @function {string} ?
901 * @param {string} side - "left" to pad the string on the left, "right" to pad right.
902 * @param {int} len - Minimum string length.
903 * @param {string} chr - Character(s) to pad
904 * @returns Padded string
906 pad : function(side, len, chr) {
909 var left = side.toLowerCase()=='left';
910 while (s.length<len) s = left? chr + s : s + chr;
915 * Add left padding to string
916 * @function {string} ?
917 * @param {int} len - Minimum string length.
918 * @param {string} chr - Character(s) to pad
919 * @returns Padded string
921 padLeft : function(len, chr) {
922 return this.pad('left',len,chr);
926 * Add right padding to string
927 * @function {string} ?
928 * @param {int} len - Minimum string length.
929 * @param {string} chr - Character(s) to pad
930 * @returns Padded string
932 padRight : function(len, chr) {
933 return this.pad('right',len,chr);
937 * Add zeros to the right of string
938 * @function {string} ?
939 * @param {int} len - Minimum string length.
940 * @returns Padded string
942 zerofill : function(len) {
943 return this.padLeft(len,'0');
947 * Remove white spaces from both ends of string.
948 * @function {string} ?
949 * @returns Trimmed string
952 return this.replace(/^\s+|\s+$/g,'');
956 * Remove white spaces from the left side of string.
957 * @function {string} ?
958 * @returns Trimmed string
960 trimLeft : function() {
961 return this.replace(/^\s+/,'');
965 * Remove white spaces from the right side of string.
966 * @function {string} ?
967 * @returns Trimmed string
969 trimRight : function() {
970 return this.replace(/\s+$/,'');
974 * Convert period separated function names into a function reference.
977 * "Prado.AJAX.Callback.Action.setValue".toFunction()
979 * @function {function} ?
980 * @returns Reference to the corresponding function
982 toFunction : function()
984 var commands = this.split(/\./);
985 var command = window;
986 jQuery(commands).each(function(idx, action)
988 if(command[new String(action)])
989 command=command[new String(action)];
991 if(typeof(command) == "function")
995 if(typeof Logger != "undefined")
996 Logger.error("Missing function", this);
998 throw new Error ("Missing function '"+this+"'");
1003 * Convert string into integer, returns null if not integer.
1005 * @returns Integer, null if string does not represent an integer.
1007 toInteger : function()
1009 var exp = /^\s*[-\+]?\d+\s*$/;
1010 if (this.match(exp) == null)
1012 var num = parseInt(this, 10);
1013 return (isNaN(num) ? null : num);
1017 * Convert string into a double/float value. <b>Internationalization
1018 * is not supported</b>
1019 * @function {double} ?
1020 * @param {string} decimalchar - Decimal character, defaults to "."
1021 * @returns Double, null if string does not represent a float value
1023 toDouble : function(decimalchar)
1025 if(this.length <= 0) return null;
1026 decimalchar = decimalchar || ".";
1027 var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$");
1028 var m = this.match(exp);
1036 var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4];
1037 var num = parseFloat(cleanInput);
1038 return (isNaN(num) ? null : num);
1042 * Convert strings that represent a currency value to float.
1043 * E.g. "10,000.50" will become "10000.50". The number
1044 * of dicimal digits, grouping and decimal characters can be specified.
1045 * <i>The currency input format is <b>very</b> strict, null will be returned if
1046 * the pattern does not match</i>.
1047 * @function {double} ?
1048 * @param {string} groupchar - Grouping character, defaults to ","
1049 * @param {int} digits - Number of decimal digits
1050 * @param {string} decimalchar - Decimal character, defaults to "."
1051 * @returns Double, null if string does not represent a currency value
1053 toCurrency : function(groupchar, digits, decimalchar)
1055 groupchar = groupchar || ",";
1056 decimalchar = decimalchar || ".";
1057 digits = typeof(digits) == "undefined" ? 2 : digits;
1059 var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)"
1060 + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "")
1062 var m = this.match(exp);
1065 var intermed = m[2] + m[5] ;
1066 var cleanInput = m[1] + intermed.replace(
1067 new RegExp("(\\" + groupchar + ")", "g"), "")
1068 + ((digits > 0) ? "." + m[7] : "");
1069 var num = parseFloat(cleanInput);
1070 return (isNaN(num) ? null : num);
1074 jQuery.extend(Date.prototype,
1079 * @param {string} format - TODO
1080 * @param {string} data - TODO
1083 SimpleFormat: function(format, data)
1086 var bits = new Array();
1087 bits['d'] = this.getDate();
1088 bits['dd'] = String(this.getDate()).zerofill(2);
1090 bits['M'] = this.getMonth()+1;
1091 bits['MM'] = String(this.getMonth()+1).zerofill(2);
1092 if(data.AbbreviatedMonthNames)
1093 bits['MMM'] = data.AbbreviatedMonthNames[this.getMonth()];
1095 bits['MMMM'] = data.MonthNames[this.getMonth()];
1096 var yearStr = "" + this.getFullYear();
1097 yearStr = (yearStr.length == 2) ? '19' + yearStr: yearStr;
1098 bits['yyyy'] = yearStr;
1099 bits['yy'] = bits['yyyy'].toString().substr(2,2);
1101 // do some funky regexs to replace the format string
1102 // with the real values
1103 var frm = new String(format);
1104 for (var sect in bits)
1106 var reg = new RegExp("\\b"+sect+"\\b" ,"g");
1107 frm = frm.replace(reg, bits[sect]);
1114 * @function {string} ?
1117 toISODate : function()
1119 var y = this.getFullYear();
1120 var m = String(this.getMonth() + 1).zerofill(2);
1121 var d = String(this.getDate()).zerofill(2);
1122 return String(y) + String(m) + String(d);
1131 * @param {string} format - TODO
1132 * @param {string} data - TODO
1135 SimpleParse: function(value, format)
1137 var val=String(value);
1138 format=String(format);
1140 if(val.length <= 0) return null;
1142 if(format.length <= 0) return new Date(value);
1144 var isInteger = function (val)
1146 var digits="1234567890";
1147 for (var i=0; i < val.length; i++)
1149 if (digits.indexOf(val.charAt(i))==-1) { return false; }
1154 var getInt = function(str,i,minlength,maxlength)
1156 for (var x=maxlength; x>=minlength; x--)
1158 var token=str.substring(i,i+x);
1159 if (token.length < minlength) { return null; }
1160 if (isInteger(token)) { return token; }
1172 var year=now.getFullYear();
1173 var month=now.getMonth()+1;
1176 while (i_format < format.length)
1178 // Get next token from format string
1179 c=format.charAt(i_format);
1181 while ((format.charAt(i_format)==c) && (i_format < format.length))
1183 token += format.charAt(i_format++);
1186 // Extract contents of value based on format token
1187 if (token=="yyyy" || token=="yy" || token=="y")
1189 if (token=="yyyy") { x=4;y=4; }
1190 if (token=="yy") { x=2;y=2; }
1191 if (token=="y") { x=2;y=4; }
1192 year=getInt(val,i_val,x,y);
1193 if (year==null) { return null; }
1194 i_val += year.length;
1197 if (year > 70) { year=1900+(year-0); }
1198 else { year=2000+(year-0); }
1202 else if (token=="MM"||token=="M")
1204 month=getInt(val,i_val,token.length,2);
1205 if(month==null||(month<1)||(month>12)){return null;}
1206 i_val+=month.length;
1208 else if (token=="dd"||token=="d")
1210 date=getInt(val,i_val,token.length,2);
1211 if(date==null||(date<1)||(date>31)){return null;}
1216 if (val.substring(i_val,i_val+token.length)!=token) {return null;}
1217 else {i_val+=token.length;}
1221 // If there are any trailing characters left in the value, it doesn't match
1222 if (i_val != val.length) { return null; }
1224 // Is date valid for month?
1227 // Check for leap year
1228 if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
1229 if (date > 29){ return null; }
1231 else { if (date > 28) { return null; } }
1234 if ((month==4)||(month==6)||(month==9)||(month==11))
1236 if (date > 30) { return null; }
1239 var newdate=new Date(year,month-1,date, 0, 0, 0);