Passed
Push — master ( 2c0405...86bdc5 )
by Maurício
07:21
created

js/sql.js (1 issue)

Labels
Severity
1
/* vim: set expandtab sw=4 ts=4 sts=4: */
2
/**
3
 * @fileoverview    functions used wherever an sql query form is used
4
 *
5
 * @requires    jQuery
6
 * @requires    js/functions.js
7
 *
8
 */
9
10
var $data_a;
11
var prevScrollX = 0;
12
13
/**
14
 * decode a string URL_encoded
15
 *
16
 * @param string str
17
 * @return string the URL-decoded string
18
 */
19
function PMA_urldecode (str) {
20
    if (typeof str !== 'undefined') {
21
        return decodeURIComponent(str.replace(/\+/g, '%20'));
22
    }
23
}
24
25
/**
26
 * endecode a string URL_decoded
27
 *
28
 * @param string str
29
 * @return string the URL-encoded string
30
 */
31
function PMA_urlencode (str) {
32
    if (typeof str !== 'undefined') {
33
        return encodeURIComponent(str).replace(/\%20/g, '+');
34
    }
35
}
36
37
/**
38
 * Saves SQL query in local storage or cookie
39
 *
40
 * @param string SQL query
41
 * @return void
42
 */
43
function PMA_autosaveSQL (query) {
44
    if (isStorageSupported('localStorage')) {
45
        window.localStorage.auto_saved_sql = query;
46
    } else {
47
        Cookies.set('auto_saved_sql', query);
48
    }
49
}
50
51
/**
52
 * Saves SQL query in local storage or cookie
53
 *
54
 * @param string database name
55
 * @param string table name
56
 * @param string SQL query
57
 * @return void
58
 */
59
function PMA_showThisQuery (db, table, query) {
60
    var show_this_query_object = {
61
        'db': db,
62
        'table': table,
63
        'query': query
64
    };
65
    if (isStorageSupported('localStorage')) {
66
        window.localStorage.show_this_query = 1;
67
        window.localStorage.show_this_query_object = JSON.stringify(show_this_query_object);
68
    } else {
69
        Cookies.set('show_this_quey', 1);
70
        Cookies.set('show_this_query_object', JSON.stringify(show_this_query_object));
71
    }
72
}
73
74
/**
75
 * Set query to codemirror if show this query is
76
 * checked and query for the db and table pair exists
77
 */
78
function setShowThisQuery () {
79
    var db = $('input[name="db"]').val();
80
    var table = $('input[name="table"]').val();
81
    if (isStorageSupported('localStorage')) {
82
        if (window.localStorage.show_this_query_object !== undefined) {
83
            var stored_db = JSON.parse(window.localStorage.show_this_query_object).db;
84
            var stored_table = JSON.parse(window.localStorage.show_this_query_object).table;
85
            var stored_query = JSON.parse(window.localStorage.show_this_query_object).query;
86
        }
87
        if (window.localStorage.show_this_query !== undefined
88
            && window.localStorage.show_this_query === '1') {
89
            $('input[name="show_query"]').prop('checked', true);
90
            if (db === stored_db && table === stored_table) {
91
                if (codemirror_editor) {
92
                    codemirror_editor.setValue(stored_query);
93
                } else if (document.sqlform) {
94
                    document.sqlform.sql_query.value = stored_query;
95
                }
96
            }
97
        } else {
98
            $('input[name="show_query"]').prop('checked', false);
99
        }
100
    }
101
}
102
103
/**
104
 * Saves SQL query with sort in local storage or cookie
105
 *
106
 * @param string SQL query
107
 * @return void
108
 */
109
function PMA_autosaveSQLSort (query) {
110
    if (query) {
111
        if (isStorageSupported('localStorage')) {
112
            window.localStorage.auto_saved_sql_sort = query;
113
        } else {
114
            Cookies.set('auto_saved_sql_sort', query);
115
        }
116
    }
117
}
118
119
/**
120
 * Get the field name for the current field.  Required to construct the query
121
 * for grid editing
122
 *
123
 * @param $table_results enclosing results table
124
 * @param $this_field    jQuery object that points to the current field's tr
125
 */
126
function getFieldName ($table_results, $this_field) {
127
    var this_field_index = $this_field.index();
128
    // ltr or rtl direction does not impact how the DOM was generated
129
    // check if the action column in the left exist
130
    var left_action_exist = !$table_results.find('th:first').hasClass('draggable');
131
    // number of column span for checkbox and Actions
132
    var left_action_skip = left_action_exist ? $table_results.find('th:first').attr('colspan') - 1 : 0;
133
134
    // If this column was sorted, the text of the a element contains something
135
    // like <small>1</small> that is useful to indicate the order in case
136
    // of a sort on multiple columns; however, we dont want this as part
137
    // of the column name so we strip it ( .clone() to .end() )
138
    var field_name = $table_results
139
        .find('thead')
140
        .find('th:eq(' + (this_field_index - left_action_skip) + ') a')
141
        .clone()    // clone the element
142
        .children() // select all the children
143
        .remove()   // remove all of them
144
        .end()      // go back to the selected element
145
        .text();    // grab the text
146
    // happens when just one row (headings contain no a)
147
    if (field_name === '') {
148
        var $heading = $table_results.find('thead').find('th:eq(' + (this_field_index - left_action_skip) + ')').children('span');
149
        // may contain column comment enclosed in a span - detach it temporarily to read the column name
150
        var $tempColComment = $heading.children().detach();
151
        field_name = $heading.text();
152
        // re-attach the column comment
153
        $heading.append($tempColComment);
154
    }
155
156
    field_name = $.trim(field_name);
157
158
    return field_name;
159
}
160
161
/**
162
 * Unbind all event handlers before tearing down a page
163
 */
