kit_cms 2.3.16 → 2.3.17

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 (80) hide show
  1. data/app/assets/images/kit/toolbar/bold.png +0 -0
  2. data/app/assets/images/kit/toolbar/formatted.png +0 -0
  3. data/app/assets/images/kit/toolbar/image.png +0 -0
  4. data/app/assets/images/kit/toolbar/link.png +0 -0
  5. data/app/assets/images/kit/toolbar/list.png +0 -0
  6. data/app/assets/images/kit/toolbar/numbered_list.png +0 -0
  7. data/app/assets/images/kit/toolbar/preview.png +0 -0
  8. data/app/assets/images/kit/toolbar/quote.png +0 -0
  9. data/app/assets/images/kit/toolbar/redo.png +0 -0
  10. data/app/assets/images/kit/toolbar/underline.png +0 -0
  11. data/app/assets/images/kit/toolbar/undo.png +0 -0
  12. data/app/assets/images/kit/toolbar/video.png +0 -0
  13. data/app/assets/javascripts/codemirror/editor.js +183 -0
  14. data/app/assets/javascripts/codemirror/markdown.js +475 -0
  15. data/app/assets/javascripts/jquery.contextmenu.js +7 -7
  16. data/app/assets/javascripts/kit/kit.js +0 -1
  17. data/app/assets/javascripts/kit/markdown.js +1 -37
  18. data/app/assets/javascripts/kit/tree.js +18 -10
  19. data/app/assets/javascripts/kit/utilities.js +1 -1
  20. data/app/assets/stylesheets/codemirror/editor.css +3 -3
  21. data/app/assets/stylesheets/codemirror/theme.css +76 -1
  22. data/app/assets/stylesheets/kit/calendar.css +58 -97
  23. data/app/assets/stylesheets/kit/cms/cms.css +19 -0
  24. data/app/assets/stylesheets/kit/cms/dsc_tree.css +4 -0
  25. data/app/assets/stylesheets/kit/forums.css +30 -0
  26. data/app/assets/stylesheets/kit/kit.css +0 -1
  27. data/app/controllers/admin/dashboard_controller.rb +11 -2
  28. data/app/controllers/admin/page_templates_controller.rb +14 -1
  29. data/app/controllers/admin/user_controller.rb +2 -3
  30. data/app/controllers/category_controller.rb +5 -6
  31. data/app/controllers/form_controller.rb +1 -1
  32. data/app/controllers/forum_controller.rb +2 -2
  33. data/app/controllers/kit_controller.rb +2 -2
  34. data/app/controllers/pages_controller.rb +24 -0
  35. data/app/controllers/user/passwords_controller.rb +2 -0
  36. data/app/controllers/user/registrations_controller.rb +1 -4
  37. data/app/controllers/user/sessions_controller.rb +2 -0
  38. data/app/controllers/user/unlocks_controller.rb +2 -0
  39. data/app/controllers/user_controller.rb +1 -1
  40. data/app/helpers/calendar_helper.rb +4 -1
  41. data/app/helpers/kit_helper.rb +3 -3
  42. data/app/mailers/notification.rb +3 -3
  43. data/app/models/activity.rb +5 -2
  44. data/app/models/calendar.rb +1 -1
  45. data/app/models/category.rb +18 -4
  46. data/app/models/experiment.rb +2 -0
  47. data/app/models/form_submission.rb +2 -2
  48. data/app/models/html_asset.rb +3 -0
  49. data/app/models/mapping.rb +1 -0
  50. data/app/models/user.rb +1 -1
  51. data/app/views/admin/blocks/_form.html.haml +1 -1
  52. data/app/views/admin/dashboard/user_comments.html.haml +19 -8
  53. data/app/views/admin/experiments/show.html.haml +1 -1
  54. data/app/views/admin/form/_form.html.haml +8 -0
  55. data/app/views/admin/page_templates/_form.html.haml +1 -1
  56. data/app/views/admin/views/_form.html.haml +4 -4
  57. data/app/views/calendar/_calendar_scripts.js.erb +2 -2
  58. data/app/views/calendar/_month.html.haml +58 -27
  59. data/app/views/category/_select_options.html.erb +1 -1
  60. data/app/views/form/_show.html.haml +9 -1
  61. data/app/views/forum/_add_post.html.haml +3 -2
  62. data/app/views/forum/_mod_thread.js.erb +2 -2
  63. data/app/views/forum/_post_scripts.js.erb +1 -2
  64. data/app/views/forum/thread.html.haml +4 -0
  65. data/app/views/layouts/_application.html.erb +1 -0
  66. data/app/views/layouts/minimal.html.erb +2 -2
  67. data/app/views/notification/form_submission.text.erb +2 -0
  68. data/app/views/pages/_form.html.haml +7 -8
  69. data/app/views/pages/_page_scripts.js.erb +1 -3
  70. data/app/views/pages/_page_template_script.js.erb +28 -0
  71. data/app/views/pages/cookie_text.html.haml +1 -1
  72. data/app/views/pages/info.html.erb +2 -2
  73. data/app/views/pages/page_template.html.haml +40 -0
  74. data/app/views/utility/_cm_editor.html.erb +34 -5
  75. data/app/views/utility/_cm_toolbar_markdown.html.haml +49 -0
  76. data/config/initializers/devise_extender.rb +9 -0
  77. data/config/initializers/html_assets.rb +4 -0
  78. data/config/initializers/quiet_asserts.rb +1 -1
  79. data/config/routes.rb +2 -0
  80. metadata +21 -3
