diff --git a/src/dom_components/model/Component.js b/src/dom_components/model/Component.js index 7e5ee88b2..5b5ec0fbe 100644 --- a/src/dom_components/model/Component.js +++ b/src/dom_components/model/Component.js @@ -1252,6 +1252,22 @@ const Component = Backbone.Model.extend(Styleable).extend( return { tagName: el.tagName ? el.tagName.toLowerCase() : '' }; }, + ensureInList(model) { + const list = Component.getList(model); + const id = model.getId(); + const current = list[id]; + + if (!current) { + // Insert in list + list[id] = model; + } else if (current !== model) { + // Create new ID + const nextId = Component.getIncrementId(id, list); + model.setId(nextId); + list[nextId] = model; + } + }, + /** * Relying simply on the number of components becomes a problem when you * store and load them back, you might hit collisions with new components diff --git a/src/dom_components/model/Components.js b/src/dom_components/model/Components.js index 999889e21..a3c45f8bd 100644 --- a/src/dom_components/model/Components.js +++ b/src/dom_components/model/Components.js @@ -18,6 +18,7 @@ export default Backbone.Collection.extend({ const coll = this; const { previousModels = [] } = opts; previousModels.forEach(md => this.removeChildren(md, coll, opts)); + models.each(model => this.onAdd(model)); }, removeChildren(removed, coll, opts = {}) { @@ -186,9 +187,10 @@ export default Backbone.Collection.extend({ }, onAdd(model, c, opts = {}) { - const em = this.em; + const { domc, em } = this; const style = model.getStyle(); const avoidInline = em && em.getConfig('avoidInlineStyle'); + domc.Component.ensureInList(model); if ( !isEmpty(style) && diff --git a/src/undo_manager/index.js b/src/undo_manager/index.js index 0d3e350c1..2b8f29015 100644 --- a/src/undo_manager/index.js +++ b/src/undo_manager/index.js @@ -182,8 +182,8 @@ export default () => { * @example * um.undo(); */ - undo() { - !em.isEditing() && um.undo(1); + undo(all = true) { + !em.isEditing() && um.undo(all); return this; }, @@ -204,8 +204,8 @@ export default () => { * @example * um.redo(); */ - redo() { - !em.isEditing() && um.redo(1); + redo(all = true) { + !em.isEditing() && um.redo(all); return this; }, @@ -276,6 +276,10 @@ export default () => { return result; }, + getPointer() { + return this.getStack().pointer; + }, + /** * Clear the stack * @return {this} diff --git a/test/specs/editor/index.js b/test/specs/editor/index.js index daa0aae72..0efcfbd59 100644 --- a/test/specs/editor/index.js +++ b/test/specs/editor/index.js @@ -70,18 +70,47 @@ describe('Editor', () => { expect(keys(all).length).toBe(initComps); }); - test.only('Components are correctly tracked with UndoManager', () => { + test('Components are correctly tracked with UndoManager', () => { editor.Components.postLoad(); // Init UndoManager const all = editor.Components.allById(); const um = editor.UndoManager; const umStack = um.getStack(); const wrapper = editor.getWrapper(); expect(umStack.length).toBe(0); - wrapper.append(`
Component 1
Component 2
`); + const comp = wrapper.append(`
Component 1
`)[0]; expect(umStack.length).toBe(1); wrapper.empty(); - console.log('Post reset', umStack); expect(umStack.length).toBe(2); expect(keys(all).length).toBe(initComps); + um.undo(false); + expect(keys(all).length).toBe(1 + initComps); + }); + + test('Components are correctly tracked with UndoManager and mutiple operations', () => { + editor.Components.postLoad(); // Init UndoManager + const all = editor.Components.allById(); + const um = editor.UndoManager; + const umStack = um.getStack(); + const wrapper = editor.getWrapper(); + expect(umStack.length).toBe(0); + wrapper.append(`
+
Component 1
+
Component 2
+
`); + expect(umStack.length).toBe(1); // UM counts first children + expect(keys(all).length).toBe(3 + initComps); + wrapper + .components() + .at(0) + .components() + .at(0) + .remove(); // Remove 1 component + // UM registers 2 identical remove undoTypes as Backbone triggers remove from the + // collection and the model + expect(umStack.length).toBe(3); + expect(keys(all).length).toBe(2 + initComps); + wrapper.empty(); + expect(umStack.length).toBe(4); + expect(keys(all).length).toBe(initComps); }); });