164
AJAX.registerTeardown('sql.js', function () {
165
    $(document).off('click', 'a.delete_row.ajax');
166
    $(document).off('submit', '.bookmarkQueryForm');
167
    $('input#bkm_label').off('keyup');
168
    $(document).off('makegrid', '.sqlqueryresults');
169
    $(document).off('stickycolumns', '.sqlqueryresults');
170
    $('#togglequerybox').off('click');
171
    $(document).off('click', '#button_submit_query');
172
    $(document).off('change', '#id_bookmark');
173
    $('input[name=\'bookmark_variable\']').off('keypress');
174
    $(document).off('submit', '#sqlqueryform.ajax');
175
    $(document).off('click', 'input[name=navig].ajax');
176
    $(document).off('submit', 'form[name=\'displayOptionsForm\'].ajax');
177
    $(document).off('mouseenter', 'th.column_heading.pointer');
178
    $(document).off('mouseleave', 'th.column_heading.pointer');
179
    $(document).off('click', 'th.column_heading.marker');
180
    $(document).off('scroll', window);
181
    $(document).off('keyup', '.filter_rows');
182
    $(document).off('click', '#printView');
183
    if (codemirror_editor) {
184
        codemirror_editor.off('change');
185
    } else {
186
        $('#sqlquery').off('input propertychange');
187
    }
188
    $('body').off('click', '.navigation .showAllRows');
189
    $('body').off('click', 'a.browse_foreign');
190
    $('body').off('click', '#simulate_dml');
191
    $('body').off('keyup', '#sqlqueryform');
192
    $('body').off('click', 'form[name="resultsForm"].ajax button[name="submit_mult"], form[name="resultsForm"].ajax input[name="submit_mult"]');
193
});
194
195
/**
196
 * @description <p>Ajax scripts for sql and browse pages</p>
197
 *
198
 * Actions ajaxified here:
199
 * <ul>
200
 * <li>Retrieve results of an SQL query</li>
201
 * <li>Paginate the results table</li>
202
 * <li>Sort the results table</li>
203
 * <li>Change table according to display options</li>
204
 * <li>Grid editing of data</li>
205
 * <li>Saving a bookmark</li>
206
 * </ul>
207
 *
208
 * @name        document.ready
209
 * @memberOf    jQuery
210
 */
