Browse Source

Added support for nestes symbols

pull/3281/head
Artur Arseniev 6 years ago
parent
commit
f55b416cc8
  1. 59
      src/dom_components/model/Component.js
  2. 52
      test/specs/dom_components/model/Symbols.js

59
src/dom_components/model/Component.js

@ -622,9 +622,7 @@ const Component = Backbone.Model.extend(Styleable).extend(
__isSymbolTop() {
const parent = this.parent();
return (
parent &&
((this.__isSymbol() && !parent.__isSymbol()) ||
(this.__getSymbol() && !parent.__getSymbol()))
!parent || (parent && !parent.__isSymbol() && !parent.__getSymbol())
);
},
@ -653,14 +651,10 @@ const Component = Backbone.Model.extend(Styleable).extend(
},
__getSymbTop(opts) {
const isSymbol = this.__isSymbol();
let result = this;
let parent = this.parent(opts);
while (
parent &&
(isSymbol ? parent.__isSymbol() : parent.__getSymbol())
) {
while (parent && (parent.__isSymbol() || parent.__getSymbol())) {
result = parent;
parent = parent.parent(opts);
}
@ -710,16 +704,23 @@ const Component = Backbone.Model.extend(Styleable).extend(
});
} else if (o.add) {
// Add
const addedInstances = m.__getSymbToUp(toUpOpts);
let addedInstances = [];
const isMainSymb = !!this.__getSymbols();
const toUp = this.__getSymbToUp(toUpOpts);
if (toUp.length) {
const addSymb = m.__getSymbol();
addedInstances =
(addSymb ? addSymb.__getSymbols() : m.__getSymbols()) || [];
addedInstances = [...addedInstances];
addedInstances.push(addSymb ? addSymb : m);
}
!isTemp &&
this.__logSymbol('add', toUp, {
opts: o,
addedInstances,
addedInstances: addedInstances.map(c => c.cid),
added: m.cid
});
// Here, before appending new symbol, I have to ensure there are no previosly
// Here, before appending a new symbol, I have to ensure there are no previosly
// created symbols (eg. used mainly when drag components around)
toUp.forEach(symb => {
const symbTop = symb.__getSymbTop();
@ -729,15 +730,33 @@ const Component = Backbone.Model.extend(Styleable).extend(
})[0];
const toAppend =
symbPrev || m.clone({ symbol: 1, symbolInv: isMainSymb });
symb.append(toAppend, { fromInstance: this, toAppend: m, ...o });
symb.append(toAppend, { fromInstance: this, ...o });
});
} else {
// Allow removing single instances
if (!m.__isSymbolTop()) {
// Allow removing single instances
const toUp = m.__getSymbToUp(toUpOpts);
!isTemp &&
this.__logSymbol('remove', toUp, { opts: o, removed: m.cid });
toUp.forEach(symb => symb.remove({ fromInstance: m, ...o }));
toUp.forEach(symb => {
const opts = { fromInstance: m, ...o };
// In case of nested symbols, I only need to propagate changes to its instances
if (symb.__isSymbolTop() && symb.__getSymbols()) {
const toUpInst = symb.__getSymbToUp({
fromInstance: m,
...toUpOpts
});
this.__logSymbol('remove-inst', toUpInst, {
opts: o,
symbol: symb
});
toUpInst.forEach(inst => {
inst.remove(opts);
});
} else {
symb.remove(opts);
}
});
}
}
},
@ -836,7 +855,17 @@ const Component = Backbone.Model.extend(Styleable).extend(
* someComponent.append(otherComponent, { at: 0 });
*/
append(components, opts = {}) {
const result = this.components().add(components, opts);
const compArr = isArray(components) ? components : [components];
const toAppend = compArr.map(comp => {
if (isString(comp)) {
return comp;
} else {
// I have to remove components from the old container before adding them to a new one
comp.collection && comp.collection.remove(comp, { temporary: 1 });
return comp;
}
});
const result = this.components().add(toAppend, opts);
return isArray(result) ? result : [result];
},

52
test/specs/dom_components/model/Symbols.js

@ -15,7 +15,7 @@ describe('Symbols', () => {
return cloned;
};
const simpleComp = '<div data-a="b">Component</div>';
const simpleComp2 = '<div data-b="c">Component 2</div>';
const simpleComp2 = '<div data-b="c">Component 3</div>';
const compMultipleNodes = `<div data-v="a">
<div data-v="b">Component 1</div>
<div data-v="c">Component 2</div>
@ -176,20 +176,18 @@ describe('Symbols', () => {
test('Moving a new added component in the instance, will propagate the action in all symbols', () => {
const added = comp.append(simpleComp)[0];
expect(added.index()).toBe(compInitChild);
const newChildLen = compInitChild + 1;
added.move(comp, { at: 0 });
expect(added.index()).toBe(0); // extra checks
expect(added.parent()).toBe(comp);
const symbRef = added.__getSymbol();
// All symbols still have the same amount of components
all.forEach(cmp => expect(cmp.components().length).toBe(newChildLen));
// All instances refer to the same symbol
allInst.forEach(cmp => expect(getFirstInnSymbol(cmp)).toBe(symbRef));
// The moved symbol contains all its instances
expect(
symbol
.components()
.at(0)
.__getSymbols().length
).toBe(allInst.length);
expect(getInnerComp(symbol).__getSymbols().length).toBe(allInst.length);
});
test('Moving a new added component in the symbol, will propagate the action in all instances', () => {
@ -309,14 +307,48 @@ describe('Symbols', () => {
expect(secComp.toHTML()).toBe(secSymbol.toHTML());
});
test('Moving the instance, of the second symbol, inside the first symbol, propagates correctly to all first instances', () => {
test('Adding the instance, of the second symbol, inside the first symbol, propagates correctly to all first instances', () => {
const added = symbol.append(secComp)[0];
// The added component is still the second instance
expect(added).toBe(secComp);
// The added component still has the reference to the second symbol
expect(added.__getSymbol()).toBe(secSymbol);
// The added component is propogated to other instances (of the first symbol)
expect(added.__getSymbols().length).toBe(allInst.length);
// The main second symbol now has the reference to all its instances
const secInstans = secSymbol.__getSymbols();
expect(secInstans.length).toBe(all.length);
// All instances still refer to the second symbol
secInstans.forEach(secInst =>
expect(secInst.__getSymbol()).toBe(secSymbol)
);
});
test('Adding the instance, of the second symbol, inside one of the first instances, propagates correctly to all first symbols', () => {
const added = comp.append(secComp)[0];
// The added component is still the second instance
expect(added).toBe(secComp);
// The added component still has the reference to the second symbol
expect(added.__getSymbol()).toBe(secSymbol);
// The main second symbol now has the reference to all its instances
const secInstans = secSymbol.__getSymbols();
expect(secInstans.length).toBe(all.length);
// All instances still refer to the second symbol
secInstans.forEach(secInst =>
expect(secInst.__getSymbol()).toBe(secSymbol)
);
});
test('Moving the second instance inside first instances, propagates correctly to all other first symbols', () => {
const added = comp.append(secComp)[0];
expect(added.parent()).toBe(comp); // extra checks
expect(added.index()).toBe(compInitChild);
const secInstansArr = secSymbol.__getSymbols().map(i => i.cid);
expect(secInstansArr.length).toBe(all.length);
added.move(comp, { at: 0 });
// After the move, the symbol still have the same references
const secInstansArr2 = secSymbol.__getSymbols().map(i => i.cid);
expect(secInstansArr2).toEqual(secInstansArr);
// All second instances refer to the same second symbol
all.forEach(c => expect(getFirstInnSymbol(c)).toBe(secSymbol));
});
});
});

Loading…
Cancel
Save