refinerycms-codemirror 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ #= require ./codemirror
2
+ #= require ./xml
3
+
4
+ # Override the refinery skin for WYMeditor
5
+ skin = WYMeditor.SKINS["refinery"]
6
+
7
+ $.extend skin,
8
+ super: skin.init,
9
+
10
+ init: (wym) ->
11
+ this.super(wym)
12
+ textarea = wym._element.get(0)
13
+ container = $(textarea).parent()
14
+ mainPanel = $(".wym_area_main", container)
15
+ section = $("<div/>").addClass("wym_codemirror wym_section").appendTo(mainPanel)
16
+
17
+ # build the codemirror textarea
18
+ codemirror = CodeMirror.fromTextArea(textarea,
19
+ lineNumbers: true
20
+ matchBrackets: true
21
+ mode: "text/html"
22
+ enterMode: "keep"
23
+ tabMode: "shift"
24
+ htmlMode: true
25
+ indentUnit: 2
26
+ onChange: -> # keep wym updated
27
+ html = codemirror.getValue()
28
+ wym.html(html)
29
+ )
30
+
31
+ # move the editor into the proper place
32
+ $(".CodeMirror", container).detach().appendTo(section)
33
+
34
+ # remove the textarea section
35
+ $(".wym_html", container).remove()
36
+
37
+ # click handler for the html button
38
+ $(".wym_tools_html a").click ->
39
+ $(".wym_iframe, .wym_codemirror", container).toggle()
40
+ codemirror.refresh() # codemirror must be refreshed if it was hidden
@@ -0,0 +1,325 @@
1
+ CodeMirror.defineMode("xml", function(config, parserConfig) {
2
+ var indentUnit = config.indentUnit;
3
+ var Kludges = parserConfig.htmlMode ? {
4
+ autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
5
+ 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
6
+ 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
7
+ 'track': true, 'wbr': true},
8
+ implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
9
+ 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
10
+ 'th': true, 'tr': true},
11
+ contextGrabbers: {
12
+ 'dd': {'dd': true, 'dt': true},
13
+ 'dt': {'dd': true, 'dt': true},
14
+ 'li': {'li': true},
15
+ 'option': {'option': true, 'optgroup': true},
16
+ 'optgroup': {'optgroup': true},
17
+ 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
18
+ 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
19
+ 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
20
+ 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
21
+ 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
22
+ 'rp': {'rp': true, 'rt': true},
23
+ 'rt': {'rp': true, 'rt': true},
24
+ 'tbody': {'tbody': true, 'tfoot': true},
25
+ 'td': {'td': true, 'th': true},
26
+ 'tfoot': {'tbody': true},
27
+ 'th': {'td': true, 'th': true},
28
+ 'thead': {'tbody': true, 'tfoot': true},
29
+ 'tr': {'tr': true}
30
+ },
31
+ doNotIndent: {"pre": true},
32
+ allowUnquoted: true,
33
+ allowMissing: false
34
+ } : {
35
+ autoSelfClosers: {},
36
+ implicitlyClosed: {},
37
+ contextGrabbers: {},
38
+ doNotIndent: {},
39
+ allowUnquoted: false,
40
+ allowMissing: false
41
+ };
42
+ var alignCDATA = parserConfig.alignCDATA;
43
+
44
+ // Return variables for tokenizers
45
+ var tagName, type;
46
+
47
+ function inText(stream, state) {
48
+ function chain(parser) {
49
+ state.tokenize = parser;
50
+ return parser(stream, state);
51
+ }
52
+
53
+ var ch = stream.next();
54
+ if (ch == "<") {
55
+ if (stream.eat("!")) {
56
+ if (stream.eat("[")) {
57
+ if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
58
+ else return null;
59
+ }
60
+ else if (stream.match("--")) return chain(inBlock("comment", "-->"));
61
+ else if (stream.match("DOCTYPE", true, true)) {
62
+ stream.eatWhile(/[\w\._\-]/);
63
+ return chain(doctype(1));
64
+ }
65
+ else return null;
66
+ }
67
+ else if (stream.eat("?")) {
68
+ stream.eatWhile(/[\w\._\-]/);
69
+ state.tokenize = inBlock("meta", "?>");
70
+ return "meta";
71
+ }
72
+ else {
73
+ type = stream.eat("/") ? "closeTag" : "openTag";
74
+ stream.eatSpace();
75
+ tagName = "";
76
+ var c;
77
+ while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
78
+ state.tokenize = inTag;
79
+ return "tag";
80
+ }
81
+ }
82
+ else if (ch == "&") {
83
+ var ok;
84
+ if (stream.eat("#")) {
85
+ if (stream.eat("x")) {
86
+ ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
87
+ } else {
88
+ ok = stream.eatWhile(/[\d]/) && stream.eat(";");
89
+ }
90
+ } else {
91
+ ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
92
+ }
93
+ return ok ? "atom" : "error";
94
+ }
95
+ else {
96
+ stream.eatWhile(/[^&<]/);
97
+ return null;
98
+ }
99
+ }
100
+
101
+ function inTag(stream, state) {
102
+ var ch = stream.next();
103
+ if (ch == ">" || (ch == "/" && stream.eat(">"))) {
104
+ state.tokenize = inText;
105
+ type = ch == ">" ? "endTag" : "selfcloseTag";
106
+ return "tag";
107
+ }
108
+ else if (ch == "=") {
109
+ type = "equals";
110
+ return null;
111
+ }
112
+ else if (/[\'\"]/.test(ch)) {
113
+ state.tokenize = inAttribute(ch);
114
+ return state.tokenize(stream, state);
115
+ }
116
+ else {
117
+ stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
118
+ return "word";
119
+ }
120
+ }
121
+
122
+ function inAttribute(quote) {
123
+ return function(stream, state) {
124
+ while (!stream.eol()) {
125
+ if (stream.next() == quote) {
126
+ state.tokenize = inTag;
127
+ break;
128
+ }
129
+ }
130
+ return "string";
131
+ };
132
+ }
133
+
134
+ function inBlock(style, terminator) {
135
+ return function(stream, state) {
136
+ while (!stream.eol()) {
137
+ if (stream.match(terminator)) {
138
+ state.tokenize = inText;
139
+ break;
140
+ }
141
+ stream.next();
142
+ }
143
+ return style;
144
+ };
145
+ }
146
+ function doctype(depth) {
147
+ return function(stream, state) {
148
+ var ch;
149
+ while ((ch = stream.next()) != null) {
150
+ if (ch == "<") {
151
+ state.tokenize = doctype(depth + 1);
152
+ return state.tokenize(stream, state);
153
+ } else if (ch == ">") {
154
+ if (depth == 1) {
155
+ state.tokenize = inText;
156
+ break;
157
+ } else {
158
+ state.tokenize = doctype(depth - 1);
159
+ return state.tokenize(stream, state);
160
+ }
161
+ }
162
+ }
163
+ return "meta";
164
+ };
165
+ }
166
+
167
+ var curState, setStyle;
168
+ function pass() {
169
+ for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
170
+ }
171
+ function cont() {
172
+ pass.apply(null, arguments);
173
+ return true;
174
+ }
175
+
176
+ function pushContext(tagName, startOfLine) {
177
+ var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
178
+ curState.context = {
179
+ prev: curState.context,
180
+ tagName: tagName,
181
+ indent: curState.indented,
182
+ startOfLine: startOfLine,
183
+ noIndent: noIndent
184
+ };
185
+ }
186
+ function popContext() {
187
+ if (curState.context) curState.context = curState.context.prev;
188
+ }
189
+
190
+ function element(type) {
191
+ if (type == "openTag") {
192
+ curState.tagName = tagName;
193
+ return cont(attributes, endtag(curState.startOfLine));
194
+ } else if (type == "closeTag") {
195
+ var err = false;
196
+ if (curState.context) {
197
+ if (curState.context.tagName != tagName) {
198
+ if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
199
+ popContext();
200
+ }
201
+ err = !curState.context || curState.context.tagName != tagName;
202
+ }
203
+ } else {
204
+ err = true;
205
+ }
206
+ if (err) setStyle = "error";
207
+ return cont(endclosetag(err));
208
+ }
209
+ return cont();
210
+ }
211
+ function endtag(startOfLine) {
212
+ return function(type) {
213
+ if (type == "selfcloseTag" ||
214
+ (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase()))) {
215
+ maybePopContext(curState.tagName.toLowerCase());
216
+ return cont();
217
+ }
218
+ if (type == "endTag") {
219
+ maybePopContext(curState.tagName.toLowerCase());
220
+ pushContext(curState.tagName, startOfLine);
221
+ return cont();
222
+ }
223
+ return cont();
224
+ };
225
+ }
226
+ function endclosetag(err) {
227
+ return function(type) {
228
+ if (err) setStyle = "error";
229
+ if (type == "endTag") { popContext(); return cont(); }
230
+ setStyle = "error";
231
+ return cont(arguments.callee);
232
+ }
233
+ }
234
+ function maybePopContext(nextTagName) {
235
+ var parentTagName;
236
+ while (true) {
237
+ if (!curState.context) {
238
+ return;
239
+ }
240
+ parentTagName = curState.context.tagName.toLowerCase();
241
+ if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
242
+ !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
243
+ return;
244
+ }
245
+ popContext();
246
+ }
247
+ }
248
+
249
+ function attributes(type) {
250
+ if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
251
+ if (type == "endTag" || type == "selfcloseTag") return pass();
252
+ setStyle = "error";
253
+ return cont(attributes);
254
+ }
255
+ function attribute(type) {
256
+ if (type == "equals") return cont(attvalue, attributes);
257
+ if (!Kludges.allowMissing) setStyle = "error";
258
+ return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
259
+ }
260
+ function attvalue(type) {
261
+ if (type == "string") return cont(attvaluemaybe);
262
+ if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
263
+ setStyle = "error";
264
+ return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
265
+ }
266
+ function attvaluemaybe(type) {
267
+ if (type == "string") return cont(attvaluemaybe);
268
+ else return pass();
269
+ }
270
+
271
+ return {
272
+ startState: function() {
273
+ return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
274
+ },
275
+
276
+ token: function(stream, state) {
277
+ if (stream.sol()) {
278
+ state.startOfLine = true;
279
+ state.indented = stream.indentation();
280
+ }
281
+ if (stream.eatSpace()) return null;
282
+
283
+ setStyle = type = tagName = null;
284
+ var style = state.tokenize(stream, state);
285
+ state.type = type;
286
+ if ((style || type) && style != "comment") {
287
+ curState = state;
288
+ while (true) {
289
+ var comb = state.cc.pop() || element;
290
+ if (comb(type || style)) break;
291
+ }
292
+ }
293
+ state.startOfLine = false;
294
+ return setStyle || style;
295
+ },
296
+
297
+ indent: function(state, textAfter, fullLine) {
298
+ var context = state.context;
299
+ if ((state.tokenize != inTag && state.tokenize != inText) ||
300
+ context && context.noIndent)
301
+ return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
302
+ if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
303
+ if (context && /^<\//.test(textAfter))
304
+ context = context.prev;
305
+ while (context && !context.startOfLine)
306
+ context = context.prev;
307
+ if (context) return context.indent + indentUnit;
308
+ else return 0;
309
+ },
310
+
311
+ compareStates: function(a, b) {
312
+ if (a.indented != b.indented || a.tokenize != b.tokenize) return false;
313
+ for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
314
+ if (!ca || !cb) return ca == cb;
315
+ if (ca.tagName != cb.tagName) return false;
316
+ }
317
+ },
318
+
319
+ electricChars: "/"
320
+ };
321
+ });
322
+
323
+ CodeMirror.defineMIME("application/xml", "xml");
324
+ if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
325
+ CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
@@ -0,0 +1,137 @@
1
+ .wym_skin_refinery .wym_codemirror {
2
+ background-color: white;
3
+ display: none;
4
+ }
5
+
6
+ .CodeMirror {
7
+ width: 100% !important;
8
+ height: 400px;
9
+ border: 1px solid #CCC;
10
+ background: white;
11
+ line-height: 1em;
12
+ font-family: monospace;
13
+ }
14
+
15
+ .CodeMirror-scroll {
16
+ line-height: 15px;
17
+ height: 100%;
18
+ overflow: auto;
19
+ height: 300px;
20
+ /* This is needed to prevent an IE[67] bug where the scrolled content
21
+ is visible outside of the scrolling box. */
22
+ position: relative;
23
+ outline: none;
24
+ }
25
+
26
+ .CodeMirror-gutter {
27
+ position: absolute; left: 0; top: 0;
28
+ z-index: 10;
29
+ background-color: #f7f7f7;
30
+ border-right: 1px solid #eee;
31
+ min-width: 2em;
32
+ height: 100%;
33
+ }
34
+ .CodeMirror-gutter-text {
35
+ color: #aaa;
36
+ text-align: right;
37
+ padding: .4em .2em .4em .4em;
38
+ white-space: pre !important;
39
+ }
40
+ .CodeMirror-lines {
41
+ padding: .4em;
42
+ white-space: pre;
43
+ }
44
+
45
+ .CodeMirror pre {
46
+ -moz-border-radius: 0;
47
+ -webkit-border-radius: 0;
48
+ -o-border-radius: 0;
49
+ border-radius: 0;
50
+ border-width: 0; margin: 0; padding: 0; background: transparent;
51
+ font-family: inherit;
52
+ font-size: inherit;
53
+ padding: 0; margin: 0;
54
+ white-space: pre;
55
+ word-wrap: normal;
56
+ line-height: inherit;
57
+ color: inherit;
58
+ }
59
+
60
+ .CodeMirror-wrap pre {
61
+ word-wrap: break-word;
62
+ white-space: pre-wrap;
63
+ word-break: normal;
64
+ }
65
+ .CodeMirror-wrap .CodeMirror-scroll {
66
+ overflow-x: hidden;
67
+ }
68
+
69
+ .CodeMirror textarea {
70
+ outline: none !important;
71
+ }
72
+
73
+ .CodeMirror pre.CodeMirror-cursor {
74
+ z-index: 10;
75
+ position: absolute;
76
+ visibility: hidden;
77
+ border-left: 1px solid black;
78
+ border-right: none;
79
+ width: 0;
80
+ }
81
+ .cm-keymap-fat-cursor pre.CodeMirror-cursor {
82
+ width: auto;
83
+ border: 0;
84
+ background: transparent;
85
+ background: rgba(0, 200, 0, .4);
86
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
87
+ }
88
+ /* Kludge to turn off filter in ie9+, which also accepts rgba */
89
+ .cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
90
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
91
+ }
92
+ .CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
93
+ .CodeMirror-focused pre.CodeMirror-cursor {
94
+ visibility: visible;
95
+ }
96
+
97
+ div.CodeMirror-selected { background: #d9d9d9; }
98
+ .CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; }
99
+
100
+ .CodeMirror-searching {
101
+ background: #ffa;
102
+ background: rgba(255, 255, 0, .4);
103
+ }
104
+
105
+ /* Default theme */
106
+
107
+ .cm-s-default span.cm-keyword {color: #708;}
108
+ .cm-s-default span.cm-atom {color: #219;}
109
+ .cm-s-default span.cm-number {color: #164;}
110
+ .cm-s-default span.cm-def {color: #00f;}
111
+ .cm-s-default span.cm-variable {color: black;}
112
+ .cm-s-default span.cm-variable-2 {color: #05a;}
113
+ .cm-s-default span.cm-variable-3 {color: #085;}
114
+ .cm-s-default span.cm-property {color: black;}
115
+ .cm-s-default span.cm-operator {color: black;}
116
+ .cm-s-default span.cm-comment {color: #a50;}
117
+ .cm-s-default span.cm-string {color: #a11;}
118
+ .cm-s-default span.cm-string-2 {color: #f50;}
119
+ .cm-s-default span.cm-meta {color: #555;}
120
+ .cm-s-default span.cm-error {color: #f00;}
121
+ .cm-s-default span.cm-qualifier {color: #555;}
122
+ .cm-s-default span.cm-builtin {color: #30a;}
123
+ .cm-s-default span.cm-bracket {color: #cc7;}
124
+ .cm-s-default span.cm-tag {color: #170;}
125
+ .cm-s-default span.cm-attribute {color: #00c;}
126
+ .cm-s-default span.cm-header {color: blue;}
127
+ .cm-s-default span.cm-quote {color: #090;}
128
+ .cm-s-default span.cm-hr {color: #999;}
129
+ .cm-s-default span.cm-link {color: #00c;}
130
+
131
+ span.cm-header, span.cm-strong {font-weight: bold;}
132
+ span.cm-em {font-style: italic;}
133
+ span.cm-emstrong {font-style: italic; font-weight: bold;}
134
+ span.cm-link {text-decoration: underline;}
135
+
136
+ div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
137
+ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}