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