211
AJAX.registerOnload('sql.js', function () {
212
    if (codemirror_editor || document.sqlform) {
213
        setShowThisQuery();
214
    }
215
    $(function () {
216
        if (codemirror_editor) {
217
            codemirror_editor.on('change', function () {
218
                PMA_autosaveSQL(codemirror_editor.getValue());
219
            });
220
        } else {
221
            $('#sqlquery').on('input propertychange', function () {
222
                PMA_autosaveSQL($('#sqlquery').val());
223
            });
224
            // Save sql query with sort
225
            if ($('#RememberSorting') !== undefined && $('#RememberSorting').is(':checked')) {
226
                $('select[name="sql_query"]').on('change', function () {
227
                    PMA_autosaveSQLSort($('select[name="sql_query"]').val());
228
                });
229
            } else {
230
                if (isStorageSupported('localStorage') && window.localStorage.auto_saved_sql_sort !== undefined) {
231
                    window.localStorage.removeItem('auto_saved_sql_sort');
232
                } else {
233
                    Cookies.set('auto_saved_sql_sort', '');
234
                }
235
            }
236
            // If sql query with sort for current table is stored, change sort by key select value
237
            var sortStoredQuery = (isStorageSupported('localStorage') && typeof window.localStorage.auto_saved_sql_sort !== 'undefined') ? window.localStorage.auto_saved_sql_sort : Cookies.get('auto_saved_sql_sort');
238
            if (typeof sortStoredQuery !== 'undefined' && sortStoredQuery !== $('select[name="sql_query"]').val() && $('select[name="sql_query"] option[value="' + sortStoredQuery + '"]').length !== 0) {
239
                $('select[name="sql_query"]').val(sortStoredQuery).trigger('change');
240
            }
241
        }
242
    });
243
244
    // Delete row from SQL results
245
    $(document).on('click', 'a.delete_row.ajax', function (e) {
246
        e.preventDefault();
247
        var question =  PMA_sprintf(PMA_messages.strDoYouReally, escapeHtml($(this).closest('td').find('div').text()));
248
        var $link = $(this);
249
        $link.PMA_confirm(question, $link.attr('href'), function (url) {
250
            $msgbox = PMA_ajaxShowMessage();
251
            var argsep = PMA_commonParams.get('arg_separator');
252
            var params = 'ajax_request=1' + argsep + 'is_js_confirmed=1';
253
            var postData = $link.getPostData();
254
            if (postData) {
255
                params += argsep + postData;
256
            }
257
            $.post(url, params, function (data) {
258
                if (data.success) {
259
                    PMA_ajaxShowMessage(data.message);
260
                    $link.closest('tr').remove();
261
                } else {
262
                    PMA_ajaxShowMessage(data.error, false);
263
                }
264
            });
265
        });
266
    });
267
268
    // Ajaxification for 'Bookmark this SQL query'
269
    $(document).on('submit', '.bookmarkQueryForm', function (e) {
270
        e.preventDefault();
271
        PMA_ajaxShowMessage();
272
        var argsep = PMA_commonParams.get('arg_separator');
273
        $.post($(this).attr('action'), 'ajax_request=1' + argsep + $(this).serialize(), function (data) {
274
            if (data.success) {
275
                PMA_ajaxShowMessage(data.message);
276
            } else {
277
                PMA_ajaxShowMessage(data.error, false);
278
            }
279
        });
280
    });
281
282
    /* Hides the bookmarkoptions checkboxes when the bookmark label is empty */
283
    $('input#bkm_label').on('keyup', function () {
284
        $('input#id_bkm_all_users, input#id_bkm_replace')
285
            .parent()
286
            .toggle($(this).val().length > 0);
287
    }).trigger('keyup');
288
289
    /**
290
     * Attach Event Handler for 'Copy to clipbpard
291
     */
292
    $(document).on('click', '#copyToClipBoard', function (event) {
293
        event.preventDefault();
294
295
        var textArea = document.createElement('textarea');
296
297
        //
298
        // *** This styling is an extra step which is likely not required. ***
299
        //
300
        // Why is it here? To ensure:
301
        // 1. the element is able to have focus and selection.
302
        // 2. if element was to flash render it has minimal visual impact.
303
        // 3. less flakyness with selection and copying which **might** occur if
304
        //    the textarea element is not visible.
305
        //
306
        // The likelihood is the element won't even render, not even a flash,
307
        // so some of these are just precautions. However in IE the element
308
        // is visible whilst the popup box asking the user for permission for
309
        // the web page to copy to the clipboard.
310
        //
311
312
        // Place in top-left corner of screen regardless of scroll position.
313
        textArea.style.position = 'fixed';
314
        textArea.style.top = 0;
315
        textArea.style.left = 0;
316
317
        // Ensure it has a small width and height. Setting to 1px / 1em
318
        // doesn't work as this gives a negative w/h on some browsers.
319
        textArea.style.width = '2em';
320
        textArea.style.height = '2em';
321
322
        // We don't need padding, reducing the size if it does flash render.
323
        textArea.style.padding = 0;
324
325
        // Clean up any borders.
326
        textArea.style.border = 'none';
327
        textArea.style.outline = 'none';
328
        textArea.style.boxShadow = 'none';
329
330
        // Avoid flash of white box if rendered for any reason.
331
        textArea.style.background = 'transparent';
332
333
        textArea.value = '';
334
335
        $('#serverinfo a').each(function () {
336
            textArea.value += $(this).text().split(':')[1].trim() + '/';
337
        });
338
        textArea.value += '\t\t' + window.location.href;
339
        textArea.value += '\n';
340
        $('.success').each(function () {
341
            textArea.value += $(this).text() + '\n\n';
342
        });
343
344
        $('.sql pre').each(function () {
345
            textArea.value += $(this).text() + '\n\n';
346
        });
347
348
        $('.table_results .column_heading a').each(function () {
349
            // Don't copy ordering number text within <small> tag
350
            textArea.value += $(this).clone().find('small').remove().end().text() + '\t';
351
        });
352
353
        textArea.value += '\n';
354
        $('.table_results tbody tr').each(function () {
355
            $(this).find('.data span').each(function () {
356
                textArea.value += $(this).text() + '\t';
357
            });
358
            textArea.value += '\n';
359
        });
360
361
        document.body.appendChild(textArea);
362
363
        textArea.select();
364
365
        try {
366
            document.execCommand('copy');
367
        } catch (err) {
368
            alert('Sorry! Unable to copy');
369
        }
370
371
        document.body.removeChild(textArea);
372
    }); // end of Copy to Clipboard action
373
374
    /**
375
     * Attach Event Handler for 'Print' link
376
     */
377
    $(document).on('click', '#printView', function (event) {
378
        event.preventDefault();
379
380
        // Take to preview mode
381
        printPreview();
382
    }); // end of 'Print' action
383
384
    /**
385
     * Attach the {@link makegrid} function to a custom event, which will be
386
     * triggered manually everytime the table of results is reloaded
387
     * @memberOf    jQuery
388
     */
389
    $(document).on('makegrid', '.sqlqueryresults', function () {
390
        $('.table_results').each(function () {
391
            PMA_makegrid(this);
392
        });
393
    });
394
395
    /*
396
     * Attach a custom event for sticky column headings which will be
397
     * triggered manually everytime the table of results is reloaded
398
     * @memberOf    jQuery
399
     */
400
    $(document).on('stickycolumns', '.sqlqueryresults', function () {
401
        $('.sticky_columns').remove();
402
        $('.table_results').each(function () {
403
            var $table_results = $(this);
404
            // add sticky columns div
405
            var $stick_columns = initStickyColumns($table_results);
406
            rearrangeStickyColumns($stick_columns, $table_results);
407
            // adjust sticky columns on scroll
408
            $(document).on('scroll', window, function () {
409
                handleStickyColumns($stick_columns, $table_results);
410
            });
411
        });
412
    });
413
414
    /**
415
     * Append the "Show/Hide query box" message to the query input form
416
     *
417
     * @memberOf jQuery
418
     * @name    appendToggleSpan
419
     */
420
    // do not add this link more than once
421
    if (! $('#sqlqueryform').find('a').is('#togglequerybox')) {
422
        $('<a id="togglequerybox"></a>')
423
            .html(PMA_messages.strHideQueryBox)
424
            .appendTo('#sqlqueryform')
425
        // initially hidden because at this point, nothing else
426
        // appears under the link
427
            .hide();
428
429
        // Attach the toggling of the query box visibility to a click
430
        $('#togglequerybox').bind('click', function () {
431
            var $link = $(this);
432
            $link.siblings().slideToggle('fast');
433
            if ($link.text() === PMA_messages.strHideQueryBox) {
434
                $link.text(PMA_messages.strShowQueryBox);
435
                // cheap trick to add a spacer between the menu tabs
436
                // and "Show query box"; feel free to improve!
437
                $('#togglequerybox_spacer').remove();
438
                $link.before('<br id="togglequerybox_spacer" />');
439
            } else {
440
                $link.text(PMA_messages.strHideQueryBox);
441
            }
442
            // avoid default click action
443
            return false;
444
        });
445
    }
446
447
448
    /**
449
     * Event handler for sqlqueryform.ajax button_submit_query
450
     *
451
     * @memberOf    jQuery
452
     */
453
    $(document).on('click', '#button_submit_query', function (event) {
454
        $('.success,.error').hide();
455
        // hide already existing error or success message
456
        var $form = $(this).closest('form');
457
        // the Go button related to query submission was clicked,
458
        // instead of the one related to Bookmarks, so empty the
459
        // id_bookmark selector to avoid misinterpretation in
460
        // import.php about what needs to be done
461
        $form.find('select[name=id_bookmark]').val('');
462
        // let normal event propagation happen
463
        if (isStorageSupported('localStorage')) {
464
            window.localStorage.removeItem('auto_saved_sql');
465
        } else {
466
            Cookies.set('auto_saved_sql', '');
467
        }
468
        var isShowQuery =  $('input[name="show_query"').is(':checked');
469
        if (isShowQuery) {
470
            window.localStorage.show_this_query = '1';
471
            var db = $('input[name="db"]').val();
472
            var table = $('input[name="table"]').val();
473
            var query;
474
            if (codemirror_editor) {
475
                query = codemirror_editor.getValue();
476
            } else {
477
                query = $('#sqlquery').val();
478
            }
479
            PMA_showThisQuery(db, table, query);
480
        } else {
481
            window.localStorage.show_this_query = '0';
482
        }
483
    });
484
485
    /**
486
     * Event handler to show appropiate number of variable boxes
487
     * based on the bookmarked query
488
     */
489
    $(document).on('change', '#id_bookmark', function (event) {
490
        var varCount = $(this).find('option:selected').data('varcount');
491
        if (typeof varCount === 'undefined') {
492
            varCount = 0;
493
        }
494
495
        var $varDiv = $('#bookmark_variables');
496
        $varDiv.empty();
497
        for (var i = 1; i <= varCount; i++) {
498
            $varDiv.append($('<label for="bookmark_variable_' + i + '">' + PMA_sprintf(PMA_messages.strBookmarkVariable, i) + '</label>'));
499
            $varDiv.append($('<input type="text" size="10" name="bookmark_variable[' + i + ']" id="bookmark_variable_' + i + '"/>'));
500
        }
501
502
        if (varCount === 0) {
503
            $varDiv.parent('.formelement').hide();
504
        } else {
505
            $varDiv.parent('.formelement').show();
506
        }
507
    });
508
509
    /**
510
     * Event handler for hitting enter on sqlqueryform bookmark_variable
511
     * (the Variable textfield in Bookmarked SQL query section)
512
     *
513
     * @memberOf    jQuery
514
     */
515
    $('input[name=bookmark_variable]').on('keypress', function (event) {
516
        // force the 'Enter Key' to implicitly click the #button_submit_bookmark
517
        var keycode = (event.keyCode ? event.keyCode : (event.which ? event.which : event.charCode));
518
        if (keycode === 13) { // keycode for enter key
519
            // When you press enter in the sqlqueryform, which
520
            // has 2 submit buttons, the default is to run the
521
            // #button_submit_query, because of the tabindex
522
            // attribute.
523
            // This submits #button_submit_bookmark instead,
524
            // because when you are in the Bookmarked SQL query
525
            // section and hit enter, you expect it to do the
526
            // same action as the Go button in that section.
527
            $('#button_submit_bookmark').trigger('click');
528
            return false;
529
        } else  {
530
            return true;
531
        }
532
    });
533
534
    /**
535
     * Ajax Event handler for 'SQL Query Submit'
536
     *
537
     * @see         PMA_ajaxShowMessage()
538
     * @memberOf    jQuery
539
     * @name        sqlqueryform_submit
540
     */
541
    $(document).on('submit', '#sqlqueryform.ajax', function (event) {
542
        event.preventDefault();
543
544
        var $form = $(this);
545
        if (codemirror_editor) {
546
            $form[0].elements.sql_query.value = codemirror_editor.getValue();
547
        }
548
        if (! checkSqlQuery($form[0])) {
549
            return false;
550
        }
551
552
        // remove any div containing a previous error message
553
        $('div.error').remove();
554
555
        var $msgbox = PMA_ajaxShowMessage();
556
        var $sqlqueryresultsouter = $('#sqlqueryresultsouter');
557
558
        PMA_prepareForAjaxRequest($form);
559
560
        var argsep = PMA_commonParams.get('arg_separator');
561
        $.post($form.attr('action'), $form.serialize() + argsep + 'ajax_page_request=true', function (data) {
562
            if (typeof data !== 'undefined' && data.success === true) {
563
                // success happens if the query returns rows or not
564
565
                // show a message that stays on screen
566
                if (typeof data.action_bookmark !== 'undefined') {
567
                    // view only
568
                    if ('1' === data.action_bookmark) {
569
                        $('#sqlquery').text(data.sql_query);
570
                        // send to codemirror if possible
571
                        setQuery(data.sql_query);
572
                    }
573
                    // delete
574
                    if ('2' === data.action_bookmark) {
575
                        $('#id_bookmark option[value=\'' + data.id_bookmark + '\']').remove();
576
                        // if there are no bookmarked queries now (only the empty option),
577
                        // remove the bookmark section
578
                        if ($('#id_bookmark option').length === 1) {
579
                            $('#fieldsetBookmarkOptions').hide();
580
                            $('#fieldsetBookmarkOptionsFooter').hide();
581
                        }
582
                    }
583
                }
584
                $sqlqueryresultsouter
585
                    .show()
586
                    .html(data.message);
587
                PMA_highlightSQL($sqlqueryresultsouter);
588
589
                if (data._menu) {
590
                    if (history && history.pushState) {
591
                        history.replaceState({
592
                            menu : data._menu
593
                        },
594
                        null
595
                        );
596
                        AJAX.handleMenu.replace(data._menu);
597
                    } else {
598
                        PMA_MicroHistory.menus.replace(data._menu);
599
                        PMA_MicroHistory.menus.add(data._menuHash, data._menu);
600
                    }
601
                } else if (data._menuHash) {
602
                    if (! (history && history.pushState)) {
603
                        PMA_MicroHistory.menus.replace(PMA_MicroHistory.menus.get(data._menuHash));
604
                    }
605
                }
606
607
                if (data._params) {
608
                    PMA_commonParams.setAll(data._params);
609
                }
610
611
                if (typeof data.ajax_reload !== 'undefined') {
612
                    if (data.ajax_reload.reload) {
613
                        if (data.ajax_reload.table_name) {
614
                            PMA_commonParams.set('table', data.ajax_reload.table_name);
615
                            PMA_commonActions.refreshMain();
616
                        } else {
617
                            PMA_reloadNavigation();
618
                        }
619
                    }
620
                } else if (typeof data.reload !== 'undefined') {
621
                    // this happens if a USE or DROP command was typed
622
                    PMA_commonActions.setDb(data.db);
623
                    var url;
624
                    if (data.db) {
625
                        if (data.table) {
626
                            url = 'table_sql.php';
627
                        } else {
628
                            url = 'db_sql.php';
629
                        }
630
                    } else {
631
                        url = 'server_sql.php';
632
                    }
633
                    PMA_commonActions.refreshMain(url, function () {
634
                        $('#sqlqueryresultsouter')
635
                            .show()
636
                            .html(data.message);
637
                        PMA_highlightSQL($('#sqlqueryresultsouter'));
638
                    });
639
                }
640
641
                $('.sqlqueryresults').trigger('makegrid').trigger('stickycolumns');
642
                $('#togglequerybox').show();
643
                PMA_init_slider();
644
645
                if (typeof data.action_bookmark === 'undefined') {
646
                    if ($('#sqlqueryform input[name="retain_query_box"]').is(':checked') !== true) {
647
                        if ($('#togglequerybox').siblings(':visible').length > 0) {
648
                            $('#togglequerybox').trigger('click');
649
                        }
650
                    }
651
                }
652
            } else if (typeof data !== 'undefined' && data.success === false) {
653
                // show an error message that stays on screen
654
                $sqlqueryresultsouter
655
                    .show()
656
                    .html(data.error);
657
            }
658
            PMA_ajaxRemoveMessage($msgbox);
659
        }); // end $.post()
660
    }); // end SQL Query submit
661
662
    /**
663
     * Ajax Event handler for the display options
664
     * @memberOf    jQuery
665
     * @name        displayOptionsForm_submit
666
     */
667
    $(document).on('submit', 'form[name=\'displayOptionsForm\'].ajax', function (event) {
668
        event.preventDefault();
669
670
        $form = $(this);
671
672
        var $msgbox = PMA_ajaxShowMessage();
673
        var argsep = PMA_commonParams.get('arg_separator');
674
        $.post($form.attr('action'), $form.serialize() + argsep + 'ajax_request=true', function (data) {
675
            PMA_ajaxRemoveMessage($msgbox);
676
            var $sqlqueryresults = $form.parents('.sqlqueryresults');
677
            $sqlqueryresults
678
                .html(data.message)
679
                .trigger('makegrid')
680
                .trigger('stickycolumns');
681
            PMA_init_slider();
682
            PMA_highlightSQL($sqlqueryresults);
683
        }); // end $.post()
684
    }); // end displayOptionsForm handler
685
686
    // Filter row handling. --STARTS--
687
    $(document).on('keyup', '.filter_rows', function () {
688
        var unique_id = $(this).data('for');
689
        var $target_table = $('.table_results[data-uniqueId=\'' + unique_id + '\']');
690
        var $header_cells = $target_table.find('th[data-column]');
691
        var target_columns = Array();
692
        // To handle colspan=4, in case of edit,copy etc options.
693
        var dummy_th = ($('.edit_row_anchor').length !== 0 ?
694
            '<th class="hide dummy_th"></th><th class="hide dummy_th"></th><th class="hide dummy_th"></th>'
695
            : '');
696
        // Selecting columns that will be considered for filtering and searching.
697
        $header_cells.each(function () {
698
            target_columns.push($.trim($(this).text()));
699
        });
700
701
        var phrase = $(this).val();
702
        // Set same value to both Filter rows fields.
703
        $('.filter_rows[data-for=\'' + unique_id + '\']').not(this).val(phrase);
704
        // Handle colspan.
705
        $target_table.find('thead > tr').prepend(dummy_th);
706
        $.uiTableFilter($target_table, phrase, target_columns);
707
        $target_table.find('th.dummy_th').remove();
708
    });
709
    // Filter row handling. --ENDS--
710
711
    // Prompt to confirm on Show All
712
    $('body').on('click', '.navigation .showAllRows', function (e) {
713
        e.preventDefault();
714
        var $form = $(this).parents('form');
715
716
        if (! $(this).is(':checked')) { // already showing all rows
717
            submitShowAllForm();
718
        } else {
719
            $form.PMA_confirm(PMA_messages.strShowAllRowsWarning, $form.attr('action'), function (url) {
720
                submitShowAllForm();
721
            });
722
        }
723
724
        function submitShowAllForm () {
725
            var argsep = PMA_commonParams.get('arg_separator');
726
            var submitData = $form.serialize() + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
727
            PMA_ajaxShowMessage();
728
            AJAX.source = $form;
729
            $.post($form.attr('action'), submitData, AJAX.responseHandler);
730
        }
731
    });
732
733
    $('body').on('keyup', '#sqlqueryform', function () {
734
        PMA_handleSimulateQueryButton();
735
    });
736
737
    /**
738
     * Ajax event handler for 'Simulate DML'.
739
     */
740
    $('body').on('click', '#simulate_dml', function () {
741
        var $form = $('#sqlqueryform');
742
        var query = '';
743
        var delimiter = $('#id_sql_delimiter').val();
744
        var db_name = $form.find('input[name="db"]').val();
745
746
        if (codemirror_editor) {
747
            query = codemirror_editor.getValue();
748
        } else {
749
            query = $('#sqlquery').val();
750
        }
751
752
        if (query.length === 0) {
753
            alert(PMA_messages.strFormEmpty);
754
            $('#sqlquery').focus();
755
            return false;
756
        }
757
758
        var $msgbox = PMA_ajaxShowMessage();
759
        $.ajax({
760
            type: 'POST',
761
            url: $form.attr('action'),
762
            data: {
763
                server: PMA_commonParams.get('server'),
764
                db: db_name,
765
                ajax_request: '1',
766
                simulate_dml: '1',
767
                sql_query: query,
768
                sql_delimiter: delimiter
769
            },
770
            success: function (response) {
771
                PMA_ajaxRemoveMessage($msgbox);
772
                if (response.success) {
773
                    var dialog_content = '<div class="preview_sql">';
774
                    if (response.sql_data) {
775
                        var len = response.sql_data.length;
776
                        for (var i = 0; i < len; i++) {
777
                            dialog_content += '<strong>' + PMA_messages.strSQLQuery +
778
                                '</strong>' + response.sql_data[i].sql_query +
779
                                PMA_messages.strMatchedRows +
780
                                ' <a href="' + response.sql_data[i].matched_rows_url +
781
                                '">' + response.sql_data[i].matched_rows + '</a><br>';
782
                            if (i < len - 1) {
783
                                dialog_content += '<hr>';
784
                            }
785
                        }
786
                    } else {
787
                        dialog_content += response.message;
788
                    }
789
                    dialog_content += '</div>';
790
                    var $dialog_content = $(dialog_content);
791
                    var button_options = {};
792
                    button_options[PMA_messages.strClose] = function () {
793
                        $(this).dialog('close');
794
                    };
795
                    var $response_dialog = $('<div />').append($dialog_content).dialog({
796
                        minWidth: 540,
797
                        maxHeight: 400,
798
                        modal: true,
799
                        buttons: button_options,
800
                        title: PMA_messages.strSimulateDML,
801
                        open: function () {
802
                            PMA_highlightSQL($(this));
803
                        },
804
                        close: function () {
805
                            $(this).remove();
806
                        }
807
                    });
808
                } else {
809
                    PMA_ajaxShowMessage(response.error);
810
                }
811
            },
812
            error: function (response) {
813
                PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest);
814
            }
815
        });
816
    });
817
818
    /**
819
     * Handles multi submits of results browsing page such as edit, delete and export
820
     */
821
    $('body').on('click', 'form[name="resultsForm"].ajax button[name="submit_mult"], form[name="resultsForm"].ajax input[name="submit_mult"]', function (e) {
822
        e.preventDefault();
823
        var $button = $(this);
824
        var $form = $button.closest('form');
825
        var argsep = PMA_commonParams.get('arg_separator');
826
        var submitData = $form.serialize() + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true' + argsep + 'submit_mult=' + $button.val();
827
        PMA_ajaxShowMessage();
828
        AJAX.source = $form;
829
        $.post($form.attr('action'), submitData, AJAX.responseHandler);
830
    });
831
}); // end $()
832
833
/**
834
 * Starting from some th, change the class of all td under it.
835
 * If isAddClass is specified, it will be used to determine whether to add or remove the class.
836
 */
