Custom CSS and Javascript - Version 2.0.9

Version Description

  • Added search functionality to code editor
  • Added bracket matching to code editor
Download this release

Release Info

Developer hearken
Plugin Icon 128x128 Custom CSS and Javascript
Version 2.0.9
Comparing to
See all releases

Code changes from version 2.0.8 to 2.0.9

codemirror/addon/dialog/dialog.css ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .CodeMirror-dialog {
2
+ position: absolute;
3
+ left: 0; right: 0;
4
+ background: inherit;
5
+ z-index: 15;
6
+ padding: .1em .8em;
7
+ overflow: hidden;
8
+ color: inherit;
9
+ }
10
+
11
+ .CodeMirror-dialog-top {
12
+ border-bottom: 1px solid #eee;
13
+ top: 0;
14
+ }
15
+
16
+ .CodeMirror-dialog-bottom {
17
+ border-top: 1px solid #eee;
18
+ bottom: 0;
19
+ }
20
+
21
+ .CodeMirror-dialog input {
22
+ border: none;
23
+ outline: none;
24
+ background: transparent;
25
+ width: 20em;
26
+ color: inherit;
27
+ font-family: monospace;
28
+ }
29
+
30
+ .CodeMirror-dialog button {
31
+ font-size: 70%;
32
+ }
codemirror/addon/dialog/dialog.js ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Open simple dialogs on top of an editor. Relies on dialog.css.
5
+
6
+ (function(mod) {
7
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
8
+ mod(require("../../lib/codemirror"));
9
+ else if (typeof define == "function" && define.amd) // AMD
10
+ define(["../../lib/codemirror"], mod);
11
+ else // Plain browser env
12
+ mod(CodeMirror);
13
+ })(function(CodeMirror) {
14
+ function dialogDiv(cm, template, bottom) {
15
+ var wrap = cm.getWrapperElement();
16
+ var dialog;
17
+ dialog = wrap.appendChild(document.createElement("div"));
18
+ if (bottom)
19
+ dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
20
+ else
21
+ dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
22
+
23
+ if (typeof template == "string") {
24
+ dialog.innerHTML = template;
25
+ } else { // Assuming it's a detached DOM element.
26
+ dialog.appendChild(template);
27
+ }
28
+ return dialog;
29
+ }
30
+
31
+ function closeNotification(cm, newVal) {
32
+ if (cm.state.currentNotificationClose)
33
+ cm.state.currentNotificationClose();
34
+ cm.state.currentNotificationClose = newVal;
35
+ }
36
+
37
+ CodeMirror.defineExtension("openDialog", function(template, callback, options) {
38
+ if (!options) options = {};
39
+
40
+ closeNotification(this, null);
41
+
42
+ var dialog = dialogDiv(this, template, options.bottom);
43
+ var closed = false, me = this;
44
+ function close(newVal) {
45
+ if (typeof newVal == 'string') {
46
+ inp.value = newVal;
47
+ } else {
48
+ if (closed) return;
49
+ closed = true;
50
+ dialog.parentNode.removeChild(dialog);
51
+ me.focus();
52
+
53
+ if (options.onClose) options.onClose(dialog);
54
+ }
55
+ }
56
+
57
+ var inp = dialog.getElementsByTagName("input")[0], button;
58
+ if (inp) {
59
+ inp.focus();
60
+
61
+ if (options.value) {
62
+ inp.value = options.value;
63
+ if (options.selectValueOnOpen !== false) {
64
+ inp.select();
65
+ }
66
+ }
67
+
68
+ if (options.onInput)
69
+ CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
70
+ if (options.onKeyUp)
71
+ CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
72
+
73
+ CodeMirror.on(inp, "keydown", function(e) {
74
+ if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
75
+ if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
76
+ inp.blur();
77
+ CodeMirror.e_stop(e);
78
+ close();
79
+ }
80
+ if (e.keyCode == 13) callback(inp.value, e);
81
+ });
82
+
83
+ if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
84
+ } else if (button = dialog.getElementsByTagName("button")[0]) {
85
+ CodeMirror.on(button, "click", function() {
86
+ close();
87
+ me.focus();
88
+ });
89
+
90
+ if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
91
+
92
+ button.focus();
93
+ }
94
+ return close;
95
+ });
96
+
97
+ CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
98
+ closeNotification(this, null);
99
+ var dialog = dialogDiv(this, template, options && options.bottom);
100
+ var buttons = dialog.getElementsByTagName("button");
101
+ var closed = false, me = this, blurring = 1;
102
+ function close() {
103
+ if (closed) return;
104
+ closed = true;
105
+ dialog.parentNode.removeChild(dialog);
106
+ me.focus();
107
+ }
108
+ buttons[0].focus();
109
+ for (var i = 0; i < buttons.length; ++i) {
110
+ var b = buttons[i];
111
+ (function(callback) {
112
+ CodeMirror.on(b, "click", function(e) {
113
+ CodeMirror.e_preventDefault(e);
114
+ close();
115
+ if (callback) callback(me);
116
+ });
117
+ })(callbacks[i]);
118
+ CodeMirror.on(b, "blur", function() {
119
+ --blurring;
120
+ setTimeout(function() { if (blurring <= 0) close(); }, 200);
121
+ });
122
+ CodeMirror.on(b, "focus", function() { ++blurring; });
123
+ }
124
+ });
125
+
126
+ /*
127
+ * openNotification
128
+ * Opens a notification, that can be closed with an optional timer
129
+ * (default 5000ms timer) and always closes on click.
130
+ *
131
+ * If a notification is opened while another is opened, it will close the
132
+ * currently opened one and open the new one immediately.
133
+ */
134
+ CodeMirror.defineExtension("openNotification", function(template, options) {
135
+ closeNotification(this, close);
136
+ var dialog = dialogDiv(this, template, options && options.bottom);
137
+ var closed = false, doneTimer;
138
+ var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
139
+
140
+ function close() {
141
+ if (closed) return;
142
+ closed = true;
143
+ clearTimeout(doneTimer);
144
+ dialog.parentNode.removeChild(dialog);
145
+ }
146
+
147
+ CodeMirror.on(dialog, 'click', function(e) {
148
+ CodeMirror.e_preventDefault(e);
149
+ close();
150
+ });
151
+
152
+ if (duration)
153
+ doneTimer = setTimeout(close, duration);
154
+
155
+ return close;
156
+ });
157
+ });
codemirror/addon/edit/matchbrackets.js ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
13
+ (document.documentMode == null || document.documentMode < 8);
14
+
15
+ var Pos = CodeMirror.Pos;
16
+
17
+ var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
18
+
19
+ function findMatchingBracket(cm, where, strict, config) {
20
+ var line = cm.getLineHandle(where.line), pos = where.ch - 1;
21
+ var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
22
+ if (!match) return null;
23
+ var dir = match.charAt(1) == ">" ? 1 : -1;
24
+ if (strict && (dir > 0) != (pos == where.ch)) return null;
25
+ var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
26
+
27
+ var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
28
+ if (found == null) return null;
29
+ return {from: Pos(where.line, pos), to: found && found.pos,
30
+ match: found && found.ch == match.charAt(0), forward: dir > 0};
31
+ }
32
+
33
+ // bracketRegex is used to specify which type of bracket to scan
34
+ // should be a regexp, e.g. /[[\]]/
35
+ //
36
+ // Note: If "where" is on an open bracket, then this bracket is ignored.
37
+ //
38
+ // Returns false when no bracket was found, null when it reached
39
+ // maxScanLines and gave up
40
+ function scanForBracket(cm, where, dir, style, config) {
41
+ var maxScanLen = (config && config.maxScanLineLength) || 10000;
42
+ var maxScanLines = (config && config.maxScanLines) || 1000;
43
+
44
+ var stack = [];
45
+ var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
46
+ var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
47
+ : Math.max(cm.firstLine() - 1, where.line - maxScanLines);
48
+ for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
49
+ var line = cm.getLine(lineNo);
50
+ if (!line) continue;
51
+ var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
52
+ if (line.length > maxScanLen) continue;
53
+ if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
54
+ for (; pos != end; pos += dir) {
55
+ var ch = line.charAt(pos);
56
+ if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
57
+ var match = matching[ch];
58
+ if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
59
+ else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
60
+ else stack.pop();
61
+ }
62
+ }
63
+ }
64
+ return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
65
+ }
66
+
67
+ function matchBrackets(cm, autoclear, config) {
68
+ // Disable brace matching in long lines, since it'll cause hugely slow updates
69
+ var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
70
+ var marks = [], ranges = cm.listSelections();
71
+ for (var i = 0; i < ranges.length; i++) {
72
+ var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
73
+ if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
74
+ var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
75
+ marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
76
+ if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
77
+ marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
78
+ }
79
+ }
80
+
81
+ if (marks.length) {
82
+ // Kludge to work around the IE bug from issue #1193, where text
83
+ // input stops going to the textare whever this fires.
84
+ if (ie_lt8 && cm.state.focused) cm.focus();
85
+
86
+ var clear = function() {
87
+ cm.operation(function() {
88
+ for (var i = 0; i < marks.length; i++) marks[i].clear();
89
+ });
90
+ };
91
+ if (autoclear) setTimeout(clear, 800);
92
+ else return clear;
93
+ }
94
+ }
95
+
96
+ var currentlyHighlighted = null;
97
+ function doMatchBrackets(cm) {
98
+ cm.operation(function() {
99
+ if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
100
+ currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
101
+ });
102
+ }
103
+
104
+ CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
105
+ if (old && old != CodeMirror.Init) {
106
+ cm.off("cursorActivity", doMatchBrackets);
107
+ if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
108
+ }
109
+ if (val) {
110
+ cm.state.matchBrackets = typeof val == "object" ? val : {};
111
+ cm.on("cursorActivity", doMatchBrackets);
112
+ }
113
+ });
114
+
115
+ CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
116
+ CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
117
+ return findMatchingBracket(this, pos, strict, config);
118
+ });
119
+ CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
120
+ return scanForBracket(this, pos, dir, style, config);
121
+ });
122
+ });
codemirror/addon/scroll/annotatescrollbar.js ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineExtension("annotateScrollbar", function(options) {
15
+ if (typeof options == "string") options = {className: options};
16
+ return new Annotation(this, options);
17
+ });
18
+
19
+ CodeMirror.defineOption("scrollButtonHeight", 0);
20
+
21
+ function Annotation(cm, options) {
22
+ this.cm = cm;
23
+ this.options = options;
24
+ this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight");
25
+ this.annotations = [];
26
+ this.doRedraw = this.doUpdate = null;
27
+ this.div = cm.getWrapperElement().appendChild(document.createElement("div"));
28
+ this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none";
29
+ this.computeScale();
30
+
31
+ function scheduleRedraw(delay) {
32
+ clearTimeout(self.doRedraw);
33
+ self.doRedraw = setTimeout(function() { self.redraw(); }, delay);
34
+ }
35
+
36
+ var self = this;
37
+ cm.on("refresh", this.resizeHandler = function() {
38
+ clearTimeout(self.doUpdate);
39
+ self.doUpdate = setTimeout(function() {
40
+ if (self.computeScale()) scheduleRedraw(20);
41
+ }, 100);
42
+ });
43
+ cm.on("markerAdded", this.resizeHandler);
44
+ cm.on("markerCleared", this.resizeHandler);
45
+ if (options.listenForChanges !== false)
46
+ cm.on("change", this.changeHandler = function() {
47
+ scheduleRedraw(250);
48
+ });
49
+ }
50
+
51
+ Annotation.prototype.computeScale = function() {
52
+ var cm = this.cm;
53
+ var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /
54
+ cm.getScrollerElement().scrollHeight
55
+ if (hScale != this.hScale) {
56
+ this.hScale = hScale;
57
+ return true;
58
+ }
59
+ };
60
+
61
+ Annotation.prototype.update = function(annotations) {
62
+ this.annotations = annotations;
63
+ this.redraw();
64
+ };
65
+
66
+ Annotation.prototype.redraw = function(compute) {
67
+ if (compute !== false) this.computeScale();
68
+ var cm = this.cm, hScale = this.hScale;
69
+
70
+ var frag = document.createDocumentFragment(), anns = this.annotations;
71
+
72
+ var wrapping = cm.getOption("lineWrapping");
73
+ var singleLineH = wrapping && cm.defaultTextHeight() * 1.5;
74
+ var curLine = null, curLineObj = null;
75
+ function getY(pos, top) {
76
+ if (curLine != pos.line) {
77
+ curLine = pos.line;
78
+ curLineObj = cm.getLineHandle(curLine);
79
+ }
80
+ if (wrapping && curLineObj.height > singleLineH)
81
+ return cm.charCoords(pos, "local")[top ? "top" : "bottom"];
82
+ var topY = cm.heightAtLine(curLineObj, "local");
83
+ return topY + (top ? 0 : curLineObj.height);
84
+ }
85
+
86
+ if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) {
87
+ var ann = anns[i];
88
+ var top = nextTop || getY(ann.from, true) * hScale;
89
+ var bottom = getY(ann.to, false) * hScale;
90
+ while (i < anns.length - 1) {
91
+ nextTop = getY(anns[i + 1].from, true) * hScale;
92
+ if (nextTop > bottom + .9) break;
93
+ ann = anns[++i];
94
+ bottom = getY(ann.to, false) * hScale;
95
+ }
96
+ if (bottom == top) continue;
97
+ var height = Math.max(bottom - top, 3);
98
+
99
+ var elt = frag.appendChild(document.createElement("div"));
100
+ elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
101
+ + (top + this.buttonHeight) + "px; height: " + height + "px";
102
+ elt.className = this.options.className;
103
+ if (ann.id) {
104
+ elt.setAttribute("annotation-id", ann.id);
105
+ }
106
+ }
107
+ this.div.textContent = "";
108
+ this.div.appendChild(frag);
109
+ };
110
+
111
+ Annotation.prototype.clear = function() {
112
+ this.cm.off("refresh", this.resizeHandler);
113
+ this.cm.off("markerAdded", this.resizeHandler);
114
+ this.cm.off("markerCleared", this.resizeHandler);
115
+ if (this.changeHandler) this.cm.off("change", this.changeHandler);
116
+ this.div.parentNode.removeChild(this.div);
117
+ };
118
+ });
codemirror/addon/search/match-highlighter.js ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Highlighting text that matches the selection
5
+ //
6
+ // Defines an option highlightSelectionMatches, which, when enabled,
7
+ // will style strings that match the selection throughout the
8
+ // document.
9
+ //
10
+ // The option can be set to true to simply enable it, or to a
11
+ // {minChars, style, wordsOnly, showToken, delay} object to explicitly
12
+ // configure it. minChars is the minimum amount of characters that should be
13
+ // selected for the behavior to occur, and style is the token style to
14
+ // apply to the matches. This will be prefixed by "cm-" to create an
15
+ // actual CSS class name. If wordsOnly is enabled, the matches will be
16
+ // highlighted only if the selected text is a word. showToken, when enabled,
17
+ // will cause the current token to be highlighted when nothing is selected.
18
+ // delay is used to specify how much time to wait, in milliseconds, before
19
+ // highlighting the matches. If annotateScrollbar is enabled, the occurences
20
+ // will be highlighted on the scrollbar via the matchesonscrollbar addon.
21
+
22
+ (function(mod) {
23
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
24
+ mod(require("../../lib/codemirror"), require("./matchesonscrollbar"));
25
+ else if (typeof define == "function" && define.amd) // AMD
26
+ define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
27
+ else // Plain browser env
28
+ mod(CodeMirror);
29
+ })(function(CodeMirror) {
30
+ "use strict";
31
+
32
+ var defaults = {
33
+ style: "matchhighlight",
34
+ minChars: 2,
35
+ delay: 100,
36
+ wordsOnly: false,
37
+ annotateScrollbar: false,
38
+ showToken: false,
39
+ trim: true
40
+ }
41
+
42
+ function State(options) {
43
+ this.options = {}
44
+ for (var name in defaults)
45
+ this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
46
+ this.overlay = this.timeout = null;
47
+ this.matchesonscroll = null;
48
+ this.active = false;
49
+ }
50
+
51
+ CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
52
+ if (old && old != CodeMirror.Init) {
53
+ removeOverlay(cm);
54
+ clearTimeout(cm.state.matchHighlighter.timeout);
55
+ cm.state.matchHighlighter = null;
56
+ cm.off("cursorActivity", cursorActivity);
57
+ cm.off("focus", onFocus)
58
+ }
59
+ if (val) {
60
+ var state = cm.state.matchHighlighter = new State(val);
61
+ if (cm.hasFocus()) {
62
+ state.active = true
63
+ highlightMatches(cm)
64
+ } else {
65
+ cm.on("focus", onFocus)
66
+ }
67
+ cm.on("cursorActivity", cursorActivity);
68
+ }
69
+ });
70
+
71
+ function cursorActivity(cm) {
72
+ var state = cm.state.matchHighlighter;
73
+ if (state.active || cm.hasFocus()) scheduleHighlight(cm, state)
74
+ }
75
+
76
+ function onFocus(cm) {
77
+ var state = cm.state.matchHighlighter
78
+ if (!state.active) {
79
+ state.active = true
80
+ scheduleHighlight(cm, state)
81
+ }
82
+ }
83
+
84
+ function scheduleHighlight(cm, state) {
85
+ clearTimeout(state.timeout);
86
+ state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
87
+ }
88
+
89
+ function addOverlay(cm, query, hasBoundary, style) {
90
+ var state = cm.state.matchHighlighter;
91
+ cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
92
+ if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
93
+ var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query;
94
+ state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
95
+ {className: "CodeMirror-selection-highlight-scrollbar"});
96
+ }
97
+ }
98
+
99
+ function removeOverlay(cm) {
100
+ var state = cm.state.matchHighlighter;
101
+ if (state.overlay) {
102
+ cm.removeOverlay(state.overlay);
103
+ state.overlay = null;
104
+ if (state.matchesonscroll) {
105
+ state.matchesonscroll.clear();
106
+ state.matchesonscroll = null;
107
+ }
108
+ }
109
+ }
110
+
111
+ function highlightMatches(cm) {
112
+ cm.operation(function() {
113
+ var state = cm.state.matchHighlighter;
114
+ removeOverlay(cm);
115
+ if (!cm.somethingSelected() && state.options.showToken) {
116
+ var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
117
+ var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
118
+ while (start && re.test(line.charAt(start - 1))) --start;
119
+ while (end < line.length && re.test(line.charAt(end))) ++end;
120
+ if (start < end)
121
+ addOverlay(cm, line.slice(start, end), re, state.options.style);
122
+ return;
123
+ }
124
+ var from = cm.getCursor("from"), to = cm.getCursor("to");
125
+ if (from.line != to.line) return;
126
+ if (state.options.wordsOnly && !isWord(cm, from, to)) return;
127
+ var selection = cm.getRange(from, to)
128
+ if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
129
+ if (selection.length >= state.options.minChars)
130
+ addOverlay(cm, selection, false, state.options.style);
131
+ });
132
+ }
133
+
134
+ function isWord(cm, from, to) {
135
+ var str = cm.getRange(from, to);
136
+ if (str.match(/^\w+$/) !== null) {
137
+ if (from.ch > 0) {
138
+ var pos = {line: from.line, ch: from.ch - 1};
139
+ var chr = cm.getRange(pos, from);
140
+ if (chr.match(/\W/) === null) return false;
141
+ }
142
+ if (to.ch < cm.getLine(from.line).length) {
143
+ var pos = {line: to.line, ch: to.ch + 1};
144
+ var chr = cm.getRange(to, pos);
145
+ if (chr.match(/\W/) === null) return false;
146
+ }
147
+ return true;
148
+ } else return false;
149
+ }
150
+
151
+ function boundariesAround(stream, re) {
152
+ return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
153
+ (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
154
+ }
155
+
156
+ function makeOverlay(query, hasBoundary, style) {
157
+ return {token: function(stream) {
158
+ if (stream.match(query) &&
159
+ (!hasBoundary || boundariesAround(stream, hasBoundary)))
160
+ return style;
161
+ stream.next();
162
+ stream.skipTo(query.charAt(0)) || stream.skipToEnd();
163
+ }};
164
+ }
165
+ });
codemirror/addon/search/matchesonscrollbar.css ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ .CodeMirror-search-match {
2
+ background: gold;
3
+ border-top: 1px solid orange;
4
+ border-bottom: 1px solid orange;
5
+ -moz-box-sizing: border-box;
6
+ box-sizing: border-box;
7
+ opacity: .5;
8
+ }
codemirror/addon/search/matchesonscrollbar.js ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
15
+ if (typeof options == "string") options = {className: options};
16
+ if (!options) options = {};
17
+ return new SearchAnnotation(this, query, caseFold, options);
18
+ });
19
+
20
+ function SearchAnnotation(cm, query, caseFold, options) {
21
+ this.cm = cm;
22
+ this.options = options;
23
+ var annotateOptions = {listenForChanges: false};
24
+ for (var prop in options) annotateOptions[prop] = options[prop];
25
+ if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
26
+ this.annotation = cm.annotateScrollbar(annotateOptions);
27
+ this.query = query;
28
+ this.caseFold = caseFold;
29
+ this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
30
+ this.matches = [];
31
+ this.update = null;
32
+
33
+ this.findMatches();
34
+ this.annotation.update(this.matches);
35
+
36
+ var self = this;
37
+ cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
38
+ }
39
+
40
+ var MAX_MATCHES = 1000;
41
+
42
+ SearchAnnotation.prototype.findMatches = function() {
43
+ if (!this.gap) return;
44
+ for (var i = 0; i < this.matches.length; i++) {
45
+ var match = this.matches[i];
46
+ if (match.from.line >= this.gap.to) break;
47
+ if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
48
+ }
49
+ var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold);
50
+ var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES;
51
+ while (cursor.findNext()) {
52
+ var match = {from: cursor.from(), to: cursor.to()};
53
+ if (match.from.line >= this.gap.to) break;
54
+ this.matches.splice(i++, 0, match);
55
+ if (this.matches.length > maxMatches) break;
56
+ }
57
+ this.gap = null;
58
+ };
59
+
60
+ function offsetLine(line, changeStart, sizeChange) {
61
+ if (line <= changeStart) return line;
62
+ return Math.max(changeStart, line + sizeChange);
63
+ }
64
+
65
+ SearchAnnotation.prototype.onChange = function(change) {
66
+ var startLine = change.from.line;
67
+ var endLine = CodeMirror.changeEnd(change).line;
68
+ var sizeChange = endLine - change.to.line;
69
+ if (this.gap) {
70
+ this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
71
+ this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
72
+ } else {
73
+ this.gap = {from: change.from.line, to: endLine + 1};
74
+ }
75
+
76
+ if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
77
+ var match = this.matches[i];
78
+ var newFrom = offsetLine(match.from.line, startLine, sizeChange);
79
+ if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
80
+ var newTo = offsetLine(match.to.line, startLine, sizeChange);
81
+ if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
82
+ }
83
+ clearTimeout(this.update);
84
+ var self = this;
85
+ this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
86
+ };
87
+
88
+ SearchAnnotation.prototype.updateAfterChange = function() {
89
+ this.findMatches();
90
+ this.annotation.update(this.matches);
91
+ };
92
+
93
+ SearchAnnotation.prototype.clear = function() {
94
+ this.cm.off("change", this.changeHandler);
95
+ this.annotation.clear();
96
+ };
97
+ });
codemirror/addon/search/search.js ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Define search commands. Depends on dialog.js or another
5
+ // implementation of the openDialog method.
6
+
7
+ // Replace works a little oddly -- it will do the replace on the next
8
+ // Ctrl-G (or whatever is bound to findNext) press. You prevent a
9
+ // replace by making sure the match is no longer selected when hitting
10
+ // Ctrl-G.
11
+
12
+ (function(mod) {
13
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
14
+ mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
15
+ else if (typeof define == "function" && define.amd) // AMD
16
+ define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
17
+ else // Plain browser env
18
+ mod(CodeMirror);
19
+ })(function(CodeMirror) {
20
+ "use strict";
21
+
22
+ function searchOverlay(query, caseInsensitive) {
23
+ if (typeof query == "string")
24
+ query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
25
+ else if (!query.global)
26
+ query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
27
+
28
+ return {token: function(stream) {
29
+ query.lastIndex = stream.pos;
30
+ var match = query.exec(stream.string);
31
+ if (match && match.index == stream.pos) {
32
+ stream.pos += match[0].length || 1;
33
+ return "searching";
34
+ } else if (match) {
35
+ stream.pos = match.index;
36
+ } else {
37
+ stream.skipToEnd();
38
+ }
39
+ }};
40
+ }
41
+
42
+ function SearchState() {
43
+ this.posFrom = this.posTo = this.lastQuery = this.query = null;
44
+ this.overlay = null;
45
+ }
46
+
47
+ function getSearchState(cm) {
48
+ return cm.state.search || (cm.state.search = new SearchState());
49
+ }
50
+
51
+ function queryCaseInsensitive(query) {
52
+ return typeof query == "string" && query == query.toLowerCase();
53
+ }
54
+
55
+ function getSearchCursor(cm, query, pos) {
56
+ // Heuristic: if the query string is all lowercase, do a case insensitive search.
57
+ return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
58
+ }
59
+
60
+ function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
61
+ cm.openDialog(text, onEnter, {
62
+ value: deflt,
63
+ selectValueOnOpen: true,
64
+ closeOnEnter: false,
65
+ onClose: function() { clearSearch(cm); },
66
+ onKeyDown: onKeyDown
67
+ });
68
+ }
69
+
70
+ function dialog(cm, text, shortText, deflt, f) {
71
+ if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
72
+ else f(prompt(shortText, deflt));
73
+ }
74
+
75
+ function confirmDialog(cm, text, shortText, fs) {
76
+ if (cm.openConfirm) cm.openConfirm(text, fs);
77
+ else if (confirm(shortText)) fs[0]();
78
+ }
79
+
80
+ function parseString(string) {
81
+ return string.replace(/\\(.)/g, function(_, ch) {
82
+ if (ch == "n") return "\n"
83
+ if (ch == "r") return "\r"
84
+ return ch
85
+ })
86
+ }
87
+
88
+ function parseQuery(query) {
89
+ var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
90
+ if (isRE) {
91
+ try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
92
+ catch(e) {} // Not a regular expression after all, do a string search
93
+ } else {
94
+ query = parseString(query)
95
+ }
96
+ if (typeof query == "string" ? query == "" : query.test(""))
97
+ query = /x^/;
98
+ return query;
99
+ }
100
+
101
+ var queryDialog =
102
+ 'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
103
+
104
+ function startSearch(cm, state, query) {
105
+ state.queryText = query;
106
+ state.query = parseQuery(query);
107
+ cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
108
+ state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
109
+ cm.addOverlay(state.overlay);
110
+ if (cm.showMatchesOnScrollbar) {
111
+ if (state.annotate) { state.annotate.clear(); state.annotate = null; }
112
+ state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
113
+ }
114
+ }
115
+
116
+ function doSearch(cm, rev, persistent, immediate) {
117
+ var state = getSearchState(cm);
118
+ if (state.query) return findNext(cm, rev);
119
+ var q = cm.getSelection() || state.lastQuery;
120
+ if (persistent && cm.openDialog) {
121
+ var hiding = null
122
+ var searchNext = function(query, event) {
123
+ CodeMirror.e_stop(event);
124
+ if (!query) return;
125
+ if (query != state.queryText) {
126
+ startSearch(cm, state, query);
127
+ state.posFrom = state.posTo = cm.getCursor();
128
+ }
129
+ if (hiding) hiding.style.opacity = 1
130
+ findNext(cm, event.shiftKey, function(_, to) {
131
+ var dialog
132
+ if (to.line < 3 && document.querySelector &&
133
+ (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
134
+ dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
135
+ (hiding = dialog).style.opacity = .4
136
+ })
137
+ };
138
+ persistentDialog(cm, queryDialog, q, searchNext, function(event, query) {
139
+ var keyName = CodeMirror.keyName(event)
140
+ var cmd = CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
141
+ if (!cmd) cmd = cm.getOption('extraKeys')[keyName]
142
+ if (cmd == "findNext" || cmd == "findPrev" ||
143
+ cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
144
+ CodeMirror.e_stop(event);
145
+ startSearch(cm, getSearchState(cm), query);
146
+ cm.execCommand(cmd);
147
+ } else if (cmd == "find" || cmd == "findPersistent") {
148
+ CodeMirror.e_stop(event);
149
+ searchNext(query, event);
150
+ }
151
+ });
152
+ if (immediate && q) {
153
+ startSearch(cm, state, q);
154
+ findNext(cm, rev);
155
+ }
156
+ } else {
157
+ dialog(cm, queryDialog, "Search for:", q, function(query) {
158
+ if (query && !state.query) cm.operation(function() {
159
+ startSearch(cm, state, query);
160
+ state.posFrom = state.posTo = cm.getCursor();
161
+ findNext(cm, rev);
162
+ });
163
+ });
164
+ }
165
+ }
166
+
167
+ function findNext(cm, rev, callback) {cm.operation(function() {
168
+ var state = getSearchState(cm);
169
+ var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
170
+ if (!cursor.find(rev)) {
171
+ cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
172
+ if (!cursor.find(rev)) return;
173
+ }
174
+ cm.setSelection(cursor.from(), cursor.to());
175
+ cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
176
+ state.posFrom = cursor.from(); state.posTo = cursor.to();
177
+ if (callback) callback(cursor.from(), cursor.to())
178
+ });}
179
+
180
+ function clearSearch(cm) {cm.operation(function() {
181
+ var state = getSearchState(cm);
182
+ state.lastQuery = state.query;
183
+ if (!state.query) return;
184
+ state.query = state.queryText = null;
185
+ cm.removeOverlay(state.overlay);
186
+ if (state.annotate) { state.annotate.clear(); state.annotate = null; }
187
+ });}
188
+
189
+ var replaceQueryDialog =
190
+ ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
191
+ var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
192
+ var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";
193
+
194
+ function replaceAll(cm, query, text) {
195
+ cm.operation(function() {
196
+ for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
197
+ if (typeof query != "string") {
198
+ var match = cm.getRange(cursor.from(), cursor.to()).match(query);
199
+ cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
200
+ } else cursor.replace(text);
201
+ }
202
+ });
203
+ }
204
+
205
+ function replace(cm, all) {
206
+ if (cm.getOption("readOnly")) return;
207
+ var query = cm.getSelection() || getSearchState(cm).lastQuery;
208
+ var dialogText = all ? "Replace all:" : "Replace:"
209
+ dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
210
+ if (!query) return;
211
+ query = parseQuery(query);
212
+ dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
213
+ text = parseString(text)
214
+ if (all) {
215
+ replaceAll(cm, query, text)
216
+ } else {
217
+ clearSearch(cm);
218
+ var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
219
+ var advance = function() {
220
+ var start = cursor.from(), match;
221
+ if (!(match = cursor.findNext())) {
222
+ cursor = getSearchCursor(cm, query);
223
+ if (!(match = cursor.findNext()) ||
224
+ (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
225
+ }
226
+ cm.setSelection(cursor.from(), cursor.to());
227
+ cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
228
+ confirmDialog(cm, doReplaceConfirm, "Replace?",
229
+ [function() {doReplace(match);}, advance,
230
+ function() {replaceAll(cm, query, text)}]);
231
+ };
232
+ var doReplace = function(match) {
233
+ cursor.replace(typeof query == "string" ? text :
234
+ text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
235
+ advance();
236
+ };
237
+ advance();
238
+ }
239
+ });
240
+ });
241
+ }
242
+
243
+ CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
244
+ CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
245
+ CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
246
+ CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
247
+ CodeMirror.commands.findNext = doSearch;
248
+ CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
249
+ CodeMirror.commands.clearSearch = clearSearch;
250
+ CodeMirror.commands.replace = replace;
251
+ CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
252
+ });
codemirror/addon/search/searchcursor.js ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+ var Pos = CodeMirror.Pos;
14
+
15
+ function SearchCursor(doc, query, pos, caseFold) {
16
+ this.atOccurrence = false; this.doc = doc;
17
+ if (caseFold == null && typeof query == "string") caseFold = false;
18
+
19
+ pos = pos ? doc.clipPos(pos) : Pos(0, 0);
20
+ this.pos = {from: pos, to: pos};
21
+
22
+ // The matches method is filled in based on the type of query.
23
+ // It takes a position and a direction, and returns an object
24
+ // describing the next occurrence of the query, or null if no
25
+ // more matches were found.
26
+ if (typeof query != "string") { // Regexp match
27
+ if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
28
+ this.matches = function(reverse, pos) {
29
+ if (reverse) {
30
+ query.lastIndex = 0;
31
+ var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
32
+ for (;;) {
33
+ query.lastIndex = cutOff;
34
+ var newMatch = query.exec(line);
35
+ if (!newMatch) break;
36
+ match = newMatch;
37
+ start = match.index;
38
+ cutOff = match.index + (match[0].length || 1);
39
+ if (cutOff == line.length) break;
40
+ }
41
+ var matchLen = (match && match[0].length) || 0;
42
+ if (!matchLen) {
43
+ if (start == 0 && line.length == 0) {match = undefined;}
44
+ else if (start != doc.getLine(pos.line).length) {
45
+ matchLen++;
46
+ }
47
+ }
48
+ } else {
49
+ query.lastIndex = pos.ch;
50
+ var line = doc.getLine(pos.line), match = query.exec(line);
51
+ var matchLen = (match && match[0].length) || 0;
52
+ var start = match && match.index;
53
+ if (start + matchLen != line.length && !matchLen) matchLen = 1;
54
+ }
55
+ if (match && matchLen)
56
+ return {from: Pos(pos.line, start),
57
+ to: Pos(pos.line, start + matchLen),
58
+ match: match};
59
+ };
60
+ } else { // String query
61
+ var origQuery = query;
62
+ if (caseFold) query = query.toLowerCase();
63
+ var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
64
+ var target = query.split("\n");
65
+ // Different methods for single-line and multi-line queries
66
+ if (target.length == 1) {
67
+ if (!query.length) {
68
+ // Empty string would match anything and never progress, so
69
+ // we define it to match nothing instead.
70
+ this.matches = function() {};
71
+ } else {
72
+ this.matches = function(reverse, pos) {
73
+ if (reverse) {
74
+ var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);
75
+ var match = line.lastIndexOf(query);
76
+ if (match > -1) {
77
+ match = adjustPos(orig, line, match);
78
+ return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
79
+ }
80
+ } else {
81
+ var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);
82
+ var match = line.indexOf(query);
83
+ if (match > -1) {
84
+ match = adjustPos(orig, line, match) + pos.ch;
85
+ return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
86
+ }
87
+ }
88
+ };
89
+ }
90
+ } else {
91
+ var origTarget = origQuery.split("\n");
92
+ this.matches = function(reverse, pos) {
93
+ var last = target.length - 1;
94
+ if (reverse) {
95
+ if (pos.line - (target.length - 1) < doc.firstLine()) return;
96
+ if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;
97
+ var to = Pos(pos.line, origTarget[last].length);
98
+ for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)
99
+ if (target[i] != fold(doc.getLine(ln))) return;
100
+ var line = doc.getLine(ln), cut = line.length - origTarget[0].length;
101
+ if (fold(line.slice(cut)) != target[0]) return;
102
+ return {from: Pos(ln, cut), to: to};
103
+ } else {
104
+ if (pos.line + (target.length - 1) > doc.lastLine()) return;
105
+ var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;
106
+ if (fold(line.slice(cut)) != target[0]) return;
107
+ var from = Pos(pos.line, cut);
108
+ for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)
109
+ if (target[i] != fold(doc.getLine(ln))) return;
110
+ if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return;
111
+ return {from: from, to: Pos(ln, origTarget[last].length)};
112
+ }
113
+ };
114
+ }
115
+ }
116
+ }
117
+
118
+ SearchCursor.prototype = {
119
+ findNext: function() {return this.find(false);},
120
+ findPrevious: function() {return this.find(true);},
121
+
122
+ find: function(reverse) {
123
+ var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
124
+ function savePosAndFail(line) {
125
+ var pos = Pos(line, 0);
126
+ self.pos = {from: pos, to: pos};
127
+ self.atOccurrence = false;
128
+ return false;
129
+ }
130
+
131
+ for (;;) {
132
+ if (this.pos = this.matches(reverse, pos)) {
133
+ this.atOccurrence = true;
134
+ return this.pos.match || true;
135
+ }
136
+ if (reverse) {
137
+ if (!pos.line) return savePosAndFail(0);
138
+ pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
139
+ }
140
+ else {
141
+ var maxLine = this.doc.lineCount();
142
+ if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
143
+ pos = Pos(pos.line + 1, 0);
144
+ }
145
+ }
146
+ },
147
+
148
+ from: function() {if (this.atOccurrence) return this.pos.from;},
149
+ to: function() {if (this.atOccurrence) return this.pos.to;},
150
+
151
+ replace: function(newText, origin) {
152
+ if (!this.atOccurrence) return;
153
+ var lines = CodeMirror.splitLines(newText);
154
+ this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin);
155
+ this.pos.to = Pos(this.pos.from.line + lines.length - 1,
156
+ lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
157
+ }
158
+ };
159
+
160
+ // Maps a position in a case-folded line back to a position in the original line
161
+ // (compensating for codepoints increasing in number during folding)
162
+ function adjustPos(orig, folded, pos) {
163
+ if (orig.length == folded.length) return pos;
164
+ for (var pos1 = Math.min(pos, orig.length);;) {
165
+ var len1 = orig.slice(0, pos1).toLowerCase().length;
166
+ if (len1 < pos) ++pos1;
167
+ else if (len1 > pos) --pos1;
168
+ else return pos1;
169
+ }
170
+ }
171
+
172
+ CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
173
+ return new SearchCursor(this.doc, query, pos, caseFold);
174
+ });
175
+ CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
176
+ return new SearchCursor(this, query, pos, caseFold);
177
+ });
178
+
179
+ CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
180
+ var ranges = [];
181
+ var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold);
182
+ while (cur.findNext()) {
183
+ if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break;
184
+ ranges.push({anchor: cur.from(), head: cur.to()});
185
+ }
186
+ if (ranges.length)
187
+ this.setSelections(ranges, 0);
188
+ });
189
+ });
css/custom-css-and-javascript.css CHANGED
@@ -1,5 +1,5 @@
1
  /**
2
- * Author: Hearken Media
3
  * License: GNU General Public License version 2 or later
4
  * License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
5
  */
