UNPKG

grapesjs_codeapps

Version:

Free and Open Source Web Builder Framework/SC Modification

340 lines (309 loc) 8.41 kB
/** * You can customize the initial state of the module from the editor initialization, by passing the following [Configuration Object](https://github.com/artf/grapesjs/blob/master/src/storage_manager/config/config.js) * ```js * const editor = grapesjs.init({ * storageManager: { * // options * } * }) * ``` * * Once the editor is instantiated you can use its API. Before using these methods you should get the module from the instance * * ```js * const storageManager = editor.StorageManager; * ``` * * * [getConfig](#getconfig) * * [isAutosave](#isautosave) * * [setAutosave](#setautosave) * * [getStepsBeforeSave](#getstepsbeforesave) * * [setStepsBeforeSave](#setstepsbeforesave) * * [setStepsBeforeSave](#setstepsbeforesave) * * [getStorages](#getstorages) * * [getCurrent](#getcurrent) * * [getCurrentStorage](#getcurrentstorage) * * [setCurrent](#setcurrent) * * [add](#add) * * [get](#get) * * [store](#store) * * [load](#load) * * @module StorageManager */ module.exports = () => { var c = {}, defaults = require('./config/config'), LocalStorage = require('./model/LocalStorage'), RemoteStorage = require('./model/RemoteStorage'); let em; var storages = {}; var defaultStorages = {}; const eventStart = 'storage:start'; const eventEnd = 'storage:end'; const eventError = 'storage:error'; return { /** * Name of the module * @type {String} * @private */ name: 'StorageManager', /** * Initialize module. Automatically called with a new instance of the editor * @param {Object} config Configurations * @param {string} [config.id='gjs-'] The prefix for the fields, useful to differentiate storing/loading * with multiple editors on the same page. For example, in local storage, the item of HTML will be saved like 'gjs-html' * @param {Boolean} [config.autosave=true] Indicates if autosave mode is enabled, works in conjunction with stepsBeforeSave * @param {number} [config.stepsBeforeSave=1] If autosave enabled, indicates how many steps/changes are necessary * before autosave is triggered * @param {string} [config.type='local'] Default storage type. Available: 'local' | 'remote' | ''(do not store) * @private * @example * ... * { * autosave: false, * type: 'remote', * } * ... */ init(config) { c = config || {}; em = c.em; for (var name in defaults) { if (!(name in c)) c[name] = defaults[name]; } defaultStorages.remote = new RemoteStorage(c); defaultStorages.local = new LocalStorage(c); c.currentStorage = c.type; this.loadDefaultProviders().setCurrent(c.type); return this; }, /** * Get configuration object * @return {Object} * */ getConfig() { return c; }, /** * Checks if autosave is enabled * @return {Boolean} * */ isAutosave() { return !!c.autosave; }, /** * Set autosave value * @param {Boolean} v * @return {this} * */ setAutosave(v) { c.autosave = !!v; return this; }, /** * Returns number of steps required before trigger autosave * @return {number} * */ getStepsBeforeSave() { return c.stepsBeforeSave; }, /** * Set steps required before trigger autosave * @param {number} v * @return {this} * */ setStepsBeforeSave(v) { c.stepsBeforeSave = v; return this; }, /** * Add new storage * @param {string} id Storage ID * @param {Object} storage Storage wrapper * @param {Function} storage.load Load method * @param {Function} storage.store Store method * @return {this} * @example * storageManager.add('local2', { * load: function(keys, clb, clbErr) { * var res = {}; * for (var i = 0, len = keys.length; i < len; i++){ * var v = localStorage.getItem(keys[i]); * if(v) res[keys[i]] = v; * } * clb(res); // might be called inside some async method * // In case of errors... * // clbErr('Went something wrong'); * }, * store: function(data, clb, clbErr) { * for(var key in data) * localStorage.setItem(key, data[key]); * clb(); // might be called inside some async method * } * }); * */ add(id, storage) { storages[id] = storage; return this; }, /** * Returns storage by id * @param {string} id Storage ID * @return {Object|null} * */ get(id) { return storages[id] || null; }, /** * Returns all storages * @return {Array} * */ getStorages() { return storages; }, /** * Returns current storage type * @return {string} * */ getCurrent() { return c.currentStorage; }, /** * Set current storage type * @param {string} id Storage ID * @return {this} * */ setCurrent(id) { c.currentStorage = id; return this; }, /** * Store key-value resources in the current storage * @param {Object} data Data in key-value format, eg. {item1: value1, item2: value2} * @param {Function} clb Callback function * @return {Object|null} * @example * storageManager.store({item1: value1, item2: value2}); * */ store(data, clb) { const st = this.get(this.getCurrent()); const toStore = {}; this.onStart('store', data); for (let key in data) { toStore[c.id + key] = data[key]; } return st ? st.store( toStore, res => { clb && clb(res); this.onEnd('store', res); }, err => { this.onError('store', err); } ) : null; }, /** * Load resource from the current storage by keys * @param {string|Array<string>} keys Keys to load * @param {Function} clb Callback function * @example * storageManager.load(['item1', 'item2'], res => { * // res -> {item1: value1, item2: value2} * }); * storageManager.load('item1', res => { * // res -> {item1: value1} * }); * */ load(keys, clb) { var st = this.get(this.getCurrent()); var keysF = []; var result = {}; if (typeof keys === 'string') keys = [keys]; this.onStart('load', keys); for (var i = 0, len = keys.length; i < len; i++) { keysF.push(c.id + keys[i]); } if (st) { st.load( keysF, res => { // Restore keys name var reg = new RegExp('^' + c.id + ''); for (var itemKey in res) { var itemKeyR = itemKey.replace(reg, ''); result[itemKeyR] = res[itemKey]; } clb && clb(result); this.onEnd('load', result); }, err => { this.onError('load', err); } ); } else { clb && clb(result); } }, /** * Load default storages * @return {this} * @private * */ loadDefaultProviders() { for (var id in defaultStorages) this.add(id, defaultStorages[id]); return this; }, /** * Get current storage * @return {Storage} * */ getCurrentStorage() { return this.get(this.getCurrent()); }, /** * On start callback * @private */ onStart(ctx, data) { if (em) { em.trigger(eventStart); ctx && em.trigger(`${eventStart}:${ctx}`, data); } }, /** * On end callback * @private */ onEnd(ctx, data) { if (em) { em.trigger(eventEnd); ctx && em.trigger(`${eventEnd}:${ctx}`, data); } }, /** * On error callback * @private */ onError(ctx, data) { if (em) { em.trigger(eventError, data); ctx && em.trigger(`${eventError}:${ctx}`, data); this.onEnd(ctx, data); } }, /** * Check if autoload is possible * @return {Boolean} * @private * */ canAutoload() { const storage = this.getCurrentStorage(); return storage && this.getConfig().autoload; } }; };