| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- /*/* ===========================================================
- * 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
- en: {
- history: {
- redo: 'Redo',
- undo: 'Undo'
- }
- },
- da: {
- history: {
- redo: 'Annuller fortryd',
- undo: 'Fortryd'
- }
- },
- de: {
- history: {
- redo: 'Wiederholen',
- undo: 'Rückgängig'
- }
- },
- fr: {
- history: {
- redo: 'Annuler',
- undo: 'Rétablir'
- }
- },
- hu: {
- history: {
- redo: 'Visszállít',
- undo: 'Visszavon'
- }
- },
- ko: {
- history: {
- redo: '다시 실행',
- undo: '되돌리기'
- }
- },
- pt_br: {
- history: {
- redo: 'Refazer',
- undo: 'Desfazer'
- }
- },
- zh_tw: {
- 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] || '<p></p>',
- prevState = stack[index],
- newState = t.$ed.html(),
- focusEl = t.doc.getSelection().focusNode,
- focusElText = '',
- latestStateTagsList,
- newStateTagsList,
- prevFocusEl = t.o.plugins.history._focusEl;
- latestStateTagsList = $('<div>' + latestState + '</div>').find('*').map(function () {
- return this.localName;
- });
- newStateTagsList = $('<div>' + newState + '</div>').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);
|