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