@@ -17,4 +17,9 @@
17
  }
18
  #pp_custom_css_js_dev_info li strong {
19
  color: #f00000;
 
 
 
 
 
20
  }
1
  /**
2
+ * Author: Potent Plugins
3
  * License: GNU General Public License version 2 or later
4
  * License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
5
  */
17
  }
18
  #pp_custom_css_js_dev_info li strong {
19
  color: #f00000;
20
+ }
21
+ #hm_custom_code_editor .CodeMirror-matchingbracket {
22
+ color: #f00;
23
+ font-weight: bold;
24
+ background-color: #ccc;
25
  }
custom-css-and-javascript.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Plugin Name: Custom CSS and Javascript
4
  * Description: Easily add custom CSS and Javascript code to your WordPress site.
5
- * Version: 2.0.7
6
  * Author: Potent Plugins
7
  * Author URI: http://potentplugins.com/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-plugin-author-uri
8
  * License: GNU General Public License version 2 or later
@@ -42,7 +42,17 @@ function hm_custom_css_js_admin_scripts($hook) {
42
  wp_enqueue_script('hm_custom_css_js_codemirror_mode_css', plugins_url('codemirror/mode/css.js', __FILE__));
43
  else
44
  wp_enqueue_script('hm_custom_css_js_codemirror_mode_js', plugins_url('codemirror/mode/javascript.js', __FILE__));
 
 
 
 
 
 
 
 
45
  wp_enqueue_style('hm_custom_css_js_codemirror', plugins_url('codemirror/codemirror.css', __FILE__));
 
 
46
  wp_enqueue_script('hm_custom_css_js', plugins_url('js/custom-css-and-javascript.js', __FILE__));
47
  wp_enqueue_style('hm_custom_css_js', plugins_url('css/custom-css-and-javascript.css', __FILE__));
48
  }
