/** * Storage plugin * * Saves editor data to browser local storage. * And uploads data from local storage if there is newer version */ var localHistoryPlugin = function () { var editor = codex.editor, CURRENT_ARTICLE_HASH = null, CURRENT_STORAGE_KEY = null, STORAGE_KEY = 'codex.editor.savedData.', STORAGE_KEYS = 'codex.editor.savedKeys', STORAGE_TIME = null, interval = null, config_ = { savingInterval: 5000, // ms retainDays: 4 // days }; /** * Checks support for localStorage and sessionStorage * @return {bool} */ function storageSupported_ () { return typeof(Storage) !== "undefined"; } /** * Formats date object * @param {number} timestamp */ function formatDate_ ( timestamp ) { var date = new Date(timestamp), hours = date.getHours(), mins = date.getMinutes(), secs = date.getSeconds(), now = new Date(); hours = hours < 10 ? '0' + hours : hours; mins = mins < 10 ? '0' + mins : mins; secs = secs < 10 ? '0' + secs : secs; var localeMonth = function ( month ) { if ( isNaN(month) ) return false; var lang = navigator.language == 'ru' ? 0 : 1, map = { ru : ['Янв','Фев','Мар','Апр','Мая','Июн','Июл','Авг','Сен','Окт','Ноя','Дек'], en : ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] }; return lang ? map.en[month] : map.ru[month]; }; return date.getDate() + ' ' + localeMonth(date.getMonth()) + ' ' + date.getFullYear() + ' ' + hours + ':' + mins + ':' + secs; } /** * Calls on editor initialize * @param {object} config - settings passed form user in codex.editor.start * @param {Number} config.retainDays - how many days should retain local versions * @param {Number} config.savingInterval - interval for saving */ var prepare = function (config) { if (!storageSupported_()) { editor.core.log('LocalStorage does not supported by your browser'); return; } CURRENT_ARTICLE_HASH = editor.currentHash; CURRENT_STORAGE_KEY = STORAGE_KEY + CURRENT_ARTICLE_HASH; if ( config.savingInterval ) config_.savingInterval = config.savingInterval; if ( config.retainDays ) config_.retainDays = config.retainDays; STORAGE_TIME = config_.retainDays * 24 * 60 * 60 * 1000; clearKeys(); var localData = get(), message, timeStyle = 'margin-top: 0.6em; color: #6e758a;'; if (localData && editor.state.blocks.savingDate < localData.savingDate) { message = 'В вашем браузере сохранена более актуальная версия материала, чем на сервере' + '
Текущая версия: ' + formatDate_(editor.state.blocks.savingDate) + '
' + '
Сохраненная версия: ' + formatDate_(localData.savingDate) + '
'; editor.notifications.notification({ type : 'confirm', message : message, okMsg : 'Переключиться', cancelMsg : 'Отмена', confirm : function () { editor.state.blocks = localData; editor.renderer.rerender(true); init(config_.savingInterval); }, cancel : function () { init(config_.savingInterval); } }); } else { init(config_.savingInterval); } return Promise.resolve(); }; var init = function (savingInterval) { interval = window.setInterval(save, savingInterval); }; /** * Saves current editor's data to localStorage with unique article key * Also saves key and expire date */ var save = function () { editor.saver.saveBlocks(); /* Using setTimeout, cause we don't know when blocks are saved */ window.setTimeout(function () { var savedBlocks = editor.state.jsonOutput, savingDate = editor.state.savingDate, data = { items: savedBlocks, savingDate : savingDate }; localStorage[CURRENT_STORAGE_KEY] = JSON.stringify(data); saveKey(savingDate); }, 500); }; /** * Returns last saved data of current article */ var get = function () { var savedData = window.localStorage[CURRENT_STORAGE_KEY], data; if (!savedData) return; try { data = JSON.parse(savedData); } catch (error) { editor.core.log('Invalid data format'); return; } return data; }; var stop = function () { window.clearInterval(interval); }; /** * Returns object of articles hash and expire date {articleHash: expireDate} */ var getKeys = function () { var savedKeys = localStorage[STORAGE_KEYS], keys = {}; if (!savedKeys) { return keys; } try { keys = JSON.parse(savedKeys); } catch (error) { editor.core.log('Invalid data format'); } return keys; }; /** * Saves current article's hash with article's expire date * @param savingDate */ var saveKey = function (savingDate) { var keys = getKeys(); keys[CURRENT_ARTICLE_HASH] = savingDate + STORAGE_TIME; localStorage[STORAGE_KEYS] = JSON.stringify(keys); }; /** * Remove articles which storage time has expired */ var clearKeys = function () { var keys = getKeys(); for (var key in keys) { if (keys[key] > +new Date()) { continue; } localStorage.removeItem(STORAGE_KEY+key); delete keys[key]; } localStorage[STORAGE_KEYS] = JSON.stringify(keys); }; var destroy = function () { stop(); localHistoryPlugin = null; }; return { prepare: prepare, init : init, save : save, get : get, stop : stop, destroy: destroy, config : config_ }; }();