Version Description
- Remove extra whitespace from CSS output
- Remove spellcheck from Customizer input
- Allow > characters in the CSS
- Add find (ctrl + f) functionality
Download this release
Release Info
Developer | edge22 |
Plugin | Simple CSS |
Version | 0.2 |
Comparing to | |
See all releases |
Code changes from version 0.1 to 0.2
- css/style.css +34 -8
- customize/css-control.php +1 -1
- js/dialog.js +157 -0
- js/search.js +228 -0
- js/searchcursor.js +189 -0
- readme.txt +14 -2
- simple-css.php +9 -3
css/style.css
CHANGED
@@ -1,12 +1,5 @@
|
|
1 |
.CodeMirror {
|
2 |
-
|
3 |
-
height: -moz-calc(100vh - 190px);
|
4 |
-
/* WebKit */
|
5 |
-
height: -webkit-calc(100vh - 190px);
|
6 |
-
/* Opera */
|
7 |
-
height: -o-calc(100vh - 190px);
|
8 |
-
/* Standard */
|
9 |
-
height: calc(100vh - 190px);
|
10 |
}
|
11 |
|
12 |
.simple-css-save {
|
@@ -40,4 +33,37 @@
|
|
40 |
|
41 |
.simple-css-sidebar .hndle {
|
42 |
cursor: auto !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
}
|
1 |
.CodeMirror {
|
2 |
+
height: 700px
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
}
|
4 |
|
5 |
.simple-css-save {
|
33 |
|
34 |
.simple-css-sidebar .hndle {
|
35 |
cursor: auto !important;
|
36 |
+
}
|
37 |
+
|
38 |
+
.CodeMirror-dialog {
|
39 |
+
position: absolute;
|
40 |
+
left: 0; right: 0;
|
41 |
+
background: inherit;
|
42 |
+
z-index: 15;
|
43 |
+
padding: .1em .8em;
|
44 |
+
overflow: hidden;
|
45 |
+
color: inherit;
|
46 |
+
}
|
47 |
+
|
48 |
+
.CodeMirror-dialog-top {
|
49 |
+
border-bottom: 1px solid #eee;
|
50 |
+
top: 0;
|
51 |
+
}
|
52 |
+
|
53 |
+
.CodeMirror-dialog-bottom {
|
54 |
+
border-top: 1px solid #eee;
|
55 |
+
bottom: 0;
|
56 |
+
}
|
57 |
+
|
58 |
+
.CodeMirror-dialog input {
|
59 |
+
border: none;
|
60 |
+
outline: none;
|
61 |
+
background: transparent;
|
62 |
+
width: 20em;
|
63 |
+
color: inherit;
|
64 |
+
font-family: monospace;
|
65 |
+
}
|
66 |
+
|
67 |
+
.CodeMirror-dialog button {
|
68 |
+
font-size: 70%;
|
69 |
}
|
customize/css-control.php
CHANGED
@@ -7,7 +7,7 @@ class Simple_CSS_Editor extends WP_Customize_Control {
|
|
7 |
<label>
|
8 |
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
|
9 |
<div class="customize-control-content">
|
10 |
-
<textarea class="widefat" cols="45" rows="15" <?php $this->link(); ?>><?php echo esc_textarea( $this->value() ); ?></textarea>
|
11 |
</div>
|
12 |
</label>
|
13 |
<?php }
|
7 |
<label>
|
8 |
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
|
9 |
<div class="customize-control-content">
|
10 |
+
<textarea spellcheck="false" class="widefat" cols="45" rows="15" <?php $this->link(); ?>><?php echo esc_textarea( $this->value() ); ?></textarea>
|
11 |
</div>
|
12 |
</label>
|
13 |
<?php }
|
js/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 |
+
if (options.value) {
|
60 |
+
inp.value = options.value;
|
61 |
+
if (options.selectValueOnOpen !== false) {
|
62 |
+
inp.select();
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
if (options.onInput)
|
67 |
+
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
|
68 |
+
if (options.onKeyUp)
|
69 |
+
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
70 |
+
|
71 |
+
CodeMirror.on(inp, "keydown", function(e) {
|
72 |
+
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
73 |
+
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
|
74 |
+
inp.blur();
|
75 |
+
CodeMirror.e_stop(e);
|
76 |
+
close();
|
77 |
+
}
|
78 |
+
if (e.keyCode == 13) callback(inp.value, e);
|
79 |
+
});
|
80 |
+
|
81 |
+
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
|
82 |
+
|
83 |
+
inp.focus();
|
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 |
+
});
|
js/search.js
ADDED
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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, f) {
|
61 |
+
cm.openDialog(text, f, {
|
62 |
+
value: deflt,
|
63 |
+
selectValueOnOpen: true,
|
64 |
+
closeOnEnter: false,
|
65 |
+
onClose: function() { clearSearch(cm); }
|
66 |
+
});
|
67 |
+
}
|
68 |
+
|
69 |
+
function dialog(cm, text, shortText, deflt, f) {
|
70 |
+
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
|
71 |
+
else f(prompt(shortText, deflt));
|
72 |
+
}
|
73 |
+
|
74 |
+
function confirmDialog(cm, text, shortText, fs) {
|
75 |
+
if (cm.openConfirm) cm.openConfirm(text, fs);
|
76 |
+
else if (confirm(shortText)) fs[0]();
|
77 |
+
}
|
78 |
+
|
79 |
+
function parseString(string) {
|
80 |
+
return string.replace(/\\(.)/g, function(_, ch) {
|
81 |
+
if (ch == "n") return "\n"
|
82 |
+
if (ch == "r") return "\r"
|
83 |
+
return ch
|
84 |
+
})
|
85 |
+
}
|
86 |
+
|
87 |
+
function parseQuery(query) {
|
88 |
+
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
89 |
+
if (isRE) {
|
90 |
+
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
|
91 |
+
catch(e) {} // Not a regular expression after all, do a string search
|
92 |
+
} else {
|
93 |
+
query = parseString(query)
|
94 |
+
}
|
95 |
+
if (typeof query == "string" ? query == "" : query.test(""))
|
96 |
+
query = /x^/;
|
97 |
+
return query;
|
98 |
+
}
|
99 |
+
|
100 |
+
var queryDialog =
|
101 |
+
'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>';
|
102 |
+
|
103 |
+
function startSearch(cm, state, query) {
|
104 |
+
state.queryText = query;
|
105 |
+
state.query = parseQuery(query);
|
106 |
+
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
|
107 |
+
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
|
108 |
+
cm.addOverlay(state.overlay);
|
109 |
+
if (cm.showMatchesOnScrollbar) {
|
110 |
+
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
111 |
+
state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
|
112 |
+
}
|
113 |
+
}
|
114 |
+
|
115 |
+
function doSearch(cm, rev, persistent) {
|
116 |
+
var state = getSearchState(cm);
|
117 |
+
if (state.query) return findNext(cm, rev);
|
118 |
+
var q = cm.getSelection() || state.lastQuery;
|
119 |
+
if (persistent && cm.openDialog) {
|
120 |
+
var hiding = null
|
121 |
+
persistentDialog(cm, queryDialog, q, function(query, event) {
|
122 |
+
CodeMirror.e_stop(event);
|
123 |
+
if (!query) return;
|
124 |
+
if (query != state.queryText) startSearch(cm, state, query);
|
125 |
+
if (hiding) hiding.style.opacity = 1
|
126 |
+
findNext(cm, event.shiftKey, function(_, to) {
|
127 |
+
var dialog
|
128 |
+
if (to.line < 3 && document.querySelector &&
|
129 |
+
(dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
|
130 |
+
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
|
131 |
+
(hiding = dialog).style.opacity = .4
|
132 |
+
})
|
133 |
+
});
|
134 |
+
} else {
|
135 |
+
dialog(cm, queryDialog, "Search for:", q, function(query) {
|
136 |
+
if (query && !state.query) cm.operation(function() {
|
137 |
+
startSearch(cm, state, query);
|
138 |
+
state.posFrom = state.posTo = cm.getCursor();
|
139 |
+
findNext(cm, rev);
|
140 |
+
});
|
141 |
+
});
|
142 |
+
}
|
143 |
+
}
|
144 |
+
|
145 |
+
function findNext(cm, rev, callback) {cm.operation(function() {
|
146 |
+
var state = getSearchState(cm);
|
147 |
+
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
|
148 |
+
if (!cursor.find(rev)) {
|
149 |
+
cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
|
150 |
+
if (!cursor.find(rev)) return;
|
151 |
+
}
|
152 |
+
cm.setSelection(cursor.from(), cursor.to());
|
153 |
+
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
|
154 |
+
state.posFrom = cursor.from(); state.posTo = cursor.to();
|
155 |
+
if (callback) callback(cursor.from(), cursor.to())
|
156 |
+
});}
|
157 |
+
|
158 |
+
function clearSearch(cm) {cm.operation(function() {
|
159 |
+
var state = getSearchState(cm);
|
160 |
+
state.lastQuery = state.query;
|
161 |
+
if (!state.query) return;
|
162 |
+
state.query = state.queryText = null;
|
163 |
+
cm.removeOverlay(state.overlay);
|
164 |
+
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
165 |
+
});}
|
166 |
+
|
167 |
+
var replaceQueryDialog =
|
168 |
+
' <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>';
|
169 |
+
var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
|
170 |
+
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";
|
171 |
+
|
172 |
+
function replaceAll(cm, query, text) {
|
173 |
+
cm.operation(function() {
|
174 |
+
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
|
175 |
+
if (typeof query != "string") {
|
176 |
+
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
|
177 |
+
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
178 |
+
} else cursor.replace(text);
|
179 |
+
}
|
180 |
+
});
|
181 |
+
}
|
182 |
+
|
183 |
+
function replace(cm, all) {
|
184 |
+
if (cm.getOption("readOnly")) return;
|
185 |
+
var query = cm.getSelection() || getSearchState(cm).lastQuery;
|
186 |
+
var dialogText = all ? "Replace all:" : "Replace:"
|
187 |
+
dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
|
188 |
+
if (!query) return;
|
189 |
+
query = parseQuery(query);
|
190 |
+
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
|
191 |
+
text = parseString(text)
|
192 |
+
if (all) {
|
193 |
+
replaceAll(cm, query, text)
|
194 |
+
} else {
|
195 |
+
clearSearch(cm);
|
196 |
+
var cursor = getSearchCursor(cm, query, cm.getCursor());
|
197 |
+
var advance = function() {
|
198 |
+
var start = cursor.from(), match;
|
199 |
+
if (!(match = cursor.findNext())) {
|
200 |
+
cursor = getSearchCursor(cm, query);
|
201 |
+
if (!(match = cursor.findNext()) ||
|
202 |
+
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
|
203 |
+
}
|
204 |
+
cm.setSelection(cursor.from(), cursor.to());
|
205 |
+
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
|
206 |
+
confirmDialog(cm, doReplaceConfirm, "Replace?",
|
207 |
+
[function() {doReplace(match);}, advance,
|
208 |
+
function() {replaceAll(cm, query, text)}]);
|
209 |
+
};
|
210 |
+
var doReplace = function(match) {
|
211 |
+
cursor.replace(typeof query == "string" ? text :
|
212 |
+
text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
213 |
+
advance();
|
214 |
+
};
|
215 |
+
advance();
|
216 |
+
}
|
217 |
+
});
|
218 |
+
});
|
219 |
+
}
|
220 |
+
|
221 |
+
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
|
222 |
+
CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
|
223 |
+
CodeMirror.commands.findNext = doSearch;
|
224 |
+
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
|
225 |
+
CodeMirror.commands.clearSearch = clearSearch;
|
226 |
+
CodeMirror.commands.replace = replace;
|
227 |
+
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
|
228 |
+
});
|
js/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 |
+
});
|
readme.txt
CHANGED
@@ -3,8 +3,8 @@ Contributors: edge22
|
|
3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UVPTY2ZJA68S6
|
4 |
Tags: CSS, custom CSS, Simple CSS, Simple Custom CSS, CSS Customizer
|
5 |
Requires at least: 4.0
|
6 |
-
Tested up to: 4.4
|
7 |
-
Stable tag: 0.
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
@@ -55,10 +55,22 @@ In most cases, #1 will work fine and is way easier.
|
|
55 |
|
56 |
== Changelog ==
|
57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
= 0.1 =
|
59 |
* Initial release
|
60 |
|
61 |
== Upgrade Notice ==
|
62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
= 0.1 =
|
64 |
* Initial release
|
3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UVPTY2ZJA68S6
|
4 |
Tags: CSS, custom CSS, Simple CSS, Simple Custom CSS, CSS Customizer
|
5 |
Requires at least: 4.0
|
6 |
+
Tested up to: 4.4.1
|
7 |
+
Stable tag: 0.2
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
55 |
|
56 |
== Changelog ==
|
57 |
|
58 |
+
= 0.2 =
|
59 |
+
* Remove extra whitespace from CSS output
|
60 |
+
* Remove spellcheck from Customizer input
|
61 |
+
* Allow > characters in the CSS
|
62 |
+
* Add find (ctrl + f) functionality
|
63 |
+
|
64 |
= 0.1 =
|
65 |
* Initial release
|
66 |
|
67 |
== Upgrade Notice ==
|
68 |
|
69 |
+
= 0.2 =
|
70 |
+
* Remove extra whitespace from CSS output
|
71 |
+
* Remove spellcheck from Customizer input
|
72 |
+
* Allow > characters in the CSS
|
73 |
+
* Add find (ctrl + f) functionality
|
74 |
+
|
75 |
= 0.1 =
|
76 |
* Initial release
|
simple-css.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
Plugin Name: Simple CSS
|
4 |
Plugin URI: https://generatepress.com
|
5 |
Description: Simply add CSS to your WordPress site using an awesome CSS editor or the live Customizer.
|
6 |
-
Version: 0.
|
7 |
Author: Tom Usborne
|
8 |
Author URI: http://edge22.com
|
9 |
License: GNU General Public License v2 or later
|
@@ -46,6 +46,9 @@ function simple_css_scripts()
|
|
46 |
// Load codemirror javascript
|
47 |
wp_enqueue_script( 'simple-css-codemirror-js', plugin_dir_url( __FILE__ ) . 'js/codemirror.js', array( 'jquery' ), null );
|
48 |
wp_enqueue_script( 'simple-css-js', plugin_dir_url( __FILE__ ) . 'js/css.js', array( 'jquery' ), null );
|
|
|
|
|
|
|
49 |
|
50 |
// Load codemirror CSS
|
51 |
wp_enqueue_style( 'simple-css-codemirror-css', plugin_dir_url( __FILE__ ) . 'css/codemirror.css', null, null );
|
@@ -112,7 +115,8 @@ function simple_css_editor()
|
|
112 |
<div class="postbox">
|
113 |
<h3 class="hndle"><span><?php _e( 'GeneratePress', 'simple-css' ); ?></span></h3>
|
114 |
<div class="inside">
|
115 |
-
<p><?php printf( __( 'Check out our free WordPress theme, %s.', 'simple-css' ), '<a href="https://generatepress.com
|
|
|
116 |
</div>
|
117 |
</div>
|
118 |
|
@@ -137,6 +141,7 @@ function simple_css_editor()
|
|
137 |
function simple_css_validate( $input )
|
138 |
{
|
139 |
$input['css'] = wp_kses( $input['css'], array( '\'', '\"', '>', '+' ) );
|
|
|
140 |
$input['theme'] = wp_filter_nohtml_kses($input['theme']);
|
141 |
return $input;
|
142 |
}
|
@@ -192,9 +197,10 @@ function simple_css_generate()
|
|
192 |
|
193 |
// Strip tabs and line breaks from our CSS
|
194 |
$output = str_replace(array("\r", "\n"), '', $output);
|
|
|
195 |
|
196 |
// Finally, print it
|
197 |
echo '<style type="text/css">';
|
198 |
echo $output;
|
199 |
-
echo '</style><!-- Generated by Simple CSS -->';
|
200 |
}
|
3 |
Plugin Name: Simple CSS
|
4 |
Plugin URI: https://generatepress.com
|
5 |
Description: Simply add CSS to your WordPress site using an awesome CSS editor or the live Customizer.
|
6 |
+
Version: 0.2
|
7 |
Author: Tom Usborne
|
8 |
Author URI: http://edge22.com
|
9 |
License: GNU General Public License v2 or later
|
46 |
// Load codemirror javascript
|
47 |
wp_enqueue_script( 'simple-css-codemirror-js', plugin_dir_url( __FILE__ ) . 'js/codemirror.js', array( 'jquery' ), null );
|
48 |
wp_enqueue_script( 'simple-css-js', plugin_dir_url( __FILE__ ) . 'js/css.js', array( 'jquery' ), null );
|
49 |
+
wp_enqueue_script( 'simple-css-search', plugin_dir_url( __FILE__ ) . 'js/search.js', array( 'jquery' ), null );
|
50 |
+
wp_enqueue_script( 'simple-css-search-cursor', plugin_dir_url( __FILE__ ) . 'js/searchcursor.js', array( 'jquery' ), null );
|
51 |
+
wp_enqueue_script( 'simple-css-dialog', plugin_dir_url( __FILE__ ) . 'js/dialog.js', array( 'jquery' ), null );
|
52 |
|
53 |
// Load codemirror CSS
|
54 |
wp_enqueue_style( 'simple-css-codemirror-css', plugin_dir_url( __FILE__ ) . 'css/codemirror.css', null, null );
|
115 |
<div class="postbox">
|
116 |
<h3 class="hndle"><span><?php _e( 'GeneratePress', 'simple-css' ); ?></span></h3>
|
117 |
<div class="inside">
|
118 |
+
<p><?php printf( __( 'Check out our free WordPress theme, %s.', 'simple-css' ), '<a href="https://generatepress.com/?utm_source=simplecss&utm_medium=plugin&utm_campaign=Simple%20CSS
|
119 |
+
" target="_blank">GeneratePress</a>' ); ?></p>
|
120 |
</div>
|
121 |
</div>
|
122 |
|
141 |
function simple_css_validate( $input )
|
142 |
{
|
143 |
$input['css'] = wp_kses( $input['css'], array( '\'', '\"', '>', '+' ) );
|
144 |
+
$input['css'] = str_replace( '>', '>', $input['css'] );
|
145 |
$input['theme'] = wp_filter_nohtml_kses($input['theme']);
|
146 |
return $input;
|
147 |
}
|
197 |
|
198 |
// Strip tabs and line breaks from our CSS
|
199 |
$output = str_replace(array("\r", "\n"), '', $output);
|
200 |
+
$output = preg_replace('/\s+/', ' ', $output);
|
201 |
|
202 |
// Finally, print it
|
203 |
echo '<style type="text/css">';
|
204 |
echo $output;
|
205 |
+
echo '</style><!-- Generated by Simple CSS - https://wordpress.org/plugins/simple-css/ -->';
|
206 |
}
|