openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

trumbowyg.history.js (8329B)


      1 /*/* ===========================================================
      2  * trumbowyg.history.js v1.0
      3  * history plugin for Trumbowyg
      4  * http://alex-d.github.com/Trumbowyg
      5  * ===========================================================
      6  * Author : Sven Dunemann [dunemann@forelabs.eu]
      7  */
      8 
      9 (function ($) {
     10     'use strict';
     11     $.extend(true, $.trumbowyg, {
     12         langs: {
     13             de: {
     14                 history: {
     15                     redo: 'Wiederholen',
     16                     undo: 'Rückgängig'
     17                 }
     18             },
     19             en: {
     20                 history: {
     21                     redo: 'Redo',
     22                     undo: 'Undo'
     23                 }
     24             },
     25             fr: {
     26                 history: {
     27                     redo: 'Annuler',
     28                     undo: 'Rétablir'
     29                 }
     30             }
     31         },
     32         plugins: {
     33             history: {
     34                 init: function (t) {
     35                     t.o.plugins.history = $.extend(true, {
     36                         _stack: [],
     37                         _index: -1,
     38                         _focusEl: undefined
     39                     }, t.o.plugins.history || {});
     40 
     41                     var btnBuildDefRedo = {
     42                         title: t.lang.history.redo,
     43                         ico: 'redo',
     44                         key: 'Y',
     45                         fn: function () {
     46                             if (t.o.plugins.history._index < t.o.plugins.history._stack.length - 1) {
     47                                 t.o.plugins.history._index += 1;
     48                                 var index = t.o.plugins.history._index;
     49                                 var newState = t.o.plugins.history._stack[index];
     50 
     51                                 t.execCmd('html', newState);
     52                                 // because of some semantic optimisations we have to save the state back
     53                                 // to history
     54                                 t.o.plugins.history._stack[index] = t.$ed.html();
     55 
     56                                 carretToEnd();
     57                                 toggleButtonStates();
     58                             }
     59                         }
     60                     };
     61 
     62                     var btnBuildDefUndo = {
     63                         title: t.lang.history.undo,
     64                         ico: 'undo',
     65                         key: 'Z',
     66                         fn: function () {
     67                             if (t.o.plugins.history._index > 0) {
     68                                 t.o.plugins.history._index -= 1;
     69                                 var index = t.o.plugins.history._index,
     70                                     newState = t.o.plugins.history._stack[index];
     71 
     72                                 t.execCmd('html', newState);
     73                                 // because of some semantic optimisations we have to save the state back
     74                                 // to history
     75                                 t.o.plugins.history._stack[index] = t.$ed.html();
     76 
     77                                 carretToEnd();
     78                                 toggleButtonStates();
     79                             }
     80                         }
     81                     };
     82 
     83                     var pushToHistory = function () {
     84                         var index = t.o.plugins.history._index,
     85                             stack = t.o.plugins.history._stack,
     86                             latestState = stack.slice(-1)[0] || '<p></p>',
     87                             prevState = stack[index],
     88                             newState = t.$ed.html(),
     89                             focusEl = t.doc.getSelection().focusNode,
     90                             focusElText = '',
     91                             latestStateTagsList,
     92                             newStateTagsList,
     93                             prevFocusEl = t.o.plugins.history._focusEl;
     94 
     95                         latestStateTagsList = $('<div>' + latestState + '</div>').find('*').map(function () {
     96                             return this.localName;
     97                         });
     98                         newStateTagsList = $('<div>' + newState + '</div>').find('*').map(function () {
     99                             return this.localName;
    100                         });
    101                         if (focusEl) {
    102                             t.o.plugins.history._focusEl = focusEl;
    103                             focusElText = focusEl.outerHTML || focusEl.textContent;
    104                         }
    105 
    106                         if (newState !== prevState) {
    107                             // a new stack entry is defined when current insert ends on a whitespace character
    108                             // or count of node elements has been changed
    109                             // or focused element differs from previous one
    110                             if (focusElText.slice(-1).match(/\s/) ||
    111                                 !arraysAreIdentical(latestStateTagsList, newStateTagsList) ||
    112                                 t.o.plugins.history._index <= 0 || focusEl !== prevFocusEl)
    113                             {
    114                                 t.o.plugins.history._index += 1;
    115                                 // remove newer entries in history when something new was added
    116                                 // because timeline was changes with interaction
    117                                 t.o.plugins.history._stack = stack.slice(
    118                                     0, t.o.plugins.history._index
    119                                 );
    120                                 // now add new state to modifed history
    121                                 t.o.plugins.history._stack.push(newState);
    122                             } else {
    123                                 // modify last stack entry
    124                                 t.o.plugins.history._stack[index] = newState;
    125                             }
    126 
    127                             toggleButtonStates();
    128                         }
    129                     };
    130 
    131                     var toggleButtonStates = function () {
    132                         var index = t.o.plugins.history._index,
    133                             stackSize = t.o.plugins.history._stack.length,
    134                             undoState = (index > 0),
    135                             redoState = (stackSize !== 0 && index !== stackSize - 1);
    136 
    137                         toggleButtonState('historyUndo', undoState);
    138                         toggleButtonState('historyRedo', redoState);
    139                     };
    140 
    141                     var toggleButtonState = function (btn, enable) {
    142                         var button = t.$box.find('.trumbowyg-' + btn + '-button');
    143 
    144                         if (enable) {
    145                             button.removeClass('trumbowyg-disable');
    146                         } else if (!button.hasClass('trumbowyg-disable')) {
    147                             button.addClass('trumbowyg-disable');
    148                         }
    149                     };
    150 
    151                     var arraysAreIdentical = function (a, b) {
    152                         if (a === b) {
    153                             return true;
    154                         }
    155                         if (a == null || b == null) {
    156                             return false;
    157                         }
    158                         if (a.length !== b.length) {
    159                             return false;
    160                         }
    161 
    162                         for (var i = 0; i < a.length; i += 1) {
    163                             if (a[i] !== b[i]) {
    164                                 return false;
    165                             }
    166                         }
    167                         return true;
    168                     };
    169 
    170                     var carretToEnd = function () {
    171                         var node = t.doc.getSelection().focusNode,
    172                             range = t.doc.createRange();
    173 
    174                         if (node.childNodes.length > 0) {
    175                             range.setStartAfter(node.childNodes[node.childNodes.length - 1]);
    176                             range.setEndAfter(node.childNodes[node.childNodes.length - 1]);
    177                             t.doc.getSelection().removeAllRanges();
    178                             t.doc.getSelection().addRange(range);
    179                         }
    180                     };
    181 
    182                     t.$c.on('tbwinit tbwchange', pushToHistory);
    183 
    184                     t.addBtnDef('historyRedo', btnBuildDefRedo);
    185                     t.addBtnDef('historyUndo', btnBuildDefUndo);
    186                 }
    187             }
    188         }
    189     });
    190 })(jQuery);