From d864545988cb354f7a0ade8f2f0f470907e8a94c Mon Sep 17 00:00:00 2001 From: Owen Leonard Date: Fri, 5 Feb 2021 18:14:55 +0000 Subject: [PATCH] Bug 27643: Add CodeMirror custom syntax highlighting for SQL runtime parameters This patch adds some additional configuration to CodeMirror so that runtime parameters have a distinct color in the CodeMirror SQL editor. To test, apply the patch and create or edit an SQL report which contains one or more runtime parameters, e.g. <>, <>, etc. Confirm that when editing the SQL, these parameters should appear as green text. Save your report and view it. The syntax highlighting should be updated in this view too. --- koha-tmpl/intranet-tmpl/lib/codemirror/overlay.js | 90 ++++++++++++++++++++++ .../intranet-tmpl/lib/codemirror/overlay.min.js | 1 + .../en/modules/reports/guided_reports_start.tt | 30 +++++++- 3 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/lib/codemirror/overlay.js create mode 100644 koha-tmpl/intranet-tmpl/lib/codemirror/overlay.min.js diff --git a/koha-tmpl/intranet-tmpl/lib/codemirror/overlay.js b/koha-tmpl/intranet-tmpl/lib/codemirror/overlay.js new file mode 100644 index 0000000000..839d9e552e --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/codemirror/overlay.js @@ -0,0 +1,90 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Utility function that allows modes to be combined. The mode given +// as the base argument takes care of most of the normal mode +// functionality, but a second (typically simple) mode is used, which +// can override the style of text. Both modes get to parse all of the +// text, but when both assign a non-null style to a piece of code, the +// overlay wins, unless the combine argument was true and not overridden, +// or state.overlay.combineTokens was true, in which case the styles are +// combined. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.overlayMode = function(base, overlay, combine) { + return { + startState: function() { + return { + base: CodeMirror.startState(base), + overlay: CodeMirror.startState(overlay), + basePos: 0, baseCur: null, + overlayPos: 0, overlayCur: null, + streamSeen: null + }; + }, + copyState: function(state) { + return { + base: CodeMirror.copyState(base, state.base), + overlay: CodeMirror.copyState(overlay, state.overlay), + basePos: state.basePos, baseCur: null, + overlayPos: state.overlayPos, overlayCur: null + }; + }, + + token: function(stream, state) { + if (stream != state.streamSeen || + Math.min(state.basePos, state.overlayPos) < stream.start) { + state.streamSeen = stream; + state.basePos = state.overlayPos = stream.start; + } + + if (stream.start == state.basePos) { + state.baseCur = base.token(stream, state.base); + state.basePos = stream.pos; + } + if (stream.start == state.overlayPos) { + stream.pos = stream.start; + state.overlayCur = overlay.token(stream, state.overlay); + state.overlayPos = stream.pos; + } + stream.pos = Math.min(state.basePos, state.overlayPos); + + // state.overlay.combineTokens always takes precedence over combine, + // unless set to null + if (state.overlayCur == null) return state.baseCur; + else if (state.baseCur != null && + state.overlay.combineTokens || + combine && state.overlay.combineTokens == null) + return state.baseCur + " " + state.overlayCur; + else return state.overlayCur; + }, + + indent: base.indent && function(state, textAfter) { + return base.indent(state.base, textAfter); + }, + electricChars: base.electricChars, + + innerMode: function(state) { return {state: state.base, mode: base}; }, + + blankLine: function(state) { + var baseToken, overlayToken; + if (base.blankLine) baseToken = base.blankLine(state.base); + if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay); + + return overlayToken == null ? + baseToken : + (combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken); + } + }; +}; + +}); diff --git a/koha-tmpl/intranet-tmpl/lib/codemirror/overlay.min.js b/koha-tmpl/intranet-tmpl/lib/codemirror/overlay.min.js new file mode 100644 index 0000000000..6e0f9b3466 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/codemirror/overlay.min.js @@ -0,0 +1 @@ +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.overlayMode=function(o,r,a){return{startState:function(){return{base:e.startState(o),overlay:e.startState(r),basePos:0,baseCur:null,overlayPos:0,overlayCur:null,streamSeen:null}},copyState:function(a){return{base:e.copyState(o,a.base),overlay:e.copyState(r,a.overlay),basePos:a.basePos,baseCur:null,overlayPos:a.overlayPos,overlayCur:null}},token:function(e,n){return(e!=n.streamSeen||Math.min(n.basePos,n.overlayPos) [% Asset.css("css/reports.css") | $raw %] @@ -1287,7 +1290,7 @@ [% INCLUDE 'guided-reports-view.inc' %] - + [% MACRO jsinclude BLOCK %] [% Asset.js("js/charts.js") | $raw %] @@ -1299,6 +1302,7 @@ [% INCLUDE 'columns_settings.inc' %] [% END %] [% Asset.js( "lib/codemirror/codemirror.min.js" ) | $raw %] + [% Asset.js( "lib/codemirror/overlay.min.js" ) | $raw %] [% Asset.js( "lib/codemirror/sql.min.js" ) | $raw %] [% Asset.js( "js/mana.js" ) | $raw %]