UNPKG

@toast-ui/editor

Version:

GFM Markdown Wysiwyg Editor - Productive and Extensible

1,665 lines (1,522 loc) 900 kB
/** * @toast-ui/editor * @version 3.2.2 | Fri Feb 17 2023 * @author NHN Cloud FE Development Lab <dl_javascript@nhn.com> * @license MIT */ import { Fragment, Schema, Slice, NodeRange, Mark as Mark$1, DOMParser, Node as Node$3 } from 'prosemirror-model'; import { DecorationSet, Decoration, EditorView } from 'prosemirror-view'; import { ReplaceAroundStep, liftTarget, canSplit, StepMap } from 'prosemirror-transform'; import { TextSelection, Plugin, PluginKey, EditorState, AllSelection, Selection, SelectionRange, NodeSelection } from 'prosemirror-state'; import { keymap } from 'prosemirror-keymap'; import { deleteSelection, selectAll, baseKeymap, chainCommands, joinForward, newlineInCode, setBlockType, wrapIn, toggleMark as toggleMark$1, exitCode } from 'prosemirror-commands'; import { InputRule, inputRules, undoInputRule } from 'prosemirror-inputrules'; import { undo, redo, history, undoDepth } from 'prosemirror-history'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics$1 = function(d, b) { extendStatics$1 = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics$1(d, b); }; function __extends$1(d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics$1(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign$1 = function() { __assign$1 = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign$1.apply(this, arguments); }; function __spreadArray$1(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); } function __makeTemplateObject(cooked, raw) { if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } return cooked; } /** * @fileoverview Execute the provided callback once for each property of object which actually exist. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ /** * Execute the provided callback once for each property of object which actually exist. * If the callback function returns false, the loop will be stopped. * Callback function(iteratee) is invoked with three arguments: * 1) The value of the property * 2) The name of the property * 3) The object being traversed * @param {Object} obj The object that will be traversed * @param {function} iteratee Callback function * @param {Object} [context] Context(this) of callback function * @memberof module:collection * @example * // ES6 * import forEachOwnProperties from 'tui-code-snippet/collection/forEachOwnProperties'; * * // CommonJS * const forEachOwnProperties = require('tui-code-snippet/collection/forEachOwnProperties'); * * let sum = 0; * * forEachOwnProperties({a:1,b:2,c:3}, function(value){ * sum += value; * }); * alert(sum); // 6 */ function forEachOwnProperties$2(obj, iteratee, context) { var key; context = context || null; for (key in obj) { if (obj.hasOwnProperty(key)) { if (iteratee.call(context, obj[key], key, obj) === false) { break; } } } } var forEachOwnProperties_1 = forEachOwnProperties$2; /** * @fileoverview Extend the target object from other objects. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ /** * @module object */ /** * Extend the target object from other objects. * @param {object} target - Object that will be extended * @param {...object} objects - Objects as sources * @returns {object} Extended object * @memberof module:object */ function extend(target, objects) { // eslint-disable-line no-unused-vars var hasOwnProp = Object.prototype.hasOwnProperty; var source, prop, i, len; for (i = 1, len = arguments.length; i < len; i += 1) { source = arguments[i]; for (prop in source) { if (hasOwnProp.call(source, prop)) { target[prop] = source[prop]; } } } return target; } var extend_1 = extend; /** * @fileoverview Check whether the given variable is a string or not. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ /** * Check whether the given variable is a string or not. * If the given variable is a string, return true. * @param {*} obj - Target for checking * @returns {boolean} Is string? * @memberof module:type */ function isString$3(obj) { return typeof obj === 'string' || obj instanceof String; } var isString_1 = isString$3; /** * @fileoverview Check whether the given variable is an instance of Array or not. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ /** * Check whether the given variable is an instance of Array or not. * If the given variable is an instance of Array, return true. * @param {*} obj - Target for checking * @returns {boolean} Is array instance? * @memberof module:type */ function isArray$3(obj) { return obj instanceof Array; } var isArray_1 = isArray$3; /** * @fileoverview Execute the provided callback once for each element present in the array(or Array-like object) in ascending order. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ /** * Execute the provided callback once for each element present * in the array(or Array-like object) in ascending order. * If the callback function returns false, the loop will be stopped. * Callback function(iteratee) is invoked with three arguments: * 1) The value of the element * 2) The index of the element * 3) The array(or Array-like object) being traversed * @param {Array|Arguments|NodeList} arr The array(or Array-like object) that will be traversed * @param {function} iteratee Callback function * @param {Object} [context] Context(this) of callback function * @memberof module:collection * @example * // ES6 * import forEachArray from 'tui-code-snippet/collection/forEachArray'; * * // CommonJS * const forEachArray = require('tui-code-snippet/collection/forEachArray'); * * let sum = 0; * * forEachArray([1,2,3], function(value){ * sum += value; * }); * alert(sum); // 6 */ function forEachArray$3(arr, iteratee, context) { var index = 0; var len = arr.length; context = context || null; for (; index < len; index += 1) { if (iteratee.call(context, arr[index], index, arr) === false) { break; } } } var forEachArray_1 = forEachArray$3; /** * @fileoverview Execute the provided callback once for each property of object(or element of array) which actually exist. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var isArray$2 = isArray_1; var forEachArray$2 = forEachArray_1; var forEachOwnProperties$1 = forEachOwnProperties_1; /** * @module collection */ /** * Execute the provided callback once for each property of object(or element of array) which actually exist. * If the object is Array-like object(ex-arguments object), It needs to transform to Array.(see 'ex2' of example). * If the callback function returns false, the loop will be stopped. * Callback function(iteratee) is invoked with three arguments: * 1) The value of the property(or The value of the element) * 2) The name of the property(or The index of the element) * 3) The object being traversed * @param {Object} obj The object that will be traversed * @param {function} iteratee Callback function * @param {Object} [context] Context(this) of callback function * @memberof module:collection * @example * // ES6 * import forEach from 'tui-code-snippet/collection/forEach'; * * // CommonJS * const forEach = require('tui-code-snippet/collection/forEach'); * * let sum = 0; * * forEach([1,2,3], function(value){ * sum += value; * }); * alert(sum); // 6 * * // In case of Array-like object * const array = Array.prototype.slice.call(arrayLike); // change to array * forEach(array, function(value){ * sum += value; * }); */ function forEach$4(obj, iteratee, context) { if (isArray$2(obj)) { forEachArray$2(obj, iteratee, context); } else { forEachOwnProperties$1(obj, iteratee, context); } } var forEach_1 = forEach$4; /** * @fileoverview Setting element style * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var isString$2 = isString_1; var forEach$3 = forEach_1; /** * Setting element style * @param {(HTMLElement|SVGElement)} element - element to setting style * @param {(string|object)} key - style prop name or {prop: value} pair object * @param {string} [value] - style value * @memberof module:domUtil */ function css(element, key, value) { var style = element.style; if (isString$2(key)) { style[key] = value; return; } forEach$3(key, function(v, k) { style[k] = v; }); } var css_1 = css; /* eslint-disable complexity */ var isArray$1 = isArray_1; /** * @module array */ /** * Returns the first index at which a given element can be found in the array * from start index(default 0), or -1 if it is not present. * It compares searchElement to elements of the Array using strict equality * (the same method used by the ===, or triple-equals, operator). * @param {*} searchElement Element to locate in the array * @param {Array} array Array that will be traversed. * @param {number} startIndex Start index in array for searching (default 0) * @returns {number} the First index at which a given element, or -1 if it is not present * @memberof module:array * @example * // ES6 * import inArray from 'tui-code-snippet/array/inArray'; * * // CommonJS * const inArray = require('tui-code-snippet/array/inArray'); * * const arr = ['one', 'two', 'three', 'four']; * const idx1 = inArray('one', arr, 3); // -1 * const idx2 = inArray('one', arr); // 0 */ function inArray$4(searchElement, array, startIndex) { var i; var length; startIndex = startIndex || 0; if (!isArray$1(array)) { return -1; } if (Array.prototype.indexOf) { return Array.prototype.indexOf.call(array, searchElement, startIndex); } length = array.length; for (i = startIndex; startIndex >= 0 && i < length; i += 1) { if (array[i] === searchElement) { return i; } } return -1; } var inArray_1 = inArray$4; /** * @fileoverview Check whether the given variable is undefined or not. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ /** * Check whether the given variable is undefined or not. * If the given variable is undefined, returns true. * @param {*} obj - Target for checking * @returns {boolean} Is undefined? * @memberof module:type */ function isUndefined$4(obj) { return obj === undefined; // eslint-disable-line no-undefined } var isUndefined_1 = isUndefined$4; /** * @fileoverview Get HTML element's design classes. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var isUndefined$3 = isUndefined_1; /** * Get HTML element's design classes. * @param {(HTMLElement|SVGElement)} element target element * @returns {string} element css class name * @memberof module:domUtil */ function getClass$3(element) { if (!element || !element.className) { return ''; } if (isUndefined$3(element.className.baseVal)) { return element.className; } return element.className.baseVal; } var getClass_1 = getClass$3; /** * @fileoverview Set className value * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var isArray = isArray_1; var isUndefined$2 = isUndefined_1; /** * Set className value * @param {(HTMLElement|SVGElement)} element - target element * @param {(string|string[])} cssClass - class names * @private */ function setClassName$2(element, cssClass) { cssClass = isArray(cssClass) ? cssClass.join(' ') : cssClass; cssClass = cssClass.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); if (isUndefined$2(element.className.baseVal)) { element.className = cssClass; return; } element.className.baseVal = cssClass; } var _setClassName = setClassName$2; /** * @fileoverview Add css class to element * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var forEach$2 = forEach_1; var inArray$3 = inArray_1; var getClass$2 = getClass_1; var setClassName$1 = _setClassName; /** * domUtil module * @module domUtil */ /** * Add css class to element * @param {(HTMLElement|SVGElement)} element - target element * @param {...string} cssClass - css classes to add * @memberof module:domUtil */ function addClass(element) { var cssClass = Array.prototype.slice.call(arguments, 1); var classList = element.classList; var newClass = []; var origin; if (classList) { forEach$2(cssClass, function(name) { element.classList.add(name); }); return; } origin = getClass$2(element); if (origin) { cssClass = [].concat(origin.split(/\s+/), cssClass); } forEach$2(cssClass, function(cls) { if (inArray$3(cls, newClass) < 0) { newClass.push(cls); } }); setClassName$1(element, newClass); } var addClass_1 = addClass; /** * @fileoverview Remove css class from element * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var forEachArray$1 = forEachArray_1; var inArray$2 = inArray_1; var getClass$1 = getClass_1; var setClassName = _setClassName; /** * Remove css class from element * @param {(HTMLElement|SVGElement)} element - target element * @param {...string} cssClass - css classes to remove * @memberof module:domUtil */ function removeClass(element) { var cssClass = Array.prototype.slice.call(arguments, 1); var classList = element.classList; var origin, newClass; if (classList) { forEachArray$1(cssClass, function(name) { classList.remove(name); }); return; } origin = getClass$1(element).split(/\s+/); newClass = []; forEachArray$1(origin, function(name) { if (inArray$2(name, cssClass) < 0) { newClass.push(name); } }); setClassName(element, newClass); } var removeClass_1 = removeClass; /** * @fileoverview Check whether the given variable is a number or not. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ /** * Check whether the given variable is a number or not. * If the given variable is a number, return true. * @param {*} obj - Target for checking * @returns {boolean} Is number? * @memberof module:type */ function isNumber(obj) { return typeof obj === 'number' || obj instanceof Number; } var isNumber_1 = isNumber; /** * @fileoverview Check whether the given variable is null or not. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ /** * Check whether the given variable is null or not. * If the given variable(arguments[0]) is null, returns true. * @param {*} obj - Target for checking * @returns {boolean} Is null? * @memberof module:type */ function isNull$1(obj) { return obj === null; } var isNull_1 = isNull$1; /** * @fileoverview Request image ping. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var forEachOwnProperties = forEachOwnProperties_1; /** * @module request */ /** * Request image ping. * @param {String} url url for ping request * @param {Object} trackingInfo infos for make query string * @returns {HTMLElement} * @memberof module:request * @example * // ES6 * import imagePing from 'tui-code-snippet/request/imagePing'; * * // CommonJS * const imagePing = require('tui-code-snippet/request/imagePing'); * * imagePing('https://www.google-analytics.com/collect', { * v: 1, * t: 'event', * tid: 'trackingid', * cid: 'cid', * dp: 'dp', * dh: 'dh' * }); */ function imagePing$1(url, trackingInfo) { var trackingElement = document.createElement('img'); var queryString = ''; forEachOwnProperties(trackingInfo, function(value, key) { queryString += '&' + key + '=' + value; }); queryString = queryString.substring(1); trackingElement.src = url + '?' + queryString; trackingElement.style.display = 'none'; document.body.appendChild(trackingElement); document.body.removeChild(trackingElement); return trackingElement; } var imagePing_1 = imagePing$1; /** * @fileoverview Send hostname on DOMContentLoaded. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var isUndefined$1 = isUndefined_1; var imagePing = imagePing_1; var ms7days = 7 * 24 * 60 * 60 * 1000; /** * Check if the date has passed 7 days * @param {number} date - milliseconds * @returns {boolean} * @private */ function isExpired(date) { var now = new Date().getTime(); return now - date > ms7days; } /** * Send hostname on DOMContentLoaded. * To prevent hostname set tui.usageStatistics to false. * @param {string} appName - application name * @param {string} trackingId - GA tracking ID * @ignore */ function sendHostname(appName, trackingId) { var url = 'https://www.google-analytics.com/collect'; var hostname = location.hostname; var hitType = 'event'; var eventCategory = 'use'; var applicationKeyForStorage = 'TOAST UI ' + appName + ' for ' + hostname + ': Statistics'; var date = window.localStorage.getItem(applicationKeyForStorage); // skip if the flag is defined and is set to false explicitly if (!isUndefined$1(window.tui) && window.tui.usageStatistics === false) { return; } // skip if not pass seven days old if (date && !isExpired(date)) { return; } window.localStorage.setItem(applicationKeyForStorage, new Date().getTime()); setTimeout(function() { if (document.readyState === 'interactive' || document.readyState === 'complete') { imagePing(url, { v: 1, t: hitType, tid: trackingId, cid: hostname, dp: hostname, dh: appName, el: appName, ec: eventCategory }); } }, 1000); } var sendHostname_1 = sendHostname; /Mac/.test(navigator.platform); var reSpaceMoreThanOne = /[\u0020]+/g; var reEscapeChars$1 = /[>(){}[\]+-.!#|]/g; var reEscapeHTML = /<([a-zA-Z_][a-zA-Z0-9\-._]*)(\s|[^\\>])*\/?>|<(\/)([a-zA-Z_][a-zA-Z0-9\-._]*)\s*\/?>|<!--[^-]+-->|<([a-zA-Z_][a-zA-Z0-9\-.:/]*)>/g; var reEscapeBackSlash = /\\[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~\\]/g; var reEscapePairedChars = /[*_~`]/g; var reMdImageSyntax = /!\[.*\]\(.*\)/g; var reEscapedCharInLinkSyntax = /[[\]]/g; var reEscapeBackSlashInSentence = /(?:^|[^\\])\\(?!\\)/g; var XMLSPECIAL$1 = '[&<>"]'; var reXmlSpecial$1 = new RegExp(XMLSPECIAL$1, 'g'); function replaceUnsafeChar$1(char) { switch (char) { case '&': return '&amp;'; case '<': return '&lt;'; case '>': return '&gt;'; case '"': return '&quot;'; default: return char; } } function escapeXml$1(text) { if (reXmlSpecial$1.test(text)) { return text.replace(reXmlSpecial$1, replaceUnsafeChar$1); } return text; } function sendHostName() { sendHostname_1('editor', 'UA-129966929-1'); } function includes(arr, targetItem) { return arr.indexOf(targetItem) !== -1; } var availableLinkAttributes = ['rel', 'target', 'hreflang', 'type']; var reMarkdownTextToEscapeMap = { codeblock: /(^ {4}[^\n]+\n*)+/, thematicBreak: /^ *((\* *){3,}|(- *){3,} *|(_ *){3,}) */, atxHeading: /^(#{1,6}) +[\s\S]+/, seTextheading: /^([^\n]+)\n *(=|-){2,} */, blockquote: /^( *>[^\n]+.*)+/, list: /^ *(\*+|-+|\d+\.) [\s\S]+/, def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? */, link: /!?\[.*\]\(.*\)/, reflink: /!?\[.*\]\s*\[([^\]]*)\]/, verticalBar: /\u007C/, fencedCodeblock: /^((`|~){3,})/, }; function sanitizeLinkAttribute(attribute) { if (!attribute) { return null; } var linkAttributes = {}; availableLinkAttributes.forEach(function (key) { if (!isUndefined_1(attribute[key])) { linkAttributes[key] = attribute[key]; } }); return linkAttributes; } function repeat$1(text, count) { var result = ''; for (var i = 0; i < count; i += 1) { result += text; } return result; } function isNeedEscapeText(text) { var needEscape = false; forEachOwnProperties_1(reMarkdownTextToEscapeMap, function (reMarkdownTextToEscape) { if (reMarkdownTextToEscape.test(text)) { needEscape = true; } return !needEscape; }); return needEscape; } function escapeTextForLink(text) { var imageSyntaxRanges = []; var result = reMdImageSyntax.exec(text); while (result) { imageSyntaxRanges.push([result.index, result.index + result[0].length]); result = reMdImageSyntax.exec(text); } return text.replace(reEscapedCharInLinkSyntax, function (matched, offset) { var isDelimiter = imageSyntaxRanges.some(function (range) { return offset > range[0] && offset < range[1]; }); return isDelimiter ? matched : "\\" + matched; }); } function escape$1(text) { var aheadReplacer = function (matched) { return "\\" + matched; }; var behindReplacer = function (matched) { return matched + "\\"; }; var escapedText = text.replace(reSpaceMoreThanOne, ' '); if (reEscapeBackSlash.test(escapedText)) { escapedText = escapedText.replace(reEscapeBackSlash, aheadReplacer); } if (reEscapeBackSlashInSentence.test(escapedText)) { escapedText = escapedText.replace(reEscapeBackSlashInSentence, behindReplacer); } escapedText = escapedText.replace(reEscapePairedChars, aheadReplacer); if (reEscapeHTML.test(escapedText)) { escapedText = escapedText.replace(reEscapeHTML, aheadReplacer); } if (isNeedEscapeText(escapedText)) { escapedText = escapedText.replace(reEscapeChars$1, aheadReplacer); } return escapedText; } function quote(text) { var result; if (text.indexOf('"') === -1) { result = '""'; } else { result = text.indexOf("'") === -1 ? "''" : '()'; } return result[0] + text + result[1]; } function isNil(value) { return isNull_1(value) || isUndefined_1(value); } function shallowEqual(o1, o2) { if (o1 === null && o1 === o2) { return true; } if (typeof o1 !== 'object' || typeof o2 !== 'object' || isNil(o1) || isNil(o2)) { return o1 === o2; } for (var key in o1) { if (o1[key] !== o2[key]) { return false; } } for (var key in o2) { if (!(key in o1)) { return false; } } return true; } function last$1(arr) { return arr[arr.length - 1]; } function between$1(value, min, max) { return value >= min && value <= max; } function isObject$1(obj) { return typeof obj === 'object' && obj !== null; } function deepMergedCopy(targetObj, obj) { var resultObj = __assign$1({}, targetObj); if (targetObj && obj) { Object.keys(obj).forEach(function (prop) { if (isObject$1(resultObj[prop])) { if (Array.isArray(obj[prop])) { resultObj[prop] = deepCopyArray(obj[prop]); } else if (resultObj.hasOwnProperty(prop)) { resultObj[prop] = deepMergedCopy(resultObj[prop], obj[prop]); } else { resultObj[prop] = deepCopy(obj[prop]); } } else { resultObj[prop] = obj[prop]; } }); } return resultObj; } function deepCopyArray(items) { return items.map(function (item) { if (isObject$1(item)) { return Array.isArray(item) ? deepCopyArray(item) : deepCopy(item); } return item; }); } function deepCopy(obj) { var keys = Object.keys(obj); if (!keys.length) { return obj; } return keys.reduce(function (acc, prop) { if (isObject$1(obj[prop])) { acc[prop] = Array.isArray(obj[prop]) ? deepCopyArray(obj[prop]) : deepCopy(obj[prop]); } else { acc[prop] = obj[prop]; } return acc; }, {}); } function assign(targetObj, obj) { if (obj === void 0) { obj = {}; } Object.keys(obj).forEach(function (prop) { if (targetObj.hasOwnProperty(prop) && typeof targetObj[prop] === 'object') { if (Array.isArray(obj[prop])) { targetObj[prop] = obj[prop]; } else { assign(targetObj[prop], obj[prop]); } } else { targetObj[prop] = obj[prop]; } }); return targetObj; } function getSortedNumPair(valueA, valueB) { return valueA > valueB ? [valueB, valueA] : [valueA, valueB]; } /** * @fileoverview Transform the Array-like object to Array. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var forEachArray = forEachArray_1; /** * Transform the Array-like object to Array. * In low IE (below 8), Array.prototype.slice.call is not perfect. So, try-catch statement is used. * @param {*} arrayLike Array-like object * @returns {Array} Array * @memberof module:collection * @example * // ES6 * import toArray from 'tui-code-snippet/collection/toArray'; * * // CommonJS * const toArray = require('tui-code-snippet/collection/toArray'); * * const arrayLike = { * 0: 'one', * 1: 'two', * 2: 'three', * 3: 'four', * length: 4 * }; * const result = toArray(arrayLike); * * alert(result instanceof Array); // true * alert(result); // one,two,three,four */ function toArray$1(arrayLike) { var arr; try { arr = Array.prototype.slice.call(arrayLike); } catch (e) { arr = []; forEachArray(arrayLike, function(value) { arr.push(value); }); } return arr; } var toArray_1 = toArray$1; function createParagraph(schema, content) { var paragraph = schema.nodes.paragraph; if (!content) { return paragraph.createAndFill(); } return paragraph.create(null, isString_1(content) ? schema.text(content) : content); } function createTextNode$1(schema, text, marks) { return schema.text(text, marks); } function createTextSelection(tr, from, to) { if (to === void 0) { to = from; } var contentSize = tr.doc.content.size; var size = contentSize > 0 ? contentSize - 1 : 1; return TextSelection.create(tr.doc, Math.min(from, size), Math.min(to, size)); } function addParagraph(tr, _a, schema) { var pos = _a.pos; tr.replaceWith(pos, pos, createParagraph(schema)); return tr.setSelection(createTextSelection(tr, pos + 1)); } function replaceTextNode(_a) { var state = _a.state, from = _a.from, startIndex = _a.startIndex, endIndex = _a.endIndex, createText = _a.createText; var tr = state.tr, doc = state.doc, schema = state.schema; for (var i = startIndex; i <= endIndex; i += 1) { var _b = doc.child(i), nodeSize = _b.nodeSize, textContent = _b.textContent, content = _b.content; var text = createText(textContent); var node = text ? createTextNode$1(schema, text) : Fragment.empty; var mappedFrom = tr.mapping.map(from); var mappedTo = mappedFrom + content.size; tr.replaceWith(mappedFrom, mappedTo, node); from += nodeSize; } return tr; } function splitAndExtendBlock(tr, pos, text, node) { var textLen = text.length; tr.split(pos) .delete(pos - textLen, pos) .insert(tr.mapping.map(pos), node) .setSelection(createTextSelection(tr, tr.mapping.map(pos) - textLen)); } function getMdStartLine(mdNode) { return mdNode.sourcepos[0][0]; } function getMdEndLine(mdNode) { return mdNode.sourcepos[1][0]; } function getMdStartCh(mdNode) { return mdNode.sourcepos[0][1]; } function getMdEndCh(mdNode) { return mdNode.sourcepos[1][1]; } function isHTMLNode(mdNode) { var type = mdNode.type; return type === 'htmlBlock' || type === 'htmlInline'; } function isStyledInlineNode(mdNode) { var type = mdNode.type; return (type === 'strike' || type === 'strong' || type === 'emph' || type === 'code' || type === 'link' || type === 'image'); } function isCodeBlockNode(mdNode) { return mdNode && mdNode.type === 'codeBlock'; } function isListNode$1(mdNode) { return mdNode && (mdNode.type === 'item' || mdNode.type === 'list'); } function isOrderedListNode(mdNode) { return isListNode$1(mdNode) && mdNode.listData.type === 'ordered'; } function isBulletListNode(mdNode) { return isListNode$1(mdNode) && mdNode.listData.type !== 'ordered'; } function isTableCellNode(mdNode) { return mdNode && (mdNode.type === 'tableCell' || mdNode.type === 'tableDelimCell'); } function isInlineNode$1(mdNode) { switch (mdNode.type) { case 'code': case 'text': case 'emph': case 'strong': case 'strike': case 'link': case 'image': case 'htmlInline': case 'linebreak': case 'softbreak': case 'customInline': return true; default: return false; } } function findClosestNode(mdNode, condition, includeSelf) { if (includeSelf === void 0) { includeSelf = true; } mdNode = includeSelf ? mdNode : mdNode.parent; while (mdNode && mdNode.type !== 'document') { if (condition(mdNode)) { return mdNode; } mdNode = mdNode.parent; } return null; } function traverseParentNodes(mdNode, iteratee, includeSelf) { if (includeSelf === void 0) { includeSelf = true; } mdNode = includeSelf ? mdNode : mdNode.parent; while (mdNode && mdNode.type !== 'document') { iteratee(mdNode); mdNode = mdNode.parent; } } function addOffsetPos(originPos, offset) { return [originPos[0], originPos[1] + offset]; } function setOffsetPos(originPos, newOffset) { return [originPos[0], newOffset]; } function getInlineMarkdownText(mdNode) { var text = mdNode.firstChild.literal; switch (mdNode.type) { case 'emph': return "*" + text + "*"; case 'strong': return "**" + text + "**"; case 'strike': return "~~" + text + "~~"; case 'code': return "`" + text + "`"; case 'link': case 'image': /* eslint-disable no-case-declarations */ var _a = mdNode, destination = _a.destination, title = _a.title; var delim = mdNode.type === 'link' ? '' : '!'; return delim + "[" + text + "](" + destination + (title ? " \"" + title + "\"" : '') + ")"; default: return null; } } function isContainer$2(node) { switch (node.type) { case 'document': case 'blockQuote': case 'list': case 'item': case 'paragraph': case 'heading': case 'emph': case 'strong': case 'strike': case 'link': case 'image': case 'table': case 'tableHead': case 'tableBody': case 'tableRow': case 'tableCell': case 'tableDelimRow': case 'customInline': return true; default: return false; } } function getChildrenText$1(node) { var buffer = []; var walker = node.walker(); var event = null; while ((event = walker.next())) { var childNode = event.node; if (childNode.type === 'text') { buffer.push(childNode.literal); } } return buffer.join(''); } var widgetRules = []; var widgetRuleMap = {}; var reWidgetPrefix = /\$\$widget\d+\s/; function unwrapWidgetSyntax(text) { var index = text.search(reWidgetPrefix); if (index !== -1) { var rest = text.substring(index); var replaced = rest.replace(reWidgetPrefix, '').replace('$$', ''); text = text.substring(0, index); text += unwrapWidgetSyntax(replaced); } return text; } function createWidgetContent(info, text) { return "$$" + info + " " + text + "$$"; } function widgetToDOM(info, text) { var _a = widgetRuleMap[info], rule = _a.rule, toDOM = _a.toDOM; var matches = unwrapWidgetSyntax(text).match(rule); if (matches) { text = matches[0]; } return toDOM(text); } function getWidgetRules() { return widgetRules; } function setWidgetRules(rules) { widgetRules = rules; widgetRules.forEach(function (rule, index) { widgetRuleMap["widget" + index] = rule; }); } function mergeNodes(nodes, text, schema, ruleIndex) { return nodes.concat(createNodesWithWidget(text, schema, ruleIndex)); } /** * create nodes with plain text and replace text matched to the widget rules with the widget node * For example, in case the text and widget rules as below * * text: $test plain text #test * widget rules: [{ rule: /$.+/ }, { rule: /#.+/ }] * * The creating node process is recursive and is as follows. * * in first widget rule(/$.+/) * $test -> widget node * plain text -> match with next widget rule * #test -> match with next widget rule * * in second widget rule(/#.+/) * plain text -> text node(no rule for matching) * #test -> widget node */ function createNodesWithWidget(text, schema, ruleIndex) { if (ruleIndex === void 0) { ruleIndex = 0; } var nodes = []; var rule = (widgetRules[ruleIndex] || {}).rule; var nextRuleIndex = ruleIndex + 1; text = unwrapWidgetSyntax(text); if (rule && rule.test(text)) { var index = void 0; while ((index = text.search(rule)) !== -1) { var prev = text.substring(0, index); // get widget node on first splitted text using next widget rule if (prev) { nodes = mergeNodes(nodes, prev, schema, nextRuleIndex); } // build widget node using current widget rule text = text.substring(index); var literal = text.match(rule)[0]; var info = "widget" + ruleIndex; nodes.push(schema.nodes.widget.create({ info: info }, schema.text(createWidgetContent(info, literal)))); text = text.substring(literal.length); } // get widget node on last splitted text using next widget rule if (text) { nodes = mergeNodes(nodes, text, schema, nextRuleIndex); } } else if (text) { nodes = ruleIndex < widgetRules.length - 1 ? mergeNodes(nodes, text, schema, nextRuleIndex) : [schema.text(text)]; } return nodes; } function getWidgetContent(widgetNode) { var event; var text = ''; var walker = widgetNode.walker(); while ((event = walker.next())) { var node = event.node, entering = event.entering; if (entering) { if (node !== widgetNode && node.type !== 'text') { text += getInlineMarkdownText(node); // skip the children walker.resumeAt(widgetNode, false); walker.next(); } else if (node.type === 'text') { text += node.literal; } } } return text; } function getDefaultCommands() { return { deleteSelection: function () { return deleteSelection; }, selectAll: function () { return selectAll; }, undo: function () { return undo; }, redo: function () { return redo; }, }; } function placeholder(options) { return new Plugin({ props: { decorations: function (state) { var doc = state.doc; if (options.text && doc.childCount === 1 && doc.firstChild.isTextblock && doc.firstChild.content.size === 0) { var placeHolder = document.createElement('span'); addClass_1(placeHolder, 'placeholder'); if (options.className) { addClass_1(placeHolder, options.className); } placeHolder.textContent = options.text; return DecorationSet.create(doc, [Decoration.widget(1, placeHolder)]); } return null; }, }, }); } /** * @fileoverview Check element has specific css class * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var inArray$1 = inArray_1; var getClass = getClass_1; /** * Check element has specific css class * @param {(HTMLElement|SVGElement)} element - target element * @param {string} cssClass - css class * @returns {boolean} * @memberof module:domUtil */ function hasClass(element, cssClass) { var origin; if (element.classList) { return element.classList.contains(cssClass); } origin = getClass(element).split(/\s+/); return inArray$1(cssClass, origin) > -1; } var hasClass_1 = hasClass; /** * @fileoverview Check element match selector * @author NHN FE Development Lab <dl_javascript@nhn.com> */ var inArray = inArray_1; var toArray = toArray_1; var elProto = Element.prototype; var matchSelector = elProto.matches || elProto.webkitMatchesSelector || elProto.mozMatchesSelector || elProto.msMatchesSelector || function(selector) { var doc = this.document || this.ownerDocument; return inArray(this, toArray(doc.querySelectorAll(selector))) > -1; }; /** * Check element match selector * @param {HTMLElement} element - element to check * @param {string} selector - selector to check * @returns {boolean} is selector matched to element? * @memberof module:domUtil */ function matches(element, selector) { return matchSelector.call(element, selector); } var matches_1 = matches; var TAG_NAME = '[A-Za-z][A-Za-z0-9-]*'; var ATTRIBUTE_NAME = '[a-zA-Z_:][a-zA-Z0-9:._-]*'; var UNQUOTED_VALUE = '[^"\'=<>`\\x00-\\x20]+'; var SINGLE_QUOTED_VALUE = "'[^']*'"; var DOUBLE_QUOTED_VALUE = '"[^"]*"'; var ATTRIBUTE_VALUE = "(?:" + UNQUOTED_VALUE + "|" + SINGLE_QUOTED_VALUE + "|" + DOUBLE_QUOTED_VALUE + ")"; var ATTRIBUTE_VALUE_SPEC = "" + '(?:\\s*=\\s*' + ATTRIBUTE_VALUE + ")"; var ATTRIBUTE$1 = "" + '(?:\\s+' + ATTRIBUTE_NAME + ATTRIBUTE_VALUE_SPEC + "?)"; var OPEN_TAG = "<(" + TAG_NAME + ")(" + ATTRIBUTE$1 + ")*\\s*/?>"; var CLOSE_TAG = "</(" + TAG_NAME + ")\\s*[>]"; var HTML_TAG = "(?:" + OPEN_TAG + "|" + CLOSE_TAG + ")"; var reHTMLTag = new RegExp("^" + HTML_TAG, 'i'); var reBR = /<br\s*\/*>/i; var reHTMLComment = /<! ---->|<!--(?:-?[^>-])(?:-?[^-])*-->/; var ALTERNATIVE_TAG_FOR_BR = '</p><p>'; function isPositionInBox(style, offsetX, offsetY) { var left = parseInt(style.left, 10); var top = parseInt(style.top, 10); var width = parseInt(style.width, 10) + parseInt(style.paddingLeft, 10) + parseInt(style.paddingRight, 10); var height = parseInt(style.height, 10) + parseInt(style.paddingTop, 10) + parseInt(style.paddingBottom, 10); return offsetX >= left && offsetX <= left + width && offsetY >= top && offsetY <= top + height; } var CLS_PREFIX = 'toastui-editor-'; function cls() { var names = []; for (var _i = 0; _i < arguments.length; _i++) { names[_i] = arguments[_i]; } var result = []; for (var _a = 0, names_1 = names; _a < names_1.length; _a++) { var name_1 = names_1[_a]; var className = void 0; if (Array.isArray(name_1)) { className = name_1[0] ? name_1[1] : null; } else { className = name_1; } if (className) { result.push("" + CLS_PREFIX + className); } } return result.join(' '); } function clsWithMdPrefix() { var names = []; for (var _i = 0; _i < arguments.length; _i++) { names[_i] = arguments[_i]; } return names.map(function (className) { return CLS_PREFIX + "md-" + className; }).join(' '); } function isTextNode(node) { return (node === null || node === void 0 ? void 0 : node.nodeType) === Node.TEXT_NODE; } function isElemNode(node) { return node && node.nodeType === Node.ELEMENT_NODE; } function findNodes(element, selector) { var nodeList = toArray_1(element.querySelectorAll(selector)); if (nodeList.length) { return nodeList; } return []; } function appendNodes(node, nodesToAppend) { nodesToAppend = isArray_1(nodesToAppend) ? toArray_1(nodesToAppend) : [nodesToAppend]; nodesToAppend.forEach(function (nodeToAppend) { node.appendChild(nodeToAppend); }); } function insertBeforeNode(insertedNode, node) { if (node.parentNode) { node.parentNode.insertBefore(insertedNode, node); } } function removeNode$1(node) { if (node.parentNode) { node.parentNode.removeChild(node); } } function unwrapNode(node) { var result = []; while (node.firstChild) { result.push(node.firstChild); if (node.parentNode) { node.parentNode.insertBefore(node.firstChild, node); } } removeNode$1(node); return result; } function toggleClass(element, className, state) { if (isUndefined_1(state)) { state = !hasClass_1(element, className); } var toggleFn = state ? addClass_1 : removeClass_1; toggleFn(element, className); } function createElementWith(contents, target) { var container = document.createElement('div'); if (isString_1(contents)) { container.innerHTML = contents; } else { container.appendChild(contents); } var firstChild = container.firstChild; if (target) { target.appendChild(firstChild); } return firstChild; } function getOuterWidth(el) { var computed = window.getComputedStyle(el); return (['margin-left', 'margin-right'].reduce(function (acc, type) { return acc + parseInt(computed.getPropertyValue(type), 10); }, 0) + el.offsetWidth); } function closest(node, found) { var condition; if (isString_1(found)) { condition = function (target) { return matches_1(target, found); }; } else { condition = function (target) { return target === found; }; } while (node && node !== document) { if (isElemNode(node) && condition(node)) { return node; } node = node.parentNode; } return null; } function getTotalOffset(el, root) { var offsetTop = 0; var offsetLeft = 0; while (el && el !== root) { var top_1 = el.offsetTop, left = el.offsetLeft, offsetParent = el.offsetParent; offsetTop += top_1; offsetLeft += left; if (offsetParent === root.offsetParent) { break; } el = el.offsetParent; } return { offsetTop: offsetTop, offsetLeft: offsetLeft }; } function setAttributes(attributes, element) { Object.keys(attributes).forEach(function (attrName) { if (isNil(attributes[attrName])) { element.removeAttribute(attrName); } else { element.setAttribute(attrName, attributes[attrName]); } }); } function replaceBRWithEmptyBlock(html) { // remove br in paragraph to compatible with markdown var replacedHTML = html.replace(/<p><br\s*\/*><\/p>/gi, '<p></p>'); var reHTMLTag = new RegExp(HTML_TAG, 'ig'); var htmlTagMatched = replacedHTML.match(reHTMLTag); htmlTagMatched === null || htmlTagMatched === void 0 ? void 0 : htmlTagMatched.forEach(function (htmlTag, index) { if (reBR.test(htmlTag)) { var alternativeTag = ALTERNATIVE_TAG_FOR_BR; if (index) { var prevTag = htmlTagMatched[index - 1]; var openTagMatched = prevTag.match(OPEN_TAG); if (openTagMatched && !/br/i.test(openTagMatched[1])) { var tagName = openTagMatched[1]; alternativeTag = "</" + tagName + "><" + tagName + ">"; } } replacedHTML = replacedHTML.replace(reBR, alternativeTag); } }); return replacedHTML; } function removeProseMirrorHackNodes(html) { var reProseMirrorImage = /<img class="ProseMirror-separator" alt="">/g; var reProseMirrorTrailingBreak = / class="ProseMirror-trailingBreak"/g; var resultHTML = html; resultHTML = resultHTML.replace(reProseMirrorImage, ''); resultHTML = resultHTML.replace(reProseMirrorTrailingBreak, ''); return resultHTML; } var pluginKey$1 = new PluginKey('widget'); var MARGIN = 5; var PopupWidget = /** @class */ (function () { function PopupWidget(view, eventEmitter) { var _this = this; this.popup = null; this.removeWidget = function () { if (_this.popup) { _this.rootEl.removeChild(_this.popup); _this.popup = null; } }; this.rootEl = view.dom.parentElement; this.eventEmitter = eventEmitter; this.eventEmitter.listen('blur', this.removeWidget); this.eventEmitter.listen('loadUI', function () { _this.rootEl = closest(view.dom.parentElement, "." + cls('defaultUI')); }); this.eventEmitter.listen('removePopupWidget', this.removeWidget); } PopupWidget.prototype.update = function (view) { var widget = pluginKey$1.getState(view.state); this.removeWidget(); if (widget) { var node = widget.node, style = widget.style; var _a = view.coordsAtPos(widget.pos), top_1 = _a.top, left = _a.left, bottom = _a.bottom; var height = bottom - top_1; var rect = this.rootEl.getBoundingClientRect(); var relTopPos = top_1 - rect.top; css_1(node, { opacity: '0' }); this.rootEl.appendChild(node); css_1(node, { position: 'absolute', left: left - rect.left + MARGIN + "px", top: (style === 'bottom' ? relTopPos + height - MARGIN : relTopPos - height) + "px", opacity: '1', }); this.popup = node; view.focus(); } }; PopupWidget.prototype.destroy = function () { this.eventEmitter.removeEventHandler('blur', this.removeWidget); }; return PopupWidget; }()); function addWidget(eventEmitter) { return new Plugin({ key: pluginKey$1, state: { init: function () { return null; }, apply: function (tr) { return tr.getMeta('widget'); }, }, view: function (editorView) { return new PopupWidget(editorView, eventEmitter); }, }); } function addDefaultImageBlobHook(eventEmitter) { eventEmitter.listen('addImageBlobHook', function (blob, callback) { var reader = new FileReader(); reader.onload = function (_a) { var target = _a.target; return callback(target.result); }; reader.readAsDataURL(blob); }); } function emitImageBlobHook(eventEmitter, blob, type) { var hook = function (imageUrl, altText) { eventEmitter.emit('command', 'addImage', { imageUrl: imageUrl, altText: altText || blob.name || 'image', }); }; eventEmitter.emit('addImageBlobHook', blob, hook, type); } function pasteImageOnly(items) { var images = toArray_1(items).filter(function (_a) { var type = _a.type; return type.indexOf('image') !== -1; }); if (images.length === 1) { var item = images[0]; if (item) { return item.getAsFile(); } } return null; } function dropImage(_a) { var eventEmitter = _a.eventEmitter; return new Plugin({ props: { handleDOMEvents: { drop: function (_, ev) { var _a; var items = (_a = ev.dataTransfer) === null || _a === void 0 ? void 0 : _a.files; if (items) { forEachArray_1(items, function (item) { if (item.type.indexOf('image') !== -1) { ev.preventDefault(); ev.stopPropagation(); emitImageBlobHook(eventEmitter, item, ev.type); return false; } return true; }); } return true; }, }, }, }); } var Node$2 = /** @class */ (function () { function Node() { } Object.defineProperty(Node.prototype