Browse Source

Add recvoery to storage

pull/4223/head
Artur Arseniev 5 years ago
parent
commit
833a663ebe
  1. 9
      src/editor/index.js
  2. 4
      src/editor/model/Editor.js
  3. 20
      src/editor/view/EditorView.js
  4. 3
      src/i18n/locale/en.js
  5. 17
      src/storage_manager/config/config.js
  6. 67
      src/storage_manager/index.js

9
src/editor/index.js

@ -133,15 +133,6 @@ export default (config = {}, opts = {}) => {
} }
}); });
// Do post render stuff after the iframe is loaded otherwise it'll
// be empty during tests
em.once('change:ready', () => {
this.UndoManager.clear();
em.get('modules').forEach(module => {
module.postRender && module.postRender(editorView);
});
});
return this; return this;
}, },

4
src/editor/model/Editor.js

@ -754,6 +754,10 @@ export default class EditorModel extends Model {
return this.get('changesCount'); return this.get('changesCount');
} }
clearDirtyCount() {
this.set('changesCount', 0);
}
getZoomDecimal() { getZoomDecimal() {
return this.get('Canvas').getZoomDecimal(); return this.get('Canvas').getZoomDecimal();
} }

20
src/editor/view/EditorView.js

@ -7,22 +7,23 @@ const $ = Backbone.$;
export default class EditorView extends View { export default class EditorView extends View {
initialize() { initialize() {
const { model } = this; const { model } = this;
const { Panels, UndoManager } = model.attributes;
model.view = this; model.view = this;
this.conf = model.config;
this.pn = model.get('Panels');
this.cv = model.get('Canvas');
model.once('change:ready', () => { model.once('change:ready', () => {
this.pn.active(); Panels.active();
this.pn.disableButtons(); Panels.disableButtons();
UndoManager.clear();
setTimeout(() => { setTimeout(() => {
model.trigger('load', model.get('Editor')); model.trigger('load', model.get('Editor'));
model.set('changesCount', 0); model.clearDirtyCount();
}); });
}); });
} }
render() { render() {
const { $el, conf, model } = this; const { $el, model } = this;
const { Panels, Canvas, modules } = model.attributes;
const conf = model.getConfig();
const pfx = conf.stylePrefix; const pfx = conf.stylePrefix;
const contEl = $(conf.el || `body ${conf.container}`); const contEl = $(conf.el || `body ${conf.container}`);
appendStyles(conf.cssIcons, { unique: 1, prepand: 1 }); appendStyles(conf.cssIcons, { unique: 1, prepand: 1 });
@ -31,8 +32,8 @@ export default class EditorView extends View {
if (conf.width) contEl.css('width', conf.width); if (conf.width) contEl.css('width', conf.width);
if (conf.height) contEl.css('height', conf.height); if (conf.height) contEl.css('height', conf.height);
$el.append(this.cv.render()); $el.append(Canvas.render());
$el.append(this.pn.render()); $el.append(Panels.render());
// Load shallow editor // Load shallow editor
const shallow = model.get('shallow'); const shallow = model.get('shallow');
@ -42,6 +43,7 @@ export default class EditorView extends View {
$el.attr('class', `${pfx}editor ${pfx}one-bg ${pfx}two-color`); $el.attr('class', `${pfx}editor ${pfx}one-bg ${pfx}two-color`);
contEl.addClass(`${pfx}editor-cont`).empty().append($el); contEl.addClass(`${pfx}editor-cont`).empty().append($el);
modules.forEach(md => md.postRender && md.postRender(this));
return this; return this;
} }

3
src/i18n/locale/en.js

@ -160,4 +160,7 @@ export default {
}, },
}, },
}, },
storageManager: {
recover: 'Do you want to recover unsaved changes?',
},
}; };

17
src/storage_manager/config/config.js