837
function PMA_changeClassForColumn ($this_th, newclass, isAddClass) {
838
    // index 0 is the th containing the big T
839
    var th_index = $this_th.index();
840
    var has_big_t = $this_th.closest('tr').children(':first').hasClass('column_action');
841
    // .eq() is zero-based
842
    if (has_big_t) {
843
        th_index--;
844
    }
845
    var $table = $this_th.parents('.table_results');
846
    if (! $table.length) {
847
        $table = $this_th.parents('table').siblings('.table_results');
848
    }
849
    var $tds = $table.find('tbody tr').find('td.data:eq(' + th_index + ')');
850
    if (isAddClass === undefined) {
851
        $tds.toggleClass(newclass);
852
    } else {
853
        $tds.toggleClass(newclass, isAddClass);
854
    }
855
}
856
857
/**
858
 * Handles browse foreign values modal dialog
859
 *
860
 * @param object $this_a reference to the browse foreign value link
861
 */
862
function browseForeignDialog ($this_a) {
863
    var formId = '#browse_foreign_form';
864
    var showAllId = '#foreign_showAll';
865
    var tableId = '#browse_foreign_table';
866
    var filterId = '#input_foreign_filter';
867
    var $dialog = null;
868
    $.get($this_a.attr('href'), { 'ajax_request': true }, function (data) {
869
        // Creates browse foreign value dialog
870
        $dialog = $('<div>').append(data.message).dialog({
871
            title: PMA_messages.strBrowseForeignValues,
872
            width: Math.min($(window).width() - 100, 700),
873
            maxHeight: $(window).height() - 100,
874
            dialogClass: 'browse_foreign_modal',
875
            close: function (ev, ui) {
876
                // remove event handlers attached to elements related to dialog
877
                $(tableId).off('click', 'td a.foreign_value');
878
                $(formId).off('click', showAllId);
879
                $(formId).off('submit');
880
                // remove dialog itself
881
                $(this).remove();
882
            },
883
            modal: true
884
        });
885
    }).done(function () {
886
        var showAll = false;
887
        $(tableId).on('click', 'td a.foreign_value', function (e) {
888
            e.preventDefault();
889
            var $input = $this_a.prev('input[type=text]');
890
            // Check if input exists or get CEdit edit_box
891
            if ($input.length === 0) {
892
                $input = $this_a.closest('.edit_area').prev('.edit_box');
893
            }
894
            // Set selected value as input value
895
            $input.val($(this).data('key'));
896
            $dialog.dialog('close');
897
        });
898
        $(formId).on('click', showAllId, function () {
899
            showAll = true;
900
        });
901
        $(formId).on('submit', function (e) {
902
            e.preventDefault();
903
            // if filter value is not equal to old value
904
            // then reset page number to 1
905
            if ($(filterId).val() !== $(filterId).data('old')) {
906
                $(formId).find('select[name=pos]').val('0');
907
            }
908
            var postParams = $(this).serializeArray();
909
            // if showAll button was clicked to submit form then
910
            // add showAll button parameter to form
911
            if (showAll) {
912
                postParams.push({
913
                    name: $(showAllId).attr('name'),
914
                    value: $(showAllId).val()
915
                });
916
            }
917
            // updates values in dialog
918
            $.post($(this).attr('action') + '?ajax_request=1', postParams, function (data) {
919
                var $obj = $('<div>').html(data.message);
920
                $(formId).html($obj.find(formId).html());
921
                $(tableId).html($obj.find(tableId).html());
922
            });
923
            showAll = false;
924
        });
925
    });
926
}
927
928
function checkSavedQuery () {
929
    if (isStorageSupported('localStorage') && window.localStorage.auto_saved_sql !== undefined) {
930
        PMA_ajaxShowMessage(PMA_messages.strPreviousSaveQuery);
931
    }
932
}
933
934
AJAX.registerOnload('sql.js', function () {
935
    $('body').on('click', 'a.browse_foreign', function (e) {
936
        e.preventDefault();
937
        browseForeignDialog($(this));
938
    });
939
940
    /**
941
     * vertical column highlighting in horizontal mode when hovering over the column header
942
     */
943
    $(document).on('mouseenter', 'th.column_heading.pointer', function (e) {
944
        PMA_changeClassForColumn($(this), 'hover', true);
945
    });
946
    $(document).on('mouseleave', 'th.column_heading.pointer', function (e) {
947
        PMA_changeClassForColumn($(this), 'hover', false);
948
    });
949
950
    /**
951
     * vertical column marking in horizontal mode when clicking the column header
952
     */
953
    $(document).on('click', 'th.column_heading.marker', function () {
954
        PMA_changeClassForColumn($(this), 'marked');
955
    });
956
957
    /**
958
     * create resizable table
959
     */
960
    $('.sqlqueryresults').trigger('makegrid').trigger('stickycolumns');
961
962
    /**
963
     * Check if there is any saved query
964
     */
965
    if (codemirror_editor || document.sqlform) {
966
        checkSavedQuery();
967
    }
968
});
969
970
/*
971
 * Profiling Chart
972
 */
973
function makeProfilingChart () {
974
    if ($('#profilingchart').length === 0 ||
975
        $('#profilingchart').html().length !== 0 ||
976
        !$.jqplot || !$.jqplot.Highlighter || !$.jqplot.PieRenderer
977
    ) {
978
        return;
979
    }
980
981
    var data = [];
982
    $.each(JSON.parse($('#profilingChartData').html()), function (key, value) {
983
        data.push([key, parseFloat(value)]);
984
    });
985
986
    // Remove chart and data divs contents
987
    $('#profilingchart').html('').show();
988
    $('#profilingChartData').html('');
989
990
    PMA_createProfilingChart('profilingchart', data);
991
}
992
993
/*
994
 * initialize profiling data tables
995
 */
996
function initProfilingTables () {
997
    if (!$.tablesorter) {
998
        return;
999
    }
1000
1001
    $('#profiletable').tablesorter({
1002
        widgets: ['zebra'],
1003
        sortList: [[0, 0]],
1004
        textExtraction: function (node) {
1005
            if (node.children.length > 0) {
1006
                return node.children[0].innerHTML;
1007
            } else {
1008
                return node.innerHTML;
1009
            }
1010
        }
1011
    });
1012
1013
    $('#profilesummarytable').tablesorter({
1014
        widgets: ['zebra'],
1015
        sortList: [[1, 1]],
1016
        textExtraction: function (node) {
1017
            if (node.children.length > 0) {
1018
                return node.children[0].innerHTML;
1019
            } else {
1020
                return node.innerHTML;
1021
            }
1022
        }
1023
    });
1024
}
1025
1026
/*
1027
 * Set position, left, top, width of sticky_columns div
1028
 */
