PageSourceSearch

https://pasvik-inari.net/js/console.js?v=4.9.4

js pasvik-inari.net collected 2026-09-25 08:37:43 UTC 57,280 bytes, 1,495 lines download raw bytes

1/* vim: set expandtab sw=4 ts=4 sts=4: */
2/**
3 * Used in or for console
4 *
5 * @package phpMyAdmin-Console
6 */
7
8/**
9 * Console object
10 */
11var PMA_console = {
12    /**
13     * @var object, jQuery object, selector is '#pma_console>.content'
14     * @access private
15     */
16    $consoleContent: null,
17    /**
18     * @var object, jQuery object, selector is '#pma_console .content',
19     *  used for resizer
20     * @access private
21     */
22    $consoleAllContents: null,
23    /**
24     * @var object, jQuery object, selector is '#pma_console .toolbar'
25     * @access private
26     */
27    $consoleToolbar: null,
28    /**
29     * @var object, jQuery object, selector is '#pma_console .template'
30     * @access private
31     */
32    $consoleTemplates: null,
33    /**
34     * @var object, jQuery object, form for submit
35     * @access private
36     */
37    $requestForm: null,
38    /**
39     * @var object, contain console config
40     * @access private
41     */
42    config: null,
43    /**
44     * @var bool, if console element exist, it'll be true
45     * @access public
46     */
47    isEnabled: false,
48    /**
49     * @var bool, make sure console events bind only once
50     * @access private
51     */
52    isInitialized: false,
53    /**
54     * Used for console initialize, reinit is ok, just some variable assignment
55     *
56     * @return void
57     */
58    initialize: function () {
59        if ($('#pma_console').length === 0) {
60            return;
61        }
62
63        PMA_console.config = configGet('Console', false);
64
65        PMA_console.isEnabled = true;
66
67        // Vars init
68        PMA_console.$consoleToolbar = $('#pma_console').find('>.toolbar');
69        PMA_console.$consoleContent = $('#pma_console').find('>.content');
70        PMA_console.$consoleAllContents = $('#pma_console').find('.content');
71        PMA_console.$consoleTemplates = $('#pma_console').find('>.templates');
72
73        // Generate a from for post
74        PMA_console.$requestForm = $('<form method="post" action="import.php">' +
75            '<input name="is_js_confirmed" value="0">' +
76            '<textarea name="sql_query"></textarea>' +
77            '<input name="console_message_id" value="0">' +
78            '<input name="server" value="">' +
79            '<input name="db" value="">' +
80            '<input name="table" value="">' +
81            '<input name="token" value="">' +
82            '</form>'
83        );
84        PMA_console.$requestForm.children('[name=token]').val(PMA_commonParams.get('token'));
85        PMA_console.$requestForm.on('submit', AJAX.requestHandler);
86
87        // Event binds shouldn't run again
88        if (PMA_console.isInitialized === false) {
89            // Load config first
90            if (PMA_console.config.AlwaysExpand === true) {
91                $('#pma_console_options input[name=always_expand]').prop('checked', true);
92            }
93            if (PMA_console.config.StartHistory === true) {
94                $('#pma_console_options').find('input[name=start_history]').prop('checked', true);
95            }
96            if (PMA_console.config.CurrentQuery === true) {
97                $('#pma_console_options').find('input[name=current_query]').prop('checked', true);
98            }
99            if (PMA_console.config.EnterExecutes === true) {
100                $('#pma_console_options').find('input[name=enter_executes]').prop('checked', true);
101            }
102            if (PMA_console.config.DarkTheme === true) {
103                $('#pma_console_options').find('input[name=dark_theme]').prop('checked', true);
104                $('#pma_console').find('>.content').addClass('console_dark_theme');
105            }
106
107            PMA_consoleResizer.initialize();
108            PMA_consoleInput.initialize();
109            PMA_consoleMessages.initialize();
110            PMA_consoleBookmarks.initialize();
111            PMA_consoleDebug.initialize();
112
113            PMA_console.$consoleToolbar.children('.console_switch').click(PMA_console.toggle);
114
115            $('#pma_console').find('.toolbar').children().mousedown(function (event) {
116                event.preventDefault();
117                event.stopImmediatePropagation();
118            });
119
120            $('#pma_console').find('.button.clear').click(function () {
121                PMA_consoleMessages.clear();
122            });
123
124            $('#pma_console').find('.button.history').click(function () {
125                PMA_consoleMessages.showHistory();
126            });
127
128            $('#pma_console').find('.button.options').click(function () {
129                PMA_console.showCard('#pma_console_options');
130            });
131
132            $('#pma_console').find('.button.debug').click(function () {
133                PMA_console.showCard('#debug_console');
134            });
135
136            PMA_console.$consoleContent.click(function (event) {
137                if (event.target === this) {
138                    PMA_consoleInput.focus();
139                }
140            });
141
142            $('#pma_console').find('.mid_layer').click(function () {
143                PMA_console.hideCard($(this).parent().children('.card'));
144            });
145            $('#debug_console').find('.switch_button').click(function () {
146                PMA_console.hideCard($(this).closest('.card'));
147            });
148            $('#pma_bookmarks').find('.switch_button').click(function () {
149                PMA_console.hideCard($(this).closest('.card'));
150            });
151            $('#pma_console_options').find('.switch_button').click(function () {
152                PMA_console.hideCard($(this).closest('.card'));
153            });
154
155            $('#pma_console_options').find('input[type=checkbox]').change(function () {
156                PMA_console.updateConfig();
157            });
158
159            $('#pma_console_options').find('.button.default').click(function () {
160                $('#pma_console_options input[name=always_expand]').prop('checked', false);
161                $('#pma_console_options').find('input[name=start_history]').prop('checked', false);
162                $('#pma_console_options').find('input[name=current_query]').prop('checked', true);
163                $('#pma_console_options').find('input[name=enter_executes]').prop('checked', false);
164                $('#pma_console_options').find('input[name=dark_theme]').prop('checked', false);
165                PMA_console.updateConfig();
166            });
167
168            $('#pma_console_options').find('input[name=enter_executes]').change(function () {
169                PMA_consoleMessages.showInstructions(PMA_console.config.EnterExecutes);
170            });
171
172            $(document).ajaxComplete(function (event, xhr, ajaxOptions) {
173                if (ajaxOptions.dataType && ajaxOptions.dataType.indexOf('json') !== -1) {
174                    return;
175                }
176                if (xhr.status !== 200) {
177                    return;
178                }
179                try {
180                    var data = JSON.parse(xhr.responseText);
181                    PMA_console.ajaxCallback(data);
182                } catch (e) {
183                    console.trace();
184                    console.log('Failed to parse JSON: ' + e.message);
185                }
186            });
187
188            PMA_console.isInitialized = true;
189        }
190
191        // Change console mode from cookie
192        switch (PMA_console.config.Mode) {
193        case 'collapse':
194            PMA_console.collapse();
195            break;
196            /* jshint -W086 */// no break needed in default section
197        default:
198            PMA_console.setConfig('Mode', 'info');
199        case 'info':
200            /* jshint +W086 */
201            PMA_console.info();
202            break;
203        case 'show':
204            PMA_console.show(true);
205            PMA_console.scrollBottom();
206            break;
207        }
208    },
209    /**
210     * Execute query and show results in console
211     *
212     * @return void
213     */
214    execute: function (queryString, options) {
215        if (typeof(queryString) !== 'string' || ! /[a-z]|[A-Z]/.test(queryString)) {
216            return;
217        }
218        PMA_console.$requestForm.children('textarea').val(queryString);
219        PMA_console.$requestForm.children('[name=server]').attr('value', PMA_commonParams.get('server'));
220        if (options && options.db) {
221            PMA_console.$requestForm.children('[name=db]').val(options.db);
222            if (options.table) {
223                PMA_console.$requestForm.children('[name=table]').val(options.table);
224            } else {
225                PMA_console.$requestForm.children('[name=table]').val('');
226            }
227        } else {
228            PMA_console.$requestForm.children('[name=db]').val(
229                (PMA_commonParams.get('db').length > 0 ? PMA_commonParams.get('db') : ''));
230        }
231        PMA_console.$requestForm.find('[name=profiling]').remove();
232        if (options && options.profiling === true) {
233            PMA_console.$requestForm.append('<input name="profiling" value="on">');
234        }
235        if (! confirmQuery(PMA_console.$requestForm[0], PMA_console.$requestForm.children('textarea')[0].value)) {
236            return;
237        }
238        PMA_console.$requestForm.children('[name=console_message_id]')
239            .val(PMA_consoleMessages.appendQuery({ sql_query: queryString }).message_id);
240        PMA_console.$requestForm.trigger('submit');
241        PMA_consoleInput.clear();
242        PMA_reloadNavigation();
243    },
244    ajaxCallback: function (data) {
245        if (data && data.console_message_id) {
246            PMA_consoleMessages.updateQuery(data.console_message_id, data.success,
247                (data._reloadQuerywindow ? data._reloadQuerywindow : false));
248        } else if (data && data._reloadQuerywindow) {
249            if (data._reloadQuerywindow.sql_query.length > 0) {
250                PMA_consoleMessages.appendQuery(data._reloadQuerywindow, 'successed')
251                    .$message.addClass(PMA_console.config.CurrentQuery ? '' : 'hide');
252            }
253        }
254    },
255    /**
256     * Change console to collapse mode
257     *
258     * @return void
259     */
260    collapse: function () {
261        PMA_console.setConfig('Mode', 'collapse');
262        var pmaConsoleHeight = Math.max(92, PMA_console.config.Height);
263
264        PMA_console.$consoleToolbar.addClass('collapsed');
265        PMA_console.$consoleAllContents.height(pmaConsoleHeight);
266        PMA_console.$consoleContent.stop();
267        PMA_console.$consoleContent.animate({ 'margin-bottom': -1 * PMA_console.$consoleContent.outerHeight() + 'px' },
268            'fast', 'easeOutQuart', function () {
269                PMA_console.$consoleContent.css({ display:'none' });
270                $(window).trigger('resize');
271            });
272        PMA_console.hideCard();
273    },
274    /**
275     * Show console
276     *
277     * @param bool inputFocus If true, focus the input line after show()
278     * @return void
279     */
280    show: function (inputFocus) {
281        PMA_console.setConfig('Mode', 'show');
282
283        var pmaConsoleHeight = Math.max(92, PMA_console.config.Height);
284        pmaConsoleHeight = Math.min(PMA_console.config.Height, (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) - 25);
285        PMA_console.$consoleContent.css({ display:'block' });
286        if (PMA_console.$consoleToolbar.hasClass('collapsed')) {
287            PMA_console.$consoleToolbar.removeClass('collapsed');
288        }
289        PMA_console.$consoleAllContents.height(pmaConsoleHeight);
290        PMA_console.$consoleContent.stop();
291        PMA_console.$consoleContent.animate({ 'margin-bottom': 0 },
292            'fast', 'easeOutQuart', function () {
293                $(window).trigger('resize');
294                if (inputFocus) {
295                    PMA_consoleInput.focus();
296                }
297            });
298    },
299    /**
300     * Change console to SQL information mode
301     * this mode shows current SQL query
302     * This mode is the default mode
303     *
304     * @return void
305     */
306    info: function () {
307        // Under construction
308        PMA_console.collapse();
309    },
310    /**
311     * Toggle console mode between collapse/show
312     * Used for toggle buttons and shortcuts
313     *
314     * @return void
315     */
316    toggle: function () {
317        switch (PMA_console.config.Mode) {
318        case 'collapse':
319        case 'info':
320            PMA_console.show(true);
321            break;
322        case 'show':
323            PMA_console.collapse();
324            break;
325        default:
326            PMA_consoleInitialize();
327        }
328    },
329    /**
330     * Scroll console to bottom
331     *
332     * @return void
333     */
334    scrollBottom: function () {
335        PMA_console.$consoleContent.scrollTop(PMA_console.$consoleContent.prop('scrollHeight'));
336    },
337    /**
338     * Show card
339     *
340     * @param string cardSelector Selector, select string will be "#pma_console " + cardSelector
341     * this param also can be JQuery object, if you need.
342     *
343     * @return void
344     */
345    showCard: function (cardSelector) {
346        var $card = null;
347        if (typeof(cardSelector) !== 'string') {
348            if (cardSelector.length > 0) {
349                $card = cardSelector;
350            } else {
351                return;
352            }
353        } else {
354            $card = $('#pma_console ' + cardSelector);
355        }
356        if ($card.length === 0) {
357            return;
358        }
359        $card.parent().children('.mid_layer').show().fadeTo(0, 0.15);
360        $card.addClass('show');
361        PMA_consoleInput.blur();
362        if ($card.parents('.card').length > 0) {
363            PMA_console.showCard($card.parents('.card'));
364        }
365    },
366    /**
367     * Scroll console to bottom
368     *
369     * @param object $targetCard Target card JQuery object, if it's empty, function will hide all cards
370     * @return void
371     */
372    hideCard: function ($targetCard) {
373        if (! $targetCard) {
374            $('#pma_console').find('.mid_layer').fadeOut(140);
375            $('#pma_console').find('.card').removeClass('show');
376        } else if ($targetCard.length > 0) {
377            $targetCard.parent().find('.mid_layer').fadeOut(140);
378            $targetCard.find('.card').removeClass('show');
379            $targetCard.removeClass('show');
380        }
381    },
382    /**
383     * Used for update console config
384     *
385     * @return void
386     */
387    updateConfig: function () {
388        PMA_console.setConfig('AlwaysExpand', $('#pma_console_options input[name=always_expand]').prop('checked'));
389        PMA_console.setConfig('StartHistory', $('#pma_console_options').find('input[name=start_history]').prop('checked'));
390        PMA_console.setConfig('CurrentQuery', $('#pma_console_options').find('input[name=current_query]').prop('checked'));
391        PMA_console.setConfig('EnterExecutes', $('#pma_console_options').find('input[name=enter_executes]').prop('checked'));
392        PMA_console.setConfig('DarkTheme', $('#pma_console_options').find('input[name=dark_theme]').prop('checked'));
393        /* Setting the dark theme of the console*/
394        if (PMA_console.config.DarkTheme) {
395            $('#pma_console').find('>.content').addClass('console_dark_theme');
396        } else {
397            $('#pma_console').find('>.content').removeClass('console_dark_theme');
398        }
399    },
400    setConfig: function (key, value) {
401        PMA_console.config[key] = value;
402        configSet('Console/' + key, value);
403    },
404    isSelect: function (queryString) {
405        var reg_exp = /^SELECT\s+/i;
406        return reg_exp.test(queryString);
407    }
408};
409
410/**
411 * Resizer object
412 * Careful: this object UI logics highly related with functions under PMA_console
413 * Resizing min-height is 32, if small than it, console will collapse
414 */
415var PMA_consoleResizer = {
416    _posY: 0,
417    _height: 0,
418    _resultHeight: 0,
419    /**
420     * Mousedown event handler for bind to resizer
421     *
422     * @return void
423     */
424    _mousedown: function (event) {
425        if (PMA_console.config.Mode !== 'show') {
426            return;
427        }
428        PMA_consoleResizer._posY = event.pageY;
429        PMA_consoleResizer._height = PMA_console.$consoleContent.height();
430        $(document).mousemove(PMA_consoleResizer._mousemove);
431        $(document).mouseup(PMA_consoleResizer._mouseup);
432        // Disable text selection while resizing
433        $(document).on('selectstart', function () {
434            return false;
435        });
436    },
437    /**
438     * Mousemove event handler for bind to resizer
439     *
440     * @return void
441     */
442    _mousemove: function (event) {
443        if (event.pageY < 35) {
444            event.pageY = 35;
445        }
446        PMA_consoleResizer._resultHeight = PMA_consoleResizer._height + (PMA_consoleResizer._posY - event.pageY);
447        // Content min-height is 32, if adjusting height small than it we'll move it out of the page
448        if (PMA_consoleResizer._resultHeight <= 32) {
449            PMA_console.$consoleAllContents.height(32);
450            PMA_console.$consoleContent.css('margin-bottom', PMA_consoleResizer._resultHeight - 32);
451        } else {
452            // Logic below makes viewable area always at bottom when adjusting height and content already at bottom
453            if (PMA_console.$consoleContent.scrollTop() + PMA_console.$consoleContent.innerHeight() + 16
454                >= PMA_console.$consoleContent.prop('scrollHeight')) {
455                PMA_console.$consoleAllContents.height(PMA_consoleResizer._resultHeight);
456                PMA_console.scrollBottom();
457            } else {
458                PMA_console.$consoleAllContents.height(PMA_consoleResizer._resultHeight);
459            }
460        }
461    },
462    /**
463     * Mouseup event handler for bind to resizer
464     *
465     * @return void
466     */
467    _mouseup: function () {
468        PMA_console.setConfig('Height', PMA_consoleResizer._resultHeight);
469        PMA_console.show();
470        $(document).off('mousemove');
471        $(document).off('mouseup');
472        $(document).off('selectstart');
473    },
474    /**
475     * Used for console resizer initialize
476     *
477     * @return void
478     */
479    initialize: function () {
480        $('#pma_console').find('.toolbar').off('mousedown');
481        $('#pma_console').find('.toolbar').mousedown(PMA_consoleResizer._mousedown);
482    }
483};
484
485
486/**
487 * Console input object
488 */
489var PMA_consoleInput = {
490    /**
491     * @var array, contains Codemirror objects or input jQuery objects
492     * @access private
493     */
494    _inputs: null,
495    /**
496     * @var bool, if codemirror enabled
497     * @access private
498     */
499    _codemirror: false,
500    /**
501     * @var int, count for history navigation, 0 for current input
502     * @access private
503     */
504    _historyCount: 0,
505    /**
506     * @var string, current input when navigating through history
507     * @access private
508     */
509    _historyPreserveCurrent: null,
510    /**
511     * Used for console input initialize
512     *
513     * @return void
514     */
515    initialize: function () {
516        // _cm object can't be reinitialize
517        if (PMA_consoleInput._inputs !== null) {
518            return;
519        }
520        if (typeof CodeMirror !== 'undefined') {
521            PMA_consoleInput._codemirror = true;
522        }
523        PMA_consoleInput._inputs = [];
524        if (PMA_consoleInput._codemirror) {
525            PMA_consoleInput._inputs.console = CodeMirror($('#pma_console').find('.console_query_input')[0], {
526                theme: 'pma',
527                mode: 'text/x-sql',
528                lineWrapping: true,
529                extraKeys: { 'Ctrl-Space': 'autocomplete' },
530                hintOptions: { 'completeSingle': false, 'completeOnSingleClick': true },
531                gutters: ['CodeMirror-lint-markers'],
532                lint: {
533                    'getAnnotations': CodeMirror.sqlLint,
534                    'async': true,
535                }
536            });
537            PMA_consoleInput._inputs.console.on('inputRead', codemirrorAutocompleteOnInputRead);
538            PMA_consoleInput._inputs.console.on('keydown', function (instance, event) {
539                PMA_consoleInput._historyNavigate(event);
540            });
541            if ($('#pma_bookmarks').length !== 0) {
542                PMA_consoleInput._inputs.bookmark = CodeMirror($('#pma_console').find('.bookmark_add_input')[0], {
543                    theme: 'pma',
544                    mode: 'text/x-sql',
545                    lineWrapping: true,
546                    extraKeys: { 'Ctrl-Space': 'autocomplete' },
547                    hintOptions: { 'completeSingle': false, 'completeOnSingleClick': true },
548                    gutters: ['CodeMirror-lint-markers'],
549                    lint: {
550                        'getAnnotations': CodeMirror.sqlLint,
551                        'async': true,
552                    }
553                });
554                PMA_consoleInput._inputs.bookmark.on('inputRead', codemirrorAutocompleteOnInputRead);
555            }
556        } else {
557            PMA_consoleInput._inputs.console =
558                $('<textarea>').appendTo('#pma_console .console_query_input')
559                    .on('keydown', PMA_consoleInput._historyNavigate);
560            if ($('#pma_bookmarks').length !== 0) {
561                PMA_consoleInput._inputs.bookmark =
562                    $('<textarea>').appendTo('#pma_console .bookmark_add_input');
563            }
564        }
565        $('#pma_console').find('.console_query_input').keydown(PMA_consoleInput._keydown);
566    },
567    _historyNavigate: function (event) {
568        if (event.keyCode === 38 || event.keyCode === 40) {
569            var upPermitted = false;
570            var downPermitted = false;
571            var editor = PMA_consoleInput._inputs.console;
572            var cursorLine;
573            var totalLine;
574            if (PMA_consoleInput._codemirror) {
575                cursorLine = editor.getCursor().line;
576                totalLine = editor.lineCount();
577            } else {
578                // Get cursor position from textarea
579                var text = PMA_consoleInput.getText();
580                cursorLine = text.substr(0, editor.prop('selectionStart')).split('\n').length - 1;
581                totalLine = text.split(/\r*\n/).length;
582            }
583            if (cursorLine === 0) {
584                upPermitted = true;
585            }
586            if (cursorLine === totalLine - 1) {
587                downPermitted = true;
588            }
589            var nextCount;
590            var queryString = false;
591            if (upPermitted && event.keyCode === 38) {
592                // Navigate up in history
593                if (PMA_consoleInput._historyCount === 0) {
594                    PMA_consoleInput._historyPreserveCurrent = PMA_consoleInput.getText();
595                }
596                nextCount = PMA_consoleInput._historyCount + 1;
597                queryString = PMA_consoleMessages.getHistory(nextCount);
598            } else if (downPermitted && event.keyCode === 40) {
599                // Navigate down in history
600                if (PMA_consoleInput._historyCount === 0) {
601                    return;
602                }
603                nextCount = PMA_consoleInput._historyCount - 1;
604                if (nextCount === 0) {
605                    queryString = PMA_consoleInput._historyPreserveCurrent;
606                } else {
607                    queryString = PMA_consoleMessages.getHistory(nextCount);
608                }
609            }
610            if (queryString !== false) {
611                PMA_consoleInput._historyCount = nextCount;
612                PMA_consoleInput.setText(queryString, 'console');
613                if (PMA_consoleInput._codemirror) {
614                    editor.setCursor(editor.lineCount(), 0);
615                }
616                event.preventDefault();
617            }
618        }
619    },
620    /**
621     * Mousedown event handler for bind to input
622     * Shortcut is Ctrl+Enter key or just ENTER, depending on console's
623     * configuration.
624     *
625     * @return void
626     */
627    _keydown: function (event) {
628        if (PMA_console.config.EnterExecutes) {
629            // Enter, but not in combination with Shift (which writes a new line).
630            if (!event.shiftKey && event.keyCode === 13) {
631                PMA_consoleInput.execute();
632            }
633        } else {
634            // Ctrl+Enter
635            if (event.ctrlKey && event.keyCode === 13) {
636                PMA_consoleInput.execute();
637            }
638        }
639    },
640    /**
641     * Used for send text to PMA_console.execute()
642     *
643     * @return void
644     */
645    execute: function () {
646        if (PMA_consoleInput._codemirror) {
647            PMA_console.execute(PMA_consoleInput._inputs.console.getValue());
648        } else {
649            PMA_console.execute(PMA_consoleInput._inputs.console.val());
650        }
651    },
652    /**
653     * Used for clear the input
654     *
655     * @param string target, default target is console input
656     * @return void
657     */
658    clear: function (target) {
659        PMA_consoleInput.setText('', target);
660    },
661    /**
662     * Used for set focus to input
663     *
664     * @return void
665     */
666    focus: function () {
667        PMA_consoleInput._inputs.console.focus();
668    },
669    /**
670     * Used for blur input
671     *
672     * @return void
673     */
674    blur: function () {
675        if (PMA_consoleInput._codemirror) {
676            PMA_consoleInput._inputs.console.getInputField().blur();
677        } else {
678            PMA_consoleInput._inputs.console.blur();
679        }
680    },
681    /**
682     * Used for set text in input
683     *
684     * @param string text
685     * @param string target
686     * @return void
687     */
688    setText: function (text, target) {
689        if (PMA_consoleInput._codemirror) {
690            switch (target) {
691            case 'bookmark':
692                PMA_console.execute(PMA_consoleInput._inputs.bookmark.setValue(text));
693                break;
694            default:
695            case 'console':
696                PMA_console.execute(PMA_consoleInput._inputs.console.setValue(text));
697            }
698        } else {
699            switch (target) {
700            case 'bookmark':
701                PMA_console.execute(PMA_consoleInput._inputs.bookmark.val(text));
702                break;
703            default:
704            case 'console':
705                PMA_console.execute(PMA_consoleInput._inputs.console.val(text));
706            }
707        }
708    },
709    getText: function (target) {
710        if (PMA_consoleInput._codemirror) {
711            switch (target) {
712            case 'bookmark':
713                return PMA_consoleInput._inputs.bookmark.getValue();
714            default:
715            case 'console':
716                return PMA_consoleInput._inputs.console.getValue();
717            }
718        } else {
719            switch (target) {
720            case 'bookmark':
721                return PMA_consoleInput._inputs.bookmark.val();
722            default:
723            case 'console':
724                return PMA_consoleInput._inputs.console.val();
725            }
726        }
727    }
728
729};
730
731
732/**
733 * Console messages, and message items management object
734 */
735var PMA_consoleMessages = {
736    /**
737     * Used for clear the messages
738     *
739     * @return void
740     */
741    clear: function () {
742        $('#pma_console').find('.content .console_message_container .message:not(.welcome)').addClass('hide');
743        $('#pma_console').find('.content .console_message_container .message.failed').remove();
744        $('#pma_console').find('.content .console_message_container .message.expanded').find('.action.collapse').click();
745    },
746    /**
747     * Used for show history messages
748     *
749     * @return void
750     */
751    showHistory: function () {
752        $('#pma_console').find('.content .console_message_container .message.hide').removeClass('hide');
753    },
754    /**
755     * Used for getting a perticular history query
756     *
757     * @param int nthLast get nth query message from latest, i.e 1st is last
758     * @return string message
759     */
760    getHistory: function (nthLast) {
761        var $queries = $('#pma_console').find('.content .console_message_container .query');
762        var length = $queries.length;
763        var $query = $queries.eq(length - nthLast);
764        if (!$query || (length - nthLast) < 0) {
765            return false;
766        } else {
767            return $query.text();
768        }
769    },
770    /**
771     * Used to show the correct message depending on which key
772     * combination executes the query (Ctrl+Enter or Enter).
773     *
774     * @param bool enterExecutes Only Enter has to be pressed to execute query.
775     * @return void
776     */
777    showInstructions: function (enterExecutes) {
778        enterExecutes = +enterExecutes || 0; // conversion to int
779        var $welcomeMsg = $('#pma_console').find('.content .console_message_container .message.welcome span');
780        $welcomeMsg.children('[id^=instructions]').hide();
781        $welcomeMsg.children('#instructions-' + enterExecutes).show();
782    },
783    /**
784     * Used for log new message
785     *
786     * @param string msgString Message to show
787     * @param string msgType Message type
788     * @return object, {message_id, $message}
789     */
790    append: function (msgString, msgType) {
791        if (typeof(msgString) !== 'string') {
792            return false;
793        }
794        // Generate an ID for each message, we can find them later
795        var msgId = Math.round(Math.random() * (899999999999) + 100000000000);
796        var now = new Date();
797        var $newMessage =
798            $('<div class="message ' +
799                (PMA_console.config.AlwaysExpand ? 'expanded' : 'collapsed') +
800                '" msgid="' + msgId + '"><div class="action_content"></div></div>');
801        switch (msgType) {
802        case 'query':
803            $newMessage.append('<div class="query highlighted"></div>');
804            if (PMA_consoleInput._codemirror) {
805                CodeMirror.runMode(msgString,
806                    'text/x-sql', $newMessage.children('.query')[0]);
807            } else {
808                $newMessage.children('.query').text(msgString);
809            }
810            $newMessage.children('.action_content')
811                .append(PMA_console.$consoleTemplates.children('.query_actions').html());
812            break;
813        default:
814        case 'normal':
815            $newMessage.append('<div>' + msgString + '</div>');
816        }
817        PMA_consoleMessages._msgEventBinds($newMessage);
818        $newMessage.find('span.text.query_time span')
819            .text(now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds())
820            .parent().attr('title', now);
821        return { message_id: msgId,
822            $message: $newMessage.appendTo('#pma_console .content .console_message_container') };
823    },
824    /**
825     * Used for log new query
826     *
827     * @param string queryData Struct should be
828     * {sql_query: "Query string", db: "Target DB", table: "Target Table"}
829     * @param string state Message state
830     * @return object, {message_id: string message id, $message: JQuery object}
831     */
832    appendQuery: function (queryData, state) {
833        var targetMessage = PMA_consoleMessages.append(queryData.sql_query, 'query');
834        if (! targetMessage) {
835            return false;
836        }
837        if (queryData.db && queryData.table) {
838            targetMessage.$message.attr('targetdb', queryData.db);
839            targetMessage.$message.attr('targettable', queryData.table);
840            targetMessage.$message.find('.text.targetdb span').text(queryData.db);
841        }
842        if (PMA_console.isSelect(queryData.sql_query)) {
843            targetMessage.$message.addClass('select');
844        }
845        switch (state) {
846        case 'failed':
847            targetMessage.$message.addClass('failed');
848            break;
849        case 'successed':
850            targetMessage.$message.addClass('successed');
851            break;
852        default:
853        case 'pending':
854            targetMessage.$message.addClass('pending');
855        }
856        return targetMessage;
857    },
858    _msgEventBinds: function ($targetMessage) {
859        // Leave unbinded elements, remove binded.
860        $targetMessage = $targetMessage.filter(':not(.binded)');
861        if ($targetMessage.length === 0) {
862            return;
863        }
864        $targetMessage.addClass('binded');
865
866        $targetMessage.find('.action.expand').click(function () {
867            $(this).closest('.message').removeClass('collapsed');
868            $(this).closest('.message').addClass('expanded');
869        });
870        $targetMessage.find('.action.collapse').click(function () {
871            $(this).closest('.message').addClass('collapsed');
872            $(this).closest('.message').removeClass('expanded');
873        });
874        $targetMessage.find('.action.edit').click(function () {
875            PMA_consoleInput.setText($(this).parent().siblings('.query').text());
876            PMA_consoleInput.focus();
877        });
878        $targetMessage.find('.action.requery').click(function () {
879            var query = $(this).parent().siblings('.query').text();
880            var $message = $(this).closest('.message');
881            if (confirm(PMA_messages.strConsoleRequeryConfirm + '\n' +
882                (query.length < 100 ? query : query.slice(0, 100) + '...'))
883            ) {
884                PMA_console.execute(query, { db: $message.attr('targetdb'), table: $message.attr('targettable') });
885            }
886        });
887        $targetMessage.find('.action.bookmark').click(function () {
888            var query = $(this).parent().siblings('.query').text();
889            var $message = $(this).closest('.message');
890            PMA_consoleBookmarks.addBookmark(query, $message.attr('targetdb'));
891            PMA_console.showCard('#pma_bookmarks .card.add');
892        });
893        $targetMessage.find('.action.edit_bookmark').click(function () {
894            var query = $(this).parent().siblings('.query').text();
895            var $message = $(this).closest('.message');
896            var isShared = $message.find('span.bookmark_label').hasClass('shared');
897            var label = $message.find('span.bookmark_label').text();
898            PMA_consoleBookmarks.addBookmark(query, $message.attr('targetdb'), label, isShared);
899            PMA_console.showCard('#pma_bookmarks .card.add');
900        });
901        $targetMessage.find('.action.delete_bookmark').click(function () {
902            var $message = $(this).closest('.message');
903            if (confirm(PMA_messages.strConsoleDeleteBookmarkConfirm + '\n' + $message.find('.bookmark_label').text())) {
904                $.post('import.php',
905                    {
906                        server: PMA_commonParams.get('server'),
907                        action_bookmark: 2,
908                        ajax_request: true,
909                        id_bookmark: $message.attr('bookmarkid') },
910                    function () {
911                        PMA_consoleBookmarks.refresh();
912                    });
913            }
914        });
915        $targetMessage.find('.action.profiling').click(function () {
916            var $message = $(this).closest('.message');
917            PMA_console.execute($(this).parent().siblings('.query').text(),
918                { db: $message.attr('targetdb'),
919                    table: $message.attr('targettable'),
920                    profiling: true });
921        });
922        $targetMessage.find('.action.explain').click(function () {
923            var $message = $(this).closest('.message');
924            PMA_console.execute('EXPLAIN ' + $(this).parent().siblings('.query').text(),
925                { db: $message.attr('targetdb'),
926                    table: $message.attr('targettable') });
927        });
928        $targetMessage.find('.action.dbg_show_trace').click(function () {
929            var $message = $(this).closest('.message');
930            if (!$message.find('.trace').length) {
931                PMA_consoleDebug.getQueryDetails(
932                    $message.data('queryInfo'),
933                    $message.data('totalTime'),
934                    $message
935                );
936                PMA_consoleMessages._msgEventBinds($message.find('.message:not(.binded)'));
937            }
938            $message.addClass('show_trace');
939            $message.removeClass('hide_trace');
940        });
941        $targetMessage.find('.action.dbg_hide_trace').click(function () {
942            var $message = $(this).closest('.message');
943            $message.addClass('hide_trace');
944            $message.removeClass('show_trace');
945        });
946        $targetMessage.find('.action.dbg_show_args').click(function () {
947            var $message = $(this).closest('.message');
948            $message.addClass('show_args expanded');
949            $message.removeClass('hide_args collapsed');
950        });
951        $targetMessage.find('.action.dbg_hide_args').click(function () {
952            var $message = $(this).closest('.message');
953            $message.addClass('hide_args collapsed');
954            $message.removeClass('show_args expanded');
955        });
956        if (PMA_consoleInput._codemirror) {
957            $targetMessage.find('.query:not(.highlighted)').each(function (index, elem) {
958                CodeMirror.runMode($(elem).text(),
959                    'text/x-sql', elem);
960                $(this).addClass('highlighted');
961            });
962        }
963    },
964    msgAppend: function (msgId, msgString, msgType) {
965        var $targetMessage = $('#pma_console').find('.content .console_message_container .message[msgid=' + msgId + ']');
966        if ($targetMessage.length === 0 || isNaN(parseInt(msgId)) || typeof(msgString) !== 'string') {
967            return false;
968        }
969        $targetMessage.append('<div>' + msgString + '</div>');
970    },
971    updateQuery: function (msgId, isSuccessed, queryData) {
972        var $targetMessage = $('#pma_console').find('.console_message_container .message[msgid=' + parseInt(msgId) + ']');
973        if ($targetMessage.length === 0 || isNaN(parseInt(msgId))) {
974            return false;
975        }
976        $targetMessage.removeClass('pending failed successed');
977        if (isSuccessed) {
978            $targetMessage.addClass('successed');
979            if (queryData) {
980                $targetMessage.children('.query').text('');
981                $targetMessage.removeClass('select');
982                if (PMA_console.isSelect(queryData.sql_query)) {
983                    $targetMessage.addClass('select');
984                }
985                if (PMA_consoleInput._codemirror) {
986                    CodeMirror.runMode(queryData.sql_query, 'text/x-sql', $targetMessage.children('.query')[0]);
987                } else {
988                    $targetMessage.children('.query').text(queryData.sql_query);
989                }
990                $targetMessage.attr('targetdb', queryData.db);
991                $targetMessage.attr('targettable', queryData.table);
992                $targetMessage.find('.text.targetdb span').text(queryData.db);
993            }
994        } else {
995            $targetMessage.addClass('failed');
996        }
997    },
998    /**
999     * Used for console messages initialize
1000     *
1001     * @return void
1002     */
1003    initialize: function () {
1004        PMA_consoleMessages._msgEventBinds($('#pma_console').find('.message:not(.binded)'));
1005        if (PMA_console.config.StartHistory) {
1006            PMA_consoleMessages.showHistory();
1007        }
1008        PMA_consoleMessages.showInstructions(PMA_console.config.EnterExecutes);
1009    }
1010};
1011
1012
1013/**
1014 * Console bookmarks card, and bookmarks items management object
1015 */
1016var PMA_consoleBookmarks = {
1017    _bookmarks: [],
1018    addBookmark: function (queryString, targetDb, label, isShared, id) {
1019        $('#pma_bookmarks').find('.add [name=shared]').prop('checked', false);
1020        $('#pma_bookmarks').find('.add [name=label]').val('');
1021        $('#pma_bookmarks').find('.add [name=targetdb]').val('');
1022        $('#pma_bookmarks').find('.add [name=id_bookmark]').val('');
1023        PMA_consoleInput.setText('', 'bookmark');
1024
1025        switch (arguments.length) {
1026        case 4:
1027            $('#pma_bookmarks').find('.add [name=shared]').prop('checked', isShared);
1028        case 3:
1029            $('#pma_bookmarks').find('.add [name=label]').val(label);
1030        case 2:
1031            $('#pma_bookmarks').find('.add [name=targetdb]').val(targetDb);
1032        case 1:
1033            PMA_consoleInput.setText(queryString, 'bookmark');
1034        default:
1035            break;
1036        }
1037    },
1038    refresh: function () {
1039        $.get('import.php',
1040            { ajax_request: true,
1041                server: PMA_commonParams.get('server'),
1042                console_bookmark_refresh: 'refresh' },
1043            function (data) {
1044                if (data.console_message_bookmark) {
1045                    $('#pma_bookmarks').find('.content.bookmark').html(data.console_message_bookmark);
1046                    PMA_consoleMessages._msgEventBinds($('#pma_bookmarks').find('.message:not(.binded)'));
1047                }
1048            });
1049    },
1050    /**
1051     * Used for console bookmarks initialize
1052     * message events are already binded by PMA_consoleMsg._msgEventBinds
1053     *
1054     * @return void
1055     */
1056    initialize: function () {
1057        if ($('#pma_bookmarks').length === 0) {
1058            return;
1059        }
1060        $('#pma_console').find('.button.bookmarks').click(function () {
1061            PMA_console.showCard('#pma_bookmarks');
1062        });
1063        $('#pma_bookmarks').find('.button.add').click(function () {
1064            PMA_console.showCard('#pma_bookmarks .card.add');
1065        });
1066        $('#pma_bookmarks').find('.card.add [name=submit]').click(function () {
1067            if ($('#pma_bookmarks').find('.card.add [name=label]').val().length === 0
1068                || PMA_consoleInput.getText('bookmark').length === 0) {
1069                alert(PMA_messages.strFormEmpty);
1070                return;
1071            }
1072            $(this).prop('disabled', true);
1073            $.post('import.php',
1074                {
1075                    ajax_request: true,
1076                    console_bookmark_add: 'true',
1077                    label: $('#pma_bookmarks').find('.card.add [name=label]').val(),
1078                    server: PMA_commonParams.get('server'),
1079                    db: $('#pma_bookmarks').find('.card.add [name=targetdb]').val(),
1080                    bookmark_query: PMA_consoleInput.getText('bookmark'),
1081                    shared: $('#pma_bookmarks').find('.card.add [name=shared]').prop('checked') },
1082                function () {
1083                    PMA_consoleBookmarks.refresh();
1084                    $('#pma_bookmarks').find('.card.add [name=submit]').prop('disabled', false);
1085                    PMA_console.hideCard($('#pma_bookmarks').find('.card.add'));
1086                });
1087        });
1088        $('#pma_console').find('.button.refresh').click(function () {
1089            PMA_consoleBookmarks.refresh();
1090        });
1091    }
1092};
1093
1094var PMA_consoleDebug;
1095PMA_consoleDebug = {
1096    _config: {
1097        groupQueries: false,
1098        orderBy: 'exec', // Possible 'exec' => Execution order, 'time' => Time taken, 'count'
1099        order: 'asc' // Possible 'asc', 'desc'
1100    },
1101    _lastDebugInfo: {
1102        debugInfo: null,
1103        url: null
1104    },
1105    initialize: function () {
1106        // Try to get debug info after every AJAX request
1107        $(document).ajaxSuccess(function (event, xhr, settings, data) {
1108            if (data._debug) {
1109                PMA_consoleDebug.showLog(data._debug, settings.url);
1110            }
1111        });
1112
1113        if (PMA_console.config.GroupQueries) {
1114            $('#debug_console').addClass('grouped');
1115        } else {
1116            $('#debug_console').addClass('ungrouped');
1117            if (PMA_console.config.OrderBy === 'count') {
1118                $('#debug_console').find('.button.order_by.sort_exec').addClass('active');
1119            }
1120        }
1121        var orderBy = PMA_console.config.OrderBy;
1122        var order = PMA_console.config.Order;
1123        $('#debug_console').find('.button.order_by.sort_' + orderBy).addClass('active');
1124        $('#debug_console').find('.button.order.order_' + order).addClass('active');
1125
1126        // Initialize actions in toolbar
1127        $('#debug_console').find('.button.group_queries').click(function () {
1128            $('#debug_console').addClass('grouped');
1129            $('#debug_console').removeClass('ungrouped');
1130            PMA_console.setConfig('GroupQueries', true);
1131            PMA_consoleDebug.refresh();
1132            if (PMA_console.config.OrderBy === 'count') {
1133                $('#debug_console').find('.button.order_by.sort_exec').removeClass('active');
1134            }
1135        });
1136        $('#debug_console').find('.button.ungroup_queries').click(function () {
1137            $('#debug_console').addClass('ungrouped');
1138            $('#debug_console').removeClass('grouped');
1139            PMA_console.setConfig('GroupQueries', false);
1140            PMA_consoleDebug.refresh();
1141            if (PMA_console.config.OrderBy === 'count') {
1142                $('#debug_console').find('.button.order_by.sort_exec').addClass('active');
1143            }
1144        });
1145        $('#debug_console').find('.button.order_by').click(function () {
1146            var $this = $(this);
1147            $('#debug_console').find('.button.order_by').removeClass('active');
1148            $this.addClass('active');
1149            if ($this.hasClass('sort_time')) {
1150                PMA_console.setConfig('OrderBy', 'time');
1151            } else if ($this.hasClass('sort_exec')) {
1152                PMA_console.setConfig('OrderBy', 'exec');
1153            } else if ($this.hasClass('sort_count')) {
1154                PMA_console.setConfig('OrderBy', 'count');
1155            }
1156            PMA_consoleDebug.refresh();
1157        });
1158        $('#debug_console').find('.button.order').click(function () {
1159            var $this = $(this);
1160            $('#debug_console').find('.button.order').removeClass('active');
1161            $this.addClass('active');
1162            if ($this.hasClass('order_asc')) {
1163                PMA_console.setConfig('Order', 'asc');
1164            } else if ($this.hasClass('order_desc')) {
1165                PMA_console.setConfig('Order', 'desc');
1166            }
1167            PMA_consoleDebug.refresh();
1168        });
1169
1170        // Show SQL debug info for first page load
1171        if (typeof debugSQLInfo !== 'undefined' && debugSQLInfo !== 'null') {
1172            $('#pma_console').find('.button.debug').removeClass('hide');
1173        } else {
1174            return;
1175        }
1176        PMA_consoleDebug.showLog(debugSQLInfo);
1177    },
1178    _formatFunctionCall: function (dbgStep) {
1179        var functionName = '';
1180        if ('class' in dbgStep) {
1181            functionName += dbgStep.class;
1182            functionName += dbgStep.type;
1183        }
1184        functionName += dbgStep.function;
1185        if (dbgStep.args && dbgStep.args.length) {
1186            functionName += '(...)';
1187        } else {
1188            functionName += '()';
1189        }
1190        return functionName;
1191    },
1192    _formatFunctionArgs: function (dbgStep) {
1193        var $args = $('<div>');
1194        if (dbgStep.args.length) {
1195            $args.append('<div class="message welcome">')
1196                .append(
1197                    $('<div class="message welcome">')
1198                        .text(
1199                            PMA_sprintf(
1200                                PMA_messages.strConsoleDebugArgsSummary,
1201                                dbgStep.args.length
1202                            )
1203                        )
1204                );
1205            for (var i = 0; i < dbgStep.args.length; i++) {
1206                $args.append(
1207                    $('<div class="message">')
1208                        .html(
1209                            '<pre>' +
1210                        escapeHtml(JSON.stringify(dbgStep.args[i], null, '  ')) +
1211                        '</pre>'
1212                        )
1213                );
1214            }
1215        }
1216        return $args;
1217    },
1218    _formatFileName: function (dbgStep) {
1219        var fileName = '';
1220        if ('file' in dbgStep) {
1221            fileName += dbgStep.file;
1222            fileName += '#' + dbgStep.line;
1223        }
1224        return fileName;
1225    },
1226    _formatBackTrace: function (dbgTrace) {
1227        var $traceElem = $('<div class="trace">');
1228        $traceElem.append(
1229            $('<div class="message welcome">')
1230        );
1231        var step;
1232        var $stepElem;
1233        for (var stepId in dbgTrace) {
1234            if (dbgTrace.hasOwnProperty(stepId)) {
1235                step = dbgTrace[stepId];
1236                if (!Array.isArray(step) && typeof step !== 'object') {
1237                    $stepElem =
1238                        $('<div class="message traceStep collapsed hide_args">')
1239                            .append(
1240                                $('<span>').text(step)
1241                            );
1242                } else {
1243                    if (typeof step.args === 'string' && step.args) {
1244                        step.args = [step.args];
1245                    }
1246                    $stepElem =
1247                        $('<div class="message traceStep collapsed hide_args">')
1248                            .append(
1249                                $('<span class="function">').text(this._formatFunctionCall(step))
1250                            )
1251                            .append(
1252                                $('<span class="file">').text(this._formatFileName(step))
1253                            );
1254                    if (step.args && step.args.length) {
1255                        $stepElem
1256                            .append(
1257                                $('<span class="args">').html(this._formatFunctionArgs(step))
1258                            )
1259                            .prepend(
1260                                $('<div class="action_content">')
1261                                    .append(
1262                                        '<span class="action dbg_show_args">' +
1263                                PMA_messages.strConsoleDebugShowArgs +
1264                                '</span> '
1265                                    )
1266                                    .append(
1267                                        '<span class="action dbg_hide_args">' +
1268                                PMA_messages.strConsoleDebugHideArgs +
1269                                '</span> '
1270                                    )
1271                            );
1272                    }
1273                }
1274                $traceElem.append($stepElem);
1275            }
1276        }
1277        return $traceElem;
1278    },
1279    _formatQueryOrGroup: function (queryInfo, totalTime) {
1280        var grouped;
1281        var queryText;
1282        var queryTime;
1283        var count;
1284        var i;
1285        if (Array.isArray(queryInfo)) {
1286            // It is grouped
1287            grouped = true;
1288
1289            queryText = queryInfo[0].query;
1290
1291            queryTime = 0;
1292            for (i in queryInfo) {
1293                queryTime += queryInfo[i].time;
1294            }
1295
1296            count = queryInfo.length;
1297        } else {
1298            queryText = queryInfo.query;
1299            queryTime = queryInfo.time;
1300        }
1301
1302        var $query = $('<div class="message collapsed hide_trace">')
1303            .append(
1304                $('#debug_console').find('.templates .debug_query').clone()
1305            )
1306            .append(
1307                $('<div class="query">')
1308                    .text(queryText)
1309            )
1310            .data('queryInfo', queryInfo)
1311            .data('totalTime', totalTime);
1312        if (grouped) {
1313            $query.find('.text.count').removeClass('hide');
1314            $query.find('.text.count span').text(count);
1315        }
1316        $query.find('.text.time span').text(queryTime + 's (' + ((queryTime * 100) / totalTime).toFixed(3) + '%)');
1317
1318        return $query;
1319    },
1320    _appendQueryExtraInfo: function (query, $elem) {
1321        if ('error' in query) {
1322            $elem.append(
1323                $('<div>').html(query.error)
1324            );
1325        }
1326        $elem.append(this._formatBackTrace(query.trace));
1327    },
1328    getQueryDetails: function (queryInfo, totalTime, $query) {
1329        if (Array.isArray(queryInfo)) {
1330            var $singleQuery;
1331            for (var i in queryInfo) {
1332                $singleQuery = $('<div class="message welcome trace">')
1333                    .text((parseInt(i) + 1) + '.')
1334                    .append(
1335                        $('<span class="time">').text(
1336                            PMA_messages.strConsoleDebugTimeTaken +
1337                        ' ' + queryInfo[i].time + 's' +
1338                        ' (' + ((queryInfo[i].time * 100) / totalTime).toFixed(3) + '%)'
1339                        )
1340                    );
1341                this._appendQueryExtraInfo(queryInfo[i], $singleQuery);
1342                $query
1343                    .append('<div class="message welcome trace">')
1344                    .append($singleQuery);
1345            }
1346        } else {
1347            this._appendQueryExtraInfo(queryInfo, $query);
1348        }
1349    },
1350    showLog: function (debugInfo, url) {
1351        this._lastDebugInfo.debugInfo = debugInfo;
1352        this._lastDebugInfo.url = url;
1353
1354        $('#debug_console').find('.debugLog').empty();
1355        $('#debug_console').find('.debug>.welcome').empty();
1356
1357        var debugJson = false;
1358        var i;
1359        if (typeof debugInfo === 'object' && 'queries' in debugInfo) {
1360            // Copy it to debugJson, so that it doesn't get changed
1361            if (!('queries' in debugInfo)) {
1362                debugJson = false;
1363            } else {
1364                debugJson = { queries: [] };
1365                for (i in debugInfo.queries) {
1366                    debugJson.queries[i] = debugInfo.queries[i];
1367                }
1368            }
1369        } else if (typeof debugInfo === 'string') {
1370            try {
1371                debugJson = JSON.parse(debugInfo);
1372            } catch (e) {
1373                debugJson = false;
1374            }
1375            if (debugJson && !('queries' in debugJson)) {
1376                debugJson = false;
1377            }
1378        }
1379        if (debugJson === false) {
1380            $('#debug_console').find('.debug>.welcome').text(
1381                PMA_messages.strConsoleDebugError
1382            );
1383            return;
1384        }
1385        var allQueries = debugJson.queries;
1386        var uniqueQueries = {};
1387
1388        var totalExec = allQueries.length;
1389
1390        // Calculate total time and make unique query array
1391        var totalTime = 0;
1392        for (i = 0; i < totalExec; ++i) {
1393            totalTime += allQueries[i].time;
1394            if (!(allQueries[i].hash in uniqueQueries)) {
1395                uniqueQueries[allQueries[i].hash] = [];
1396            }
1397            uniqueQueries[allQueries[i].hash].push(allQueries[i]);
1398        }
1399        // Count total unique queries, convert uniqueQueries to Array
1400        var totalUnique = 0;
1401        var uniqueArray = [];
1402        for (var hash in uniqueQueries) {
1403            if (uniqueQueries.hasOwnProperty(hash)) {
1404                ++totalUnique;
1405                uniqueArray.push(uniqueQueries[hash]);
1406            }
1407        }
1408        uniqueQueries = uniqueArray;
1409        // Show summary
1410        $('#debug_console').find('.debug>.welcome').append(
1411            $('<span class="debug_summary">').text(
1412                PMA_sprintf(
1413                    PMA_messages.strConsoleDebugSummary,
1414                    totalUnique,
1415                    totalExec,
1416                    totalTime
1417                )
1418            )
1419        );
1420        if (url) {
1421            $('#debug_console').find('.debug>.welcome').append(
1422                $('<span class="script_name">').text(url.split('?')[0])
1423            );
1424        }
1425
1426        // For sorting queries
1427        function sortByTime (a, b) {
1428            var order = ((PMA_console.config.Order === 'asc') ? 1 : -1);
1429            if (Array.isArray(a) && Array.isArray(b)) {
1430                // It is grouped
1431                var timeA = 0;
1432                var timeB = 0;
1433                var i;
1434                for (i in a) {
1435                    timeA += a[i].time;
1436                }
1437                for (i in b) {
1438                    timeB += b[i].time;
1439                }
1440                return (timeA - timeB) * order;
1441            } else {
1442                return (a.time - b.time) * order;
1443            }
1444        }
1445
1446        function sortByCount (a, b) {
1447            var order = ((PMA_console.config.Oorder === 'asc') ? 1 : -1);
1448            return (a.length - b.length) * order;
1449        }
1450
1451        var orderBy = PMA_console.config.OrderBy;
1452        var order = PMA_console.config.Order;
1453
1454        if (PMA_console.config.GroupQueries) {
1455            // Sort queries
1456            if (orderBy === 'time') {
1457                uniqueQueries.sort(sortByTime);
1458            } else if (orderBy === 'count') {
1459                uniqueQueries.sort(sortByCount);
1460            } else if (orderBy === 'exec' && order === 'desc') {
1461                uniqueQueries.reverse();
1462            }
1463            for (i in uniqueQueries) {
1464                if (orderBy === 'time') {
1465                    uniqueQueries[i].sort(sortByTime);
1466                } else if (orderBy === 'exec' && order === 'desc') {
1467                    uniqueQueries[i].reverse();
1468                }
1469                $('#debug_console').find('.debugLog').append(this._formatQueryOrGroup(uniqueQueries[i], totalTime));
1470            }
1471        } else {
1472            if (orderBy === 'time') {
1473                allQueries.sort(sortByTime);
1474            } else if (order === 'desc') {
1475                allQueries.reverse();
1476            }
1477            for (i = 0; i < totalExec; ++i) {
1478                $('#debug_console').find('.debugLog').append(this._formatQueryOrGroup(allQueries[i], totalTime));
1479            }
1480        }
1481
1482        PMA_consoleMessages._msgEventBinds($('#debug_console').find('.message:not(.binded)'));
1483    },
1484    refresh: function () {
1485        var last = this._lastDebugInfo;
1486        PMA_consoleDebug.showLog(last.debugInfo, last.url);
1487    }
1488};
1489
1490/** s
1491 * Executed on page load
1492 */
1493$(function () {
1494    PMA_console.initialize();
1495});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.