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