📄 form-field.js
字号:
// $Id: form-field.js 7944 2007-08-22 10:59:14Z andrew $/** * * Copyright (c) 2004-2006 by Zapatec, Inc. * http://www.zapatec.com * 1700 MLK Way, Berkeley, California, * 94709, U.S.A. * All rights reserved. *//** * @private * The Zapatec.Form object constructor. * It would put special marks near field(basing on form config). * * You always could retrieve reference to this object: * <pre> * document.getElementById('yourField').zpFormField * </pre> * @param form {Object} reference to Zapatec.Form instance. @see Zapatec.Form * @param field {Object} reference to HTML form element. */Zapatec.Form.Field = function(objArgs){ // Call constructor of superclass Zapatec.Form.SUPERconstructor.call(this, objArgs);};/** * Unique static id of the widget class. Gives ability for Zapatec#inherit to * determine and store path to this file correctly when it is included using * Zapatec#include. When this file is included using Zapatec#include or path * to this file is gotten using Zapatec#getPath, this value must be specified * as script id. * @private */Zapatec.Form.Field.id = "Zapatec.Form.Field";// Inherit SuperClassZapatec.inherit(Zapatec.Form.Field, Zapatec.Widget);/** * Configures form field. Gets called from parent init method. * * @private * @param {object} objArgs User configuration */Zapatec.Form.Field.prototype.configure = function(objArgs){ // Set defaults config options this.defineConfigOption('theme', objArgs.formConfig && objArgs.formConfig.theme ? objArgs.formConfig.theme : "" ); this.defineConfigOption('themePath', objArgs.formConfig && objArgs.formConfig.themePath ? objArgs.formConfig.themePath : Zapatec.Form.path + "../themes/" ); if(!objArgs.lang && objArgs.formConfig.lang){ objArgs.lang = objArgs.formConfig.lang; } if(!objArgs.langCountryCode && objArgs.formConfig.langCountryCode){ objArgs.langCountryCode = objArgs.formConfig.langCountryCode; } if(!objArgs.langEncoding && objArgs.formConfig.langEncoding){ objArgs.langEncoding = objArgs.formConfig.langEncoding; } this.defineConfigOption('form'); this.defineConfigOption('formConfig', {}); this.defineConfigOption('field'); this.defineConfigOption('langId', "Zapatec.Form"); // Call parent method Zapatec.Form.SUPERclass.configure.call(this, objArgs); this.config.form = Zapatec.Widget.getElementById(this.config.form); this.config.field = Zapatec.Widget.getElementById(this.config.field);};/** * Reconfigures the widget with new config options after it was initialized. * May be used to change look or behavior of the widget after it has loaded * the data. In the argument pass only values for changed config options. * There is no need to pass config options that were not changed. * * @param {object} objArgs Changes to user configuration */Zapatec.Form.Field.prototype.reconfigure = function(objArgs) { // Call parent method Zapatec.Form.SUPERclass.reconfigure.call(this, objArgs);};Zapatec.Form.Field.prototype.init = function(objArgs){ if (Zapatec.Form.Utils.ignoreField(objArgs.field) || objArgs.field.zpFormField) { return null; } this.autoCompleteOptions = []; // stores values for autocompletion this.form = null; // storing params in internal variables. this.state = {}; // variable for storing internal variables this.features = {}; // setup array of features this.keyPressCounter = 0; // this variable indicates how many key was pressed during last // Zapatec.Form.Field.DELAYED_INTERVAL period. this.firstRun = true; // default value this.chars = null; // if field has zpFormMask - this.enteredValue = null; // it will use this arrays this.dropDown = null; // if needed - this variable will be used this.isBooleanField = false; // if this is boolean (boolean field can be //only in two stated - checked on unchecked) this.isEditing = false; // Determines if field is editing in a moment // processing Widget functionality Zapatec.Form.SUPERclass.init.call(this, objArgs); this.field = this.config.field; this.features = Zapatec.Form.Utils.getTokens(this.field.className, " "); if(this.hasFeature("zpFormRequired")){ this.setFeature("zpFormRequired", true); } this.isBooleanField = ( this.field.nodeName.toLowerCase() == 'input' && ( this.field.type.toLowerCase() == 'radio' || this.field.type.toLowerCase() == 'checkbox' ) ); var md = null; // use new "zpFormAllowedChars" instead of deprecated "zpFormAllowed-" if(md = this.field.className.match(/zpFormAllowed-(\S+)/)){ if(!this.features['zpFormAllowedChars']){ this.features['zpFormAllowedChars'] = ""; } this.features['zpFormAllowedChars'] += '\\' + md[1].split('').join('\\'); } if( typeof(this.features['zpFormAllowedChars']) != 'undefined' && this.getFeature('zpFormAllowedChars') == null ){ var undef; this.features['zpFormAllowedChars'] = undef; } // if this field has zpFormAutoComplete or zpFormAutoCompleteStrict - // extract autocomplete options if( ( this.hasFeature("zpFormAutoComplete") || this.hasFeature("zpFormAutoCompleteStrict") ) && this.field.nodeName.toUpperCase() == "SELECT" ){ var input = document.createElement('input'); for(var ii = 0; ii < this.field.attributes.length; ii++){ var attr = this.field.attributes[ii]; if(attr.name == 'class'){ input.className = this.field.getAttribute(attr.name); } else { input.setAttribute(attr.name, this.field.getAttribute(attr.name)); } } for(var ii = 0; ii < this.field.options.length; ii++){ this.autoCompleteOptions.push(this.field.options[ii].innerHTML); } if(this.field.selectedIndex != null){ var val = null; if( this.field.options[this.field.selectedIndex].value != null && this.field.options[this.field.selectedIndex].value != "" ){ val = this.field.options[this.field.selectedIndex].value; } else { val = this.field.options[this.field.selectedIndex].innerHTML; } input.value = val; input.setAttribute("value", val); } Zapatec.Utils.insertAfter(this.field, input); Zapatec.Utils.destroy(this.field); input.type = 'text'; this.field = input; } if( this.hasFeature("zpFormAutoComplete") || this.hasFeature("zpFormAutoCompleteStrict") || this.hasFeature("zpFormSuggest") ){ // disable browser tips this.field.setAttribute("autocomplete", "off"); this.field.autoComplete = "off"; } var self = this; this.form = this.config.form; if(!this.form){ // Form widget stub this.form = { container: {elements:[this.field]}, fireEvent: function(){}, validate: function(){return self.validate()}, toggleSubmits: function(){}, container: this.field.parentNode }; if(this.field.parentNode){ Zapatec.Utils.addClass(this.field.parentNode, this.getClassName({prefix: "zpForm"})); } } // initializing internal arrays for zpFormMask validation type if(this.hasFeature("zpFormMask")){ // remove maxlength attribute if present. // It makes no sense together with mask and avoids mask to work correctly if(this.field.hasAttribute && this.field.hasAttribute("maxlength")){ this.field.setAttribute("maxlength", null); } var mask = this.getFeature("zpFormMask"); var maskChars = mask.split(''); this.chars = []; this.enteredValue = []; for(var ii = 0; ii < maskChars.length; ii++){ var tmp = null; switch(maskChars[ii]){ case "0": tmp = "[0-9]"; break; case "L": tmp = "[a-zA-Z]"; break; case "A": tmp = "[0-9a-zA-Z]"; break; case "&": tmp = "."; break; case "\\": i++; if(i >= maskChars.length) break; // fall through default: this.chars.push(maskChars[ii]); this.enteredValue.push(maskChars[ii]); } if(tmp != null){ var re = new RegExp("^" + tmp + "$"); this.chars.push(re); this.enteredValue.push(null); } } } // creating back reference this.createProperty(this.field, "zpFormField", this); // setting up special handlers for all events. // Note: we need to get reference to Zapatec.Form.Field from field object, // because this can be cloned field. In that case in IE cloned object // will have eventlisteners from original object. var oldOnKeyDown = this.field.onkeydown || function(){return true;}; Zapatec.Utils.createProperty(this.field, "onkeydown", function(ev){ var zpField = Zapatec.Utils.getTargetElement(ev).zpFormField; var res = oldOnKeyDown(); return zpField.keydown(ev) && res; }); var oldOnKeyPress = this.field.onkeypress || function(){return true;}; Zapatec.Utils.createProperty(this.field, "onkeypress", function(ev){ var zpField = Zapatec.Utils.getTargetElement(ev).zpFormField; var res = oldOnKeyPress(); return zpField.keypress(ev) && res; }); Zapatec.Utils.addEvent(this.field, 'keyup', function(ev){ var zpField = Zapatec.Utils.getTargetElement(ev).zpFormField; return zpField.keyup(ev); }); Zapatec.Utils.addEvent(this.field, 'focus', function(ev){ var zpField = Zapatec.Utils.getTargetElement(ev).zpFormField; return zpField.focus(ev); }); Zapatec.Utils.addEvent(this.field, 'blur', function(ev){ var zpField = Zapatec.Utils.getTargetElement(ev).zpFormField; return zpField.blur(ev); }); if(this.field.nodeName.toLowerCase() == 'select'){ Zapatec.Utils.addEvent(this.field, 'change', function(ev){ var zpField = Zapatec.Utils.getTargetElement(ev).zpFormField; return zpField.valueChanged(ev); }); } // validate field when field value changes var onChangeFunc = function(ev){ var zpField = Zapatec.Utils.getTargetElement(ev).zpFormField; return zpField.valueChanged(ev); }; Zapatec.Utils.addEvent(this.field, 'keyup', onChangeFunc); if(Zapatec.is_ie){ Zapatec.Utils.addEvent(this.field, 'paste', onChangeFunc); } else if(Zapatec.is_gecko) { Zapatec.Utils.addEvent(this.field, 'input', onChangeFunc); } else { Zapatec.Utils.addEvent(this.field, 'change', onChangeFunc); } if(this.isBooleanField){ onChangeFunc = function(ev){ var zpField = Zapatec.Utils.getTargetElement(ev).zpFormField; return zpField.booleanChanged(); }; Zapatec.Utils.addEvent(this.field, 'change', onChangeFunc); // IE doesn't fire onchange on first change Zapatec.Utils.addEvent(this.field, 'click', onChangeFunc); } // Next some <span> elements, as IE doens't support multi-class selectors. this.requiredMark = Zapatec.Utils.createElement('span'); this.requiredMark.className = Zapatec.Form.IGNORE_CLASSNAME; this.requiredMark.id = "zpFormField" + this.id + "StatusImg1"; this.editingMark = this.requiredMark.appendChild(Zapatec.Utils.createElement('span')); this.editingMark.className = Zapatec.Form.IGNORE_CLASSNAME; this.editingMark.id = "zpFormField" + this.id + "StatusImg2"; this.emptyMark = this.editingMark.appendChild(Zapatec.Utils.createElement('span')); this.emptyMark.className = Zapatec.Form.IGNORE_CLASSNAME; this.emptyMark.id = "zpFormField" + this.id + "StatusImg3"; this.validMark = this.emptyMark.appendChild(Zapatec.Utils.createElement('span')); this.validMark.className = Zapatec.Form.IGNORE_CLASSNAME; this.validMark.id = "zpFormField" + this.id + "StatusImg4"; this.fetchingMark = this.validMark.appendChild(Zapatec.Utils.createElement('span')); this.fetchingMark.className = Zapatec.Form.IGNORE_CLASSNAME; this.fetchingMark.id = "zpFormField" + this.id + "StatusImg5"; // The innermost is the one we actually style. this.statusImg = this.fetchingMark.appendChild(Zapatec.Utils.createElement('span')); this.statusImg.className = Zapatec.Form.IGNORE_CLASSNAME + ' zpStatusImg'; this.statusImg.id = "zpFormField" + this.id + "StatusImg"; this.addCircularRef(this, "statusImg"); this.addCircularRef(this, "fetchingMark"); this.addCircularRef(this, "validMark"); this.addCircularRef(this, "emptyMark"); this.addCircularRef(this, "editingMark"); this.addCircularRef(this, "requiredMark"); // An error container. this.errorText = Zapatec.Utils.createElement('span'); this.errorText.id = "zpFormField" + this.id + "ErrorText"; this.errorText.className = Zapatec.Form.IGNORE_CLASSNAME + ' zpFormError'; if(this.field.type && this.field.type.toLowerCase() == "hidden"){ // if this is hidden field - hide dependant elements this.errorText.style.display = 'none'; this.requiredMark.style.display = 'none'; } // Radio buttons and checkboxes needs some more functionality if(this.isBooleanField){ // add custom CSS classes to checkboxes and radiobuttons if(this.field.type.toLowerCase() == "checkbox"){ this.field.className += " zpFormCheckbox"; this.statusImg.className += " zpCheckboxStatusImg"; } else if(this.field.type.toLowerCase() == "radio"){ this.field.className += " zpFormRadio"; this.statusImg.className += " zpRadioStatusImg"; } else { this.statusImg.className += " zpCommonStatusImg"; } } else { this.statusImg.className += " zpCommonStatusImg"; } var lastNode = this.field; // Attach the outermost <span> near the input field. if(this.config.formConfig.statusImgPos == 'afterField'){ Zapatec.Utils.insertAfter(this.field, this.requiredMark); lastNode = this.requiredMark; } else if(this.config.formConfig.statusImgPos == 'beforeField'){ this.field.parentNode.insertBefore(this.requiredMark, this.field); } // Position it by the field if configured that way. if(this.config.formConfig.showErrors == 'afterField'){ Zapatec.Utils.insertAfter(this.field, this.errorText); lastNode = this.errorText; } else if (this.config.formConfig.showErrors == 'beforeField'){ this.field.parentNode.insertBefore(this.errorText, this.field); } if(this.hasFeature("zpFormMultiple")){ this.createProperty(this.field, "zpLastNode", lastNode); } if( this.hasFeature("zpFormSuggest") || this.hasFeature("zpFormAutoComplete") || this.hasFeature("zpFormAutoCompleteStrict") ){ if(typeof(Zapatec.AutoComplete) == 'undefined'){ Zapatec.Transport.loadJS({ url: Zapatec.zapatecPath + '../zpautocomplete/src/zpautocomplete-core.js', async: true, onLoad: function(){ self.initDropDown(); } }); } else { this.initDropDown(); } } if(this.field.value){ // if field has predefined value this.ajaxValidate(); this.suggestValue(); this.ajaxFill(); } this.setValueFromField(true);};// interval before last keystroke and sending request to server.Zapatec.Form.Field.DELAYED_INTERVAL = 1000;/** * @private * Create Zapatec.DropDown object */Zapatec.Form.Field.prototype.initDropDown = function(){ var self = this; var arrow = Zapatec.Utils.createElement("span"); arrow.className = Zapatec.Form.IGNORE_CLASSNAME + " dropDownArrow"; arrow.id = "zpFormField" + this.id + "DropDownArrow"; this.createProperty(arrow, "onclick", function(ev){ self.field.focus(ev); self.autoCompleteValue(self.getAutoCompleteOptions(true)); self.suggestValue(true); }); Zapatec.Utils.insertAfter(this.field, arrow); var tmpConfig = Zapatec.Utils.clone (this.config.formConfig.autoCompleteConfig); if (!tmpConfig) { tmpConfig = {}; } tmpConfig.fields = [this.field]; tmpConfig.width = "auto"; tmpConfig.dataOnDemand = false; tmpConfig.convertTip = function(tipObj){ return tipObj.title; } tmpConfig.selectTip = function(tipObj){ self.setValue(tipObj.title) self.valueChanged(); if (self.field.onchange) { self.field.onchange(); } } this.dropDown = new Zapatec.AutoComplete(tmpConfig); this.dropDown.field = this.field;};/** * @private * This function is called when field value is changed using copy-paste. * For IE it is called when pasting clipboard into field, for FF on each field * value change(including keystrokes), for other browser - on "onchange" event. */Zapatec.Form.Field.prototype.valueChanged = function(ev){ if(this.hasFeature("zpFormAllowedChars") || this.hasFeature("zpFormMask")){ this.setValueFromField(); } else { this.validate(); } if(!ev){ ev = window.event; } this.fireEvent("valueChanged", ev); this.fireEvent("all", ev, "valueChanged"); this.form.fireEvent("valueChanged", ev); this.form.fireEvent("all", ev, "valueChanged"); return true;};/** * @private * This function is called when checkbox or radio button is checked/unchecked. */Zapatec.Form.Field.prototype.booleanChanged = function(ev){ if(!this.isBooleanField){ return; } var elements = this.form.container.elements; for(var ii = 0; ii < elements.length; ii++){ var el = elements[ii]; if( el.name == this.field.name && el.zpFormField ){ if(!this.firstRun){ el.zpFormField.firstRun = false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -