mirror of https://github.com/artf/grapesjs.git
nocodeframeworkdrag-and-dropsite-buildersite-generatortemplate-builderui-builderweb-builderweb-builder-frameworkwebsite-builderno-codepage-builder
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
5.2 KiB
267 lines
5.2 KiB
/**
|
|
* This module allows to manage the stack of changes applied on canvas
|
|
*
|
|
* You can access the module in this way
|
|
* ```js
|
|
* const undoManager = editor.UndoManager;
|
|
* ```
|
|
*
|
|
*/
|
|
import UndoManager from 'backbone-undo';
|
|
|
|
module.exports = () => {
|
|
let em;
|
|
let config;
|
|
let um;
|
|
let beforeCache;
|
|
const configDef = {};
|
|
const keymaps = {};
|
|
|
|
/*
|
|
const canvas = this.get('Canvas');
|
|
|
|
if (this.um) {
|
|
return;
|
|
}
|
|
|
|
var cmp = this.get('DomComponents');
|
|
if(cmp && this.config.undoManager) {
|
|
var that = this;
|
|
this.um = new UndoManager({
|
|
register: [cmp.getComponents(), this.get('CssComposer').getAll()],
|
|
track: true
|
|
});
|
|
this.UndoManager = this.um;
|
|
this.set('UndoManager', this.um);
|
|
|
|
key('⌘+z, ctrl+z', () => {
|
|
if (canvas.isInputFocused()) {
|
|
return;
|
|
}
|
|
|
|
that.um.undo(true);
|
|
that.trigger('component:update');
|
|
});
|
|
|
|
key('⌘+shift+z, ctrl+shift+z', () => {
|
|
if (canvas.isInputFocused()) {
|
|
return;
|
|
}
|
|
that.um.redo(true);
|
|
that.trigger('component:update');
|
|
});
|
|
|
|
var beforeCache;
|
|
const customUndoType = {
|
|
on: function (model, value, opts) {
|
|
var opt = opts || {};
|
|
if(!beforeCache){
|
|
beforeCache = model.previousAttributes();
|
|
}
|
|
if (opt && opt.avoidStore) {
|
|
return;
|
|
} else {
|
|
var obj = {
|
|
object: model,
|
|
before: beforeCache,
|
|
after: model.toJSON()
|
|
};
|
|
beforeCache = null;
|
|
return obj;
|
|
}
|
|
},
|
|
undo: function (model, bf, af, opt) {
|
|
model.set(bf);
|
|
// Update also inputs inside Style Manager
|
|
that.trigger('change:selectedComponent');
|
|
},
|
|
redo: function (model, bf, af, opt) {
|
|
model.set(af);
|
|
// Update also inputs inside Style Manager
|
|
that.trigger('change:selectedComponent');
|
|
}
|
|
};
|
|
|
|
UndoManager.removeUndoType("change");
|
|
UndoManager.addUndoType("change:style", customUndoType);
|
|
UndoManager.addUndoType("change:attributes", customUndoType);
|
|
UndoManager.addUndoType("change:content", customUndoType);
|
|
UndoManager.addUndoType("change:src", customUndoType);
|
|
}
|
|
*/
|
|
|
|
return {
|
|
|
|
name: 'UndoManager',
|
|
|
|
|
|
/**
|
|
* Initialize module
|
|
* @param {Object} config Configurations
|
|
* @private
|
|
*/
|
|
init(opts = {}) {
|
|
config = { ...opts, ...configDef };
|
|
em = config.em;
|
|
this.em = em;
|
|
um = new UndoManager({ track: true, register: [] });
|
|
um.changeUndoType('change', { condition: false });
|
|
const updated = () => {
|
|
em.trigger('change:selectedComponent');
|
|
em.trigger('change:canvasOffset');
|
|
console.log('updated');
|
|
};
|
|
const customUndoType = {
|
|
on(object, value, opt = {}) {
|
|
!beforeCache && (beforeCache = object.previousAttributes());
|
|
|
|
if (opt.avoidStore) {
|
|
return;
|
|
} else {
|
|
const result = {
|
|
object,
|
|
before: beforeCache,
|
|
after: object.toJSON()
|
|
};
|
|
beforeCache = null;
|
|
return result;
|
|
}
|
|
},
|
|
|
|
undo(model, bf, af, opt) {
|
|
model.set(bf);
|
|
updated();
|
|
},
|
|
|
|
redo(model, bf, af, opt) {
|
|
model.set(af);
|
|
updated();
|
|
}
|
|
};
|
|
|
|
const events = ['style', 'attributes', 'content', 'src'];
|
|
events.forEach(ev => um.addUndoType(`change:${ev}`, customUndoType));
|
|
|
|
return this;
|
|
},
|
|
|
|
|
|
/**
|
|
* Get module configurations
|
|
* @return {Object} Configuration object
|
|
*/
|
|
getConfig() {
|
|
return config;
|
|
},
|
|
|
|
|
|
/**
|
|
* Add an entity (Model/Collection) to track changes
|
|
* @param {Model|Collection} entity Entity to track
|
|
*/
|
|
add(entity) {
|
|
um.register(entity);
|
|
},
|
|
|
|
|
|
/**
|
|
* Remove and stop tracking the entity (Model/Collection)
|
|
* @param {Model|Collection} entity Entity to remove
|
|
*/
|
|
remove(entity) {
|
|
um.unregister(entity);
|
|
},
|
|
|
|
|
|
/**
|
|
* Remove all entities
|
|
*/
|
|
removeAll() {
|
|
um.unregisterAll()
|
|
},
|
|
|
|
|
|
/**
|
|
* Start/resume tracking changes
|
|
*/
|
|
start() {
|
|
um.startTracking();
|
|
},
|
|
|
|
|
|
/**
|
|
* Stop tracking changes
|
|
*/
|
|
stop() {
|
|
um.stopTracking();
|
|
},
|
|
|
|
|
|
/**
|
|
* Undo last change
|
|
*/
|
|
undo() {
|
|
if (em.get('Canvas').isInputFocused()) return;
|
|
um.undo(1);
|
|
},
|
|
|
|
|
|
/**
|
|
* Undo all changes
|
|
*/
|
|
undoAll() {
|
|
um.undoAll();
|
|
},
|
|
|
|
|
|
/**
|
|
* Redo last change
|
|
*/
|
|
redo() {
|
|
if (em.get('Canvas').isInputFocused()) return;
|
|
um.redo(1);
|
|
},
|
|
|
|
|
|
/**
|
|
* Redo all changes
|
|
*/
|
|
redoAll() {
|
|
um.redoAll();
|
|
},
|
|
|
|
|
|
/**
|
|
* Checks if there is an available undo
|
|
* @return {Boolean}
|
|
*/
|
|
hasUndo() {
|
|
return um.isAvailable('undo');
|
|
},
|
|
|
|
|
|
/**
|
|
* Checks if there is an available redo
|
|
* @return {Boolean}
|
|
*/
|
|
hasRedo() {
|
|
return um.isAvailable('redo');
|
|
},
|
|
|
|
|
|
/**
|
|
* Get stack of changes
|
|
* @return {Array}
|
|
*/
|
|
getStack() {
|
|
return um.stack;
|
|
},
|
|
|
|
/**
|
|
* Clear the stack
|
|
*/
|
|
clear() {
|
|
um.clear();
|
|
}
|
|
};
|
|
};
|
|
|