Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

10235 wiersze
317KB

  1. /*!
  2. *
  3. * Super simple WYSIWYG editor v0.8.20
  4. * https://summernote.org
  5. *
  6. *
  7. * Copyright 2013- Alan Hong and contributors
  8. * Summernote may be freely distributed under the MIT license.
  9. *
  10. * Date: 2021-10-14T21:15Z
  11. *
  12. */
  13. (function webpackUniversalModuleDefinition(root, factory) {
  14. if(typeof exports === 'object' && typeof module === 'object')
  15. module.exports = factory(require("jQuery"));
  16. else if(typeof define === 'function' && define.amd)
  17. define(["jQuery"], factory);
  18. else {
  19. var a = typeof exports === 'object' ? factory(require("jQuery")) : factory(root["jQuery"]);
  20. for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
  21. }
  22. })(self, function(__WEBPACK_EXTERNAL_MODULE__1145__) {
  23. return /******/ (() => { // webpackBootstrap
  24. /******/ "use strict";
  25. /******/ var __webpack_modules__ = ({
  26. /***/ 9770:
  27. /***/ ((__unused_webpack_module, __unused_webpack___webpack_exports__, __webpack_require__) => {
  28. /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1145);
  29. /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__);
  30. (jquery__WEBPACK_IMPORTED_MODULE_0___default().summernote) = (jquery__WEBPACK_IMPORTED_MODULE_0___default().summernote) || {
  31. lang: {}
  32. };
  33. jquery__WEBPACK_IMPORTED_MODULE_0___default().extend((jquery__WEBPACK_IMPORTED_MODULE_0___default().summernote.lang), {
  34. 'en-US': {
  35. font: {
  36. bold: 'Bold',
  37. italic: 'Italic',
  38. underline: 'Underline',
  39. clear: 'Remove Font Style',
  40. height: 'Line Height',
  41. name: 'Font Family',
  42. strikethrough: 'Strikethrough',
  43. subscript: 'Subscript',
  44. superscript: 'Superscript',
  45. size: 'Font Size',
  46. sizeunit: 'Font Size Unit'
  47. },
  48. image: {
  49. image: 'Picture',
  50. insert: 'Insert Image',
  51. resizeFull: 'Resize full',
  52. resizeHalf: 'Resize half',
  53. resizeQuarter: 'Resize quarter',
  54. resizeNone: 'Original size',
  55. floatLeft: 'Float Left',
  56. floatRight: 'Float Right',
  57. floatNone: 'Remove float',
  58. shapeRounded: 'Shape: Rounded',
  59. shapeCircle: 'Shape: Circle',
  60. shapeThumbnail: 'Shape: Thumbnail',
  61. shapeNone: 'Shape: None',
  62. dragImageHere: 'Drag image or text here',
  63. dropImage: 'Drop image or Text',
  64. selectFromFiles: 'Select from files',
  65. maximumFileSize: 'Maximum file size',
  66. maximumFileSizeError: 'Maximum file size exceeded.',
  67. url: 'Image URL',
  68. remove: 'Remove Image',
  69. original: 'Original'
  70. },
  71. video: {
  72. video: 'Video',
  73. videoLink: 'Video Link',
  74. insert: 'Insert Video',
  75. url: 'Video URL',
  76. providers: '(YouTube, Google Drive, Vimeo, Vine, Instagram, DailyMotion, Youku, Peertube)'
  77. },
  78. link: {
  79. link: 'Link',
  80. insert: 'Insert Link',
  81. unlink: 'Unlink',
  82. edit: 'Edit',
  83. textToDisplay: 'Text to display',
  84. url: 'To what URL should this link go?',
  85. openInNewWindow: 'Open in new window',
  86. useProtocol: 'Use default protocol'
  87. },
  88. table: {
  89. table: 'Table',
  90. addRowAbove: 'Add row above',
  91. addRowBelow: 'Add row below',
  92. addColLeft: 'Add column left',
  93. addColRight: 'Add column right',
  94. delRow: 'Delete row',
  95. delCol: 'Delete column',
  96. delTable: 'Delete table'
  97. },
  98. hr: {
  99. insert: 'Insert Horizontal Rule'
  100. },
  101. style: {
  102. style: 'Style',
  103. p: 'Normal',
  104. blockquote: 'Quote',
  105. pre: 'Code',
  106. h1: 'Header 1',
  107. h2: 'Header 2',
  108. h3: 'Header 3',
  109. h4: 'Header 4',
  110. h5: 'Header 5',
  111. h6: 'Header 6'
  112. },
  113. lists: {
  114. unordered: 'Unordered list',
  115. ordered: 'Ordered list'
  116. },
  117. options: {
  118. help: 'Help',
  119. fullscreen: 'Full Screen',
  120. codeview: 'Code View'
  121. },
  122. paragraph: {
  123. paragraph: 'Paragraph',
  124. outdent: 'Outdent',
  125. indent: 'Indent',
  126. left: 'Align left',
  127. center: 'Align center',
  128. right: 'Align right',
  129. justify: 'Justify full'
  130. },
  131. color: {
  132. recent: 'Recent Color',
  133. more: 'More Color',
  134. background: 'Background Color',
  135. foreground: 'Text Color',
  136. transparent: 'Transparent',
  137. setTransparent: 'Set transparent',
  138. reset: 'Reset',
  139. resetToDefault: 'Reset to default',
  140. cpSelect: 'Select'
  141. },
  142. shortcut: {
  143. shortcuts: 'Keyboard shortcuts',
  144. close: 'Close',
  145. textFormatting: 'Text formatting',
  146. action: 'Action',
  147. paragraphFormatting: 'Paragraph formatting',
  148. documentStyle: 'Document Style',
  149. extraKeys: 'Extra keys'
  150. },
  151. help: {
  152. 'escape': 'Escape',
  153. 'insertParagraph': 'Insert Paragraph',
  154. 'undo': 'Undo the last command',
  155. 'redo': 'Redo the last command',
  156. 'tab': 'Tab',
  157. 'untab': 'Untab',
  158. 'bold': 'Set a bold style',
  159. 'italic': 'Set a italic style',
  160. 'underline': 'Set a underline style',
  161. 'strikethrough': 'Set a strikethrough style',
  162. 'removeFormat': 'Clean a style',
  163. 'justifyLeft': 'Set left align',
  164. 'justifyCenter': 'Set center align',
  165. 'justifyRight': 'Set right align',
  166. 'justifyFull': 'Set full align',
  167. 'insertUnorderedList': 'Toggle unordered list',
  168. 'insertOrderedList': 'Toggle ordered list',
  169. 'outdent': 'Outdent on current paragraph',
  170. 'indent': 'Indent on current paragraph',
  171. 'formatPara': 'Change current block\'s format as a paragraph(P tag)',
  172. 'formatH1': 'Change current block\'s format as H1',
  173. 'formatH2': 'Change current block\'s format as H2',
  174. 'formatH3': 'Change current block\'s format as H3',
  175. 'formatH4': 'Change current block\'s format as H4',
  176. 'formatH5': 'Change current block\'s format as H5',
  177. 'formatH6': 'Change current block\'s format as H6',
  178. 'insertHorizontalRule': 'Insert horizontal rule',
  179. 'linkDialog.show': 'Show Link Dialog'
  180. },
  181. history: {
  182. undo: 'Undo',
  183. redo: 'Redo'
  184. },
  185. specialChar: {
  186. specialChar: 'SPECIAL CHARACTERS',
  187. select: 'Select Special characters'
  188. },
  189. output: {
  190. noSelection: 'No Selection Made!'
  191. }
  192. }
  193. });
  194. /***/ }),
  195. /***/ 1145:
  196. /***/ ((module) => {
  197. module.exports = __WEBPACK_EXTERNAL_MODULE__1145__;
  198. /***/ })
  199. /******/ });
  200. /************************************************************************/
  201. /******/ // The module cache
  202. /******/ var __webpack_module_cache__ = {};
  203. /******/
  204. /******/ // The require function
  205. /******/ function __webpack_require__(moduleId) {
  206. /******/ // Check if module is in cache
  207. /******/ var cachedModule = __webpack_module_cache__[moduleId];
  208. /******/ if (cachedModule !== undefined) {
  209. /******/ return cachedModule.exports;
  210. /******/ }
  211. /******/ // Create a new module (and put it into the cache)
  212. /******/ var module = __webpack_module_cache__[moduleId] = {
  213. /******/ // no module.id needed
  214. /******/ // no module.loaded needed
  215. /******/ exports: {}
  216. /******/ };
  217. /******/
  218. /******/ // Execute the module function
  219. /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  220. /******/
  221. /******/ // Return the exports of the module
  222. /******/ return module.exports;
  223. /******/ }
  224. /******/
  225. /************************************************************************/
  226. /******/ /* webpack/runtime/compat get default export */
  227. /******/ (() => {
  228. /******/ // getDefaultExport function for compatibility with non-harmony modules
  229. /******/ __webpack_require__.n = (module) => {
  230. /******/ var getter = module && module.__esModule ?
  231. /******/ () => (module['default']) :
  232. /******/ () => (module);
  233. /******/ __webpack_require__.d(getter, { a: getter });
  234. /******/ return getter;
  235. /******/ };
  236. /******/ })();
  237. /******/
  238. /******/ /* webpack/runtime/define property getters */
  239. /******/ (() => {
  240. /******/ // define getter functions for harmony exports
  241. /******/ __webpack_require__.d = (exports, definition) => {
  242. /******/ for(var key in definition) {
  243. /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  244. /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  245. /******/ }
  246. /******/ }
  247. /******/ };
  248. /******/ })();
  249. /******/
  250. /******/ /* webpack/runtime/hasOwnProperty shorthand */
  251. /******/ (() => {
  252. /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  253. /******/ })();
  254. /******/
  255. /******/ /* webpack/runtime/make namespace object */
  256. /******/ (() => {
  257. /******/ // define __esModule on exports
  258. /******/ __webpack_require__.r = (exports) => {
  259. /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  260. /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  261. /******/ }
  262. /******/ Object.defineProperty(exports, '__esModule', { value: true });
  263. /******/ };
  264. /******/ })();
  265. /******/
  266. /************************************************************************/
  267. var __webpack_exports__ = {};
  268. // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
  269. (() => {
  270. // ESM COMPAT FLAG
  271. __webpack_require__.r(__webpack_exports__);
  272. // EXTERNAL MODULE: external "jQuery"
  273. var external_jQuery_ = __webpack_require__(1145);
  274. var external_jQuery_default = /*#__PURE__*/__webpack_require__.n(external_jQuery_);
  275. // EXTERNAL MODULE: ./src/lang/summernote-en-US.js
  276. var summernote_en_US = __webpack_require__(9770);
  277. ;// CONCATENATED MODULE: ./src/js/core/env.js
  278. /**
  279. * returns whether font is installed or not.
  280. *
  281. * @param {String} fontName
  282. * @return {Boolean}
  283. */
  284. var genericFontFamilies = ['sans-serif', 'serif', 'monospace', 'cursive', 'fantasy'];
  285. function validFontName(fontName) {
  286. return external_jQuery_default().inArray(fontName.toLowerCase(), genericFontFamilies) === -1 ? "'".concat(fontName, "'") : fontName;
  287. }
  288. function isFontInstalled(fontName) {
  289. var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';
  290. var testText = 'mmmmmmmmmmwwwww';
  291. var testSize = '200px';
  292. var canvas = document.createElement('canvas');
  293. var context = canvas.getContext('2d');
  294. context.font = testSize + " '" + testFontName + "'";
  295. var originalWidth = context.measureText(testText).width;
  296. context.font = testSize + ' ' + validFontName(fontName) + ', "' + testFontName + '"';
  297. var width = context.measureText(testText).width;
  298. return originalWidth !== width;
  299. }
  300. var userAgent = navigator.userAgent;
  301. var isMSIE = /MSIE|Trident/i.test(userAgent);
  302. var browserVersion;
  303. if (isMSIE) {
  304. var matches = /MSIE (\d+[.]\d+)/.exec(userAgent);
  305. if (matches) {
  306. browserVersion = parseFloat(matches[1]);
  307. }
  308. matches = /Trident\/.*rv:([0-9]{1,}[.0-9]{0,})/.exec(userAgent);
  309. if (matches) {
  310. browserVersion = parseFloat(matches[1]);
  311. }
  312. }
  313. var isEdge = /Edge\/\d+/.test(userAgent);
  314. var isSupportTouch = 'ontouchstart' in window || navigator.MaxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; // [workaround] IE doesn't have input events for contentEditable
  315. // - see: https://goo.gl/4bfIvA
  316. var inputEventName = isMSIE ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input';
  317. /**
  318. * @class core.env
  319. *
  320. * Object which check platform and agent
  321. *
  322. * @singleton
  323. * @alternateClassName env
  324. */
  325. /* harmony default export */ const env = ({
  326. isMac: navigator.appVersion.indexOf('Mac') > -1,
  327. isMSIE: isMSIE,
  328. isEdge: isEdge,
  329. isFF: !isEdge && /firefox/i.test(userAgent),
  330. isPhantom: /PhantomJS/i.test(userAgent),
  331. isWebkit: !isEdge && /webkit/i.test(userAgent),
  332. isChrome: !isEdge && /chrome/i.test(userAgent),
  333. isSafari: !isEdge && /safari/i.test(userAgent) && !/chrome/i.test(userAgent),
  334. browserVersion: browserVersion,
  335. isSupportTouch: isSupportTouch,
  336. isFontInstalled: isFontInstalled,
  337. isW3CRangeSupport: !!document.createRange,
  338. inputEventName: inputEventName,
  339. genericFontFamilies: genericFontFamilies,
  340. validFontName: validFontName
  341. });
  342. ;// CONCATENATED MODULE: ./src/js/core/func.js
  343. /**
  344. * @class core.func
  345. *
  346. * func utils (for high-order func's arg)
  347. *
  348. * @singleton
  349. * @alternateClassName func
  350. */
  351. function eq(itemA) {
  352. return function (itemB) {
  353. return itemA === itemB;
  354. };
  355. }
  356. function eq2(itemA, itemB) {
  357. return itemA === itemB;
  358. }
  359. function peq2(propName) {
  360. return function (itemA, itemB) {
  361. return itemA[propName] === itemB[propName];
  362. };
  363. }
  364. function ok() {
  365. return true;
  366. }
  367. function fail() {
  368. return false;
  369. }
  370. function not(f) {
  371. return function () {
  372. return !f.apply(f, arguments);
  373. };
  374. }
  375. function and(fA, fB) {
  376. return function (item) {
  377. return fA(item) && fB(item);
  378. };
  379. }
  380. function func_self(a) {
  381. return a;
  382. }
  383. function invoke(obj, method) {
  384. return function () {
  385. return obj[method].apply(obj, arguments);
  386. };
  387. }
  388. var idCounter = 0;
  389. /**
  390. * reset globally-unique id
  391. *
  392. */
  393. function resetUniqueId() {
  394. idCounter = 0;
  395. }
  396. /**
  397. * generate a globally-unique id
  398. *
  399. * @param {String} [prefix]
  400. */
  401. function uniqueId(prefix) {
  402. var id = ++idCounter + '';
  403. return prefix ? prefix + id : id;
  404. }
  405. /**
  406. * returns bnd (bounds) from rect
  407. *
  408. * - IE Compatibility Issue: http://goo.gl/sRLOAo
  409. * - Scroll Issue: http://goo.gl/sNjUc
  410. *
  411. * @param {Rect} rect
  412. * @return {Object} bounds
  413. * @return {Number} bounds.top
  414. * @return {Number} bounds.left
  415. * @return {Number} bounds.width
  416. * @return {Number} bounds.height
  417. */
  418. function rect2bnd(rect) {
  419. var $document = external_jQuery_default()(document);
  420. return {
  421. top: rect.top + $document.scrollTop(),
  422. left: rect.left + $document.scrollLeft(),
  423. width: rect.right - rect.left,
  424. height: rect.bottom - rect.top
  425. };
  426. }
  427. /**
  428. * returns a copy of the object where the keys have become the values and the values the keys.
  429. * @param {Object} obj
  430. * @return {Object}
  431. */
  432. function invertObject(obj) {
  433. var inverted = {};
  434. for (var key in obj) {
  435. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  436. inverted[obj[key]] = key;
  437. }
  438. }
  439. return inverted;
  440. }
  441. /**
  442. * @param {String} namespace
  443. * @param {String} [prefix]
  444. * @return {String}
  445. */
  446. function namespaceToCamel(namespace, prefix) {
  447. prefix = prefix || '';
  448. return prefix + namespace.split('.').map(function (name) {
  449. return name.substring(0, 1).toUpperCase() + name.substring(1);
  450. }).join('');
  451. }
  452. /**
  453. * Returns a function, that, as long as it continues to be invoked, will not
  454. * be triggered. The function will be called after it stops being called for
  455. * N milliseconds. If `immediate` is passed, trigger the function on the
  456. * leading edge, instead of the trailing.
  457. * @param {Function} func
  458. * @param {Number} wait
  459. * @param {Boolean} immediate
  460. * @return {Function}
  461. */
  462. function debounce(func, wait, immediate) {
  463. var timeout;
  464. return function () {
  465. var context = this;
  466. var args = arguments;
  467. var later = function later() {
  468. timeout = null;
  469. if (!immediate) {
  470. func.apply(context, args);
  471. }
  472. };
  473. var callNow = immediate && !timeout;
  474. clearTimeout(timeout);
  475. timeout = setTimeout(later, wait);
  476. if (callNow) {
  477. func.apply(context, args);
  478. }
  479. };
  480. }
  481. /**
  482. *
  483. * @param {String} url
  484. * @return {Boolean}
  485. */
  486. function isValidUrl(url) {
  487. var expression = /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/gi;
  488. return expression.test(url);
  489. }
  490. /* harmony default export */ const func = ({
  491. eq: eq,
  492. eq2: eq2,
  493. peq2: peq2,
  494. ok: ok,
  495. fail: fail,
  496. self: func_self,
  497. not: not,
  498. and: and,
  499. invoke: invoke,
  500. resetUniqueId: resetUniqueId,
  501. uniqueId: uniqueId,
  502. rect2bnd: rect2bnd,
  503. invertObject: invertObject,
  504. namespaceToCamel: namespaceToCamel,
  505. debounce: debounce,
  506. isValidUrl: isValidUrl
  507. });
  508. ;// CONCATENATED MODULE: ./src/js/core/lists.js
  509. /**
  510. * returns the first item of an array.
  511. *
  512. * @param {Array} array
  513. */
  514. function head(array) {
  515. return array[0];
  516. }
  517. /**
  518. * returns the last item of an array.
  519. *
  520. * @param {Array} array
  521. */
  522. function last(array) {
  523. return array[array.length - 1];
  524. }
  525. /**
  526. * returns everything but the last entry of the array.
  527. *
  528. * @param {Array} array
  529. */
  530. function initial(array) {
  531. return array.slice(0, array.length - 1);
  532. }
  533. /**
  534. * returns the rest of the items in an array.
  535. *
  536. * @param {Array} array
  537. */
  538. function tail(array) {
  539. return array.slice(1);
  540. }
  541. /**
  542. * returns item of array
  543. */
  544. function find(array, pred) {
  545. for (var idx = 0, len = array.length; idx < len; idx++) {
  546. var item = array[idx];
  547. if (pred(item)) {
  548. return item;
  549. }
  550. }
  551. }
  552. /**
  553. * returns true if all of the values in the array pass the predicate truth test.
  554. */
  555. function lists_all(array, pred) {
  556. for (var idx = 0, len = array.length; idx < len; idx++) {
  557. if (!pred(array[idx])) {
  558. return false;
  559. }
  560. }
  561. return true;
  562. }
  563. /**
  564. * returns true if the value is present in the list.
  565. */
  566. function contains(array, item) {
  567. if (array && array.length && item) {
  568. if (array.indexOf) {
  569. return array.indexOf(item) !== -1;
  570. } else if (array.contains) {
  571. // `DOMTokenList` doesn't implement `.indexOf`, but it implements `.contains`
  572. return array.contains(item);
  573. }
  574. }
  575. return false;
  576. }
  577. /**
  578. * get sum from a list
  579. *
  580. * @param {Array} array - array
  581. * @param {Function} fn - iterator
  582. */
  583. function sum(array, fn) {
  584. fn = fn || func.self;
  585. return array.reduce(function (memo, v) {
  586. return memo + fn(v);
  587. }, 0);
  588. }
  589. /**
  590. * returns a copy of the collection with array type.
  591. * @param {Collection} collection - collection eg) node.childNodes, ...
  592. */
  593. function from(collection) {
  594. var result = [];
  595. var length = collection.length;
  596. var idx = -1;
  597. while (++idx < length) {
  598. result[idx] = collection[idx];
  599. }
  600. return result;
  601. }
  602. /**
  603. * returns whether list is empty or not
  604. */
  605. function isEmpty(array) {
  606. return !array || !array.length;
  607. }
  608. /**
  609. * cluster elements by predicate function.
  610. *
  611. * @param {Array} array - array
  612. * @param {Function} fn - predicate function for cluster rule
  613. * @param {Array[]}
  614. */
  615. function clusterBy(array, fn) {
  616. if (!array.length) {
  617. return [];
  618. }
  619. var aTail = tail(array);
  620. return aTail.reduce(function (memo, v) {
  621. var aLast = last(memo);
  622. if (fn(last(aLast), v)) {
  623. aLast[aLast.length] = v;
  624. } else {
  625. memo[memo.length] = [v];
  626. }
  627. return memo;
  628. }, [[head(array)]]);
  629. }
  630. /**
  631. * returns a copy of the array with all false values removed
  632. *
  633. * @param {Array} array - array
  634. * @param {Function} fn - predicate function for cluster rule
  635. */
  636. function compact(array) {
  637. var aResult = [];
  638. for (var idx = 0, len = array.length; idx < len; idx++) {
  639. if (array[idx]) {
  640. aResult.push(array[idx]);
  641. }
  642. }
  643. return aResult;
  644. }
  645. /**
  646. * produces a duplicate-free version of the array
  647. *
  648. * @param {Array} array
  649. */
  650. function unique(array) {
  651. var results = [];
  652. for (var idx = 0, len = array.length; idx < len; idx++) {
  653. if (!contains(results, array[idx])) {
  654. results.push(array[idx]);
  655. }
  656. }
  657. return results;
  658. }
  659. /**
  660. * returns next item.
  661. * @param {Array} array
  662. */
  663. function next(array, item) {
  664. if (array && array.length && item) {
  665. var idx = array.indexOf(item);
  666. return idx === -1 ? null : array[idx + 1];
  667. }
  668. return null;
  669. }
  670. /**
  671. * returns prev item.
  672. * @param {Array} array
  673. */
  674. function prev(array, item) {
  675. if (array && array.length && item) {
  676. var idx = array.indexOf(item);
  677. return idx === -1 ? null : array[idx - 1];
  678. }
  679. return null;
  680. }
  681. /**
  682. * @class core.list
  683. *
  684. * list utils
  685. *
  686. * @singleton
  687. * @alternateClassName list
  688. */
  689. /* harmony default export */ const lists = ({
  690. head: head,
  691. last: last,
  692. initial: initial,
  693. tail: tail,
  694. prev: prev,
  695. next: next,
  696. find: find,
  697. contains: contains,
  698. all: lists_all,
  699. sum: sum,
  700. from: from,
  701. isEmpty: isEmpty,
  702. clusterBy: clusterBy,
  703. compact: compact,
  704. unique: unique
  705. });
  706. ;// CONCATENATED MODULE: ./src/js/core/dom.js
  707. var NBSP_CHAR = String.fromCharCode(160);
  708. var ZERO_WIDTH_NBSP_CHAR = "\uFEFF";
  709. /**
  710. * @method isEditable
  711. *
  712. * returns whether node is `note-editable` or not.
  713. *
  714. * @param {Node} node
  715. * @return {Boolean}
  716. */
  717. function isEditable(node) {
  718. return node && external_jQuery_default()(node).hasClass('note-editable');
  719. }
  720. /**
  721. * @method isControlSizing
  722. *
  723. * returns whether node is `note-control-sizing` or not.
  724. *
  725. * @param {Node} node
  726. * @return {Boolean}
  727. */
  728. function isControlSizing(node) {
  729. return node && external_jQuery_default()(node).hasClass('note-control-sizing');
  730. }
  731. /**
  732. * @method makePredByNodeName
  733. *
  734. * returns predicate which judge whether nodeName is same
  735. *
  736. * @param {String} nodeName
  737. * @return {Function}
  738. */
  739. function makePredByNodeName(nodeName) {
  740. nodeName = nodeName.toUpperCase();
  741. return function (node) {
  742. return node && node.nodeName.toUpperCase() === nodeName;
  743. };
  744. }
  745. /**
  746. * @method isText
  747. *
  748. *
  749. *
  750. * @param {Node} node
  751. * @return {Boolean} true if node's type is text(3)
  752. */
  753. function isText(node) {
  754. return node && node.nodeType === 3;
  755. }
  756. /**
  757. * @method isElement
  758. *
  759. *
  760. *
  761. * @param {Node} node
  762. * @return {Boolean} true if node's type is element(1)
  763. */
  764. function isElement(node) {
  765. return node && node.nodeType === 1;
  766. }
  767. /**
  768. * ex) br, col, embed, hr, img, input, ...
  769. * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
  770. */
  771. function isVoid(node) {
  772. return node && /^BR|^IMG|^HR|^IFRAME|^BUTTON|^INPUT|^AUDIO|^VIDEO|^EMBED/.test(node.nodeName.toUpperCase());
  773. }
  774. function isPara(node) {
  775. if (isEditable(node)) {
  776. return false;
  777. } // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph
  778. return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase());
  779. }
  780. function isHeading(node) {
  781. return node && /^H[1-7]/.test(node.nodeName.toUpperCase());
  782. }
  783. var isPre = makePredByNodeName('PRE');
  784. var isLi = makePredByNodeName('LI');
  785. function isPurePara(node) {
  786. return isPara(node) && !isLi(node);
  787. }
  788. var isTable = makePredByNodeName('TABLE');
  789. var isData = makePredByNodeName('DATA');
  790. function isInline(node) {
  791. return !isBodyContainer(node) && !isList(node) && !isHr(node) && !isPara(node) && !isTable(node) && !isBlockquote(node) && !isData(node);
  792. }
  793. function isList(node) {
  794. return node && /^UL|^OL/.test(node.nodeName.toUpperCase());
  795. }
  796. var isHr = makePredByNodeName('HR');
  797. function isCell(node) {
  798. return node && /^TD|^TH/.test(node.nodeName.toUpperCase());
  799. }
  800. var isBlockquote = makePredByNodeName('BLOCKQUOTE');
  801. function isBodyContainer(node) {
  802. return isCell(node) || isBlockquote(node) || isEditable(node);
  803. }
  804. var isAnchor = makePredByNodeName('A');
  805. function isParaInline(node) {
  806. return isInline(node) && !!ancestor(node, isPara);
  807. }
  808. function isBodyInline(node) {
  809. return isInline(node) && !ancestor(node, isPara);
  810. }
  811. var isBody = makePredByNodeName('BODY');
  812. /**
  813. * returns whether nodeB is closest sibling of nodeA
  814. *
  815. * @param {Node} nodeA
  816. * @param {Node} nodeB
  817. * @return {Boolean}
  818. */
  819. function isClosestSibling(nodeA, nodeB) {
  820. return nodeA.nextSibling === nodeB || nodeA.previousSibling === nodeB;
  821. }
  822. /**
  823. * returns array of closest siblings with node
  824. *
  825. * @param {Node} node
  826. * @param {function} [pred] - predicate function
  827. * @return {Node[]}
  828. */
  829. function withClosestSiblings(node, pred) {
  830. pred = pred || func.ok;
  831. var siblings = [];
  832. if (node.previousSibling && pred(node.previousSibling)) {
  833. siblings.push(node.previousSibling);
  834. }
  835. siblings.push(node);
  836. if (node.nextSibling && pred(node.nextSibling)) {
  837. siblings.push(node.nextSibling);
  838. }
  839. return siblings;
  840. }
  841. /**
  842. * blank HTML for cursor position
  843. * - [workaround] old IE only works with &nbsp;
  844. * - [workaround] IE11 and other browser works with bogus br
  845. */
  846. var blankHTML = env.isMSIE && env.browserVersion < 11 ? '&nbsp;' : '<br>';
  847. /**
  848. * @method nodeLength
  849. *
  850. * returns #text's text size or element's childNodes size
  851. *
  852. * @param {Node} node
  853. */
  854. function nodeLength(node) {
  855. if (isText(node)) {
  856. return node.nodeValue.length;
  857. }
  858. if (node) {
  859. return node.childNodes.length;
  860. }
  861. return 0;
  862. }
  863. /**
  864. * returns whether deepest child node is empty or not.
  865. *
  866. * @param {Node} node
  867. * @return {Boolean}
  868. */
  869. function deepestChildIsEmpty(node) {
  870. do {
  871. if (node.firstElementChild === null || node.firstElementChild.innerHTML === '') break;
  872. } while (node = node.firstElementChild);
  873. return dom_isEmpty(node);
  874. }
  875. /**
  876. * returns whether node is empty or not.
  877. *
  878. * @param {Node} node
  879. * @return {Boolean}
  880. */
  881. function dom_isEmpty(node) {
  882. var len = nodeLength(node);
  883. if (len === 0) {
  884. return true;
  885. } else if (!isText(node) && len === 1 && node.innerHTML === blankHTML) {
  886. // ex) <p><br></p>, <span><br></span>
  887. return true;
  888. } else if (lists.all(node.childNodes, isText) && node.innerHTML === '') {
  889. // ex) <p></p>, <span></span>
  890. return true;
  891. }
  892. return false;
  893. }
  894. /**
  895. * padding blankHTML if node is empty (for cursor position)
  896. */
  897. function paddingBlankHTML(node) {
  898. if (!isVoid(node) && !nodeLength(node)) {
  899. node.innerHTML = blankHTML;
  900. }
  901. }
  902. /**
  903. * find nearest ancestor predicate hit
  904. *
  905. * @param {Node} node
  906. * @param {Function} pred - predicate function
  907. */
  908. function ancestor(node, pred) {
  909. while (node) {
  910. if (pred(node)) {
  911. return node;
  912. }
  913. if (isEditable(node)) {
  914. break;
  915. }
  916. node = node.parentNode;
  917. }
  918. return null;
  919. }
  920. /**
  921. * find nearest ancestor only single child blood line and predicate hit
  922. *
  923. * @param {Node} node
  924. * @param {Function} pred - predicate function
  925. */
  926. function singleChildAncestor(node, pred) {
  927. node = node.parentNode;
  928. while (node) {
  929. if (nodeLength(node) !== 1) {
  930. break;
  931. }
  932. if (pred(node)) {
  933. return node;
  934. }
  935. if (isEditable(node)) {
  936. break;
  937. }
  938. node = node.parentNode;
  939. }
  940. return null;
  941. }
  942. /**
  943. * returns new array of ancestor nodes (until predicate hit).
  944. *
  945. * @param {Node} node
  946. * @param {Function} [optional] pred - predicate function
  947. */
  948. function listAncestor(node, pred) {
  949. pred = pred || func.fail;
  950. var ancestors = [];
  951. ancestor(node, function (el) {
  952. if (!isEditable(el)) {
  953. ancestors.push(el);
  954. }
  955. return pred(el);
  956. });
  957. return ancestors;
  958. }
  959. /**
  960. * find farthest ancestor predicate hit
  961. */
  962. function lastAncestor(node, pred) {
  963. var ancestors = listAncestor(node);
  964. return lists.last(ancestors.filter(pred));
  965. }
  966. /**
  967. * returns common ancestor node between two nodes.
  968. *
  969. * @param {Node} nodeA
  970. * @param {Node} nodeB
  971. */
  972. function commonAncestor(nodeA, nodeB) {
  973. var ancestors = listAncestor(nodeA);
  974. for (var n = nodeB; n; n = n.parentNode) {
  975. if (ancestors.indexOf(n) > -1) return n;
  976. }
  977. return null; // difference document area
  978. }
  979. /**
  980. * listing all previous siblings (until predicate hit).
  981. *
  982. * @param {Node} node
  983. * @param {Function} [optional] pred - predicate function
  984. */
  985. function listPrev(node, pred) {
  986. pred = pred || func.fail;
  987. var nodes = [];
  988. while (node) {
  989. if (pred(node)) {
  990. break;
  991. }
  992. nodes.push(node);
  993. node = node.previousSibling;
  994. }
  995. return nodes;
  996. }
  997. /**
  998. * listing next siblings (until predicate hit).
  999. *
  1000. * @param {Node} node
  1001. * @param {Function} [pred] - predicate function
  1002. */
  1003. function listNext(node, pred) {
  1004. pred = pred || func.fail;
  1005. var nodes = [];
  1006. while (node) {
  1007. if (pred(node)) {
  1008. break;
  1009. }
  1010. nodes.push(node);
  1011. node = node.nextSibling;
  1012. }
  1013. return nodes;
  1014. }
  1015. /**
  1016. * listing descendant nodes
  1017. *
  1018. * @param {Node} node
  1019. * @param {Function} [pred] - predicate function
  1020. */
  1021. function listDescendant(node, pred) {
  1022. var descendants = [];
  1023. pred = pred || func.ok; // start DFS(depth first search) with node
  1024. (function fnWalk(current) {
  1025. if (node !== current && pred(current)) {
  1026. descendants.push(current);
  1027. }
  1028. for (var idx = 0, len = current.childNodes.length; idx < len; idx++) {
  1029. fnWalk(current.childNodes[idx]);
  1030. }
  1031. })(node);
  1032. return descendants;
  1033. }
  1034. /**
  1035. * wrap node with new tag.
  1036. *
  1037. * @param {Node} node
  1038. * @param {Node} tagName of wrapper
  1039. * @return {Node} - wrapper
  1040. */
  1041. function wrap(node, wrapperName) {
  1042. var parent = node.parentNode;
  1043. var wrapper = external_jQuery_default()('<' + wrapperName + '>')[0];
  1044. parent.insertBefore(wrapper, node);
  1045. wrapper.appendChild(node);
  1046. return wrapper;
  1047. }
  1048. /**
  1049. * insert node after preceding
  1050. *
  1051. * @param {Node} node
  1052. * @param {Node} preceding - predicate function
  1053. */
  1054. function insertAfter(node, preceding) {
  1055. var next = preceding.nextSibling;
  1056. var parent = preceding.parentNode;
  1057. if (next) {
  1058. parent.insertBefore(node, next);
  1059. } else {
  1060. parent.appendChild(node);
  1061. }
  1062. return node;
  1063. }
  1064. /**
  1065. * append elements.
  1066. *
  1067. * @param {Node} node
  1068. * @param {Collection} aChild
  1069. */
  1070. function appendChildNodes(node, aChild) {
  1071. external_jQuery_default().each(aChild, function (idx, child) {
  1072. node.appendChild(child);
  1073. });
  1074. return node;
  1075. }
  1076. /**
  1077. * returns whether boundaryPoint is left edge or not.
  1078. *
  1079. * @param {BoundaryPoint} point
  1080. * @return {Boolean}
  1081. */
  1082. function isLeftEdgePoint(point) {
  1083. return point.offset === 0;
  1084. }
  1085. /**
  1086. * returns whether boundaryPoint is right edge or not.
  1087. *
  1088. * @param {BoundaryPoint} point
  1089. * @return {Boolean}
  1090. */
  1091. function isRightEdgePoint(point) {
  1092. return point.offset === nodeLength(point.node);
  1093. }
  1094. /**
  1095. * returns whether boundaryPoint is edge or not.
  1096. *
  1097. * @param {BoundaryPoint} point
  1098. * @return {Boolean}
  1099. */
  1100. function isEdgePoint(point) {
  1101. return isLeftEdgePoint(point) || isRightEdgePoint(point);
  1102. }
  1103. /**
  1104. * returns whether node is left edge of ancestor or not.
  1105. *
  1106. * @param {Node} node
  1107. * @param {Node} ancestor
  1108. * @return {Boolean}
  1109. */
  1110. function isLeftEdgeOf(node, ancestor) {
  1111. while (node && node !== ancestor) {
  1112. if (position(node) !== 0) {
  1113. return false;
  1114. }
  1115. node = node.parentNode;
  1116. }
  1117. return true;
  1118. }
  1119. /**
  1120. * returns whether node is right edge of ancestor or not.
  1121. *
  1122. * @param {Node} node
  1123. * @param {Node} ancestor
  1124. * @return {Boolean}
  1125. */
  1126. function isRightEdgeOf(node, ancestor) {
  1127. if (!ancestor) {
  1128. return false;
  1129. }
  1130. while (node && node !== ancestor) {
  1131. if (position(node) !== nodeLength(node.parentNode) - 1) {
  1132. return false;
  1133. }
  1134. node = node.parentNode;
  1135. }
  1136. return true;
  1137. }
  1138. /**
  1139. * returns whether point is left edge of ancestor or not.
  1140. * @param {BoundaryPoint} point
  1141. * @param {Node} ancestor
  1142. * @return {Boolean}
  1143. */
  1144. function isLeftEdgePointOf(point, ancestor) {
  1145. return isLeftEdgePoint(point) && isLeftEdgeOf(point.node, ancestor);
  1146. }
  1147. /**
  1148. * returns whether point is right edge of ancestor or not.
  1149. * @param {BoundaryPoint} point
  1150. * @param {Node} ancestor
  1151. * @return {Boolean}
  1152. */
  1153. function isRightEdgePointOf(point, ancestor) {
  1154. return isRightEdgePoint(point) && isRightEdgeOf(point.node, ancestor);
  1155. }
  1156. /**
  1157. * returns offset from parent.
  1158. *
  1159. * @param {Node} node
  1160. */
  1161. function position(node) {
  1162. var offset = 0;
  1163. while (node = node.previousSibling) {
  1164. offset += 1;
  1165. }
  1166. return offset;
  1167. }
  1168. function hasChildren(node) {
  1169. return !!(node && node.childNodes && node.childNodes.length);
  1170. }
  1171. /**
  1172. * returns previous boundaryPoint
  1173. *
  1174. * @param {BoundaryPoint} point
  1175. * @param {Boolean} isSkipInnerOffset
  1176. * @return {BoundaryPoint}
  1177. */
  1178. function prevPoint(point, isSkipInnerOffset) {
  1179. var node;
  1180. var offset;
  1181. if (point.offset === 0) {
  1182. if (isEditable(point.node)) {
  1183. return null;
  1184. }
  1185. node = point.node.parentNode;
  1186. offset = position(point.node);
  1187. } else if (hasChildren(point.node)) {
  1188. node = point.node.childNodes[point.offset - 1];
  1189. offset = nodeLength(node);
  1190. } else {
  1191. node = point.node;
  1192. offset = isSkipInnerOffset ? 0 : point.offset - 1;
  1193. }
  1194. return {
  1195. node: node,
  1196. offset: offset
  1197. };
  1198. }
  1199. /**
  1200. * returns next boundaryPoint
  1201. *
  1202. * @param {BoundaryPoint} point
  1203. * @param {Boolean} isSkipInnerOffset
  1204. * @return {BoundaryPoint}
  1205. */
  1206. function nextPoint(point, isSkipInnerOffset) {
  1207. var node, offset;
  1208. if (nodeLength(point.node) === point.offset) {
  1209. if (isEditable(point.node)) {
  1210. return null;
  1211. }
  1212. var nextTextNode = getNextTextNode(point.node);
  1213. if (nextTextNode) {
  1214. node = nextTextNode;
  1215. offset = 0;
  1216. } else {
  1217. node = point.node.parentNode;
  1218. offset = position(point.node) + 1;
  1219. }
  1220. } else if (hasChildren(point.node)) {
  1221. node = point.node.childNodes[point.offset];
  1222. offset = 0;
  1223. } else {
  1224. node = point.node;
  1225. offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;
  1226. }
  1227. return {
  1228. node: node,
  1229. offset: offset
  1230. };
  1231. }
  1232. /**
  1233. * returns next boundaryPoint with empty node
  1234. *
  1235. * @param {BoundaryPoint} point
  1236. * @param {Boolean} isSkipInnerOffset
  1237. * @return {BoundaryPoint}
  1238. */
  1239. function nextPointWithEmptyNode(point, isSkipInnerOffset) {
  1240. var node,
  1241. offset = 0; // if node is empty string node, return current node's sibling.
  1242. if (dom_isEmpty(point.node)) {
  1243. if (point.node === null) {
  1244. return null;
  1245. }
  1246. node = point.node.nextSibling;
  1247. offset = 0;
  1248. return {
  1249. node: node,
  1250. offset: offset
  1251. };
  1252. }
  1253. if (nodeLength(point.node) === point.offset) {
  1254. if (isEditable(point.node)) {
  1255. return null;
  1256. }
  1257. node = point.node.parentNode;
  1258. offset = position(point.node) + 1; // if next node is editable , return current node's sibling node.
  1259. if (isEditable(node)) {
  1260. node = point.node.nextSibling;
  1261. offset = 0;
  1262. }
  1263. } else if (hasChildren(point.node)) {
  1264. node = point.node.childNodes[point.offset];
  1265. offset = 0;
  1266. if (dom_isEmpty(node)) {
  1267. if (!dom_isEmpty(point.node.nextSibling)) {
  1268. return {
  1269. node: point.node.nextSibling,
  1270. offset: offset
  1271. };
  1272. }
  1273. return null;
  1274. }
  1275. } else {
  1276. node = point.node;
  1277. offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;
  1278. if (dom_isEmpty(node)) {
  1279. return null;
  1280. }
  1281. }
  1282. return {
  1283. node: node,
  1284. offset: offset
  1285. };
  1286. }
  1287. /*
  1288. * returns the next Text node index or 0 if not found.
  1289. */
  1290. function getNextTextNode(actual) {
  1291. if (!actual.nextSibling) return undefined;
  1292. if (actual.parent !== actual.nextSibling.parent) return undefined;
  1293. if (isText(actual.nextSibling)) return actual.nextSibling;else return getNextTextNode(actual.nextSibling);
  1294. }
  1295. /**
  1296. * returns whether pointA and pointB is same or not.
  1297. *
  1298. * @param {BoundaryPoint} pointA
  1299. * @param {BoundaryPoint} pointB
  1300. * @return {Boolean}
  1301. */
  1302. function isSamePoint(pointA, pointB) {
  1303. return pointA.node === pointB.node && pointA.offset === pointB.offset;
  1304. }
  1305. /**
  1306. * returns whether point is visible (can set cursor) or not.
  1307. *
  1308. * @param {BoundaryPoint} point
  1309. * @return {Boolean}
  1310. */
  1311. function isVisiblePoint(point) {
  1312. if (isText(point.node) || !hasChildren(point.node) || dom_isEmpty(point.node)) {
  1313. return true;
  1314. }
  1315. var leftNode = point.node.childNodes[point.offset - 1];
  1316. var rightNode = point.node.childNodes[point.offset];
  1317. if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode)) || isTable(rightNode)) {
  1318. return true;
  1319. }
  1320. return false;
  1321. }
  1322. /**
  1323. * @method prevPointUtil
  1324. *
  1325. * @param {BoundaryPoint} point
  1326. * @param {Function} pred
  1327. * @return {BoundaryPoint}
  1328. */
  1329. function prevPointUntil(point, pred) {
  1330. while (point) {
  1331. if (pred(point)) {
  1332. return point;
  1333. }
  1334. point = prevPoint(point);
  1335. }
  1336. return null;
  1337. }
  1338. /**
  1339. * @method nextPointUntil
  1340. *
  1341. * @param {BoundaryPoint} point
  1342. * @param {Function} pred
  1343. * @return {BoundaryPoint}
  1344. */
  1345. function nextPointUntil(point, pred) {
  1346. while (point) {
  1347. if (pred(point)) {
  1348. return point;
  1349. }
  1350. point = nextPoint(point);
  1351. }
  1352. return null;
  1353. }
  1354. /**
  1355. * returns whether point has character or not.
  1356. *
  1357. * @param {Point} point
  1358. * @return {Boolean}
  1359. */
  1360. function isCharPoint(point) {
  1361. if (!isText(point.node)) {
  1362. return false;
  1363. }
  1364. var ch = point.node.nodeValue.charAt(point.offset - 1);
  1365. return ch && ch !== ' ' && ch !== NBSP_CHAR;
  1366. }
  1367. /**
  1368. * returns whether point has space or not.
  1369. *
  1370. * @param {Point} point
  1371. * @return {Boolean}
  1372. */
  1373. function isSpacePoint(point) {
  1374. if (!isText(point.node)) {
  1375. return false;
  1376. }
  1377. var ch = point.node.nodeValue.charAt(point.offset - 1);
  1378. return ch === ' ' || ch === NBSP_CHAR;
  1379. }
  1380. /**
  1381. * @method walkPoint
  1382. *
  1383. * @param {BoundaryPoint} startPoint
  1384. * @param {BoundaryPoint} endPoint
  1385. * @param {Function} handler
  1386. * @param {Boolean} isSkipInnerOffset
  1387. */
  1388. function walkPoint(startPoint, endPoint, handler, isSkipInnerOffset) {
  1389. var point = startPoint;
  1390. while (point) {
  1391. handler(point);
  1392. if (isSamePoint(point, endPoint)) {
  1393. break;
  1394. }
  1395. var isSkipOffset = isSkipInnerOffset && startPoint.node !== point.node && endPoint.node !== point.node;
  1396. point = nextPointWithEmptyNode(point, isSkipOffset);
  1397. }
  1398. }
  1399. /**
  1400. * @method makeOffsetPath
  1401. *
  1402. * return offsetPath(array of offset) from ancestor
  1403. *
  1404. * @param {Node} ancestor - ancestor node
  1405. * @param {Node} node
  1406. */
  1407. function makeOffsetPath(ancestor, node) {
  1408. var ancestors = listAncestor(node, func.eq(ancestor));
  1409. return ancestors.map(position).reverse();
  1410. }
  1411. /**
  1412. * @method fromOffsetPath
  1413. *
  1414. * return element from offsetPath(array of offset)
  1415. *
  1416. * @param {Node} ancestor - ancestor node
  1417. * @param {array} offsets - offsetPath
  1418. */
  1419. function fromOffsetPath(ancestor, offsets) {
  1420. var current = ancestor;
  1421. for (var i = 0, len = offsets.length; i < len; i++) {
  1422. if (current.childNodes.length <= offsets[i]) {
  1423. current = current.childNodes[current.childNodes.length - 1];
  1424. } else {
  1425. current = current.childNodes[offsets[i]];
  1426. }
  1427. }
  1428. return current;
  1429. }
  1430. /**
  1431. * @method splitNode
  1432. *
  1433. * split element or #text
  1434. *
  1435. * @param {BoundaryPoint} point
  1436. * @param {Object} [options]
  1437. * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
  1438. * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
  1439. * @param {Boolean} [options.isDiscardEmptySplits] - default: false
  1440. * @return {Node} right node of boundaryPoint
  1441. */
  1442. function splitNode(point, options) {
  1443. var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;
  1444. var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;
  1445. var isDiscardEmptySplits = options && options.isDiscardEmptySplits;
  1446. if (isDiscardEmptySplits) {
  1447. isSkipPaddingBlankHTML = true;
  1448. } // edge case
  1449. if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {
  1450. if (isLeftEdgePoint(point)) {
  1451. return point.node;
  1452. } else if (isRightEdgePoint(point)) {
  1453. return point.node.nextSibling;
  1454. }
  1455. } // split #text
  1456. if (isText(point.node)) {
  1457. return point.node.splitText(point.offset);
  1458. } else {
  1459. var childNode = point.node.childNodes[point.offset];
  1460. var clone = insertAfter(point.node.cloneNode(false), point.node);
  1461. appendChildNodes(clone, listNext(childNode));
  1462. if (!isSkipPaddingBlankHTML) {
  1463. paddingBlankHTML(point.node);
  1464. paddingBlankHTML(clone);
  1465. }
  1466. if (isDiscardEmptySplits) {
  1467. if (dom_isEmpty(point.node)) {
  1468. remove(point.node);
  1469. }
  1470. if (dom_isEmpty(clone)) {
  1471. remove(clone);
  1472. return point.node.nextSibling;
  1473. }
  1474. }
  1475. return clone;
  1476. }
  1477. }
  1478. /**
  1479. * @method splitTree
  1480. *
  1481. * split tree by point
  1482. *
  1483. * @param {Node} root - split root
  1484. * @param {BoundaryPoint} point
  1485. * @param {Object} [options]
  1486. * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
  1487. * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
  1488. * @return {Node} right node of boundaryPoint
  1489. */
  1490. function splitTree(root, point, options) {
  1491. // ex) [#text, <span>, <p>]
  1492. var ancestors = listAncestor(point.node, func.eq(root));
  1493. if (!ancestors.length) {
  1494. return null;
  1495. } else if (ancestors.length === 1) {
  1496. return splitNode(point, options);
  1497. }
  1498. return ancestors.reduce(function (node, parent) {
  1499. if (node === point.node) {
  1500. node = splitNode(point, options);
  1501. }
  1502. return splitNode({
  1503. node: parent,
  1504. offset: node ? position(node) : nodeLength(parent)
  1505. }, options);
  1506. });
  1507. }
  1508. /**
  1509. * split point
  1510. *
  1511. * @param {Point} point
  1512. * @param {Boolean} isInline
  1513. * @return {Object}
  1514. */
  1515. function splitPoint(point, isInline) {
  1516. // find splitRoot, container
  1517. // - inline: splitRoot is a child of paragraph
  1518. // - block: splitRoot is a child of bodyContainer
  1519. var pred = isInline ? isPara : isBodyContainer;
  1520. var ancestors = listAncestor(point.node, pred);
  1521. var topAncestor = lists.last(ancestors) || point.node;
  1522. var splitRoot, container;
  1523. if (pred(topAncestor)) {
  1524. splitRoot = ancestors[ancestors.length - 2];
  1525. container = topAncestor;
  1526. } else {
  1527. splitRoot = topAncestor;
  1528. container = splitRoot.parentNode;
  1529. } // if splitRoot is exists, split with splitTree
  1530. var pivot = splitRoot && splitTree(splitRoot, point, {
  1531. isSkipPaddingBlankHTML: isInline,
  1532. isNotSplitEdgePoint: isInline
  1533. }); // if container is point.node, find pivot with point.offset
  1534. if (!pivot && container === point.node) {
  1535. pivot = point.node.childNodes[point.offset];
  1536. }
  1537. return {
  1538. rightNode: pivot,
  1539. container: container
  1540. };
  1541. }
  1542. function create(nodeName) {
  1543. return document.createElement(nodeName);
  1544. }
  1545. function createText(text) {
  1546. return document.createTextNode(text);
  1547. }
  1548. /**
  1549. * @method remove
  1550. *
  1551. * remove node, (isRemoveChild: remove child or not)
  1552. *
  1553. * @param {Node} node
  1554. * @param {Boolean} isRemoveChild
  1555. */
  1556. function remove(node, isRemoveChild) {
  1557. if (!node || !node.parentNode) {
  1558. return;
  1559. }
  1560. if (node.removeNode) {
  1561. return node.removeNode(isRemoveChild);
  1562. }
  1563. var parent = node.parentNode;
  1564. if (!isRemoveChild) {
  1565. var nodes = [];
  1566. for (var i = 0, len = node.childNodes.length; i < len; i++) {
  1567. nodes.push(node.childNodes[i]);
  1568. }
  1569. for (var _i = 0, _len = nodes.length; _i < _len; _i++) {
  1570. parent.insertBefore(nodes[_i], node);
  1571. }
  1572. }
  1573. parent.removeChild(node);
  1574. }
  1575. /**
  1576. * @method removeWhile
  1577. *
  1578. * @param {Node} node
  1579. * @param {Function} pred
  1580. */
  1581. function removeWhile(node, pred) {
  1582. while (node) {
  1583. if (isEditable(node) || !pred(node)) {
  1584. break;
  1585. }
  1586. var parent = node.parentNode;
  1587. remove(node);
  1588. node = parent;
  1589. }
  1590. }
  1591. /**
  1592. * @method replace
  1593. *
  1594. * replace node with provided nodeName
  1595. *
  1596. * @param {Node} node
  1597. * @param {String} nodeName
  1598. * @return {Node} - new node
  1599. */
  1600. function replace(node, nodeName) {
  1601. if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {
  1602. return node;
  1603. }
  1604. var newNode = create(nodeName);
  1605. if (node.style.cssText) {
  1606. newNode.style.cssText = node.style.cssText;
  1607. }
  1608. appendChildNodes(newNode, lists.from(node.childNodes));
  1609. insertAfter(newNode, node);
  1610. remove(node);
  1611. return newNode;
  1612. }
  1613. var isTextarea = makePredByNodeName('TEXTAREA');
  1614. /**
  1615. * @param {jQuery} $node
  1616. * @param {Boolean} [stripLinebreaks] - default: false
  1617. */
  1618. function value($node, stripLinebreaks) {
  1619. var val = isTextarea($node[0]) ? $node.val() : $node.html();
  1620. if (stripLinebreaks) {
  1621. return val.replace(/[\n\r]/g, '');
  1622. }
  1623. return val;
  1624. }
  1625. /**
  1626. * @method html
  1627. *
  1628. * get the HTML contents of node
  1629. *
  1630. * @param {jQuery} $node
  1631. * @param {Boolean} [isNewlineOnBlock]
  1632. */
  1633. function html($node, isNewlineOnBlock) {
  1634. var markup = value($node);
  1635. if (isNewlineOnBlock) {
  1636. var regexTag = /<(\/?)(\b(?!!)[^>\s]*)(.*?)(\s*\/?>)/g;
  1637. markup = markup.replace(regexTag, function (match, endSlash, name) {
  1638. name = name.toUpperCase();
  1639. var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) && !!endSlash;
  1640. var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);
  1641. return match + (isEndOfInlineContainer || isBlockNode ? '\n' : '');
  1642. });
  1643. markup = markup.trim();
  1644. }
  1645. return markup;
  1646. }
  1647. function posFromPlaceholder(placeholder) {
  1648. var $placeholder = external_jQuery_default()(placeholder);
  1649. var pos = $placeholder.offset();
  1650. var height = $placeholder.outerHeight(true); // include margin
  1651. return {
  1652. left: pos.left,
  1653. top: pos.top + height
  1654. };
  1655. }
  1656. function attachEvents($node, events) {
  1657. Object.keys(events).forEach(function (key) {
  1658. $node.on(key, events[key]);
  1659. });
  1660. }
  1661. function detachEvents($node, events) {
  1662. Object.keys(events).forEach(function (key) {
  1663. $node.off(key, events[key]);
  1664. });
  1665. }
  1666. /**
  1667. * @method isCustomStyleTag
  1668. *
  1669. * assert if a node contains a "note-styletag" class,
  1670. * which implies that's a custom-made style tag node
  1671. *
  1672. * @param {Node} an HTML DOM node
  1673. */
  1674. function isCustomStyleTag(node) {
  1675. return node && !isText(node) && lists.contains(node.classList, 'note-styletag');
  1676. }
  1677. /* harmony default export */ const dom = ({
  1678. /** @property {String} NBSP_CHAR */
  1679. NBSP_CHAR: NBSP_CHAR,
  1680. /** @property {String} ZERO_WIDTH_NBSP_CHAR */
  1681. ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,
  1682. /** @property {String} blank */
  1683. blank: blankHTML,
  1684. /** @property {String} emptyPara */
  1685. emptyPara: "<p>".concat(blankHTML, "</p>"),
  1686. makePredByNodeName: makePredByNodeName,
  1687. isEditable: isEditable,
  1688. isControlSizing: isControlSizing,
  1689. isText: isText,
  1690. isElement: isElement,
  1691. isVoid: isVoid,
  1692. isPara: isPara,
  1693. isPurePara: isPurePara,
  1694. isHeading: isHeading,
  1695. isInline: isInline,
  1696. isBlock: func.not(isInline),
  1697. isBodyInline: isBodyInline,
  1698. isBody: isBody,
  1699. isParaInline: isParaInline,
  1700. isPre: isPre,
  1701. isList: isList,
  1702. isTable: isTable,
  1703. isData: isData,
  1704. isCell: isCell,
  1705. isBlockquote: isBlockquote,
  1706. isBodyContainer: isBodyContainer,
  1707. isAnchor: isAnchor,
  1708. isDiv: makePredByNodeName('DIV'),
  1709. isLi: isLi,
  1710. isBR: makePredByNodeName('BR'),
  1711. isSpan: makePredByNodeName('SPAN'),
  1712. isB: makePredByNodeName('B'),
  1713. isU: makePredByNodeName('U'),
  1714. isS: makePredByNodeName('S'),
  1715. isI: makePredByNodeName('I'),
  1716. isImg: makePredByNodeName('IMG'),
  1717. isTextarea: isTextarea,
  1718. deepestChildIsEmpty: deepestChildIsEmpty,
  1719. isEmpty: dom_isEmpty,
  1720. isEmptyAnchor: func.and(isAnchor, dom_isEmpty),
  1721. isClosestSibling: isClosestSibling,
  1722. withClosestSiblings: withClosestSiblings,
  1723. nodeLength: nodeLength,
  1724. isLeftEdgePoint: isLeftEdgePoint,
  1725. isRightEdgePoint: isRightEdgePoint,
  1726. isEdgePoint: isEdgePoint,
  1727. isLeftEdgeOf: isLeftEdgeOf,
  1728. isRightEdgeOf: isRightEdgeOf,
  1729. isLeftEdgePointOf: isLeftEdgePointOf,
  1730. isRightEdgePointOf: isRightEdgePointOf,
  1731. prevPoint: prevPoint,
  1732. nextPoint: nextPoint,
  1733. nextPointWithEmptyNode: nextPointWithEmptyNode,
  1734. isSamePoint: isSamePoint,
  1735. isVisiblePoint: isVisiblePoint,
  1736. prevPointUntil: prevPointUntil,
  1737. nextPointUntil: nextPointUntil,
  1738. isCharPoint: isCharPoint,
  1739. isSpacePoint: isSpacePoint,
  1740. walkPoint: walkPoint,
  1741. ancestor: ancestor,
  1742. singleChildAncestor: singleChildAncestor,
  1743. listAncestor: listAncestor,
  1744. lastAncestor: lastAncestor,
  1745. listNext: listNext,
  1746. listPrev: listPrev,
  1747. listDescendant: listDescendant,
  1748. commonAncestor: commonAncestor,
  1749. wrap: wrap,
  1750. insertAfter: insertAfter,
  1751. appendChildNodes: appendChildNodes,
  1752. position: position,
  1753. hasChildren: hasChildren,
  1754. makeOffsetPath: makeOffsetPath,
  1755. fromOffsetPath: fromOffsetPath,
  1756. splitTree: splitTree,
  1757. splitPoint: splitPoint,
  1758. create: create,
  1759. createText: createText,
  1760. remove: remove,
  1761. removeWhile: removeWhile,
  1762. replace: replace,
  1763. html: html,
  1764. value: value,
  1765. posFromPlaceholder: posFromPlaceholder,
  1766. attachEvents: attachEvents,
  1767. detachEvents: detachEvents,
  1768. isCustomStyleTag: isCustomStyleTag
  1769. });
  1770. ;// CONCATENATED MODULE: ./src/js/Context.js
  1771. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  1772. 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); } }
  1773. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  1774. var Context = /*#__PURE__*/function () {
  1775. /**
  1776. * @param {jQuery} $note
  1777. * @param {Object} options
  1778. */
  1779. function Context($note, options) {
  1780. _classCallCheck(this, Context);
  1781. this.$note = $note;
  1782. this.memos = {};
  1783. this.modules = {};
  1784. this.layoutInfo = {};
  1785. this.options = external_jQuery_default().extend(true, {}, options); // init ui with options
  1786. (external_jQuery_default()).summernote.ui = external_jQuery_default().summernote.ui_template(this.options);
  1787. this.ui = (external_jQuery_default()).summernote.ui;
  1788. this.initialize();
  1789. }
  1790. /**
  1791. * create layout and initialize modules and other resources
  1792. */
  1793. _createClass(Context, [{
  1794. key: "initialize",
  1795. value: function initialize() {
  1796. this.layoutInfo = this.ui.createLayout(this.$note);
  1797. this._initialize();
  1798. this.$note.hide();
  1799. return this;
  1800. }
  1801. /**
  1802. * destroy modules and other resources and remove layout
  1803. */
  1804. }, {
  1805. key: "destroy",
  1806. value: function destroy() {
  1807. this._destroy();
  1808. this.$note.removeData('summernote');
  1809. this.ui.removeLayout(this.$note, this.layoutInfo);
  1810. }
  1811. /**
  1812. * destory modules and other resources and initialize it again
  1813. */
  1814. }, {
  1815. key: "reset",
  1816. value: function reset() {
  1817. var disabled = this.isDisabled();
  1818. this.code(dom.emptyPara);
  1819. this._destroy();
  1820. this._initialize();
  1821. if (disabled) {
  1822. this.disable();
  1823. }
  1824. }
  1825. }, {
  1826. key: "_initialize",
  1827. value: function _initialize() {
  1828. var _this = this;
  1829. // set own id
  1830. this.options.id = func.uniqueId(external_jQuery_default().now()); // set default container for tooltips, popovers, and dialogs
  1831. this.options.container = this.options.container || this.layoutInfo.editor; // add optional buttons
  1832. var buttons = external_jQuery_default().extend({}, this.options.buttons);
  1833. Object.keys(buttons).forEach(function (key) {
  1834. _this.memo('button.' + key, buttons[key]);
  1835. });
  1836. var modules = external_jQuery_default().extend({}, this.options.modules, (external_jQuery_default()).summernote.plugins || {}); // add and initialize modules
  1837. Object.keys(modules).forEach(function (key) {
  1838. _this.module(key, modules[key], true);
  1839. });
  1840. Object.keys(this.modules).forEach(function (key) {
  1841. _this.initializeModule(key);
  1842. });
  1843. }
  1844. }, {
  1845. key: "_destroy",
  1846. value: function _destroy() {
  1847. var _this2 = this;
  1848. // destroy modules with reversed order
  1849. Object.keys(this.modules).reverse().forEach(function (key) {
  1850. _this2.removeModule(key);
  1851. });
  1852. Object.keys(this.memos).forEach(function (key) {
  1853. _this2.removeMemo(key);
  1854. }); // trigger custom onDestroy callback
  1855. this.triggerEvent('destroy', this);
  1856. }
  1857. }, {
  1858. key: "code",
  1859. value: function code(html) {
  1860. var isActivated = this.invoke('codeview.isActivated');
  1861. if (html === undefined) {
  1862. this.invoke('codeview.sync');
  1863. return isActivated ? this.layoutInfo.codable.val() : this.layoutInfo.editable.html();
  1864. } else {
  1865. if (isActivated) {
  1866. this.invoke('codeview.sync', html);
  1867. } else {
  1868. this.layoutInfo.editable.html(html);
  1869. }
  1870. this.$note.val(html);
  1871. this.triggerEvent('change', html, this.layoutInfo.editable);
  1872. }
  1873. }
  1874. }, {
  1875. key: "isDisabled",
  1876. value: function isDisabled() {
  1877. return this.layoutInfo.editable.attr('contenteditable') === 'false';
  1878. }
  1879. }, {
  1880. key: "enable",
  1881. value: function enable() {
  1882. this.layoutInfo.editable.attr('contenteditable', true);
  1883. this.invoke('toolbar.activate', true);
  1884. this.triggerEvent('disable', false);
  1885. this.options.editing = true;
  1886. }
  1887. }, {
  1888. key: "disable",
  1889. value: function disable() {
  1890. // close codeview if codeview is opend
  1891. if (this.invoke('codeview.isActivated')) {
  1892. this.invoke('codeview.deactivate');
  1893. }
  1894. this.layoutInfo.editable.attr('contenteditable', false);
  1895. this.options.editing = false;
  1896. this.invoke('toolbar.deactivate', true);
  1897. this.triggerEvent('disable', true);
  1898. }
  1899. }, {
  1900. key: "triggerEvent",
  1901. value: function triggerEvent() {
  1902. var namespace = lists.head(arguments);
  1903. var args = lists.tail(lists.from(arguments));
  1904. var callback = this.options.callbacks[func.namespaceToCamel(namespace, 'on')];
  1905. if (callback) {
  1906. callback.apply(this.$note[0], args);
  1907. }
  1908. this.$note.trigger('summernote.' + namespace, args);
  1909. }
  1910. }, {
  1911. key: "initializeModule",
  1912. value: function initializeModule(key) {
  1913. var module = this.modules[key];
  1914. module.shouldInitialize = module.shouldInitialize || func.ok;
  1915. if (!module.shouldInitialize()) {
  1916. return;
  1917. } // initialize module
  1918. if (module.initialize) {
  1919. module.initialize();
  1920. } // attach events
  1921. if (module.events) {
  1922. dom.attachEvents(this.$note, module.events);
  1923. }
  1924. }
  1925. }, {
  1926. key: "module",
  1927. value: function module(key, ModuleClass, withoutIntialize) {
  1928. if (arguments.length === 1) {
  1929. return this.modules[key];
  1930. }
  1931. this.modules[key] = new ModuleClass(this);
  1932. if (!withoutIntialize) {
  1933. this.initializeModule(key);
  1934. }
  1935. }
  1936. }, {
  1937. key: "removeModule",
  1938. value: function removeModule(key) {
  1939. var module = this.modules[key];
  1940. if (module.shouldInitialize()) {
  1941. if (module.events) {
  1942. dom.detachEvents(this.$note, module.events);
  1943. }
  1944. if (module.destroy) {
  1945. module.destroy();
  1946. }
  1947. }
  1948. delete this.modules[key];
  1949. }
  1950. }, {
  1951. key: "memo",
  1952. value: function memo(key, obj) {
  1953. if (arguments.length === 1) {
  1954. return this.memos[key];
  1955. }
  1956. this.memos[key] = obj;
  1957. }
  1958. }, {
  1959. key: "removeMemo",
  1960. value: function removeMemo(key) {
  1961. if (this.memos[key] && this.memos[key].destroy) {
  1962. this.memos[key].destroy();
  1963. }
  1964. delete this.memos[key];
  1965. }
  1966. /**
  1967. * Some buttons need to change their visual style immediately once they get pressed
  1968. */
  1969. }, {
  1970. key: "createInvokeHandlerAndUpdateState",
  1971. value: function createInvokeHandlerAndUpdateState(namespace, value) {
  1972. var _this3 = this;
  1973. return function (event) {
  1974. _this3.createInvokeHandler(namespace, value)(event);
  1975. _this3.invoke('buttons.updateCurrentStyle');
  1976. };
  1977. }
  1978. }, {
  1979. key: "createInvokeHandler",
  1980. value: function createInvokeHandler(namespace, value) {
  1981. var _this4 = this;
  1982. return function (event) {
  1983. event.preventDefault();
  1984. var $target = external_jQuery_default()(event.target);
  1985. _this4.invoke(namespace, value || $target.closest('[data-value]').data('value'), $target);
  1986. };
  1987. }
  1988. }, {
  1989. key: "invoke",
  1990. value: function invoke() {
  1991. var namespace = lists.head(arguments);
  1992. var args = lists.tail(lists.from(arguments));
  1993. var splits = namespace.split('.');
  1994. var hasSeparator = splits.length > 1;
  1995. var moduleName = hasSeparator && lists.head(splits);
  1996. var methodName = hasSeparator ? lists.last(splits) : lists.head(splits);
  1997. var module = this.modules[moduleName || 'editor'];
  1998. if (!moduleName && this[methodName]) {
  1999. return this[methodName].apply(this, args);
  2000. } else if (module && module[methodName] && module.shouldInitialize()) {
  2001. return module[methodName].apply(module, args);
  2002. }
  2003. }
  2004. }]);
  2005. return Context;
  2006. }();
  2007. ;// CONCATENATED MODULE: ./src/js/summernote.js
  2008. external_jQuery_default().fn.extend({
  2009. /**
  2010. * Summernote API
  2011. *
  2012. * @param {Object|String}
  2013. * @return {this}
  2014. */
  2015. summernote: function summernote() {
  2016. var type = external_jQuery_default().type(lists.head(arguments));
  2017. var isExternalAPICalled = type === 'string';
  2018. var hasInitOptions = type === 'object';
  2019. var options = external_jQuery_default().extend({}, (external_jQuery_default()).summernote.options, hasInitOptions ? lists.head(arguments) : {}); // Update options
  2020. options.langInfo = external_jQuery_default().extend(true, {}, (external_jQuery_default()).summernote.lang["en-US"], (external_jQuery_default()).summernote.lang[options.lang]);
  2021. options.icons = external_jQuery_default().extend(true, {}, (external_jQuery_default()).summernote.options.icons, options.icons);
  2022. options.tooltip = options.tooltip === 'auto' ? !env.isSupportTouch : options.tooltip;
  2023. this.each(function (idx, note) {
  2024. var $note = external_jQuery_default()(note);
  2025. if (!$note.data('summernote')) {
  2026. var context = new Context($note, options);
  2027. $note.data('summernote', context);
  2028. $note.data('summernote').triggerEvent('init', context.layoutInfo);
  2029. }
  2030. });
  2031. var $note = this.first();
  2032. if ($note.length) {
  2033. var context = $note.data('summernote');
  2034. if (isExternalAPICalled) {
  2035. return context.invoke.apply(context, lists.from(arguments));
  2036. } else if (options.focus) {
  2037. context.invoke('editor.focus');
  2038. }
  2039. }
  2040. return this;
  2041. }
  2042. });
  2043. ;// CONCATENATED MODULE: ./src/js/core/range.js
  2044. function range_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  2045. function range_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); } }
  2046. function range_createClass(Constructor, protoProps, staticProps) { if (protoProps) range_defineProperties(Constructor.prototype, protoProps); if (staticProps) range_defineProperties(Constructor, staticProps); return Constructor; }
  2047. /**
  2048. * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js
  2049. *
  2050. * @param {TextRange} textRange
  2051. * @param {Boolean} isStart
  2052. * @return {BoundaryPoint}
  2053. *
  2054. * @see http://msdn.microsoft.com/en-us/library/ie/ms535872(v=vs.85).aspx
  2055. */
  2056. function textRangeToPoint(textRange, isStart) {
  2057. var container = textRange.parentElement();
  2058. var offset;
  2059. var tester = document.body.createTextRange();
  2060. var prevContainer;
  2061. var childNodes = lists.from(container.childNodes);
  2062. for (offset = 0; offset < childNodes.length; offset++) {
  2063. if (dom.isText(childNodes[offset])) {
  2064. continue;
  2065. }
  2066. tester.moveToElementText(childNodes[offset]);
  2067. if (tester.compareEndPoints('StartToStart', textRange) >= 0) {
  2068. break;
  2069. }
  2070. prevContainer = childNodes[offset];
  2071. }
  2072. if (offset !== 0 && dom.isText(childNodes[offset - 1])) {
  2073. var textRangeStart = document.body.createTextRange();
  2074. var curTextNode = null;
  2075. textRangeStart.moveToElementText(prevContainer || container);
  2076. textRangeStart.collapse(!prevContainer);
  2077. curTextNode = prevContainer ? prevContainer.nextSibling : container.firstChild;
  2078. var pointTester = textRange.duplicate();
  2079. pointTester.setEndPoint('StartToStart', textRangeStart);
  2080. var textCount = pointTester.text.replace(/[\r\n]/g, '').length;
  2081. while (textCount > curTextNode.nodeValue.length && curTextNode.nextSibling) {
  2082. textCount -= curTextNode.nodeValue.length;
  2083. curTextNode = curTextNode.nextSibling;
  2084. } // [workaround] enforce IE to re-reference curTextNode, hack
  2085. var dummy = curTextNode.nodeValue; // eslint-disable-line
  2086. if (isStart && curTextNode.nextSibling && dom.isText(curTextNode.nextSibling) && textCount === curTextNode.nodeValue.length) {
  2087. textCount -= curTextNode.nodeValue.length;
  2088. curTextNode = curTextNode.nextSibling;
  2089. }
  2090. container = curTextNode;
  2091. offset = textCount;
  2092. }
  2093. return {
  2094. cont: container,
  2095. offset: offset
  2096. };
  2097. }
  2098. /**
  2099. * return TextRange from boundary point (inspired by google closure-library)
  2100. * @param {BoundaryPoint} point
  2101. * @return {TextRange}
  2102. */
  2103. function pointToTextRange(point) {
  2104. var textRangeInfo = function textRangeInfo(container, offset) {
  2105. var node, isCollapseToStart;
  2106. if (dom.isText(container)) {
  2107. var prevTextNodes = dom.listPrev(container, func.not(dom.isText));
  2108. var prevContainer = lists.last(prevTextNodes).previousSibling;
  2109. node = prevContainer || container.parentNode;
  2110. offset += lists.sum(lists.tail(prevTextNodes), dom.nodeLength);
  2111. isCollapseToStart = !prevContainer;
  2112. } else {
  2113. node = container.childNodes[offset] || container;
  2114. if (dom.isText(node)) {
  2115. return textRangeInfo(node, 0);
  2116. }
  2117. offset = 0;
  2118. isCollapseToStart = false;
  2119. }
  2120. return {
  2121. node: node,
  2122. collapseToStart: isCollapseToStart,
  2123. offset: offset
  2124. };
  2125. };
  2126. var textRange = document.body.createTextRange();
  2127. var info = textRangeInfo(point.node, point.offset);
  2128. textRange.moveToElementText(info.node);
  2129. textRange.collapse(info.collapseToStart);
  2130. textRange.moveStart('character', info.offset);
  2131. return textRange;
  2132. }
  2133. /**
  2134. * Wrapped Range
  2135. *
  2136. * @constructor
  2137. * @param {Node} sc - start container
  2138. * @param {Number} so - start offset
  2139. * @param {Node} ec - end container
  2140. * @param {Number} eo - end offset
  2141. */
  2142. var WrappedRange = /*#__PURE__*/function () {
  2143. function WrappedRange(sc, so, ec, eo) {
  2144. range_classCallCheck(this, WrappedRange);
  2145. this.sc = sc;
  2146. this.so = so;
  2147. this.ec = ec;
  2148. this.eo = eo; // isOnEditable: judge whether range is on editable or not
  2149. this.isOnEditable = this.makeIsOn(dom.isEditable); // isOnList: judge whether range is on list node or not
  2150. this.isOnList = this.makeIsOn(dom.isList); // isOnAnchor: judge whether range is on anchor node or not
  2151. this.isOnAnchor = this.makeIsOn(dom.isAnchor); // isOnCell: judge whether range is on cell node or not
  2152. this.isOnCell = this.makeIsOn(dom.isCell); // isOnData: judge whether range is on data node or not
  2153. this.isOnData = this.makeIsOn(dom.isData);
  2154. } // nativeRange: get nativeRange from sc, so, ec, eo
  2155. range_createClass(WrappedRange, [{
  2156. key: "nativeRange",
  2157. value: function nativeRange() {
  2158. if (env.isW3CRangeSupport) {
  2159. var w3cRange = document.createRange();
  2160. w3cRange.setStart(this.sc, this.so);
  2161. w3cRange.setEnd(this.ec, this.eo);
  2162. return w3cRange;
  2163. } else {
  2164. var textRange = pointToTextRange({
  2165. node: this.sc,
  2166. offset: this.so
  2167. });
  2168. textRange.setEndPoint('EndToEnd', pointToTextRange({
  2169. node: this.ec,
  2170. offset: this.eo
  2171. }));
  2172. return textRange;
  2173. }
  2174. }
  2175. }, {
  2176. key: "getPoints",
  2177. value: function getPoints() {
  2178. return {
  2179. sc: this.sc,
  2180. so: this.so,
  2181. ec: this.ec,
  2182. eo: this.eo
  2183. };
  2184. }
  2185. }, {
  2186. key: "getStartPoint",
  2187. value: function getStartPoint() {
  2188. return {
  2189. node: this.sc,
  2190. offset: this.so
  2191. };
  2192. }
  2193. }, {
  2194. key: "getEndPoint",
  2195. value: function getEndPoint() {
  2196. return {
  2197. node: this.ec,
  2198. offset: this.eo
  2199. };
  2200. }
  2201. /**
  2202. * select update visible range
  2203. */
  2204. }, {
  2205. key: "select",
  2206. value: function select() {
  2207. var nativeRng = this.nativeRange();
  2208. if (env.isW3CRangeSupport) {
  2209. var selection = document.getSelection();
  2210. if (selection.rangeCount > 0) {
  2211. selection.removeAllRanges();
  2212. }
  2213. selection.addRange(nativeRng);
  2214. } else {
  2215. nativeRng.select();
  2216. }
  2217. return this;
  2218. }
  2219. /**
  2220. * Moves the scrollbar to start container(sc) of current range
  2221. *
  2222. * @return {WrappedRange}
  2223. */
  2224. }, {
  2225. key: "scrollIntoView",
  2226. value: function scrollIntoView(container) {
  2227. var height = external_jQuery_default()(container).height();
  2228. if (container.scrollTop + height < this.sc.offsetTop) {
  2229. container.scrollTop += Math.abs(container.scrollTop + height - this.sc.offsetTop);
  2230. }
  2231. return this;
  2232. }
  2233. /**
  2234. * @return {WrappedRange}
  2235. */
  2236. }, {
  2237. key: "normalize",
  2238. value: function normalize() {
  2239. /**
  2240. * @param {BoundaryPoint} point
  2241. * @param {Boolean} isLeftToRight - true: prefer to choose right node
  2242. * - false: prefer to choose left node
  2243. * @return {BoundaryPoint}
  2244. */
  2245. var getVisiblePoint = function getVisiblePoint(point, isLeftToRight) {
  2246. if (!point) {
  2247. return point;
  2248. } // Just use the given point [XXX:Adhoc]
  2249. // - case 01. if the point is on the middle of the node
  2250. // - case 02. if the point is on the right edge and prefer to choose left node
  2251. // - case 03. if the point is on the left edge and prefer to choose right node
  2252. // - case 04. if the point is on the right edge and prefer to choose right node but the node is void
  2253. // - case 05. if the point is on the left edge and prefer to choose left node but the node is void
  2254. // - case 06. if the point is on the block node and there is no children
  2255. if (dom.isVisiblePoint(point)) {
  2256. if (!dom.isEdgePoint(point) || dom.isRightEdgePoint(point) && !isLeftToRight || dom.isLeftEdgePoint(point) && isLeftToRight || dom.isRightEdgePoint(point) && isLeftToRight && dom.isVoid(point.node.nextSibling) || dom.isLeftEdgePoint(point) && !isLeftToRight && dom.isVoid(point.node.previousSibling) || dom.isBlock(point.node) && dom.isEmpty(point.node)) {
  2257. return point;
  2258. }
  2259. } // point on block's edge
  2260. var block = dom.ancestor(point.node, dom.isBlock);
  2261. var hasRightNode = false;
  2262. if (!hasRightNode) {
  2263. var prevPoint = dom.prevPoint(point) || {
  2264. node: null
  2265. };
  2266. hasRightNode = (dom.isLeftEdgePointOf(point, block) || dom.isVoid(prevPoint.node)) && !isLeftToRight;
  2267. }
  2268. var hasLeftNode = false;
  2269. if (!hasLeftNode) {
  2270. var _nextPoint = dom.nextPoint(point) || {
  2271. node: null
  2272. };
  2273. hasLeftNode = (dom.isRightEdgePointOf(point, block) || dom.isVoid(_nextPoint.node)) && isLeftToRight;
  2274. }
  2275. if (hasRightNode || hasLeftNode) {
  2276. // returns point already on visible point
  2277. if (dom.isVisiblePoint(point)) {
  2278. return point;
  2279. } // reverse direction
  2280. isLeftToRight = !isLeftToRight;
  2281. }
  2282. var nextPoint = isLeftToRight ? dom.nextPointUntil(dom.nextPoint(point), dom.isVisiblePoint) : dom.prevPointUntil(dom.prevPoint(point), dom.isVisiblePoint);
  2283. return nextPoint || point;
  2284. };
  2285. var endPoint = getVisiblePoint(this.getEndPoint(), false);
  2286. var startPoint = this.isCollapsed() ? endPoint : getVisiblePoint(this.getStartPoint(), true);
  2287. return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
  2288. }
  2289. /**
  2290. * returns matched nodes on range
  2291. *
  2292. * @param {Function} [pred] - predicate function
  2293. * @param {Object} [options]
  2294. * @param {Boolean} [options.includeAncestor]
  2295. * @param {Boolean} [options.fullyContains]
  2296. * @return {Node[]}
  2297. */
  2298. }, {
  2299. key: "nodes",
  2300. value: function nodes(pred, options) {
  2301. pred = pred || func.ok;
  2302. var includeAncestor = options && options.includeAncestor;
  2303. var fullyContains = options && options.fullyContains; // TODO compare points and sort
  2304. var startPoint = this.getStartPoint();
  2305. var endPoint = this.getEndPoint();
  2306. var nodes = [];
  2307. var leftEdgeNodes = [];
  2308. dom.walkPoint(startPoint, endPoint, function (point) {
  2309. if (dom.isEditable(point.node)) {
  2310. return;
  2311. }
  2312. var node;
  2313. if (fullyContains) {
  2314. if (dom.isLeftEdgePoint(point)) {
  2315. leftEdgeNodes.push(point.node);
  2316. }
  2317. if (dom.isRightEdgePoint(point) && lists.contains(leftEdgeNodes, point.node)) {
  2318. node = point.node;
  2319. }
  2320. } else if (includeAncestor) {
  2321. node = dom.ancestor(point.node, pred);
  2322. } else {
  2323. node = point.node;
  2324. }
  2325. if (node && pred(node)) {
  2326. nodes.push(node);
  2327. }
  2328. }, true);
  2329. return lists.unique(nodes);
  2330. }
  2331. /**
  2332. * returns commonAncestor of range
  2333. * @return {Element} - commonAncestor
  2334. */
  2335. }, {
  2336. key: "commonAncestor",
  2337. value: function commonAncestor() {
  2338. return dom.commonAncestor(this.sc, this.ec);
  2339. }
  2340. /**
  2341. * returns expanded range by pred
  2342. *
  2343. * @param {Function} pred - predicate function
  2344. * @return {WrappedRange}
  2345. */
  2346. }, {
  2347. key: "expand",
  2348. value: function expand(pred) {
  2349. var startAncestor = dom.ancestor(this.sc, pred);
  2350. var endAncestor = dom.ancestor(this.ec, pred);
  2351. if (!startAncestor && !endAncestor) {
  2352. return new WrappedRange(this.sc, this.so, this.ec, this.eo);
  2353. }
  2354. var boundaryPoints = this.getPoints();
  2355. if (startAncestor) {
  2356. boundaryPoints.sc = startAncestor;
  2357. boundaryPoints.so = 0;
  2358. }
  2359. if (endAncestor) {
  2360. boundaryPoints.ec = endAncestor;
  2361. boundaryPoints.eo = dom.nodeLength(endAncestor);
  2362. }
  2363. return new WrappedRange(boundaryPoints.sc, boundaryPoints.so, boundaryPoints.ec, boundaryPoints.eo);
  2364. }
  2365. /**
  2366. * @param {Boolean} isCollapseToStart
  2367. * @return {WrappedRange}
  2368. */
  2369. }, {
  2370. key: "collapse",
  2371. value: function collapse(isCollapseToStart) {
  2372. if (isCollapseToStart) {
  2373. return new WrappedRange(this.sc, this.so, this.sc, this.so);
  2374. } else {
  2375. return new WrappedRange(this.ec, this.eo, this.ec, this.eo);
  2376. }
  2377. }
  2378. /**
  2379. * splitText on range
  2380. */
  2381. }, {
  2382. key: "splitText",
  2383. value: function splitText() {
  2384. var isSameContainer = this.sc === this.ec;
  2385. var boundaryPoints = this.getPoints();
  2386. if (dom.isText(this.ec) && !dom.isEdgePoint(this.getEndPoint())) {
  2387. this.ec.splitText(this.eo);
  2388. }
  2389. if (dom.isText(this.sc) && !dom.isEdgePoint(this.getStartPoint())) {
  2390. boundaryPoints.sc = this.sc.splitText(this.so);
  2391. boundaryPoints.so = 0;
  2392. if (isSameContainer) {
  2393. boundaryPoints.ec = boundaryPoints.sc;
  2394. boundaryPoints.eo = this.eo - this.so;
  2395. }
  2396. }
  2397. return new WrappedRange(boundaryPoints.sc, boundaryPoints.so, boundaryPoints.ec, boundaryPoints.eo);
  2398. }
  2399. /**
  2400. * delete contents on range
  2401. * @return {WrappedRange}
  2402. */
  2403. }, {
  2404. key: "deleteContents",
  2405. value: function deleteContents() {
  2406. if (this.isCollapsed()) {
  2407. return this;
  2408. }
  2409. var rng = this.splitText();
  2410. var nodes = rng.nodes(null, {
  2411. fullyContains: true
  2412. }); // find new cursor point
  2413. var point = dom.prevPointUntil(rng.getStartPoint(), function (point) {
  2414. return !lists.contains(nodes, point.node);
  2415. });
  2416. var emptyParents = [];
  2417. external_jQuery_default().each(nodes, function (idx, node) {
  2418. // find empty parents
  2419. var parent = node.parentNode;
  2420. if (point.node !== parent && dom.nodeLength(parent) === 1) {
  2421. emptyParents.push(parent);
  2422. }
  2423. dom.remove(node, false);
  2424. }); // remove empty parents
  2425. external_jQuery_default().each(emptyParents, function (idx, node) {
  2426. dom.remove(node, false);
  2427. });
  2428. return new WrappedRange(point.node, point.offset, point.node, point.offset).normalize();
  2429. }
  2430. /**
  2431. * makeIsOn: return isOn(pred) function
  2432. */
  2433. }, {
  2434. key: "makeIsOn",
  2435. value: function makeIsOn(pred) {
  2436. return function () {
  2437. var ancestor = dom.ancestor(this.sc, pred);
  2438. return !!ancestor && ancestor === dom.ancestor(this.ec, pred);
  2439. };
  2440. }
  2441. /**
  2442. * @param {Function} pred
  2443. * @return {Boolean}
  2444. */
  2445. }, {
  2446. key: "isLeftEdgeOf",
  2447. value: function isLeftEdgeOf(pred) {
  2448. if (!dom.isLeftEdgePoint(this.getStartPoint())) {
  2449. return false;
  2450. }
  2451. var node = dom.ancestor(this.sc, pred);
  2452. return node && dom.isLeftEdgeOf(this.sc, node);
  2453. }
  2454. /**
  2455. * returns whether range was collapsed or not
  2456. */
  2457. }, {
  2458. key: "isCollapsed",
  2459. value: function isCollapsed() {
  2460. return this.sc === this.ec && this.so === this.eo;
  2461. }
  2462. /**
  2463. * wrap inline nodes which children of body with paragraph
  2464. *
  2465. * @return {WrappedRange}
  2466. */
  2467. }, {
  2468. key: "wrapBodyInlineWithPara",
  2469. value: function wrapBodyInlineWithPara() {
  2470. if (dom.isBodyContainer(this.sc) && dom.isEmpty(this.sc)) {
  2471. this.sc.innerHTML = dom.emptyPara;
  2472. return new WrappedRange(this.sc.firstChild, 0, this.sc.firstChild, 0);
  2473. }
  2474. /**
  2475. * [workaround] firefox often create range on not visible point. so normalize here.
  2476. * - firefox: |<p>text</p>|
  2477. * - chrome: <p>|text|</p>
  2478. */
  2479. var rng = this.normalize();
  2480. if (dom.isParaInline(this.sc) || dom.isPara(this.sc)) {
  2481. return rng;
  2482. } // find inline top ancestor
  2483. var topAncestor;
  2484. if (dom.isInline(rng.sc)) {
  2485. var ancestors = dom.listAncestor(rng.sc, func.not(dom.isInline));
  2486. topAncestor = lists.last(ancestors);
  2487. if (!dom.isInline(topAncestor)) {
  2488. topAncestor = ancestors[ancestors.length - 2] || rng.sc.childNodes[rng.so];
  2489. }
  2490. } else {
  2491. topAncestor = rng.sc.childNodes[rng.so > 0 ? rng.so - 1 : 0];
  2492. }
  2493. if (topAncestor) {
  2494. // siblings not in paragraph
  2495. var inlineSiblings = dom.listPrev(topAncestor, dom.isParaInline).reverse();
  2496. inlineSiblings = inlineSiblings.concat(dom.listNext(topAncestor.nextSibling, dom.isParaInline)); // wrap with paragraph
  2497. if (inlineSiblings.length) {
  2498. var para = dom.wrap(lists.head(inlineSiblings), 'p');
  2499. dom.appendChildNodes(para, lists.tail(inlineSiblings));
  2500. }
  2501. }
  2502. return this.normalize();
  2503. }
  2504. /**
  2505. * insert node at current cursor
  2506. *
  2507. * @param {Node} node
  2508. * @return {Node}
  2509. */
  2510. }, {
  2511. key: "insertNode",
  2512. value: function insertNode(node) {
  2513. var rng = this;
  2514. if (dom.isText(node) || dom.isInline(node)) {
  2515. rng = this.wrapBodyInlineWithPara().deleteContents();
  2516. }
  2517. var info = dom.splitPoint(rng.getStartPoint(), dom.isInline(node));
  2518. if (info.rightNode) {
  2519. info.rightNode.parentNode.insertBefore(node, info.rightNode);
  2520. if (dom.isEmpty(info.rightNode) && dom.isPara(node)) {
  2521. info.rightNode.parentNode.removeChild(info.rightNode);
  2522. }
  2523. } else {
  2524. info.container.appendChild(node);
  2525. }
  2526. return node;
  2527. }
  2528. /**
  2529. * insert html at current cursor
  2530. */
  2531. }, {
  2532. key: "pasteHTML",
  2533. value: function pasteHTML(markup) {
  2534. markup = external_jQuery_default().trim(markup);
  2535. var contentsContainer = external_jQuery_default()('<div></div>').html(markup)[0];
  2536. var childNodes = lists.from(contentsContainer.childNodes); // const rng = this.wrapBodyInlineWithPara().deleteContents();
  2537. var rng = this;
  2538. var reversed = false;
  2539. if (rng.so >= 0) {
  2540. childNodes = childNodes.reverse();
  2541. reversed = true;
  2542. }
  2543. childNodes = childNodes.map(function (childNode) {
  2544. return rng.insertNode(childNode);
  2545. });
  2546. if (reversed) {
  2547. childNodes = childNodes.reverse();
  2548. }
  2549. return childNodes;
  2550. }
  2551. /**
  2552. * returns text in range
  2553. *
  2554. * @return {String}
  2555. */
  2556. }, {
  2557. key: "toString",
  2558. value: function toString() {
  2559. var nativeRng = this.nativeRange();
  2560. return env.isW3CRangeSupport ? nativeRng.toString() : nativeRng.text;
  2561. }
  2562. /**
  2563. * returns range for word before cursor
  2564. *
  2565. * @param {Boolean} [findAfter] - find after cursor, default: false
  2566. * @return {WrappedRange}
  2567. */
  2568. }, {
  2569. key: "getWordRange",
  2570. value: function getWordRange(findAfter) {
  2571. var endPoint = this.getEndPoint();
  2572. if (!dom.isCharPoint(endPoint)) {
  2573. return this;
  2574. }
  2575. var startPoint = dom.prevPointUntil(endPoint, function (point) {
  2576. return !dom.isCharPoint(point);
  2577. });
  2578. if (findAfter) {
  2579. endPoint = dom.nextPointUntil(endPoint, function (point) {
  2580. return !dom.isCharPoint(point);
  2581. });
  2582. }
  2583. return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
  2584. }
  2585. /**
  2586. * returns range for words before cursor
  2587. *
  2588. * @param {Boolean} [findAfter] - find after cursor, default: false
  2589. * @return {WrappedRange}
  2590. */
  2591. }, {
  2592. key: "getWordsRange",
  2593. value: function getWordsRange(findAfter) {
  2594. var endPoint = this.getEndPoint();
  2595. var isNotTextPoint = function isNotTextPoint(point) {
  2596. return !dom.isCharPoint(point) && !dom.isSpacePoint(point);
  2597. };
  2598. if (isNotTextPoint(endPoint)) {
  2599. return this;
  2600. }
  2601. var startPoint = dom.prevPointUntil(endPoint, isNotTextPoint);
  2602. if (findAfter) {
  2603. endPoint = dom.nextPointUntil(endPoint, isNotTextPoint);
  2604. }
  2605. return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
  2606. }
  2607. /**
  2608. * returns range for words before cursor that match with a Regex
  2609. *
  2610. * example:
  2611. * range: 'hi @Peter Pan'
  2612. * regex: '/@[a-z ]+/i'
  2613. * return range: '@Peter Pan'
  2614. *
  2615. * @param {RegExp} [regex]
  2616. * @return {WrappedRange|null}
  2617. */
  2618. }, {
  2619. key: "getWordsMatchRange",
  2620. value: function getWordsMatchRange(regex) {
  2621. var endPoint = this.getEndPoint();
  2622. var startPoint = dom.prevPointUntil(endPoint, function (point) {
  2623. if (!dom.isCharPoint(point) && !dom.isSpacePoint(point)) {
  2624. return true;
  2625. }
  2626. var rng = new WrappedRange(point.node, point.offset, endPoint.node, endPoint.offset);
  2627. var result = regex.exec(rng.toString());
  2628. return result && result.index === 0;
  2629. });
  2630. var rng = new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
  2631. var text = rng.toString();
  2632. var result = regex.exec(text);
  2633. if (result && result[0].length === text.length) {
  2634. return rng;
  2635. } else {
  2636. return null;
  2637. }
  2638. }
  2639. /**
  2640. * create offsetPath bookmark
  2641. *
  2642. * @param {Node} editable
  2643. */
  2644. }, {
  2645. key: "bookmark",
  2646. value: function bookmark(editable) {
  2647. return {
  2648. s: {
  2649. path: dom.makeOffsetPath(editable, this.sc),
  2650. offset: this.so
  2651. },
  2652. e: {
  2653. path: dom.makeOffsetPath(editable, this.ec),
  2654. offset: this.eo
  2655. }
  2656. };
  2657. }
  2658. /**
  2659. * create offsetPath bookmark base on paragraph
  2660. *
  2661. * @param {Node[]} paras
  2662. */
  2663. }, {
  2664. key: "paraBookmark",
  2665. value: function paraBookmark(paras) {
  2666. return {
  2667. s: {
  2668. path: lists.tail(dom.makeOffsetPath(lists.head(paras), this.sc)),
  2669. offset: this.so
  2670. },
  2671. e: {
  2672. path: lists.tail(dom.makeOffsetPath(lists.last(paras), this.ec)),
  2673. offset: this.eo
  2674. }
  2675. };
  2676. }
  2677. /**
  2678. * getClientRects
  2679. * @return {Rect[]}
  2680. */
  2681. }, {
  2682. key: "getClientRects",
  2683. value: function getClientRects() {
  2684. var nativeRng = this.nativeRange();
  2685. return nativeRng.getClientRects();
  2686. }
  2687. }]);
  2688. return WrappedRange;
  2689. }();
  2690. /**
  2691. * Data structure
  2692. * * BoundaryPoint: a point of dom tree
  2693. * * BoundaryPoints: two boundaryPoints corresponding to the start and the end of the Range
  2694. *
  2695. * See to http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position
  2696. */
  2697. /* harmony default export */ const range = ({
  2698. /**
  2699. * create Range Object From arguments or Browser Selection
  2700. *
  2701. * @param {Node} sc - start container
  2702. * @param {Number} so - start offset
  2703. * @param {Node} ec - end container
  2704. * @param {Number} eo - end offset
  2705. * @return {WrappedRange}
  2706. */
  2707. create: function create(sc, so, ec, eo) {
  2708. if (arguments.length === 4) {
  2709. return new WrappedRange(sc, so, ec, eo);
  2710. } else if (arguments.length === 2) {
  2711. // collapsed
  2712. ec = sc;
  2713. eo = so;
  2714. return new WrappedRange(sc, so, ec, eo);
  2715. } else {
  2716. var wrappedRange = this.createFromSelection();
  2717. if (!wrappedRange && arguments.length === 1) {
  2718. var bodyElement = arguments[0];
  2719. if (dom.isEditable(bodyElement)) {
  2720. bodyElement = bodyElement.lastChild;
  2721. }
  2722. return this.createFromBodyElement(bodyElement, dom.emptyPara === arguments[0].innerHTML);
  2723. }
  2724. return wrappedRange;
  2725. }
  2726. },
  2727. createFromBodyElement: function createFromBodyElement(bodyElement) {
  2728. var isCollapseToStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  2729. var wrappedRange = this.createFromNode(bodyElement);
  2730. return wrappedRange.collapse(isCollapseToStart);
  2731. },
  2732. createFromSelection: function createFromSelection() {
  2733. var sc, so, ec, eo;
  2734. if (env.isW3CRangeSupport) {
  2735. var selection = document.getSelection();
  2736. if (!selection || selection.rangeCount === 0) {
  2737. return null;
  2738. } else if (dom.isBody(selection.anchorNode)) {
  2739. // Firefox: returns entire body as range on initialization.
  2740. // We won't never need it.
  2741. return null;
  2742. }
  2743. var nativeRng = selection.getRangeAt(0);
  2744. sc = nativeRng.startContainer;
  2745. so = nativeRng.startOffset;
  2746. ec = nativeRng.endContainer;
  2747. eo = nativeRng.endOffset;
  2748. } else {
  2749. // IE8: TextRange
  2750. var textRange = document.selection.createRange();
  2751. var textRangeEnd = textRange.duplicate();
  2752. textRangeEnd.collapse(false);
  2753. var textRangeStart = textRange;
  2754. textRangeStart.collapse(true);
  2755. var startPoint = textRangeToPoint(textRangeStart, true);
  2756. var endPoint = textRangeToPoint(textRangeEnd, false); // same visible point case: range was collapsed.
  2757. if (dom.isText(startPoint.node) && dom.isLeftEdgePoint(startPoint) && dom.isTextNode(endPoint.node) && dom.isRightEdgePoint(endPoint) && endPoint.node.nextSibling === startPoint.node) {
  2758. startPoint = endPoint;
  2759. }
  2760. sc = startPoint.cont;
  2761. so = startPoint.offset;
  2762. ec = endPoint.cont;
  2763. eo = endPoint.offset;
  2764. }
  2765. return new WrappedRange(sc, so, ec, eo);
  2766. },
  2767. /**
  2768. * @method
  2769. *
  2770. * create WrappedRange from node
  2771. *
  2772. * @param {Node} node
  2773. * @return {WrappedRange}
  2774. */
  2775. createFromNode: function createFromNode(node) {
  2776. var sc = node;
  2777. var so = 0;
  2778. var ec = node;
  2779. var eo = dom.nodeLength(ec); // browsers can't target a picture or void node
  2780. if (dom.isVoid(sc)) {
  2781. so = dom.listPrev(sc).length - 1;
  2782. sc = sc.parentNode;
  2783. }
  2784. if (dom.isBR(ec)) {
  2785. eo = dom.listPrev(ec).length - 1;
  2786. ec = ec.parentNode;
  2787. } else if (dom.isVoid(ec)) {
  2788. eo = dom.listPrev(ec).length;
  2789. ec = ec.parentNode;
  2790. }
  2791. return this.create(sc, so, ec, eo);
  2792. },
  2793. /**
  2794. * create WrappedRange from node after position
  2795. *
  2796. * @param {Node} node
  2797. * @return {WrappedRange}
  2798. */
  2799. createFromNodeBefore: function createFromNodeBefore(node) {
  2800. return this.createFromNode(node).collapse(true);
  2801. },
  2802. /**
  2803. * create WrappedRange from node after position
  2804. *
  2805. * @param {Node} node
  2806. * @return {WrappedRange}
  2807. */
  2808. createFromNodeAfter: function createFromNodeAfter(node) {
  2809. return this.createFromNode(node).collapse();
  2810. },
  2811. /**
  2812. * @method
  2813. *
  2814. * create WrappedRange from bookmark
  2815. *
  2816. * @param {Node} editable
  2817. * @param {Object} bookmark
  2818. * @return {WrappedRange}
  2819. */
  2820. createFromBookmark: function createFromBookmark(editable, bookmark) {
  2821. var sc = dom.fromOffsetPath(editable, bookmark.s.path);
  2822. var so = bookmark.s.offset;
  2823. var ec = dom.fromOffsetPath(editable, bookmark.e.path);
  2824. var eo = bookmark.e.offset;
  2825. return new WrappedRange(sc, so, ec, eo);
  2826. },
  2827. /**
  2828. * @method
  2829. *
  2830. * create WrappedRange from paraBookmark
  2831. *
  2832. * @param {Object} bookmark
  2833. * @param {Node[]} paras
  2834. * @return {WrappedRange}
  2835. */
  2836. createFromParaBookmark: function createFromParaBookmark(bookmark, paras) {
  2837. var so = bookmark.s.offset;
  2838. var eo = bookmark.e.offset;
  2839. var sc = dom.fromOffsetPath(lists.head(paras), bookmark.s.path);
  2840. var ec = dom.fromOffsetPath(lists.last(paras), bookmark.e.path);
  2841. return new WrappedRange(sc, so, ec, eo);
  2842. }
  2843. });
  2844. ;// CONCATENATED MODULE: ./src/js/core/key.js
  2845. var KEY_MAP = {
  2846. 'BACKSPACE': 8,
  2847. 'TAB': 9,
  2848. 'ENTER': 13,
  2849. 'ESCAPE': 27,
  2850. 'SPACE': 32,
  2851. 'DELETE': 46,
  2852. // Arrow
  2853. 'LEFT': 37,
  2854. 'UP': 38,
  2855. 'RIGHT': 39,
  2856. 'DOWN': 40,
  2857. // Number: 0-9
  2858. 'NUM0': 48,
  2859. 'NUM1': 49,
  2860. 'NUM2': 50,
  2861. 'NUM3': 51,
  2862. 'NUM4': 52,
  2863. 'NUM5': 53,
  2864. 'NUM6': 54,
  2865. 'NUM7': 55,
  2866. 'NUM8': 56,
  2867. // Alphabet: a-z
  2868. 'B': 66,
  2869. 'E': 69,
  2870. 'I': 73,
  2871. 'J': 74,
  2872. 'K': 75,
  2873. 'L': 76,
  2874. 'R': 82,
  2875. 'S': 83,
  2876. 'U': 85,
  2877. 'V': 86,
  2878. 'Y': 89,
  2879. 'Z': 90,
  2880. 'SLASH': 191,
  2881. 'LEFTBRACKET': 219,
  2882. 'BACKSLASH': 220,
  2883. 'RIGHTBRACKET': 221,
  2884. // Navigation
  2885. 'HOME': 36,
  2886. 'END': 35,
  2887. 'PAGEUP': 33,
  2888. 'PAGEDOWN': 34
  2889. };
  2890. /**
  2891. * @class core.key
  2892. *
  2893. * Object for keycodes.
  2894. *
  2895. * @singleton
  2896. * @alternateClassName key
  2897. */
  2898. /* harmony default export */ const key = ({
  2899. /**
  2900. * @method isEdit
  2901. *
  2902. * @param {Number} keyCode
  2903. * @return {Boolean}
  2904. */
  2905. isEdit: function isEdit(keyCode) {
  2906. return lists.contains([KEY_MAP.BACKSPACE, KEY_MAP.TAB, KEY_MAP.ENTER, KEY_MAP.SPACE, KEY_MAP.DELETE], keyCode);
  2907. },
  2908. /**
  2909. * @method isMove
  2910. *
  2911. * @param {Number} keyCode
  2912. * @return {Boolean}
  2913. */
  2914. isMove: function isMove(keyCode) {
  2915. return lists.contains([KEY_MAP.LEFT, KEY_MAP.UP, KEY_MAP.RIGHT, KEY_MAP.DOWN], keyCode);
  2916. },
  2917. /**
  2918. * @method isNavigation
  2919. *
  2920. * @param {Number} keyCode
  2921. * @return {Boolean}
  2922. */
  2923. isNavigation: function isNavigation(keyCode) {
  2924. return lists.contains([KEY_MAP.HOME, KEY_MAP.END, KEY_MAP.PAGEUP, KEY_MAP.PAGEDOWN], keyCode);
  2925. },
  2926. /**
  2927. * @property {Object} nameFromCode
  2928. * @property {String} nameFromCode.8 "BACKSPACE"
  2929. */
  2930. nameFromCode: func.invertObject(KEY_MAP),
  2931. code: KEY_MAP
  2932. });
  2933. ;// CONCATENATED MODULE: ./src/js/core/async.js
  2934. /**
  2935. * @method readFileAsDataURL
  2936. *
  2937. * read contents of file as representing URL
  2938. *
  2939. * @param {File} file
  2940. * @return {Promise} - then: dataUrl
  2941. */
  2942. function readFileAsDataURL(file) {
  2943. return external_jQuery_default().Deferred(function (deferred) {
  2944. external_jQuery_default().extend(new FileReader(), {
  2945. onload: function onload(e) {
  2946. var dataURL = e.target.result;
  2947. deferred.resolve(dataURL);
  2948. },
  2949. onerror: function onerror(err) {
  2950. deferred.reject(err);
  2951. }
  2952. }).readAsDataURL(file);
  2953. }).promise();
  2954. }
  2955. /**
  2956. * @method createImage
  2957. *
  2958. * create `<image>` from url string
  2959. *
  2960. * @param {String} url
  2961. * @return {Promise} - then: $image
  2962. */
  2963. function createImage(url) {
  2964. return external_jQuery_default().Deferred(function (deferred) {
  2965. var $img = external_jQuery_default()('<img>');
  2966. $img.one('load', function () {
  2967. $img.off('error abort');
  2968. deferred.resolve($img);
  2969. }).one('error abort', function () {
  2970. $img.off('load').detach();
  2971. deferred.reject($img);
  2972. }).css({
  2973. display: 'none'
  2974. }).appendTo(document.body).attr('src', url);
  2975. }).promise();
  2976. }
  2977. ;// CONCATENATED MODULE: ./src/js/editing/History.js
  2978. function History_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  2979. function History_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); } }
  2980. function History_createClass(Constructor, protoProps, staticProps) { if (protoProps) History_defineProperties(Constructor.prototype, protoProps); if (staticProps) History_defineProperties(Constructor, staticProps); return Constructor; }
  2981. var History = /*#__PURE__*/function () {
  2982. function History(context) {
  2983. History_classCallCheck(this, History);
  2984. this.stack = [];
  2985. this.stackOffset = -1;
  2986. this.context = context;
  2987. this.$editable = context.layoutInfo.editable;
  2988. this.editable = this.$editable[0];
  2989. }
  2990. History_createClass(History, [{
  2991. key: "makeSnapshot",
  2992. value: function makeSnapshot() {
  2993. var rng = range.create(this.editable);
  2994. var emptyBookmark = {
  2995. s: {
  2996. path: [],
  2997. offset: 0
  2998. },
  2999. e: {
  3000. path: [],
  3001. offset: 0
  3002. }
  3003. };
  3004. return {
  3005. contents: this.$editable.html(),
  3006. bookmark: rng && rng.isOnEditable() ? rng.bookmark(this.editable) : emptyBookmark
  3007. };
  3008. }
  3009. }, {
  3010. key: "applySnapshot",
  3011. value: function applySnapshot(snapshot) {
  3012. if (snapshot.contents !== null) {
  3013. this.$editable.html(snapshot.contents);
  3014. }
  3015. if (snapshot.bookmark !== null) {
  3016. range.createFromBookmark(this.editable, snapshot.bookmark).select();
  3017. }
  3018. }
  3019. /**
  3020. * @method rewind
  3021. * Rewinds the history stack back to the first snapshot taken.
  3022. * Leaves the stack intact, so that "Redo" can still be used.
  3023. */
  3024. }, {
  3025. key: "rewind",
  3026. value: function rewind() {
  3027. // Create snap shot if not yet recorded
  3028. if (this.$editable.html() !== this.stack[this.stackOffset].contents) {
  3029. this.recordUndo();
  3030. } // Return to the first available snapshot.
  3031. this.stackOffset = 0; // Apply that snapshot.
  3032. this.applySnapshot(this.stack[this.stackOffset]);
  3033. }
  3034. /**
  3035. * @method commit
  3036. * Resets history stack, but keeps current editor's content.
  3037. */
  3038. }, {
  3039. key: "commit",
  3040. value: function commit() {
  3041. // Clear the stack.
  3042. this.stack = []; // Restore stackOffset to its original value.
  3043. this.stackOffset = -1; // Record our first snapshot (of nothing).
  3044. this.recordUndo();
  3045. }
  3046. /**
  3047. * @method reset
  3048. * Resets the history stack completely; reverting to an empty editor.
  3049. */
  3050. }, {
  3051. key: "reset",
  3052. value: function reset() {
  3053. // Clear the stack.
  3054. this.stack = []; // Restore stackOffset to its original value.
  3055. this.stackOffset = -1; // Clear the editable area.
  3056. this.$editable.html(''); // Record our first snapshot (of nothing).
  3057. this.recordUndo();
  3058. }
  3059. /**
  3060. * undo
  3061. */
  3062. }, {
  3063. key: "undo",
  3064. value: function undo() {
  3065. // Create snap shot if not yet recorded
  3066. if (this.$editable.html() !== this.stack[this.stackOffset].contents) {
  3067. this.recordUndo();
  3068. }
  3069. if (this.stackOffset > 0) {
  3070. this.stackOffset--;
  3071. this.applySnapshot(this.stack[this.stackOffset]);
  3072. }
  3073. }
  3074. /**
  3075. * redo
  3076. */
  3077. }, {
  3078. key: "redo",
  3079. value: function redo() {
  3080. if (this.stack.length - 1 > this.stackOffset) {
  3081. this.stackOffset++;
  3082. this.applySnapshot(this.stack[this.stackOffset]);
  3083. }
  3084. }
  3085. /**
  3086. * recorded undo
  3087. */
  3088. }, {
  3089. key: "recordUndo",
  3090. value: function recordUndo() {
  3091. this.stackOffset++; // Wash out stack after stackOffset
  3092. if (this.stack.length > this.stackOffset) {
  3093. this.stack = this.stack.slice(0, this.stackOffset);
  3094. } // Create new snapshot and push it to the end
  3095. this.stack.push(this.makeSnapshot()); // If the stack size reachs to the limit, then slice it
  3096. if (this.stack.length > this.context.options.historyLimit) {
  3097. this.stack.shift();
  3098. this.stackOffset -= 1;
  3099. }
  3100. }
  3101. }]);
  3102. return History;
  3103. }();
  3104. ;// CONCATENATED MODULE: ./src/js/editing/Style.js
  3105. function Style_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3106. function Style_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); } }
  3107. function Style_createClass(Constructor, protoProps, staticProps) { if (protoProps) Style_defineProperties(Constructor.prototype, protoProps); if (staticProps) Style_defineProperties(Constructor, staticProps); return Constructor; }
  3108. var Style = /*#__PURE__*/function () {
  3109. function Style() {
  3110. Style_classCallCheck(this, Style);
  3111. }
  3112. Style_createClass(Style, [{
  3113. key: "jQueryCSS",
  3114. value:
  3115. /**
  3116. * @method jQueryCSS
  3117. *
  3118. * [workaround] for old jQuery
  3119. * passing an array of style properties to .css()
  3120. * will result in an object of property-value pairs.
  3121. * (compability with version < 1.9)
  3122. *
  3123. * @private
  3124. * @param {jQuery} $obj
  3125. * @param {Array} propertyNames - An array of one or more CSS properties.
  3126. * @return {Object}
  3127. */
  3128. function jQueryCSS($obj, propertyNames) {
  3129. var result = {};
  3130. external_jQuery_default().each(propertyNames, function (idx, propertyName) {
  3131. result[propertyName] = $obj.css(propertyName);
  3132. });
  3133. return result;
  3134. }
  3135. /**
  3136. * returns style object from node
  3137. *
  3138. * @param {jQuery} $node
  3139. * @return {Object}
  3140. */
  3141. }, {
  3142. key: "fromNode",
  3143. value: function fromNode($node) {
  3144. var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];
  3145. var styleInfo = this.jQueryCSS($node, properties) || {};
  3146. var fontSize = $node[0].style.fontSize || styleInfo['font-size'];
  3147. styleInfo['font-size'] = parseInt(fontSize, 10);
  3148. styleInfo['font-size-unit'] = fontSize.match(/[a-z%]+$/);
  3149. return styleInfo;
  3150. }
  3151. /**
  3152. * paragraph level style
  3153. *
  3154. * @param {WrappedRange} rng
  3155. * @param {Object} styleInfo
  3156. */
  3157. }, {
  3158. key: "stylePara",
  3159. value: function stylePara(rng, styleInfo) {
  3160. external_jQuery_default().each(rng.nodes(dom.isPara, {
  3161. includeAncestor: true
  3162. }), function (idx, para) {
  3163. external_jQuery_default()(para).css(styleInfo);
  3164. });
  3165. }
  3166. /**
  3167. * insert and returns styleNodes on range.
  3168. *
  3169. * @param {WrappedRange} rng
  3170. * @param {Object} [options] - options for styleNodes
  3171. * @param {String} [options.nodeName] - default: `SPAN`
  3172. * @param {Boolean} [options.expandClosestSibling] - default: `false`
  3173. * @param {Boolean} [options.onlyPartialContains] - default: `false`
  3174. * @return {Node[]}
  3175. */
  3176. }, {
  3177. key: "styleNodes",
  3178. value: function styleNodes(rng, options) {
  3179. rng = rng.splitText();
  3180. var nodeName = options && options.nodeName || 'SPAN';
  3181. var expandClosestSibling = !!(options && options.expandClosestSibling);
  3182. var onlyPartialContains = !!(options && options.onlyPartialContains);
  3183. if (rng.isCollapsed()) {
  3184. return [rng.insertNode(dom.create(nodeName))];
  3185. }
  3186. var pred = dom.makePredByNodeName(nodeName);
  3187. var nodes = rng.nodes(dom.isText, {
  3188. fullyContains: true
  3189. }).map(function (text) {
  3190. return dom.singleChildAncestor(text, pred) || dom.wrap(text, nodeName);
  3191. });
  3192. if (expandClosestSibling) {
  3193. if (onlyPartialContains) {
  3194. var nodesInRange = rng.nodes(); // compose with partial contains predication
  3195. pred = func.and(pred, function (node) {
  3196. return lists.contains(nodesInRange, node);
  3197. });
  3198. }
  3199. return nodes.map(function (node) {
  3200. var siblings = dom.withClosestSiblings(node, pred);
  3201. var head = lists.head(siblings);
  3202. var tails = lists.tail(siblings);
  3203. external_jQuery_default().each(tails, function (idx, elem) {
  3204. dom.appendChildNodes(head, elem.childNodes);
  3205. dom.remove(elem);
  3206. });
  3207. return lists.head(siblings);
  3208. });
  3209. } else {
  3210. return nodes;
  3211. }
  3212. }
  3213. /**
  3214. * get current style on cursor
  3215. *
  3216. * @param {WrappedRange} rng
  3217. * @return {Object} - object contains style properties.
  3218. */
  3219. }, {
  3220. key: "current",
  3221. value: function current(rng) {
  3222. var $cont = external_jQuery_default()(!dom.isElement(rng.sc) ? rng.sc.parentNode : rng.sc);
  3223. var styleInfo = this.fromNode($cont); // document.queryCommandState for toggle state
  3224. // [workaround] prevent Firefox nsresult: "0x80004005 (NS_ERROR_FAILURE)"
  3225. try {
  3226. styleInfo = external_jQuery_default().extend(styleInfo, {
  3227. 'font-bold': document.queryCommandState('bold') ? 'bold' : 'normal',
  3228. 'font-italic': document.queryCommandState('italic') ? 'italic' : 'normal',
  3229. 'font-underline': document.queryCommandState('underline') ? 'underline' : 'normal',
  3230. 'font-subscript': document.queryCommandState('subscript') ? 'subscript' : 'normal',
  3231. 'font-superscript': document.queryCommandState('superscript') ? 'superscript' : 'normal',
  3232. 'font-strikethrough': document.queryCommandState('strikethrough') ? 'strikethrough' : 'normal',
  3233. 'font-family': document.queryCommandValue('fontname') || styleInfo['font-family']
  3234. });
  3235. } catch (e) {// eslint-disable-next-line
  3236. } // list-style-type to list-style(unordered, ordered)
  3237. if (!rng.isOnList()) {
  3238. styleInfo['list-style'] = 'none';
  3239. } else {
  3240. var orderedTypes = ['circle', 'disc', 'disc-leading-zero', 'square'];
  3241. var isUnordered = orderedTypes.indexOf(styleInfo['list-style-type']) > -1;
  3242. styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered';
  3243. }
  3244. var para = dom.ancestor(rng.sc, dom.isPara);
  3245. if (para && para.style['line-height']) {
  3246. styleInfo['line-height'] = para.style.lineHeight;
  3247. } else {
  3248. var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10);
  3249. styleInfo['line-height'] = lineHeight.toFixed(1);
  3250. }
  3251. styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);
  3252. styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable);
  3253. styleInfo.range = rng;
  3254. return styleInfo;
  3255. }
  3256. }]);
  3257. return Style;
  3258. }();
  3259. ;// CONCATENATED MODULE: ./src/js/editing/Bullet.js
  3260. function Bullet_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3261. function Bullet_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); } }
  3262. function Bullet_createClass(Constructor, protoProps, staticProps) { if (protoProps) Bullet_defineProperties(Constructor.prototype, protoProps); if (staticProps) Bullet_defineProperties(Constructor, staticProps); return Constructor; }
  3263. var Bullet = /*#__PURE__*/function () {
  3264. function Bullet() {
  3265. Bullet_classCallCheck(this, Bullet);
  3266. }
  3267. Bullet_createClass(Bullet, [{
  3268. key: "insertOrderedList",
  3269. value:
  3270. /**
  3271. * toggle ordered list
  3272. */
  3273. function insertOrderedList(editable) {
  3274. this.toggleList('OL', editable);
  3275. }
  3276. /**
  3277. * toggle unordered list
  3278. */
  3279. }, {
  3280. key: "insertUnorderedList",
  3281. value: function insertUnorderedList(editable) {
  3282. this.toggleList('UL', editable);
  3283. }
  3284. /**
  3285. * indent
  3286. */
  3287. }, {
  3288. key: "indent",
  3289. value: function indent(editable) {
  3290. var _this = this;
  3291. var rng = range.create(editable).wrapBodyInlineWithPara();
  3292. var paras = rng.nodes(dom.isPara, {
  3293. includeAncestor: true
  3294. });
  3295. var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));
  3296. external_jQuery_default().each(clustereds, function (idx, paras) {
  3297. var head = lists.head(paras);
  3298. if (dom.isLi(head)) {
  3299. var previousList = _this.findList(head.previousSibling);
  3300. if (previousList) {
  3301. paras.map(function (para) {
  3302. return previousList.appendChild(para);
  3303. });
  3304. } else {
  3305. _this.wrapList(paras, head.parentNode.nodeName);
  3306. paras.map(function (para) {
  3307. return para.parentNode;
  3308. }).map(function (para) {
  3309. return _this.appendToPrevious(para);
  3310. });
  3311. }
  3312. } else {
  3313. external_jQuery_default().each(paras, function (idx, para) {
  3314. external_jQuery_default()(para).css('marginLeft', function (idx, val) {
  3315. return (parseInt(val, 10) || 0) + 25;
  3316. });
  3317. });
  3318. }
  3319. });
  3320. rng.select();
  3321. }
  3322. /**
  3323. * outdent
  3324. */
  3325. }, {
  3326. key: "outdent",
  3327. value: function outdent(editable) {
  3328. var _this2 = this;
  3329. var rng = range.create(editable).wrapBodyInlineWithPara();
  3330. var paras = rng.nodes(dom.isPara, {
  3331. includeAncestor: true
  3332. });
  3333. var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));
  3334. external_jQuery_default().each(clustereds, function (idx, paras) {
  3335. var head = lists.head(paras);
  3336. if (dom.isLi(head)) {
  3337. _this2.releaseList([paras]);
  3338. } else {
  3339. external_jQuery_default().each(paras, function (idx, para) {
  3340. external_jQuery_default()(para).css('marginLeft', function (idx, val) {
  3341. val = parseInt(val, 10) || 0;
  3342. return val > 25 ? val - 25 : '';
  3343. });
  3344. });
  3345. }
  3346. });
  3347. rng.select();
  3348. }
  3349. /**
  3350. * toggle list
  3351. *
  3352. * @param {String} listName - OL or UL
  3353. */
  3354. }, {
  3355. key: "toggleList",
  3356. value: function toggleList(listName, editable) {
  3357. var _this3 = this;
  3358. var rng = range.create(editable).wrapBodyInlineWithPara();
  3359. var paras = rng.nodes(dom.isPara, {
  3360. includeAncestor: true
  3361. });
  3362. var bookmark = rng.paraBookmark(paras);
  3363. var clustereds = lists.clusterBy(paras, func.peq2('parentNode')); // paragraph to list
  3364. if (lists.find(paras, dom.isPurePara)) {
  3365. var wrappedParas = [];
  3366. external_jQuery_default().each(clustereds, function (idx, paras) {
  3367. wrappedParas = wrappedParas.concat(_this3.wrapList(paras, listName));
  3368. });
  3369. paras = wrappedParas; // list to paragraph or change list style
  3370. } else {
  3371. var diffLists = rng.nodes(dom.isList, {
  3372. includeAncestor: true
  3373. }).filter(function (listNode) {
  3374. return !external_jQuery_default().nodeName(listNode, listName);
  3375. });
  3376. if (diffLists.length) {
  3377. external_jQuery_default().each(diffLists, function (idx, listNode) {
  3378. dom.replace(listNode, listName);
  3379. });
  3380. } else {
  3381. paras = this.releaseList(clustereds, true);
  3382. }
  3383. }
  3384. range.createFromParaBookmark(bookmark, paras).select();
  3385. }
  3386. /**
  3387. * @param {Node[]} paras
  3388. * @param {String} listName
  3389. * @return {Node[]}
  3390. */
  3391. }, {
  3392. key: "wrapList",
  3393. value: function wrapList(paras, listName) {
  3394. var head = lists.head(paras);
  3395. var last = lists.last(paras);
  3396. var prevList = dom.isList(head.previousSibling) && head.previousSibling;
  3397. var nextList = dom.isList(last.nextSibling) && last.nextSibling;
  3398. var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last); // P to LI
  3399. paras = paras.map(function (para) {
  3400. return dom.isPurePara(para) ? dom.replace(para, 'LI') : para;
  3401. }); // append to list(<ul>, <ol>)
  3402. dom.appendChildNodes(listNode, paras);
  3403. if (nextList) {
  3404. dom.appendChildNodes(listNode, lists.from(nextList.childNodes));
  3405. dom.remove(nextList);
  3406. }
  3407. return paras;
  3408. }
  3409. /**
  3410. * @method releaseList
  3411. *
  3412. * @param {Array[]} clustereds
  3413. * @param {Boolean} isEscapseToBody
  3414. * @return {Node[]}
  3415. */
  3416. }, {
  3417. key: "releaseList",
  3418. value: function releaseList(clustereds, isEscapseToBody) {
  3419. var _this4 = this;
  3420. var releasedParas = [];
  3421. external_jQuery_default().each(clustereds, function (idx, paras) {
  3422. var head = lists.head(paras);
  3423. var last = lists.last(paras);
  3424. var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) : head.parentNode;
  3425. var parentItem = headList.parentNode;
  3426. if (headList.parentNode.nodeName === 'LI') {
  3427. paras.map(function (para) {
  3428. var newList = _this4.findNextSiblings(para);
  3429. if (parentItem.nextSibling) {
  3430. parentItem.parentNode.insertBefore(para, parentItem.nextSibling);
  3431. } else {
  3432. parentItem.parentNode.appendChild(para);
  3433. }
  3434. if (newList.length) {
  3435. _this4.wrapList(newList, headList.nodeName);
  3436. para.appendChild(newList[0].parentNode);
  3437. }
  3438. });
  3439. if (headList.children.length === 0) {
  3440. parentItem.removeChild(headList);
  3441. }
  3442. if (parentItem.childNodes.length === 0) {
  3443. parentItem.parentNode.removeChild(parentItem);
  3444. }
  3445. } else {
  3446. var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {
  3447. node: last.parentNode,
  3448. offset: dom.position(last) + 1
  3449. }, {
  3450. isSkipPaddingBlankHTML: true
  3451. }) : null;
  3452. var middleList = dom.splitTree(headList, {
  3453. node: head.parentNode,
  3454. offset: dom.position(head)
  3455. }, {
  3456. isSkipPaddingBlankHTML: true
  3457. });
  3458. paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) : lists.from(middleList.childNodes).filter(dom.isLi); // LI to P
  3459. if (isEscapseToBody || !dom.isList(headList.parentNode)) {
  3460. paras = paras.map(function (para) {
  3461. return dom.replace(para, 'P');
  3462. });
  3463. }
  3464. external_jQuery_default().each(lists.from(paras).reverse(), function (idx, para) {
  3465. dom.insertAfter(para, headList);
  3466. }); // remove empty lists
  3467. var rootLists = lists.compact([headList, middleList, lastList]);
  3468. external_jQuery_default().each(rootLists, function (idx, rootList) {
  3469. var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList));
  3470. external_jQuery_default().each(listNodes.reverse(), function (idx, listNode) {
  3471. if (!dom.nodeLength(listNode)) {
  3472. dom.remove(listNode, true);
  3473. }
  3474. });
  3475. });
  3476. }
  3477. releasedParas = releasedParas.concat(paras);
  3478. });
  3479. return releasedParas;
  3480. }
  3481. /**
  3482. * @method appendToPrevious
  3483. *
  3484. * Appends list to previous list item, if
  3485. * none exist it wraps the list in a new list item.
  3486. *
  3487. * @param {HTMLNode} ListItem
  3488. * @return {HTMLNode}
  3489. */
  3490. }, {
  3491. key: "appendToPrevious",
  3492. value: function appendToPrevious(node) {
  3493. return node.previousSibling ? dom.appendChildNodes(node.previousSibling, [node]) : this.wrapList([node], 'LI');
  3494. }
  3495. /**
  3496. * @method findList
  3497. *
  3498. * Finds an existing list in list item
  3499. *
  3500. * @param {HTMLNode} ListItem
  3501. * @return {Array[]}
  3502. */
  3503. }, {
  3504. key: "findList",
  3505. value: function findList(node) {
  3506. return node ? lists.find(node.children, function (child) {
  3507. return ['OL', 'UL'].indexOf(child.nodeName) > -1;
  3508. }) : null;
  3509. }
  3510. /**
  3511. * @method findNextSiblings
  3512. *
  3513. * Finds all list item siblings that follow it
  3514. *
  3515. * @param {HTMLNode} ListItem
  3516. * @return {HTMLNode}
  3517. */
  3518. }, {
  3519. key: "findNextSiblings",
  3520. value: function findNextSiblings(node) {
  3521. var siblings = [];
  3522. while (node.nextSibling) {
  3523. siblings.push(node.nextSibling);
  3524. node = node.nextSibling;
  3525. }
  3526. return siblings;
  3527. }
  3528. }]);
  3529. return Bullet;
  3530. }();
  3531. ;// CONCATENATED MODULE: ./src/js/editing/Typing.js
  3532. function Typing_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3533. function Typing_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); } }
  3534. function Typing_createClass(Constructor, protoProps, staticProps) { if (protoProps) Typing_defineProperties(Constructor.prototype, protoProps); if (staticProps) Typing_defineProperties(Constructor, staticProps); return Constructor; }
  3535. /**
  3536. * @class editing.Typing
  3537. *
  3538. * Typing
  3539. *
  3540. */
  3541. var Typing = /*#__PURE__*/function () {
  3542. function Typing(context) {
  3543. Typing_classCallCheck(this, Typing);
  3544. // a Bullet instance to toggle lists off
  3545. this.bullet = new Bullet();
  3546. this.options = context.options;
  3547. }
  3548. /**
  3549. * insert tab
  3550. *
  3551. * @param {WrappedRange} rng
  3552. * @param {Number} tabsize
  3553. */
  3554. Typing_createClass(Typing, [{
  3555. key: "insertTab",
  3556. value: function insertTab(rng, tabsize) {
  3557. var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR));
  3558. rng = rng.deleteContents();
  3559. rng.insertNode(tab, true);
  3560. rng = range.create(tab, tabsize);
  3561. rng.select();
  3562. }
  3563. /**
  3564. * insert paragraph
  3565. *
  3566. * @param {jQuery} $editable
  3567. * @param {WrappedRange} rng Can be used in unit tests to "mock" the range
  3568. *
  3569. * blockquoteBreakingLevel
  3570. * 0 - No break, the new paragraph remains inside the quote
  3571. * 1 - Break the first blockquote in the ancestors list
  3572. * 2 - Break all blockquotes, so that the new paragraph is not quoted (this is the default)
  3573. */
  3574. }, {
  3575. key: "insertParagraph",
  3576. value: function insertParagraph(editable, rng) {
  3577. rng = rng || range.create(editable); // deleteContents on range.
  3578. rng = rng.deleteContents(); // Wrap range if it needs to be wrapped by paragraph
  3579. rng = rng.wrapBodyInlineWithPara(); // finding paragraph
  3580. var splitRoot = dom.ancestor(rng.sc, dom.isPara);
  3581. var nextPara; // on paragraph: split paragraph
  3582. if (splitRoot) {
  3583. // if it is an empty line with li
  3584. if (dom.isLi(splitRoot) && (dom.isEmpty(splitRoot) || dom.deepestChildIsEmpty(splitRoot))) {
  3585. // toggle UL/OL and escape
  3586. this.bullet.toggleList(splitRoot.parentNode.nodeName);
  3587. return;
  3588. } else {
  3589. var blockquote = null;
  3590. if (this.options.blockquoteBreakingLevel === 1) {
  3591. blockquote = dom.ancestor(splitRoot, dom.isBlockquote);
  3592. } else if (this.options.blockquoteBreakingLevel === 2) {
  3593. blockquote = dom.lastAncestor(splitRoot, dom.isBlockquote);
  3594. }
  3595. if (blockquote) {
  3596. // We're inside a blockquote and options ask us to break it
  3597. nextPara = external_jQuery_default()(dom.emptyPara)[0]; // If the split is right before a <br>, remove it so that there's no "empty line"
  3598. // after the split in the new blockquote created
  3599. if (dom.isRightEdgePoint(rng.getStartPoint()) && dom.isBR(rng.sc.nextSibling)) {
  3600. external_jQuery_default()(rng.sc.nextSibling).remove();
  3601. }
  3602. var split = dom.splitTree(blockquote, rng.getStartPoint(), {
  3603. isDiscardEmptySplits: true
  3604. });
  3605. if (split) {
  3606. split.parentNode.insertBefore(nextPara, split);
  3607. } else {
  3608. dom.insertAfter(nextPara, blockquote); // There's no split if we were at the end of the blockquote
  3609. }
  3610. } else {
  3611. nextPara = dom.splitTree(splitRoot, rng.getStartPoint()); // not a blockquote, just insert the paragraph
  3612. var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor);
  3613. emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor));
  3614. external_jQuery_default().each(emptyAnchors, function (idx, anchor) {
  3615. dom.remove(anchor);
  3616. }); // replace empty heading, pre or custom-made styleTag with P tag
  3617. if ((dom.isHeading(nextPara) || dom.isPre(nextPara) || dom.isCustomStyleTag(nextPara)) && dom.isEmpty(nextPara)) {
  3618. nextPara = dom.replace(nextPara, 'p');
  3619. }
  3620. }
  3621. } // no paragraph: insert empty paragraph
  3622. } else {
  3623. var next = rng.sc.childNodes[rng.so];
  3624. nextPara = external_jQuery_default()(dom.emptyPara)[0];
  3625. if (next) {
  3626. rng.sc.insertBefore(nextPara, next);
  3627. } else {
  3628. rng.sc.appendChild(nextPara);
  3629. }
  3630. }
  3631. range.create(nextPara, 0).normalize().select().scrollIntoView(editable);
  3632. }
  3633. }]);
  3634. return Typing;
  3635. }();
  3636. ;// CONCATENATED MODULE: ./src/js/editing/Table.js
  3637. function Table_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3638. function Table_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); } }
  3639. function Table_createClass(Constructor, protoProps, staticProps) { if (protoProps) Table_defineProperties(Constructor.prototype, protoProps); if (staticProps) Table_defineProperties(Constructor, staticProps); return Constructor; }
  3640. /**
  3641. * @class Create a virtual table to create what actions to do in change.
  3642. * @param {object} startPoint Cell selected to apply change.
  3643. * @param {enum} where Where change will be applied Row or Col. Use enum: TableResultAction.where
  3644. * @param {enum} action Action to be applied. Use enum: TableResultAction.requestAction
  3645. * @param {object} domTable Dom element of table to make changes.
  3646. */
  3647. var TableResultAction = function TableResultAction(startPoint, where, action, domTable) {
  3648. var _startPoint = {
  3649. 'colPos': 0,
  3650. 'rowPos': 0
  3651. };
  3652. var _virtualTable = [];
  3653. var _actionCellList = []; /// ///////////////////////////////////////////
  3654. // Private functions
  3655. /// ///////////////////////////////////////////
  3656. /**
  3657. * Set the startPoint of action.
  3658. */
  3659. function setStartPoint() {
  3660. if (!startPoint || !startPoint.tagName || startPoint.tagName.toLowerCase() !== 'td' && startPoint.tagName.toLowerCase() !== 'th') {
  3661. // Impossible to identify start Cell point
  3662. return;
  3663. }
  3664. _startPoint.colPos = startPoint.cellIndex;
  3665. if (!startPoint.parentElement || !startPoint.parentElement.tagName || startPoint.parentElement.tagName.toLowerCase() !== 'tr') {
  3666. // Impossible to identify start Row point
  3667. return;
  3668. }
  3669. _startPoint.rowPos = startPoint.parentElement.rowIndex;
  3670. }
  3671. /**
  3672. * Define virtual table position info object.
  3673. *
  3674. * @param {int} rowIndex Index position in line of virtual table.
  3675. * @param {int} cellIndex Index position in column of virtual table.
  3676. * @param {object} baseRow Row affected by this position.
  3677. * @param {object} baseCell Cell affected by this position.
  3678. * @param {bool} isSpan Inform if it is an span cell/row.
  3679. */
  3680. function setVirtualTablePosition(rowIndex, cellIndex, baseRow, baseCell, isRowSpan, isColSpan, isVirtualCell) {
  3681. var objPosition = {
  3682. 'baseRow': baseRow,
  3683. 'baseCell': baseCell,
  3684. 'isRowSpan': isRowSpan,
  3685. 'isColSpan': isColSpan,
  3686. 'isVirtual': isVirtualCell
  3687. };
  3688. if (!_virtualTable[rowIndex]) {
  3689. _virtualTable[rowIndex] = [];
  3690. }
  3691. _virtualTable[rowIndex][cellIndex] = objPosition;
  3692. }
  3693. /**
  3694. * Create action cell object.
  3695. *
  3696. * @param {object} virtualTableCellObj Object of specific position on virtual table.
  3697. * @param {enum} resultAction Action to be applied in that item.
  3698. */
  3699. function getActionCell(virtualTableCellObj, resultAction, virtualRowPosition, virtualColPosition) {
  3700. return {
  3701. 'baseCell': virtualTableCellObj.baseCell,
  3702. 'action': resultAction,
  3703. 'virtualTable': {
  3704. 'rowIndex': virtualRowPosition,
  3705. 'cellIndex': virtualColPosition
  3706. }
  3707. };
  3708. }
  3709. /**
  3710. * Recover free index of row to append Cell.
  3711. *
  3712. * @param {int} rowIndex Index of row to find free space.
  3713. * @param {int} cellIndex Index of cell to find free space in table.
  3714. */
  3715. function recoverCellIndex(rowIndex, cellIndex) {
  3716. if (!_virtualTable[rowIndex]) {
  3717. return cellIndex;
  3718. }
  3719. if (!_virtualTable[rowIndex][cellIndex]) {
  3720. return cellIndex;
  3721. }
  3722. var newCellIndex = cellIndex;
  3723. while (_virtualTable[rowIndex][newCellIndex]) {
  3724. newCellIndex++;
  3725. if (!_virtualTable[rowIndex][newCellIndex]) {
  3726. return newCellIndex;
  3727. }
  3728. }
  3729. }
  3730. /**
  3731. * Recover info about row and cell and add information to virtual table.
  3732. *
  3733. * @param {object} row Row to recover information.
  3734. * @param {object} cell Cell to recover information.
  3735. */
  3736. function addCellInfoToVirtual(row, cell) {
  3737. var cellIndex = recoverCellIndex(row.rowIndex, cell.cellIndex);
  3738. var cellHasColspan = cell.colSpan > 1;
  3739. var cellHasRowspan = cell.rowSpan > 1;
  3740. var isThisSelectedCell = row.rowIndex === _startPoint.rowPos && cell.cellIndex === _startPoint.colPos;
  3741. setVirtualTablePosition(row.rowIndex, cellIndex, row, cell, cellHasRowspan, cellHasColspan, false); // Add span rows to virtual Table.
  3742. var rowspanNumber = cell.attributes.rowSpan ? parseInt(cell.attributes.rowSpan.value, 10) : 0;
  3743. if (rowspanNumber > 1) {
  3744. for (var rp = 1; rp < rowspanNumber; rp++) {
  3745. var rowspanIndex = row.rowIndex + rp;
  3746. adjustStartPoint(rowspanIndex, cellIndex, cell, isThisSelectedCell);
  3747. setVirtualTablePosition(rowspanIndex, cellIndex, row, cell, true, cellHasColspan, true);
  3748. }
  3749. } // Add span cols to virtual table.
  3750. var colspanNumber = cell.attributes.colSpan ? parseInt(cell.attributes.colSpan.value, 10) : 0;
  3751. if (colspanNumber > 1) {
  3752. for (var cp = 1; cp < colspanNumber; cp++) {
  3753. var cellspanIndex = recoverCellIndex(row.rowIndex, cellIndex + cp);
  3754. adjustStartPoint(row.rowIndex, cellspanIndex, cell, isThisSelectedCell);
  3755. setVirtualTablePosition(row.rowIndex, cellspanIndex, row, cell, cellHasRowspan, true, true);
  3756. }
  3757. }
  3758. }
  3759. /**
  3760. * Process validation and adjust of start point if needed
  3761. *
  3762. * @param {int} rowIndex
  3763. * @param {int} cellIndex
  3764. * @param {object} cell
  3765. * @param {bool} isSelectedCell
  3766. */
  3767. function adjustStartPoint(rowIndex, cellIndex, cell, isSelectedCell) {
  3768. if (rowIndex === _startPoint.rowPos && _startPoint.colPos >= cell.cellIndex && cell.cellIndex <= cellIndex && !isSelectedCell) {
  3769. _startPoint.colPos++;
  3770. }
  3771. }
  3772. /**
  3773. * Create virtual table of cells with all cells, including span cells.
  3774. */
  3775. function createVirtualTable() {
  3776. var rows = domTable.rows;
  3777. for (var rowIndex = 0; rowIndex < rows.length; rowIndex++) {
  3778. var cells = rows[rowIndex].cells;
  3779. for (var cellIndex = 0; cellIndex < cells.length; cellIndex++) {
  3780. addCellInfoToVirtual(rows[rowIndex], cells[cellIndex]);
  3781. }
  3782. }
  3783. }
  3784. /**
  3785. * Get action to be applied on the cell.
  3786. *
  3787. * @param {object} cell virtual table cell to apply action
  3788. */
  3789. function getDeleteResultActionToCell(cell) {
  3790. switch (where) {
  3791. case TableResultAction.where.Column:
  3792. if (cell.isColSpan) {
  3793. return TableResultAction.resultAction.SubtractSpanCount;
  3794. }
  3795. break;
  3796. case TableResultAction.where.Row:
  3797. if (!cell.isVirtual && cell.isRowSpan) {
  3798. return TableResultAction.resultAction.AddCell;
  3799. } else if (cell.isRowSpan) {
  3800. return TableResultAction.resultAction.SubtractSpanCount;
  3801. }
  3802. break;
  3803. }
  3804. return TableResultAction.resultAction.RemoveCell;
  3805. }
  3806. /**
  3807. * Get action to be applied on the cell.
  3808. *
  3809. * @param {object} cell virtual table cell to apply action
  3810. */
  3811. function getAddResultActionToCell(cell) {
  3812. switch (where) {
  3813. case TableResultAction.where.Column:
  3814. if (cell.isColSpan) {
  3815. return TableResultAction.resultAction.SumSpanCount;
  3816. } else if (cell.isRowSpan && cell.isVirtual) {
  3817. return TableResultAction.resultAction.Ignore;
  3818. }
  3819. break;
  3820. case TableResultAction.where.Row:
  3821. if (cell.isRowSpan) {
  3822. return TableResultAction.resultAction.SumSpanCount;
  3823. } else if (cell.isColSpan && cell.isVirtual) {
  3824. return TableResultAction.resultAction.Ignore;
  3825. }
  3826. break;
  3827. }
  3828. return TableResultAction.resultAction.AddCell;
  3829. }
  3830. function init() {
  3831. setStartPoint();
  3832. createVirtualTable();
  3833. } /// ///////////////////////////////////////////
  3834. // Public functions
  3835. /// ///////////////////////////////////////////
  3836. /**
  3837. * Recover array os what to do in table.
  3838. */
  3839. this.getActionList = function () {
  3840. var fixedRow = where === TableResultAction.where.Row ? _startPoint.rowPos : -1;
  3841. var fixedCol = where === TableResultAction.where.Column ? _startPoint.colPos : -1;
  3842. var actualPosition = 0;
  3843. var canContinue = true;
  3844. while (canContinue) {
  3845. var rowPosition = fixedRow >= 0 ? fixedRow : actualPosition;
  3846. var colPosition = fixedCol >= 0 ? fixedCol : actualPosition;
  3847. var row = _virtualTable[rowPosition];
  3848. if (!row) {
  3849. canContinue = false;
  3850. return _actionCellList;
  3851. }
  3852. var cell = row[colPosition];
  3853. if (!cell) {
  3854. canContinue = false;
  3855. return _actionCellList;
  3856. } // Define action to be applied in this cell
  3857. var resultAction = TableResultAction.resultAction.Ignore;
  3858. switch (action) {
  3859. case TableResultAction.requestAction.Add:
  3860. resultAction = getAddResultActionToCell(cell);
  3861. break;
  3862. case TableResultAction.requestAction.Delete:
  3863. resultAction = getDeleteResultActionToCell(cell);
  3864. break;
  3865. }
  3866. _actionCellList.push(getActionCell(cell, resultAction, rowPosition, colPosition));
  3867. actualPosition++;
  3868. }
  3869. return _actionCellList;
  3870. };
  3871. init();
  3872. };
  3873. /**
  3874. *
  3875. * Where action occours enum.
  3876. */
  3877. TableResultAction.where = {
  3878. 'Row': 0,
  3879. 'Column': 1
  3880. };
  3881. /**
  3882. *
  3883. * Requested action to apply enum.
  3884. */
  3885. TableResultAction.requestAction = {
  3886. 'Add': 0,
  3887. 'Delete': 1
  3888. };
  3889. /**
  3890. *
  3891. * Result action to be executed enum.
  3892. */
  3893. TableResultAction.resultAction = {
  3894. 'Ignore': 0,
  3895. 'SubtractSpanCount': 1,
  3896. 'RemoveCell': 2,
  3897. 'AddCell': 3,
  3898. 'SumSpanCount': 4
  3899. };
  3900. /**
  3901. *
  3902. * @class editing.Table
  3903. *
  3904. * Table
  3905. *
  3906. */
  3907. var Table = /*#__PURE__*/function () {
  3908. function Table() {
  3909. Table_classCallCheck(this, Table);
  3910. }
  3911. Table_createClass(Table, [{
  3912. key: "tab",
  3913. value:
  3914. /**
  3915. * handle tab key
  3916. *
  3917. * @param {WrappedRange} rng
  3918. * @param {Boolean} isShift
  3919. */
  3920. function tab(rng, isShift) {
  3921. var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
  3922. var table = dom.ancestor(cell, dom.isTable);
  3923. var cells = dom.listDescendant(table, dom.isCell);
  3924. var nextCell = lists[isShift ? 'prev' : 'next'](cells, cell);
  3925. if (nextCell) {
  3926. range.create(nextCell, 0).select();
  3927. }
  3928. }
  3929. /**
  3930. * Add a new row
  3931. *
  3932. * @param {WrappedRange} rng
  3933. * @param {String} position (top/bottom)
  3934. * @return {Node}
  3935. */
  3936. }, {
  3937. key: "addRow",
  3938. value: function addRow(rng, position) {
  3939. var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
  3940. var currentTr = external_jQuery_default()(cell).closest('tr');
  3941. var trAttributes = this.recoverAttributes(currentTr);
  3942. var html = external_jQuery_default()('<tr' + trAttributes + '></tr>');
  3943. var vTable = new TableResultAction(cell, TableResultAction.where.Row, TableResultAction.requestAction.Add, external_jQuery_default()(currentTr).closest('table')[0]);
  3944. var actions = vTable.getActionList();
  3945. for (var idCell = 0; idCell < actions.length; idCell++) {
  3946. var currentCell = actions[idCell];
  3947. var tdAttributes = this.recoverAttributes(currentCell.baseCell);
  3948. switch (currentCell.action) {
  3949. case TableResultAction.resultAction.AddCell:
  3950. html.append('<td' + tdAttributes + '>' + dom.blank + '</td>');
  3951. break;
  3952. case TableResultAction.resultAction.SumSpanCount:
  3953. {
  3954. if (position === 'top') {
  3955. var baseCellTr = currentCell.baseCell.parent;
  3956. var isTopFromRowSpan = (!baseCellTr ? 0 : currentCell.baseCell.closest('tr').rowIndex) <= currentTr[0].rowIndex;
  3957. if (isTopFromRowSpan) {
  3958. var newTd = external_jQuery_default()('<div></div>').append(external_jQuery_default()('<td' + tdAttributes + '>' + dom.blank + '</td>').removeAttr('rowspan')).html();
  3959. html.append(newTd);
  3960. break;
  3961. }
  3962. }
  3963. var rowspanNumber = parseInt(currentCell.baseCell.rowSpan, 10);
  3964. rowspanNumber++;
  3965. currentCell.baseCell.setAttribute('rowSpan', rowspanNumber);
  3966. }
  3967. break;
  3968. }
  3969. }
  3970. if (position === 'top') {
  3971. currentTr.before(html);
  3972. } else {
  3973. var cellHasRowspan = cell.rowSpan > 1;
  3974. if (cellHasRowspan) {
  3975. var lastTrIndex = currentTr[0].rowIndex + (cell.rowSpan - 2);
  3976. external_jQuery_default()(external_jQuery_default()(currentTr).parent().find('tr')[lastTrIndex]).after(external_jQuery_default()(html));
  3977. return;
  3978. }
  3979. currentTr.after(html);
  3980. }
  3981. }
  3982. /**
  3983. * Add a new col
  3984. *
  3985. * @param {WrappedRange} rng
  3986. * @param {String} position (left/right)
  3987. * @return {Node}
  3988. */
  3989. }, {
  3990. key: "addCol",
  3991. value: function addCol(rng, position) {
  3992. var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
  3993. var row = external_jQuery_default()(cell).closest('tr');
  3994. var rowsGroup = external_jQuery_default()(row).siblings();
  3995. rowsGroup.push(row);
  3996. var vTable = new TableResultAction(cell, TableResultAction.where.Column, TableResultAction.requestAction.Add, external_jQuery_default()(row).closest('table')[0]);
  3997. var actions = vTable.getActionList();
  3998. for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {
  3999. var currentCell = actions[actionIndex];
  4000. var tdAttributes = this.recoverAttributes(currentCell.baseCell);
  4001. switch (currentCell.action) {
  4002. case TableResultAction.resultAction.AddCell:
  4003. if (position === 'right') {
  4004. external_jQuery_default()(currentCell.baseCell).after('<td' + tdAttributes + '>' + dom.blank + '</td>');
  4005. } else {
  4006. external_jQuery_default()(currentCell.baseCell).before('<td' + tdAttributes + '>' + dom.blank + '</td>');
  4007. }
  4008. break;
  4009. case TableResultAction.resultAction.SumSpanCount:
  4010. if (position === 'right') {
  4011. var colspanNumber = parseInt(currentCell.baseCell.colSpan, 10);
  4012. colspanNumber++;
  4013. currentCell.baseCell.setAttribute('colSpan', colspanNumber);
  4014. } else {
  4015. external_jQuery_default()(currentCell.baseCell).before('<td' + tdAttributes + '>' + dom.blank + '</td>');
  4016. }
  4017. break;
  4018. }
  4019. }
  4020. }
  4021. /*
  4022. * Copy attributes from element.
  4023. *
  4024. * @param {object} Element to recover attributes.
  4025. * @return {string} Copied string elements.
  4026. */
  4027. }, {
  4028. key: "recoverAttributes",
  4029. value: function recoverAttributes(el) {
  4030. var resultStr = '';
  4031. if (!el) {
  4032. return resultStr;
  4033. }
  4034. var attrList = el.attributes || [];
  4035. for (var i = 0; i < attrList.length; i++) {
  4036. if (attrList[i].name.toLowerCase() === 'id') {
  4037. continue;
  4038. }
  4039. if (attrList[i].specified) {
  4040. resultStr += ' ' + attrList[i].name + '=\'' + attrList[i].value + '\'';
  4041. }
  4042. }
  4043. return resultStr;
  4044. }
  4045. /**
  4046. * Delete current row
  4047. *
  4048. * @param {WrappedRange} rng
  4049. * @return {Node}
  4050. */
  4051. }, {
  4052. key: "deleteRow",
  4053. value: function deleteRow(rng) {
  4054. var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
  4055. var row = external_jQuery_default()(cell).closest('tr');
  4056. var cellPos = row.children('td, th').index(external_jQuery_default()(cell));
  4057. var rowPos = row[0].rowIndex;
  4058. var vTable = new TableResultAction(cell, TableResultAction.where.Row, TableResultAction.requestAction.Delete, external_jQuery_default()(row).closest('table')[0]);
  4059. var actions = vTable.getActionList();
  4060. for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {
  4061. if (!actions[actionIndex]) {
  4062. continue;
  4063. }
  4064. var baseCell = actions[actionIndex].baseCell;
  4065. var virtualPosition = actions[actionIndex].virtualTable;
  4066. var hasRowspan = baseCell.rowSpan && baseCell.rowSpan > 1;
  4067. var rowspanNumber = hasRowspan ? parseInt(baseCell.rowSpan, 10) : 0;
  4068. switch (actions[actionIndex].action) {
  4069. case TableResultAction.resultAction.Ignore:
  4070. continue;
  4071. case TableResultAction.resultAction.AddCell:
  4072. {
  4073. var nextRow = row.next('tr')[0];
  4074. if (!nextRow) {
  4075. continue;
  4076. }
  4077. var cloneRow = row[0].cells[cellPos];
  4078. if (hasRowspan) {
  4079. if (rowspanNumber > 2) {
  4080. rowspanNumber--;
  4081. nextRow.insertBefore(cloneRow, nextRow.cells[cellPos]);
  4082. nextRow.cells[cellPos].setAttribute('rowSpan', rowspanNumber);
  4083. nextRow.cells[cellPos].innerHTML = '';
  4084. } else if (rowspanNumber === 2) {
  4085. nextRow.insertBefore(cloneRow, nextRow.cells[cellPos]);
  4086. nextRow.cells[cellPos].removeAttribute('rowSpan');
  4087. nextRow.cells[cellPos].innerHTML = '';
  4088. }
  4089. }
  4090. }
  4091. continue;
  4092. case TableResultAction.resultAction.SubtractSpanCount:
  4093. if (hasRowspan) {
  4094. if (rowspanNumber > 2) {
  4095. rowspanNumber--;
  4096. baseCell.setAttribute('rowSpan', rowspanNumber);
  4097. if (virtualPosition.rowIndex !== rowPos && baseCell.cellIndex === cellPos) {
  4098. baseCell.innerHTML = '';
  4099. }
  4100. } else if (rowspanNumber === 2) {
  4101. baseCell.removeAttribute('rowSpan');
  4102. if (virtualPosition.rowIndex !== rowPos && baseCell.cellIndex === cellPos) {
  4103. baseCell.innerHTML = '';
  4104. }
  4105. }
  4106. }
  4107. continue;
  4108. case TableResultAction.resultAction.RemoveCell:
  4109. // Do not need remove cell because row will be deleted.
  4110. continue;
  4111. }
  4112. }
  4113. row.remove();
  4114. }
  4115. /**
  4116. * Delete current col
  4117. *
  4118. * @param {WrappedRange} rng
  4119. * @return {Node}
  4120. */
  4121. }, {
  4122. key: "deleteCol",
  4123. value: function deleteCol(rng) {
  4124. var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
  4125. var row = external_jQuery_default()(cell).closest('tr');
  4126. var cellPos = row.children('td, th').index(external_jQuery_default()(cell));
  4127. var vTable = new TableResultAction(cell, TableResultAction.where.Column, TableResultAction.requestAction.Delete, external_jQuery_default()(row).closest('table')[0]);
  4128. var actions = vTable.getActionList();
  4129. for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {
  4130. if (!actions[actionIndex]) {
  4131. continue;
  4132. }
  4133. switch (actions[actionIndex].action) {
  4134. case TableResultAction.resultAction.Ignore:
  4135. continue;
  4136. case TableResultAction.resultAction.SubtractSpanCount:
  4137. {
  4138. var baseCell = actions[actionIndex].baseCell;
  4139. var hasColspan = baseCell.colSpan && baseCell.colSpan > 1;
  4140. if (hasColspan) {
  4141. var colspanNumber = baseCell.colSpan ? parseInt(baseCell.colSpan, 10) : 0;
  4142. if (colspanNumber > 2) {
  4143. colspanNumber--;
  4144. baseCell.setAttribute('colSpan', colspanNumber);
  4145. if (baseCell.cellIndex === cellPos) {
  4146. baseCell.innerHTML = '';
  4147. }
  4148. } else if (colspanNumber === 2) {
  4149. baseCell.removeAttribute('colSpan');
  4150. if (baseCell.cellIndex === cellPos) {
  4151. baseCell.innerHTML = '';
  4152. }
  4153. }
  4154. }
  4155. }
  4156. continue;
  4157. case TableResultAction.resultAction.RemoveCell:
  4158. dom.remove(actions[actionIndex].baseCell, true);
  4159. continue;
  4160. }
  4161. }
  4162. }
  4163. /**
  4164. * create empty table element
  4165. *
  4166. * @param {Number} rowCount
  4167. * @param {Number} colCount
  4168. * @return {Node}
  4169. */
  4170. }, {
  4171. key: "createTable",
  4172. value: function createTable(colCount, rowCount, options) {
  4173. var tds = [];
  4174. var tdHTML;
  4175. for (var idxCol = 0; idxCol < colCount; idxCol++) {
  4176. tds.push('<td>' + dom.blank + '</td>');
  4177. }
  4178. tdHTML = tds.join('');
  4179. var trs = [];
  4180. var trHTML;
  4181. for (var idxRow = 0; idxRow < rowCount; idxRow++) {
  4182. trs.push('<tr>' + tdHTML + '</tr>');
  4183. }
  4184. trHTML = trs.join('');
  4185. var $table = external_jQuery_default()('<table>' + trHTML + '</table>');
  4186. if (options && options.tableClassName) {
  4187. $table.addClass(options.tableClassName);
  4188. }
  4189. return $table[0];
  4190. }
  4191. /**
  4192. * Delete current table
  4193. *
  4194. * @param {WrappedRange} rng
  4195. * @return {Node}
  4196. */
  4197. }, {
  4198. key: "deleteTable",
  4199. value: function deleteTable(rng) {
  4200. var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
  4201. external_jQuery_default()(cell).closest('table').remove();
  4202. }
  4203. }]);
  4204. return Table;
  4205. }();
  4206. ;// CONCATENATED MODULE: ./src/js/module/Editor.js
  4207. function Editor_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4208. function Editor_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); } }
  4209. function Editor_createClass(Constructor, protoProps, staticProps) { if (protoProps) Editor_defineProperties(Constructor.prototype, protoProps); if (staticProps) Editor_defineProperties(Constructor, staticProps); return Constructor; }
  4210. var KEY_BOGUS = 'bogus';
  4211. /**
  4212. * @class Editor
  4213. */
  4214. var Editor = /*#__PURE__*/function () {
  4215. function Editor(context) {
  4216. var _this = this;
  4217. Editor_classCallCheck(this, Editor);
  4218. this.context = context;
  4219. this.$note = context.layoutInfo.note;
  4220. this.$editor = context.layoutInfo.editor;
  4221. this.$editable = context.layoutInfo.editable;
  4222. this.options = context.options;
  4223. this.lang = this.options.langInfo;
  4224. this.editable = this.$editable[0];
  4225. this.lastRange = null;
  4226. this.snapshot = null;
  4227. this.style = new Style();
  4228. this.table = new Table();
  4229. this.typing = new Typing(context);
  4230. this.bullet = new Bullet();
  4231. this.history = new History(context);
  4232. this.context.memo('help.escape', this.lang.help.escape);
  4233. this.context.memo('help.undo', this.lang.help.undo);
  4234. this.context.memo('help.redo', this.lang.help.redo);
  4235. this.context.memo('help.tab', this.lang.help.tab);
  4236. this.context.memo('help.untab', this.lang.help.untab);
  4237. this.context.memo('help.insertParagraph', this.lang.help.insertParagraph);
  4238. this.context.memo('help.insertOrderedList', this.lang.help.insertOrderedList);
  4239. this.context.memo('help.insertUnorderedList', this.lang.help.insertUnorderedList);
  4240. this.context.memo('help.indent', this.lang.help.indent);
  4241. this.context.memo('help.outdent', this.lang.help.outdent);
  4242. this.context.memo('help.formatPara', this.lang.help.formatPara);
  4243. this.context.memo('help.insertHorizontalRule', this.lang.help.insertHorizontalRule);
  4244. this.context.memo('help.fontName', this.lang.help.fontName); // native commands(with execCommand), generate function for execCommand
  4245. var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull', 'formatBlock', 'removeFormat', 'backColor'];
  4246. for (var idx = 0, len = commands.length; idx < len; idx++) {
  4247. this[commands[idx]] = function (sCmd) {
  4248. return function (value) {
  4249. _this.beforeCommand();
  4250. document.execCommand(sCmd, false, value);
  4251. _this.afterCommand(true);
  4252. };
  4253. }(commands[idx]);
  4254. this.context.memo('help.' + commands[idx], this.lang.help[commands[idx]]);
  4255. }
  4256. this.fontName = this.wrapCommand(function (value) {
  4257. return _this.fontStyling('font-family', env.validFontName(value));
  4258. });
  4259. this.fontSize = this.wrapCommand(function (value) {
  4260. var unit = _this.currentStyle()['font-size-unit'];
  4261. return _this.fontStyling('font-size', value + unit);
  4262. });
  4263. this.fontSizeUnit = this.wrapCommand(function (value) {
  4264. var size = _this.currentStyle()['font-size'];
  4265. return _this.fontStyling('font-size', size + value);
  4266. });
  4267. for (var _idx = 1; _idx <= 6; _idx++) {
  4268. this['formatH' + _idx] = function (idx) {
  4269. return function () {
  4270. _this.formatBlock('H' + idx);
  4271. };
  4272. }(_idx);
  4273. this.context.memo('help.formatH' + _idx, this.lang.help['formatH' + _idx]);
  4274. }
  4275. this.insertParagraph = this.wrapCommand(function () {
  4276. _this.typing.insertParagraph(_this.editable);
  4277. });
  4278. this.insertOrderedList = this.wrapCommand(function () {
  4279. _this.bullet.insertOrderedList(_this.editable);
  4280. });
  4281. this.insertUnorderedList = this.wrapCommand(function () {
  4282. _this.bullet.insertUnorderedList(_this.editable);
  4283. });
  4284. this.indent = this.wrapCommand(function () {
  4285. _this.bullet.indent(_this.editable);
  4286. });
  4287. this.outdent = this.wrapCommand(function () {
  4288. _this.bullet.outdent(_this.editable);
  4289. });
  4290. /**
  4291. * insertNode
  4292. * insert node
  4293. * @param {Node} node
  4294. */
  4295. this.insertNode = this.wrapCommand(function (node) {
  4296. if (_this.isLimited(external_jQuery_default()(node).text().length)) {
  4297. return;
  4298. }
  4299. var rng = _this.getLastRange();
  4300. rng.insertNode(node);
  4301. _this.setLastRange(range.createFromNodeAfter(node).select());
  4302. });
  4303. /**
  4304. * insert text
  4305. * @param {String} text
  4306. */
  4307. this.insertText = this.wrapCommand(function (text) {
  4308. if (_this.isLimited(text.length)) {
  4309. return;
  4310. }
  4311. var rng = _this.getLastRange();
  4312. var textNode = rng.insertNode(dom.createText(text));
  4313. _this.setLastRange(range.create(textNode, dom.nodeLength(textNode)).select());
  4314. });
  4315. /**
  4316. * paste HTML