tui-editor
Version:
GFM Markdown Wysiwyg Editor - Productive and Extensible
1,631 lines (1,324 loc) • 973 kB
JavaScript
/*!
* tui-editor
* @version 1.4.6
* @author NHN FE Development Lab <dl_javascript@nhn.com> (https://nhn.github.io/tui.editor/)
* @license MIT
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("jquery"), require("tui-code-snippet"), require("codemirror"), require("markdown-it"), require("to-mark"), require("highlight.js"), require("squire-rte"));
else if(typeof define === 'function' && define.amd)
define(["jquery", "tui-code-snippet", "codemirror", "markdown-it", "to-mark", "highlight.js", "squire-rte"], factory);
else if(typeof exports === 'object')
exports["Editor"] = factory(require("jquery"), require("tui-code-snippet"), require("codemirror"), require("markdown-it"), require("to-mark"), require("highlight.js"), require("squire-rte"));
else
root["tui"] = root["tui"] || {}, root["tui"]["Editor"] = factory(root["$"], (root["tui"] && root["tui"]["util"]), root["CodeMirror"], root["markdownit"], root["toMark"], root["hljs"], root["Squire"]);
})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_0__, __WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_6__, __WEBPACK_EXTERNAL_MODULE_22__, __WEBPACK_EXTERNAL_MODULE_23__, __WEBPACK_EXTERNAL_MODULE_32__, __WEBPACK_EXTERNAL_MODULE_67__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "dist/";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 45);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_0__;
/***/ }),
/* 1 */
/***/ (function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
* @fileoverview Implements CommandManager
* @author NHN FE Development Lab <dl_javascript@nhn.com>
*/
var _jquery = __webpack_require__(0);
var _jquery2 = _interopRequireDefault(_jquery);
var _tuiCodeSnippet = __webpack_require__(1);
var _tuiCodeSnippet2 = _interopRequireDefault(_tuiCodeSnippet);
var _command = __webpack_require__(21);
var _command2 = _interopRequireDefault(_command);
var _util = __webpack_require__(14);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var KEYMAP_OS_INDEX = _util.isMac ? 1 : 0;
/**
* Class CommandManager
*/
var CommandManager = function () {
/**
* @param {ToastUIEditor} base nedInstance
* @param {object} [options={}] - option object
* @param {boolean} [options.useCommandShortcut=true] - execute command with keyMap
*/
function CommandManager(base) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, CommandManager);
this._command = new _tuiCodeSnippet2.default.Map();
this._mdCommand = new _tuiCodeSnippet2.default.Map();
this._wwCommand = new _tuiCodeSnippet2.default.Map();
this._options = _jquery2.default.extend({
'useCommandShortcut': true
}, options);
this.base = base;
this.keyMapCommand = {};
this._initEvent();
}
/**
* You can change command before command addition by addCommandBefore event.
* @param {object} command - command
* @returns {object}
* @private
*/
_createClass(CommandManager, [{
key: '_addCommandBefore',
value: function _addCommandBefore(command) {
var commandWrapper = { command: command };
this.base.eventManager.emit('addCommandBefore', commandWrapper);
return commandWrapper.command || command;
}
/**
* Add command
* @memberof CommandManager
* @param {Command} command Command instance
* @returns {Command} Command
*/
}, {
key: 'addCommand',
value: function addCommand(command) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
if (args.length) {
command = CommandManager.command.apply(CommandManager, [command].concat(args));
}
command = this._addCommandBefore(command);
var name = command.getName();
var commandBase = void 0;
if (command.isMDType()) {
commandBase = this._mdCommand;
} else if (command.isWWType()) {
commandBase = this._wwCommand;
} else if (command.isGlobalType()) {
commandBase = this._command;
}
commandBase.set(name, command);
if (command.keyMap) {
this.keyMapCommand[command.keyMap[KEYMAP_OS_INDEX]] = name;
}
return command;
}
/**
* _initEvent
* Bind event handler to eventManager
* @private
* @memberof CommandManager
*/
}, {
key: '_initEvent',
value: function _initEvent() {
var _this = this;
this.base.eventManager.listen('command', function () {
_this.exec.apply(_this, arguments);
});
this.base.eventManager.listen('keyMap', function (ev) {
if (!_this._options.useCommandShortcut) {
return;
}
var command = _this.keyMapCommand[ev.keyMap];
if (command) {
ev.data.preventDefault();
_this.exec(command);
}
});
}
/**
* Execute command
* @memberof CommandManager
* @param {String} name Command name
* @param {*} ...args Command argument
* @returns {*}
*/
}, {
key: 'exec',
value: function exec(name) {
var commandToRun = void 0,
result = void 0;
var context = this.base;
commandToRun = this._command.get(name);
if (!commandToRun) {
if (this.base.isMarkdownMode()) {
commandToRun = this._mdCommand.get(name);
context = this.base.mdEditor;
} else {
commandToRun = this._wwCommand.get(name);
context = this.base.wwEditor;
}
}
if (commandToRun) {
var _commandToRun;
for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
args.unshift(context);
result = (_commandToRun = commandToRun).exec.apply(_commandToRun, args);
}
return result;
}
}]);
return CommandManager;
}();
/**
* Create command by given editor type and property object
* @memberof CommandManager
* @param {string} type Command type
* @param {{name: string, keyMap: Array}} props Property
* @returns {*}
*/
CommandManager.command = function (type, props) {
var command = _command2.default.factory(type, props.name, props.keyMap);
_tuiCodeSnippet2.default.extend(command, props);
return command;
};
exports.default = CommandManager;
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.I18n = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
* @fileoverview Implements i18n
* @author NHN FE Development Lab <dl_javascript@nhn.com>
*/
var _tuiCodeSnippet = __webpack_require__(1);
var _tuiCodeSnippet2 = _interopRequireDefault(_tuiCodeSnippet);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var sharedInstance = void 0;
var DEFAULT_CODE = 'en_US';
/**
* Class I18n
*/
var I18n = function () {
/**
* Creates an instance of I18n.
* @memberof I18n
*/
function I18n() {
_classCallCheck(this, I18n);
this._code = DEFAULT_CODE;
this._langs = new _tuiCodeSnippet2.default.Map();
}
/**
* Set locale code
* @param {string} code locale code
*/
_createClass(I18n, [{
key: 'setCode',
value: function setCode(code) {
this._code = code;
}
/**
* Set language set
* @param {string|string[]} codes locale code
* @param {object} data language set
*/
}, {
key: 'setLanguage',
value: function setLanguage(codes, data) {
var _this = this;
codes = [].concat(codes);
codes.forEach(function (code) {
if (!_this._langs.has(code)) {
_this._langs.set(code, data);
} else {
var langData = _this._langs.get(code);
_this._langs.set(code, _tuiCodeSnippet2.default.extend(langData, data));
}
});
}
/**
* Get text of key
* @param {string} key key of text
* @param {string} code locale code
* @returns {string}
*/
}, {
key: 'get',
value: function get(key, code) {
if (!code) {
code = this._code;
}
var langSet = this._langs.get(code);
if (!langSet) {
langSet = this._langs.get(DEFAULT_CODE);
}
var text = langSet[key];
if (!text) {
throw new Error('There is no text key "' + key + '" in ' + code);
}
return text;
}
}], [{
key: 'getSharedInstance',
value: function getSharedInstance() {
if (!sharedInstance) {
sharedInstance = new I18n();
}
return sharedInstance;
}
}]);
return I18n;
}();
exports.I18n = I18n;
exports.default = new I18n();
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _jquery = __webpack_require__(0);
var _jquery2 = _interopRequireDefault(_jquery);
var _tuiCodeSnippet = __webpack_require__(1);
var _tuiCodeSnippet2 = _interopRequireDefault(_tuiCodeSnippet);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @fileoverview DOM Utils
* @author NHN FE Development Lab <dl_javascript@nhn.com>
*/
var FIND_ZWB = /\u200B/g;
/**
* isTextNode
* Check if node is text node
* @param {Node} node node to check
* @returns {boolean} result
* @ignore
*/
var isTextNode = function isTextNode(node) {
return node && node.nodeType === Node.TEXT_NODE;
};
/**
* isElemNode
* Check if node is element node
* @param {Node} node node to check
* @returns {boolean} result
* @ignore
*/
var isElemNode = function isElemNode(node) {
return node && node.nodeType === Node.ELEMENT_NODE;
};
/**
* Check that the node is block node
* @param {Node} node node
* @returns {boolean}
* @ignore
*/
var isBlockNode = function isBlockNode(node) {
return (/^(ADDRESS|ARTICLE|ASIDE|BLOCKQUOTE|DETAILS|DIALOG|DD|DIV|DL|DT|FIELDSET|FIGCAPTION|FIGURE|FOOTER|FORM|H[\d]|HEADER|HGROUP|HR|LI|MAIN|NAV|OL|P|PRE|SECTION|UL)$/ig.test(this.getNodeName(node))
);
};
/**
* getNodeName
* Get node name of node
* @param {Node} node node
* @returns {string} node name
* @ignore
*/
var getNodeName = function getNodeName(node) {
if (isElemNode(node)) {
return node.tagName;
}
return 'TEXT';
};
/**
* getTextLength
* Get node offset length of node(for Range API)
* @param {Node} node node
* @returns {number} length
* @ignore
*/
var getTextLength = function getTextLength(node) {
var len = void 0;
if (isElemNode(node)) {
len = node.textContent.replace(FIND_ZWB, '').length;
} else if (isTextNode(node)) {
len = node.nodeValue.replace(FIND_ZWB, '').length;
}
return len;
};
/**
* getOffsetLength
* Get node offset length of node(for Range API)
* @param {Node} node node
* @returns {number} length
* @ignore
*/
var getOffsetLength = function getOffsetLength(node) {
var len = void 0;
if (isElemNode(node)) {
len = node.childNodes.length;
} else if (isTextNode(node)) {
len = node.nodeValue.replace(FIND_ZWB, '').length;
}
return len;
};
/**
* getNodeOffsetOfParent
* get node offset between parent's childnodes
* @param {Node} node node
* @returns {number} offset(index)
* @ignore
*/
var getNodeOffsetOfParent = function getNodeOffsetOfParent(node) {
var childNodesOfParent = node.parentNode.childNodes;
var i = void 0,
t = void 0,
found = void 0;
for (i = 0, t = childNodesOfParent.length; i < t; i += 1) {
if (childNodesOfParent[i] === node) {
found = i;
break;
}
}
return found;
};
/**
* getChildNodeByOffset
* get child node by offset
* @param {Node} node node
* @param {number} index offset index
* @returns {Node} foudned node
* @ignore
*/
var getChildNodeByOffset = function getChildNodeByOffset(node, index) {
var currentNode = void 0;
if (isTextNode(node)) {
currentNode = node;
} else if (node.childNodes.length && index >= 0) {
currentNode = node.childNodes[index];
}
return currentNode;
};
/**
* getNodeWithDirectionUntil
* find next node from passed node
* @param {strong} direction previous or next
* @param {Node} node node
* @param {string} untilNodeName parent node name to limit
* @returns {Node} founded node
* @ignore
*/
var getNodeWithDirectionUntil = function getNodeWithDirectionUntil(direction, node, untilNodeName) {
var directionKey = direction + 'Sibling';
var nodeName = void 0,
foundedNode = void 0;
while (node && !node[directionKey]) {
nodeName = getNodeName(node.parentNode);
if (nodeName === untilNodeName || nodeName === 'BODY') {
break;
}
node = node.parentNode;
}
if (node[directionKey]) {
foundedNode = node[directionKey];
}
return foundedNode;
};
/**
* getPrevOffsetNodeUntil
* get prev node of childnode pointed with index
* @param {Node} node node
* @param {number} index offset index
* @param {string} untilNodeName parent node name to limit
* @returns {Node} founded node
* @ignore
*/
var getPrevOffsetNodeUntil = function getPrevOffsetNodeUntil(node, index, untilNodeName) {
var prevNode = void 0;
if (index > 0) {
prevNode = getChildNodeByOffset(node, index - 1);
} else {
prevNode = getNodeWithDirectionUntil('previous', node, untilNodeName);
}
return prevNode;
};
var getParentUntilBy = function getParentUntilBy(node, matchCondition, stopCondition) {
var foundedNode = void 0;
while (node.parentNode && !matchCondition(node.parentNode)) {
node = node.parentNode;
if (stopCondition && stopCondition(node.parentNode)) {
break;
}
}
if (matchCondition(node.parentNode)) {
foundedNode = node;
}
return foundedNode;
};
/**
* getParentUntil
* get parent node until paseed node name
* @param {Node} node node
* @param {string|HTMLNode} untilNode node name or node to limit
* @returns {Node} founded node
* @ignore
*/
var getParentUntil = function getParentUntil(node, untilNode) {
var foundedNode = void 0;
if (_tuiCodeSnippet2.default.isString(untilNode)) {
foundedNode = getParentUntilBy(node, function (targetNode) {
return untilNode === getNodeName(targetNode);
});
} else {
foundedNode = getParentUntilBy(node, function (targetNode) {
return untilNode === targetNode;
});
}
return foundedNode;
};
/**
* getNodeWithDirectionUnderParent
* get node on the given direction under given parent
* @param {strong} direction previous or next
* @param {Node} node node
* @param {string|Node} underNode parent node name to limit
* @returns {Node} founded node
* @ignore
*/
var getNodeWithDirectionUnderParent = function getNodeWithDirectionUnderParent(direction, node, underNode) {
var directionKey = direction + 'Sibling';
var foundedNode = void 0;
node = getParentUntil(node, underNode);
if (node && node[directionKey]) {
foundedNode = node[directionKey];
}
return foundedNode;
};
/**
* getTopPrevNodeUnder
* get top previous top level node under given node
* @param {Node} node node
* @param {Node} underNode underNode
* @returns {Node} founded node
* @ignore
*/
var getTopPrevNodeUnder = function getTopPrevNodeUnder(node, underNode) {
return getNodeWithDirectionUnderParent('previous', node, underNode);
};
/**
* getNextTopBlockNode
* get next top level block node
* @param {Node} node node
* @param {Node} underNode underNode
* @returns {Node} founded node
* @ignore
*/
var getTopNextNodeUnder = function getTopNextNodeUnder(node, underNode) {
return getNodeWithDirectionUnderParent('next', node, underNode);
};
/**
* Get parent element the body element
* @param {Node} node Node for start searching
* @returns {Node}
* @ignore
*/
var getTopBlockNode = function getTopBlockNode(node) {
return getParentUntil(node, 'BODY');
};
/**
* Get previous text node
* @param {Node} node Node for start searching
* @returns {Node}
* @ignore
*/
var getPrevTextNode = function getPrevTextNode(node) {
node = node.previousSibling || node.parentNode;
while (!isTextNode(node) && getNodeName(node) !== 'BODY') {
if (node.previousSibling) {
node = node.previousSibling;
while (node.lastChild) {
node = node.lastChild;
}
} else {
node = node.parentNode;
}
}
if (getNodeName(node) === 'BODY') {
node = null;
}
return node;
};
/**
* test whether root contains the given node
* @param {HTMLNode} root - root node
* @param {HTMLNode} node - node to test
* @returns {Boolean} true if root contains node
*/
var containsNode = function containsNode(root, node) {
var walker = document.createTreeWalker(root, 4, null, false);
var found = root === node;
while (!found && walker.nextNode()) {
found = walker.currentNode === node;
}
return found;
};
/**
* find node by offset
* @param {HTMLElement} root Root element
* @param {Array.<number>} offsetList offset list
* @param {function} textNodeFilter Text node filter
* @returns {Array}
* @ignore
*/
var findOffsetNode = function findOffsetNode(root, offsetList, textNodeFilter) {
var result = [];
var text = '';
var walkerOffset = 0;
var newWalkerOffset = void 0;
if (!offsetList.length) {
return result;
}
var offset = offsetList.shift();
var walker = document.createTreeWalker(root, 4, null, false);
while (walker.nextNode()) {
text = walker.currentNode.nodeValue || '';
if (textNodeFilter) {
text = textNodeFilter(text);
}
newWalkerOffset = walkerOffset + text.length;
while (newWalkerOffset >= offset) {
result.push({
container: walker.currentNode,
offsetInContainer: offset - walkerOffset,
offset: offset
});
if (!offsetList.length) {
return result;
}
offset = offsetList.shift();
}
walkerOffset = newWalkerOffset;
}
// there should be offset left
do {
result.push({
container: walker.currentNode,
offsetInContainer: text.length,
offset: offset
});
offset = offsetList.shift();
} while (!_tuiCodeSnippet2.default.isUndefined(offset));
return result;
};
var getNodeInfo = function getNodeInfo(node) {
var path = {};
path.tagName = node.nodeName;
if (node.id) {
path.id = node.id;
}
var className = node.className.trim();
if (className) {
path.className = className;
}
return path;
};
var getPath = function getPath(node, root) {
var paths = [];
while (node && node !== root) {
if (isElemNode(node)) {
paths.unshift(getNodeInfo(node));
}
node = node.parentNode;
}
return paths;
};
/**
* Find next, previous TD or TH element by given TE element
* @param {HTMLElement} node TD element
* @param {string} direction 'next' or 'previous'
* @returns {HTMLElement|null}
* @ignore
*/
var getTableCellByDirection = function getTableCellByDirection(node, direction) {
var targetElement = null;
if (!_tuiCodeSnippet2.default.isUndefined(direction) && (direction === 'next' || direction === 'previous')) {
if (direction === 'next') {
targetElement = node.nextElementSibling;
} else {
targetElement = node.previousElementSibling;
}
}
return targetElement;
};
/**
* Find sibling TR's TD element by given TD and direction
* @param {HTMLElement} node TD element
* @param {string} direction Boolean value for find first TD in next line
* @param {boolean} [needEdgeCell=false] Boolean value for find first TD in next line
* @returns {HTMLElement|null}
* @ignore
*/
var getSiblingRowCellByDirection = function getSiblingRowCellByDirection(node, direction, needEdgeCell) {
var tableCellElement = null;
var $node = void 0,
index = void 0,
$targetRowElement = void 0,
$currentContainer = void 0,
$siblingContainer = void 0,
isSiblingContainerExists = void 0;
if (!_tuiCodeSnippet2.default.isUndefined(direction) && (direction === 'next' || direction === 'previous')) {
if (node) {
$node = (0, _jquery2.default)(node);
if (direction === 'next') {
$targetRowElement = $node.parent().next();
$currentContainer = $node.parents('thead');
$siblingContainer = $currentContainer[0] && $currentContainer.next();
isSiblingContainerExists = $siblingContainer && getNodeName($siblingContainer[0]) === 'TBODY';
index = 0;
} else {
$targetRowElement = $node.parent().prev();
$currentContainer = $node.parents('tbody');
$siblingContainer = $currentContainer[0] && $currentContainer.prev();
isSiblingContainerExists = $siblingContainer && getNodeName($siblingContainer[0]) === 'THEAD';
index = node.parentNode.childNodes.length - 1;
}
if (_tuiCodeSnippet2.default.isUndefined(needEdgeCell) || !needEdgeCell) {
index = getNodeOffsetOfParent(node);
}
if ($targetRowElement[0]) {
tableCellElement = $targetRowElement.children('td,th')[index];
} else if ($currentContainer[0] && isSiblingContainerExists) {
tableCellElement = $siblingContainer.find('td,th')[index];
}
}
}
return tableCellElement;
};
/**
* Check that the inline node is supported by markdown
* @param {Node} node TD element
* @returns {boolean}
* @ignore
*/
var isMDSupportInlineNode = function isMDSupportInlineNode(node) {
return (/^(A|B|BR|CODE|DEL|EM|I|IMG|S|SPAN|STRONG)$/ig.test(node.nodeName)
);
};
/**
* Check that node is styled node.
* Styled node is a node that has text and decorates text.
* @param {Node} node TD element
* @returns {boolean}
* @ignore
*/
var isStyledNode = function isStyledNode(node) {
return (/^(A|ABBR|ACRONYM|B|BDI|BDO|BIG|CITE|CODE|DEL|DFN|EM|I|INS|KBD|MARK|Q|S|SAMP|SMALL|SPAN|STRONG|SUB|SUP|U|VAR)$/ig.test(node.nodeName)
);
};
/**
* remove node from 'start' node to 'end-1' node inside parent
* if 'end' node is null, remove all child nodes after 'start' node.
* @param {Node} parent - parent node
* @param {Node} start - start node to remove
* @param {Node} end - end node to remove
* @ignore
*/
var removeChildFromStartToEndNode = function removeChildFromStartToEndNode(parent, start, end) {
var child = start;
if (!child || parent !== child.parentNode) {
return;
}
while (child !== end) {
var next = child.nextSibling;
parent.removeChild(child);
child = next;
}
};
/**
* remove nodes along the direction from the node to reach targetParent node
* @param {Node} targetParent - stop removing when reach target parent node
* @param {Node} node - start node
* @param {boolean} isForward - direction
* @ignore
*/
var removeNodesByDirection = function removeNodesByDirection(targetParent, node, isForward) {
var parent = node;
while (parent !== targetParent) {
var nextParent = parent.parentNode;
var _parent = parent,
nextSibling = _parent.nextSibling,
previousSibling = _parent.previousSibling;
if (!isForward && nextSibling) {
removeChildFromStartToEndNode(nextParent, nextSibling, null);
} else if (isForward && previousSibling) {
removeChildFromStartToEndNode(nextParent, nextParent.childNodes[0], parent);
}
parent = nextParent;
}
};
var getLeafNode = function getLeafNode(node) {
var result = node;
while (result.childNodes && result.childNodes.length) {
var _result = result,
nextLeaf = _result.firstChild;
// When inline tag have empty text node with other childnodes, ignore empty text node.
if (isTextNode(nextLeaf) && !getTextLength(nextLeaf)) {
result = nextLeaf.nextSibling || nextLeaf;
} else {
result = nextLeaf;
}
}
return result;
};
/**
* check if a coordinates is inside a task box
* @param {object} style - computed style of task box
* @param {number} offsetX - event x offset
* @param {number} offsetY - event y offset
* @returns {boolean}
* @ignore
*/
var isInsideTaskBox = function isInsideTaskBox(style, offsetX, offsetY) {
var rect = {
left: parseInt(style.left, 10),
top: parseInt(style.top, 10),
width: parseInt(style.width, 10),
height: parseInt(style.height, 10)
};
return offsetX >= rect.left && offsetX <= rect.left + rect.width && offsetY >= rect.top && offsetY <= rect.top + rect.height;
};
/**
* Check whether node is OL or UL
* @param {node} node - node
* @returns {boolean} - whether node is OL or UL
* @ignore
*/
var isListNode = function isListNode(node) {
if (!node) {
return false;
}
return node.nodeName === 'UL' || node.nodeName === 'OL';
};
/**
* Check whether node is first list item
* @param {node} node - node
* @returns {boolean} whether node is first list item
* @ignore
*/
var isFirstListItem = function isFirstListItem(node) {
var nodeName = node.nodeName,
parentNode = node.parentNode;
return nodeName === 'LI' && node === parentNode.firstChild;
};
/**
* Check whether node is first level list item
* @param {node} node - node
* @returns {boolean} whether node is first level list item
* @ignore
*/
var isFirstLevelListItem = function isFirstLevelListItem(node) {
var nodeName = node.nodeName,
listNode = node.parentNode;
var listParentNode = listNode.parentNode;
return nodeName === 'LI' && !isListNode(listParentNode);
};
/**
* Merge node to target node and detach node
* @param {node} node - node
* @param {node} targetNode - target node
* @ignore
*/
var mergeNode = function mergeNode(node, targetNode) {
if (node.hasChildNodes()) {
_tuiCodeSnippet2.default.forEachArray(node.childNodes, function () {
targetNode.appendChild(node.firstChild);
});
targetNode.normalize();
}
if (node.parentNode) {
node.parentNode.removeChild(node);
}
};
/**
* Create hr that is not contenteditable
* @returns {node} hr is wraped div
* @ignore
*/
var createHorizontalRule = function createHorizontalRule() {
var div = document.createElement('div');
var hr = document.createElement('hr');
div.setAttribute('contenteditable', false);
hr.setAttribute('contenteditable', false);
div.appendChild(hr);
return div;
};
/**
* Create Empty Line
* @returns {node} <div><br></div>
* @private
*/
var createEmptyLine = function createEmptyLine() {
var div = document.createElement('div');
div.appendChild(document.createElement('br'));
return div;
};
/**
* Find same tagName child node and change wrapping order.
* For example, if below node need to optimize 'B' tag.
* <i><s><b>test</b></s></i>
* should be changed tag's order.
* <b><i><s>test</s></i></b>
* @param {node} node
* @param {string} tagName
* @returns {node}
* @private
*/
var changeTagOrder = function changeTagOrder(node, tagName) {
if (node.nodeName !== 'SPAN') {
var parentNode = node.parentNode;
var tempNode = node;
while (tempNode.childNodes && tempNode.childNodes.length === 1 && !isTextNode(tempNode.firstChild)) {
tempNode = tempNode.firstChild;
if (tempNode.nodeName === 'SPAN') {
break;
}
if (tempNode.nodeName === tagName) {
var wrapper = document.createElement(tagName);
mergeNode(tempNode, tempNode.parentNode);
parentNode.replaceChild(wrapper, node);
wrapper.appendChild(node);
return wrapper;
}
}
}
return node;
};
/**
* Find same tagName nodes and merge from startNode to endNode.
* @param {node} startNode
* @param {node} endNode
* @param {string} tagName
* @returns {node}
* @private
*/
var mergeSameNodes = function mergeSameNodes(startNode, endNode, tagName) {
var startBlockNode = changeTagOrder(startNode, tagName);
if (startBlockNode.nodeName === tagName) {
var endBlockNode = changeTagOrder(endNode, tagName);
var mergeTargetNode = startBlockNode;
var nextNode = startBlockNode.nextSibling;
while (nextNode) {
var tempNext = nextNode.nextSibling;
nextNode = changeTagOrder(nextNode, tagName);
if (nextNode.nodeName === tagName) {
// eslint-disable-next-line max-depth
if (mergeTargetNode) {
mergeNode(nextNode, mergeTargetNode);
} else {
mergeTargetNode = nextNode;
}
} else {
mergeTargetNode = null;
}
if (nextNode === endBlockNode) {
break;
}
nextNode = tempNext;
}
}
};
/**
* Find same tagName nodes in range and merge nodes.
* For example range is like this
* <s><b>AAA</b></s><b>BBB</b>
* nodes is changed below
* <b><s>AAA</s>BBB</b>
* @param {range} range
* @param {string} tagName
* @private
*/
var optimizeRange = function optimizeRange(range, tagName) {
var collapsed = range.collapsed,
commonAncestorContainer = range.commonAncestorContainer,
startContainer = range.startContainer,
endContainer = range.endContainer;
if (!collapsed) {
var optimizedNode = null;
if (startContainer !== endContainer) {
mergeSameNodes(getParentUntil(startContainer, commonAncestorContainer), getParentUntil(endContainer, commonAncestorContainer), tagName);
optimizedNode = commonAncestorContainer;
} else if (isTextNode(startContainer)) {
optimizedNode = startContainer.parentNode;
}
if (optimizedNode && optimizedNode.nodeName === tagName) {
var _optimizedNode = optimizedNode,
previousSibling = _optimizedNode.previousSibling;
var tempNode = void 0;
if (previousSibling) {
tempNode = changeTagOrder(previousSibling);
if (tempNode.nodeName === tagName) {
mergeNode(optimizedNode, tempNode);
}
}
var _optimizedNode2 = optimizedNode,
nextSibling = _optimizedNode2.nextSibling;
if (nextSibling) {
tempNode = changeTagOrder(nextSibling);
if (tempNode.nodeName === tagName) {
mergeNode(tempNode, optimizedNode);
}
}
}
}
};
/**
* Gets all text node from root element.
* @param {HTMLElement} root Root element
* @returns {Array} list of text nodes
*/
var getAllTextNode = function getAllTextNode(root) {
var walker = document.createTreeWalker(root, 4, null, false);
var result = [];
while (walker.nextNode()) {
var node = walker.currentNode;
if (isTextNode(node)) {
result.push(node);
}
}
return result;
};
exports.default = {
getNodeName: getNodeName,
isTextNode: isTextNode,
isElemNode: isElemNode,
isBlockNode: isBlockNode,
getTextLength: getTextLength,
getOffsetLength: getOffsetLength,
getPrevOffsetNodeUntil: getPrevOffsetNodeUntil,
getNodeOffsetOfParent: getNodeOffsetOfParent,
getChildNodeByOffset: getChildNodeByOffset,
getNodeWithDirectionUntil: getNodeWithDirectionUntil,
containsNode: containsNode,
getTopPrevNodeUnder: getTopPrevNodeUnder,
getTopNextNodeUnder: getTopNextNodeUnder,
getParentUntilBy: getParentUntilBy,
getParentUntil: getParentUntil,
getTopBlockNode: getTopBlockNode,
getPrevTextNode: getPrevTextNode,
findOffsetNode: findOffsetNode,
getPath: getPath,
getNodeInfo: getNodeInfo,
getTableCellByDirection: getTableCellByDirection,
getSiblingRowCellByDirection: getSiblingRowCellByDirection,
isMDSupportInlineNode: isMDSupportInlineNode,
isStyledNode: isStyledNode,
removeChildFromStartToEndNode: removeChildFromStartToEndNode,
removeNodesByDirection: removeNodesByDirection,
getLeafNode: getLeafNode,
isInsideTaskBox: isInsideTaskBox,
isListNode: isListNode,
isFirstListItem: isFirstListItem,
isFirstLevelListItem: isFirstLevelListItem,
mergeNode: mergeNode,
createHorizontalRule: createHorizontalRule,
createEmptyLine: createEmptyLine,
changeTagOrder: changeTagOrder,
mergeSameNodes: mergeSameNodes,
optimizeRange: optimizeRange,
getAllTextNode: getAllTextNode
};
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _jquery = __webpack_require__(0);
var _jquery2 = _interopRequireDefault(_jquery);
var _tuiCodeSnippet = __webpack_require__(1);
var _tuiCodeSnippet2 = _interopRequireDefault(_tuiCodeSnippet);
var _uicontroller = __webpack_require__(8);
var _uicontroller2 = _interopRequireDefault(_uicontroller);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
* @fileoverview Implements LayerPopup
* @author NHN FE Development Lab <dl_javascript@nhn.com>
*/
var CLASS_PREFIX = 'tui-popup-';
var CLASS_FIT_WINDOW = 'fit-window';
var LAYOUT_TEMPLATE_MODELESS = '<div class="' + CLASS_PREFIX + 'header">\n <span class="' + CLASS_PREFIX + 'title"></span>\n <div class="' + CLASS_PREFIX + 'header-buttons">\n <button type="button" class="' + CLASS_PREFIX + 'close-button"></button>\n </div>\n </div>\n <div class="' + CLASS_PREFIX + 'body"></div>';
var LAYOUT_TEMPLATE_MODAL = '<div class="' + CLASS_PREFIX + 'wrapper">\n <div class="' + CLASS_PREFIX + 'header">\n <span class="' + CLASS_PREFIX + 'title"></span>\n <div class="' + CLASS_PREFIX + 'header-buttons">\n <button type="button" class="' + CLASS_PREFIX + 'close-button"></button>\n </div>\n </div>\n <div class="' + CLASS_PREFIX + 'body"></div>\n </div>';
/**
* A number, or a string containing a number.
* @typedef {Object} LayerPopupOption
* @property {string[]} [openerCssQuery] - Css Query list to bind clickevent that open popup
* @property {string[]} [closerCssQuery] - Css Query list to bind clickevent that close popup
* @property {jQuery} $el - popup root element
* @property {jQuery|string} [content] - popup content that html string or jQuery element
* @property {string} [textContent] - popup text content
* @property {string} title - popup title
* @property {boolean} [header] - whether to draw header
* @property {jQuery} [$target] - element to append popup
* @property {boolean} modal - true: modal, false: modeless
* @property {string} [headerButtons] - replace header(close) button
*/
/**
* Class LayerPopup
* @extends {UIController}
*/
var LayerPopup = function (_UIController) {
_inherits(LayerPopup, _UIController);
/**
* Creates an instance of LayerPopup.
* @param {LayerPopupOption} options - popup option
* @memberof LayerPopup
*/
function LayerPopup(options) {
_classCallCheck(this, LayerPopup);
options = _tuiCodeSnippet2.default.extend({
header: true,
$target: (0, _jquery2.default)('body'),
textContent: ''
}, options);
var _this = _possibleConstructorReturn(this, (LayerPopup.__proto__ || Object.getPrototypeOf(LayerPopup)).call(this, {
tagName: 'div',
className: options.modal ? CLASS_PREFIX + 'modal-background' : CLASS_PREFIX + 'wrapper',
rootElement: options.$el
}));
_this._initInstance(options);
_this._initDOM(options);
_this._initDOMEvent(options);
_this._initEditorEvent(options);
return _this;
}
/**
* init instance.
* store properties & prepare before initialize DOM
* @param {LayerPopupOption} options - layer popup options
* @memberof LayerPopup
* @protected
*/
_createClass(LayerPopup, [{
key: '_initInstance',
value: function _initInstance(options) {
this._$target = options.$target;
if (options.$el) {
this.$el = options.$el;
this._isExternalHtmlUse = true;
}
if (options.content) {
this.$content = (0, _jquery2.default)(options.content);
} else {
this.$content = options.textContent;
}
this.options = options;
}
/**
* initialize DOM, render popup
* @memberof LayerPopup
* @protected
*/
}, {
key: '_initDOM',
value: function _initDOM() {
this._initLayout();
if (!this._isExternalHtmlUse) {
if (_tuiCodeSnippet2.default.isExisty(this.options.title)) {
this.setTitle(this.options.title);
}
this.setContent(this.$content);
}
var buttons = this.options.headerButtons;
if (buttons) {
this.$el.find('.' + CLASS_PREFIX + 'close-button').remove();
var $buttonWrapper = this.$el.find('.' + CLASS_PREFIX + 'header-buttons');
$buttonWrapper.empty();
$buttonWrapper.append((0, _jquery2.default)(buttons));
}
if (this.options.css) {
this.$el.css(this.options.css);
}
}
/**
* bind DOM events
* @memberof LayerPopup
* @protected
*/
}, {
key: '_initDOMEvent',
value: function _initDOMEvent() {
var _this2 = this;
var _options = this.options,
openerCssQuery = _options.openerCssQuery,
closerCssQuery = _options.closerCssQuery;
if (openerCssQuery) {
(0, _jquery2.default)(openerCssQuery).on('click.' + this._id, function () {
return _this2.show();
});
}
if (closerCssQuery) {
(0, _jquery2.default)(closerCssQuery).on('click.' + this._id, function () {
return _this2.hide();
});
}
this.on('click .' + CLASS_PREFIX + 'close-button', function () {
return _this2.hide();
});
}
/**
* bind editor events
* @memberof LayerPopup
* @protected
* @abstract
*/
}, {
key: '_initEditorEvent',
value: function _initEditorEvent() {}
}, {
key: '_initLayout',
value: function _initLayout() {
var options = this.options;
if (!this._isExternalHtmlUse) {
var layout = options.modal ? LAYOUT_TEMPLATE_MODAL : LAYOUT_TEMPLATE_MODELESS;
this.$el.html(layout);
this.$el.addClass(options.className);
this.hide();
this._$target.append(this.$el);
this.$body = this.$el.find('.' + CLASS_PREFIX + 'body');
if (!options.header) {
this.$el.find('.' + CLASS_PREFIX + 'header').remove();
}
} else {
this.hide();
this._$target.append(this.$el);
}
}
/**
* set popup content
* @param {jQuery|HTMLElement|string} $content - content
* @memberof LayerPopup
*/
}, {
key: 'setContent',
value: function setContent($content) {
this.$body.empty();
this.$body.append($content);
}
/**
* set title
* @param {string} title - title text
* @memberof LayerPopup
*/
}, {
key: 'setTitle',
value: function setTitle(title) {
var $title = this.$el.find('.' + CLASS_PREFIX + 'title');
$title.empty();
$title.append(title);
}
/**
* get title element
* @memberof LayerPopup
* @returns {HTMLElement} - title html element
*/
}, {
key: 'getTitleElement',
value: function getTitleElement() {
return this.$el.find('.' + CLASS_PREFIX + 'title').get(0);
}
/**
* hide popup
* @memberof LayerPopup
*/
}, {
key: 'hide',
value: function hide() {
this.$el.css('display', 'none');
this._isShow = false;
this.trigger('hidden', this);
}
/**
* show popup
* @memberof LayerPopup
*/
}, {
key: 'show',
value: function show() {
this.$el.css('display', 'block');
this._isShow = true;
this.trigger('shown', t