UPDATE 4.4.0.0
[phpmyadmin.git] / js / rte.js
blob77658b579f09d3f371f8d74b2f19e560ca2992df
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
2 /**
3  * JavaScript functionality for Routines, Triggers and Events.
4  *
5  * @package PhpMyadmin
6  */
7 /**
8  * @var RTE Contains all the JavaScript functionality
9  *          for Routines, Triggers and Events
10  */
11 var RTE = {
12     /**
13      * Construct for the object that provides the
14      * functionality for Routines, Triggers and Events
15      */
16     object: function (type) {
17         $.extend(this, RTE.COMMON);
18         switch (type) {
19         case 'routine':
20             $.extend(this, RTE.ROUTINE);
21             break;
22         case 'trigger':
23             // nothing extra yet for triggers
24             break;
25         case 'event':
26             $.extend(this, RTE.EVENT);
27             break;
28         default:
29             break;
30         }
31     },
32     /**
33      * @var string param_template Template for a row in the routine editor
34      */
35     param_template: ''
38 /**
39  * @var RTE.COMMON a JavaScript namespace containing the functionality
40  *                 for Routines, Triggers and Events
41  *
42  *                 This namespace is extended by the functionality required
43  *                 to handle a specific item (a routine, trigger or event)
44  *                 in the relevant javascript files in this folder
45  */
46 RTE.COMMON = {
47     /**
48      * @var $ajaxDialog Query object containing the reference to the
49      *                  dialog that contains the editor
50      */
51     $ajaxDialog: null,
52     /**
53      * @var syntaxHiglighter Reference to the codemirror editor
54      */
55     syntaxHiglighter: null,
56     /**
57      * @var buttonOptions Object containing options for
58      *                    the jQueryUI dialog buttons
59      */
60     buttonOptions: {},
61     /**
62      * Validate editor form fields.
63      */
64     validate: function () {
65         /**
66          * @var $elm a jQuery object containing the reference
67          *           to an element that is being validated
68          */
69         var $elm = null;
70         // Common validation. At the very least the name
71         // and the definition must be provided for an item
72         $elm = $('table.rte_table').last().find('input[name=item_name]');
73         if ($elm.val() === '') {
74             $elm.focus();
75             alert(PMA_messages.strFormEmpty);
76             return false;
77         }
78         $elm = $('table.rte_table').find('textarea[name=item_definition]');
79         if ($elm.val() === '') {
80             if (this.syntaxHiglighter !== null) {
81                 this.syntaxHiglighter.focus();
82             }
83             else {
84                 $('textarea[name=item_definition]').last().focus();
85             }
86             alert(PMA_messages.strFormEmpty);
87             return false;
88         }
89         // The validation has so far passed, so now
90         // we can validate item-specific fields.
91         return this.validateCustom();
92     }, // end validate()
93     /**
94      * Validate custom editor form fields.
95      * This function can be overridden by
96      * other files in this folder
97      */
98     validateCustom: function () {
99         return true;
100     }, // end validateCustom()
101     /**
102      * Execute some code after the ajax
103      * dialog for the editor is shown.
104      * This function can be overridden by
105      * other files in this folder
106      */
107     postDialogShow: function () {
108         // Nothing by default
109     }, // end postDialogShow()
111     exportDialog: function ($this) {
112         var $msg = PMA_ajaxShowMessage();
113         // Fire the ajax request straight away
114         $.get($this.attr('href'), {'ajax_request': true}, function (data) {
115             if (data.success === true) {
116                 PMA_ajaxRemoveMessage($msg);
117                 /**
118                  * @var button_options Object containing options
119                  *                     for jQueryUI dialog buttons
120                  */
121                 var button_options = {};
122                 button_options[PMA_messages.strClose] = function () {
123                     $(this).dialog("close").remove();
124                 };
125                 /**
126                  * Display the dialog to the user
127                  */
128                 var $ajaxDialog = $('<div>' + data.message + '</div>').dialog({
129                     width: 500,
130                     buttons: button_options,
131                     title: data.title
132                 });
133                 // Attach syntax highlighted editor to export dialog
134                 /**
135                  * @var $elm jQuery object containing the reference
136                  *           to the Export textarea.
137                  */
138                 var $elm = $ajaxDialog.find('textarea');
139                 /**
140                  * @var opts Options to pass to the codemirror editor
141                  */
142                 var opts = {
143                     lineNumbers: true,
144                     matchBrackets: true,
145                     extraKeys: {"Ctrl-Space": "autocomplete"},
146                     hintOptions: {"completeSingle": false, "completeOnSingleClick": true},
147                     indentUnit: 4,
148                     mode: "text/x-mysql",
149                     lineWrapping: true
150                 };
151                 CodeMirror.fromTextArea($elm[0], opts)
152                     .on("inputRead", codemirrorAutocompleteOnInputRead);
153             } else {
154                 PMA_ajaxShowMessage(data.error, false);
155             }
156         }); // end $.get()
157     },  // end exportDialog()
158     editorDialog: function (is_new, $this) {
159         var that = this;
160         /**
161          * @var $edit_row jQuery object containing the reference to
162          *                the row of the the item being edited
163          *                from the list of items
164          */
165         var $edit_row = null;
166         if ($this.hasClass('edit_anchor')) {
167             // Remeber the row of the item being edited for later,
168             // so that if the edit is successful, we can replace the
169             // row with info about the modified item.
170             $edit_row = $this.parents('tr');
171         }
172         /**
173          * @var $msg jQuery object containing the reference to
174          *           the AJAX message shown to the user
175          */
176         var $msg = PMA_ajaxShowMessage();
177         $.get($this.attr('href'), {'ajax_request': true}, function (data) {
178             if (data.success === true) {
179                 // We have successfully fetched the editor form
180                 PMA_ajaxRemoveMessage($msg);
181                 // Now define the function that is called when
182                 // the user presses the "Go" button
183                 that.buttonOptions[PMA_messages.strGo] = function () {
184                     // Move the data from the codemirror editor back to the
185                     // textarea, where it can be used in the form submission.
186                     if (typeof CodeMirror != 'undefined') {
187                         that.syntaxHiglighter.save();
188                     }
189                     // Validate editor and submit request, if passed.
190                     if (that.validate()) {
191                         /**
192                          * @var data Form data to be sent in the AJAX request
193                          */
194                         var data = $('form.rte_form').last().serialize();
195                         $msg = PMA_ajaxShowMessage(
196                             PMA_messages.strProcessingRequest
197                         );
198                         var url = $('form.rte_form').last().attr('action');
199                         $.post(url, data, function (data) {
200                             if (data.success === true) {
201                                 // Item created successfully
202                                 PMA_ajaxRemoveMessage($msg);
203                                 PMA_slidingMessage(data.message);
204                                 that.$ajaxDialog.dialog('close');
205                                 // If we are in 'edit' mode, we must
206                                 // remove the reference to the old row.
207                                 if (mode === 'edit' && $edit_row !== null ) {
208                                     $edit_row.remove();
209                                 }
210                                 // Sometimes, like when moving a trigger from
211                                 // a table to another one, the new row should
212                                 // not be inserted into the list. In this case
213                                 // "data.insert" will be set to false.
214                                 if (data.insert) {
215                                     // Insert the new row at the correct
216                                     // location in the list of items
217                                     /**
218                                      * @var text Contains the name of an item from
219                                      *           the list that is used in comparisons
220                                      *           to find the correct location where
221                                      *           to insert a new row.
222                                      */
223                                     var text = '';
224                                     /**
225                                      * @var inserted Whether a new item has been
226                                      *               inserted in the list or not
227                                      */
228                                     var inserted = false;
229                                     $('table.data').find('tr').each(function () {
230                                         text = $(this)
231                                                 .children('td')
232                                                 .eq(0)
233                                                 .find('strong')
234                                                 .text()
235                                                 .toUpperCase();
236                                         text = $.trim(text);
237                                         if (text !== '' && text > data.name) {
238                                             $(this).before(data.new_row);
239                                             inserted = true;
240                                             return false;
241                                         }
242                                     });
243                                     if (! inserted) {
244                                         // If we didn't manage to insert the row yet,
245                                         // it must belong at the end of the list,
246                                         // so we insert it there.
247                                         $('table.data').append(data.new_row);
248                                     }
249                                     // Fade-in the new row
250                                     $('tr.ajaxInsert')
251                                         .show('slow')
252                                         .removeClass('ajaxInsert');
253                                 } else if ($('table.data').find('tr').has('td').length === 0) {
254                                     // If we are not supposed to insert the new row,
255                                     // we will now check if the table is empty and
256                                     // needs to be hidden. This will be the case if
257                                     // we were editing the only item in the list,
258                                     // which we removed and will not be inserting
259                                     // something else in its place.
260                                     $('table.data').hide("slow", function () {
261                                         $('#nothing2display').show("slow");
262                                     });
263                                 }
264                                 // Now we have inserted the row at the correct
265                                 // position, but surely at least some row classes
266                                 // are wrong now. So we will itirate throught
267                                 // all rows and assign correct classes to them
268                                 /**
269                                  * @var ct Count of processed rows
270                                  */
271                                 var ct = 0;
272                                 /**
273                                  * @var rowclass Class to be attached to the row
274                                  *               that is being processed
275                                  */
276                                 var rowclass = '';
277                                 $('table.data').find('tr').has('td').each(function () {
278                                     rowclass = (ct % 2 === 0) ? 'odd' : 'even';
279                                     $(this).removeClass().addClass(rowclass);
280                                     ct++;
281                                 });
282                                 // If this is the first item being added, remove
283                                 // the "No items" message and show the list.
284                                 if ($('table.data').find('tr').has('td').length > 0 &&
285                                     $('#nothing2display').is(':visible')
286                                     ) {
287                                     $('#nothing2display').hide("slow", function () {
288                                         $('table.data').show("slow");
289                                     });
290                                 }
291                                 PMA_reloadNavigation();
292                             } else {
293                                 PMA_ajaxShowMessage(data.error, false);
294                             }
295                         }); // end $.post()
296                     } // end "if (that.validate())"
297                 }; // end of function that handles the submission of the Editor
298                 that.buttonOptions[PMA_messages.strClose] = function () {
299                     $(this).dialog("close");
300                 };
301                 /**
302                  * Display the dialog to the user
303                  */
304                 that.$ajaxDialog = $('<div id="rteDialog">' + data.message + '</div>').dialog({
305                     width: 700,
306                     minWidth: 500,
307                     maxHeight: $(window).height(),
308                     buttons: that.buttonOptions,
309                     title: data.title,
310                     modal: true,
311                     open: function () {
312                         if ($('#rteDialog').parents('.ui-dialog').height() > $(window).height()) {
313                             $('#rteDialog').dialog("option", "height", $(window).height());
314                         }
315                         $(this).find('input[name=item_name]').focus();
316                         $(this).find('input.datefield').each(function () {
317                             PMA_addDatepicker($(this).css('width', '95%'), 'date');
318                         });
319                         $(this).find('input.datetimefield').each(function () {
320                             PMA_addDatepicker($(this).css('width', '95%'), 'datetime');
321                         });
322                         $.datepicker.initialized = false;
323                     },
324                     close: function () {
325                         $(this).remove();
326                     }
327                 });
328                 /**
329                  * @var mode Used to remeber whether the editor is in
330                  *           "Edit" or "Add" mode
331                  */
332                 var mode = 'add';
333                 if ($('input[name=editor_process_edit]').length > 0) {
334                     mode = 'edit';
335                 }
336                 // Attach syntax highlighted editor to the definition
337                 /**
338                  * @var elm jQuery object containing the reference to
339                  *                 the Definition textarea.
340                  */
341                 var $elm = $('textarea[name=item_definition]').last();
342                 /**
343                  * @var opts Options to pass to the codemirror editor
344                  */
345                 var opts = {
346                     lineNumbers: true,
347                     matchBrackets: true,
348                     extraKeys: {"Ctrl-Space": "autocomplete"},
349                     hintOptions: {"completeSingle": false, "completeOnSingleClick": true},
350                     indentUnit: 4,
351                     mode: "text/x-mysql",
352                     lineWrapping: true
353                 };
354                 if (typeof CodeMirror != 'undefined') {
355                     that.syntaxHiglighter = CodeMirror.fromTextArea($elm[0], opts);
356                     that.syntaxHiglighter.on("inputRead", codemirrorAutocompleteOnInputRead);
357                 }
358                 // Execute item-specific code
359                 that.postDialogShow(data);
360             } else {
361                 PMA_ajaxShowMessage(data.error, false);
362             }
363         }); // end $.get()
364     },
366     dropDialog: function ($this) {
367        /**
368          * @var $curr_row Object containing reference to the current row
369          */
370         var $curr_row = $this.parents('tr');
371         /**
372          * @var question String containing the question to be asked for confirmation
373          */
374         var question = $('<div/>').text(
375             $curr_row.children('td').children('.drop_sql').html()
376         );
377         // We ask for confirmation first here, before submitting the ajax request
378         $this.PMA_confirm(question, $this.attr('href'), function (url) {
379             /**
380              * @var msg jQuery object containing the reference to
381              *          the AJAX message shown to the user
382              */
383             var $msg = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
384             $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function (data) {
385                 if (data.success === true) {
386                     /**
387                      * @var $table Object containing reference
388                      *             to the main list of elements
389                      */
390                     var $table = $curr_row.parent();
391                     // Check how many rows will be left after we remove
392                     // the one that the user has requested us to remove
393                     if ($table.find('tr').length === 3) {
394                         // If there are two rows left, it means that they are
395                         // the header of the table and the rows that we are
396                         // about to remove, so after the removal there will be
397                         // nothing to show in the table, so we hide it.
398                         $table.hide("slow", function () {
399                             $(this).find('tr.even, tr.odd').remove();
400                             $('#nothing2display').show("slow");
401                         });
402                     } else {
403                         $curr_row.hide("slow", function () {
404                             $(this).remove();
405                             // Now we have removed the row from the list, but maybe
406                             // some row classes are wrong now. So we will itirate
407                             // throught all rows and assign correct classes to them.
408                             /**
409                              * @var ct Count of processed rows
410                              */
411                             var ct = 0;
412                             /**
413                              * @var rowclass Class to be attached to the row
414                              *               that is being processed
415                              */
416                             var rowclass = '';
417                             $table.find('tr').has('td').each(function () {
418                                 rowclass = (ct % 2 === 0) ? 'odd' : 'even';
419                                 $(this).removeClass().addClass(rowclass);
420                                 ct++;
421                             });
422                         });
423                     }
424                     // Get rid of the "Loading" message
425                     PMA_ajaxRemoveMessage($msg);
426                     // Show the query that we just executed
427                     PMA_slidingMessage(data.sql_query);
428                     PMA_reloadNavigation();
429                 } else {
430                     PMA_ajaxShowMessage(data.error, false);
431                 }
432             }); // end $.get()
433         }); // end $.PMA_confirm()
434     }
435 }; // end RTE namespace
438  * @var RTE.EVENT JavaScript functionality for events
439  */
440 RTE.EVENT = {
441     validateCustom: function () {
442         /**
443          * @var elm a jQuery object containing the reference
444          *          to an element that is being validated
445          */
446         var $elm = null;
447         if (this.$ajaxDialog.find('select[name=item_type]').find(':selected').val() === 'RECURRING') {
448             // The interval field must not be empty for recurring events
449             $elm = this.$ajaxDialog.find('input[name=item_interval_value]');
450             if ($elm.val() === '') {
451                 $elm.focus();
452                 alert(PMA_messages.strFormEmpty);
453                 return false;
454             }
455         } else {
456             // The execute_at field must not be empty for "once off" events
457             $elm = this.$ajaxDialog.find('input[name=item_execute_at]');
458             if ($elm.val() === '') {
459                 $elm.focus();
460                 alert(PMA_messages.strFormEmpty);
461                 return false;
462             }
463         }
464         return true;
465     }
469  * @var RTE.ROUTINE JavaScript functionality for routines
470  */
471 RTE.ROUTINE = {
472     /**
473      * Overriding the postDialogShow() function defined in common.js
474      *
475      * @param data JSON-encoded data from the ajax request
476      */
477     postDialogShow: function (data) {
478         // Cache the template for a parameter table row
479         RTE.param_template = data.param_template;
480         var that = this;
481         // Make adjustments in the dialog to make it AJAX compatible
482         $('td.routine_param_remove').show();
483         $('input[name=routine_removeparameter]').remove();
484         $('input[name=routine_addparameter]').css('width', '100%');
485         // Enable/disable the 'options' dropdowns for parameters as necessary
486         $('table.routine_params_table').last().find('th[colspan=2]').attr('colspan', '1');
487         $('table.routine_params_table').last().find('tr').has('td').each(function () {
488             that.setOptionsForParameter(
489                 $(this).find('select[name^=item_param_type]'),
490                 $(this).find('input[name^=item_param_length]'),
491                 $(this).find('select[name^=item_param_opts_text]'),
492                 $(this).find('select[name^=item_param_opts_num]')
493             );
494         });
495         // Enable/disable the 'options' dropdowns for
496         // function return value as necessary
497         this.setOptionsForParameter(
498             $('table.rte_table').last().find('select[name=item_returntype]'),
499             $('table.rte_table').last().find('input[name=item_returnlength]'),
500             $('table.rte_table').last().find('select[name=item_returnopts_text]'),
501             $('table.rte_table').last().find('select[name=item_returnopts_num]')
502         );
503     },
504     /**
505      * Overriding the validateCustom() function defined in common.js
506      */
507     validateCustom: function () {
508         /**
509          * @var isSuccess Stores the outcome of the validation
510          */
511         var isSuccess = true;
512         /**
513          * @var inputname The value of the "name" attribute for
514          *                the field that is being processed
515          */
516         var inputname = '';
517         this.$ajaxDialog.find('table.routine_params_table').last().find('tr').each(function () {
518             // Every parameter of a routine must have
519             // a non-empty direction, name and type
520             if (isSuccess) {
521                 $(this).find(':input').each(function () {
522                     inputname = $(this).attr('name');
523                     if (inputname.substr(0, 14) === 'item_param_dir' ||
524                         inputname.substr(0, 15) === 'item_param_name' ||
525                         inputname.substr(0, 15) === 'item_param_type') {
526                         if ($(this).val() === '') {
527                             $(this).focus();
528                             isSuccess = false;
529                             return false;
530                         }
531                     }
532                 });
533             } else {
534                 return false;
535             }
536         });
537         if (! isSuccess) {
538             alert(PMA_messages.strFormEmpty);
539             return false;
540         }
541         this.$ajaxDialog.find('table.routine_params_table').last().find('tr').each(function () {
542             // SET, ENUM, VARCHAR and VARBINARY fields must have length/values
543             var $inputtyp = $(this).find('select[name^=item_param_type]');
544             var $inputlen = $(this).find('input[name^=item_param_length]');
545             if ($inputtyp.length && $inputlen.length) {
546                 if (($inputtyp.val() === 'ENUM' || $inputtyp.val() === 'SET' || $inputtyp.val().substr(0, 3) === 'VAR') &&
547                     $inputlen.val() === ''
548                    ) {
549                     $inputlen.focus();
550                     isSuccess = false;
551                     return false;
552                 }
553             }
554         });
555         if (! isSuccess) {
556             alert(PMA_messages.strFormEmpty);
557             return false;
558         }
559         if (this.$ajaxDialog.find('select[name=item_type]').find(':selected').val() === 'FUNCTION') {
560             // The length/values of return variable for functions must
561             // be set, if the type is SET, ENUM, VARCHAR or VARBINARY.
562             var $returntyp = this.$ajaxDialog.find('select[name=item_returntype]');
563             var $returnlen = this.$ajaxDialog.find('input[name=item_returnlength]');
564             if (($returntyp.val() === 'ENUM' || $returntyp.val() === 'SET' || $returntyp.val().substr(0, 3) === 'VAR') &&
565                 $returnlen.val() === ''
566                 ) {
567                 $returnlen.focus();
568                 alert(PMA_messages.strFormEmpty);
569                 return false;
570             }
571         }
572         if ($('select[name=item_type]').find(':selected').val() === 'FUNCTION') {
573             // A function must contain a RETURN statement in its definition
574             if (this.$ajaxDialog.find('table.rte_table').find('textarea[name=item_definition]').val().toUpperCase().indexOf('RETURN') < 0) {
575                 this.syntaxHiglighter.focus();
576                 alert(PMA_messages.MissingReturn);
577                 return false;
578             }
579         }
580         return true;
581     },
582     /**
583      * Enable/disable the "options" dropdown and "length" input for
584      * parameters and the return variable in the routine editor
585      * as necessary.
586      *
587      * @param type a jQuery object containing the reference
588      *             to the "Type" dropdown box
589      * @param len  a jQuery object containing the reference
590      *             to the "Length" input box
591      * @param text a jQuery object containing the reference
592      *             to the dropdown box with options for
593      *             parameters of text type
594      * @param num  a jQuery object containing the reference
595      *             to the dropdown box with options for
596      *             parameters of numeric type
597      */
598     setOptionsForParameter: function ($type, $len, $text, $num) {
599         /**
600          * @var no_opts a jQuery object containing the reference
601          *              to an element to be displayed when no
602          *              options are available
603          */
604         var $no_opts = $text.parent().parent().find('.no_opts');
605         /**
606          * @var no_len a jQuery object containing the reference
607          *             to an element to be displayed when no
608          *             "length/values" field is available
609          */
610         var $no_len  = $len.parent().parent().find('.no_len');
612         // Process for parameter options
613         switch ($type.val()) {
614         case 'TINYINT':
615         case 'SMALLINT':
616         case 'MEDIUMINT':
617         case 'INT':
618         case 'BIGINT':
619         case 'DECIMAL':
620         case 'FLOAT':
621         case 'DOUBLE':
622         case 'REAL':
623             $text.parent().hide();
624             $num.parent().show();
625             $no_opts.hide();
626             break;
627         case 'TINYTEXT':
628         case 'TEXT':
629         case 'MEDIUMTEXT':
630         case 'LONGTEXT':
631         case 'CHAR':
632         case 'VARCHAR':
633         case 'SET':
634         case 'ENUM':
635             $text.parent().show();
636             $num.parent().hide();
637             $no_opts.hide();
638             break;
639         default:
640             $text.parent().hide();
641             $num.parent().hide();
642             $no_opts.show();
643             break;
644         }
645         // Process for parameter length
646         switch ($type.val()) {
647         case 'DATE':
648         case 'DATETIME':
649         case 'TIME':
650         case 'TINYBLOB':
651         case 'TINYTEXT':
652         case 'BLOB':
653         case 'TEXT':
654         case 'MEDIUMBLOB':
655         case 'MEDIUMTEXT':
656         case 'LONGBLOB':
657         case 'LONGTEXT':
658             $text.closest('tr').find('a:first').hide();
659             $len.parent().hide();
660             $no_len.show();
661             break;
662         default:
663             if ($type.val() == 'ENUM' || $type.val() == 'SET') {
664                 $text.closest('tr').find('a:first').show();
665             } else {
666                 $text.closest('tr').find('a:first').hide();
667             }
668             $len.parent().show();
669             $no_len.hide();
670             break;
671         }
672     },
673     executeDialog: function ($this) {
674         var that = this;
675         /**
676          * @var msg jQuery object containing the reference to
677          *          the AJAX message shown to the user
678          */
679         var $msg = PMA_ajaxShowMessage();
680         $.get($this.attr('href'), {'ajax_request': true}, function (data) {
681             if (data.success === true) {
682                 PMA_ajaxRemoveMessage($msg);
683                 // If 'data.dialog' is true we show a dialog with a form
684                 // to get the input parameters for routine, otherwise
685                 // we just show the results of the query
686                 if (data.dialog) {
687                     // Define the function that is called when
688                     // the user presses the "Go" button
689                     that.buttonOptions[PMA_messages.strGo] = function () {
690                         /**
691                          * @var data Form data to be sent in the AJAX request
692                          */
693                         var data = $('form.rte_form').last().serialize();
694                         $msg = PMA_ajaxShowMessage(
695                             PMA_messages.strProcessingRequest
696                         );
697                         $.post('db_routines.php', data, function (data) {
698                             if (data.success === true) {
699                                 // Routine executed successfully
700                                 PMA_ajaxRemoveMessage($msg);
701                                 PMA_slidingMessage(data.message);
702                                 $ajaxDialog.dialog('close');
703                             } else {
704                                 PMA_ajaxShowMessage(data.error, false);
705                             }
706                         });
707                     };
708                     that.buttonOptions[PMA_messages.strClose] = function () {
709                         $(this).dialog("close");
710                     };
711                     /**
712                      * Display the dialog to the user
713                      */
714                     $ajaxDialog = $('<div>' + data.message + '</div>').dialog({
715                         width: 650,
716                         buttons: that.buttonOptions,
717                         title: data.title,
718                         modal: true,
719                         close: function () {
720                             $(this).remove();
721                         }
722                     });
723                     $ajaxDialog.find('input[name^=params]').first().focus();
724                     /**
725                      * Attach the datepickers to the relevant form fields
726                      */
727                     $ajaxDialog.find('input.datefield, input.datetimefield').each(function () {
728                         PMA_addDatepicker($(this).css('width', '95%'));
729                     });
730                     /*
731                     * Define the function if the user presses enter
732                     */
733                     $('form.rte_form').on('keyup', function (event) {
734                         event.preventDefault();
735                         if (event.keyCode === 13) {
736                             /**
737                             * @var data Form data to be sent in the AJAX request
738                             */
739                             var data = $(this).serialize();
740                             $msg = PMA_ajaxShowMessage(
741                                 PMA_messages.strProcessingRequest
742                             );
743                             var url = $(this).attr('action');
744                             $.post(url, data, function (data) {
745                                 if (data.success === true) {
746                                     // Routine executed successfully
747                                     PMA_ajaxRemoveMessage($msg);
748                                     PMA_slidingMessage(data.message);
749                                     $('form.rte_form').off('keyup');
750                                     $ajaxDialog.remove();
751                                 } else {
752                                     PMA_ajaxShowMessage(data.error, false);
753                                 }
754                             });
755                         }
756                     });
757                 } else {
758                     // Routine executed successfully
759                     PMA_slidingMessage(data.message);
760                 }
761             } else {
762                 PMA_ajaxShowMessage(data.error, false);
763             }
764         }); // end $.get()
765     }
769  * Attach Ajax event handlers for the Routines, Triggers and Events editor
770  */
771 $(function () {
772     /**
773      * Attach Ajax event handlers for the Add/Edit functionality.
774      */
775     $(document).on('click', 'a.ajax.add_anchor, a.ajax.edit_anchor', function (event) {
776         event.preventDefault();
777         var type = $(this).attr('href').substr(0, $(this).attr('href').indexOf('?'));
778         if (type.indexOf('routine') != -1) {
779             type = 'routine';
780         } else if (type.indexOf('trigger') != -1) {
781             type = 'trigger';
782         } else if (type.indexOf('event') != -1) {
783             type = 'event';
784         } else {
785             type = '';
786         }
787         var dialog = new RTE.object(type);
788         dialog.editorDialog($(this).hasClass('add_anchor'), $(this));
789     }); // end $(document).on()
791     /**
792      * Attach Ajax event handlers for the Execute routine functionality
793      */
794     $(document).on('click', 'a.ajax.exec_anchor', function (event) {
795         event.preventDefault();
796         var dialog = new RTE.object('routine');
797         dialog.executeDialog($(this));
798     }); // end $(document).on()
800     /**
801      * Attach Ajax event handlers for Export of Routines, Triggers and Events
802      */
803     $(document).on('click', 'a.ajax.export_anchor', function (event) {
804         event.preventDefault();
805         var dialog = new RTE.object();
806         dialog.exportDialog($(this));
807     }); // end $(document).on()
809     /**
810      * Attach Ajax event handlers for Drop functionality
811      * of Routines, Triggers and Events.
812      */
813     $(document).on('click', 'a.ajax.drop_anchor', function (event) {
814         event.preventDefault();
815         var dialog = new RTE.object();
816         dialog.dropDialog($(this));
817     }); // end $(document).on()
819     /**
820      * Attach Ajax event handlers for the "Change event/routine type"
821      * functionality in the events editor, so that the correct
822      * rows are shown in the editor when changing the event type
823      */
824     $(document).on('change', 'select[name=item_type]', function () {
825         $(this)
826         .closest('table')
827         .find('tr.recurring_event_row, tr.onetime_event_row, tr.routine_return_row, .routine_direction_cell')
828         .toggle();
829     }); // end $(document).on()
831     /**
832      * Attach Ajax event handlers for the "Change parameter type"
833      * functionality in the routines editor, so that the correct
834      * option/length fields, if any, are shown when changing
835      * a parameter type
836      */
837     $(document).on('change', 'select[name^=item_param_type]', function () {
838         /**
839          * @var row jQuery object containing the reference to
840          *          a row in the routine parameters table
841          */
842         var $row = $(this).parents('tr').first();
843         var rte = new RTE.object('routine');
844         rte.setOptionsForParameter(
845             $row.find('select[name^=item_param_type]'),
846             $row.find('input[name^=item_param_length]'),
847             $row.find('select[name^=item_param_opts_text]'),
848             $row.find('select[name^=item_param_opts_num]')
849         );
850     }); // end $(document).on()
852     /**
853      * Attach Ajax event handlers for the "Change the type of return
854      * variable of function" functionality, so that the correct fields,
855      * if any, are shown when changing the function return type type
856      */
857     $(document).on('change', 'select[name=item_returntype]', function () {
858         var rte = new RTE.object('routine');
859         var $table = $(this).closest('table.rte_table');
860         rte.setOptionsForParameter(
861             $table.find('select[name=item_returntype]'),
862             $table.find('input[name=item_returnlength]'),
863             $table.find('select[name=item_returnopts_text]'),
864             $table.find('select[name=item_returnopts_num]')
865         );
866     }); // end $(document).on()
868     /**
869      * Attach Ajax event handlers for the "Add parameter to routine" functionality
870      */
871     $(document).on('click', 'input[name=routine_addparameter]', function (event) {
872         event.preventDefault();
873         /**
874          * @var routine_params_table jQuery object containing the reference
875          *                           to the routine parameters table
876          */
877         var $routine_params_table = $(this).closest('div.ui-dialog').find('.routine_params_table');
878         /**
879          * @var new_param_row A string containing the HTML code for the
880          *                    new row for the routine parameters table
881          */
882         var new_param_row = RTE.param_template.replace(/%s/g, $routine_params_table.find('tr').length - 1);
883         // Append the new row to the parameters table
884         $routine_params_table.append(new_param_row);
885         // Make sure that the row is correctly shown according to the type of routine
886         if ($(this).closest('div.ui-dialog').find('table.rte_table select[name=item_type]').val() === 'FUNCTION') {
887             $('tr.routine_return_row').show();
888             $('td.routine_direction_cell').hide();
889         }
890         /**
891          * @var newrow jQuery object containing the reference to the newly
892          *             inserted row in the routine parameters table
893          */
894         var $newrow = $(this).closest('div.ui-dialog').find('table.routine_params_table').find('tr').has('td').last();
895         // Enable/disable the 'options' dropdowns for parameters as necessary
896         var rte = new RTE.object('routine');
897         rte.setOptionsForParameter(
898             $newrow.find('select[name^=item_param_type]'),
899             $newrow.find('input[name^=item_param_length]'),
900             $newrow.find('select[name^=item_param_opts_text]'),
901             $newrow.find('select[name^=item_param_opts_num]')
902         );
903     }); // end $(document).on()
905     /**
906      * Attach Ajax event handlers for the
907      * "Remove parameter from routine" functionality
908      */
909     $(document).on('click', 'a.routine_param_remove_anchor', function (event) {
910         event.preventDefault();
911         $(this).parent().parent().remove();
912         // After removing a parameter, the indices of the name attributes in
913         // the input fields lose the correct order and need to be reordered.
914         /**
915          * @var index Counter used for reindexing the input
916          *            fields in the routine parameters table
917          */
918         var index = 0;
919         $(this).closest('div.ui-dialog').find('table.routine_params_table').find('tr').has('td').each(function () {
920             $(this).find(':input').each(function () {
921                 /**
922                  * @var inputname The value of the name attribute of
923                  *                the input field being reindexed
924                  */
925                 var inputname = $(this).attr('name');
926                 if (inputname.substr(0, 14) === 'item_param_dir') {
927                     $(this).attr('name', inputname.substr(0, 14) + '[' + index + ']');
928                 } else if (inputname.substr(0, 15) === 'item_param_name') {
929                     $(this).attr('name', inputname.substr(0, 15) + '[' + index + ']');
930                 } else if (inputname.substr(0, 15) === 'item_param_type') {
931                     $(this).attr('name', inputname.substr(0, 15) + '[' + index + ']');
932                 } else if (inputname.substr(0, 17) === 'item_param_length') {
933                     $(this).attr('name', inputname.substr(0, 17) + '[' + index + ']');
934                     $(this).attr('id', 'item_param_length_' + index);
935                 } else if (inputname.substr(0, 20) === 'item_param_opts_text') {
936                     $(this).attr('name', inputname.substr(0, 20) + '[' + index + ']');
937                 } else if (inputname.substr(0, 19) === 'item_param_opts_num') {
938                     $(this).attr('name', inputname.substr(0, 19) + '[' + index + ']');
939                 }
940             });
941             index++;
942         });
943     }); // end $(document).on()
944 }); // end of $()