@@ -2,6 +2,7 @@ import AbstractComponent from '../components/AbstractComponent';
22import describeComponentList from '../components/util/describeComponentList' ;
33import Editor from '../Editor' ;
44import { EditorLocalization } from '../localization' ;
5+ import { assertIsStringArray } from '../util/assertions' ;
56import Erase from './Erase' ;
67import SerializableCommand from './SerializableCommand' ;
78
@@ -32,10 +33,23 @@ export default class Duplicate extends SerializableCommand {
3233 private duplicates : AbstractComponent [ ] ;
3334 private reverse : Erase ;
3435
35- public constructor ( private toDuplicate : AbstractComponent [ ] ) {
36+ public constructor (
37+ private toDuplicate : AbstractComponent [ ] ,
38+
39+ // @internal -- IDs given to the duplicate elements
40+ idsForDuplicates ?: string [ ] ,
41+ ) {
3642 super ( 'duplicate' ) ;
3743
38- this . duplicates = toDuplicate . map ( ( elem ) => elem . clone ( ) ) ;
44+ this . duplicates = toDuplicate . map ( ( elem , idx ) => {
45+ // For collaborative editing, it's important for the clones to have
46+ // the same IDs as the originals
47+ if ( idsForDuplicates && idsForDuplicates [ idx ] ) {
48+ return elem . cloneWithId ( idsForDuplicates [ idx ] ) ;
49+ } else {
50+ return elem . clone ( ) ;
51+ }
52+ } ) ;
3953 this . reverse = new Erase ( this . duplicates ) ;
4054 }
4155
@@ -63,13 +77,42 @@ export default class Duplicate extends SerializableCommand {
6377 }
6478
6579 protected serializeToJSON ( ) {
66- return this . toDuplicate . map ( ( elem ) => elem . getId ( ) ) ;
80+ return {
81+ originalIds : this . toDuplicate . map ( ( elem ) => elem . getId ( ) ) ,
82+ cloneIds : this . duplicates . map ( ( elem ) => elem . getId ( ) ) ,
83+ } ;
6784 }
6885
6986 static {
7087 SerializableCommand . register ( 'duplicate' , ( json : any , editor : Editor ) => {
71- const elems = json . map ( ( id : string ) => editor . image . lookupElement ( id ) ) ;
72- return new Duplicate ( elems ) ;
88+ let originalIds ;
89+ let cloneIds ;
90+ // Compatibility with older editors
91+ if ( Array . isArray ( json ) ) {
92+ originalIds = json ;
93+ cloneIds = [ ] ;
94+ } else {
95+ originalIds = json . originalIds ;
96+ cloneIds = json . cloneIds ;
97+ }
98+ assertIsStringArray ( originalIds ) ;
99+ assertIsStringArray ( cloneIds ) ;
100+
101+ // Resolve to elements -- only keep the elements that can be found in the image.
102+ const resolvedElements = [ ] ;
103+ const filteredCloneIds = [ ] ;
104+ for ( let i = 0 ; i < originalIds . length ; i ++ ) {
105+ const originalId = originalIds [ i ] ;
106+ const foundElement = editor . image . lookupElement ( originalId ) ;
107+ if ( ! foundElement ) {
108+ console . warn ( 'Duplicate command: Could not find element with ID' , originalId ) ;
109+ } else {
110+ filteredCloneIds . push ( cloneIds [ i ] ) ;
111+ resolvedElements . push ( foundElement ) ;
112+ }
113+ }
114+
115+ return new Duplicate ( resolvedElements , filteredCloneIds ) ;
73116 } ) ;
74117 }
75118}
0 commit comments