diff options
Diffstat (limited to 'js/components/htmleditor.js')
-rwxr-xr-x | js/components/htmleditor.js | 679 |
1 files changed, 679 insertions, 0 deletions
diff --git a/js/components/htmleditor.js b/js/components/htmleditor.js new file mode 100755 index 0000000..68b5b52 --- /dev/null +++ b/js/components/htmleditor.js | |||
@@ -0,0 +1,679 @@ | |||
1 | /*! UIkit 2.26.4 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ | ||
2 | (function(addon) { | ||
3 | |||
4 | var component; | ||
5 | |||
6 | if (window.UIkit) { | ||
7 | component = addon(UIkit); | ||
8 | } | ||
9 | |||
10 | if (typeof define == "function" && define.amd) { | ||
11 | define("uikit-htmleditor", ["uikit"], function(){ | ||
12 | return component || addon(UIkit); | ||
13 | }); | ||
14 | } | ||
15 | |||
16 | })(function(UI) { | ||
17 | |||
18 | "use strict"; | ||
19 | |||
20 | var editors = []; | ||
21 | |||
22 | UI.component('htmleditor', { | ||
23 | |||
24 | defaults: { | ||
25 | iframe : false, | ||
26 | mode : 'split', | ||
27 | markdown : false, | ||
28 | autocomplete : true, | ||
29 | enablescripts: false, | ||
30 | height : 500, | ||
31 | maxsplitsize : 1000, | ||
32 | codemirror : { mode: 'htmlmixed', lineWrapping: true, dragDrop: false, autoCloseTags: true, matchTags: true, autoCloseBrackets: true, matchBrackets: true, indentUnit: 4, indentWithTabs: false, tabSize: 4, hintOptions: {completionSingle:false} }, | ||
33 | toolbar : [ 'bold', 'italic', 'strike', 'link', 'image', 'blockquote', 'listUl', 'listOl' ], | ||
34 | lblPreview : 'Preview', | ||
35 | lblCodeview : 'HTML', | ||
36 | lblMarkedview: 'Markdown' | ||
37 | }, | ||
38 | |||
39 | boot: function() { | ||
40 | |||
41 | // init code | ||
42 | UI.ready(function(context) { | ||
43 | |||
44 | UI.$('textarea[data-uk-htmleditor]', context).each(function() { | ||
45 | |||
46 | var editor = UI.$(this); | ||
47 | |||
48 | if (!editor.data('htmleditor')) { | ||
49 | UI.htmleditor(editor, UI.Utils.options(editor.attr('data-uk-htmleditor'))); | ||
50 | } | ||
51 | }); | ||
52 | }); | ||
53 | }, | ||
54 | |||
55 | init: function() { | ||
56 | |||
57 | var $this = this, tpl = UI.components.htmleditor.template; | ||
58 | |||
59 | this.CodeMirror = this.options.CodeMirror || CodeMirror; | ||
60 | this.buttons = {}; | ||
61 | |||
62 | tpl = tpl.replace(/\{:lblPreview}/g, this.options.lblPreview); | ||
63 | tpl = tpl.replace(/\{:lblCodeview}/g, this.options.lblCodeview); | ||
64 | |||
65 | this.htmleditor = UI.$(tpl); | ||
66 | this.content = this.htmleditor.find('.uk-htmleditor-content'); | ||
67 | this.toolbar = this.htmleditor.find('.uk-htmleditor-toolbar'); | ||
68 | this.preview = this.htmleditor.find('.uk-htmleditor-preview').children().eq(0); | ||
69 | this.code = this.htmleditor.find('.uk-htmleditor-code'); | ||
70 | |||
71 | this.element.before(this.htmleditor).appendTo(this.code); | ||
72 | this.editor = this.CodeMirror.fromTextArea(this.element[0], this.options.codemirror); | ||
73 | this.editor.htmleditor = this; | ||
74 | this.editor.on('change', UI.Utils.debounce(function() { $this.render(); }, 150)); | ||
75 | this.editor.on('change', function() { | ||
76 | $this.editor.save(); | ||
77 | $this.element.trigger('input'); | ||
78 | }); | ||
79 | this.code.find('.CodeMirror').css('height', this.options.height); | ||
80 | |||
81 | // iframe mode? | ||
82 | if (this.options.iframe) { | ||
83 | |||
84 | this.iframe = UI.$('<iframe class="uk-htmleditor-iframe" frameborder="0" scrolling="auto" height="100" width="100%"></iframe>'); | ||
85 | this.preview.append(this.iframe); | ||
86 | |||
87 | // must open and close document object to start using it! | ||
88 | this.iframe[0].contentWindow.document.open(); | ||
89 | this.iframe[0].contentWindow.document.close(); | ||
90 | |||
91 | this.preview.container = UI.$(this.iframe[0].contentWindow.document).find('body'); | ||
92 | |||
93 | // append custom stylesheet | ||
94 | if (typeof(this.options.iframe) === 'string') { | ||
95 | this.preview.container.parent().append('<link rel="stylesheet" href="'+this.options.iframe+'">'); | ||
96 | } | ||
97 | |||
98 | } else { | ||
99 | this.preview.container = this.preview; | ||
100 | } | ||
101 | |||
102 | UI.$win.on('resize load', UI.Utils.debounce(function() { $this.fit(); }, 200)); | ||
103 | |||
104 | var previewContainer = this.iframe ? this.preview.container:$this.preview.parent(), | ||
105 | codeContent = this.code.find('.CodeMirror-sizer'), | ||
106 | codeScroll = this.code.find('.CodeMirror-scroll').on('scroll', UI.Utils.debounce(function() { | ||
107 | |||
108 | if ($this.htmleditor.attr('data-mode') == 'tab') return; | ||
109 | |||
110 | // calc position | ||
111 | var codeHeight = codeContent.height() - codeScroll.height(), | ||
112 | previewHeight = previewContainer[0].scrollHeight - ($this.iframe ? $this.iframe.height() : previewContainer.height()), | ||
113 | ratio = previewHeight / codeHeight, | ||
114 | previewPosition = codeScroll.scrollTop() * ratio; | ||
115 | |||
116 | // apply new scroll | ||
117 | previewContainer.scrollTop(previewPosition); | ||
118 | |||
119 | }, 10)); | ||
120 | |||
121 | this.htmleditor.on('click', '.uk-htmleditor-button-code, .uk-htmleditor-button-preview', function(e) { | ||
122 | |||
123 | e.preventDefault(); | ||
124 | |||
125 | if ($this.htmleditor.attr('data-mode') == 'tab') { | ||
126 | |||
127 | $this.htmleditor.find('.uk-htmleditor-button-code, .uk-htmleditor-button-preview').removeClass('uk-active').filter(this).addClass('uk-active'); | ||
128 | |||
129 | $this.activetab = UI.$(this).hasClass('uk-htmleditor-button-code') ? 'code' : 'preview'; | ||
130 | $this.htmleditor.attr('data-active-tab', $this.activetab); | ||
131 | $this.editor.refresh(); | ||
132 | } | ||
133 | }); | ||
134 | |||
135 | // toolbar actions | ||
136 | this.htmleditor.on('click', 'a[data-htmleditor-button]', function() { | ||
137 | |||
138 | if (!$this.code.is(':visible')) return; | ||
139 | |||
140 | $this.trigger('action.' + UI.$(this).data('htmleditor-button'), [$this.editor]); | ||
141 | }); | ||
142 | |||
143 | this.preview.parent().css('height', this.code.height()); | ||
144 | |||
145 | // autocomplete | ||
146 | if (this.options.autocomplete && this.CodeMirror.showHint && this.CodeMirror.hint && this.CodeMirror.hint.html) { | ||
147 | |||
148 | this.editor.on('inputRead', UI.Utils.debounce(function() { | ||
149 | var doc = $this.editor.getDoc(), POS = doc.getCursor(), mode = $this.CodeMirror.innerMode($this.editor.getMode(), $this.editor.getTokenAt(POS).state).mode.name; | ||
150 | |||
151 | if (mode == 'xml') { //html depends on xml | ||
152 | |||
153 | var cur = $this.editor.getCursor(), token = $this.editor.getTokenAt(cur); | ||
154 | |||
155 | if (token.string.charAt(0) == '<' || token.type == 'attribute') { | ||
156 | $this.CodeMirror.showHint($this.editor, $this.CodeMirror.hint.html, { completeSingle: false }); | ||
157 | } | ||
158 | } | ||
159 | }, 100)); | ||
160 | } | ||
161 | |||
162 | this.debouncedRedraw = UI.Utils.debounce(function () { $this.redraw(); }, 5); | ||
163 | |||
164 | this.on('init.uk.component', function() { | ||
165 | $this.debouncedRedraw(); | ||
166 | }); | ||
167 | |||
168 | this.element.attr('data-uk-check-display', 1).on('display.uk.check', function(e) { | ||
169 | if (this.htmleditor.is(":visible")) this.fit(); | ||
170 | }.bind(this)); | ||
171 | |||
172 | editors.push(this); | ||
173 | }, | ||
174 | |||
175 | addButton: function(name, button) { | ||
176 | this.buttons[name] = button; | ||
177 | }, | ||
178 | |||
179 | addButtons: function(buttons) { | ||
180 | UI.$.extend(this.buttons, buttons); | ||
181 | }, | ||
182 | |||
183 | replaceInPreview: function(regexp, callback) { | ||
184 | |||
185 | var editor = this.editor, results = [], value = editor.getValue(), offset = -1, index = 0; | ||
186 | |||
187 | this.currentvalue = this.currentvalue.replace(regexp, function() { | ||
188 | |||
189 | offset = value.indexOf(arguments[0], ++offset); | ||
190 | |||
191 | var match = { | ||
192 | matches: arguments, | ||
193 | from : translateOffset(offset), | ||
194 | to : translateOffset(offset + arguments[0].length), | ||
195 | replace: function(value) { | ||
196 | editor.replaceRange(value, match.from, match.to); | ||
197 | }, | ||
198 | inRange: function(cursor) { | ||
199 | |||
200 | if (cursor.line === match.from.line && cursor.line === match.to.line) { | ||
201 | return cursor.ch >= match.from.ch && cursor.ch < match.to.ch; | ||
202 | } | ||
203 | |||
204 | return (cursor.line === match.from.line && cursor.ch >= match.from.ch) || | ||
205 | (cursor.line > match.from.line && cursor.line < match.to.line) || | ||
206 | (cursor.line === match.to.line && cursor.ch < match.to.ch); | ||
207 | } | ||
208 | }; | ||
209 | |||
210 | var result = typeof(callback) === 'string' ? callback : callback(match, index); | ||
211 | |||
212 | if (!result && result !== '') { | ||
213 | return arguments[0]; | ||
214 | } | ||
215 | |||
216 | index++; | ||
217 | |||
218 | results.push(match); | ||
219 | return result; | ||
220 | }); | ||
221 | |||
222 | function translateOffset(offset) { | ||
223 | var result = editor.getValue().substring(0, offset).split('\n'); | ||
224 | return { line: result.length - 1, ch: result[result.length - 1].length } | ||
225 | } | ||
226 | |||
227 | return results; | ||
228 | }, | ||
229 | |||
230 | _buildtoolbar: function() { | ||
231 | |||
232 | if (!(this.options.toolbar && this.options.toolbar.length)) return; | ||
233 | |||
234 | var $this = this, bar = []; | ||
235 | |||
236 | this.toolbar.empty(); | ||
237 | |||
238 | this.options.toolbar.forEach(function(button) { | ||
239 | if (!$this.buttons[button]) return; | ||
240 | |||
241 | var title = $this.buttons[button].title ? $this.buttons[button].title : button; | ||
242 | |||
243 | bar.push('<li><a data-htmleditor-button="'+button+'" title="'+title+'" data-uk-tooltip>'+$this.buttons[button].label+'</a></li>'); | ||
244 | }); | ||
245 | |||
246 | this.toolbar.html(bar.join('\n')); | ||
247 | }, | ||
248 | |||
249 | fit: function() { | ||
250 | |||
251 | var mode = this.options.mode; | ||
252 | |||
253 | if (mode == 'split' && this.htmleditor.width() < this.options.maxsplitsize) { | ||
254 | mode = 'tab'; | ||
255 | } | ||
256 | |||
257 | if (mode == 'tab') { | ||
258 | if (!this.activetab) { | ||
259 | this.activetab = 'code'; | ||
260 | this.htmleditor.attr('data-active-tab', this.activetab); | ||
261 | } | ||
262 | |||
263 | this.htmleditor.find('.uk-htmleditor-button-code, .uk-htmleditor-button-preview').removeClass('uk-active') | ||
264 | .filter(this.activetab == 'code' ? '.uk-htmleditor-button-code' : '.uk-htmleditor-button-preview') | ||
265 | .addClass('uk-active'); | ||
266 | } | ||
267 | |||
268 | this.editor.refresh(); | ||
269 | this.preview.parent().css('height', this.code.height()); | ||
270 | |||
271 | this.htmleditor.attr('data-mode', mode); | ||
272 | }, | ||
273 | |||
274 | redraw: function() { | ||
275 | this._buildtoolbar(); | ||
276 | this.render(); | ||
277 | this.fit(); | ||
278 | }, | ||
279 | |||
280 | getMode: function() { | ||
281 | return this.editor.getOption('mode'); | ||
282 | }, | ||
283 | |||
284 | getCursorMode: function() { | ||
285 | var param = { mode: 'html'}; | ||
286 | this.trigger('cursorMode', [param]); | ||
287 | return param.mode; | ||
288 | }, | ||
289 | |||
290 | render: function() { | ||
291 | |||
292 | this.currentvalue = this.editor.getValue(); | ||
293 | |||
294 | if (!this.options.enablescripts) { | ||
295 | this.currentvalue = this.currentvalue.replace(/<(script|style)\b[^<]*(?:(?!<\/(script|style)>)<[^<]*)*<\/(script|style)>/img, ''); | ||
296 | } | ||
297 | |||
298 | // empty code | ||
299 | if (!this.currentvalue) { | ||
300 | |||
301 | this.element.val(''); | ||
302 | this.preview.container.html(''); | ||
303 | |||
304 | return; | ||
305 | } | ||
306 | |||
307 | this.trigger('render', [this]); | ||
308 | this.trigger('renderLate', [this]); | ||
309 | |||
310 | this.preview.container.html(this.currentvalue); | ||
311 | }, | ||
312 | |||
313 | addShortcut: function(name, callback) { | ||
314 | var map = {}; | ||
315 | if (!UI.$.isArray(name)) { | ||
316 | name = [name]; | ||
317 | } | ||
318 | |||
319 | name.forEach(function(key) { | ||
320 | map[key] = callback; | ||
321 | }); | ||
322 | |||
323 | this.editor.addKeyMap(map); | ||
324 | |||
325 | return map; | ||
326 | }, | ||
327 | |||
328 | addShortcutAction: function(action, shortcuts) { | ||
329 | var editor = this; | ||
330 | this.addShortcut(shortcuts, function() { | ||
331 | editor.element.trigger('action.' + action, [editor.editor]); | ||
332 | }); | ||
333 | }, | ||
334 | |||
335 | replaceSelection: function(replace) { | ||
336 | |||
337 | var text = this.editor.getSelection(); | ||
338 | |||
339 | if (!text.length) { | ||
340 | |||
341 | var cur = this.editor.getCursor(), | ||
342 | curLine = this.editor.getLine(cur.line), | ||
343 | start = cur.ch, | ||
344 | end = start; | ||
345 | |||
346 | while (end < curLine.length && /[\w$]+/.test(curLine.charAt(end))) ++end; | ||
347 | while (start && /[\w$]+/.test(curLine.charAt(start - 1))) --start; | ||
348 | |||
349 | var curWord = start != end && curLine.slice(start, end); | ||
350 | |||
351 | if (curWord) { | ||
352 | this.editor.setSelection({ line: cur.line, ch: start}, { line: cur.line, ch: end }); | ||
353 | text = curWord; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | var html = replace.replace('$1', text); | ||
358 | |||
359 | this.editor.replaceSelection(html, 'end'); | ||
360 | this.editor.focus(); | ||
361 | }, | ||
362 | |||
363 | replaceLine: function(replace) { | ||
364 | var pos = this.editor.getDoc().getCursor(), | ||
365 | text = this.editor.getLine(pos.line), | ||
366 | html = replace.replace('$1', text); | ||
367 | |||
368 | this.editor.replaceRange(html , { line: pos.line, ch: 0 }, { line: pos.line, ch: text.length }); | ||
369 | this.editor.setCursor({ line: pos.line, ch: html.length }); | ||
370 | this.editor.focus(); | ||
371 | }, | ||
372 | |||
373 | save: function() { | ||
374 | this.editor.save(); | ||
375 | } | ||
376 | }); | ||
377 | |||
378 | |||
379 | UI.components.htmleditor.template = [ | ||
380 | '<div class="uk-htmleditor uk-clearfix" data-mode="split">', | ||
381 | '<div class="uk-htmleditor-navbar">', | ||
382 | '<ul class="uk-htmleditor-navbar-nav uk-htmleditor-toolbar"></ul>', | ||
383 | '<div class="uk-htmleditor-navbar-flip">', | ||
384 | '<ul class="uk-htmleditor-navbar-nav">', | ||
385 | '<li class="uk-htmleditor-button-code"><a>{:lblCodeview}</a></li>', | ||
386 | '<li class="uk-htmleditor-button-preview"><a>{:lblPreview}</a></li>', | ||
387 | '<li><a data-htmleditor-button="fullscreen"><i class="uk-icon-expand"></i></a></li>', | ||
388 | '</ul>', | ||
389 | '</div>', | ||
390 | '</div>', | ||
391 | '<div class="uk-htmleditor-content">', | ||
392 | '<div class="uk-htmleditor-code"></div>', | ||
393 | '<div class="uk-htmleditor-preview"><div></div></div>', | ||
394 | '</div>', | ||
395 | '</div>' | ||
396 | ].join(''); | ||
397 | |||
398 | |||
399 | UI.plugin('htmleditor', 'base', { | ||
400 | |||
401 | init: function(editor) { | ||
402 | |||
403 | editor.addButtons({ | ||
404 | |||
405 | fullscreen: { | ||
406 | title : 'Fullscreen', | ||
407 | label : '<i class="uk-icon-expand"></i>' | ||
408 | }, | ||
409 | bold : { | ||
410 | title : 'Bold', | ||
411 | label : '<i class="uk-icon-bold"></i>' | ||
412 | }, | ||
413 | italic : { | ||
414 | title : 'Italic', | ||
415 | label : '<i class="uk-icon-italic"></i>' | ||
416 | }, | ||
417 | strike : { | ||
418 | title : 'Strikethrough', | ||
419 | label : '<i class="uk-icon-strikethrough"></i>' | ||
420 | }, | ||
421 | blockquote : { | ||
422 | title : 'Blockquote', | ||
423 | label : '<i class="uk-icon-quote-right"></i>' | ||
424 | }, | ||
425 | link : { | ||
426 | title : 'Link', | ||
427 | label : '<i class="uk-icon-link"></i>' | ||
428 | }, | ||
429 | image : { | ||
430 | title : 'Image', | ||
431 | label : '<i class="uk-icon-picture-o"></i>' | ||
432 | }, | ||
433 | listUl : { | ||
434 | title : 'Unordered List', | ||
435 | label : '<i class="uk-icon-list-ul"></i>' | ||
436 | }, | ||
437 | listOl : { | ||
438 | title : 'Ordered List', | ||
439 | label : '<i class="uk-icon-list-ol"></i>' | ||
440 | } | ||
441 | |||
442 | }); | ||
443 | |||
444 | addAction('bold', '<strong>$1</strong>'); | ||
445 | addAction('italic', '<em>$1</em>'); | ||
446 | addAction('strike', '<del>$1</del>'); | ||
447 | addAction('blockquote', '<blockquote><p>$1</p></blockquote>', 'replaceLine'); | ||
448 | addAction('link', '<a href="http://">$1</a>'); | ||
449 | addAction('image', '<img src="http://" alt="$1">'); | ||
450 | |||
451 | var listfn = function(tag) { | ||
452 | if (editor.getCursorMode() == 'html') { | ||
453 | |||
454 | tag = tag || 'ul'; | ||
455 | |||
456 | var cm = editor.editor, | ||
457 | doc = cm.getDoc(), | ||
458 | pos = doc.getCursor(true), | ||
459 | posend = doc.getCursor(false), | ||
460 | im = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(cm.getCursor()).state), | ||
461 | inList = im && im.state && im.state.context && ['ul','ol'].indexOf(im.state.context.tagName) != -1; | ||
462 | |||
463 | for (var i=pos.line; i<(posend.line+1);i++) { | ||
464 | cm.replaceRange('<li>'+cm.getLine(i)+'</li>', { line: i, ch: 0 }, { line: i, ch: cm.getLine(i).length }); | ||
465 | } | ||
466 | |||
467 | if (!inList) { | ||
468 | cm.replaceRange('<'+tag+'>'+"\n"+cm.getLine(pos.line), { line: pos.line, ch: 0 }, { line: pos.line, ch: cm.getLine(pos.line).length }); | ||
469 | cm.replaceRange(cm.getLine((posend.line+1))+"\n"+'</'+tag+'>', { line: (posend.line+1), ch: 0 }, { line: (posend.line+1), ch: cm.getLine((posend.line+1)).length }); | ||
470 | cm.setCursor({ line: posend.line+1, ch: cm.getLine(posend.line+1).length }); | ||
471 | } else { | ||
472 | cm.setCursor({ line: posend.line, ch: cm.getLine(posend.line).length }); | ||
473 | } | ||
474 | |||
475 | cm.focus(); | ||
476 | } | ||
477 | }; | ||
478 | |||
479 | editor.on('action.listUl', function() { | ||
480 | listfn('ul'); | ||
481 | }); | ||
482 | |||
483 | editor.on('action.listOl', function() { | ||
484 | listfn('ol'); | ||
485 | }); | ||
486 | |||
487 | editor.htmleditor.on('click', 'a[data-htmleditor-button="fullscreen"]', function() { | ||
488 | |||
489 | editor.htmleditor.toggleClass('uk-htmleditor-fullscreen'); | ||
490 | |||
491 | var wrap = editor.editor.getWrapperElement(); | ||
492 | |||
493 | if (editor.htmleditor.hasClass('uk-htmleditor-fullscreen')) { | ||
494 | |||
495 | var fixedParent = false, parents = editor.htmleditor.parents().each(function(){ | ||
496 | if (UI.$(this).css('position')=='fixed' && !UI.$(this).is('html')) { | ||
497 | fixedParent = UI.$(this); | ||
498 | } | ||
499 | }); | ||
500 | |||
501 | editor.htmleditor.data('fixedParents', false); | ||
502 | |||
503 | if (fixedParent) { | ||
504 | |||
505 | var transformed = []; | ||
506 | |||
507 | fixedParent = fixedParent.parent().find(parents).each(function(){ | ||
508 | |||
509 | if (UI.$(this).css('transform') != 'none') { | ||
510 | transformed.push(UI.$(this).data('transform-reset', { | ||
511 | 'transform': this.style.transform, | ||
512 | '-webkit-transform': this.style.webkitTransform, | ||
513 | '-webkit-transition':this.style.webkitTransition, | ||
514 | 'transition':this.style.transition | ||
515 | }).css({ | ||
516 | 'transform': 'none', | ||
517 | '-webkit-transform': 'none', | ||
518 | '-webkit-transition':'none', | ||
519 | 'transition':'none' | ||
520 | })); | ||
521 | } | ||
522 | }); | ||
523 | |||
524 | editor.htmleditor.data('fixedParents', transformed); | ||
525 | } | ||
526 | |||
527 | editor.editor.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, width: wrap.style.width, height: wrap.style.height}; | ||
528 | wrap.style.width = ''; | ||
529 | wrap.style.height = editor.content.height()+'px'; | ||
530 | document.documentElement.style.overflow = 'hidden'; | ||
531 | |||
532 | } else { | ||
533 | |||
534 | document.documentElement.style.overflow = ''; | ||
535 | var info = editor.editor.state.fullScreenRestore; | ||
536 | wrap.style.width = info.width; wrap.style.height = info.height; | ||
537 | window.scrollTo(info.scrollLeft, info.scrollTop); | ||
538 | |||
539 | if (editor.htmleditor.data('fixedParents')) { | ||
540 | editor.htmleditor.data('fixedParents').forEach(function(parent){ | ||
541 | parent.css(parent.data('transform-reset')); | ||
542 | }); | ||
543 | } | ||
544 | } | ||
545 | |||
546 | setTimeout(function() { | ||
547 | editor.fit(); | ||
548 | UI.$win.trigger('resize'); | ||
549 | }, 50); | ||
550 | }); | ||
551 | |||
552 | editor.addShortcut(['Ctrl-S', 'Cmd-S'], function() { editor.element.trigger('htmleditor-save', [editor]); }); | ||
553 | editor.addShortcutAction('bold', ['Ctrl-B', 'Cmd-B']); | ||
554 | |||
555 | function addAction(name, replace, mode) { | ||
556 | editor.on('action.'+name, function() { | ||
557 | if (editor.getCursorMode() == 'html') { | ||
558 | editor[mode == 'replaceLine' ? 'replaceLine' : 'replaceSelection'](replace); | ||
559 | } | ||
560 | }); | ||
561 | } | ||
562 | } | ||
563 | }); | ||
564 | |||
565 | UI.plugin('htmleditor', 'markdown', { | ||
566 | |||
567 | init: function(editor) { | ||
568 | |||
569 | var parser = editor.options.mdparser || window.marked || null; | ||
570 | |||
571 | if (!parser) return; | ||
572 | |||
573 | if (editor.options.markdown) { | ||
574 | enableMarkdown(); | ||
575 | } | ||
576 | |||
577 | addAction('bold', '**$1**'); | ||
578 | addAction('italic', '*$1*'); | ||
579 | addAction('strike', '~~$1~~'); | ||
580 | addAction('blockquote', '> $1', 'replaceLine'); | ||
581 | addAction('link', '[$1](http://)'); | ||
582 | addAction('image', ''); | ||
583 | |||
584 | editor.on('action.listUl', function() { | ||
585 | |||
586 | if (editor.getCursorMode() == 'markdown') { | ||
587 | |||
588 | var cm = editor.editor, | ||
589 | pos = cm.getDoc().getCursor(true), | ||
590 | posend = cm.getDoc().getCursor(false); | ||
591 | |||
592 | for (var i=pos.line; i<(posend.line+1);i++) { | ||
593 | cm.replaceRange('* '+cm.getLine(i), { line: i, ch: 0 }, { line: i, ch: cm.getLine(i).length }); | ||
594 | } | ||
595 | |||
596 | cm.setCursor({ line: posend.line, ch: cm.getLine(posend.line).length }); | ||
597 | cm.focus(); | ||
598 | } | ||
599 | }); | ||
600 | |||
601 | editor.on('action.listOl', function() { | ||
602 | |||
603 | if (editor.getCursorMode() == 'markdown') { | ||
604 | |||
605 | var cm = editor.editor, | ||
606 | pos = cm.getDoc().getCursor(true), | ||
607 | posend = cm.getDoc().getCursor(false), | ||
608 | prefix = 1; | ||
609 | |||
610 | if (pos.line > 0) { | ||
611 | var prevline = cm.getLine(pos.line-1), matches; | ||
612 | |||
613 | if(matches = prevline.match(/^(\d+)\./)) { | ||
614 | prefix = Number(matches[1])+1; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | for (var i=pos.line; i<(posend.line+1);i++) { | ||
619 | cm.replaceRange(prefix+'. '+cm.getLine(i), { line: i, ch: 0 }, { line: i, ch: cm.getLine(i).length }); | ||
620 | prefix++; | ||
621 | } | ||
622 | |||
623 | cm.setCursor({ line: posend.line, ch: cm.getLine(posend.line).length }); | ||
624 | cm.focus(); | ||
625 | } | ||
626 | }); | ||
627 | |||
628 | editor.on('renderLate', function() { | ||
629 | if (editor.editor.options.mode == 'gfm') { | ||
630 | editor.currentvalue = parser(editor.currentvalue); | ||
631 | } | ||
632 | }); | ||
633 | |||
634 | editor.on('cursorMode', function(e, param) { | ||
635 | if (editor.editor.options.mode == 'gfm') { | ||
636 | var pos = editor.editor.getDoc().getCursor(); | ||
637 | if (!editor.editor.getTokenAt(pos).state.base.htmlState) { | ||
638 | param.mode = 'markdown'; | ||
639 | } | ||
640 | } | ||
641 | }); | ||
642 | |||
643 | UI.$.extend(editor, { | ||
644 | |||
645 | enableMarkdown: function() { | ||
646 | enableMarkdown(); | ||
647 | this.render(); | ||
648 | }, | ||
649 | disableMarkdown: function() { | ||
650 | this.editor.setOption('mode', 'htmlmixed'); | ||
651 | this.htmleditor.find('.uk-htmleditor-button-code a').html(this.options.lblCodeview); | ||
652 | this.render(); | ||
653 | } | ||
654 | |||
655 | }); | ||
656 | |||
657 | // switch markdown mode on event | ||
658 | editor.on({ | ||
659 | enableMarkdown : function() { editor.enableMarkdown(); }, | ||
660 | disableMarkdown : function() { editor.disableMarkdown(); } | ||
661 | }); | ||
662 | |||
663 | function enableMarkdown() { | ||
664 | editor.editor.setOption('mode', 'gfm'); | ||
665 | editor.htmleditor.find('.uk-htmleditor-button-code a').html(editor.options.lblMarkedview); | ||
666 | } | ||
667 | |||
668 | function addAction(name, replace, mode) { | ||
669 | editor.on('action.'+name, function() { | ||
670 | if (editor.getCursorMode() == 'markdown') { | ||
671 | editor[mode == 'replaceLine' ? 'replaceLine' : 'replaceSelection'](replace); | ||
672 | } | ||
673 | }); | ||
674 | } | ||
675 | } | ||
676 | }); | ||
677 | |||
678 | return UI.htmleditor; | ||
679 | }); | ||