From e03449460ab1d343b4ac1d838fdf53354bb2d054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 21 May 2013 10:01:57 +0200 Subject: [PATCH 1/7] Highlight SQL using CodeMirror --- js/codemirror/addon/runmode/colorize.js | 29 +++++++++++++ js/codemirror/addon/runmode/runmode.js | 56 +++++++++++++++++++++++++ js/functions.js | 4 ++ libraries/Header.class.php | 2 + 4 files changed, 91 insertions(+) create mode 100644 js/codemirror/addon/runmode/colorize.js create mode 100644 js/codemirror/addon/runmode/runmode.js diff --git a/js/codemirror/addon/runmode/colorize.js b/js/codemirror/addon/runmode/colorize.js new file mode 100644 index 0000000000..62286d21e4 --- /dev/null +++ b/js/codemirror/addon/runmode/colorize.js @@ -0,0 +1,29 @@ +CodeMirror.colorize = (function() { + + var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; + + function textContent(node, out) { + if (node.nodeType == 3) return out.push(node.nodeValue); + for (var ch = node.firstChild; ch; ch = ch.nextSibling) { + textContent(ch, out); + if (isBlock.test(node.nodeType)) out.push("\n"); + } + } + + return function(collection, defaultMode) { + if (!collection) collection = document.body.getElementsByTagName("pre"); + + for (var i = 0; i < collection.length; ++i) { + var node = collection[i]; + var mode = node.getAttribute("data-lang") || defaultMode; + if (!mode) continue; + + var text = []; + textContent(node, text); + node.innerHTML = ""; + CodeMirror.runMode(text.join(""), mode, node); + + node.className += " cm-s-default"; + } + }; +})(); diff --git a/js/codemirror/addon/runmode/runmode.js b/js/codemirror/addon/runmode/runmode.js new file mode 100644 index 0000000000..a7da6d718f --- /dev/null +++ b/js/codemirror/addon/runmode/runmode.js @@ -0,0 +1,56 @@ +CodeMirror.runMode = function(string, modespec, callback, options) { + var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); + var ie = /MSIE \d/.test(navigator.userAgent); + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); + + if (callback.nodeType == 1) { + var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function(text, style) { + if (text == "\n") { + // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. + // Emitting a carriage return makes everything ok. + node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0;;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start); + stream.start = stream.pos; + } + } +}; diff --git a/js/functions.js b/js/functions.js index de254e6717..f680b35cd0 100644 --- a/js/functions.js +++ b/js/functions.js @@ -3446,6 +3446,10 @@ AJAX.registerOnload('functions.js', function () { $elm.focus().bind('keydown', catchKeypressesFromSqlTextboxes); } } + $elm = $('code.sql'); + if ($elm.length > 0) { + CodeMirror.colorize($elm, 'text/x-mysql'); + } }); AJAX.registerTeardown('functions.js', function () { if (codemirror_editor) { diff --git a/libraries/Header.class.php b/libraries/Header.class.php index 9599f47d06..4136288e46 100644 --- a/libraries/Header.class.php +++ b/libraries/Header.class.php @@ -356,6 +356,8 @@ class PMA_Header if ($GLOBALS['cfg']['CodemirrorEnable']) { $this->_scripts->addFile('codemirror/lib/codemirror.js'); $this->_scripts->addFile('codemirror/mode/sql/sql.js'); + $this->_scripts->addFile('codemirror/addon/runmode/runmode.js'); + $this->_scripts->addFile('codemirror/addon/runmode/colorize.js'); } if ($this->_userprefsOfferImport) { $this->_scripts->addFile('config.js'); From 31cfc4e34e553dfedfa0b48ea2460b5640d95254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 22 May 2013 15:45:58 +0200 Subject: [PATCH 2/7] Hook SQL highlighter to more places Unfortunately there are quite many places where SQL query might appear, hopefully I've made it correctly. --- js/ajax.js | 4 +++- js/functions.js | 32 ++++++++++++++++++++++++++++---- js/indexes.js | 1 + js/server_privileges.js | 5 +++++ js/sql.js | 1 + js/tbl_select.js | 1 + js/tbl_structure.js | 5 +++++ 7 files changed, 44 insertions(+), 5 deletions(-) diff --git a/js/ajax.js b/js/ajax.js index 3c13151975..f43a2d0977 100644 --- a/js/ajax.js +++ b/js/ajax.js @@ -136,7 +136,7 @@ var AJAX = { return true; } else if (href && href.match(/^mailto/)) { return true; - } else if ($(this).hasClass('ui-datepicker-next') || + } else if ($(this).hasClass('ui-datepicker-next') || $(this).hasClass('ui-datepicker-prev') ) { return true; @@ -255,6 +255,7 @@ var AJAX = { $('#page_content').replaceWith( "
" + data.message + "
" ); + PMA_highlightSQL($('#page_content')); } if (data._selflink) { @@ -277,6 +278,7 @@ var AJAX = { } if (data._displayMessage) { $('#page_content').prepend(data._displayMessage); + PMA_highlightSQL($('#page_content')); } $('#pma_errors').remove(); diff --git a/js/functions.js b/js/functions.js index f680b35cd0..efde26fc5d 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1486,6 +1486,25 @@ function catchKeypressesFromSqlTextboxes(event) { } } +/** + * Higlights SQL using CodeMirror. + */ +function PMA_highlightSQL(base) +{ + var $elm = base.find('code.sql'); + $elm.each(function () { + var $sql = $(this); + /* We only care about visible elements to avoid double processing */ + if ($sql.is(":visible")) { + var $highlight = $('
'); + $sql.append($highlight); + console.log('Highlight SQL: ' + $sql.text()); + CodeMirror.runMode($sql.text(), 'text/x-mysql', $highlight[0]); + $sql.find('pre').hide(); + } + }); +} + /** * Show a message on the top of the page for an Ajax request * @@ -1597,6 +1616,7 @@ function PMA_ajaxShowMessage(message, timeout) PMA_messages.strDismiss ); } + PMA_highlightSQL($retval); return $retval; } @@ -2109,6 +2129,7 @@ AJAX.registerOnload('functions.js', function () { $.post($form.attr('action'), $form.serialize() + "&submit_num_fields=1", function (data) { if (data.success) { $("#page_content").html(data.message); + PMA_highlightSQL($('#page_content')); PMA_verifyColumnsProperties(); PMA_ajaxRemoveMessage($msgbox); } else { @@ -2217,6 +2238,7 @@ AJAX.registerOnload('functions.js', function () { PMA_commonParams.set('table', tbl); PMA_commonActions.refreshMain(false, function () { $('#page_content').html(data.message); + PMA_highlightSQL($('#page_content')); }); } else { PMA_ajaxShowMessage(data.error, false); @@ -2247,6 +2269,7 @@ AJAX.registerOnload('functions.js', function () { PMA_ajaxShowMessage(data.message); $("
").prependTo("#page_content"); $("#sqlqueryresults").html(data.sql_query); + PMA_highlightSQL($('#page_content')); scrollToTop(); } else if (data.success === true) { var $temp_div = $("
"); @@ -2255,6 +2278,7 @@ AJAX.registerOnload('functions.js', function () { PMA_ajaxShowMessage($success); $("
").prependTo("#page_content"); $("#sqlqueryresults").html(data.message); + PMA_highlightSQL($('#page_content')); PMA_init_slider(); $("#sqlqueryresults").children("fieldset,br").remove(); scrollToTop(); @@ -2399,6 +2423,7 @@ AJAX.registerOnload('functions.js', function () { $.post($the_form.attr('action'), $the_form.serialize() + '&change_pw=' + this_value, function (data) { if (data.success === true) { $("#page_content").prepend(data.message); + PMA_highlightSQL($('#page_content')); $("#change_password_dialog").hide().remove(); $("#edit_user_dialog").dialog("close").remove(); PMA_ajaxRemoveMessage($msgbox); @@ -2809,6 +2834,7 @@ function indexEditorDialog(url, title, callback_success, callback_failure) $('
') .html(data.sql_query) .prependTo('#page_content'); + PMA_highlightSQL($('#page_content')); } $("#result_query .notice").remove(); $("#result_query").prepend(data.message); @@ -3413,6 +3439,7 @@ AJAX.registerOnload('functions.js', function () { PMA_ajaxShowMessage(data.message); $("
").prependTo("#page_content"); $("#sqlqueryresults").html(data.sql_query); + PMA_highlightSQL($('#page_content')); } else { PMA_ajaxShowMessage(data.error, false); } @@ -3446,10 +3473,7 @@ AJAX.registerOnload('functions.js', function () { $elm.focus().bind('keydown', catchKeypressesFromSqlTextboxes); } } - $elm = $('code.sql'); - if ($elm.length > 0) { - CodeMirror.colorize($elm, 'text/x-mysql'); - } + PMA_highlightSQL($('body')); }); AJAX.registerTeardown('functions.js', function () { if (codemirror_editor) { diff --git a/js/indexes.js b/js/indexes.js index 919afe0011..b016f19463 100644 --- a/js/indexes.js +++ b/js/indexes.js @@ -159,6 +159,7 @@ AJAX.registerOnload('indexes.js', function () { $('
') .html(data.sql_query) .prependTo('#page_content'); + PMA_highlightSQL($('#page_content')); } PMA_commonActions.refreshMain(false, function () { $("a.ajax[href^=#indexes]").click(); diff --git a/js/server_privileges.js b/js/server_privileges.js index 9da401a922..8a643c7625 100644 --- a/js/server_privileges.js +++ b/js/server_privileges.js @@ -101,6 +101,7 @@ function addUser($form) PMA_ajaxShowMessage(data.message); $("#result_query").remove(); $('#page_content').prepend(data.sql_query); + PMA_highlightSQL($('#page_content')); $("#result_query").css({ 'margin-top' : '0.5em' }); @@ -234,6 +235,7 @@ AJAX.registerOnload('server_privileges.js', function () { .find("form[name=usersForm]") .append('') .end(); + PMA_highlightSQL($div); displayPasswordGenerateButton(); PMA_showHints($div); PMA_ajaxRemoveMessage($msgbox); @@ -361,6 +363,8 @@ AJAX.registerOnload('server_privileges.js', function () { $div.empty(); } $div.html(data.message); + PMA_highlightSQL($div); + var $div = $('#edit_user_dialog'); displayPasswordGenerateButton(); $(checkboxes_sel).trigger("change"); PMA_ajaxRemoveMessage($msgbox); @@ -430,6 +434,7 @@ AJAX.registerOnload('server_privileges.js', function () { if (data.sql_query) { $("#result_query").remove(); $('#page_content').prepend(data.sql_query); + PMA_highlightSQL($('#page_content')); $("#result_query").css({ 'margin-top' : '0.5em' }); diff --git a/js/sql.js b/js/sql.js index cdf06690d3..aeb681a708 100644 --- a/js/sql.js +++ b/js/sql.js @@ -304,6 +304,7 @@ AJAX.registerOnload('sql.js', function () { $('
') .html(data.sql_query) .prependTo('#page_content'); + PMA_highlightSQL($('#page_content')); } }); PMA_reloadNavigation(); diff --git a/js/tbl_select.js b/js/tbl_select.js index 742e17fb25..7df822864a 100644 --- a/js/tbl_select.js +++ b/js/tbl_select.js @@ -128,6 +128,7 @@ AJAX.registerOnload('tbl_select.js', function () { } else { $("#sqlqueryresults").html(data.error); } + PMA_highlightSQL($('#sqlqueryresults')); }); // end $.post() }); diff --git a/js/tbl_structure.js b/js/tbl_structure.js index 5f20efce79..9ea8d5f1bf 100644 --- a/js/tbl_structure.js +++ b/js/tbl_structure.js @@ -85,6 +85,7 @@ AJAX.registerOnload('tbl_structure.js', function () { .append(data.message) .append(data.sql_query) .show(); + PMA_highlightSQL($('#page_content')); $("#result_query .notice").remove(); $form.remove(); PMA_ajaxRemoveMessage($msg); @@ -109,6 +110,7 @@ AJAX.registerOnload('tbl_structure.js', function () { $('
') .html(data.message) .insertBefore('#page_content'); + PMA_highlightSQL($('#page_content')); PMA_verifyColumnsProperties(); } else { PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + " : " + data.error, false); @@ -135,6 +137,7 @@ AJAX.registerOnload('tbl_structure.js', function () { .html(data.message) ) .show(); + PMA_highlightSQL($('#page_content')); PMA_verifyColumnsProperties(); } else { $('#page_content').show(); @@ -180,6 +183,7 @@ AJAX.registerOnload('tbl_structure.js', function () { $('
') .html(data.sql_query) .prependTo('#page_content'); + PMA_highlightSQL($('#page_content')); } toggleRowColors($curr_row.next()); // Adjust the row numbers @@ -235,6 +239,7 @@ AJAX.registerOnload('tbl_structure.js', function () { $('
') .html(data.sql_query) .prependTo('#page_content'); + PMA_highlightSQL($('#page_content')); } }); PMA_reloadNavigation(); From ee70ebd10a55d4045ad7b9b2d62827112adcbbcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 22 May 2013 15:51:36 +0200 Subject: [PATCH 3/7] Fixed highlight interactions with inline editor --- js/functions.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/js/functions.js b/js/functions.js index efde26fc5d..c3a9c1ea87 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1352,6 +1352,7 @@ AJAX.registerOnload('functions.js', function () { var $form = $(this).prev('form'); var sql_query = $form.find("input[name='sql_query']").val(); var $inner_sql = $(this).parent().prev().find('.inner_sql'); + var $sql_highlight = $(this).parent().prev().find('.sql-highlight'); var old_text = $inner_sql.html(); var new_content = "\n"; @@ -1364,6 +1365,7 @@ AJAX.registerOnload('functions.js', function () { } $editor_area.html(new_content); $inner_sql.hide(); + $sql_highlight.hide(); bindCodeMirrorToInlineEditor(); return false; @@ -1387,8 +1389,8 @@ AJAX.registerOnload('functions.js', function () { $("input#sql_query_edit_discard").live('click', function () { $('div#inline_editor_outer') - .empty() - .siblings('.inner_sql').show(); + .siblings('.sql-highlight').show(); + $('div#inline_editor_outer').remove(); }); $('input.sqlbutton').click(function (evt) { @@ -1496,7 +1498,7 @@ function PMA_highlightSQL(base) var $sql = $(this); /* We only care about visible elements to avoid double processing */ if ($sql.is(":visible")) { - var $highlight = $('
'); + var $highlight = $('
'); $sql.append($highlight); console.log('Highlight SQL: ' + $sql.text()); CodeMirror.runMode($sql.text(), 'text/x-mysql', $highlight[0]); From 1c0eb2a467d4613fc4460ebdb032423acbd461b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 21 May 2013 10:03:00 +0200 Subject: [PATCH 4/7] Default to none PHP highlighting --- libraries/config.default.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/config.default.php b/libraries/config.default.php index abe1957073..b55d1486b0 100644 --- a/libraries/config.default.php +++ b/libraries/config.default.php @@ -2764,7 +2764,7 @@ $cfg['SQP'] = array(); * * @global string $cfg['SQP']['fmtType'] */ -$cfg['SQP']['fmtType'] = 'html'; +$cfg['SQP']['fmtType'] = 'none'; /** * Amount to indent each level (floats are valid) From ec052d1d10e260901805097e341ea438b3560597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Fri, 24 May 2013 10:03:11 +0200 Subject: [PATCH 5/7] Correctly detect already performed highlighting --- js/functions.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/functions.js b/js/functions.js index c3a9c1ea87..7fdbefe5b6 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1496,13 +1496,14 @@ function PMA_highlightSQL(base) var $elm = base.find('code.sql'); $elm.each(function () { var $sql = $(this); + var $pre = $sql.find('pre'); /* We only care about visible elements to avoid double processing */ - if ($sql.is(":visible")) { + if ($pre.is(":visible")) { var $highlight = $('
'); $sql.append($highlight); console.log('Highlight SQL: ' + $sql.text()); CodeMirror.runMode($sql.text(), 'text/x-mysql', $highlight[0]); - $sql.find('pre').hide(); + $pre.hide(); } }); } From 8c5daeeb38b5cd25263d770edc49b6ae440dc971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Fri, 24 May 2013 10:03:50 +0200 Subject: [PATCH 6/7] Drop console.log --- js/functions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/functions.js b/js/functions.js index 7fdbefe5b6..0e45e4a5af 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1501,7 +1501,6 @@ function PMA_highlightSQL(base) if ($pre.is(":visible")) { var $highlight = $('
'); $sql.append($highlight); - console.log('Highlight SQL: ' + $sql.text()); CodeMirror.runMode($sql.text(), 'text/x-mysql', $highlight[0]); $pre.hide(); } From 2af13548dae4cccbb27908a3dbc1c429102d8ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Fri, 24 May 2013 10:06:53 +0200 Subject: [PATCH 7/7] Drop not used colorize addon --- js/codemirror/addon/runmode/colorize.js | 29 ------------------------- libraries/Header.class.php | 1 - 2 files changed, 30 deletions(-) delete mode 100644 js/codemirror/addon/runmode/colorize.js diff --git a/js/codemirror/addon/runmode/colorize.js b/js/codemirror/addon/runmode/colorize.js deleted file mode 100644 index 62286d21e4..0000000000 --- a/js/codemirror/addon/runmode/colorize.js +++ /dev/null @@ -1,29 +0,0 @@ -CodeMirror.colorize = (function() { - - var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; - - function textContent(node, out) { - if (node.nodeType == 3) return out.push(node.nodeValue); - for (var ch = node.firstChild; ch; ch = ch.nextSibling) { - textContent(ch, out); - if (isBlock.test(node.nodeType)) out.push("\n"); - } - } - - return function(collection, defaultMode) { - if (!collection) collection = document.body.getElementsByTagName("pre"); - - for (var i = 0; i < collection.length; ++i) { - var node = collection[i]; - var mode = node.getAttribute("data-lang") || defaultMode; - if (!mode) continue; - - var text = []; - textContent(node, text); - node.innerHTML = ""; - CodeMirror.runMode(text.join(""), mode, node); - - node.className += " cm-s-default"; - } - }; -})(); diff --git a/libraries/Header.class.php b/libraries/Header.class.php index 4136288e46..b833d2c99c 100644 --- a/libraries/Header.class.php +++ b/libraries/Header.class.php @@ -357,7 +357,6 @@ class PMA_Header $this->_scripts->addFile('codemirror/lib/codemirror.js'); $this->_scripts->addFile('codemirror/mode/sql/sql.js'); $this->_scripts->addFile('codemirror/addon/runmode/runmode.js'); - $this->_scripts->addFile('codemirror/addon/runmode/colorize.js'); } if ($this->_userprefsOfferImport) { $this->_scripts->addFile('config.js');