<< | к задаче | главная | печатать | обсудить(0 сообщений) >>
Задача: qForms, библиотека типичного функционала валидации/построения/связки html-форм
Исходник: qforms.js - Один из основных файлов :: qForms api-139 [javascript, code #150, hits: 6764, рейтинг: 3/6,4.88(2251)] +
автор: - [добавлен: 28.05.2006] управление:
  1. // find out which version of JavaScript the user has
  2. var _jsver = 11;
  3. for( var z=2; z < 6; z++ ) document.write("<scr"+"ipt language=\"JavaScript1." + z + "\">_jsver = 1" + z + ";</scr"+"ipt>");
  4.  
  5. /******************************************************************************
  6. qForm API Initialization
  7. ******************************************************************************/
  8. // define _a object
  9. function _a(){
  10. // qForm's Version info
  11. this.version = "139";
  12.  
  13. // initialize the number of qForm instances
  14. this.instances = 0;
  15. // initialize an object to use for pointers
  16. this.objects = new Object();
  17. // the path where the external library components are found
  18. this.librarypath = "";
  19. // specifies whether the browser should autodetect the version of JavaScript being used
  20. this.autodetect = true;
  21. // this specifies the default modules to load when the wildcard ("*") is specified
  22. this.modules = new Array("field", "functions|12", "validation");
  23. // this is the name of the modules that have been loaded, libraries will not be loaded more then once
  24. this.packages = new Object();
  25. // this is a list of validators that has loaded
  26. this.validators = new Array();
  27. // this contains a list of the original contents of a container, when the setValue() method is used on a container, then the containers object is checked to see if the key exists
  28. this.containers = new Object();
  29. // this structure defines the version of JavaScript being used
  30. this.jsver = new Object();
  31. for( var z=1; z < 9; z++ ) this.jsver["1" + z] = "1." + z;
  32.  
  33. // this is background color style to use when a form field validation error has occurred
  34. this.errorColor = "red";
  35. // the style attribute to adjust when throwing an error
  36. this.styleAttribute = "backgroundColor";
  37. // this specifies whether or not to use error color coding (by default browser that support it use it)
  38. this.useErrorColorCoding = (document.all || document.getElementById) ? true : false;
  39. // this specifies whether all qForm objects should be validated upon a form submission, or just the form being submitted. By default only the form being submitted is validated.
  40. this.validateAll = false;
  41. // this specifies whether or not a form can be submitted if validation errors occurred. If set to false, the user gets an alert box, if set to true, the user receives a confirm box.
  42. this.allowSubmitOnError = false;
  43. // the place holder for the number of custom validators that have been initialized
  44. this.customValidators = 0;
  45. // specify whether the reset method should be run when the form object is initialized
  46. this.resetOnInit = false;
  47. // determine whether to show status bar messages
  48. this.showStatusMsgs = true;
  49.  
  50. // set the regular expression attributes
  51. this.reAttribs = "gi";
  52. return true;
  53. }
  54. qFormAPI = new _a();
  55.  
  56. // define _a setLibraryPath(); prototype
  57. function _a_setLibraryPath(path){
  58. if( path.substring(path.length-1) != '/' ) path += '/';
  59. this.librarypath = path;
  60. return true;
  61. }
  62. _a.prototype.setLibraryPath = _a_setLibraryPath;
  63.  
  64. // define _a include(); prototype
  65. function _a_include(src, path, ver){
  66. var source = src;
  67. if( !source ) return true;
  68. if( !path ) var path = this.librarypath + "qforms/";
  69. if( !ver ) var ver = "";
  70.  
  71. if( source.substring(source.length-3) != ".js" ) source += ".js";
  72. var thisPackage = source.substring(0,source.length-3);
  73.  
  74. var strJS = "<scr"+"ipt language=\"JavaScript";
  75. var strEJS = "\"></scr"+"ipt>";
  76.  
  77. // if the package is already loaded, then kill method
  78. if( this.packages[thisPackage] ) return true;
  79.  
  80. if( thisPackage == "*" ){
  81. for( var i=0; i < this.modules.length; i++ ){
  82. var source = this.modules[i];
  83. var ver = "99";
  84. if( source.indexOf("|") > -1 ){
  85. ver = source.substring(source.indexOf("|") + 1);
  86. source = source.substring(0, source.indexOf("|"));
  87. }
  88. if( _jsver > ver && this.autodetect ){
  89. document.write(strJS + this.jsver[ver] + "\" src=\"" + path + source + "_js" + ver + ".js" + strEJS);
  90. } else {
  91. document.write(strJS + "\" src=\"" + path + source + ".js" + strEJS);
  92. }
  93. this.packages[source] = true;
  94. }
  95. } else {
  96. if( !this.autodetect || _jsver < 12 || ver.length == 0 ){
  97. document.write(strJS + "\" src=\"" + path + source + strEJS);
  98. } else if( this.autodetect && (parseInt(_jsver, 10) >= parseInt(ver, 10)) ){
  99. source = source.substring(0,source.length-3) + "_js" + ver + source.substring(source.length-3);
  100. document.write(strJS + this.jsver[ver] + "\" src=\"" + path + source + strEJS);
  101. } else {
  102. document.write(strJS + "\" src=\"" + path + source + strEJS);
  103. }
  104. }
  105.  
  106. this.packages[thisPackage] = true;
  107. return true;
  108. }
  109. _a.prototype.include = _a_include;
  110.  
  111. function _a_unload(){
  112. var isFramed = false;
  113. // loop through all the forms and reset the status of the form to idle
  114. for( obj in qFormAPI.objects ){
  115. qFormAPI.objects[obj]._status = "idle";
  116. if( !!qFormAPI.objects[obj]._frame ) isFramed = true;
  117. }
  118. // some psuedo garbage collection to destroy some of the pointers if in a framed environment
  119. if( isFramed ){
  120. // kill the objects if using frames
  121. this.objects = new Object();
  122. // kill the containers if using frames
  123. this.containers = new Object();
  124. }
  125. return true;
  126. }
  127. _a.prototype.unload = _a_unload;
  128.  
  129. // define _a validate(); prototype
  130. function _a_validate(qForm){
  131. // if just validate a single form, then validate now and exit
  132. if( !this.validateAll ) return qFormAPI.objects[qForm].validate();
  133.  
  134. var aryErrors = new Array();
  135.  
  136. // loop through all the forms
  137. for( obj in qFormAPI.objects ){
  138. // check the form for errors
  139. qFormAPI.objects[obj].checkForErrors();
  140. // add the errors from this form t adde queue
  141. for( var i=0; i < qFormAPI.objects[obj]._queue.errors.length; i++ ){
  142. aryErrors[aryErrors.length] = qFormAPI.objects[obj]._queue.errors[i];
  143. }
  144. }
  145.  
  146. // if there are no errors then return true
  147. if( aryErrors.length == 0 ) return true;
  148.  
  149. var strError = "The following error(s) occurred:\n";
  150. for( var i=0; i < aryErrors.length; i++ ) strError += " - " + aryErrors[i] + "\n";
  151.  
  152. var result = false;
  153. // check to see if the user is allowed to submit the form even if an error occurred
  154. if( this._allowSubmitOnError && this._showAlerts ) result = confirm(strError + "\nAre you sure you want to continue?");
  155. // if the form can be submitted with errors and errors should not be alerted set a hidden field equal to the errors
  156. else if( this._allowSubmitOnError && !this._showAlerts ) result = true;
  157. // otherwise, just display the error
  158. else alert(strError);
  159.  
  160. return result;
  161. }
  162. _a.prototype.validate = _a_validate;
  163.  
  164. function _a_reset(hardReset){
  165. // loop through all the forms and reset the properties
  166. for( obj in qFormAPI.objects ) qFormAPI.objects[obj].reset(hardReset);
  167. return true;
  168. }
  169. _a.prototype.reset = _a_reset;
  170.  
  171. // define _a getFields(); prototype
  172. function _a_getFields(){
  173. stcAllData = new Object();
  174.  
  175. // loop through all the forms
  176. for( obj in qFormAPI.objects ){
  177. // check the form for errors
  178. var tmpStruct = qFormAPI.objects[obj].getFields();
  179. // add the value from this form to the structure
  180. for( field in tmpStruct ){
  181. if( !stcAllData[field] ){
  182. stcAllData[field] = tmpStruct[field];
  183. } else {
  184. stcAllData[field] += "," + tmpStruct[field];
  185. }
  186. }
  187. }
  188.  
  189. // return all the form data
  190. return stcAllData;
  191. }
  192. _a.prototype.getFields = _a_getFields;
  193.  
  194. // define _a setFields(); prototype
  195. function _a_setFields(struct, rd, ra){
  196. // loop through each form and populate the fields
  197. for( obj in qFormAPI.objects ) qFormAPI.objects[obj].setFields(struct, rd, ra);
  198. }
  199. _a.prototype.setFields = _a_setFields;
  200.  
  201. // define _a dump(); prototype
  202. function _a_dump(){
  203. var str = "";
  204. formData = this.getFields();
  205. for( field in formData ) str += field + " = " + formData[field] + "\n";
  206. alert(str);
  207. }
  208. _a.prototype.dump = _a_dump;
  209.  
  210.  
  211. /******************************************************************************
  212. qForm Object
  213. ******************************************************************************/
  214. // define qForm object
  215. function qForm(name, parent, frame){
  216. if( name == null ) return true;
  217. if( !name ) return alert("No form specified.");
  218. // increase the instance counter
  219. qFormAPI.instances++;
  220. // make sure the unload event is called
  221. if( qFormAPI.instances == 1 ) window.onunload = new Function(_functionToString(window.onunload, ";qFormAPI.unload();"));
  222. this._name = name;
  223. this._parent = (!!parent) ? parent : null;
  224. this._frame = (!!frame) ? frame : null;
  225. this._status = null;
  226. this._queue = new Object();
  227. this._queue.errorFields = ",";
  228. this._queue.errors = new Array();
  229. this._queue.validation = new Array();
  230. this._showAlerts = true;
  231. this._allowSubmitOnError = qFormAPI.allowSubmitOnError;
  232. this._locked = false;
  233. this._skipValidation = false;
  234. qFormAPI.objects[this._name] = this;
  235. // this is a string pointer to the qFormAPI object copy of this object
  236. this._pointer = "qFormAPI.objects['" + this._name + "']";
  237. this.init();
  238. return true;
  239. }
  240. // initialize dummy qForm object so that NS will initialize the prototype object
  241. new qForm(null, null, null);
  242.  
  243. // define qForm init(); prototype
  244. function _q_init(){
  245. if( !this._name ) return false;
  246.  
  247. // if this is NS4 and the form is in a layer
  248. if( this._parent && document.layers ) this._form = this._parent + ".document." + this._name;
  249. // otherwise point to the form
  250. else this._form = "document." + this._name;
  251.  
  252. // if the form is in a frame, then add path to the frame
  253. if( this._frame ) this._form = this._frame + "." + this._form;
  254.  
  255. // create a pointer to the form object
  256. this.obj = eval(this._form);
  257.  
  258. // if the object doesn't exist, thrown an error
  259. if( !this.obj ) return alert("The form \"" + this._name + "\" does not exist. This error \nwill occur if the Form object was initialized before the form \nhas been created or if it simply doesn't exist. Please make \nsure to initialize the Form object after page loads to avoid \npotential problems.");
  260.  
  261. // set the onSubmit method equal to whatever the current onSubmit is
  262. // this function is then run whenever the submitCheck determines it's ok to submit the form
  263. this.onSubmit = new Function(_functionToString(this.obj.onsubmit, ""));
  264. // replace the form's onSubmit event and just run the submitCheck() method
  265. var strSubmitCheck = this._pointer + ".submitCheck();";
  266. if( this._frame ) strSubmitCheck = "top." + strSubmitCheck;
  267. this.obj.onsubmit = new Function("return " + strSubmitCheck);
  268.  
  269. // loop through form elements
  270. this._fields = new Array();
  271. this._pointers = new Object();
  272. for( var j=0; j < this.obj.elements.length; j++ ) this.addField(this.obj.elements[j].name);
  273. this._status = "initialized";
  274.  
  275. // reset the form
  276. if( qFormAPI.resetOnInit ) this.reset();
  277.  
  278. return true;
  279. }
  280. qForm.prototype.init = _q_init;
  281.  
  282. // define qForm addField prototype
  283. function _q_addField(field){
  284. if( typeof field == "undefined" || field.length == 0 ) return false;
  285. o = this.obj[field];
  286. if( typeof o == "undefined" ) return false;
  287. // if the field is an array
  288. if( typeof o.type == "undefined" ) o = o[0];
  289. if( (!!o.type) && (typeof this[field] == "undefined") && (field.length > 0) ){
  290. this[field] = new Field(o, field, this._name);
  291. this._fields[this._fields.length] = field;
  292. this._pointers[field.toLowerCase()] = this[field];
  293. }
  294. return true;
  295. }
  296. qForm.prototype.addField = _q_addField;
  297.  
  298. // define qForm removeField prototype
  299. function _q_removeField(field){
  300. // this function requires a JS1.2 browser
  301.  
  302. // currently, events attached to a form field are not
  303. // deleted. this means you'll need to manually remove
  304. // the field from the DOM, or errors will occur
  305. if( typeof this[field] == "undefined" ) return false;
  306.  
  307. var f = this._fields;
  308. // find the field in the fields array and remove it
  309. for( var i=0; i < f.length; i++ ){
  310. if( f[i] == field ){
  311. var fp = i;
  312. break;
  313. }
  314. }
  315.  
  316. if( _jsver >= 12 ){
  317. delete this[field];
  318. f.splice(fp,1);
  319. delete this._pointers[field.toLowerCase()];
  320.  
  321. var q = this._queue.validation;
  322. // loop through validation queue, and remove references of
  323. for( var j=0; j < q.length; j++ ){
  324. if( q[j][0] == field ){
  325. q.splice(j,1);
  326. j--;
  327. }
  328. }
  329. }
  330. return true;
  331. }
  332. qForm.prototype.removeField = _q_removeField;
  333.  
  334.  
  335. // define qForm submitCheck prototype
  336. function _q_submitCheck(){
  337. // make sure the form is submitted more then once
  338. if( this._status == "submitting" || this._status == "validating" ) return false;
  339. this._status = "submitting";
  340.  
  341. // validate the form
  342. var result = qFormAPI.validate(this._name);
  343. // if no errors occurred, run the onSubmit() method
  344. if( result ){
  345. // run the custom onSubmit method
  346. var x = this.onSubmit();
  347. // if a boolean value was passed back, then update the result value
  348. if( typeof x == "boolean" ) result = x;
  349. }
  350.  
  351. // if the form shouldn't be submitted, then reset the form's status
  352. if( !result ){
  353. // if any validation errors occur or the form is not to be submitted because the
  354. // onSubmit() event return false, then set the reset the form's status
  355. this._status = "idle";
  356. // run any processing that should be done before submitting the form
  357. } else {
  358. // make sure to select all "container" objects so the values are included when submitted
  359. _setContainerValues(this);
  360. }
  361. return result;
  362. }
  363. qForm.prototype.submitCheck = _q_submitCheck;
  364.  
  365. // define qForm onSubmit(); prototype
  366. qForm.prototype.onSubmit = new Function("");
  367.  
  368.  
  369. // define qForm addMethod(); prototype
  370. function _q_addMethod(name, fn, type){
  371. if( arguments.length < 2 ) return alert("To create a new method, you must specify \nboth a name and function to run: \n obj.addMethod(\"checkTime\", _isTime);");
  372. var type = _param(arguments[2], "from").toLowerCase();
  373.  
  374. // set the object to attach the prototype method to
  375. if( type == "field" ) type = "Field";
  376. else type = "qForm";
  377.  
  378. // if adding a predefined function, then add it now
  379. if( typeof fn == "function" ){
  380. strFN = fn.toString();
  381. strFN = strFN.substring(strFN.indexOf(" "), strFN.indexOf("("));
  382. eval(type + ".prototype." + name + " = " + strFN);
  383.  
  384. // if creating a new function, then add it now
  385. } else {
  386. var fnTemp = new Function(fn);
  387. eval(type + ".prototype." + name + " = fnTemp;");
  388. }
  389. return true;
  390. }
  391. qForm.prototype.addMethod = _q_addMethod;
  392.  
  393. // define qForm addEvent(); prototype
  394. function _q_addEvent(event, cmd, append){
  395. if( arguments.length < 2 ) return alert("Invalid arguments. Please use the format \naddEvent(event, command, [append]).");
  396. var append = _param(arguments[2], true, "boolean");
  397. _addEvent(this._pointer + ".obj", arguments[0], arguments[1], append);
  398. return true;
  399. }
  400. qForm.prototype.addEvent = _q_addEvent;
  401.  
  402. // define qForm required(); prototype
  403. function _q_required(fields, value){
  404. var value = _param(arguments[1], true, "boolean");
  405. aryField = _removeSpaces(fields).split(",");
  406.  
  407. for( var i=0; i < aryField.length; i++ ){
  408. if( !this[aryField[i]] ) return alert("The form field \"" + aryField[i] + "\" does not exist.");
  409. this[aryField[i]].required = value;
  410. }
  411. return true;
  412. }
  413. qForm.prototype.required = _q_required;
  414.  
  415. // define qForm optional(); prototype
  416. function _q_optional(fields){
  417. // turn the fields off
  418. this.required(fields, false);
  419. return true;
  420. }
  421. qForm.prototype.optional = _q_optional;
  422.  
  423.  
  424. // define qForm forceValidation(); prototype
  425. function _q_forceValidation(fields, value){
  426. var value = _param(arguments[1], true, "boolean");
  427. aryField = _removeSpaces(fields).split(",");
  428.  
  429. for( var i=0; i < aryField.length; i++ ){
  430. if( !this[aryField[i]] ) return alert("The form field \"" + aryField[i] + "\" does not exist.");
  431. this[aryField[i]].validate = value;
  432. }
  433. return true;
  434. }
  435. qForm.prototype.forceValidation = _q_forceValidation;
  436.  
  437.  
  438. // define qForm submit(); prototype
  439. function _q_submit(){
  440. var x = false;
  441. // do not submit the form more then once
  442. if( this._status == "submitting" ) return false;
  443. if( this.obj.onsubmit() ) x = this.obj.submit();
  444. return (typeof x == "undefined") ? true : x;
  445. }
  446. qForm.prototype.submit = _q_submit;
  447.  
  448. // define qForm disabled(); prototype
  449. function _q_disabled(status){
  450. var objExists = (typeof this.obj.disabled == "boolean") ? true : false;
  451. if( arguments.length == 0 ) var status = (this.obj.disabled) ? false : true;
  452. // if the "disabled" var doesn't exist, then use the build in "locked" feature
  453. if( !objExists ) this._locked = status;
  454. // switch the status of the disabled property
  455. else this.obj.disabled = status;
  456. return true;
  457. }
  458. qForm.prototype.disabled = _q_disabled;
  459.  
  460. // define qForm reset(); prototype
  461. function _q_reset(hardReset){
  462. if( this._status == null ) return false;
  463. // loop through form elements
  464. for( var j=0; j < this._fields.length; j++ ){
  465. // reset the value for this field
  466. this[this._fields[j]].setValue(((!!hardReset) ? null : this[this._fields[j]].defaultValue), true, false);
  467. // enforce any depencies of the current field
  468. if( this[this._fields[j]]._queue.dependencies.length > 0 ) this[this._fields[j]].enforceDependency();
  469. }
  470. return true;
  471. }
  472. qForm.prototype.reset = _q_reset;
  473.  
  474. // define qForm getFields(); prototype
  475. function _q_getFields(){
  476. if( this._status == null ) return false;
  477. struct = new Object();
  478. // loop through form elements
  479. for( var j=0; j < this._fields.length; j++ ) struct[this._fields[j]] = this[this._fields[j]].getValue();
  480. return struct;
  481. }
  482. qForm.prototype.getFields = _q_getFields;
  483.  
  484. // define qForm setFields(); prototype
  485. function _q_setFields(struct, rd, ra){
  486. if( this._status == null ) return false;
  487. // if you need to reset the default values of the fields
  488. var resetDefault = _param(arguments[1], false, "boolean");
  489. var resetAll = _param(arguments[2], true, "boolean");
  490. // reset the form
  491. if( resetAll ) this.reset();
  492. // loop through form elements
  493. for( key in struct ){
  494. var obj = this._pointers[key.toLowerCase()];
  495. if( obj ){
  496. obj.setValue(struct[key], true, false);
  497. if(resetDefault) obj.defaultValue = struct[key];
  498. }
  499. }
  500. return true;
  501. }
  502. qForm.prototype.setFields = _q_setFields;
  503.  
  504. // define qForm hasChanged(); prototype
  505. function _q_hasChanged(){
  506. if( this._status == null ) return false;
  507. var b = false;
  508. // loop through form elements
  509. for( var j=0; j < this._fields.length; j++ ){
  510. if( this[this._fields[j]].getValue() != this[this._fields[j]].defaultValue ){
  511. b = true;
  512. break;
  513. }
  514. }
  515. return b;
  516. }
  517. qForm.prototype.hasChanged = _q_hasChanged;
  518.  
  519. // define qForm changedFields(); prototype
  520. function _q_changedFields(){
  521. if( this._status == null ) return false;
  522. struct = new Object();
  523. // loop through form elements
  524. for( var j=0; j < this._fields.length; j++ ){
  525. if( this[this._fields[j]].getValue() != this[this._fields[j]].defaultValue ){
  526. struct[this._fields[j]] = this[this._fields[j]].getValue();
  527. }
  528. }
  529. return struct;
  530. }
  531. qForm.prototype.changedFields = _q_changedFields;
  532.  
  533. // define qForm dump(); prototype
  534. function _q_dump(){
  535. var str = "";
  536. var f = this.getFields();
  537. for( fld in f ) str += fld + " = " + f[fld] + "\n";
  538. alert(str);
  539. }
  540. qForm.prototype.dump = _q_dump;
  541.  
  542. /******************************************************************************
  543. Field Object
  544. ******************************************************************************/
  545. // define Field object
  546. function Field(form, field, formName, init){
  547. if( arguments.length > 3 ) return true;
  548. this._queue = new Object();
  549. this._queue.dependencies = new Array();
  550. this._queue.validation = new Array();
  551. this.qForm = qFormAPI.objects[formName];
  552. this.name = field;
  553. this.path = this.qForm._form + "['" + field + "']";
  554. this.pointer = this.qForm._pointer + "['" + field + "']";
  555. this.obj = eval(this.path);
  556. this.locked = false;
  557. this.description = field.toLowerCase();
  558. this.required = false;
  559. this.validate = false;
  560. this.container = false;
  561. this.type = (!this.obj.type && !!this.obj[0]) ? this.obj[0].type : this.obj.type;
  562. this.validatorAttached = false;
  563.  
  564. var value = this.getValue();
  565. this.defaultValue = value;
  566. this.lastValue = value;
  567.  
  568. // initialize the field object
  569. this.init();
  570.  
  571. return true;
  572. }
  573. new Field(null, null, null, true);
  574.  
  575. // define Field init(); prototype
  576. function _f_init(){
  577. if( qFormAPI.useErrorColorCoding && this.obj.style ) this.styleValue = (!!this.obj.style[qFormAPI.styleAttribute]) ? this.obj.style[qFormAPI.styleAttribute].toLowerCase() : "";
  578.  
  579. if( document.layers && (this.type == "radio" || this.type == "checkbox") && !!this.obj[0] ){
  580. this.addEvent("onclick", "return " + this.pointer + ".allowFocus();");
  581. } else {
  582. this.addEvent("onfocus", "return " + this.pointer + ".allowFocus();");
  583. }
  584. }
  585. Field.prototype.init = _f_init;
  586.  
  587. // define Field allowFocus(); prototype
  588. function _f_allowFocus(){
  589. // if the background color equals the error color, then reset the style to the original background
  590. if( qFormAPI.useErrorColorCoding && this.obj.style ){
  591. if( this.qForm._queue.errorFields.indexOf(","+this.name+",") > -1 ) this.obj.style[qFormAPI.styleAttribute] = this.styleValue;
  592. }
  593. // store the current value in the lastValue property
  594. this.lastValue = this.getValue();
  595. // check to see if the field is locked
  596. var result = this.checkIfLocked();
  597.  
  598. // if the field is locked, and we have a select box, we need to reset the value of the field
  599. // and call the onblur method to remove focus
  600. if( (this.type.indexOf("select") > -1) && !result ){
  601. this.resetLast();
  602. this.blur();
  603. }
  604.  
  605. // if the field isn't locked, run the onFocus event
  606. if( !result ) this.onFocus();
  607. // return the result of the checkIfLocked() method
  608. return result;
  609. }
  610. Field.prototype.allowFocus = _f_allowFocus;
  611.  
  612. // define qForm onFocus(); prototype
  613. Field.prototype.onFocus = new Function("");
  614.  
  615. // define Field addEvent(); prototype
  616. function _f_addEvent(event, cmd, append){
  617. if( arguments.length < 2 ) return alert("Invalid arguments. Please use the format \naddEvent(event, command, [append]).");
  618. var append = _param(arguments[2], true, "boolean");
  619.  
  620. // if the field is a multi-array element, then apply the event to all items in the array
  621. if( (this.type == "radio" || this.type == "checkbox") && !!this.obj[0] ){
  622. for( var i=0; i < this.obj.length; i++ ) _addEvent(this.path + "[" + i + "]", arguments[0], arguments[1], append);
  623. } else {
  624. _addEvent(this.path, arguments[0], arguments[1], append);
  625. }
  626. return true;
  627. }
  628. Field.prototype.addEvent = _f_addEvent;
  629.  
  630. // define Field disabled(); prototype
  631. function _f_disabled(s){
  632. var status = arguments[0];
  633. var oField = (this.type == "radio") ? this.obj[0] : this.obj;
  634. var objExists = (typeof oField.disabled == "boolean") ? true : false;
  635. if( arguments.length == 0 ) var status = (oField.disabled) ? false : true;
  636. // if the "disabled" var doesn't exist, then use the build in "locked" feature
  637. if( !objExists ) this.locked = status;
  638. // switch the status of the disabled property
  639. else {
  640. if( !!this.obj[0] && this.type.indexOf("select") == -1 ) for( var i=0; i < this.obj.length; i++ ) this.obj[i].disabled = status;
  641. else this.obj.disabled = status;
  642. }
  643. return true;
  644. }
  645. Field.prototype.disabled = _f_disabled;
  646.  
  647. // define Field checkIfLocked(); prototype
  648. function _f_checkIfLocked(showMsg){
  649. var bShowMsg = _param(arguments[0], this.qForm._showAlerts);
  650. // if the value isn't equal to the key, then don't relocate the user
  651. if( this.isLocked() ){
  652. this.blur();
  653. if( bShowMsg ) alert("This field is disabled.");
  654. return false;
  655. }
  656. return true;
  657. }
  658. Field.prototype.checkIfLocked = _f_checkIfLocked;
  659.  
  660. // define Field isLocked(); prototype
  661. function _f_isLocked(){
  662. var isLocked = this.locked;
  663. if( this.qForm._locked ) isLocked = true; // if the entire form is locked
  664. return isLocked;
  665. }
  666. Field.prototype.isLocked = _f_isLocked;
  667.  
  668. // define Field isDisabled(); prototype
  669. function _f_isDisabled(){
  670. // if the disabled object exists, then get its status
  671. if( typeof this.obj.disabled == "boolean" ){
  672. var isDisabled = this.obj.disabled;
  673. if( this.qForm.obj.disabled ) isDisabled = true; // if the entire form is locked
  674. return isDisabled;
  675. // otherwise, return false (saying it's not disabled)
  676. } else {
  677. return false;
  678. }
  679. }
  680. Field.prototype.isDisabled = _f_isDisabled;
  681.  
  682. // define Field focus(); prototype
  683. function _f_focus(){
  684. if( !!this.obj.focus ) this.obj.focus();
  685. }
  686. Field.prototype.focus = _f_focus;
  687.  
  688. // define Field blur(); prototype
  689. function _f_blur(){
  690. if( !!this.obj.blur ) this.obj.blur();
  691. }
  692. Field.prototype.blur = _f_blur;
  693.  
  694. // define Field select(); prototype
  695. function _f_select(){
  696. if( !!this.obj.select ) this.obj.select();
  697. }
  698. Field.prototype.select = _f_select;
  699.  
  700. // define Field reset(); prototype
  701. function _f_reset(){
  702. this.setValue(this.defaultValue, true, false);
  703. }
  704. Field.prototype.reset = _f_reset;
  705.  
  706. // define Field getValue(); prototype
  707. function _f_getValue(){
  708. var type = (this.type.substring(0,6) == "select") ? "select" : this.type;
  709. var value = new Array();
  710.  
  711. if( type == "select" ){
  712. if( this.type == "select-one" && !this.container ){
  713. value[value.length] = (this.obj.selectedIndex == -1) ? "" : this.obj[this.obj.selectedIndex].value;
  714. } else {
  715. // loop through all element in the array for this field
  716. for( var i=0; i < this.obj.length; i++ ){
  717. // if the element is selected, get the selected values (unless it's a dummy container)
  718. if( (this.obj[i].selected || this.container) && (!this.dummyContainer) ){
  719. // append the selected value, if the value property doesn't exist, use the text
  720. value[value.length] = this.obj[i].value;
  721. }
  722. }
  723. }
  724. } else if( (type == "checkbox") || (type == "radio") ){
  725. // if more then one checkbox
  726. if( !!this.obj[0] && !this.obj.value ){
  727. // loop through all checkbox elements, and if a checkbox is checked, grab the value
  728. for( var i=0; i < this.obj.length; i++ ) if( this.obj[i].checked ) value[value.length] = this.obj[i].value;
  729. // otherwise, store the value of the field (if checkmarked) into the list
  730. } else if( this.obj.checked ){
  731. value[value.length] = this.obj.value;
  732. }
  733. } else {
  734. value[value.length] = this.obj.value;
  735. }
  736. return value.join(",");
  737. }
  738. Field.prototype.getValue = _f_getValue;
  739.  
  740. // define Field setValue(); prototype
  741. function _f_setValue(value, bReset, doEvents){
  742. this.lastValue = this.getValue();
  743. var reset = _param(arguments[1], true, "boolean");
  744. var doEvents = _param(arguments[2], true, "boolean");
  745. var type = (this.type.substring(0,6) == "select") ? "select" : this.type;
  746. var v;
  747.  
  748. if( type == "select" ){
  749. var bSelectOne = (this.type == "select-one") ? true : false;
  750. var orig = value;
  751. value = "," + value + ",";
  752. bLookForFirst = true; // if select-one type, then only select the first value found
  753. // if the select box is not a container
  754. if( !this.container ){
  755. // loop through all element in the array for this field
  756. for( var i=0; i < this.obj.length; i++ ){
  757. v = this.obj[i].value;
  758. bSelectItem = (value.indexOf("," + v + ",") > -1) ? true : false;
  759. if( bSelectItem && (bLookForFirst || !bSelectOne) ) this.obj[i].selected = true;
  760. else if( reset || bSelectOne) this.obj[i].selected = false;
  761. if( bSelectItem && bLookForFirst ) bLookForFirst = false;
  762. }
  763. // if a select-one box and nothing selected, then try to select the default value
  764. if( bSelectOne && bLookForFirst ){
  765. if( this.defaultValue == orig ) if( this.obj.length > 0 ) this.obj[0].selected = true;
  766. else this.setValue(this.defaultValue);
  767. }
  768. // if the select box is a container, then search through the container's original contents
  769. } else {
  770. newValues = new Object();
  771. for( var i=0; i < this.boundContainers.length; i++ ){
  772. var sCName = this.qForm._name + "_" + this.boundContainers[i];
  773. // check to see if the container exists, if it does check for the value
  774. if( qFormAPI.containers[sCName] ){
  775. // loop through all the container objects
  776. for( key in qFormAPI.containers[sCName] ){
  777. // if the key is in the container, then make sure to add the value
  778. if( value.indexOf("," + key + ",") > -1 ){
  779. newValues[key] = qFormAPI.containers[sCName][key];
  780. }
  781. }
  782. }
  783. }
  784. // populate the container values
  785. this.populate(newValues, reset)
  786. }
  787.  
  788. } else if( (type == "checkbox") || (type == "radio") ){
  789. // if more then one checkbox
  790. if( !!this.obj[0] && !this.obj.value ){
  791. // surround the value by commas for detection
  792. value = "," + value + ",";
  793. // loop through all checkbox elements, and if a checkbox is checked, grab the value
  794. for( var i=0; i < this.obj.length; i++ ){
  795. if( value.indexOf("," + this.obj[i].value + ",") > -1 ) this.obj[i].checked = true;
  796. else if( reset ) this.obj[i].checked = false;
  797. }
  798. // otherwise, store the value of the field (if checkmarked) into the list
  799. } else if( this.obj.value == value ){
  800. this.obj.checked = true;
  801. } else if( reset ){
  802. this.obj.checked = false;
  803. }
  804.  
  805. } else {
  806. this.obj.value = (!value) ? "" : value;
  807. }
  808.  
  809. // run the trigger events
  810. if( doEvents ){
  811. this.triggerEvent("onblur");
  812. // run the onchange event if the value has changed
  813. if( this.lastValue != value ) this.triggerEvent("onchange");
  814. }
  815. // run the onSetValue method
  816. this.onSetValue();
  817.  
  818. return true;
  819. }
  820. Field.prototype.setValue = _f_setValue;
  821.  
  822. // define Field onSetValue(); prototype
  823. Field.prototype.onSetValue = new Function("");
  824.  
  825. // define Field triggerEvent(); prototype
  826. function _f_triggerEvent(event){
  827. oEvent = eval("this.obj." + event);
  828. if( (this.obj.type == "checkbox") || (this.obj.type == "radio") && !!this.obj[0] ){
  829. for( var k=0; k < this.obj.length; k++ ){
  830. oEvent = eval("this.obj[k]." + event);
  831. if( typeof oEvent == "function" ) oEvent();
  832. }
  833. } else if( typeof oEvent == "function" ){
  834. oEvent();
  835. }
  836. }
  837. Field.prototype.triggerEvent = _f_triggerEvent;
  838.  
  839. /******************************************************************************
  840. Validation Object
  841. ******************************************************************************/
  842. // define qForm addValidator(); prototype
  843. function _q_addValidator(name, fn){
  844. if( arguments.length < 2 ) return alert("To create a new validation object, you must specify \nboth a name and function to run: \n obj.addValidator(\"isTime\", __isTime);");
  845. if( typeof fn == "string" ){
  846. var _func = new Function(fn);
  847. _addValidator(name, _func);
  848. } else {
  849. _addValidator(name, fn);
  850. }
  851. return true;
  852. }
  853. qForm.prototype.addValidator = _q_addValidator;
  854.  
  855. // define Field validateExp(); prototype
  856. function _f_validateExp(expression, error, cmd){
  857. var expression = _param(arguments[0], "false");
  858. var error = _param(arguments[1], "An error occurred on the field '\" + this.description + \"'.");
  859. var cmd = _param(arguments[2]);
  860.  
  861. var strFn = "if( " + expression + " ){ this.error = \"" + error + "\";}";
  862. if( cmd.length > 0 ) strFn += cmd;
  863. strValidateExp = "_validateExp" + qFormAPI.customValidators;
  864. _addValidator(strValidateExp, new Function(strFn));
  865. eval(this.pointer + ".validate" + strValidateExp + "();");
  866. qFormAPI.customValidators++;
  867. }
  868. Field.prototype.validateExp = _f_validateExp;
  869.  
  870. function _addValidator(name, fn, alwaysRun){
  871. var alwaysRun = _param(arguments[2], false, "boolean");
  872.  
  873. if( arguments.length < 2 ) return alert("To create a new validation object, you must specify \nboth a name and function to run: \n _addValidator(\"isTime\", __isTime);");
  874. // strip "is" out of name if present
  875. if( name.substring(0,2).toLowerCase() == "is" ) name = name.substring(2);
  876.  
  877. // if the validator has already been loaded, do not load it
  878. for( var a=0; a < qFormAPI.validators.length; a++ ) if( qFormAPI.validators[a] == name ) return alert("The " + name + " validator has already been loaded.");
  879.  
  880. // add the validator to the array of validators
  881. qFormAPI.validators[qFormAPI.validators.length] = name;
  882.  
  883. // if not registering a simple expression evaluator, then update the status bar
  884. if( qFormAPI.showStatusMsgs && name.substring(0,12) != "_validateExp" ){
  885. // update the status bar with the initialization request
  886. window.status = "Initializing the validate" + name + "() and is" + name + "() validation scripts...";
  887. // clear the status bar
  888. setTimeout("window.status = ''", 100);
  889. }
  890.  
  891. var strFN = fn.toString();
  892. var strName = strFN.substring(strFN.indexOf(" "), strFN.indexOf("("));
  893. var strArguments = strFN.substring( strFN.indexOf("(")+1, strFN.indexOf(")") );
  894. // remove spaces from the arguments
  895. while( strArguments.indexOf(" ") > -1 ) strArguments = strArguments.substring( 0, strArguments.indexOf(" ") ) + strArguments.substring( strArguments.indexOf(" ")+1 );
  896.  
  897. // add rountine to check to see if the validation method should be processed
  898. // if displaying errors, but the field is locked then return false immediately
  899. var strBody = "var display = (this.qForm._status == 'validating') ? false : true;\n";
  900. strBody += "if( (display && this.isLocked()) || this.qForm._status.substring(0,5) == 'error') return false;\n this.value = this.getValue();";
  901. if( !alwaysRun ) strBody += "if( !display && this.value.length == 0 && !this.required ) return false;\n";
  902. strBody += "this.error = '';\n";
  903.  
  904. // get the body of the custom function
  905. strBody += strFN.substring( strFN.indexOf("{")+1, strFN.lastIndexOf("}") );
  906.  
  907. // if alerting the user to the error
  908. strBody += "if( this.error.length > 0 && !!errorMsg) this.error = errorMsg;\n";
  909. strBody += "if( display && this.error.length > 0 ){\n";
  910. strBody += "if( this.qForm._status.indexOf('_ShowError') > -1 ){\n";
  911. strBody += "this.qForm._status = 'error';\n";
  912. // if the user has specified an error message, then display the custom message
  913. strBody += "alert(this.error);\n";
  914. strBody += "setTimeout(this.pointer + \".focus();\", 1);\n";
  915. strBody += "setTimeout(this.pointer + \".qForm._status = 'idle';\", 100);\n";
  916. strBody += "} return false;\n";
  917. strBody += "} else if ( display ){ return true; } return this.error;\n";
  918.  
  919. // start build a string to create the new function
  920. var strNewFN = "new Function(";
  921. var aryArguments = strArguments.split(",");
  922. for( var i=0; i < aryArguments.length; i++ ){
  923. if(aryArguments[i] != "") strNewFN += "\"" + aryArguments[i] + "\",";
  924. }
  925. var strRuleFN = strNewFN;
  926.  
  927. strNewFN += "\"errorMsg\",strBody);";
  928.  
  929. // create the Field prototype for validation
  930. eval("Field.prototype.is" + name + " = " + strNewFN);
  931.  
  932. // create validation rule, the validation rule must loop through the arguments provided
  933. // and create a string to stick in the validation queue. This string will be eval() later
  934. // on to check for errors
  935. var strRule = "var cmd = this.pointer + '.is" + name + "';\n";
  936. strRule += "cmd += '( ';\n";
  937. strRule += "for( i=0; i < arguments.length; i++ ){ \n";
  938. strRule += "if( typeof arguments[i] == 'string' ) cmd += '\"' + arguments[i] + '\",';\n";
  939. strRule += "else cmd += arguments[i] + ',';\n";
  940. strRule += "}\n";
  941. strRule += "cmd = cmd.substring(0, cmd.length-1);\n";
  942. strRule += "cmd += ')';\n";
  943. strRule += "this.qForm._queue.validation[this.qForm._queue.validation.length] = new Array(this.name, cmd);\n";
  944. strRule += "this._queue.validation[this._queue.validation.length] = cmd;\n";
  945. strRule += "if( !this.validatorAttached ){ this.addEvent('onblur', this.pointer + '.checkForErrors()');";
  946. strRule += "this.validatorAttached = true;}\n";
  947. strRule += "return true;\n";
  948. strRuleFN += "\"errorMsg\",strRule);";
  949. eval("Field.prototype.validate" + name + " = " + strRuleFN);
  950.  
  951. return true;
  952. }
  953.  
  954. // define Field checkForErrors(); prototype
  955. function _f_checkForErrors(){
  956. if( !this.validate || this.qForms._skipValidation ) return true;
  957. // change the status of the form
  958. this.qForm._status += "_ShowError";
  959. // loop through the validation queue and validation each item, if the item has already been validated, don't validate again
  960. for( var i=0; i < this._queue.validation.length; i++ ) if( !eval(this._queue.validation[i]) ) break;
  961. // reset the status to idle
  962. setTimeout(this.pointer + ".qForm._status = 'idle';", 100);
  963. return true;
  964. }
  965. Field.prototype.checkForErrors = _f_checkForErrors;
  966.  
  967. // define qForm validate(); prototype
  968. function _q_validate(){
  969. // if validation library hasn't been loaded, then return true
  970. if( !qFormAPI.packages.validation || this._skipValidation ) return true;
  971.  
  972. // check the form for errors
  973. this.checkForErrors();
  974.  
  975. // if there are no errors then return true
  976. if( this._queue.errors.length == 0 ) return true;
  977.  
  978. // run the custom onError event, if it returns false, cancel request
  979. var result = this.onError();
  980. if( result == false ) return true;
  981.  
  982. var strError = "The following error(s) occurred:\n";
  983. for( var i=0; i < this._queue.errors.length; i++ ) strError += " - " + this._queue.errors[i] + "\n";
  984.  
  985. var result = false;
  986. // check to see if the user is allowed to submit the form even if an error occurred
  987. if( this._allowSubmitOnError && this._showAlerts ) result = confirm(strError + "\nAre you sure you want to continue?");
  988. // if the form can be submitted with errors and errors should not be alerted set a hidden field equal to the errors
  989. else if( this._allowSubmitOnError && !this._showAlerts ) result = true;
  990. // otherwise, just display the error
  991. else alert(strError);
  992.  
  993. return result;
  994. }
  995. qForm.prototype.validate = _q_validate;
  996.  
  997. // define qForm checkForErrors(); prototype
  998. function _q_checkForErrors(){
  999. var status = this._status; // copy the current form's status
  1000. this._status = "validating"; // set form's status to validating
  1001. this._queue.errors = new Array(); // clear the current error queue
  1002. aryQueue = new Array(); // create a local queue for the required fields
  1003. this._queue.errorFields = ",";
  1004.  
  1005.  
  1006. // loop through form elements
  1007. for( var j=0; j < this._fields.length; j++ ){
  1008. // if the current field is required, then check to make sure it's value isn't blank
  1009. if( this[this._fields[j]].required ) aryQueue[aryQueue.length] = new Array(this._fields[j], this._pointer + "['" + this._fields[j] + "'].isNotEmpty(\"The " + this[this._fields[j]].description + " field is required.\");");
  1010. // reset the CSS settings on the field
  1011. if( qFormAPI.useErrorColorCoding && this[this._fields[j]].obj.style ) this[this._fields[j]].obj.style[qFormAPI.styleAttribute] = this[this._fields[j]].styleValue;
  1012. }
  1013.  
  1014. // loop through the required fields queue, if the field throws an error, don't validate later
  1015. for( var i=0; i < aryQueue.length; i++ ) this[aryQueue[i][0]].throwError(eval(aryQueue[i][1]));
  1016.  
  1017. // loop through the validation queue and validation each item, if the item has already been validated, don't validate again
  1018. for( var i=0; i < this._queue.validation.length; i++ ) this[this._queue.validation[i][0]].throwError(eval(this._queue.validation[i][1]));
  1019.  
  1020. // run the custom validation routine
  1021. this.onValidate();
  1022.  
  1023. // set form's status back to it's last status
  1024. this._status = status;
  1025.  
  1026. return true;
  1027. }
  1028. qForm.prototype.checkForErrors = _q_checkForErrors;
  1029.  
  1030. // define qForm onValidate(); prototype
  1031. qForm.prototype.onValidate = new Function("");
  1032.  
  1033. // define qForm onError(); prototype
  1034. qForm.prototype.onError = new Function("");
  1035.  
  1036. // define Field throwError() prototype
  1037. function _f_throwError(error){
  1038. var q = this.qForm;
  1039. // if the error msg is a valid string and this field hasn't errored already, then queue msg
  1040. if( (typeof error == "string") && (error.length > 0) && (q._queue.errorFields.indexOf("," + this.name + ",") == -1) ){
  1041. q._queue.errors[q._queue.errors.length] = error;
  1042. q._queue.errorFields += this.name + ",";
  1043. // change the background color of failed validation fields to red
  1044. if( qFormAPI.useErrorColorCoding && this.obj.style ) this.obj.style[qFormAPI.styleAttribute] = qFormAPI.errorColor;
  1045. return true;
  1046. }
  1047. return false;
  1048. }
  1049. Field.prototype.throwError = _f_throwError;
  1050.  
  1051. /******************************************************************************
  1052. Required Functions
  1053. ******************************************************************************/
  1054. // define the addEvent() function
  1055. function _addEvent(obj, event, cmd, append){
  1056. if( arguments.length < 3 ) return alert("Invalid arguments. Please use the format \n_addEvent(object, event, command, [append]).");
  1057. var append = _param(arguments[3], true, "boolean");
  1058. var event = arguments[0] + "." + arguments[1].toLowerCase();
  1059. var objEvent = eval(event);
  1060. var strEvent = (objEvent) ? objEvent.toString() : "";
  1061. // strip out the body of the function
  1062. strEvent = strEvent.substring(strEvent.indexOf("{")+1, strEvent.lastIndexOf("}"));
  1063. strEvent = (append) ? (strEvent + cmd) : (cmd + strEvent);
  1064. strEvent += "\n";
  1065. eval(event + " = new Function(strEvent)");
  1066. return true;
  1067. }
  1068.  
  1069. // define the _functionToString() function
  1070. function _functionToString(fn, cmd, append){
  1071. if( arguments.length < 1 ) return alert("Invalid arguments. Please use the format \n_functionToString(function, [command], [append]).");
  1072. var append = _param(arguments[2], true, "boolean");
  1073. var strFunction = (!fn) ? "" : fn.toString();
  1074. // strip out the body of the function
  1075. strFunction = strFunction.substring(strFunction.indexOf("{")+1, strFunction.lastIndexOf("}"));
  1076. if( cmd ) strFunction = (append) ? (strFunction + cmd + "\n") : (cmd + strFunction + "\n");
  1077. return strFunction;
  1078. }
  1079.  
  1080. // define the _param(value, default, type) function
  1081. function _param(v, d, t){
  1082. // if no default value is present, use an empty string
  1083. if( typeof d == "undefined" ) d = "";
  1084. // if no type value is present, use "string"
  1085. if( typeof t == "undefined" ) t = "string";
  1086. // if datatype should be a number and it's a string, convert it to a number
  1087. if( t == "number" && typeof v == "string" ) var v = parseFloat(arguments[0]);
  1088. // get the value to return, if the v param is not equal to the type, use default value
  1089. var value = (typeof v != "undefined" && typeof v == t.toLowerCase()) ? v : d;
  1090. return value;
  1091. }
  1092.  
  1093. // define the _removeSpaces(value) function
  1094. function _removeSpaces(v){
  1095. // remove all spaces
  1096. while( v.indexOf(" ") > -1 ) v = v.substring( 0, v.indexOf(" ") ) + v.substring( v.indexOf(" ")+1 );
  1097. return v;
  1098. }
  1099.  
  1100. // defined the _setContainerValues(obj) function
  1101. function _setContainerValues(obj){
  1102. // loop through form elements
  1103. for( var i=0; i < obj._fields.length; i++ ){
  1104. if( obj[obj._fields[i]].container && obj[obj._fields[i]].type.substring(0,6) == "select" ){
  1105. for( var x=0; x < obj[obj._fields[i]].obj.length; x++ ){
  1106. obj[obj._fields[i]].obj[x].selected = (!obj[obj._fields[i]].dummyContainer);
  1107. }
  1108. }
  1109. }
  1110. }
  1111.  
/******************************************************************************
qForm JavaScript API

Author: Dan G. Switzer, II
Date: December 10, 2000
Build: 139

Description:
This library provides a API to forms on your page. This simplifies retrieval
of field values by providing methods to retrieve the values from fields,
without having to do complicate coding.

To contribute money to further the development of the qForms API, see:
http://www.pengoworks.com/qForms/donations/

GNU License
---------------------------------------------------------------------------
This library provides common methods for interacting with HTML forms
Copyright (C) 2001 Dan G. Switzer, II

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for mser details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/

+добавить реализацию
 
каталог | задачи | паттерны | исходники | стат | форумы | карта сайта | контакты | ссылки 
© 2000-2018 CodeLAB Group
  Все права защищены
Страница сгенерирована за 0.00261 секунд
Количество запросов к БД: 7, gzip: 29.4kb/254.0kb(89%)