Completed
Push — master ( 64741e...904a1b )
by Maurício
09:11
created

js/console.js (4 issues)

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
 */
11
var 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').on('click', PMA_console.toggle);
114
115
            $('#pma_console').find('.toolbar').children().on('mousedown', function (event) {
116
                event.preventDefault();
117
                event.stopImmediatePropagation();
118
            });
119
120
            $('#pma_console').find('.button.clear').on('click', function () {
121
                PMA_consoleMessages.clear();
122
            });
123
124
            $('#pma_console').find('.button.history').on('click', function () {
125
                PMA_consoleMessages.showHistory();
126
            });
127
128
            $('#pma_console').find('.button.options').on('click', function () {
129
                PMA_console.showCard('#pma_console_options');
130
            });
131
132
            $('#pma_console').find('.button.debug').on('click', function () {
133
                PMA_console.showCard('#debug_console');
134
            });
135
136
            PMA_console.$consoleContent.on('click', function (event) {
137
                if (event.target === this) {
138
                    PMA_consoleInput.focus();
139
                }
140
            });
141
142
            $('#pma_console').find('.mid_layer').on('click', function () {
143
                PMA_console.hideCard($(this).parent().children('.card'));
144
            });
145
            $('#debug_console').find('.switch_button').on('click', function () {
146
                PMA_console.hideCard($(this).closest('.card'));
147
            });
148
            $('#pma_bookmarks').find('.switch_button').on('click', function () {
149
                PMA_console.hideCard($(this).closest('.card'));
150
            });
151
            $('#pma_console_options').find('.switch_button').on('click', function () {
152
                PMA_console.hideCard($(this).closest('.card'));
153
            });
154
155
            $('#pma_console_options').find('input[type=checkbox]').on('change', function () {
156
                PMA_console.updateConfig();
157
            });
158
159
            $('#pma_console_options').find('.button.default').on('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]').on('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
 */
415
var 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').on('mousedown', PMA_consoleResizer._mousedown);
482
    }
483
};
484
485
486
/**
487
 * Console input object
488
 */
489
var 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').on('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
 */
735
var 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').trigger('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').on('click', function () {
867
            $(this).closest('.message').removeClass('collapsed');
868
            $(this).closest('.message').addClass('expanded');
869
        });
870
        $targetMessage.find('.action.collapse').on('click', function () {
871
            $(this).closest('.message').addClass('collapsed');
872
            $(this).closest('.message').removeClass('expanded');
873
        });
874
        $targetMessage.find('.action.edit').on('click', function () {
875
            PMA_consoleInput.setText($(this).parent().siblings('.query').text());
876
            PMA_consoleInput.focus();
877
        });
878
        $targetMessage.find('.action.requery').on('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').on('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').on('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').on('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').on('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').on('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').on('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').on('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').on('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').on('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
 */
1016
var 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);
0 ignored issues
show
Expected a 'break' statement before 'case'.
Loading history...
1028
        case 3:
1029
            $('#pma_bookmarks').find('.add [name=label]').val(label);
0 ignored issues
show
Expected a 'break' statement before 'case'.
Loading history...
1030
        case 2:
1031
            $('#pma_bookmarks').find('.add [name=targetdb]').val(targetDb);
0 ignored issues
show
Expected a 'break' statement before 'case'.
Loading history...
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').on('click', function () {
1061
            PMA_console.showCard('#pma_bookmarks');
1062
        });
1063
        $('#pma_bookmarks').find('.button.add').on('click', function () {
1064
            PMA_console.showCard('#pma_bookmarks .card.add');
1065
        });
1066
        $('#pma_bookmarks').find('.card.add [name=submit]').on('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').on('click', function () {
1089
            PMA_consoleBookmarks.refresh();
1090
        });
1091
    }
1092
};
1093
1094
var PMA_consoleDebug;
0 ignored issues
show
'PMA_consoleDebug' was used before it was defined.
Loading history...
1095
PMA_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').on('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').on('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').on('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').on('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
});
1496