Version Description
- Added search functionality to code editor
- Added bracket matching to code editor
Download this release
Release Info
Developer | hearken |
Plugin | 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 +32 -0
- codemirror/addon/dialog/dialog.js +157 -0
- codemirror/addon/edit/matchbrackets.js +122 -0
- codemirror/addon/scroll/annotatescrollbar.js +118 -0
- codemirror/addon/search/match-highlighter.js +165 -0
- codemirror/addon/search/matchesonscrollbar.css +8 -0
- codemirror/addon/search/matchesonscrollbar.js +97 -0
- codemirror/addon/search/search.js +252 -0
- codemirror/addon/search/searchcursor.js +189 -0
- css/custom-css-and-javascript.css +6 -1
- custom-css-and-javascript.php +11 -1
- js/custom-css-and-javascript.js +2 -1
- readme.txt +75 -71
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:
|
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.
|
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 |
-
Stable tag: 2.0.
|
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.
|
56 |
-
*
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
*
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
*
|
68 |
-
|
69 |
-
|
70 |
-
|
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 ==
|