UNPKG

roosterjs

Version:

A simple facade for all roosterjs code

1,135 lines (1,037 loc) 687 kB
var roosterjs = /******/ (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, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // 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 = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "./packages/roosterjs/lib/index.ts"); /******/ }) /************************************************************************/ /******/ ({ /***/ "./packages/roosterjs-editor-api/lib/experiment/experimentSetIndentation.ts": /*!**********************************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/experiment/experimentSetIndentation.ts ***! \**********************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var blockFormat_1 = __webpack_require__(/*! ../utils/blockFormat */ "./packages/roosterjs-editor-api/lib/utils/blockFormat.ts"); var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); var roosterjs_editor_dom_2 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); var BlockWrapper = '<blockquote style="margin-top:0;margin-bottom:0"></blockquote>'; /** * @internal */ function experimentSetIndentation(editor, indentation) { var handler = indentation == 0 /* Increase */ ? indent : outdent; blockFormat_1.default(editor, function (region, start, end) { var blocks = roosterjs_editor_dom_1.getSelectedBlockElementsInRegion(region); var blockGroups = [[]]; for (var i = 0; i < blocks.length; i++) { var startNode = blocks[i].getStartNode(); var vList = roosterjs_editor_dom_2.createVListFromRegion(region, true /*includeSiblingLists*/, startNode); if (vList) { blockGroups.push([]); while (blocks[i + 1] && vList.contains(blocks[i + 1].getStartNode())) { i++; } vList.setIndentation(start, end, indentation); vList.writeBack(); } else { blockGroups[blockGroups.length - 1].push(blocks[i]); } } blockGroups.forEach(function (group) { return handler(region, group); }); }); } exports.default = experimentSetIndentation; function indent(region, blocks) { if (blocks.length > 0) { var startNode = blocks[0].getStartNode(); var endNode = blocks[blocks.length - 1].getEndNode(); var nodes = roosterjs_editor_dom_2.collapseNodesInRegion(region, [startNode, endNode]); roosterjs_editor_dom_2.wrap(nodes, BlockWrapper); } } function outdent(region, blocks) { blocks.forEach(function (blockElement) { var node = blockElement.collapseToSingleElement(); var quote = roosterjs_editor_dom_2.findClosestElementAncestor(node, region.rootNode, 'blockquote'); if (quote) { if (node == quote) { node = roosterjs_editor_dom_2.wrap(roosterjs_editor_dom_2.toArray(node.childNodes)); } while (roosterjs_editor_dom_2.isNodeInRegion(region, node) && roosterjs_editor_dom_2.getTagOfNode(node) != 'BLOCKQUOTE') { node = roosterjs_editor_dom_2.splitBalancedNodeRange(node); } if (roosterjs_editor_dom_2.isNodeInRegion(region, node)) { roosterjs_editor_dom_2.unwrap(node); } } }); } /***/ }), /***/ "./packages/roosterjs-editor-api/lib/experiment/experimentToggleListType.ts": /*!**********************************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/experiment/experimentToggleListType.ts ***! \**********************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var blockFormat_1 = __webpack_require__(/*! ../utils/blockFormat */ "./packages/roosterjs-editor-api/lib/utils/blockFormat.ts"); var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); /** * @internal */ function experimentToggleListType(editor, listType) { blockFormat_1.default(editor, function (region, start, end) { var vList = roosterjs_editor_dom_1.createVListFromRegion(region, true /*includeSiblingLists*/); if (vList) { vList.changeListType(start, end, listType); vList.writeBack(); } }); } exports.default = experimentToggleListType; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/changeFontSize.ts": /*!********************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/changeFontSize.ts ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ "./packages/roosterjs-editor-api/lib/utils/applyInlineStyle.ts"); var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); /** * Default font size sequence, in pt. Suggest editor UI use this sequence as your font size list, * So that when increase/decrease font size, the font size can match the sequence of your font size picker */ exports.FONT_SIZES = [8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]; var MIN_FONT_SIZE = 1; var MAX_FONT_SIZE = 1000; /** * Increase or decrease font size in selection * @param editor The editor instance * @param change Whether increase or decrease font size * @param fontSizes A sorted font size array, in pt. Default value is FONT_SIZES */ function changeFontSize(editor, change, fontSizes) { if (fontSizes === void 0) { fontSizes = exports.FONT_SIZES; } var changeBase = change == 0 /* Increase */ ? 1 : -1; applyInlineStyle_1.default(editor, function (element) { var pt = parseFloat(roosterjs_editor_dom_1.getComputedStyle(element, 'font-size')); element.style.fontSize = getNewFontSize(pt, changeBase, fontSizes) + 'pt'; var lineHeight = roosterjs_editor_dom_1.getComputedStyle(element, 'line-height'); if (lineHeight != 'normal') { element.style.lineHeight = 'normal'; } }); } exports.default = changeFontSize; function getNewFontSize(pt, changeBase, fontSizes) { pt = changeBase == 1 ? Math.floor(pt) : Math.ceil(pt); var last = fontSizes[fontSizes.length - 1]; if (pt <= fontSizes[0]) { pt = Math.max(pt + changeBase, MIN_FONT_SIZE); } else if (pt > last || (pt == last && changeBase == 1)) { pt = pt / 10; pt = changeBase == 1 ? Math.floor(pt) : Math.ceil(pt); pt = Math.min(Math.max((pt + changeBase) * 10, last), MAX_FONT_SIZE); } else if (changeBase == 1) { for (var i = 0; i < fontSizes.length; i++) { if (pt < fontSizes[i]) { pt = fontSizes[i]; break; } } } else { for (var i = fontSizes.length - 1; i >= 0; i--) { if (pt > fontSizes[i]) { pt = fontSizes[i]; break; } } } return pt; } exports.getNewFontSize = getNewFontSize; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/clearBlockFormat.ts": /*!**********************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/clearBlockFormat.ts ***! \**********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var collapseSelectedBlocks_1 = __webpack_require__(/*! ../utils/collapseSelectedBlocks */ "./packages/roosterjs-editor-api/lib/utils/collapseSelectedBlocks.ts"); var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); exports.TAGS_TO_UNWRAP = 'B,I,U,STRONG,EM,SUB,SUP,STRIKE,FONT,CENTER,H1,H2,H3,H4,H5,H6,UL,OL,LI,SPAN,P,BLOCKQUOTE,CODE,S,PRE'.split(','); exports.TAGS_TO_STOP_UNWRAP = ['TD', 'TH', 'TR', 'TABLE', 'TBODY', 'THEAD']; exports.ATTRIBUTES_TO_PRESERVE = ['href']; /** * Clear all formats of selected blocks. * When selection is collapsed, only clear format of current block. * @param editor The editor instance * @param tagsToUnwrap Optional. A string array contains HTML tags in upper case which we will unwrap when clear format * @param tagsToStopUnwrap Optional. A string array contains HTML tags in upper case which we will stop unwrap if these tags are hit */ function clearBlockFormat(editor, tagsToUnwrap, tagsToStopUnwrap, attributesToPreserve) { if (tagsToUnwrap === void 0) { tagsToUnwrap = exports.TAGS_TO_UNWRAP; } if (tagsToStopUnwrap === void 0) { tagsToStopUnwrap = exports.TAGS_TO_STOP_UNWRAP; } if (attributesToPreserve === void 0) { attributesToPreserve = exports.ATTRIBUTES_TO_PRESERVE; } editor.focus(); editor.addUndoSnapshot(function (start, end) { var groups = [{}]; var stopUnwrapSelector = tagsToStopUnwrap.join(','); // 1. Collapse the selected blocks and get first and last element collapseSelectedBlocks_1.default(editor, function (element) { var group = groups[groups.length - 1]; var td = editor.getElementAtCursor(stopUnwrapSelector, element); if (td != group.td && group.first) { groups.push((group = {})); } group.td = td; group.first = group.first || element; group.last = element; }); groups .filter(function (group) { return group.first; }) .forEach(function (group) { // 2. Collapse with first and last element to make them under same parent var nodes = editor.collapseNodes(group.first, group.last, true /*canSplitParent*/); // 3. Continue collapse until we can't collapse any more (hit root node, or a table) if (canCollapse(tagsToStopUnwrap, nodes[0])) { while (editor.contains(nodes[0].parentNode) && canCollapse(tagsToStopUnwrap, nodes[0].parentNode)) { nodes = [roosterjs_editor_dom_1.splitBalancedNodeRange(nodes)]; } } // 4. Clear formats of the nodes nodes.forEach(function (node) { return clearNodeFormat(node, tagsToUnwrap, tagsToStopUnwrap, attributesToPreserve); }); // 5. Clear CSS of container TD if exist if (group.td) { var styles = group.td.getAttribute('style') || ''; var styleArray = styles.split(';'); styleArray = styleArray.filter(function (style) { return style.trim().toLowerCase().indexOf('border') == 0; }); styles = styleArray.join(';'); if (styles) { group.td.setAttribute('style', styles); } else { group.td.removeAttribute('style'); } } }); editor.select(start, end); }, "Format" /* Format */); } exports.default = clearBlockFormat; function clearNodeFormat(node, tagsToUnwrap, tagsToStopUnwrap, attributesToPreserve) { if (node.nodeType != 1 /* Element */ || roosterjs_editor_dom_1.getTagOfNode(node) == 'BR') { return false; } // 1. Recursively clear format of all its child nodes var allChildrenAreBlock = roosterjs_editor_dom_1.toArray(node.childNodes) .map(function (n) { return clearNodeFormat(n, tagsToUnwrap, tagsToStopUnwrap, attributesToPreserve); }) .reduce(function (previousValue, value) { return previousValue && value; }, true); if (!canCollapse(tagsToStopUnwrap, node)) { return false; } var returnBlockElement = roosterjs_editor_dom_1.isBlockElement(node); // 2. If we should unwrap this tag, put it into an array and unwrap it later if (tagsToUnwrap.indexOf(roosterjs_editor_dom_1.getTagOfNode(node)) >= 0 || allChildrenAreBlock) { if (returnBlockElement && !allChildrenAreBlock) { roosterjs_editor_dom_1.wrap(node); } roosterjs_editor_dom_1.unwrap(node); } else { // 3. Otherwise, remove all attributes clearAttribute(node, attributesToPreserve); } return returnBlockElement; } function clearAttribute(element, attributesToPreserve) { for (var _i = 0, _a = roosterjs_editor_dom_1.toArray(element.attributes); _i < _a.length; _i++) { var attr = _a[_i]; if (attributesToPreserve.indexOf(attr.name.toLowerCase()) < 0 && attr.name.indexOf('data-') != 0) { element.removeAttribute(attr.name); } } } function canCollapse(tagsToStopUnwrap, node) { return tagsToStopUnwrap.indexOf(roosterjs_editor_dom_1.getTagOfNode(node)) < 0; } /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/clearFormat.ts": /*!*****************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/clearFormat.ts ***! \*****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var execCommand_1 = __webpack_require__(/*! ../utils/execCommand */ "./packages/roosterjs-editor-api/lib/utils/execCommand.ts"); var setBackgroundColor_1 = __webpack_require__(/*! ./setBackgroundColor */ "./packages/roosterjs-editor-api/lib/format/setBackgroundColor.ts"); var setFontName_1 = __webpack_require__(/*! ./setFontName */ "./packages/roosterjs-editor-api/lib/format/setFontName.ts"); var setFontSize_1 = __webpack_require__(/*! ./setFontSize */ "./packages/roosterjs-editor-api/lib/format/setFontSize.ts"); var setTextColor_1 = __webpack_require__(/*! ./setTextColor */ "./packages/roosterjs-editor-api/lib/format/setTextColor.ts"); var toggleBold_1 = __webpack_require__(/*! ./toggleBold */ "./packages/roosterjs-editor-api/lib/format/toggleBold.ts"); var toggleItalic_1 = __webpack_require__(/*! ./toggleItalic */ "./packages/roosterjs-editor-api/lib/format/toggleItalic.ts"); var toggleUnderline_1 = __webpack_require__(/*! ./toggleUnderline */ "./packages/roosterjs-editor-api/lib/format/toggleUnderline.ts"); var STYLES_TO_REMOVE = ['font', 'text-decoration', 'color', 'background']; /** * Clear the format in current selection, after cleaning, the format will be * changed to default format. The format that get cleaned include B/I/U/font name/ * font size/text color/background color/align left/align right/align center/superscript/subscript * @param editor The editor instance */ function clearFormat(editor) { editor.focus(); editor.addUndoSnapshot(function () { execCommand_1.default(editor, "removeFormat" /* RemoveFormat */); editor.queryElements('[class]', 1 /* OnSelection */, function (node) { return node.removeAttribute('class'); }); var defaultFormat = editor.getDefaultFormat(); var isDefaultFormatEmpty = Object.keys(defaultFormat).length === 0; editor.queryElements('[style]', 2 /* InSelection */, function (node) { STYLES_TO_REMOVE.forEach(function (style) { return node.style.removeProperty(style); }); // when default format is empty, keep the HTML minimum by removing style attribute if there's no style // (note: because default format is empty, we're not adding style back in) if (isDefaultFormatEmpty && node.getAttribute('style') === '') { node.removeAttribute('style'); } }); if (!isDefaultFormatEmpty) { if (defaultFormat.fontFamily) { setFontName_1.default(editor, defaultFormat.fontFamily); } if (defaultFormat.fontSize) { setFontSize_1.default(editor, defaultFormat.fontSize); } if (defaultFormat.textColor) { if (defaultFormat.textColors) { setTextColor_1.default(editor, defaultFormat.textColors); } else { setTextColor_1.default(editor, defaultFormat.textColor); } } if (defaultFormat.backgroundColor) { if (defaultFormat.backgroundColors) { setBackgroundColor_1.default(editor, defaultFormat.backgroundColors); } else { setBackgroundColor_1.default(editor, defaultFormat.backgroundColor); } } if (defaultFormat.bold) { toggleBold_1.default(editor); } if (defaultFormat.italic) { toggleItalic_1.default(editor); } if (defaultFormat.underline) { toggleUnderline_1.default(editor); } } }, "Format" /* Format */); } exports.default = clearFormat; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/createLink.ts": /*!****************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/createLink.ts ***! \****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); // Regex matching Uri scheme var URI_REGEX = /^[a-zA-Z]+:/i; // Regex matching begin of email address var MAILTO_REGEX = /^[\w.%+-]+@/i; // Regex matching begin of ftp, i.e. ftp.microsoft.com var FTP_REGEX = /^ftp\./i; var TEMP_TITLE = 'istemptitle'; function applyLinkPrefix(url) { if (!url) { return url; } // Add link prefix per rule: // (a) if the url always starts with a URI scheme, leave it as it is // (b) if the url is an email address, xxx@... add mailto: prefix // (c) if the url starts with ftp., add ftp:// prefix // (d) rest, add http:// prefix var prefix = ''; if (url.search(URI_REGEX) < 0) { if (url.search(MAILTO_REGEX) == 0) { prefix = 'mailto:'; } else if (url.search(FTP_REGEX) == 0) { prefix = 'ftp://'; } else { // fallback to http:// prefix = 'http://'; } } return prefix + url; } /** * Insert a hyperlink at cursor. * When there is a selection, hyperlink will be applied to the selection, * otherwise a hyperlink will be inserted to the cursor position. * @param editor Editor object * @param link Link address, can be http(s), mailto, notes, file, unc, ftp, news, telnet, gopher, wais. * When protocol is not specified, a best matched protocol will be predicted. * @param altText Optional alt text of the link, will be shown when hover on the link * @param displayText Optional display text for the link. * If specified, the display text of link will be replaced with this text. * If not specified and there wasn't a link, the link url will be used as display text. */ function createLink(editor, link, altText, displayText) { editor.focus(); var url = (checkXss(link) || '').trim(); if (url) { var linkData = roosterjs_editor_dom_1.matchLink(url); // matchLink can match most links, but not all, i.e. if you pass link a link as "abc", it won't match // we know in that case, users will want to insert a link like http://abc // so we have separate logic in applyLinkPrefix to add link prefix depending on the format of the link // i.e. if the link starts with something like abc@xxx, we will add mailto: prefix // if the link starts with ftp.xxx, we will add ftp:// link. For more, see applyLinkPrefix var normalizedUrl_1 = linkData ? linkData.normalizedUrl : applyLinkPrefix(url); var originalUrl_1 = linkData ? linkData.originalUrl : url; editor.addUndoSnapshot(function () { var range = editor.getSelectionRange(); var anchor = null; if (range && range.collapsed) { anchor = getAnchorNodeAtCursor(editor); // If there is already a link, just change its href if (anchor) { anchor.href = normalizedUrl_1; // Change text content if it is specified updateAnchorDisplayText(anchor, displayText); } else { anchor = editor.getDocument().createElement('A'); anchor.textContent = displayText || originalUrl_1; anchor.href = normalizedUrl_1; editor.insertNode(anchor); } } else { // the selection is not collapsed, use browser execCommand editor.getDocument().execCommand("createLink" /* CreateLink */, false, normalizedUrl_1); anchor = getAnchorNodeAtCursor(editor); updateAnchorDisplayText(anchor, displayText); } if (altText && anchor) { // Hack: Ideally this should be done by HyperLink plugin. // We make a hack here since we don't have an event to notify HyperLink plugin // before we apply the link. anchor.removeAttribute(TEMP_TITLE); anchor.title = altText; } return anchor; }, "CreateLink" /* CreateLink */); } } exports.default = createLink; function getAnchorNodeAtCursor(editor) { return editor.queryElements('a[href]', 1 /* OnSelection */)[0]; } function updateAnchorDisplayText(anchor, displayText) { if (displayText && anchor.textContent != displayText) { anchor.textContent = displayText; } } function checkXss(link) { var santizer = new roosterjs_editor_dom_1.HtmlSanitizer(); var doc = new DOMParser().parseFromString('<a></a>', 'text/html'); var a = doc.body.firstChild; a.href = link || ''; santizer.sanitize(doc.body); // We use getAttribute because some browsers will try to make the href property a valid link. // This has unintended side effects when the link lacks a protocol. return a.getAttribute('href'); } /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/getFormatState.ts": /*!********************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/getFormatState.ts ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(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.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var roosterjs_editor_core_1 = __webpack_require__(/*! roosterjs-editor-core */ "./packages/roosterjs-editor-core/lib/index.ts"); var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); var roosterjs_editor_dom_2 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); /** * Get element based Format State at cursor * @param editor The editor instance * @param event (Optional) The plugin event, it stores the event cached data for looking up. * In this function the event cache is used to get list state and header level. If not passed, * it will query the node within selection to get the info * @returns An ElementBasedFormatState object */ function getElementBasedFormatState(editor, event) { var listTag = roosterjs_editor_dom_1.getTagOfNode(roosterjs_editor_core_1.cacheGetElementAtCursor(editor, event, 'OL,UL')); var headerTag = roosterjs_editor_dom_1.getTagOfNode(roosterjs_editor_core_1.cacheGetElementAtCursor(editor, event, 'H1,H2,H3,H4,H5,H6')); return { isBullet: listTag == 'UL', isNumbering: listTag == 'OL', headerLevel: (headerTag && parseInt(headerTag[1])) || 0, canUnlink: !!editor.queryElements('a[href]', 1 /* OnSelection */)[0], canAddImageAltText: !!editor.queryElements('img', 1 /* OnSelection */)[0], isBlockQuote: !!editor.queryElements('blockquote', 1 /* OnSelection */)[0], }; } exports.getElementBasedFormatState = getElementBasedFormatState; /** * Get style based Format State at cursor * @param editor The editor instance * @returns A StyleBasedFormatState object */ function getStyleBasedFormatState(editor) { var range = editor.getSelectionRange(); var node = range && roosterjs_editor_dom_1.Position.getStart(range).normalize().node; var styles = node ? roosterjs_editor_dom_1.getComputedStyles(node) : []; return { fontName: styles[0], fontSize: styles[1], textColor: styles[2], backgroundColor: styles[3], }; } exports.getStyleBasedFormatState = getStyleBasedFormatState; /** * Get format state at cursor * A format state is a collection of all format related states, e.g., * bold, italic, underline, font name, font size, etc. * @param editor The editor instance * @param event (Optional) The plugin event, it stores the event cached data for looking up. * In this function the event cache is used to get list state and header level. If not passed, * it will query the node within selection to get the info * @returns The format state at cursor */ function getFormatState(editor, event) { return __assign(__assign(__assign(__assign({}, roosterjs_editor_dom_2.getPendableFormatState(editor.getDocument())), getElementBasedFormatState(editor, event)), getStyleBasedFormatState(editor)), { canUndo: editor.canUndo(), canRedo: editor.canRedo() }); } exports.default = getFormatState; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/insertImage.ts": /*!*****************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/insertImage.ts ***! \*****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function insertImage(editor, imageFile) { if (typeof imageFile == 'string') { insertImageWithSrc(editor, imageFile); } else { var reader = new FileReader(); reader.onload = function (event) { if (!editor.isDisposed()) { insertImageWithSrc(editor, event.target.result); } }; reader.readAsDataURL(imageFile); } } exports.default = insertImage; function insertImageWithSrc(editor, src) { editor.addUndoSnapshot(function () { var image = editor.getDocument().createElement('img'); image.src = src; image.style.maxWidth = '100%'; editor.insertNode(image); }, "Format" /* Format */); } /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/removeLink.ts": /*!****************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/removeLink.ts ***! \****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); /** * Remove link at selection. If no links at selection, do nothing. * If selection contains multiple links, all of the link styles will be removed. * If only part of a link is selected, the whole link style will be removed. * @param editor The editor instance */ function removeLink(editor) { editor.focus(); editor.addUndoSnapshot(function (start, end) { editor.queryElements('a[href]', 1 /* OnSelection */, roosterjs_editor_dom_1.unwrap); editor.select(start, end); }, "Format" /* Format */); } exports.default = removeLink; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/replaceWithNode.ts": /*!*********************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/replaceWithNode.ts ***! \*********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function replaceWithNode(editor, textOrRange, node, exactMatch, searcher) { // Make sure the text and node is valid if (!textOrRange || !node) { return false; } var range; if (typeof textOrRange == 'string') { searcher = searcher || editor.getContentSearcherOfCursor(); range = searcher && searcher.getRangeFromText(textOrRange, exactMatch); } else { range = textOrRange; } if (range) { var backupRange = editor.getSelectionRange(); // If the range to replace is right before current cursor, it is actually an exact match if (backupRange.collapsed && range.endContainer == backupRange.startContainer && range.endOffset == backupRange.startOffset) { exactMatch = true; } editor.insertNode(node, { position: 5 /* Range */, updateCursor: exactMatch, replaceSelection: true, insertOnNewLine: false, range: range, }); return true; } return false; } exports.default = replaceWithNode; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/setAlignment.ts": /*!******************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/setAlignment.ts ***! \******************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var execCommand_1 = __webpack_require__(/*! ../utils/execCommand */ "./packages/roosterjs-editor-api/lib/utils/execCommand.ts"); /** * Set content alignment * @param editor The editor instance * @param alignment The alignment option: * Alignment.Center, Alignment.Left, Alignment.Right */ function setAlignment(editor, alignment) { var command = "justifyLeft" /* JustifyLeft */; var align = 'left'; if (alignment == 1 /* Center */) { command = "justifyCenter" /* JustifyCenter */; align = 'center'; } else if (alignment == 2 /* Right */) { command = "justifyRight" /* JustifyRight */; align = 'right'; } editor.addUndoSnapshot(function () { execCommand_1.default(editor, command); editor.queryElements('[align]', 1 /* OnSelection */, function (node) { return (node.style.textAlign = align); }); }, "Format" /* Format */); } exports.default = setAlignment; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/setBackgroundColor.ts": /*!************************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/setBackgroundColor.ts ***! \************************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ "./packages/roosterjs-editor-api/lib/utils/applyInlineStyle.ts"); /** * Set background color at current selection * @param editor The editor instance * @param color One of two options: * The color string, can be any of the predefined color names (e.g, 'red') * or hexadecimal color string (e.g, '#FF0000') or rgb value (e.g, 'rgb(255, 0, 0)') supported by browser. * Currently there's no validation to the string, if the passed string is invalid, it won't take affect * Alternatively, you can pass a @typedef ModeIndepenentColor. If in light mode, the lightModeColor property will be used. * If in dark mode, the darkModeColor will be used and the lightModeColor will be used when converting back to light mode. **/ function setBackgroundColor(editor, color) { if (typeof color === 'string') { var trimmedColor_1 = color.trim(); applyInlineStyle_1.default(editor, function (element, isInnerNode) { element.style.backgroundColor = isInnerNode ? '' : trimmedColor_1; }); } else { var darkMode_1 = editor.isDarkMode(); var appliedColor_1 = darkMode_1 ? color.darkModeColor : color.lightModeColor; applyInlineStyle_1.default(editor, function (element, isInnerNode) { element.style.backgroundColor = isInnerNode ? '' : appliedColor_1; if (darkMode_1) { element.dataset.ogsb = color.lightModeColor; } }); } } exports.default = setBackgroundColor; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/setDirection.ts": /*!******************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/setDirection.ts ***! \******************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var collapseSelectedBlocks_1 = __webpack_require__(/*! ../utils/collapseSelectedBlocks */ "./packages/roosterjs-editor-api/lib/utils/collapseSelectedBlocks.ts"); /** * Change direction for the blocks/paragraph at selection * @param editor The editor instance * @param direction The direction option: * Direction.LeftToRight refers to 'ltr', Direction.RightToLeft refers to 'rtl' */ function setDirection(editor, direction) { editor.focus(); editor.addUndoSnapshot(function (start, end) { collapseSelectedBlocks_1.default(editor, function (element) { element.setAttribute('dir', direction == 0 /* LeftToRight */ ? 'ltr' : 'rtl'); element.style.textAlign = direction == 0 /* LeftToRight */ ? 'left' : 'right'; }); editor.select(start, end); }, "Format" /* Format */); } exports.default = setDirection; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/setFontName.ts": /*!*****************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/setFontName.ts ***! \*****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ "./packages/roosterjs-editor-api/lib/utils/applyInlineStyle.ts"); /** * Set font name at selection * @param editor The editor instance * @param fontName The fontName string, should be a valid CSS font-family style. * Currently there's no validation to the string, if the passed string is invalid, it won't take affect */ function setFontName(editor, fontName) { fontName = fontName.trim(); // The browser provided execCommand creates a HTML <font> tag with face attribute. <font> is not HTML5 standard // (http://www.w3schools.com/tags/tag_font.asp). Use applyInlineStyle which gives flexibility on applying inline style // for here, we use CSS font-family style applyInlineStyle_1.default(editor, function (element, isInnerNode) { element.style.fontFamily = isInnerNode ? '' : fontName; }); } exports.default = setFontName; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/setFontSize.ts": /*!*****************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/setFontSize.ts ***! \*****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ "./packages/roosterjs-editor-api/lib/utils/applyInlineStyle.ts"); var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts"); /** * Set font size at selection * @param editor The editor instance * @param fontSize The fontSize string, should be a valid CSS font-size style. * Currently there's no validation to the string, if the passed string is invalid, it won't take affect */ function setFontSize(editor, fontSize) { fontSize = fontSize.trim(); // The browser provided execCommand only accepts 1-7 point value. In addition, it uses HTML <font> tag with size attribute. // <font> is not HTML5 standard (http://www.w3schools.com/tags/tag_font.asp). Use applyInlineStyle which gives flexibility on applying inline style // for here, we use CSS font-size style applyInlineStyle_1.default(editor, function (element, isInnerNode) { element.style.fontSize = isInnerNode ? '' : fontSize; var lineHeight = roosterjs_editor_dom_1.getComputedStyle(element, 'line-height'); if (lineHeight != 'normal') { element.style.lineHeight = 'normal'; } }); } exports.default = setFontSize; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/setImageAltText.ts": /*!*********************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/setImageAltText.ts ***! \*********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** * Set image alt text for all selected images at selection. If no images is contained * in selection, do nothing. * The alt attribute provides alternative information for an image if a user for some reason * cannot view it (because of slow connection, an error in the src attribute, or if the user * uses a screen reader). See https://www.w3schools.com/tags/att_img_alt.asp * @param editor The editor instance * @param altText The image alt text */ function setImageAltText(editor, altText) { editor.focus(); editor.addUndoSnapshot(function () { editor.queryElements('img', 1 /* OnSelection */, function (node) { return node.setAttribute('alt', altText); }); }, "Format" /* Format */); } exports.default = setImageAltText; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/setIndentation.ts": /*!********************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/setIndentation.ts ***! \********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var experimentSetIndentation_1 = __webpack_require__(/*! ../experiment/experimentSetIndentation */ "./packages/roosterjs-editor-api/lib/experiment/experimentSetIndentation.ts"); var processList_1 = __webpack_require__(/*! ../utils/processList */ "./packages/roosterjs-editor-api/lib/utils/processList.ts"); /** * Set indentation at selection * If selection contains bullet/numbering list, increase/decrease indentation will * increase/decrease the list level by one. * @param editor The editor instance * @param indentation The indentation option: * Indentation.Increase to increase indentation or Indentation.Decrease to decrease indentation */ function setIndentation(editor, indentation) { if (editor.useExperimentFeatures()) { experimentSetIndentation_1.default(editor, indentation); } else { var command_1 = indentation == 0 /* Increase */ ? "indent" /* Indent */ : "outdent" /* Outdent */; editor.addUndoSnapshot(function () { editor.focus(); var listNode = editor.getElementAtCursor('OL,UL'); var newNode; if (listNode) { // There is already list node, setIndentation() will increase/decrease the list level, // so we need to process the list when change indentation newNode = processList_1.default(editor, command_1); } else { // No existing list node, browser will create <Blockquote> node for indentation. // We need to set top and bottom margin to 0 to avoid unnecessary spaces editor.getDocument().execCommand(command_1, false, null); editor.queryElements('BLOCKQUOTE', 1 /* OnSelection */, function (node) { newNode = newNode || node; node.style.marginTop = '0px'; node.style.marginBottom = '0px'; }); } return newNode; }, "Format" /* Format */); } } exports.default = setIndentation; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/setTextColor.ts": /*!******************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/setTextColor.ts ***! \******************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ "./packages/roosterjs-editor-api/lib/utils/applyInlineStyle.ts"); /** * Set text color at selection * @param editor The editor instance * @param color One of two options: * The color string, can be any of the predefined color names (e.g, 'red') * or hexadecimal color string (e.g, '#FF0000') or rgb value (e.g, 'rgb(255, 0, 0)') supported by browser. * Currently there's no validation to the string, if the passed string is invalid, it won't take affect * Alternatively, you can pass a @typedef ModeIndepenentColor. If in light mode, the lightModeColor property will be used. * If in dark mode, the darkModeColor will be used and the lightModeColor will be used when converting back to light mode. */ function setTextColor(editor, color) { if (typeof color === 'string') { var trimmedColor_1 = color.trim(); applyInlineStyle_1.default(editor, function (element, isInnerNode) { element.style.color = isInnerNode ? '' : trimmedColor_1; }); } else { var darkMode_1 = editor.isDarkMode(); var appliedColor_1 = darkMode_1 ? color.darkModeColor : color.lightModeColor; applyInlineStyle_1.default(editor, function (element, isInnerNode) { element.style.color = isInnerNode ? '' : appliedColor_1; if (darkMode_1) { element.dataset.ogsc = color.lightModeColor; } }); } } exports.default = setTextColor; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/toggleBlockQuote.ts": /*!**********************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/toggleBlockQuote.ts ***! \**********************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var toggleTagCore_1 = __webpack_require__(/*! ../utils/toggleTagCore */ "./packages/roosterjs-editor-api/lib/utils/toggleTagCore.ts"); var BLOCKQUOTE_TAG = 'blockquote'; var DEFAULT_STYLER = function (element) { element.style.borderLeft = '3px solid'; element.style.borderColor = '#C8C8C8'; element.style.paddingLeft = '10px'; element.style.color = '#666666'; }; /** * Toggle blockquote at selection, if selection already contains any blockquoted elements, * the blockquoted elements will be unblockquoted and other elements will take no affect * @param editor The editor instance * @param styler (Optional) The custom styler for setting the style for the blockquote element */ function toggleBlockQuote(editor, styler) { toggleTagCore_1.default(editor, BLOCKQUOTE_TAG, styler || DEFAULT_STYLER); } exports.default = toggleBlockQuote; /***/ }), /***/ "./packages/roosterjs-editor-api/lib/format/toggleBold.ts": /*!****************************************************************!*\ !*** ./packages/roosterjs-editor-api/lib/format/toggleBold.ts ***! \****************************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var execCommand_1 = __webpack_require__(/*! ../utils/execCommand */ "./packages/roosterjs-editor-api/lib/utils/execCommand.ts"); /** * Toggle bold at selection * If selection is collapsed, it will only affect the following input after caret * If selection contains only bold text, the bold style will be removed * If selection contains only normal text, bold style will be added to the whole selected text * If selection contains both bold and normal text, bold stle wil