UNPKG

suneditor

Version:

Vanilla JavaScript WYSIWYG web editor (2.x legacy version, actively maintained)

219 lines (191 loc) 7.09 kB
/* * wysiwyg web editor * * suneditor.js * Copyright 2019 JiHong Lee. * MIT license. */ 'use strict'; export default function (core, change) { const _w = core._w; const util = core.util; const delayTime = core.options.historyStackDelayTime; let editor = core.context.element; let undo = core.context.tool.undo; let redo = core.context.tool.redo; let pushDelay = null; let stackIndex = 0; let stack = []; function setContentsFromStack () { const item = stack[stackIndex]; editor.wysiwyg.innerHTML = item.contents; core.setRange(util.getNodeFromPath(item.s.path, editor.wysiwyg), item.s.offset, util.getNodeFromPath(item.e.path, editor.wysiwyg), item.e.offset); core.focus(); if (stack.length <= 1) { if (undo) undo.setAttribute('disabled', true); if (redo) redo.setAttribute('disabled', true); } else { if (stackIndex === 0) { if (undo) undo.setAttribute('disabled', true); if (redo) redo.removeAttribute('disabled'); } else if (stackIndex === stack.length - 1) { if (undo) undo.removeAttribute('disabled'); if (redo) redo.setAttribute('disabled', true); } else { if (undo) undo.removeAttribute('disabled'); if (redo) redo.removeAttribute('disabled'); } } core.controllersOff(); core._checkComponents(); core._setCharCount(); core._resourcesStateChange(); // onChange change(); } function pushStack () { core._checkComponents(); const current = editor.wysiwyg.innerHTML; if (!current || (!!stack[stackIndex] && current === stack[stackIndex].contents)) return; stackIndex++; const range = core._variable._range; if (stack.length > stackIndex) { stack = stack.slice(0, stackIndex); if (redo) redo.setAttribute('disabled', true); } if (!range) { stack[stackIndex] = { contents: current, s: { path: [0, 0], offset: [0, 0] }, e: { path: 0, offset: 0 } }; } else { stack[stackIndex] = { contents: current, s: { path: util.getNodePath(range.startContainer, null, null), offset: range.startOffset }, e: { path: util.getNodePath(range.endContainer, null, null), offset: range.endOffset } }; } if (stackIndex === 1 && undo) undo.removeAttribute('disabled'); core._setCharCount(); // onChange change(); } return { /** * @description History stack */ stack: stack, /** * @description Saving the current status to the history object stack * If "delay" is true, it will be saved after (options.historyStackDelayTime || 400) miliseconds * If the function is called again with the "delay" argument true before it is saved, the delay time is renewal * You can specify the delay time by sending a number. * @param {Boolean|Number} delay If true, Add stack without delay time. */ push: function (delay) { _w.setTimeout(core._resourcesStateChange.bind(core)); const time = typeof delay === 'number' ? (delay > 0 ? delay : 0) : (!delay ? 0 : delayTime); if (!time || pushDelay) { _w.clearTimeout(pushDelay); if (!time) { pushStack(); return; } } pushDelay = _w.setTimeout(function () { _w.clearTimeout(pushDelay); pushDelay = null; pushStack(); }, time); }, /** * @description Undo function */ undo: function () { if (stackIndex > 0) { stackIndex--; setContentsFromStack(); } }, /** * @description Redo function */ redo: function () { if (stack.length - 1 > stackIndex) { stackIndex++; setContentsFromStack(); } }, /** * @description Go to the history stack for that index. * If "index" is -1, go to the last stack */ go: function (index) { stackIndex = index < 0 ? (stack.length - 1) : index; setContentsFromStack(); }, /** * @description Get the current history stack index. * @returns {Number} Current Stack index */ getCurrentIndex: function () { return stackIndex; }, /** * @description Reset the history object */ reset: function (ignoreChangeEvent) { if (undo) undo.setAttribute('disabled', true); if (redo) redo.setAttribute('disabled', true); core._variable.isChanged = false; if (core.context.tool.save) core.context.tool.save.setAttribute('disabled', true); stack.splice(0); stackIndex = 0; // pushStack stack[stackIndex] = { contents: core.getContents(true), s: { path: [0, 0], offset: 0 }, e: { path: [0, 0], offset: 0 } }; if (!ignoreChangeEvent) change(); }, /** * @description Reset the disabled state of the buttons to fit the current stack. * @private */ _resetCachingButton: function () { editor = core.context.element; undo = core.context.tool.undo; redo = core.context.tool.redo; if (stackIndex === 0) { if (undo) undo.setAttribute('disabled', true); if (redo && stackIndex === stack.length - 1) redo.setAttribute('disabled', true); core._variable.isChanged = false; if (core.context.tool.save) core.context.tool.save.setAttribute('disabled', true); } else if (stackIndex === stack.length - 1) { if (redo) redo.setAttribute('disabled', true); } }, /** * @description Remove all stacks and remove the timeout function. * @private */ _destroy: function () { if (pushDelay) _w.clearTimeout(pushDelay); stack = null; } }; }