vinsol_spree_themes 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ });