mirror of https://github.com/artf/grapesjs.git
committed by
GitHub
59 changed files with 4901 additions and 63022 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
@ -0,0 +1,354 @@ |
|||
import Editor from 'editor'; |
|||
import { keySymbol, keySymbols } from 'dom_components/model/Component'; |
|||
|
|||
describe('Symbols', () => { |
|||
let editor; |
|||
let wrapper; |
|||
const createSymbol = comp => { |
|||
const symbol = comp.clone({ symbol: 1 }); |
|||
comp.parent().append(symbol, { at: comp.index() + 1 }); |
|||
return symbol; |
|||
}; |
|||
const duplicate = comp => { |
|||
const cloned = comp.clone({}); |
|||
comp.parent().append(cloned, { at: comp.index() + 1 }); |
|||
return cloned; |
|||
}; |
|||
const simpleComp = '<div data-a="b">Component</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> |
|||
</div>`; |
|||
|
|||
let allInst, all, comp, symbol, compInitChild; |
|||
let secComp, secSymbol; |
|||
const getInnerComp = (cmp, i = 0) => cmp.components().at(i); |
|||
const getFirstInnSymbol = cmp => getInnerComp(cmp).__getSymbol(); |
|||
const getInnSymbol = (cmp, i = 0) => getInnerComp(cmp, i).__getSymbol(); |
|||
|
|||
beforeAll(() => { |
|||
editor = new Editor(); |
|||
wrapper = editor.getWrapper(); |
|||
}); |
|||
|
|||
afterAll(() => { |
|||
wrapper = {}; |
|||
editor.destroy(); |
|||
}); |
|||
|
|||
beforeEach(() => {}); |
|||
|
|||
afterEach(() => { |
|||
wrapper.components().reset(); |
|||
}); |
|||
|
|||
test('Create symbol from a component', () => { |
|||
const comp = wrapper.append(simpleComp)[0]; |
|||
const symbol = createSymbol(comp); |
|||
const symbs = symbol.__getSymbols(); |
|||
expect(symbol.__isSymbol()).toBe(true); |
|||
expect(comp.__getSymbol()).toBe(symbol); |
|||
expect(symbs.length).toBe(1); |
|||
expect(symbs[0]).toBe(comp); |
|||
expect(comp.toHTML()).toBe(symbol.toHTML()); |
|||
}); |
|||
|
|||
test('Create 1 symbol and clone the instance for another one', () => { |
|||
const comp = wrapper.append(simpleComp)[0]; |
|||
const symbol = createSymbol(comp); |
|||
const comp2 = createSymbol(comp); |
|||
const symbs = symbol.__getSymbols(); |
|||
expect(symbs.length).toBe(2); |
|||
expect(symbs[0]).toBe(comp); |
|||
expect(symbs[1]).toBe(comp2); |
|||
expect(comp2.__getSymbol()).toBe(symbol); |
|||
expect(comp2.toHTML()).toBe(symbol.toHTML()); |
|||
}); |
|||
|
|||
test('Create 1 symbol and clone it to have another instance', () => { |
|||
const comp = wrapper.append(simpleComp)[0]; |
|||
const symbol = createSymbol(comp); |
|||
const comp2 = createSymbol(symbol); |
|||
const symbs = symbol.__getSymbols(); |
|||
expect(symbs.length).toBe(2); |
|||
expect(symbs[0]).toBe(comp); |
|||
expect(symbs[1]).toBe(comp2); |
|||
expect(comp2.__getSymbol()).toBe(symbol); |
|||
expect(comp2.toHTML()).toBe(symbol.toHTML()); |
|||
}); |
|||
|
|||
test('Symbols and instances are correctly serialized', () => { |
|||
const comp = wrapper.append(simpleComp)[0]; |
|||
const symbol = createSymbol(comp); |
|||
const idComp = comp.getId(); |
|||
const idSymb = symbol.getId(); |
|||
const jsonComp = JSON.parse(JSON.stringify(comp)); |
|||
const jsonSymb = JSON.parse(JSON.stringify(symbol)); |
|||
expect(jsonComp[keySymbol]).toBe(idSymb); |
|||
expect(jsonSymb[keySymbols]).toEqual([idComp]); |
|||
}); |
|||
|
|||
test("Removing one instance doesn't affect others", () => { |
|||
const comp = wrapper.append(simpleComp)[0]; |
|||
const symbol = createSymbol(comp); |
|||
const comp2 = createSymbol(comp); |
|||
expect(wrapper.components().length).toBe(3); |
|||
comp.remove(); |
|||
expect(wrapper.components().length).toBe(2); |
|||
expect(comp2.__getSymbol()).toBe(symbol); |
|||
}); |
|||
|
|||
test('New component added to an instance is correctly propogated to all others', () => { |
|||
const comp = wrapper.append(compMultipleNodes)[0]; |
|||
const compLen = comp.components().length; |
|||
const symbol = createSymbol(comp); |
|||
// Create and add 2 instances
|
|||
const comp2 = createSymbol(comp); |
|||
const comp3 = createSymbol(comp2); |
|||
const allInst = [comp, comp2, comp3]; |
|||
const all = [...allInst, symbol]; |
|||
all.forEach(cmp => expect(cmp.components().length).toBe(compLen)); |
|||
expect(wrapper.components().length).toBe(4); |
|||
// Append new component to one of the instances
|
|||
const added = comp3.append(simpleComp, { at: 0 })[0]; |
|||
// The append should be propagated
|
|||
all.forEach(cmp => expect(cmp.components().length).toBe(compLen + 1)); |
|||
// The new added component became part of the symbol instance
|
|||
const addedSymb = added.__getSymbol(); |
|||
const symbAdded = symbol.components().at(0); |
|||
expect(addedSymb).toBe(symbAdded); |
|||
allInst.forEach(cmp => |
|||
expect( |
|||
cmp |
|||
.components() |
|||
.at(0) |
|||
.__getSymbol() |
|||
).toBe(symbAdded) |
|||
); |
|||
// The new main Symbol should keep the track of all instances
|
|||
expect(symbAdded.__getSymbols().length).toBe(allInst.length); |
|||
}); |
|||
|
|||
describe('Creating 3 symbols in the wrapper', () => { |
|||
beforeEach(() => { |
|||
comp = wrapper.append(compMultipleNodes)[0]; |
|||
compInitChild = comp.components().length; |
|||
symbol = createSymbol(comp); |
|||
const comp2 = createSymbol(comp); |
|||
const comp3 = createSymbol(comp); |
|||
allInst = [comp, comp2, comp3]; |
|||
all = [...allInst, symbol]; |
|||
}); |
|||
|
|||
afterEach(() => { |
|||
wrapper.components().reset(); |
|||
}); |
|||
|
|||
test('The wrapper contains all the symbols', () => { |
|||
expect(wrapper.components().length).toBe(all.length); |
|||
}); |
|||
|
|||
test('All the symbols contain the same amount of children', () => { |
|||
all.forEach(cmp => expect(cmp.components().length).toBe(compInitChild)); |
|||
}); |
|||
|
|||
test('Adding a new component to a symbol, it will be propogated to all instances', () => { |
|||
const added = symbol.append(simpleComp, { at: 0 })[0]; |
|||
all.forEach(cmp => |
|||
expect(cmp.components().length).toBe(compInitChild + 1) |
|||
); |
|||
// Check symbol references
|
|||
expect(added.__getSymbols().length).toBe(allInst.length); |
|||
allInst.forEach(cmp => expect(getFirstInnSymbol(cmp)).toBe(added)); |
|||
}); |
|||
|
|||
test('Adding a new component to an instance of the symbol, it will be propogated to all symbols', () => { |
|||
const added = comp.append(simpleComp, { at: 0 })[0]; |
|||
all.forEach(cmp => |
|||
expect(cmp.components().length).toBe(compInitChild + 1) |
|||
); |
|||
// Check symbol references
|
|||
const addSymb = added.__getSymbol(); |
|||
expect(symbol.components().at(0)).toBe(addSymb); |
|||
allInst.forEach(cmp => expect(getFirstInnSymbol(cmp)).toBe(addSymb)); |
|||
}); |
|||
|
|||
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(getInnerComp(symbol).__getSymbols().length).toBe(allInst.length); |
|||
}); |
|||
|
|||
test('Moving a new added component in the symbol, will propagate the action in all instances', () => { |
|||
const added = symbol.append(simpleComp)[0]; |
|||
const newChildLen = compInitChild + 1; |
|||
added.move(symbol, { at: 0 }); |
|||
// 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(added)); |
|||
// The moved symbol contains all its instances
|
|||
expect(added.__getSymbols().length).toBe(allInst.length); |
|||
}); |
|||
|
|||
test('Adding a class, reflects changes to all symbols', () => { |
|||
const initSel = symbol.getSelectorsString(); |
|||
all.forEach(cmp => expect(cmp.getSelectorsString()).toBe(initSel)); |
|||
// Adding a class to a symbol
|
|||
symbol.addClass('myclass'); |
|||
const newSel = symbol.getSelectorsString(); |
|||
expect(newSel).not.toBe(initSel); |
|||
all.forEach(cmp => expect(cmp.getSelectorsString()).toBe(newSel)); |
|||
// Adding a class to an instance
|
|||
comp.addClass('myclass2'); |
|||
const newSel2 = comp.getSelectorsString(); |
|||
expect(newSel2).not.toBe(newSel); |
|||
all.forEach(cmp => expect(cmp.getSelectorsString()).toBe(newSel2)); |
|||
}); |
|||
|
|||
test('Updating some prop, reflects changes to all symbols', () => { |
|||
const propKey = 'someprop'; |
|||
const propValue = 'somevalue'; |
|||
all.forEach(cmp => expect(cmp.get(propKey)).toBeFalsy()); |
|||
// Updating the symbol
|
|||
symbol.set(propKey, propValue); |
|||
all.forEach(cmp => expect(cmp.get(propKey)).toBe(propValue)); |
|||
// Updating the instance
|
|||
const propValue2 = 'somevalue2'; |
|||
comp.set(propKey, propValue2); |
|||
all.forEach(cmp => expect(cmp.get(propKey)).toBe(propValue2)); |
|||
}); |
|||
|
|||
test('Updating some attribute, reflects changes to all symbols', () => { |
|||
const attrKey = 'data-attr'; |
|||
const attrValue = 'somevalue'; |
|||
all.forEach(cmp => expect(cmp.getAttributes()[attrKey]).toBeFalsy()); |
|||
// Updating the symbol
|
|||
symbol.addAttributes({ [attrKey]: attrValue }); |
|||
all.forEach(cmp => expect(cmp.getAttributes()[attrKey]).toBe(attrValue)); |
|||
// Updating the instance with another attribute
|
|||
const attrKey2 = 'data-attr2'; |
|||
const attrValue2 = 'somevalue2'; |
|||
comp.addAttributes({ [attrKey2]: attrValue2 }); |
|||
all.forEach(cmp => { |
|||
const attrs = cmp.getAttributes(); |
|||
expect(attrs[attrKey]).toBe(attrValue); |
|||
expect(attrs[attrKey2]).toBe(attrValue2); |
|||
}); |
|||
// All symbols still have the same HTML
|
|||
const symbHtml = symbol.toHTML(); |
|||
all.forEach(cmp => expect(cmp.toHTML()).toBe(symbHtml)); |
|||
}); |
|||
|
|||
test('Cloning a component in an instance, reflects changes to all symbols', () => { |
|||
const cloned = duplicate(comp.components().at(0)); |
|||
const clonedSymb = symbol.components().at(1); |
|||
const newLen = comp.components().length; |
|||
expect(newLen).toBe(compInitChild + 1); |
|||
expect(cloned.__getSymbol()).toBe(clonedSymb); |
|||
// All symbols have the same amount of components
|
|||
all.forEach(cmp => expect(cmp.components().length).toBe(newLen)); |
|||
// All instances refer to the same symbol
|
|||
allInst.forEach(cmp => expect(getInnSymbol(cmp, 1)).toBe(clonedSymb)); |
|||
// Symbol contains the reference of instances
|
|||
const innerSymb = allInst.map(i => getInnerComp(i, 1)); |
|||
expect(clonedSymb.__getSymbols()).toEqual(innerSymb); |
|||
}); |
|||
|
|||
test('Cloning a component in a symbol, reflects changes to all instances', () => { |
|||
const clonedSymb = duplicate(getInnerComp(symbol)); |
|||
const cloned = getInnerComp(comp, 1); |
|||
const newLen = symbol.components().length; |
|||
// As above
|
|||
expect(newLen).toBe(compInitChild + 1); |
|||
expect(cloned.__getSymbol()).toBe(clonedSymb); |
|||
all.forEach(cmp => expect(cmp.components().length).toBe(newLen)); |
|||
allInst.forEach(cmp => expect(getInnSymbol(cmp, 1)).toBe(clonedSymb)); |
|||
const innerSymb = allInst.map(i => getInnerComp(i, 1)); |
|||
expect(clonedSymb.__getSymbols()).toEqual(innerSymb); |
|||
}); |
|||
}); |
|||
|
|||
describe('Nested symbols', () => { |
|||
beforeEach(() => { |
|||
comp = wrapper.append(compMultipleNodes)[0]; |
|||
compInitChild = comp.components().length; |
|||
symbol = createSymbol(comp); |
|||
const comp2 = createSymbol(comp); |
|||
const comp3 = createSymbol(comp); |
|||
allInst = [comp, comp2, comp3]; |
|||
all = [...allInst, symbol]; |
|||
// Second symbol
|
|||
secComp = wrapper.append(simpleComp2)[0]; |
|||
secSymbol = createSymbol(secComp); |
|||
}); |
|||
|
|||
afterEach(() => { |
|||
wrapper.components().reset(); |
|||
}); |
|||
|
|||
test('Second symbol created properly', () => { |
|||
const symbs = secSymbol.__getSymbols(); |
|||
expect(secSymbol.__isSymbol()).toBe(true); |
|||
expect(secComp.__getSymbol()).toBe(secSymbol); |
|||
expect(symbs.length).toBe(1); |
|||
expect(symbs[0]).toBe(secComp); |
|||
expect(secComp.toHTML()).toBe(secSymbol.toHTML()); |
|||
}); |
|||
|
|||
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 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)); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -1,68 +1,38 @@ |
|||
const HtmlWebpackPlugin = require('html-webpack-plugin'); |
|||
const pkg = require('./package.json'); |
|||
const webpack = require('webpack'); |
|||
const path = require('path'); |
|||
const fs = require('fs'); |
|||
import path from 'path'; |
|||
import pkg from './package.json'; |
|||
|
|||
const rootDir = path.resolve(__dirname); |
|||
let plugins = []; |
|||
|
|||
module.exports = env => { |
|||
const name = pkg.name; |
|||
const isProd = env === 'prod'; |
|||
const output = { |
|||
path: path.join(__dirname), |
|||
filename: 'dist/grapes.min.js', |
|||
library: name, |
|||
export default ({ config }) => ({ |
|||
...config, |
|||
output: { |
|||
...config.output, |
|||
filename: 'grapes.min.js', |
|||
libraryExport: 'default', |
|||
libraryTarget: 'umd', |
|||
}; |
|||
|
|||
if (isProd) { |
|||
plugins = [ |
|||
new webpack.optimize.ModuleConcatenationPlugin(), |
|||
new webpack.BannerPlugin(`${name} - ${pkg.version}`), |
|||
]; |
|||
} else if (env === 'dev') { |
|||
output.filename = 'dist/grapes.js'; |
|||
} else { |
|||
const index = 'index.html'; |
|||
const indexDev = `_${index}`; |
|||
const template = fs.existsSync(indexDev) ? indexDev : index; |
|||
plugins.push(new HtmlWebpackPlugin({ template, inject: false })); |
|||
} |
|||
|
|||
return { |
|||
entry: './src', |
|||
output: output, |
|||
plugins: plugins, |
|||
mode: isProd ? 'production' : 'development', |
|||
devtool: isProd ? 'source-map' : (!env ? 'cheap-module-eval-source-map' : false), |
|||
devServer: { |
|||
headers: { 'Access-Control-Allow-Origin': '*' }, |
|||
disableHostCheck: true, |
|||
}, |
|||
module: { |
|||
rules: [{ |
|||
}, |
|||
devServer: { |
|||
headers: { 'Access-Control-Allow-Origin': '*' }, |
|||
disableHostCheck: true, |
|||
}, |
|||
module: { |
|||
rules: [ |
|||
{ |
|||
test: /\/index\.js$/, |
|||
loader: 'string-replace-loader', |
|||
query: { |
|||
search: '<# VERSION #>', |
|||
replace: pkg.version |
|||
} |
|||
}, { |
|||
test: /\.js$/, |
|||
loader: 'babel-loader', |
|||
include: /src/, |
|||
options: { cacheDirectory: true }, |
|||
}], |
|||
}, |
|||
resolve: { |
|||
modules: ['src', 'node_modules'], |
|||
alias: { |
|||
jquery: 'cash-dom', |
|||
backbone: `${rootDir}/node_modules/backbone`, |
|||
underscore: `${rootDir}/node_modules/underscore`, |
|||
} |
|||
}, |
|||
...config.module.rules, |
|||
], |
|||
}, |
|||
resolve: { |
|||
modules: ['src', 'node_modules'], |
|||
alias: { |
|||
jquery: 'cash-dom', |
|||
backbone: `${rootDir}/node_modules/backbone`, |
|||
underscore: `${rootDir}/node_modules/underscore`, |
|||
} |
|||
}; |
|||
} |
|||
}, |
|||
}); |
|||
Loading…
Reference in new issue