vinsol_spree_themes 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.ruby-version +1 -0
  4. data/Appraisals +16 -0
  5. data/Gemfile +9 -0
  6. data/Gemfile.lock +386 -0
  7. data/LICENSE +26 -0
  8. data/README.md +250 -0
  9. data/Rakefile +21 -0
  10. data/app/assets/javascripts/spree/backend/codemirror/codemirror.js +9351 -0
  11. data/app/assets/javascripts/spree/backend/codemirror/css-hint.js +60 -0
  12. data/app/assets/javascripts/spree/backend/codemirror/fullscreen.js +41 -0
  13. data/app/assets/javascripts/spree/backend/codemirror/html-hint.js +348 -0
  14. data/app/assets/javascripts/spree/backend/codemirror/javascript-hint.js +155 -0
  15. data/app/assets/javascripts/spree/backend/codemirror/javascript.js +813 -0
  16. data/app/assets/javascripts/spree/backend/codemirror/markdown.js +796 -0
  17. data/app/assets/javascripts/spree/backend/codemirror/ruby.js +295 -0
  18. data/app/assets/javascripts/spree/backend/codemirror/show-hint.js +438 -0
  19. data/app/assets/javascripts/spree/backend/editor.js +11 -0
  20. data/app/assets/javascripts/spree/backend/jquery.treemenu.js +87 -0
  21. data/app/assets/javascripts/spree/backend/main.js +26 -0
  22. data/app/assets/javascripts/spree/backend/spree_themes.js +2 -0
  23. data/app/assets/javascripts/spree/backend/template.js +51 -0
  24. data/app/assets/javascripts/spree/backend/theme.js +17 -0
  25. data/app/assets/javascripts/spree/frontend/spree_themes.js +2 -0
  26. data/app/assets/stylesheets/spree/backend/codemirror/codemirror.css +340 -0
  27. data/app/assets/stylesheets/spree/backend/codemirror/fullscreen.css +6 -0
  28. data/app/assets/stylesheets/spree/backend/codemirror/show-hint.css +36 -0
  29. data/app/assets/stylesheets/spree/backend/editor.css +7 -0
  30. data/app/assets/stylesheets/spree/backend/jquery.treemenu.css +8 -0
  31. data/app/assets/stylesheets/spree/backend/spree_themes.css +7 -0
  32. data/app/assets/stylesheets/spree/backend/style.css +239 -0
  33. data/app/assets/stylesheets/spree/backend/template_editor.css +39 -0
  34. data/app/assets/stylesheets/spree/frontend/spree_themes.css +6 -0
  35. data/app/assets/stylesheets/spree/frontend/theme_preview.css +9 -0
  36. data/app/controllers/spree/admin/themes_controller.rb +80 -0
  37. data/app/controllers/spree/admin/themes_preview_controller.rb +30 -0
  38. data/app/controllers/spree/admin/themes_templates_controller.rb +60 -0
  39. data/app/controllers/spree/fragment_cache_controller.rb +13 -0
  40. data/app/controllers/spree/store_controller_decorator.rb +37 -0
  41. data/app/helpers/spree/base_helper_decorator.rb +45 -0
  42. data/app/models/spree/theme.rb +153 -0
  43. data/app/models/spree/themes_template.rb +67 -0
  44. data/app/models/spree/themes_template/cache_resolver.rb +37 -0
  45. data/app/overrides/spree/add_preview_bar_to_store.html.rb +6 -0
  46. data/app/overrides/spree/add_theme_meta_details_to_store.html.rb +6 -0
  47. data/app/overrides/spree/admin/add_themes_tab.html.rb +6 -0
  48. data/app/services/assets_precompiler_service.rb +86 -0
  49. data/app/services/file_generator_service.rb +29 -0
  50. data/app/services/template_generator_service.rb +101 -0
  51. data/app/services/zip_file_builder.rb +87 -0
  52. data/app/services/zip_file_extractor.rb +52 -0
  53. data/app/views/spree/admin/shared/_theme_menu_button.html.erb +5 -0
  54. data/app/views/spree/admin/themes/_themes.html.erb +44 -0
  55. data/app/views/spree/admin/themes/_upload.html.erb +17 -0
  56. data/app/views/spree/admin/themes/index.html.erb +50 -0
  57. data/app/views/spree/admin/themes_templates/_editor.html.erb +29 -0
  58. data/app/views/spree/admin/themes_templates/_template.html.erb +12 -0
  59. data/app/views/spree/admin/themes_templates/edit.html.erb +13 -0
  60. data/app/views/spree/admin/themes_templates/edit.js.erb +1 -0
  61. data/app/views/spree/admin/themes_templates/index.html.erb +27 -0
  62. data/app/views/spree/admin/themes_templates/new.html.erb +56 -0
  63. data/app/views/spree/shared/_preview_bar.html.erb +7 -0
  64. data/app/views/spree/shared/_theme_metadata.html.erb +9 -0
  65. data/bin/rails +7 -0
  66. data/config/initializers/assets.rb +24 -0
  67. data/config/initializers/sprockets.rb +85 -0
  68. data/config/locales/en.yml +52 -0
  69. data/config/routes.rb +22 -0
  70. data/db/migrate/20170628072452_vinsol_spree_themes_create_themes_and_themes_templates_table.rb +24 -0
  71. data/gemfiles/spree_3_1.gemfile +8 -0
  72. data/gemfiles/spree_3_2.gemfile +9 -0
  73. data/gemfiles/spree_master.gemfile +9 -0
  74. data/lib/generators/themes/default.zip +0 -0
  75. data/lib/generators/vinsol_spree_themes/install/install_generator.rb +50 -0
  76. data/lib/tasks/sync_templates.rake +47 -0
  77. data/lib/vinsol_spree_themes.rb +3 -0
  78. data/lib/vinsol_spree_themes/engine.rb +22 -0
  79. data/lib/vinsol_spree_themes/factories.rb +6 -0
  80. data/lib/vinsol_spree_themes/version.rb +18 -0
  81. data/spec/spec_helper.rb +93 -0
  82. data/vinsol_spree_themes.gemspec +43 -0
  83. metadata +374 -0
