/*/* =========================================================== * trumbowyg.history.js v1.0 * history plugin for Trumbowyg * http://alex-d.github.com/Trumbowyg * =========================================================== * Author : Sven Dunemann [dunemann@forelabs.eu] */ (function ($) { 'use strict'; $.extend(true, $.trumbowyg, { langs: { // jshint camelcase:false de: { history: { redo: 'Wiederholen', undo: 'Rückgängig' } }, en: { history: { redo: 'Redo', undo: 'Undo' } }, da: { history: { redo: 'Annuller fortryd', undo: 'Fortryd' } }, fr: { history: { redo: 'Annuler', undo: 'Rétablir' } }, zh_tw: { history: { redo: '重做', undo: '復原' } }, pt_br: { history: { redo: 'Refazer', undo: 'Desfazer' } }, ko: { history: { redo: '다시 실행', undo: '되돌리기' } }, // jshint camelcase:true }, plugins: { history: { init: function (t) { t.o.plugins.history = $.extend(true, { _stack: [], _index: -1, _focusEl: undefined }, t.o.plugins.history || {}); var btnBuildDefRedo = { title: t.lang.history.redo, ico: 'redo', key: 'Y', fn: function () { if (t.o.plugins.history._index < t.o.plugins.history._stack.length - 1) { t.o.plugins.history._index += 1; var index = t.o.plugins.history._index; var newState = t.o.plugins.history._stack[index]; t.execCmd('html', newState); // because of some semantic optimisations we have to save the state back // to history t.o.plugins.history._stack[index] = t.$ed.html(); carretToEnd(); toggleButtonStates(); } } }; var btnBuildDefUndo = { title: t.lang.history.undo, ico: 'undo', key: 'Z', fn: function () { if (t.o.plugins.history._index > 0) { t.o.plugins.history._index -= 1; var index = t.o.plugins.history._index, newState = t.o.plugins.history._stack[index]; t.execCmd('html', newState); // because of some semantic optimisations we have to save the state back // to history t.o.plugins.history._stack[index] = t.$ed.html(); carretToEnd(); toggleButtonStates(); } } }; var pushToHistory = function () { var index = t.o.plugins.history._index, stack = t.o.plugins.history._stack, latestState = stack.slice(-1)[0] || '

', prevState = stack[index], newState = t.$ed.html(), focusEl = t.doc.getSelection().focusNode, focusElText = '', latestStateTagsList, newStateTagsList, prevFocusEl = t.o.plugins.history._focusEl; latestStateTagsList = $('
' + latestState + '
').find('*').map(function () { return this.localName; }); newStateTagsList = $('
' + newState + '
').find('*').map(function () { return this.localName; }); if (focusEl) { t.o.plugins.history._focusEl = focusEl; focusElText = focusEl.outerHTML || focusEl.textContent; } if (newState !== prevState) { // a new stack entry is defined when current insert ends on a whitespace character // or count of node elements has been changed // or focused element differs from previous one if (focusElText.slice(-1).match(/\s/) || !arraysAreIdentical(latestStateTagsList, newStateTagsList) || t.o.plugins.history._index <= 0 || focusEl !== prevFocusEl) { t.o.plugins.history._index += 1; // remove newer entries in history when something new was added // because timeline was changes with interaction t.o.plugins.history._stack = stack.slice( 0, t.o.plugins.history._index ); // now add new state to modified history t.o.plugins.history._stack.push(newState); } else { // modify last stack entry t.o.plugins.history._stack[index] = newState; } toggleButtonStates(); } }; var toggleButtonStates = function () { var index = t.o.plugins.history._index, stackSize = t.o.plugins.history._stack.length, undoState = (index > 0), redoState = (stackSize !== 0 && index !== stackSize - 1); toggleButtonState('historyUndo', undoState); toggleButtonState('historyRedo', redoState); }; var toggleButtonState = function (btn, enable) { var button = t.$box.find('.trumbowyg-' + btn + '-button'); if (enable) { button.removeClass('trumbowyg-disable'); } else if (!button.hasClass('trumbowyg-disable')) { button.addClass('trumbowyg-disable'); } }; var arraysAreIdentical = function (a, b) { if (a === b) { return true; } if (a == null || b == null) { return false; } if (a.length !== b.length) { return false; } for (var i = 0; i < a.length; i += 1) { if (a[i] !== b[i]) { return false; } } return true; }; var carretToEnd = function () { var node = t.doc.getSelection().focusNode, range = t.doc.createRange(); if (node.childNodes.length > 0) { range.setStartAfter(node.childNodes[node.childNodes.length - 1]); range.setEndAfter(node.childNodes[node.childNodes.length - 1]); t.doc.getSelection().removeAllRanges(); t.doc.getSelection().addRange(range); } }; t.$c.on('tbwinit tbwchange', pushToHistory); t.addBtnDef('historyRedo', btnBuildDefRedo); t.addBtnDef('historyUndo', btnBuildDefUndo); } } } }); })(jQuery);