2
  /**
3
  * Plugin Name: Custom CSS and Javascript
4
  * Description: Easily add custom CSS and Javascript code to your WordPress site.
5
+ * Version: 2.0.9
6
  * Author: Potent Plugins
7
  * Author URI: http://potentplugins.com/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-plugin-author-uri
8
  * License: GNU General Public License version 2 or later
42
  wp_enqueue_script('hm_custom_css_js_codemirror_mode_css', plugins_url('codemirror/mode/css.js', __FILE__));
43
  else
44
  wp_enqueue_script('hm_custom_css_js_codemirror_mode_js', plugins_url('codemirror/mode/javascript.js', __FILE__));
45
+ wp_enqueue_script('hm_custom_css_js_codemirror_dialog', plugins_url('codemirror/addon/dialog/dialog.js', __FILE__));
46
+ wp_enqueue_script('hm_custom_css_js_codemirror_matchbrackets', plugins_url('codemirror/addon/edit/matchbrackets.js', __FILE__));
47
+ wp_enqueue_script('hm_custom_css_js_codemirror_search', plugins_url('codemirror/addon/search/search.js', __FILE__));
48
+ wp_enqueue_script('hm_custom_css_js_codemirror_searchcursor', plugins_url('codemirror/addon/search/searchcursor.js', __FILE__));
49
+ wp_enqueue_script('hm_custom_css_js_codemirror_matchhighlighter', plugins_url('codemirror/addon/search/match-highlighter.js', __FILE__));
50
+ wp_enqueue_script('hm_custom_css_js_codemirror_annotatescrollbar', plugins_url('codemirror/addon/scroll/annotatescrollbar.js', __FILE__));
51
+ wp_enqueue_script('hm_custom_css_js_codemirror_matchesonscrollbar', plugins_url('codemirror/addon/search/matchesonscrollbar.js', __FILE__));
52
+
53
  wp_enqueue_style('hm_custom_css_js_codemirror', plugins_url('codemirror/codemirror.css', __FILE__));
54
+ wp_enqueue_style('hm_custom_css_js_codemirror_dialog', plugins_url('codemirror/addon/dialog/dialog.css', __FILE__));
55
+ wp_enqueue_style('hm_custom_css_js_codemirror_matchesonscrollbar', plugins_url('codemirror/addon/search/matchesonscrollbar.css', __FILE__));
56
  wp_enqueue_script('hm_custom_css_js', plugins_url('js/custom-css-and-javascript.js', __FILE__));
57
  wp_enqueue_style('hm_custom_css_js', plugins_url('css/custom-css-and-javascript.css', __FILE__));
58
  }
js/custom-css-and-javascript.js CHANGED
@@ -7,7 +7,8 @@ var hm_custom_code_editor, hm_custom_code_editor_has_changes = false, hm_custom_
7
  jQuery(document).ready(function($) {
8
  hm_custom_code_editor = CodeMirror(document.getElementById("hm_custom_code_editor"), {
9
  lineNumbers: true,
10
- mode: hm_custom_css_js_mode.toLowerCase()
 
11
  });
12
  hm_custom_code_editor.on("change", function() {
13
  if (hm_custom_code_editor_has_changes)
7
  jQuery(document).ready(function($) {
8
  hm_custom_code_editor = CodeMirror(document.getElementById("hm_custom_code_editor"), {
9
  lineNumbers: true,
10
+ mode: hm_custom_css_js_mode.toLowerCase(),
11
+ matchBrackets: true
12
  });
13
  hm_custom_code_editor.on("change", function() {
14
  if (hm_custom_code_editor_has_changes)
readme.txt CHANGED
@@ -1,72 +1,76 @@
1
- === Custom CSS and Javascript ===
2
- Contributors: hearken
3
- Donate link: https://potentplugins.com/donate/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-plugin-readme-donate-link
4
- Tags: css, custom css, styles, custom styles, stylesheet, custom stylesheet, javascript, custom javascript, js, custom js
5
- Requires at least: 3.5
6
- Tested up to: 4.7
7
- Stable tag: 2.0.8
8
- License: GPLv2 or later
9
- License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
-
11
- Easily add custom CSS and Javascript code to your WordPress site, with draft previewing, revisions, and minification!
12
-
13
- == Description ==
14
-
15
- This plugin allows you to add custom site-wide CSS styles and Javascript code to your WordPress site. Useful for overriding your theme's styles and adding client-side functionality.
16
-
17
- Features:
18
-
19
- * Code editor with syntax highlighting and AJAX saving to avoid reloading the editor at each save.
20
- * Save and preview your CSS and Javascript as a draft that is only applied to logged-in users with the necessary permissions until you are ready to publish your changes to the public.
21
- * View and restore past revisions of your CSS and Javascript.
22
- * Automatically minify your custom CSS and Jasascript code to reduce file size.
23
- * For the public, custom CSS and Javascript code is served from the filesystem instead of the database for optimal performance.
24
-
25
- Now available! [Custom CSS and Javascript Developer Edition](https://potentplugins.com/downloads/custom-css-javascript-developer-edition/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-repo-upgrade-link):
26
-
27
- * Divide your CSS and Javascript into multiple virtual files to keep your code organized (the code is still served as one CSS and one JS file on the front-end for efficiency).
28
- * Supports Sassy CSS (SCSS)!
29
- * Live preview for CSS!
30
- * Upload and download CSS and Javascript files, individually or in ZIP files.
31
- * The developer logo and review/donation links are removed from the editor page in the WordPress admin.
32
-
33
- [Click here](https://potentplugins.com/downloads/custom-css-javascript-developer-edition/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-repo-upgrade-link) to purchase!
34
-
35
- If you like this plugin, please consider [making a donation](https://potentplugins.com/donate/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-plugin-repo-donate-link).
36
-
37
- == Installation ==
38
-
39
- 1. Click "Plugins" > "Add New" in the WordPress admin menu.
40
- 1. Search for "Custom CSS and Javascript".
41
- 1. Click "Install Now".
42
- 1. Click "Activate Plugin".
43
-
44
- Alternatively, you can manually upload the plugin to your wp-content/plugins directory.
45
-
46
- == Frequently Asked Questions ==
47
-
48
- == Screenshots ==
49
-
50
- 1. Custom CSS editor
51
-
52
-
53
- == Changelog ==
54
-
55
- = 2.0.8 =
56
- * Fixed issue with backslash in CSS
57
-
58
- = 2.0.5 =
59
- * Improved HTTPS support
60
-
61
- = 2.0 =
62
- * Added revisions
63
- * Added drafts/previewing
64
- * Added minification
65
-
66
- = 1.0.5 =
67
- * Changed file storage location to prevent deletion on plugin update. IMPORTANT: BACK UP YOUR CUSTOM CSS AND JAVASCRIPT CODE BEFORE INSTALLING THIS UPDATE.
68
-
69
- = 1.0 =
70
- * Initial release
71
-
 
 
 
 
72
  == Upgrade Notice ==
1
+ === Custom CSS and Javascript ===
2
+ Contributors: hearken
3
+ Donate link: https://potentplugins.com/donate/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-plugin-readme-donate-link
4
+ Tags: css, custom css, styles, custom styles, stylesheet, custom stylesheet, javascript, custom javascript, js, custom js
5
+ Requires at least: 3.5
6
+ Tested up to: 4.9.4
7
+ Stable tag: 2.0.9
8
+ License: GPLv2 or later
9
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
+
11
+ Easily add custom CSS and Javascript code to your WordPress site, with draft previewing, revisions, and minification!
12
+
13
+ == Description ==
14
+
15
+ This plugin allows you to add custom site-wide CSS styles and Javascript code to your WordPress site. Useful for overriding your theme's styles and adding client-side functionality.
16
+
17
+ Features:
18
+
19
+ * Code editor with syntax highlighting and AJAX saving to avoid reloading the editor at each save.
20
+ * Save and preview your CSS and Javascript as a draft that is only applied to logged-in users with the necessary permissions until you are ready to publish your changes to the public.
21
+ * View and restore past revisions of your CSS and Javascript.
22
+ * Automatically minify your custom CSS and Jasascript code to reduce file size.
23
+ * For the public, custom CSS and Javascript code is served from the filesystem instead of the database for optimal performance.
24
+
25
+ Now available! [Custom CSS and Javascript Developer Edition](https://potentplugins.com/downloads/custom-css-javascript-developer-edition/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-repo-upgrade-link):
26
+
27
+ * Divide your CSS and Javascript into multiple virtual files to keep your code organized (the code is still served as one CSS and one JS file on the front-end for efficiency).
28
+ * Supports Sassy CSS (SCSS)!
29
+ * Live preview for CSS!
30
+ * Upload and download CSS and Javascript files, individually or in ZIP files.
31
+ * The developer logo and review/donation links are removed from the editor page in the WordPress admin.
32
+
33
+ [Click here](https://potentplugins.com/downloads/custom-css-javascript-developer-edition/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-repo-upgrade-link) to purchase!
34
+
35
+ If you like this plugin, please consider [making a donation](https://potentplugins.com/donate/?utm_source=custom-css-and-javascript&utm_medium=link&utm_campaign=wp-plugin-repo-donate-link).
36
+
37
+ == Installation ==
38
+
39
+ 1. Click "Plugins" > "Add New" in the WordPress admin menu.
40
+ 1. Search for "Custom CSS and Javascript".
41
+ 1. Click "Install Now".
42
+ 1. Click "Activate Plugin".
43
+
44
+ Alternatively, you can manually upload the plugin to your wp-content/plugins directory.
45
+
46
+ == Frequently Asked Questions ==
47
+
48
+ == Screenshots ==
49
+
50
+ 1. Custom CSS editor
51
+
52
+
53
+ == Changelog ==
54
+
55
+ = 2.0.9 =
56
+ * Added search functionality to code editor
57
+ * Added bracket matching to code editor
58
+
59
+ = 2.0.8 =
60
+ * Fixed issue with backslash in CSS
61
+
62
+ = 2.0.5 =
63
+ * Improved HTTPS support
64
+
65
+ = 2.0 =
66
+ * Added revisions
67
+ * Added drafts/previewing
68
+ * Added minification
69
+
70
+ = 1.0.5 =
71
+ * Changed file storage location to prevent deletion on plugin update. IMPORTANT: BACK UP YOUR CUSTOM CSS AND JAVASCRIPT CODE BEFORE INSTALLING THIS UPDATE.
72
+
73
+ = 1.0 =
74
+ * Initial release
75
+
76
  == Upgrade Notice ==