@ -13,11 +13,18 @@ export default {
autoload: true, autoload: true,
/** /**
* (TODO) In case the remote storage is selected, and this options is enabled, the project * In case the `remote` storage is selected, and this options is enabled, the project
* will be also stored on the local one. * will be stored on the `local` storage in case the remote one fails.
* The local data are cleared on every sucessful remote save. In case the remote storage * The local data are cleared on every sucessful remote save. When the remote storage
* fails (eg. network issue), on project reload, a dialog with the possibility to recovery * fails (eg. network issue) and the editor is reloaded, a dialog with the possibility to
* previous data will be shown. * recovery previous data will be shown.
* @example
* // Enable recovery with default confirm dialog
* recovery: true,
* // Enable recovery with a custom dialog
* recovery: (accept, cancel, editor) => {
* confirm('Recover data?') ? accept() : cancel();
* },
*/ */
recovery: false, recovery: false,

67
src/storage_manager/index.js

@ -54,12 +54,16 @@ import defaults from './config/config';
import LocalStorage from './model/LocalStorage'; import LocalStorage from './model/LocalStorage';
import RemoteStorage from './model/RemoteStorage'; import RemoteStorage from './model/RemoteStorage';
import { deepMerge } from 'utils/mixins'; import { deepMerge } from 'utils/mixins';
import { isEmpty, isFunction } from 'underscore';
const eventStart = 'storage:start'; const eventStart = 'storage:start';
const eventAfter = 'storage:after'; const eventAfter = 'storage:after';
const eventEnd = 'storage:end'; const eventEnd = 'storage:end';
const eventError = 'storage:error'; const eventError = 'storage:error';
const STORAGE_LOCAL = 'local';
const STORAGE_REMOTE = 'remote';
export default () => { export default () => {
var c = {}; var c = {};
let em; let em;
@ -73,8 +77,8 @@ export default () => {
c = deepMerge(defaults, config); c = deepMerge(defaults, config);
em = c.em; em = c.em;
if (c._disable) c.type = 0; if (c._disable) c.type = 0;
defaultStorages.remote = new RemoteStorage(c); defaultStorages[STORAGE_REMOTE] = new RemoteStorage(c);
defaultStorages.local = new LocalStorage(c); defaultStorages[STORAGE_LOCAL] = new LocalStorage(c);
c.currentStorage = c.type; c.currentStorage = c.type;
this.loadDefaultProviders().setCurrent(c.type); this.loadDefaultProviders().setCurrent(c.type);
return this; return this;
@ -202,8 +206,21 @@ export default () => {
async store(data, options = {}) { async store(data, options = {}) {
const st = this.getCurrentStorage(); const st = this.getCurrentStorage();
const opts = { ...this.getCurrentOptons(), ...options }; const opts = { ...this.getCurrentOptons(), ...options };
const recovery = this.getRecoveryStorage();
const recoveryOpts = this.getCurrentOptons(STORAGE_LOCAL);
try {
await this.__exec(st, opts, data);
recovery && (await this.__exec(recovery, recoveryOpts, {}));
} catch (error) {
if (recovery) {
await this.__exec(recovery, recoveryOpts, data);
} else {
throw error;
}
}
return await this.__exec(st, opts, data); return data;
}, },
/** /**
@ -217,9 +234,45 @@ export default () => {
async load(options = {}) { async load(options = {}) {
const st = this.getCurrentStorage(); const st = this.getCurrentStorage();
const opts = { ...this.getCurrentOptons(), ...options }; const opts = { ...this.getCurrentOptons(), ...options };
const result = await this.__exec(st, opts); const recoveryStorage = this.getRecoveryStorage();
let result;
return result; if (recoveryStorage) {
const recoveryData = await this.__exec(recoveryStorage, this.getCurrentOptons(STORAGE_LOCAL));
if (!isEmpty(recoveryData)) {
try {
await this.__askRecovery();
result = recoveryData;
} catch (error) {}
}
}
if (!result) {
result = await this.__exec(st, opts);
}
return result || {};
},
__askRecovery() {
const recovery = this.getRecovery();
return new Promise((res, rej) => {
if (isFunction(recovery)) {
recovery(res, rej, em?.getEditor());
} else {
confirm(em?.t('storageManager.recover')) ? res() : rej();
}
});
},
getRecovery() {
return this.getConfig().recovery;
},
getRecoveryStorage() {
const recovery = this.getRecovery();
return recovery && this.getCurrent() === STORAGE_REMOTE && this.get(STORAGE_LOCAL);
}, },
async __exec(storage, opts, data) { async __exec(storage, opts, data) {
@ -288,9 +341,9 @@ export default () => {
return this.get(this.getCurrent()); return this.get(this.getCurrent());
}, },
getCurrentOptons() { getCurrentOptons(type) {
const config = this.getConfig(); const config = this.getConfig();
const current = this.getCurrent(); const current = type || this.getCurrent();
return config.options[current] || {}; return config.options[current] || {};
}, },

Loading…
Cancel
Save