Merge #15685 - Fix #15682 - Timestamp method not taking current time
[phpmyadmin.git] / js / tbl_select.js
blob1e44db695bc290b59a630afc5ba56de442e4f98b
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
2 /**
3  * @fileoverview JavaScript functions used on tbl_select.php
4  *
5  * @requires    jQuery
6  * @requires    js/functions.js
7  */
9 /**
10  * Ajax event handlers for this page
11  *
12  * Actions ajaxified here:
13  * Table search
14  */
16 /**
17  * Checks if given data-type is numeric or date.
18  *
19  * @param string data_type Column data-type
20  *
21  * @return bool|string
22  */
23 function PMA_checkIfDataTypeNumericOrDate (data_type) {
24     // To test for numeric data-types.
25     var numeric_re = new RegExp(
26         'TINYINT|SMALLINT|MEDIUMINT|INT|BIGINT|DECIMAL|FLOAT|DOUBLE|REAL',
27         'i'
28     );
30     // To test for date data-types.
31     var date_re = new RegExp(
32         'DATETIME|DATE|TIMESTAMP|TIME|YEAR',
33         'i'
34     );
36     // Return matched data-type
37     if (numeric_re.test(data_type)) {
38         return numeric_re.exec(data_type)[0];
39     }
41     if (date_re.test(data_type)) {
42         return date_re.exec(data_type)[0];
43     }
45     return false;
48 /**
49  * Unbind all event handlers before tearing down a page
50  */
51 AJAX.registerTeardown('tbl_select.js', function () {
52     $('#togglesearchformlink').off('click');
53     $(document).off('submit', '#tbl_search_form.ajax');
54     $('select.geom_func').off('change');
55     $(document).off('click', 'span.open_search_gis_editor');
56     $('body').off('change', 'select[name*="criteriaColumnOperators"]'); // Fix for bug #13778, changed 'click' to 'change'
57 });
59 AJAX.registerOnload('tbl_select.js', function () {
60     /**
61      * Prepare a div containing a link, otherwise it's incorrectly displayed
62      * after a couple of clicks
63      */
64     $('<div id="togglesearchformdiv"><a id="togglesearchformlink"></a></div>')
65         .insertAfter('#tbl_search_form')
66         // don't show it until we have results on-screen
67         .hide();
69     $('#togglesearchformlink')
70         .html(PMA_messages.strShowSearchCriteria)
71         .on('click', function () {
72             var $link = $(this);
73             $('#tbl_search_form').slideToggle();
74             if ($link.text() === PMA_messages.strHideSearchCriteria) {
75                 $link.text(PMA_messages.strShowSearchCriteria);
76             } else {
77                 $link.text(PMA_messages.strHideSearchCriteria);
78             }
79             // avoid default click action
80             return false;
81         });
83     var tableRows = $('#fieldset_table_qbe select');
84     $.each(tableRows, function (index, item) {
85         $(item).on('change', function () {
86             changeValueFieldType(this, index);
87         });
88     });
90     /**
91      * Ajax event handler for Table search
92      */
93     $(document).on('submit', '#tbl_search_form.ajax', function (event) {
94         var unaryFunctions = [
95             'IS NULL',
96             'IS NOT NULL',
97             '= \'\'',
98             '!= \'\''
99         ];
101         var geomUnaryFunctions = [
102             'IsEmpty',
103             'IsSimple',
104             'IsRing',
105             'IsClosed',
106         ];
108         // jQuery object to reuse
109         var $search_form = $(this);
110         event.preventDefault();
112         // empty previous search results while we are waiting for new results
113         $('#sqlqueryresultsouter').empty();
114         var $msgbox = PMA_ajaxShowMessage(PMA_messages.strSearching, false);
116         PMA_prepareForAjaxRequest($search_form);
118         var values = {};
119         $search_form.find(':input').each(function () {
120             var $input = $(this);
121             if ($input.attr('type') === 'checkbox' || $input.attr('type') === 'radio') {
122                 if ($input.is(':checked')) {
123                     values[this.name] = $input.val();
124                 }
125             } else {
126                 values[this.name] = $input.val();
127             }
128         });
129         var columnCount = $('select[name="columnsToDisplay[]"] option').length;
130         // Submit values only for the columns that have unary column operator or a search criteria
131         for (var a = 0; a < columnCount; a++) {
132             if ($.inArray(values['criteriaColumnOperators[' + a + ']'], unaryFunctions) >= 0) {
133                 continue;
134             }
136             if (values['geom_func[' + a + ']'] &&
137                 $.isArray(values['geom_func[' + a + ']'], geomUnaryFunctions) >= 0) {
138                 continue;
139             }
141             if (values['criteriaValues[' + a + ']'] === '' || values['criteriaValues[' + a + ']'] === null) {
142                 delete values['criteriaValues[' + a + ']'];
143                 delete values['criteriaColumnOperators[' + a + ']'];
144                 delete values['criteriaColumnNames[' + a + ']'];
145                 delete values['criteriaColumnTypes[' + a + ']'];
146                 delete values['criteriaColumnCollations[' + a + ']'];
147             }
148         }
149         // If all columns are selected, use a single parameter to indicate that
150         if (values['columnsToDisplay[]'] !== null) {
151             if (values['columnsToDisplay[]'].length === columnCount) {
152                 delete values['columnsToDisplay[]'];
153                 values.displayAllColumns = true;
154             }
155         } else {
156             values.displayAllColumns = true;
157         }
159         $.post($search_form.attr('action'), values, function (data) {
160             PMA_ajaxRemoveMessage($msgbox);
161             if (typeof data !== 'undefined' && data.success === true) {
162                 if (typeof data.sql_query !== 'undefined') { // zero rows
163                     $('#sqlqueryresultsouter').html(data.sql_query);
164                 } else { // results found
165                     $('#sqlqueryresultsouter').html(data.message);
166                     $('.sqlqueryresults').trigger('makegrid').trigger('stickycolumns');
167                 }
168                 $('#tbl_search_form')
169                     // workaround for bug #3168569 - Issue on toggling the "Hide search criteria" in chrome.
170                     .slideToggle()
171                     .hide();
172                 $('#togglesearchformlink')
173                     // always start with the Show message
174                     .text(PMA_messages.strShowSearchCriteria);
175                 $('#togglesearchformdiv')
176                     // now it's time to show the div containing the link
177                     .show();
178                 // needed for the display options slider in the results
179                 PMA_init_slider();
180                 $('html, body').animate({ scrollTop: 0 }, 'fast');
181             } else {
182                 $('#sqlqueryresultsouter').html(data.error);
183             }
184             PMA_highlightSQL($('#sqlqueryresultsouter'));
185         }); // end $.post()
186     });
188     // Following section is related to the 'function based search' for geometry data types.
189     // Initialy hide all the open_gis_editor spans
190     $('span.open_search_gis_editor').hide();
192     $('select.geom_func').bind('change', function () {
193         var $geomFuncSelector = $(this);
195         var binaryFunctions = [
196             'Contains',
197             'Crosses',
198             'Disjoint',
199             'Equals',
200             'Intersects',
201             'Overlaps',
202             'Touches',
203             'Within',
204             'MBRContains',
205             'MBRDisjoint',
206             'MBREquals',
207             'MBRIntersects',
208             'MBROverlaps',
209             'MBRTouches',
210             'MBRWithin',
211             'ST_Contains',
212             'ST_Crosses',
213             'ST_Disjoint',
214             'ST_Equals',
215             'ST_Intersects',
216             'ST_Overlaps',
217             'ST_Touches',
218             'ST_Within'
219         ];
221         var tempArray = [
222             'Envelope',
223             'EndPoint',
224             'StartPoint',
225             'ExteriorRing',
226             'Centroid',
227             'PointOnSurface'
228         ];
229         var outputGeomFunctions = binaryFunctions.concat(tempArray);
231         // If the chosen function takes two geometry objects as parameters
232         var $operator = $geomFuncSelector.parents('tr').find('td:nth-child(5)').find('select');
233         if ($.inArray($geomFuncSelector.val(), binaryFunctions) >= 0) {
234             $operator.prop('readonly', true);
235         } else {
236             $operator.prop('readonly', false);
237         }
239         // if the chosen function's output is a geometry, enable GIS editor
240         var $editorSpan = $geomFuncSelector.parents('tr').find('span.open_search_gis_editor');
241         if ($.inArray($geomFuncSelector.val(), outputGeomFunctions) >= 0) {
242             $editorSpan.show();
243         } else {
244             $editorSpan.hide();
245         }
246     });
248     $(document).on('click', 'span.open_search_gis_editor', function (event) {
249         event.preventDefault();
251         var $span = $(this);
252         // Current value
253         var value = $span.parent('td').children('input[type=\'text\']').val();
254         // Field name
255         var field = 'Parameter';
256         // Column type
257         var geom_func = $span.parents('tr').find('.geom_func').val();
258         var type;
259         if (geom_func === 'Envelope') {
260             type = 'polygon';
261         } else if (geom_func === 'ExteriorRing') {
262             type = 'linestring';
263         } else {
264             type = 'point';
265         }
266         // Names of input field and null checkbox
267         var input_name = $span.parent('td').children('input[type=\'text\']').attr('name');
268         // Token
270         openGISEditor();
271         if (!gisEditorLoaded) {
272             loadJSAndGISEditor(value, field, type, input_name);
273         } else {
274             loadGISEditor(value, field, type, input_name);
275         }
276     });
278     /**
279      * Ajax event handler for Range-Search.
280      */
281     $('body').on('change', 'select[name*="criteriaColumnOperators"]', function () { // Fix for bug #13778, changed 'click' to 'change'
282         $source_select = $(this);
283         // Get the column name.
284         var column_name = $(this)
285             .closest('tr')
286             .find('th:first')
287             .text();
289         // Get the data-type of column excluding size.
290         var data_type = $(this)
291             .closest('tr')
292             .find('td[data-type]')
293             .attr('data-type');
294         data_type = PMA_checkIfDataTypeNumericOrDate(data_type);
296         // Get the operator.
297         var operator = $(this).val();
299         if ((operator === 'BETWEEN' || operator === 'NOT BETWEEN')
300             && data_type
301         ) {
302             var $msgbox = PMA_ajaxShowMessage();
303             $.ajax({
304                 url: 'tbl_select.php',
305                 type: 'POST',
306                 data: {
307                     server: PMA_commonParams.get('server'),
308                     ajax_request: 1,
309                     db: $('input[name="db"]').val(),
310                     table: $('input[name="table"]').val(),
311                     column: column_name,
312                     range_search: 1
313                 },
314                 success: function (response) {
315                     PMA_ajaxRemoveMessage($msgbox);
316                     if (response.success) {
317                         // Get the column min value.
318                         var min = response.column_data.min
319                             ? '(' + PMA_messages.strColumnMin +
320                                 ' ' + response.column_data.min + ')'
321                             : '';
322                         // Get the column max value.
323                         var max = response.column_data.max
324                             ? '(' + PMA_messages.strColumnMax +
325                                 ' ' + response.column_data.max + ')'
326                             : '';
327                         var button_options = {};
328                         button_options[PMA_messages.strGo] = function () {
329                             var min_value = $('#min_value').val();
330                             var max_value = $('#max_value').val();
331                             var final_value = '';
332                             if (min_value.length && max_value.length) {
333                                 final_value = min_value + ', ' +
334                                     max_value;
335                             }
336                             var $target_field = $source_select.closest('tr')
337                                 .find('[name*="criteriaValues"]');
339                             // If target field is a select list.
340                             if ($target_field.is('select')) {
341                                 $target_field.val(final_value);
342                                 var $options = $target_field.find('option');
343                                 var $closest_min = null;
344                                 var $closest_max = null;
345                                 // Find closest min and max value.
346                                 $options.each(function () {
347                                     if (
348                                         $closest_min === null
349                                         || Math.abs($(this).val() - min_value) < Math.abs($closest_min.val() - min_value)
350                                     ) {
351                                         $closest_min = $(this);
352                                     }
354                                     if (
355                                         $closest_max === null
356                                         || Math.abs($(this).val() - max_value) < Math.abs($closest_max.val() - max_value)
357                                     ) {
358                                         $closest_max = $(this);
359                                     }
360                                 });
362                                 $closest_min.attr('selected', 'selected');
363                                 $closest_max.attr('selected', 'selected');
364                             } else {
365                                 $target_field.val(final_value);
366                             }
367                             $(this).dialog('close');
368                         };
369                         button_options[PMA_messages.strCancel] = function () {
370                             $(this).dialog('close');
371                         };
373                         // Display dialog box.
374                         $('<div/>').append(
375                             '<fieldset>' +
376                             '<legend>' + operator + '</legend>' +
377                             '<label for="min_value">' + PMA_messages.strMinValue +
378                             '</label>' +
379                             '<input type="text" id="min_value" />' + '<br>' +
380                             '<span class="small_font">' + min + '</span>' + '<br>' +
381                             '<label for="max_value">' + PMA_messages.strMaxValue +
382                             '</label>' +
383                             '<input type="text" id="max_value" />' + '<br>' +
384                             '<span class="small_font">' + max + '</span>' +
385                             '</fieldset>'
386                         ).dialog({
387                             minWidth: 500,
388                             maxHeight: 400,
389                             modal: true,
390                             buttons: button_options,
391                             title: PMA_messages.strRangeSearch,
392                             open: function () {
393                                 // Add datepicker wherever required.
394                                 PMA_addDatepicker($('#min_value'), data_type);
395                                 PMA_addDatepicker($('#max_value'), data_type);
396                             },
397                             close: function () {
398                                 $(this).remove();
399                             }
400                         });
401                     } else {
402                         PMA_ajaxShowMessage(response.error);
403                     }
404                 },
405                 error: function (response) {
406                     PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest);
407                 }
408             });
409         }
410     });
411     var windowwidth = $(window).width();
412     $('.jsresponsive').css('max-width', (windowwidth - 69) + 'px');