@@ -5,6 +5,7 @@
5
5
  *= require "./htmlmixed"
6
6
  *= require "./sass"
7
7
  *= require "./css"
8
+ *= require "./markdown"
8
9
  *= require "./xml"
9
10
  *= require "./javascript"
10
11
  *= require "./dialog"
@@ -16,4 +17,186 @@
16
17
  *
17
18
  */
18
19
 
20
+ var html_editors = new Array();
19
21
 
22
+ function do_bold(editor) {
23
+ insert_formatting(editor, "*", "*", "Bold");
24
+ }
25
+
26
+ function do_underline(editor) {
27
+ insert_formatting(editor, "_", "_", "Underlined");
28
+ }
29
+
30
+ function do_cmd(editor, cmd) {
31
+ if (cmd=='list') {
32
+ do_list(editor, '-');
33
+ }
34
+ if (cmd=='numbered_list') {
35
+ do_list(editor, '1.');
36
+ }
37
+ if (cmd=='image') {
38
+ do_image(editor);
39
+ }
40
+ if (cmd=='video') {
41
+ do_video(editor);
42
+ }
43
+ if (cmd=='link') {
44
+ do_link(editor);
45
+ }
46
+ if (cmd=='bold') {
47
+ insert_formatting(editor, '**', '**', 'Bold');
48
+ }
49
+ if (cmd=='underline') {
50
+ insert_formatting(editor, '_', '_', 'Underline');
51
+ }
52
+ if (cmd=='pre') {
53
+ do_prefix(editor, ' ');
54
+ }
55
+ if (cmd=='quote') {
56
+ do_prefix(editor, '> ');
57
+ }
58
+ if (cmd=='undo') {
59
+ do_undo(editor);
60
+ }
61
+ if (cmd=='redo') {
62
+ do_redo(editor);
63
+ }
64
+ if (cmd=='preview') {
65
+ do_preview(editor);
66
+ }
67
+ }
68
+
69
+ function do_prefix(editor, prefix) {
70
+ var editor = html_editors[editor];
71
+ var start_pos = editor.getCursor('start');
72
+ var end_pos = editor.getCursor('end');
73
+
74
+ if (editor.somethingSelected()) {
75
+ for (var i = start_pos.line; i <= end_pos.line; i++) {
76
+ editor.setLine(i, prefix + editor.getLine(i));
77
+ }
78
+ } else {
79
+ if (start_pos.ch==0) {
80
+ editor.replaceSelection(prefix);
81
+ }
82
+ else {
83
+ editor.setLine(start_pos.line, prefix + editor.getLine(start_pos.line));
84
+ }
85
+ start_pos.ch = start_pos.ch + prefix.length;
86
+ editor.setCursor(start_pos);
87
+ }
88
+ editor.focus();
89
+ }
90
+
91
+ function do_link(editor) {
92
+ var url = prompt("Enter the full URL for the link", "http://");
93
+
94
+ insert_formatting(editor, '[', '](' + url + ')', 'Link');
95
+ }
96
+
97
+ function do_video(editor) {
98
+ var editor = html_editors[editor];
99
+ var start_pos = editor.getCursor('start');
100
+ var url = prompt("Enter Youtube 'share' URL or Vimeo URL");
101
+
102
+ editor.replaceSelection(url);
103
+ start_pos.ch = start_pos.ch + url.length;
104
+ editor.setCursor(start_pos);
105
+ editor.focus();
106
+ }
107
+
108
+ function do_undo(editor) {
109
+ var editor = html_editors[editor];
110
+ editor.undo();
111
+ }
112
+
113
+ function do_redo(editor) {
114
+ var editor = html_editors[editor];
115
+ editor.redo();
116
+ }
117
+
118
+ function do_image(editor) {
119
+ var editor = html_editors[editor];
120
+ var url = prompt("Enter the full URL of the image", "http://");
121
+ var start_pos = editor.getCursor('start');
122
+
123
+ editor.replaceSelection("![](" + url + ")");
124
+ start_pos.ch = start_pos.ch + url.length + 5;
125
+ editor.setCursor(start_pos);
126
+ editor.focus();
127
+ }
128
+
129
+ function do_list(editor_name,list) {
130
+ var editor = html_editors[editor_name];
131
+ var start_pos = editor.getCursor('start');
132
+ var end_pos = editor.getCursor('end');
133
+ var to_insert = '';
134
+
135
+ if (editor.somethingSelected()) {
136
+ if (start_pos.line != end_pos.line) {
137
+ do_prefix(editor_name, list);
138
+ return;
139
+ }
140
+ else {
141
+ var selection = editor.getSelection();
142
+ editor.replaceSelection(((start_pos.ch==0) ? '' : '\r') + list + ' ' + selection + '\r' + list + ' ');
143
+ start_pos.line = start_pos.line + 2;
144
+ start_pos.ch = selection.length + list.length;
145
+ }
146
+ editor.setCursor(start_pos);
147
+ }
148
+ else {
149
+ if (start_pos.ch>0) {
150
+ var line = editor.getLine(start_pos.line);
151
+ if (line && line.indexOf(list)==0) {
152
+ editor.setLine(start_pos.line, editor.getLine(start_pos.line) + '\r' + list + ' ');
153
+ }
154
+ else {
155
+ editor.setLine(start_pos.line, list + ' ' + editor.getLine(start_pos.line) + '\r' + list + ' ');
156
+ }
157
+ start_pos.line = start_pos.line + 1;
158
+ editor.setCursor(start_pos);
159
+ } else {
160
+ editor.replaceSelection(list + ' ');
161
+ start_pos.ch = list.length+1;
162
+ editor.setCursor(start_pos);
163
+ }
164
+ }
165
+ editor.focus();
166
+ }
167
+
168
+ function insert_formatting(editor,start,end,placeholder) {
169
+ var editor = html_editors[editor];
170
+ var current = editor.getSelection();
171
+ var placeholder_mode = false;
172
+ var start_pos = editor.getCursor("start");
173
+ var end_pos = editor.getCursor("end");
174
+
175
+ if (!editor.somethingSelected()) {
176
+ current = placeholder;
177
+ placeholder_mode = true;
178
+ }
179
+
180
+ editor.replaceSelection(start + current + end);
181
+ if (placeholder_mode) {
182
+ start_pos.ch = start_pos.ch + start.length;
183
+ end_pos.ch = start_pos.ch + placeholder.length;
184
+ editor.setSelection( start_pos, end_pos);
185
+ }
186
+ else {
187
+ end_pos.ch = end_pos.ch + (start.length*2);
188
+ editor.setCursor(end_pos);
189
+ }
190
+ editor.focus();
191
+ }
192
+
193
+
194
+ function do_preview(field) {
195
+ var editor = html_editors[field];
196
+ $('#preview_' + field).dialog({ autoOpen: true,
197
+ width: 800, height: 500, modal: true, resizable: true, show: {effect:"drop"}, title: "Preview", closeOnEscape: true, dialogClass: "modal_markdown_preview" });
198
+
199
+ $.post('/utility/markdown_preview', {body: editor.getValue()}, function(data) {
200
+ $('#preview_' + field).html(data);
201
+ });
202
+ }
@@ -0,0 +1,475 @@
1
+ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
2
+
3
+ var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html");
4
+ var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain");
5
+ var aliases = {
6
+ html: "htmlmixed",
7
+ js: "javascript",
8
+ json: "application/json",
9
+ c: "text/x-csrc",
10
+ "c++": "text/x-c++src",
11
+ java: "text/x-java",
12
+ csharp: "text/x-csharp",
13
+ "c#": "text/x-csharp",
14
+ scala: "text/x-scala"
15
+ };
16
+
17
+ var getMode = (function () {
18
+ var i, modes = {}, mimes = {}, mime;
19
+
20
+ var list = [];
21
+ for (var m in CodeMirror.modes)
22
+ if (CodeMirror.modes.propertyIsEnumerable(m)) list.push(m);
23
+ for (i = 0; i < list.length; i++) {
24
+ modes[list[i]] = list[i];
25
+ }
26
+ var mimesList = [];
27
+ for (var m in CodeMirror.mimeModes)
28
+ if (CodeMirror.mimeModes.propertyIsEnumerable(m))
29
+ mimesList.push({mime: m, mode: CodeMirror.mimeModes[m]});
30
+ for (i = 0; i < mimesList.length; i++) {
31
+ mime = mimesList[i].mime;
32
+ mimes[mime] = mimesList[i].mime;
33
+ }
34
+
35
+ for (var a in aliases) {
36
+ if (aliases[a] in modes || aliases[a] in mimes)
37
+ modes[a] = aliases[a];
38
+ }
39
+
40
+ return function (lang) {
41
+ return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null;
42
+ };
43
+ }());
44
+
45
+ // Should underscores in words open/close em/strong?
46
+ if (modeCfg.underscoresBreakWords === undefined)
47
+ modeCfg.underscoresBreakWords = true;
48
+
49
+ // Turn on fenced code blocks? ("```" to start/end)
50
+ if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false;
51
+
52
+ var codeDepth = 0;
53
+ var prevLineHasContent = false
54
+ , thisLineHasContent = false;
55
+
56
+ var header = 'header'
57
+ , code = 'comment'
58
+ , quote = 'quote'
59
+ , list = 'string'
60
+ , hr = 'hr'
61
+ , image = 'tag'
62
+ , linkinline = 'link'
63
+ , linkemail = 'link'
64
+ , linktext = 'link'
65
+ , linkhref = 'string'
66
+ , em = 'em'
67
+ , strong = 'strong'
68
+ , emstrong = 'emstrong';
69
+
70
+ var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
71
+ , ulRE = /^[*\-+]\s+/
72
+ , olRE = /^[0-9]+\.\s+/
73
+ , headerRE = /^(?:\={1,}|-{1,})$/
74
+ , textRE = /^[^!\[\]*_\\<>` "'(]+/;
75
+
76
+ function switchInline(stream, state, f) {
77
+ state.f = state.inline = f;
78
+ return f(stream, state);
79
+ }
80
+
81
+ function switchBlock(stream, state, f) {
82
+ state.f = state.block = f;
83
+ return f(stream, state);
84
+ }
85
+
86
+
87
+ // Blocks
88
+
89
+ function blankLine(state) {
90
+ // Reset linkTitle state
91
+ state.linkTitle = false;
92
+ // Reset EM state
93
+ state.em = false;
94
+ // Reset STRONG state
95
+ state.strong = false;
96
+ // Reset state.quote
97
+ state.quote = false;
98
+ if (!htmlFound && state.f == htmlBlock) {
99
+ state.f = inlineNormal;
100
+ state.block = blockNormal;
101
+ }
102
+ return null;
103
+ }
104
+
105
+ function blockNormal(stream, state) {
106
+
107
+ if (state.list !== false && state.indentationDiff >= 0) { // Continued list
108
+ if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
109
+ state.indentation -= state.indentationDiff;
110
+ }
111
+ state.list = null;
112
+ } else { // No longer a list
113
+ state.list = false;
114
+ }
115
+
116
+ if (state.indentationDiff >= 4) {
117
+ state.indentation -= 4;
118
+ stream.skipToEnd();
119
+ return code;
120
+ } else if (stream.eatSpace()) {
121
+ return null;
122
+ } else if (stream.peek() === '#' || (prevLineHasContent && stream.match(headerRE)) ) {
123
+ state.header = true;
124
+ } else if (stream.eat('>')) {
125
+ state.indentation++;
126
+ state.quote = true;
127
+ } else if (stream.peek() === '[') {
128
+ return switchInline(stream, state, footnoteLink);
129
+ } else if (stream.match(hrRE, true)) {
130
+ return hr;
131
+ } else if (stream.match(ulRE, true) || stream.match(olRE, true)) {
132
+ state.indentation += 4;
133
+ state.list = true;
134
+ } else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) {
135
+ // try switching mode
136
+ state.localMode = getMode(RegExp.$1);
137
+ if (state.localMode) state.localState = state.localMode.startState();
138
+ switchBlock(stream, state, local);
139
+ return code;
140
+ }
141
+
142
+ return switchInline(stream, state, state.inline);
143
+ }
144
+
145
+ function htmlBlock(stream, state) {
146
+ var style = htmlMode.token(stream, state.htmlState);
147
+ if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
148
+ state.f = inlineNormal;
149
+ state.block = blockNormal;
150
+ }
151
+ if (state.md_inside && stream.current().indexOf(">")!=-1) {
152
+ state.f = inlineNormal;
153
+ state.block = blockNormal;
154
+ state.htmlState.context = undefined;
155
+ }
156
+ return style;
157
+ }
158
+
159
+ function local(stream, state) {
160
+ if (stream.sol() && stream.match(/^```/, true)) {
161
+ state.localMode = state.localState = null;
162
+ state.f = inlineNormal;
163
+ state.block = blockNormal;
164
+ return code;
165
+ } else if (state.localMode) {
166
+ return state.localMode.token(stream, state.localState);
167
+ } else {
168
+ stream.skipToEnd();
169
+ return code;
170
+ }
171
+ }
172
+
173
+ // Inline
174
+ function getType(state) {
175
+ var styles = [];
176
+
177
+ if (state.strong) { styles.push(state.em ? emstrong : strong); }
178
+ else if (state.em) { styles.push(em); }
179
+
180
+ if (state.linkText) { styles.push(linktext); }
181
+
182
+ if (state.code) { styles.push(code); }
183
+
184
+ if (state.header) { styles.push(header); }
185
+ if (state.quote) { styles.push(quote); }
186
+ if (state.list !== false) { styles.push(list); }
187
+
188
+ return styles.length ? styles.join(' ') : null;
189
+ }
190
+
191
+ function handleText(stream, state) {
192
+ if (stream.match(textRE, true)) {
193
+ return getType(state);
194
+ }
195
+ return undefined;
196
+ }
197
+
198
+ function inlineNormal(stream, state) {
199
+ var style = state.text(stream, state);
200
+ if (typeof style !== 'undefined')
201
+ return style;
202
+
203
+ if (state.list) { // List marker (*, +, -, 1., etc)
204
+ state.list = null;
205
+ return list;
206
+ }
207
+
208
+ var ch = stream.next();
209
+
210
+ if (ch === '\\') {
211
+ stream.next();
212
+ return getType(state);
213
+ }
214
+
215
+ // Matches link titles present on next line
216
+ if (state.linkTitle) {
217
+ state.linkTitle = false;
218
+ var matchCh = ch;
219
+ if (ch === '(') {
220
+ matchCh = ')';
221
+ }
222
+ matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
223
+ var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
224
+ if (stream.match(new RegExp(regex), true)) {
225
+ return linkhref;
226
+ }
227
+ }
228
+
229
+ // If this block is changed, it may need to be updated in GFM mode
230
+ if (ch === '`') {
231
+ var t = getType(state);
232
+ var before = stream.pos;
233
+ stream.eatWhile('`');
234
+ var difference = 1 + stream.pos - before;
235
+ if (!state.code) {
236
+ codeDepth = difference;
237
+ state.code = true;
238
+ return getType(state);
239
+ } else {
240
+ if (difference === codeDepth) { // Must be exact
241
+ state.code = false;
242
+ return t;
243
+ }
244
+ return getType(state);
245
+ }
246
+ } else if (state.code) {
247
+ return getType(state);
248
+ }
249
+
250
+ if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
251
+ stream.match(/\[[^\]]*\]/);
252
+ state.inline = state.f = linkHref;
253
+ return image;
254
+ }
255
+
256
+ if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) {
257
+ state.linkText = true;
258
+ return getType(state);
259
+ }
260
+
261
+ if (ch === ']' && state.linkText) {
262
+ var type = getType(state);
263
+ state.linkText = false;
264
+ state.inline = state.f = linkHref;
265
+ return type;
266
+ }
267
+
268
+ if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) {
269
+ return switchInline(stream, state, inlineElement(linkinline, '>'));
270
+ }
271
+
272
+ if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, true)) {
273
+ return switchInline(stream, state, inlineElement(linkemail, '>'));
274
+ }
275
+
276
+ if (ch === '<' && stream.match(/^\w/, false)) {
277
+ if (stream.string.indexOf(">")!=-1) {
278
+ var atts = stream.string.substring(1,stream.string.indexOf(">"));
279
+ if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) {
280
+ state.md_inside = true;
281
+ }
282
+ }
283
+ stream.backUp(1);
284
+ return switchBlock(stream, state, htmlBlock);
285
+ }
286
+
287
+ if (ch === '<' && stream.match(/^\/\w*?>/)) {
288
+ state.md_inside = false;
289
+ return "tag";
290
+ }
291
+
292
+ var ignoreUnderscore = false;
293
+ if (!modeCfg.underscoresBreakWords) {
294
+ if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
295
+ var prevPos = stream.pos - 2;
296
+ if (prevPos >= 0) {
297
+ var prevCh = stream.string.charAt(prevPos);
298
+ if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
299
+ ignoreUnderscore = true;
300
+ }
301
+ }
302
+ }
303
+ }
304
+ var t = getType(state);
305
+ if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
306
+ if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
307
+ state.strong = false;
308
+ return t;
309
+ } else if (!state.strong && stream.eat(ch)) { // Add STRONG
310
+ state.strong = ch;
311
+ return getType(state);
312
+ } else if (state.em === ch) { // Remove EM
313
+ state.em = false;
314
+ return t;
315
+ } else if (!state.em) { // Add EM
316
+ state.em = ch;
317
+ return getType(state);
318
+ }
319
+ } else if (ch === ' ') {
320
+ if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
321
+ if (stream.peek() === ' ') { // Surrounded by spaces, ignore
322
+ return getType(state);
323
+ } else { // Not surrounded by spaces, back up pointer
324
+ stream.backUp(1);
325
+ }
326
+ }
327
+ }
328
+
329
+ return getType(state);
330
+ }
331
+
332
+ function linkHref(stream, state) {
333
+ // Check if space, and return NULL if so (to avoid marking the space)
334
+ if(stream.eatSpace()){
335
+ return null;
336
+ }
337
+ var ch = stream.next();
338
+ if (ch === '(' || ch === '[') {
339
+ return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
340
+ }
341
+ return 'error';
342
+ }
343
+
344
+ function footnoteLink(stream, state) {
345
+ if (stream.match(/^[^\]]*\]:/, true)) {
346
+ state.f = footnoteUrl;
347
+ return linktext;
348
+ }
349
+ return switchInline(stream, state, inlineNormal);
350
+ }
351
+
352
+ function footnoteUrl(stream, state) {
353
+ // Check if space, and return NULL if so (to avoid marking the space)
354
+ if(stream.eatSpace()){
355
+ return null;
356
+ }
357
+ // Match URL
358
+ stream.match(/^[^\s]+/, true);
359
+ // Check for link title
360
+ if (stream.peek() === undefined) { // End of line, set flag to check next line
361
+ state.linkTitle = true;
362
+ } else { // More content on line, check if link title
363
+ stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true);
364
+ }
365
+ state.f = state.inline = inlineNormal;
366
+ return linkhref;
367
+ }
368
+
369
+ var savedInlineRE = [];
370
+ function inlineRE(endChar) {
371
+ if (!savedInlineRE[endChar]) {
372
+ // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
373
+ endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
374
+ // Match any non-endChar, escaped character, as well as the closing
375
+ // endChar.
376
+ savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
377
+ }
378
+ return savedInlineRE[endChar];
379
+ }
380
+
381
+ function inlineElement(type, endChar, next) {
382
+ next = next || inlineNormal;
383
+ return function(stream, state) {
384
+ stream.match(inlineRE(endChar));
385
+ state.inline = state.f = next;
386
+ return type;
387
+ };
388
+ }
389
+
390
+ return {
391
+ startState: function() {
392
+ prevLineHasContent = false;
393
+ thisLineHasContent = false;
394
+ return {
395
+ f: blockNormal,
396
+
397
+ block: blockNormal,
398
+ htmlState: CodeMirror.startState(htmlMode),
399
+ indentation: 0,
400
+
401
+ inline: inlineNormal,
402
+ text: handleText,
403
+
404
+ linkText: false,
405
+ linkTitle: false,
406
+ em: false,
407
+ strong: false,
408
+ header: false,
409
+ list: false,
410
+ quote: false
411
+ };
412
+ },
413
+
414
+ copyState: function(s) {
415
+ return {
416
+ f: s.f,
417
+
418
+ block: s.block,
419
+ htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
420
+ indentation: s.indentation,
421
+
422
+ localMode: s.localMode,
423
+ localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
424
+
425
+ inline: s.inline,
426
+ text: s.text,
427
+ linkTitle: s.linkTitle,
428
+ em: s.em,
429
+ strong: s.strong,
430
+ header: s.header,
431
+ list: s.list,
432
+ quote: s.quote,
433
+ md_inside: s.md_inside
434
+ };
435
+ },
436
+
437
+ token: function(stream, state) {
438
+ if (stream.sol()) {
439
+ if (stream.match(/^\s*$/, true)) {
440
+ prevLineHasContent = false;
441
+ return blankLine(state);
442
+ } else {
443
+ if(thisLineHasContent){
444
+ prevLineHasContent = true;
445
+ thisLineHasContent = false;
446
+ }
447
+ thisLineHasContent = true;
448
+ }
449
+
450
+ // Reset state.header
451
+ state.header = false;
452
+
453
+ // Reset state.code
454
+ state.code = false;
455
+
456
+ state.f = state.block;
457
+ var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
458
+ var difference = Math.floor((indentation - state.indentation) / 4) * 4;
459
+ if (difference > 4) difference = 4;
460
+ var adjustedIndentation = state.indentation + difference;
461
+ state.indentationDiff = adjustedIndentation - state.indentation;
462
+ state.indentation = adjustedIndentation;
463
+ if (indentation > 0) return null;
464
+ }
465
+ return state.f(stream, state);
466
+ },
467
+
468
+ blankLine: blankLine,
469
+
470
+ getType: getType
471
+ };
472
+
473
+ }, "xml");
474
+
475
+ CodeMirror.defineMIME("text/x-markdown", "markdown");