1029
function setStickyColumnsPosition ($sticky_columns, $table_results, position, top, left, margin_left) {
1030
    $sticky_columns
1031
        .css('position', position)
1032
        .css('top', top)
1033
        .css('left', left ? left : 'auto')
1034
        .css('margin-left', margin_left ? margin_left : '0px')
1035
        .css('width', $table_results.width());
1036
}
1037
1038
/*
1039
 * Initialize sticky columns
1040
 */
1041
function initStickyColumns ($table_results) {
1042
    return $('<table class="sticky_columns"></table>')
1043
        .insertBefore($table_results)
1044
        .css('position', 'fixed')
1045
        .css('z-index', '99')
1046
        .css('width', $table_results.width())
1047
        .css('margin-left', $('#page_content').css('margin-left'))
1048
        .css('top', $('#floating_menubar').height())
1049
        .css('display', 'none');
1050
}
1051
1052
/*
1053
 * Arrange/Rearrange columns in sticky header
1054
 */
1055
function rearrangeStickyColumns ($sticky_columns, $table_results) {
0 ignored issues
show
'rearrangeStickyColumns' was used before it was defined.
Loading history...
1056
    var $originalHeader = $table_results.find('thead');
1057
    var $originalColumns = $originalHeader.find('tr:first').children();
1058
    var $clonedHeader = $originalHeader.clone();
1059
    var is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
1060
    var is_safari = navigator.userAgent.indexOf('Safari') > -1;
1061
    // clone width per cell
1062
    $clonedHeader.find('tr:first').children().each(function (i) {
1063
        var width = $originalColumns.eq(i).width();
1064
        if (! is_firefox && ! is_safari) {
1065
            width += 1;
1066
        }
1067
        $(this).width(width);
1068
        if (is_safari) {
1069
            $(this).css('min-width', width).css('max-width', width);
1070
        }
1071
    });
1072
    $sticky_columns.empty().append($clonedHeader);
1073
}
1074
1075
/*
1076
 * Adjust sticky columns on horizontal/vertical scroll for all tables
1077
 */
