src/myams/resources/js/ext/tinymce/dev/plugins/textpattern/plugin.js
changeset 0 f05d7aea098a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/myams/resources/js/ext/tinymce/dev/plugins/textpattern/plugin.js	Fri Jul 10 16:59:11 2020 +0200
@@ -0,0 +1,268 @@
+/**
+ * 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;
+	};
+});
\ No newline at end of file