UPDATE 4.4.0.0
[phpmyadmin.git] / js / tbl_select.js
blob05511fd65fc0310606cab63406edb8cf54ad4daf
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         // jQuery object to reuse
96         $search_form = $(this);
97         event.preventDefault();
99         // empty previous search results while we are waiting for new results
100         $("#sqlqueryresultsouter").empty();
101         var $msgbox = PMA_ajaxShowMessage(PMA_messages.strSearching, false);
103         PMA_prepareForAjaxRequest($search_form);
105         var values = {};
106         $search_form.find(':input').each(function () {
107             var $input = $(this);
108             if ($input.attr('type') == 'checkbox' || $input.attr('type') == 'radio') {
109                 if ($input.is(':checked')) {
110                     values[this.name] = $input.val();
111                 }
112             } else {
113                 values[this.name] = $input.val();
114             }
115         });
116         var columnCount = $('select[name="columnsToDisplay[]"] option').length;
117         // Submit values only for the columns that have unary column operator or a search criteria
118         for (var a = 0; a < columnCount; a++) {
119             if ($.inArray(values['criteriaColumnOperators[' + a + ']'], unaryFunctions) >= 0) {
120                 continue;
121             }
123             if (values['criteriaValues[' + a + ']'] === '' || values['criteriaValues[' + a + ']'] === null) {
124                 delete values['criteriaValues[' + a + ']'];
125                 delete values['criteriaColumnOperators[' + a + ']'];
126                 delete values['criteriaColumnNames[' + a + ']'];
127                 delete values['criteriaColumnTypes[' + a + ']'];
128                 delete values['criteriaColumnCollations[' + a + ']'];
129             }
130         }
131         // If all columns are selected, use a single parameter to indicate that
132         if (values['columnsToDisplay[]'] !== null) {
133             if (values['columnsToDisplay[]'].length == columnCount) {
134                 delete values['columnsToDisplay[]'];
135                 values.displayAllColumns = true;
136             }
137         } else {
138             values.displayAllColumns = true;
139         }
141         $.post($search_form.attr('action'), values, function (data) {
142             PMA_ajaxRemoveMessage($msgbox);
143             if (typeof data !== 'undefined' && data.success === true) {
144                 if (typeof data.sql_query !== 'undefined') { // zero rows
145                     $("#sqlqueryresultsouter").html(data.sql_query);
146                 } else { // results found
147                     $("#sqlqueryresultsouter").html(data.message);
148                     $(".sqlqueryresults").trigger('makegrid').trigger('stickycolumns');
149                 }
150                 $('#tbl_search_form')
151                 // workaround for bug #3168569 - Issue on toggling the "Hide search criteria" in chrome.
152                  .slideToggle()
153                  .hide();
154                 $('#togglesearchformlink')
155                  // always start with the Show message
156                  .text(PMA_messages.strShowSearchCriteria);
157                 $('#togglesearchformdiv')
158                  // now it's time to show the div containing the link
159                  .show();
160                  // needed for the display options slider in the results
161                 PMA_init_slider();
162             } else {
163                 $("#sqlqueryresultsouter").html(data.error);
164             }
165             PMA_highlightSQL($('#sqlqueryresultsouter'));
166         }); // end $.post()
167     });
169     // Following section is related to the 'function based search' for geometry data types.
170     // Initialy hide all the open_gis_editor spans
171     $('span.open_search_gis_editor').hide();
173     $('select.geom_func').bind('change', function () {
174         var $geomFuncSelector = $(this);
176         var binaryFunctions = [
177             'Contains',
178             'Crosses',
179             'Disjoint',
180             'Equals',
181             'Intersects',
182             'Overlaps',
183             'Touches',
184             'Within',
185             'MBRContains',
186             'MBRDisjoint',
187             'MBREquals',
188             'MBRIntersects',
189             'MBROverlaps',
190             'MBRTouches',
191             'MBRWithin',
192             'ST_Contains',
193             'ST_Crosses',
194             'ST_Disjoint',
195             'ST_Equals',
196             'ST_Intersects',
197             'ST_Overlaps',
198             'ST_Touches',
199             'ST_Within'
200         ];
202         var tempArray = [
203             'Envelope',
204             'EndPoint',
205             'StartPoint',
206             'ExteriorRing',
207             'Centroid',
208             'PointOnSurface'
209         ];
210         var outputGeomFunctions = binaryFunctions.concat(tempArray);
212         // If the chosen function takes two geometry objects as parameters
213         var $operator = $geomFuncSelector.parents('tr').find('td:nth-child(5)').find('select');
214         if ($.inArray($geomFuncSelector.val(), binaryFunctions) >= 0) {
215             $operator.prop('readonly', true);
216         } else {
217             $operator.prop('readonly', false);
218         }
220         // if the chosen function's output is a geometry, enable GIS editor
221         var $editorSpan = $geomFuncSelector.parents('tr').find('span.open_search_gis_editor');
222         if ($.inArray($geomFuncSelector.val(), outputGeomFunctions) >= 0) {
223             $editorSpan.show();
224         } else {
225             $editorSpan.hide();
226         }
228     });
230     $(document).on('click', 'span.open_search_gis_editor', function (event) {
231         event.preventDefault();
233         var $span = $(this);
234         // Current value
235         var value = $span.parent('td').children("input[type='text']").val();
236         // Field name
237         var field = 'Parameter';
238         // Column type
239         var geom_func = $span.parents('tr').find('.geom_func').val();
240         var type;
241         if (geom_func == 'Envelope') {
242             type = 'polygon';
243         } else if (geom_func == 'ExteriorRing') {
244             type = 'linestring';
245         } else {
246             type = 'point';
247         }
248         // Names of input field and null checkbox
249         var input_name = $span.parent('td').children("input[type='text']").attr('name');
250         //Token
251         var token = $("input[name='token']").val();
253         openGISEditor();
254         if (!gisEditorLoaded) {
255             loadJSAndGISEditor(value, field, type, input_name, token);
256         } else {
257             loadGISEditor(value, field, type, input_name, token);
258         }
259     });
261     /**
262      * Ajax event handler for Range-Search.
263      */
264     $('body').on('click', 'select[name*="criteriaColumnOperators"]', function () {
265         $source_select = $(this);
266         // Get the column name.
267         var column_name = $(this)
268             .closest('tr')
269             .find('th:first')
270             .text();
272         // Get the data-type of column excluding size.
273         var data_type = $(this)
274             .closest('tr')
275             .find('td[data-type]')
276             .attr('data-type');
277         data_type = PMA_checkIfDataTypeNumericOrDate(data_type);
279         // Get the operator.
280         var operator = $(this).val();
282         if ((operator == 'BETWEEN' || operator == 'NOT BETWEEN')
283             && data_type
284         ) {
285             var $msgbox = PMA_ajaxShowMessage();
286             $.ajax({
287                 url: 'tbl_select.php',
288                 type: 'POST',
289                 data: {
290                     token: $('input[name="token"]').val(),
291                     ajax_request: 1,
292                     db: $('input[name="db"]').val(),
293                     table: $('input[name="table"]').val(),
294                     column: column_name,
295                     range_search: 1
296                 },
297                 success: function (response) {
298                     PMA_ajaxRemoveMessage($msgbox);
299                     if (response.success) {
300                         // Get the column min value.
301                         var min = response.column_data.min
302                             ? '(' + PMA_messages.strColumnMin +
303                                 ' ' + response.column_data.min + ')'
304                             : '';
305                         // Get the column max value.
306                         var max = response.column_data.max
307                             ? '(' + PMA_messages.strColumnMax +
308                                 ' ' + response.column_data.max + ')'
309                             : '';
310                         var button_options = {};
311                         button_options[PMA_messages.strGo] = function () {
312                             var min_value = $('#min_value').val();
313                             var max_value = $('#max_value').val();
314                             var final_value = '';
315                             if (min_value.length && max_value.length) {
316                                 final_value = min_value + ', ' +
317                                     max_value;
318                             }
319                             var $target_field = $source_select.closest('tr')
320                                 .find('[name*="criteriaValues"]');
322                             // If target field is a select list.
323                             if ($target_field.is('select')) {
324                                 $target_field.val(final_value);
325                                 var $options = $target_field.find('option');
326                                 var $closest_min = null;
327                                 var $closest_max = null;
328                                 // Find closest min and max value.
329                                 $options.each(function () {
330                                     if (
331                                         $closest_min === null
332                                         || Math.abs($(this).val() - min_value) < Math.abs($closest_min.val() - min_value)
333                                     ) {
334                                         $closest_min = $(this);
335                                     }
337                                     if (
338                                         $closest_max === null
339                                         || Math.abs($(this).val() - max_value) < Math.abs($closest_max.val() - max_value)
340                                     ) {
341                                         $closest_max = $(this);
342                                     }
343                                 });
345                                 $closest_min.attr('selected', 'selected');
346                                 $closest_max.attr('selected', 'selected');
347                             } else {
348                                 $target_field.val(final_value);
349                             }
350                             $(this).dialog("close");
351                         };
352                         button_options[PMA_messages.strCancel] = function () {
353                             $(this).dialog("close");
354                         };
356                         // Display dialog box.
357                         $('<div/>').append(
358                             '<fieldset>' +
359                             '<legend>' + operator + '</legend>' +
360                             '<lablel for="min_value">' + PMA_messages.strMinValue +
361                             '</label>' +
362                             '<input type="text" id="min_value" />' + '<br>' +
363                             '<span class="small_font">' + min + '</span>' + '<br>' +
364                             '<lablel for="max_value">' + PMA_messages.strMaxValue +
365                             '</label>' +
366                             '<input type="text" id="max_value" />' + '<br>' +
367                             '<span class="small_font">' + max + '</span>' +
368                             '</fieldset>'
369                         ).dialog({
370                             minWidth: 500,
371                             maxHeight: 400,
372                             modal: true,
373                             buttons: button_options,
374                             title: PMA_messages.strRangeSearch,
375                             open: function () {
376                                 // Add datepicker wherever required.
377                                 PMA_addDatepicker($('#min_value'), data_type);
378                                 PMA_addDatepicker($('#max_value'), data_type);
379                             },
380                             close: function () {
381                                 $(this).remove();
382                             }
383                         });
384                     } else {
385                         PMA_ajaxShowMessage(response.error);
386                     }
387                 },
388                 error: function (response) {
389                     PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest);
390                 }
391             });
392         }
393     });