Simple CSS - Version 0.2

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 Icon 128x128 Simple CSS
Version 0.2
Comparing to
See all releases

Code changes from version 0.1 to 0.2

Files changed (7) hide show
  1. css/style.css +34 -8
  2. customize/css-control.php +1 -1
  3. js/dialog.js +157 -0
  4. js/search.js +228 -0
  5. js/searchcursor.js +189 -0
  6. readme.txt +14 -2
  7. simple-css.php +9 -3
css/style.css CHANGED
@@ -1,12 +1,5 @@
1
  .CodeMirror {
2
- /* Firefox */
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.1
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.1
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" target="_blank">GeneratePress</a>' ); ?></p>
 
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( '&gt;', '>', $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
  }