remove todo, after upgrade PHPExcel
[phpmyadmin/arisferyanto.git] / setup / scripts.js
blob16b05681f94758049bab2a3569c7b54e68cc6385
1 /**\r
2  * functions used in setup script\r
3  * \r
4  * @version $Id$\r
5  */\r
6 \r
7 // show this window in top frame\r
8 if (top != self) {\r
9     window.top.location.href = location;\r
10 }\r
12 // default values for fields\r
13 var defaultValues = {};\r
15 // language strings\r
16 var PMA_messages = {};\r
18 /**\r
19  * Returns field type\r
20  *\r
21  * @param Element field\r
22  */\r
23 function getFieldType(field) {\r
24     if (field.tagName == 'INPUT') {\r
25         return field.getProperty('type');\r
26     } else if (field.tagName == 'SELECT') {\r
27         return 'select';\r
28     } else if (field.tagName == 'TEXTAREA') {\r
29         return 'text';\r
30     }\r
31     return '';\r
32 }\r
34 /**\r
35  * Sets field value\r
36  *\r
37  * value must be of type:\r
38  * o undefined (omitted) - restore default value (form default, not PMA default)\r
39  * o String - if type is 'text'\r
40  * o boolean - if type is 'checkbox'\r
41  * o Array of values - if type is 'select'\r
42  *\r
43  * @param Element field\r
44  * @param String  field_type  see getFieldType\r
45  * @param mixed   value\r
46  */\r
47 function setFieldValue(field, field_type, value) {\r
48     switch (field_type) {\r
49         case 'text':\r
50             field.value = $defined(value) ? value : field.defaultValue;\r
51             break;\r
52         case 'checkbox':\r
53             field.checked = $defined(value) ? value : field.defaultChecked;\r
54             break;\r
55         case 'select':\r
56             var i, imax = field.options.length;\r
57             if (!$defined(value)) {\r
58                 for (i = 0; i < imax; i++) {\r
59                     field.options[i].selected = field.options[i].defaultSelected;\r
60                 }\r
61             } else {\r
62                 for (i = 0; i < imax; i++) {\r
63                     field.options[i].selected = (value.indexOf(field.options[i].value) != -1);\r
64                 }\r
65             }\r
66             break;\r
67     }\r
68     markField(field);\r
69 }\r
71 /**\r
72  * Gets field value\r
73  *\r
74  * Will return one of:\r
75  * o String - if type is 'text'\r
76  * o boolean - if type is 'checkbox'\r
77  * o Array of values - if type is 'select'\r
78  *\r
79  * @param Element field\r
80  * @param String  field_type  see getFieldType\r
81  * @return mixed\r
82  */\r
83 function getFieldValue(field, field_type) {\r
84     switch (field_type) {\r
85         case 'text':\r
86             return field.value;\r
87         case 'checkbox':\r
88             return field.checked;\r
89         case 'select':\r
90             var i, imax = field.options.length, items = [];\r
91             for (i = 0; i < imax; i++) {\r
92                 if (field.options[i].selected) {\r
93                     items.push(field.options[i].value);\r
94                 }\r
95             }\r
96             return items;\r
97     }\r
98 }\r
100 /**\r
101  * Returns values for all fields in fieldsets\r
102  */\r
103 function getAllValues() {\r
104     var elements = $$('fieldset input, fieldset select, fieldset textarea');\r
105     var values = {}\r
106     var type, value;\r
107     for (var i = 0; i < elements.length; i++) {\r
108         type = getFieldType(elements[i]);\r
109         value = getFieldValue(elements[i], type);\r
110         if (typeof value != 'undefined') {\r
111             // we only have single selects, fatten array\r
112             if (type == 'select') {\r
113                 value = value[0];\r
114             }\r
115             values[elements[i].name] = value;\r
116         }\r
117     }\r
118     return values;\r
121 /**\r
122  * Checks whether field has its default value\r
123  *\r
124  * @param Element field\r
125  * @param String  type\r
126  * @return boolean\r
127  */\r
128 function checkFieldDefault(field, type) {\r
129     if (!$defined(defaultValues[field.id])) {\r
130         return true;\r
131     }\r
132     var isDefault = true\r
133     var currentValue = getFieldValue(field, type);\r
134     if (type != 'select') {\r
135         isDefault = currentValue == defaultValues[field.id];\r
136     } else {\r
137         // compare arrays, will work for our representation of select values\r
138         if (currentValue.length != defaultValues[field.id].length) {\r
139             isDefault = false;\r
140         }\r
141         else {\r
142             for (var i = 0; i < currentValue.length; i++) {\r
143                 if (currentValue[i] != defaultValues[field.id][i]) {\r
144                     isDefault = false;\r
145                     break;\r
146                 }\r
147             }\r
148         }\r
149     }\r
150     return isDefault;\r
153 /**\r
154  * Returns element's id prefix\r
155  * @param Element element\r
156  */\r
157 function getIdPrefix(element) {\r
158     return element.id.replace(/[^-]+$/, '');\r
161 // ------------------------------------------------------------------\r
162 // Messages\r
163 //\r
165 // stores hidden message ids\r
166 var hiddenMessages = [];\r
168 window.addEvent('domready', function() {\r
169     var hidden = hiddenMessages.length;\r
170     for (var i = 0; i < hidden; i++) {\r
171         $(hiddenMessages[i]).style.display = 'none';\r
172     }\r
173     if (hidden > 0) {\r
174         var link = $('show_hidden_messages');\r
175         link.addEvent('click', function(e) {\r
176             e.stop();\r
177             for (var i = 0; i < hidden; i++) {\r
178                 $(hiddenMessages[i]).style.display = '';\r
179             }\r
180             this.dispose();\r
181         });\r
182         link.set('html', link.get('html').replace('#MSG_COUNT', hidden));\r
183         link.style.display = '';\r
184     }\r
185 });\r
187 //\r
188 // END: Messages\r
189 // ------------------------------------------------------------------\r
191 // ------------------------------------------------------------------\r
192 // Form validation and field operations\r
193 //\r
195 // form validator assignments\r
196 var validate = {};\r
198 // form validator list\r
199 var validators = {\r
200     /**\r
201      * Validates positive number\r
202      *\r
203      * @param boolean isKeyUp\r
204      */\r
205     validate_positive_number: function (isKeyUp) {\r
206         var result = this.value.test('^[0-9]*$') && this.value != '0';\r
207         return result ? true : PMA_messages['error_nan_p'];\r
208     },\r
209     /**\r
210      * Validates non-negative number\r
211      *\r
212      * @param boolean isKeyUp\r
213      */\r
214     validate_non_negative_number: function (isKeyUp) {\r
215         var result = this.value.test('^[0-9]*$');\r
216         return result ? true : PMA_messages['error_nan_nneg'];\r
217     },\r
218     /**\r
219      * Validates port number\r
220      *\r
221      * @param boolean isKeyUp\r
222      */\r
223     validate_port_number: function(isKeyUp) {\r
224         var result = this.value.test('^[0-9]*$') && this.value != '0';\r
225         if (!result || this.value > 65536) {\r
226             result = PMA_messages['error_incorrect_port'];\r
227         }\r
228         return result;\r
229     },\r
230     // field validators\r
231     _field: {\r
232         /**\r
233          * hide_db field\r
234          *\r
235          * @param boolean isKeyUp\r
236          */\r
237         hide_db: function(isKeyUp) {\r
238             if (!isKeyUp && this.value != '') {\r
239                 var data = {};\r
240                 data[this.id] = this.value;\r
241                 ajaxValidate(this, 'Servers/1/hide_db', data);\r
242             }\r
243             return true;\r
244         },\r
245                 /**\r
246          * TrustedProxies field\r
247          *\r
248          * @param boolean isKeyUp\r
249          */\r
250         TrustedProxies: function(isKeyUp) {\r
251             if (!isKeyUp && this.value != '') {\r
252                 var data = {};\r
253                 data[this.id] = this.value;\r
254                 ajaxValidate(this, 'TrustedProxies', data);\r
255             }\r
256             return true;\r
257         },\r
258     },\r
259     // fieldset validators\r
260     _fieldset: {\r
261         /**\r
262          * Validates Server fieldset\r
263          *\r
264          * @param boolean isKeyUp\r
265          */\r
266         Server: function(isKeyUp) {\r
267             if (!isKeyUp) {\r
268                 ajaxValidate(this, 'Server', getAllValues());\r
269             }\r
270             return true;\r
271         },\r
272         /**\r
273          * Validates Server_login_options fieldset\r
274          *\r
275          * @param boolean isKeyUp\r
276          */\r
277         Server_login_options: function(isKeyUp) {\r
278             return validators._fieldset.Server.bind(this)(isKeyUp);\r
279         },\r
280         /**\r
281          * Validates Server_pmadb fieldset\r
282          *\r
283          * @param boolean isKeyUp\r
284          */\r
285         Server_pmadb: function(isKeyUp) {\r
286             if (isKeyUp) {\r
287                 return true;\r
288             }\r
290             var prefix = getIdPrefix(this.getElement('input'));\r
291             var pmadb_active = $(prefix + 'pmadb').value != '';\r
292             if (pmadb_active) {\r
293                 ajaxValidate(this, 'Server_pmadb', getAllValues());\r
294             }\r
296             return true;\r
297         }\r
298     }\r
301 /**\r
302  * Calls server-side validation procedures\r
303  *\r
304  * @param Element parent  input field in <fieldset> or <fieldset>\r
305  * @param String id       validator id\r
306  * @param Object values   values hash (element_id: value)\r
307  */\r
308 function ajaxValidate(parent, id, values) {\r
309     // ensure that parent is a fieldset\r
310     if (parent.tagName != 'FIELDSET') {\r
311         parent = parent.getParent('fieldset');\r
312         if (!parent) {\r
313             return false;\r
314         }\r
315     }\r
316     // ensure that we have a Request object\r
317     if (typeof parent.request == 'undefined') {\r
318         parent.validate = {\r
319             request: new Request.JSON({\r
320                 url: 'validate.php',\r
321                 autoCancel: true,\r
322                 onSuccess: function(response) {\r
323                     if (response == null) {\r
324                         return;\r
325                     }\r
326                     var error = {};\r
327                     if ($type(response) != 'object') {\r
328                         error[parent.id] = [response];\r
329                     } else if (typeof response['error'] != 'undefined') {\r
330                         error[parent.id] = [response['error']];\r
331                     } else {\r
332                         $each(response, function(value, key) {\r
333                             error[key] = $type(value) == 'array' ? value : [value];\r
334                         });\r
335                     }\r
336                     displayErrors(error);\r
337                 }}),\r
338             token: parent.getParent('form').token.value\r
339         };\r
340     }\r
342     parent.validate.request.send({\r
343         data: {\r
344             token: parent.validate.token,\r
345             id: id,\r
346             values: JSON.encode(values)}\r
347     });\r
349     return true;\r
352 /**\r
353  * Registers validator for given field\r
354  *\r
355  * @param String  id       field id\r
356  * @param String  type     validator (key in validators object)\r
357  * @param boolean onKeyUp  whether fire on key up\r
358  * @param mixed   params   validation function parameters\r
359  */\r
360 function validateField(id, type, onKeyUp, params) {\r
361     if (typeof validators[type] == 'undefined') {\r
362         return;\r
363     }\r
364     if (typeof validate[id] == 'undefined') {\r
365         validate[id] = [];\r
366     }\r
367     validate[id].push([type, params, onKeyUp]);\r
370 /**\r
371  * Returns valdiation functions associated with form field\r
372  *\r
373  * @param  String  field_id     form field id\r
374  * @param  boolean onKeyUpOnly  see validateField\r
375  * @return Array  array of [function, paramseters to be passed to function]\r
376  */\r
377 function getFieldValidators(field_id, onKeyUpOnly) {\r
378     // look for field bound validator\r
379     var name = field_id.match(/[^-]+$/)[0];\r
380     if (typeof validators._field[name] != 'undefined') {\r
381         return [[validators._field[name], null]];\r
382     }\r
384     // look for registered validators\r
385     var functions = [];\r
386     if (typeof validate[field_id] != 'undefined') {\r
387         // validate[field_id]: array of [type, params, onKeyUp]\r
388         for (var i = 0, imax = validate[field_id].length; i < imax; i++) {\r
389             if (onKeyUpOnly && !validate[field_id][i][2]) {\r
390                 continue;\r
391             }\r
392             functions.push([validators[validate[field_id][i][0]], validate[field_id][i][1]]);\r
393         }\r
394     }\r
396     return functions;\r
399 /**\r
400  * Displays errors for given form fields\r
401  *\r
402  * WARNING: created DOM elements must be identical with the ones made by\r
403  * display_input() in FormDisplay.tpl.php!\r
404  *\r
405  * @param Object  error list (key: field id, value: error array)\r
406  */\r
407 function displayErrors(errors) {\r
408     $each(errors, function(errors, field_id) {\r
409         var field = $(field_id);\r
410         var isFieldset = field.tagName == 'FIELDSET';\r
411         var errorCnt = isFieldset\r
412             ? field.getElement('dl.errors')\r
413             : field.getNext('.inline_errors');\r
415         // remove empty errors (used to clear error list)\r
416         errors = errors.filter(function(item) {\r
417             return item != '';\r
418         });\r
420         if (errors.length) {\r
421             // if error container doesn't exist, create it\r
422             if (errorCnt === null) {\r
423                 if (isFieldset) {\r
424                     errorCnt = new Element('dl', {\r
425                         'class': 'errors'\r
426                     });\r
427                     errorCnt.inject(field.getElement('table'), 'before');\r
428                 } else {\r
429                     errorCnt = new Element('dl', {\r
430                         'class': 'inline_errors'\r
431                     });\r
432                     errorCnt.inject(field.getParent('td'), 'bottom');\r
433                 }\r
434             }\r
436             var html = '';\r
437             for (var i = 0, imax = errors.length; i < imax; i++) {\r
438                 html += '<dd>' + errors[i] + '</dd>';\r
439             }\r
440             errorCnt.set('html', html);\r
441         } else if (errorCnt !== null) {\r
442             // remove useless error container\r
443             errorCnt.dispose();\r
444         }\r
445     });\r
448 /**\r
449  * Validates fieldset and puts errors in 'errors' object\r
450  *\r
451  * @param Element field\r
452  * @param boolean isKeyUp\r
453  * @param Object  errors\r
454  */\r
455 function validate_fieldset(fieldset, isKeyUp, errors) {\r
456     if (fieldset && typeof validators._fieldset[fieldset.id] != 'undefined') {\r
457         var fieldset_errors = validators._fieldset[fieldset.id].bind(fieldset)(isKeyUp);\r
458         $each(fieldset_errors, function(field_errors, field_id) {\r
459             if (typeof errors[field_id] == 'undefined') {\r
460                 errors[field_id] = [];\r
461             }\r
462             errors[field_id][$type(field_errors) == 'array' ? 'extend' : 'push'](field_errors);\r
463         });\r
464     }\r
467 /**\r
468  * Validates form field and puts errors in 'errors' object\r
469  *\r
470  * @param Element field\r
471  * @param boolean isKeyUp\r
472  * @param Object  errors\r
473  */\r
474 function validate_field(field, isKeyUp, errors) {\r
475     errors[field.id] = [];\r
476     var functions = getFieldValidators(field.id, isKeyUp);\r
477     for (var i = 0; i < functions.length; i++) {\r
478         var result = functions[i][0].bind(field)(isKeyUp, functions[i][1]);\r
479         if (result !== true) {\r
480             errors[field.id][$type(result) == 'array' ? 'extend' : 'push'](result);\r
481         }\r
482     }\r
485 /**\r
486  * Validates form field and parent fieldset\r
487  *\r
488  * @param Element field\r
489  * @param boolean isKeyUp\r
490  */\r
491 function validate_field_and_fieldset(field, isKeyUp) {\r
492     var errors = {};\r
493     validate_field(field, isKeyUp, errors);\r
494     validate_fieldset(field.getParent('fieldset'), isKeyUp, errors);\r
495     displayErrors(errors);\r
498 /**\r
499  * Marks field depending on its value (system default or custom)\r
500  *\r
501  * @param Element field\r
502  */\r
503 function markField(field) {\r
504     var type = getFieldType(field);\r
505     var isDefault = checkFieldDefault(field, type);\r
507     // checkboxes uses parent <span> for marking\r
508     var fieldMarker = (type == 'checkbox') ? field.getParent() : field;\r
509     setRestoreDefaultBtn(field, !isDefault);\r
510     fieldMarker[isDefault ? 'removeClass' : 'addClass']('custom');\r
513 /**\r
514  * Enables or disables the "restore default value" button\r
515  *\r
516  * @param Element field\r
517  * @param bool    display\r
518  */\r
519 function setRestoreDefaultBtn(field, display) {\r
520     var td = field.getParent('td');\r
521     if (!td) return;\r
522     var el = td.getElement('.restore-default');\r
523     if (!el) return;\r
524     el.style.display = (display ? '' : 'none');\r
527 window.addEvent('domready', function() {\r
528     var elements = $$('input[id], select[id], textarea[id]');\r
529     var elements_count = elements.length;\r
531     // register validators and mark custom values\r
532     for (var i = 0; i < elements_count; i++) {\r
533         var el = elements[i];\r
534         markField(el);\r
535         el.addEvent('change', function(e) {\r
536             validate_field_and_fieldset(this, false);\r
537             markField(this);\r
538         });\r
539         // text fields can be validated after each change\r
540         if (el.tagName == 'INPUT' && el.type == 'text') {\r
541             el.addEvent('keyup', function(e) {\r
542                 validate_field_and_fieldset(this, true);\r
543                 markField(el);\r
544             });\r
545         }\r
546         // disable textarea spellcheck\r
547         if (el.tagName == 'TEXTAREA') {\r
548             el.setProperty('spellcheck', false)\r
549         }\r
550     }\r
552         // check whether we've refreshed a page and browser remembered modified\r
553         // form values\r
554         var check_page_refresh = $('check_page_refresh');\r
555         if (!check_page_refresh || check_page_refresh.value == '1') {\r
556                 // run all field validators\r
557                 var errors = {};\r
558                 for (var i = 0; i < elements_count; i++) {\r
559                         validate_field(elements[i], false, errors);\r
560                 }\r
561                 // run all fieldset validators\r
562                 $$('fieldset').each(function(el){\r
563                         validate_fieldset(el, false, errors);\r
564                 });\r
565                 \r
566                 displayErrors(errors);\r
567         } else if (check_page_refresh) {\r
568                 check_page_refresh.value = '1';\r
569         }\r
570 });\r
572 //\r
573 // END: Form validation and field operations\r
574 // ------------------------------------------------------------------\r
576 // ------------------------------------------------------------------\r
577 // Tabbed forms\r
578 //\r
580 /**\r
581  * Sets active tab\r
582  *\r
583  * @param Element tab_link\r
584  */\r
585 function setTab(tab_link) {\r
586     var tabs_menu = tab_link.getParent('.tabs');\r
588     var links = tabs_menu.getElements('a');\r
589     var contents;\r
590     for (var i = 0, imax = links.length; i < imax; i++) {\r
591         contents = $(links[i].getProperty('href').substr(1));\r
592         if (links[i] == tab_link) {\r
593             links[i].addClass('active');\r
594             contents.style.display = 'block';\r
595         } else {\r
596             links[i].removeClass('active');\r
597             contents.style.display = 'none';\r
598         }\r
599     }\r
600     location.hash = 'tab_' + tab_link.getProperty('href').substr(1);\r
603 window.addEvent('domready', function() {\r
604     var tabs = $$('.tabs');\r
605     var url_tab = location.hash.match(/^#tab_.+/)\r
606         ? $$('a[href$="' + location.hash.substr(5) + '"]') : null;\r
607     if (url_tab) {\r
608         url_tab = url_tab[0];\r
609     }\r
610     // add tabs events and activate one tab (the first one or indicated by location hash)\r
611     for (var i = 0, imax = tabs.length; i < imax; i++) {\r
612         var links = tabs[i].getElements('a');\r
613         var selected_tab = links[0];\r
614         for (var j = 0, jmax = links.length; j < jmax; j++) {\r
615             links[j].addEvent('click', function(e) {\r
616                 e.stop();\r
617                 setTab(this);\r
618             });\r
619             if (links[j] == url_tab) {\r
620                 selected_tab = links[j];\r
621             }\r
622         }\r
623         setTab(selected_tab);\r
624     }\r
625     // tab links handling, check each 200ms\r
626     // (works with history in FF, further browser support here would be an overkill)\r
627     var prev_hash = location.hash;\r
628     (function() {\r
629         if (location.hash != prev_hash) {\r
630             prev_hash = location.hash;\r
631             var url_tab = location.hash.match(/^#tab_.+/)\r
632                 ? $$('a[href$="' + location.hash.substr(5) + '"]') : null;\r
633             if (url_tab) {\r
634                 setTab(url_tab[0]);\r
635             }\r
636         }\r
637     }).periodical(200);\r
638 });\r
640 //\r
641 // END: Tabbed forms\r
642 // ------------------------------------------------------------------\r
644 // ------------------------------------------------------------------\r
645 // Form reset buttons\r
646 //\r
648 window.addEvent('domready', function() {\r
649     var buttons = $$('input[type=button]');\r
650     for (var i = 0, imax = buttons.length; i < imax; i++) {\r
651         buttons[i].addEvent('click', function(e) {\r
652             var fields = this.getParent('fieldset').getElements('input, select, textarea');\r
653             for (var i = 0, imax = fields.length; i < imax; i++) {\r
654                 setFieldValue(fields[i], getFieldType(fields[i]));\r
655             }\r
656         });\r
657     }\r
658 });\r
660 //\r
661 // END: Form reset buttons\r
662 // ------------------------------------------------------------------\r
664 // ------------------------------------------------------------------\r
665 // "Restore default" and "set value" buttons\r
666 //\r
668 /**\r
669  * Restores field's default value\r
670  *\r
671  * @param String field_id\r
672  */\r
673 function restoreField(field_id) {\r
674     var field = $(field_id);\r
675     if (!field || !$defined(defaultValues[field_id])) {\r
676         return;\r
677     }\r
678     setFieldValue(field, getFieldType(field), defaultValues[field_id]);\r
681 window.addEvent('domready', function() {\r
682     var buttons = $$('.restore-default, .set-value');\r
683     var fixIE = Browser.Engine.name == 'trident' && Browser.Engine.version == 4;\r
684     for (var i = 0, imax = buttons.length; i < imax; i++) {\r
685         buttons[i].set('opacity', 0.25);\r
686         if (!buttons[i].hasClass('restore-default')) {\r
687             // restore-default is handled by markField\r
688             buttons[i].style.display = '';\r
689         }\r
690         buttons[i].addEvents({\r
691             mouseenter: function(e) {this.set('opacity', 1);},\r
692             mouseleave: function(e) {this.set('opacity', 0.25);},\r
693             click: function(e) {\r
694                 e.stop();\r
695                 var href = this.getProperty('href').substr(1);\r
696                 var field_id;\r
697                 if (this.hasClass('restore-default')) {\r
698                     field_id = href;\r
699                     restoreField(field_id);\r
700                 } else {\r
701                     field_id = href.match(/^[^=]+/)[0];\r
702                     var value = href.match(/=(.+)$/)[1];\r
703                     setFieldValue($(field_id), 'text', value);\r
704                 }\r
705                 $(field_id).fireEvent('change');\r
706             }\r
707         });\r
708         // fix IE showing <img> alt text instead of link title\r
709         if (fixIE) {\r
710             buttons[i].getChildren('img')[0].alt = buttons[i].title;\r
711         }\r
712     }\r
713 });\r
715 //\r
716 // END: "Restore default" and "set value" buttons\r
717 // ------------------------------------------------------------------\r