@@ -0,0 +1,796 @@
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("../xml/xml"), require("../meta"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../xml/xml", "../meta"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
15
+
16
+ var htmlMode = CodeMirror.getMode(cmCfg, "text/html");
17
+ var htmlModeMissing = htmlMode.name == "null"
18
+
19
+ function getMode(name) {
20
+ if (CodeMirror.findModeByName) {
21
+ var found = CodeMirror.findModeByName(name);
22
+ if (found) name = found.mime || found.mimes[0];
23
+ }
24
+ var mode = CodeMirror.getMode(cmCfg, name);
25
+ return mode.name == "null" ? null : mode;
26
+ }
27
+
28
+ // Should characters that affect highlighting be highlighted separate?
29
+ // Does not include characters that will be output (such as `1.` and `-` for lists)
30
+ if (modeCfg.highlightFormatting === undefined)
31
+ modeCfg.highlightFormatting = false;
32
+
33
+ // Maximum number of nested blockquotes. Set to 0 for infinite nesting.
34
+ // Excess `>` will emit `error` token.
35
+ if (modeCfg.maxBlockquoteDepth === undefined)
36
+ modeCfg.maxBlockquoteDepth = 0;
37
+
38
+ // Use `fencedCodeBlocks` to configure fenced code blocks. false to
39
+ // disable, string to specify a precise regexp that the fence should
40
+ // match, and true to allow three or more backticks or tildes (as
41
+ // per CommonMark).
42
+
43
+ // Turn on task lists? ("- [ ] " and "- [x] ")
44
+ if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
45
+
46
+ // Turn on strikethrough syntax
47
+ if (modeCfg.strikethrough === undefined)
48
+ modeCfg.strikethrough = false;
49
+
50
+ // Allow token types to be overridden by user-provided token types.
51
+ if (modeCfg.tokenTypeOverrides === undefined)
52
+ modeCfg.tokenTypeOverrides = {};
53
+
54
+ var tokenTypes = {
55
+ header: "header",
56
+ code: "comment",
57
+ quote: "quote",
58
+ list1: "variable-2",
59
+ list2: "variable-3",
60
+ list3: "keyword",
61
+ hr: "hr",
62
+ image: "image",
63
+ imageAltText: "image-alt-text",
64
+ imageMarker: "image-marker",
65
+ formatting: "formatting",
66
+ linkInline: "link",
67
+ linkEmail: "link",
68
+ linkText: "link",
69
+ linkHref: "string",
70
+ em: "em",
71
+ strong: "strong",
72
+ strikethrough: "strikethrough"
73
+ };
74
+
75
+ for (var tokenType in tokenTypes) {
76
+ if (tokenTypes.hasOwnProperty(tokenType) && modeCfg.tokenTypeOverrides[tokenType]) {
77
+ tokenTypes[tokenType] = modeCfg.tokenTypeOverrides[tokenType];
78
+ }
79
+ }
80
+
81
+ var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/
82
+ , listRE = /^(?:[*\-+]|^[0-9]+([.)]))\s+/
83
+ , taskListRE = /^\[(x| )\](?=\s)/ // Must follow listRE
84
+ , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/
85
+ , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/
86
+ , textRE = /^[^#!\[\]*_\\<>` "'(~]+/
87
+ , fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) +
88
+ ")[ \\t]*([\\w+#\-]*)")
89
+ , punctuation = /[!\"#$%&\'()*+,\-\.\/:;<=>?@\[\\\]^_`{|}~—]/
90
+
91
+ function switchInline(stream, state, f) {
92
+ state.f = state.inline = f;
93
+ return f(stream, state);
94
+ }
95
+
96
+ function switchBlock(stream, state, f) {
97
+ state.f = state.block = f;
98
+ return f(stream, state);
99
+ }
100
+
101
+ function lineIsEmpty(line) {
102
+ return !line || !/\S/.test(line.string)
103
+ }
104
+
105
+ // Blocks
106
+
107
+ function blankLine(state) {
108
+ // Reset linkTitle state
109
+ state.linkTitle = false;
110
+ // Reset EM state
111
+ state.em = false;
112
+ // Reset STRONG state
113
+ state.strong = false;
114
+ // Reset strikethrough state
115
+ state.strikethrough = false;
116
+ // Reset state.quote
117
+ state.quote = 0;
118
+ // Reset state.indentedCode
119
+ state.indentedCode = false;
120
+ if (state.f == htmlBlock) {
121
+ state.f = inlineNormal;
122
+ state.block = blockNormal;
123
+ }
124
+ // Reset state.trailingSpace
125
+ state.trailingSpace = 0;
126
+ state.trailingSpaceNewLine = false;
127
+ // Mark this line as blank
128
+ state.prevLine = state.thisLine
129
+ state.thisLine = null
130
+ return null;
131
+ }
132
+
133
+ function blockNormal(stream, state) {
134
+
135
+ var sol = stream.sol();
136
+
137
+ var prevLineIsList = state.list !== false,
138
+ prevLineIsIndentedCode = state.indentedCode;
139
+
140
+ state.indentedCode = false;
141
+
142
+ if (prevLineIsList) {
143
+ if (state.indentationDiff >= 0) { // Continued list
144
+ if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
145
+ state.indentation -= state.indentationDiff;
146
+ }
147
+ state.list = null;
148
+ } else if (state.indentation > 0) {
149
+ state.list = null;
150
+ } else { // No longer a list
151
+ state.list = false;
152
+ }
153
+ }
154
+
155
+ var match = null;
156
+ if (state.indentationDiff >= 4) {
157
+ stream.skipToEnd();
158
+ if (prevLineIsIndentedCode || lineIsEmpty(state.prevLine)) {
159
+ state.indentation -= 4;
160
+ state.indentedCode = true;
161
+ return tokenTypes.code;
162
+ } else {
163
+ return null;
164
+ }
165
+ } else if (stream.eatSpace()) {
166
+ return null;
167
+ } else if ((match = stream.match(atxHeaderRE)) && match[1].length <= 6) {
168
+ state.header = match[1].length;
169
+ if (modeCfg.highlightFormatting) state.formatting = "header";
170
+ state.f = state.inline;
171
+ return getType(state);
172
+ } else if (!lineIsEmpty(state.prevLine) && !state.quote && !prevLineIsList &&
173
+ !prevLineIsIndentedCode && (match = stream.match(setextHeaderRE))) {
174
+ state.header = match[0].charAt(0) == '=' ? 1 : 2;
175
+ if (modeCfg.highlightFormatting) state.formatting = "header";
176
+ state.f = state.inline;
177
+ return getType(state);
178
+ } else if (stream.eat('>')) {
179
+ state.quote = sol ? 1 : state.quote + 1;
180
+ if (modeCfg.highlightFormatting) state.formatting = "quote";
181
+ stream.eatSpace();
182
+ return getType(state);
183
+ } else if (stream.peek() === '[') {
184
+ return switchInline(stream, state, footnoteLink);
185
+ } else if (stream.match(hrRE, true)) {
186
+ state.hr = true;
187
+ return tokenTypes.hr;
188
+ } else if (match = stream.match(listRE)) {
189
+ var listType = match[1] ? "ol" : "ul";
190
+ state.indentation = stream.column() + stream.current().length;
191
+ state.list = true;
192
+
193
+ // While this list item's marker's indentation
194
+ // is less than the deepest list item's content's indentation,
195
+ // pop the deepest list item indentation off the stack.
196
+ while (state.listStack && stream.column() < state.listStack[state.listStack.length - 1]) {
197
+ state.listStack.pop();
198
+ }
199
+
200
+ // Add this list item's content's indentation to the stack
201
+ state.listStack.push(state.indentation);
202
+
203
+ if (modeCfg.taskLists && stream.match(taskListRE, false)) {
204
+ state.taskList = true;
205
+ }
206
+ state.f = state.inline;
207
+ if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
208
+ return getType(state);
209
+ } else if (modeCfg.fencedCodeBlocks && (match = stream.match(fencedCodeRE, true))) {
210
+ state.fencedChars = match[1]
211
+ // try switching mode
212
+ state.localMode = getMode(match[2]);
213
+ if (state.localMode) state.localState = CodeMirror.startState(state.localMode);
214
+ state.f = state.block = local;
215
+ if (modeCfg.highlightFormatting) state.formatting = "code-block";
216
+ state.code = -1
217
+ return getType(state);
218
+ }
219
+
220
+ return switchInline(stream, state, state.inline);
221
+ }
222
+
223
+ function htmlBlock(stream, state) {
224
+ var style = htmlMode.token(stream, state.htmlState);
225
+ if (!htmlModeMissing) {
226
+ var inner = CodeMirror.innerMode(htmlMode, state.htmlState)
227
+ if ((inner.mode.name == "xml" && inner.state.tagStart === null &&
228
+ (!inner.state.context && inner.state.tokenize.isInText)) ||
229
+ (state.md_inside && stream.current().indexOf(">") > -1)) {
230
+ state.f = inlineNormal;
231
+ state.block = blockNormal;
232
+ state.htmlState = null;
233
+ }
234
+ }
235
+ return style;
236
+ }
237
+
238
+ function local(stream, state) {
239
+ if (state.fencedChars && stream.match(state.fencedChars)) {
240
+ if (modeCfg.highlightFormatting) state.formatting = "code-block";
241
+ var returnType = getType(state)
242
+ state.localMode = state.localState = null;
243
+ state.block = blockNormal;
244
+ state.f = inlineNormal;
245
+ state.fencedChars = null;
246
+ state.code = 0
247
+ return returnType;
248
+ } else if (state.fencedChars && stream.skipTo(state.fencedChars)) {
249
+ return "comment"
250
+ } else if (state.localMode) {
251
+ return state.localMode.token(stream, state.localState);
252
+ } else {
253
+ stream.skipToEnd();
254
+ return tokenTypes.code;
255
+ }
256
+ }
257
+
258
+ // Inline
259
+ function getType(state) {
260
+ var styles = [];
261
+
262
+ if (state.formatting) {
263
+ styles.push(tokenTypes.formatting);
264
+
265
+ if (typeof state.formatting === "string") state.formatting = [state.formatting];
266
+
267
+ for (var i = 0; i < state.formatting.length; i++) {
268
+ styles.push(tokenTypes.formatting + "-" + state.formatting[i]);
269
+
270
+ if (state.formatting[i] === "header") {
271
+ styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.header);
272
+ }
273
+
274
+ // Add `formatting-quote` and `formatting-quote-#` for blockquotes
275
+ // Add `error` instead if the maximum blockquote nesting depth is passed
276
+ if (state.formatting[i] === "quote") {
277
+ if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
278
+ styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.quote);
279
+ } else {
280
+ styles.push("error");
281
+ }
282
+ }
283
+ }
284
+ }
285
+
286
+ if (state.taskOpen) {
287
+ styles.push("meta");
288
+ return styles.length ? styles.join(' ') : null;
289
+ }
290
+ if (state.taskClosed) {
291
+ styles.push("property");
292
+ return styles.length ? styles.join(' ') : null;
293
+ }
294
+
295
+ if (state.linkHref) {
296
+ styles.push(tokenTypes.linkHref, "url");
297
+ } else { // Only apply inline styles to non-url text
298
+ if (state.strong) { styles.push(tokenTypes.strong); }
299
+ if (state.em) { styles.push(tokenTypes.em); }
300
+ if (state.strikethrough) { styles.push(tokenTypes.strikethrough); }
301
+ if (state.linkText) { styles.push(tokenTypes.linkText); }
302
+ if (state.code) { styles.push(tokenTypes.code); }
303
+ if (state.image) { styles.push(tokenTypes.image); }
304
+ if (state.imageAltText) { styles.push(tokenTypes.imageAltText, "link"); }
305
+ if (state.imageMarker) { styles.push(tokenTypes.imageMarker); }
306
+ }
307
+
308
+ if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); }
309
+
310
+ if (state.quote) {
311
+ styles.push(tokenTypes.quote);
312
+
313
+ // Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth
314
+ if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
315
+ styles.push(tokenTypes.quote + "-" + state.quote);
316
+ } else {
317
+ styles.push(tokenTypes.quote + "-" + modeCfg.maxBlockquoteDepth);
318
+ }
319
+ }
320
+
321
+ if (state.list !== false) {
322
+ var listMod = (state.listStack.length - 1) % 3;
323
+ if (!listMod) {
324
+ styles.push(tokenTypes.list1);
325
+ } else if (listMod === 1) {
326
+ styles.push(tokenTypes.list2);
327
+ } else {
328
+ styles.push(tokenTypes.list3);
329
+ }
330
+ }
331
+
332
+ if (state.trailingSpaceNewLine) {
333
+ styles.push("trailing-space-new-line");
334
+ } else if (state.trailingSpace) {
335
+ styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b"));
336
+ }
337
+
338
+ return styles.length ? styles.join(' ') : null;
339
+ }
340
+
341
+ function handleText(stream, state) {
342
+ if (stream.match(textRE, true)) {
343
+ return getType(state);
344
+ }
345
+ return undefined;
346
+ }
347
+
348
+ function inlineNormal(stream, state) {
349
+ var style = state.text(stream, state);
350
+ if (typeof style !== 'undefined')
351
+ return style;
352
+
353
+ if (state.list) { // List marker (*, +, -, 1., etc)
354
+ state.list = null;
355
+ return getType(state);
356
+ }
357
+
358
+ if (state.taskList) {
359
+ var taskOpen = stream.match(taskListRE, true)[1] !== "x";
360
+ if (taskOpen) state.taskOpen = true;
361
+ else state.taskClosed = true;
362
+ if (modeCfg.highlightFormatting) state.formatting = "task";
363
+ state.taskList = false;
364
+ return getType(state);
365
+ }
366
+
367
+ state.taskOpen = false;
368
+ state.taskClosed = false;
369
+
370
+ if (state.header && stream.match(/^#+$/, true)) {
371
+ if (modeCfg.highlightFormatting) state.formatting = "header";
372
+ return getType(state);
373
+ }
374
+
375
+ var ch = stream.next();
376
+
377
+ // Matches link titles present on next line
378
+ if (state.linkTitle) {
379
+ state.linkTitle = false;
380
+ var matchCh = ch;
381
+ if (ch === '(') {
382
+ matchCh = ')';
383
+ }
384
+ matchCh = (matchCh+'').replace(/([.?*+^\[\]\\(){}|-])/g, "\\$1");
385
+ var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
386
+ if (stream.match(new RegExp(regex), true)) {
387
+ return tokenTypes.linkHref;
388
+ }
389
+ }
390
+
391
+ // If this block is changed, it may need to be updated in GFM mode
392
+ if (ch === '`') {
393
+ var previousFormatting = state.formatting;
394
+ if (modeCfg.highlightFormatting) state.formatting = "code";
395
+ stream.eatWhile('`');
396
+ var count = stream.current().length
397
+ if (state.code == 0) {
398
+ state.code = count
399
+ return getType(state)
400
+ } else if (count == state.code) { // Must be exact
401
+ var t = getType(state)
402
+ state.code = 0
403
+ return t
404
+ } else {
405
+ state.formatting = previousFormatting
406
+ return getType(state)
407
+ }
408
+ } else if (state.code) {
409
+ return getType(state);
410
+ }
411
+
412
+ if (ch === '\\') {
413
+ stream.next();
414
+ if (modeCfg.highlightFormatting) {
415
+ var type = getType(state);
416
+ var formattingEscape = tokenTypes.formatting + "-escape";
417
+ return type ? type + " " + formattingEscape : formattingEscape;
418
+ }
419
+ }
420
+
421
+ if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
422
+ state.imageMarker = true;
423
+ state.image = true;
424
+ if (modeCfg.highlightFormatting) state.formatting = "image";
425
+ return getType(state);
426
+ }
427
+
428
+ if (ch === '[' && state.imageMarker && stream.match(/[^\]]*\](\(.*?\)| ?\[.*?\])/, false)) {
429
+ state.imageMarker = false;
430
+ state.imageAltText = true
431
+ if (modeCfg.highlightFormatting) state.formatting = "image";
432
+ return getType(state);
433
+ }
434
+
435
+ if (ch === ']' && state.imageAltText) {
436
+ if (modeCfg.highlightFormatting) state.formatting = "image";
437
+ var type = getType(state);
438
+ state.imageAltText = false;
439
+ state.image = false;
440
+ state.inline = state.f = linkHref;
441
+ return type;
442
+ }
443
+
444
+ if (ch === '[' && !state.image) {
445
+ state.linkText = true;
446
+ if (modeCfg.highlightFormatting) state.formatting = "link";
447
+ return getType(state);
448
+ }
449
+
450
+ if (ch === ']' && state.linkText) {
451
+ if (modeCfg.highlightFormatting) state.formatting = "link";
452
+ var type = getType(state);
453
+ state.linkText = false;
454
+ state.inline = state.f = stream.match(/\(.*?\)| ?\[.*?\]/, false) ? linkHref : inlineNormal
455
+ return type;
456
+ }
457
+
458
+ if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) {
459
+ state.f = state.inline = linkInline;
460
+ if (modeCfg.highlightFormatting) state.formatting = "link";
461
+ var type = getType(state);
462
+ if (type){
463
+ type += " ";
464
+ } else {
465
+ type = "";
466
+ }
467
+ return type + tokenTypes.linkInline;
468
+ }
469
+
470
+ if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) {
471
+ state.f = state.inline = linkInline;
472
+ if (modeCfg.highlightFormatting) state.formatting = "link";
473
+ var type = getType(state);
474
+ if (type){
475
+ type += " ";
476
+ } else {
477
+ type = "";
478
+ }
479
+ return type + tokenTypes.linkEmail;
480
+ }
481
+
482
+ if (ch === '<' && stream.match(/^(!--|[a-z]+(?:\s+[a-z_:.\-]+(?:\s*=\s*[^ >]+)?)*\s*>)/i, false)) {
483
+ var end = stream.string.indexOf(">", stream.pos);
484
+ if (end != -1) {
485
+ var atts = stream.string.substring(stream.start, end);
486
+ if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) state.md_inside = true;
487
+ }
488
+ stream.backUp(1);
489
+ state.htmlState = CodeMirror.startState(htmlMode);
490
+ return switchBlock(stream, state, htmlBlock);
491
+ }
492
+
493
+ if (ch === '<' && stream.match(/^\/\w*?>/)) {
494
+ state.md_inside = false;
495
+ return "tag";
496
+ } else if (ch === "*" || ch === "_") {
497
+ var len = 1, before = stream.pos == 1 ? " " : stream.string.charAt(stream.pos - 2)
498
+ while (len < 3 && stream.eat(ch)) len++
499
+ var after = stream.peek() || " "
500
+ // See http://spec.commonmark.org/0.27/#emphasis-and-strong-emphasis
501
+ var leftFlanking = !/\s/.test(after) && (!punctuation.test(after) || /\s/.test(before) || punctuation.test(before))
502
+ var rightFlanking = !/\s/.test(before) && (!punctuation.test(before) || /\s/.test(after) || punctuation.test(after))
503
+ var setEm = null, setStrong = null
504
+ if (len % 2) { // Em
505
+ if (!state.em && leftFlanking && (ch === "*" || !rightFlanking || punctuation.test(before)))
506
+ setEm = true
507
+ else if (state.em == ch && rightFlanking && (ch === "*" || !leftFlanking || punctuation.test(after)))
508
+ setEm = false
509
+ }
510
+ if (len > 1) { // Strong
511
+ if (!state.strong && leftFlanking && (ch === "*" || !rightFlanking || punctuation.test(before)))
512
+ setStrong = true
513
+ else if (state.strong == ch && rightFlanking && (ch === "*" || !leftFlanking || punctuation.test(after)))
514
+ setStrong = false
515
+ }
516
+ if (setStrong != null || setEm != null) {
517
+ if (modeCfg.highlightFormatting) state.formatting = setEm == null ? "strong" : setStrong == null ? "em" : "strong em"
518
+ if (setEm === true) state.em = ch
519
+ if (setStrong === true) state.strong = ch
520
+ var t = getType(state)
521
+ if (setEm === false) state.em = false
522
+ if (setStrong === false) state.strong = false
523
+ return t
524
+ }
525
+ } else if (ch === ' ') {
526
+ if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
527
+ if (stream.peek() === ' ') { // Surrounded by spaces, ignore
528
+ return getType(state);
529
+ } else { // Not surrounded by spaces, back up pointer
530
+ stream.backUp(1);
531
+ }
532
+ }
533
+ }
534
+
535
+ if (modeCfg.strikethrough) {
536
+ if (ch === '~' && stream.eatWhile(ch)) {
537
+ if (state.strikethrough) {// Remove strikethrough
538
+ if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
539
+ var t = getType(state);
540
+ state.strikethrough = false;
541
+ return t;
542
+ } else if (stream.match(/^[^\s]/, false)) {// Add strikethrough
543
+ state.strikethrough = true;
544
+ if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
545
+ return getType(state);
546
+ }
547
+ } else if (ch === ' ') {
548
+ if (stream.match(/^~~/, true)) { // Probably surrounded by space
549
+ if (stream.peek() === ' ') { // Surrounded by spaces, ignore
550
+ return getType(state);
551
+ } else { // Not surrounded by spaces, back up pointer
552
+ stream.backUp(2);
553
+ }
554
+ }
555
+ }
556
+ }
557
+
558
+ if (ch === ' ') {
559
+ if (stream.match(/ +$/, false)) {
560
+ state.trailingSpace++;
561
+ } else if (state.trailingSpace) {
562
+ state.trailingSpaceNewLine = true;
563
+ }
564
+ }
565
+
566
+ return getType(state);
567
+ }
568
+
569
+ function linkInline(stream, state) {
570
+ var ch = stream.next();
571
+
572
+ if (ch === ">") {
573
+ state.f = state.inline = inlineNormal;
574
+ if (modeCfg.highlightFormatting) state.formatting = "link";
575
+ var type = getType(state);
576
+ if (type){
577
+ type += " ";
578
+ } else {
579
+ type = "";
580
+ }
581
+ return type + tokenTypes.linkInline;
582
+ }
583
+
584
+ stream.match(/^[^>]+/, true);
585
+
586
+ return tokenTypes.linkInline;
587
+ }
588
+
589
+ function linkHref(stream, state) {
590
+ // Check if space, and return NULL if so (to avoid marking the space)
591
+ if(stream.eatSpace()){
592
+ return null;
593
+ }
594
+ var ch = stream.next();
595
+ if (ch === '(' || ch === '[') {
596
+ state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]");
597
+ if (modeCfg.highlightFormatting) state.formatting = "link-string";
598
+ state.linkHref = true;
599
+ return getType(state);
600
+ }
601
+ return 'error';
602
+ }
603
+
604
+ var linkRE = {
605
+ ")": /^(?:[^\\\(\)]|\\.|\((?:[^\\\(\)]|\\.)*\))*?(?=\))/,
606
+ "]": /^(?:[^\\\[\]]|\\.|\[(?:[^\\\[\]]|\\.)*\])*?(?=\])/
607
+ }
608
+
609
+ function getLinkHrefInside(endChar) {
610
+ return function(stream, state) {
611
+ var ch = stream.next();
612
+
613
+ if (ch === endChar) {
614
+ state.f = state.inline = inlineNormal;
615
+ if (modeCfg.highlightFormatting) state.formatting = "link-string";
616
+ var returnState = getType(state);
617
+ state.linkHref = false;
618
+ return returnState;
619
+ }
620
+
621
+ stream.match(linkRE[endChar])
622
+ state.linkHref = true;
623
+ return getType(state);
624
+ };
625
+ }
626
+
627
+ function footnoteLink(stream, state) {
628
+ if (stream.match(/^([^\]\\]|\\.)*\]:/, false)) {
629
+ state.f = footnoteLinkInside;
630
+ stream.next(); // Consume [
631
+ if (modeCfg.highlightFormatting) state.formatting = "link";
632
+ state.linkText = true;
633
+ return getType(state);
634
+ }
635
+ return switchInline(stream, state, inlineNormal);
636
+ }
637
+
638
+ function footnoteLinkInside(stream, state) {
639
+ if (stream.match(/^\]:/, true)) {
640
+ state.f = state.inline = footnoteUrl;
641
+ if (modeCfg.highlightFormatting) state.formatting = "link";
642
+ var returnType = getType(state);
643
+ state.linkText = false;
644
+ return returnType;
645
+ }
646
+
647
+ stream.match(/^([^\]\\]|\\.)+/, true);
648
+
649
+ return tokenTypes.linkText;
650
+ }
651
+
652
+ function footnoteUrl(stream, state) {
653
+ // Check if space, and return NULL if so (to avoid marking the space)
654
+ if(stream.eatSpace()){
655
+ return null;
656
+ }
657
+ // Match URL
658
+ stream.match(/^[^\s]+/, true);
659
+ // Check for link title
660
+ if (stream.peek() === undefined) { // End of line, set flag to check next line
661
+ state.linkTitle = true;
662
+ } else { // More content on line, check if link title
663
+ stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true);
664
+ }
665
+ state.f = state.inline = inlineNormal;
666
+ return tokenTypes.linkHref + " url";
667
+ }
668
+
669
+ var mode = {
670
+ startState: function() {
671
+ return {
672
+ f: blockNormal,
673
+
674
+ prevLine: null,
675
+ thisLine: null,
676
+
677
+ block: blockNormal,
678
+ htmlState: null,
679
+ indentation: 0,
680
+
681
+ inline: inlineNormal,
682
+ text: handleText,
683
+
684
+ formatting: false,
685
+ linkText: false,
686
+ linkHref: false,
687
+ linkTitle: false,
688
+ code: 0,
689
+ em: false,
690
+ strong: false,
691
+ header: 0,
692
+ hr: false,
693
+ taskList: false,
694
+ list: false,
695
+ listStack: [],
696
+ quote: 0,
697
+ trailingSpace: 0,
698
+ trailingSpaceNewLine: false,
699
+ strikethrough: false,
700
+ fencedChars: null
701
+ };
702
+ },
703
+
704
+ copyState: function(s) {
705
+ return {
706
+ f: s.f,
707
+
708
+ prevLine: s.prevLine,
709
+ thisLine: s.thisLine,
710
+
711
+ block: s.block,
712
+ htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState),
713
+ indentation: s.indentation,
714
+
715
+ localMode: s.localMode,
716
+ localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
717
+
718
+ inline: s.inline,
719
+ text: s.text,
720
+ formatting: false,
721
+ linkText: s.linkText,
722
+ linkTitle: s.linkTitle,
723
+ code: s.code,
724
+ em: s.em,
725
+ strong: s.strong,
726
+ strikethrough: s.strikethrough,
727
+ header: s.header,
728
+ hr: s.hr,
729
+ taskList: s.taskList,
730
+ list: s.list,
731
+ listStack: s.listStack.slice(0),
732
+ quote: s.quote,
733
+ indentedCode: s.indentedCode,
734
+ trailingSpace: s.trailingSpace,
735
+ trailingSpaceNewLine: s.trailingSpaceNewLine,
736
+ md_inside: s.md_inside,
737
+ fencedChars: s.fencedChars
738
+ };
739
+ },
740
+
741
+ token: function(stream, state) {
742
+
743
+ // Reset state.formatting
744
+ state.formatting = false;
745
+
746
+ if (stream != state.thisLine) {
747
+ var forceBlankLine = state.header || state.hr;
748
+
749
+ // Reset state.header and state.hr
750
+ state.header = 0;
751
+ state.hr = false;
752
+
753
+ if (stream.match(/^\s*$/, true) || forceBlankLine) {
754
+ blankLine(state);
755
+ if (!forceBlankLine) return null
756
+ state.prevLine = null
757
+ }
758
+
759
+ state.prevLine = state.thisLine
760
+ state.thisLine = stream
761
+
762
+ // Reset state.taskList
763
+ state.taskList = false;
764
+
765
+ // Reset state.trailingSpace
766
+ state.trailingSpace = 0;
767
+ state.trailingSpaceNewLine = false;
768
+
769
+ state.f = state.block;
770
+ var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
771
+ state.indentationDiff = Math.min(indentation - state.indentation, 4);
772
+ state.indentation = state.indentation + state.indentationDiff;
773
+ if (indentation > 0) return null;
774
+ }
775
+ return state.f(stream, state);
776
+ },
777
+
778
+ innerMode: function(state) {
779
+ if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode};
780
+ if (state.localState) return {state: state.localState, mode: state.localMode};
781
+ return {state: state, mode: mode};
782
+ },
783
+
784
+ blankLine: blankLine,
785
+
786
+ getType: getType,
787
+
788
+ closeBrackets: "()[]{}''\"\"``",
789
+ fold: "markdown"
790
+ };
791
+ return mode;
792
+ }, "xml");
793
+
794
+ CodeMirror.defineMIME("text/x-markdown", "markdown");
795
+
796
+ });