1078
function handleAllStickyColumns () {
1079
    $('.sticky_columns').each(function () {
1080
        handleStickyColumns($(this), $(this).next('.table_results'));
1081
    });
1082
}
1083
1084
/*
1085
 * Adjust sticky columns on horizontal/vertical scroll
1086
 */
1087
function handleStickyColumns ($sticky_columns, $table_results) {
1088
    var currentScrollX = $(window).scrollLeft();
1089
    var windowOffset = $(window).scrollTop();
1090
    var tableStartOffset = $table_results.offset().top;
1091
    var tableEndOffset = tableStartOffset + $table_results.height();
1092
    if (windowOffset >= tableStartOffset && windowOffset <= tableEndOffset) {
1093
        // for horizontal scrolling
1094
        if (prevScrollX !== currentScrollX) {
1095
            prevScrollX = currentScrollX;
1096
            setStickyColumnsPosition($sticky_columns, $table_results, 'absolute', $('#floating_menubar').height() + windowOffset - tableStartOffset);
1097
        // for vertical scrolling
1098
        } else {
1099
            setStickyColumnsPosition($sticky_columns, $table_results, 'fixed', $('#floating_menubar').height(), $('#pma_navigation').width() - currentScrollX, $('#page_content').css('margin-left'));
1100
        }
1101
        $sticky_columns.show();
1102
    } else {
1103
        $sticky_columns.hide();
1104
    }
1105
}
1106
1107
AJAX.registerOnload('sql.js', function () {
1108
    makeProfilingChart();
1109
    initProfilingTables();
1110
});
1111