UNPKG

alpaca

Version:

Alpaca provides the easiest and fastest way to generate interactive forms for the web and mobile devices. It runs simply as HTML5 or more elaborately using Bootstrap, jQuery Mobile or jQuery UI. Alpaca uses Handlebars to process JSON schema and provide

268 lines (219 loc) 6.76 kB
/** * plugin.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /*global tinymce:true */ tinymce.PluginManager.add('textpattern', function(editor) { var isPatternsDirty = true, patterns; patterns = editor.settings.textpattern_patterns || [ {start: '*', end: '*', format: 'italic'}, {start: '**', end: '**', format: 'bold'}, {start: '#', format: 'h1'}, {start: '##', format: 'h2'}, {start: '###', format: 'h3'}, {start: '####', format: 'h4'}, {start: '#####', format: 'h5'}, {start: '######', format: 'h6'}, {start: '1. ', cmd: 'InsertOrderedList'}, {start: '* ', cmd: 'InsertUnorderedList'}, {start: '- ', cmd: 'InsertUnorderedList'} ]; // Returns a sorted patterns list, ordered descending by start length function getPatterns() { if (isPatternsDirty) { patterns.sort(function(a, b) { if (a.start.length > b.start.length) { return -1; } if (a.start.length < b.start.length) { return 1; } return 0; }); isPatternsDirty = false; } return patterns; } // Finds a matching pattern to the specified text function findPattern(text) { var patterns = getPatterns(); for (var i = 0; i < patterns.length; i++) { if (text.indexOf(patterns[i].start) !== 0) { continue; } if (patterns[i].end && text.lastIndexOf(patterns[i].end) != text.length - patterns[i].end.length) { continue; } return patterns[i]; } } // Finds the best matching end pattern function findEndPattern(text, offset, delta) { var patterns, pattern, i; // Find best matching end patterns = getPatterns(); for (i = 0; i < patterns.length; i++) { pattern = patterns[i]; if (pattern.end && text.substr(offset - pattern.end.length - delta, pattern.end.length) == pattern.end) { return pattern; } } } // Handles inline formats like *abc* and **abc** function applyInlineFormat(space) { var selection, dom, rng, container, offset, startOffset, text, patternRng, pattern, delta, format; function splitContainer() { // Split text node and remove start/end from text node container = container.splitText(startOffset); container.splitText(offset - startOffset - delta); container.deleteData(0, pattern.start.length); container.deleteData(container.data.length - pattern.end.length, pattern.end.length); } selection = editor.selection; dom = editor.dom; if (!selection.isCollapsed()) { return; } rng = selection.getRng(true); container = rng.startContainer; offset = rng.startOffset; text = container.data; delta = space ? 1 : 0; if (container.nodeType != 3) { return; } // Find best matching end pattern = findEndPattern(text, offset, delta); if (!pattern) { return; } // Find start of matched pattern // TODO: Might need to improve this if there is nested formats startOffset = Math.max(0, offset - delta); startOffset = text.lastIndexOf(pattern.start, startOffset - pattern.end.length - 1); if (startOffset === -1) { return; } // Setup a range for the matching word patternRng = dom.createRng(); patternRng.setStart(container, startOffset); patternRng.setEnd(container, offset - delta); pattern = findPattern(patternRng.toString()); if (!pattern || !pattern.end) { return; } // If container match doesn't have anything between start/end then do nothing if (container.data.length <= pattern.start.length + pattern.end.length) { return; } format = editor.formatter.get(pattern.format); if (format && format[0].inline) { splitContainer(); editor.formatter.apply(pattern.format, {}, container); return container; } } // Handles block formats like ##abc or 1. abc function applyBlockFormat() { var selection, dom, container, firstTextNode, node, format, textBlockElm, pattern, walker, rng, offset; selection = editor.selection; dom = editor.dom; if (!selection.isCollapsed()) { return; } textBlockElm = dom.getParent(selection.getStart(), 'p'); if (textBlockElm) { walker = new tinymce.dom.TreeWalker(textBlockElm, textBlockElm); while ((node = walker.next())) { if (node.nodeType == 3) { firstTextNode = node; break; } } if (firstTextNode) { pattern = findPattern(firstTextNode.data); if (!pattern) { return; } rng = selection.getRng(true); container = rng.startContainer; offset = rng.startOffset; if (firstTextNode == container) { offset = Math.max(0, offset - pattern.start.length); } if (tinymce.trim(firstTextNode.data).length == pattern.start.length) { return; } if (pattern.format) { format = editor.formatter.get(pattern.format); if (format && format[0].block) { firstTextNode.deleteData(0, pattern.start.length); editor.formatter.apply(pattern.format, {}, firstTextNode); rng.setStart(container, offset); rng.collapse(true); selection.setRng(rng); } } if (pattern.cmd) { editor.undoManager.transact(function() { firstTextNode.deleteData(0, pattern.start.length); editor.execCommand(pattern.cmd); }); } } } } function handleEnter() { var rng, wrappedTextNode; wrappedTextNode = applyInlineFormat(); if (wrappedTextNode) { rng = editor.dom.createRng(); rng.setStart(wrappedTextNode, wrappedTextNode.data.length); rng.setEnd(wrappedTextNode, wrappedTextNode.data.length); editor.selection.setRng(rng); } applyBlockFormat(); } function handleSpace() { var wrappedTextNode, lastChar, lastCharNode, rng, dom; wrappedTextNode = applyInlineFormat(true); if (wrappedTextNode) { dom = editor.dom; lastChar = wrappedTextNode.data.slice(-1); // Move space after the newly formatted node if (/[\u00a0 ]/.test(lastChar)) { wrappedTextNode.deleteData(wrappedTextNode.data.length - 1, 1); lastCharNode = dom.doc.createTextNode(lastChar); if (wrappedTextNode.nextSibling) { dom.insertAfter(lastCharNode, wrappedTextNode.nextSibling); } else { wrappedTextNode.parentNode.appendChild(lastCharNode); } rng = dom.createRng(); rng.setStart(lastCharNode, 1); rng.setEnd(lastCharNode, 1); editor.selection.setRng(rng); } } } editor.on('keydown', function(e) { if (e.keyCode == 13 && !tinymce.util.VK.modifierPressed(e)) { handleEnter(); } }, true); editor.on('keyup', function(e) { if (e.keyCode == 32 && !tinymce.util.VK.modifierPressed(e)) { handleSpace(); } }); this.getPatterns = getPatterns; this.setPatterns = function(newPatterns) { patterns = newPatterns; isPatternsDirty = true; }; });