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;
},

4
src/editor/model/Editor.js

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

20
src/editor/view/EditorView.js

@ -7,22 +7,23 @@ const $ = Backbone.$;
export default class EditorView extends View {
initialize() {
const { model } = this;
const { Panels, UndoManager } = model.attributes;
model.view = this;
this.conf = model.config;
this.pn = model.get('Panels');
this.cv = model.get('Canvas');
model.once('change:ready', () => {
this.pn.active();
this.pn.disableButtons();
Panels.active();
Panels.disableButtons();
UndoManager.clear();
setTimeout(() => {
model.trigger('load', model.get('Editor'));
model.set('changesCount', 0);
model.clearDirtyCount();
});
});
}
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 contEl = $(conf.el || `body ${conf.container}`);
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.height) contEl.css('height', conf.height);
$el.append(this.cv.render());
$el.append(this.pn.render());
$el.append(Canvas.render());
$el.append(Panels.render());
// Load shallow editor
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`);
contEl.addClass(`${pfx}editor-cont`).empty().append($el);
modules.forEach(md => md.postRender && md.postRender(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,
/**
* (TODO) In case the remote storage is selected, and this options is enabled, the project
* will be also stored on the local one.
* The local data are cleared on every sucessful remote save. In case the remote storage
* fails (eg. network issue), on project reload, a dialog with the possibility to recovery
* previous data will be shown.
* In case the `remote` storage is selected, and this options is enabled, the project
* will be stored on the `local` storage in case the remote one fails.
* The local data are cleared on every sucessful remote save. When the remote storage
* fails (eg. network issue) and the editor is reloaded, a dialog with the possibility to
* 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,

67
src/storage_manager/index.js

@ -54,12 +54,16 @@ import defaults from './config/config';
import LocalStorage from './model/LocalStorage';
import RemoteStorage from './model/RemoteStorage';
import { deepMerge } from 'utils/mixins';
import { isEmpty, isFunction } from 'underscore';
const eventStart = 'storage:start';
const eventAfter = 'storage:after';
const eventEnd = 'storage:end';
const eventError = 'storage:error';
const STORAGE_LOCAL = 'local';
const STORAGE_REMOTE = 'remote';
export default () => {
var c = {};
let em;
@ -73,8 +77,8 @@ export default () => {
c = deepMerge(defaults, config);
em = c.em;
if (c._disable) c.type = 0;
defaultStorages.remote = new RemoteStorage(c);
defaultStorages.local = new LocalStorage(c);
defaultStorages[STORAGE_REMOTE] = new RemoteStorage(c);
defaultStorages[STORAGE_LOCAL] = new LocalStorage(c);
c.currentStorage = c.type;
this.loadDefaultProviders().setCurrent(c.type);
return this;
@ -202,8 +206,21 @@ export default () => {
async store(data, options = {}) {
const st = this.getCurrentStorage();
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 = {}) {
const st = this.getCurrentStorage();
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) {
@ -288,9 +341,9 @@ export default () => {
return this.get(this.getCurrent());
},
getCurrentOptons() {
getCurrentOptons(type) {
const config = this.getConfig();
const current = this.getCurrent();
const current = type || this.getCurrent();
return config.options[current] || {};
},

Loading…
Cancel
Save