Browse Source

Merge pull request #3167 from artf/dev

Merge dev
pull/3550/head
Artur Arseniev 6 years ago
committed by GitHub
parent
commit
d9cdb671e6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      dist/css/grapes.min.css
  2. 7669
      dist/grapes.js
  3. 6
      dist/grapes.min.js
  4. 2
      dist/grapes.min.js.map
  5. 2
      docs/README.md
  6. 2
      docs/modules/Components.md
  7. 667
      package-lock.json
  8. 10
      package.json
  9. 9
      src/asset_manager/index.js
  10. 10
      src/block_manager/index.js
  11. 20
      src/canvas/index.js
  12. 4
      src/canvas/view/CanvasView.js
  13. 6
      src/canvas/view/FrameView.js
  14. 4
      src/canvas/view/FrameWrapView.js
  15. 6
      src/code_manager/index.js
  16. 57
      src/commands/index.js
  17. 5
      src/commands/view/CopyComponent.js
  18. 19
      src/commands/view/SelectComponent.js
  19. 26
      src/css_composer/index.js
  20. 28
      src/css_composer/model/CssRule.js
  21. 2
      src/css_composer/model/CssRules.js
  22. 8
      src/device_manager/index.js
  23. 20
      src/dom_components/index.js
  24. 205
      src/dom_components/model/Component.js
  25. 60
      src/dom_components/model/Components.js
  26. 2
      src/dom_components/view/ComponentTextView.js
  27. 5
      src/domain_abstract/ui/Input.js
  28. 5
      src/domain_abstract/ui/InputColor.js
  29. 26
      src/domain_abstract/ui/InputNumber.js
  30. 25
      src/editor/model/Editor.js
  31. 5
      src/i18n/index.js
  32. 198
      src/i18n/locale/ca.js
  33. 8
      src/keymaps/index.js
  34. 6
      src/modal_dialog/index.js
  35. 3
      src/navigator/index.js
  36. 7
      src/navigator/view/ItemView.js
  37. 8
      src/panels/index.js
  38. 20
      src/panels/view/ButtonView.js
  39. 11
      src/panels/view/ButtonsView.js
  40. 5
      src/parser/index.js
  41. 2
      src/parser/model/ParserHtml.js
  42. 5
      src/rich_text_editor/index.js
  43. 9
      src/selector_manager/index.js
  44. 35
      src/selector_manager/model/Selector.js
  45. 11
      src/storage_manager/index.js
  46. 10
      src/style_manager/index.js
  47. 11
      src/style_manager/model/Sectors.js
  48. 6
      src/style_manager/view/PropertyColorView.js
  49. 6
      src/style_manager/view/PropertyCompositeView.js
  50. 4
      src/style_manager/view/PropertyStackView.js
  51. 15
      src/style_manager/view/PropertyView.js
  52. 12
      src/style_manager/view/SectorsView.js
  53. 10
      src/styles/scss/_gjs_inputs.scss
  54. 6
      src/styles/scss/main.scss
  55. 5
      src/trait_manager/index.js
  56. 14
      src/trait_manager/view/TraitNumberView.js
  57. 8
      src/undo_manager/index.js
  58. 2
      src/utils/index.js
  59. 2
      src/utils/mixins.js
  60. 11
      test/specs/css_composer/e2e/CssComposer.js
  61. 6
      test/specs/dom_components/model/Component.js
  62. 17
      test/specs/editor/index.js
  63. 2
      test/specs/grapesjs/index.js
  64. 2
      test/specs/panels/view/ButtonView.js
  65. 32
      test/specs/parser/model/ParserHtml.js
  66. 38
      test/specs/selector_manager/e2e/ClassManager.js

2
dist/css/grapes.min.css

File diff suppressed because one or more lines are too long

7669
dist/grapes.js

File diff suppressed because it is too large

6
dist/grapes.min.js

File diff suppressed because one or more lines are too long

2
dist/grapes.min.js.map

File diff suppressed because one or more lines are too long

2
docs/README.md

@ -11,7 +11,7 @@ GrapesJS ships with features and tools that enable you to craft easy to use buil
## Why GrapesJS?
GrapesJS was designed primarily to for use inside Content Management Systems to speed up the creation of dynamic templates and replace common WYSIWYG editors. Which are good for content editing, but inappropriate for creating HTML structures. Instead of creating an application we decided to create an extensible framework that could be used by anyone for any purpose.
GrapesJS was designed primarily for use inside Content Management Systems to speed up the creation of dynamic templates and replace common WYSIWYG editors. Which are good for content editing, but inappropriate for creating HTML structures. Instead of creating an application we decided to create an extensible framework that could be used by anyone for any purpose.

2
docs/modules/Components.md

@ -79,7 +79,7 @@ In the first step, the HTML string is parsed and transformed to what is called *
}
```
The real **Component Definition** would be a little bit bigger so so we'd reduced the JSON for the sake of simplicity.
The real **Component Definition** would be a little bit bigger so we've reduced the JSON for the sake of simplicity.
You might notice the result is similar to what is generally called a **Virtual DOM**, a lightweight representation of the DOM element. This actually helps the editor to keep track of the state of our elements and make performance-friendly changes/updates.
The meaning of properties like `tagName`, `attributes` and `components` are quite obvious, but what about `type`?! This particular property specifies the **Component Type** of our **Component Definition** (you check the list of default components [below](#built-in-component-types)) and if it's omitted, the default one will be used `type: 'default'`.

667
package-lock.json

@ -1,6 +1,6 @@
{
"name": "grapesjs",
"version": "0.16.27",
"version": "0.16.30",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -3502,12 +3502,6 @@
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
"dev": true
},
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
"ansi-align": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",
@ -3643,16 +3637,6 @@
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true
},
"are-we-there-yet": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"dev": true,
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@ -3686,12 +3670,6 @@
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
"dev": true
},
"array-find-index": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
"integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
"dev": true
},
"array-flatten": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
@ -3811,12 +3789,6 @@
"integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
"dev": true
},
"async-foreach": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
"integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
"dev": true
},
"async-limiter": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
@ -5218,15 +5190,6 @@
"file-uri-to-path": "1.0.0"
}
},
"block-stream": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
"integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
"dev": true,
"requires": {
"inherits": "~2.0.0"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@ -5844,24 +5807,6 @@
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
"dev": true
},
"camelcase-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
"dev": true,
"requires": {
"camelcase": "^2.0.0",
"map-obj": "^1.0.0"
},
"dependencies": {
"camelcase": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
"integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
"dev": true
}
}
},
"caniuse-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@ -6162,9 +6107,9 @@
"dev": true
},
"codemirror": {
"version": "5.53.2",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.53.2.tgz",
"integrity": "sha512-wvSQKS4E+P8Fxn/AQ+tQtJnF1qH5UOlxtugFLpubEZ5jcdH2iXTVinb+Xc/4QjshuOxRm4fUsU2QPF1JJKiyXA=="
"version": "5.58.3",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.58.3.tgz",
"integrity": "sha512-KBhB+juiyOOgn0AqtRmWyAT3yoElkuvWTI6hsHa9E6GQrl6bk/fdAYcvuqW1/upO9T9rtEtapWdw4XYcNiVDEA=="
},
"codemirror-formatting": {
"version": "1.0.0",
@ -6372,12 +6317,6 @@
"integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true
},
"consolidate": {
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz",
@ -6939,15 +6878,6 @@
"cssom": "0.3.x"
}
},
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
"integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
"dev": true,
"requires": {
"array-find-index": "^1.0.1"
}
},
"cyclist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
@ -7223,12 +7153,6 @@
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@ -9191,18 +9115,6 @@
}
}
},
"fstream": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
"integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"inherits": "~2.0.0",
"mkdirp": ">=0.5 0",
"rimraf": "2"
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@ -9226,31 +9138,6 @@
"simple-git": "^1.85.0"
}
},
"gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
}
},
"gaze": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
"integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
"dev": true,
"requires": {
"globule": "^1.0.0"
}
},
"gensync": {
"version": "1.0.0-beta.1",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
@ -9476,17 +9363,6 @@
}
}
},
"globule": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz",
"integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==",
"dev": true,
"requires": {
"glob": "~7.1.1",
"lodash": "~4.17.12",
"minimatch": "~3.0.2"
}
},
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
@ -9613,12 +9489,6 @@
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
"has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true
},
"has-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
@ -9744,9 +9614,9 @@
"dev": true
},
"highlight.js": {
"version": "9.18.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz",
"integrity": "sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==",
"version": "9.18.5",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.5.tgz",
"integrity": "sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==",
"dev": true
},
"hmac-drbg": {
@ -10354,12 +10224,6 @@
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
"in-publish": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
"integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==",
"dev": true
},
"indent-string": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
@ -11964,12 +11828,6 @@
}
}
},
"js-base64": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz",
"integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==",
"dev": true
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -12759,16 +12617,6 @@
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"loud-rejection": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
"integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
"dev": true,
"requires": {
"currently-unhandled": "^0.4.1",
"signal-exit": "^3.0.0"
}
},
"lower-case": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
@ -12825,12 +12673,6 @@
"integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
"dev": true
},
"map-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
"integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
"dev": true
},
"map-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
@ -13062,114 +12904,6 @@
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
"dev": true
},
"meow": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
"dev": true,
"requires": {
"camelcase-keys": "^2.0.0",
"decamelize": "^1.1.2",
"loud-rejection": "^1.0.0",
"map-obj": "^1.0.1",
"minimist": "^1.1.3",
"normalize-package-data": "^2.3.4",
"object-assign": "^4.0.1",
"read-pkg-up": "^1.0.1",
"redent": "^1.0.0",
"trim-newlines": "^1.0.0"
},
"dependencies": {
"find-up": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
"dev": true,
"requires": {
"path-exists": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^2.2.0",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0",
"strip-bom": "^2.0.0"
}
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
"dev": true,
"requires": {
"error-ex": "^1.2.0"
}
},
"path-exists": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
"dev": true,
"requires": {
"pinkie-promise": "^2.0.0"
}
},
"path-type": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
"dev": true,
"requires": {
"load-json-file": "^1.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^1.0.0"
}
},
"read-pkg-up": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
"dev": true,
"requires": {
"find-up": "^1.0.0",
"read-pkg": "^1.0.0"
}
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
"requires": {
"is-utf8": "^0.2.0"
}
}
}
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@ -13542,7 +13276,8 @@
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
"dev": true
"dev": true,
"optional": true
},
"nanomatch": {
"version": "1.2.13",
@ -13626,34 +13361,6 @@
"integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==",
"dev": true
},
"node-gyp": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
"integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
"dev": true,
"requires": {
"fstream": "^1.0.0",
"glob": "^7.0.3",
"graceful-fs": "^4.1.2",
"mkdirp": "^0.5.0",
"nopt": "2 || 3",
"npmlog": "0 || 1 || 2 || 3 || 4",
"osenv": "0",
"request": "^2.87.0",
"rimraf": "2",
"semver": "~5.3.0",
"tar": "^2.0.0",
"which": "1"
},
"dependencies": {
"semver": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
"dev": true
}
}
},
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@ -13724,83 +13431,6 @@
"integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==",
"dev": true
},
"node-sass": {
"version": "4.13.1",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz",
"integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==",
"dev": true,
"requires": {
"async-foreach": "^0.1.3",
"chalk": "^1.1.1",
"cross-spawn": "^3.0.0",
"gaze": "^1.0.0",
"get-stdin": "^4.0.1",
"glob": "^7.0.3",
"in-publish": "^2.0.0",
"lodash": "^4.17.15",
"meow": "^3.7.0",
"mkdirp": "^0.5.1",
"nan": "^2.13.2",
"node-gyp": "^3.8.0",
"npmlog": "^4.0.0",
"request": "^2.88.0",
"sass-graph": "^2.2.4",
"stdout-stream": "^1.4.0",
"true-case-path": "^1.0.2"
},
"dependencies": {
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"cross-spawn": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
"integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
"dev": true,
"requires": {
"lru-cache": "^4.0.1",
"which": "^1.2.9"
}
},
"get-stdin": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
"integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
"dev": true
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
}
}
},
"nopt": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
"integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
"dev": true,
"requires": {
"abbrev": "1"
}
},
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@ -13915,18 +13545,6 @@
}
}
},
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"nprogress": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
@ -14210,16 +13828,6 @@
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
"osenv": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true,
"requires": {
"os-homedir": "^1.0.0",
"os-tmpdir": "^1.0.0"
}
},
"p-cancelable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
@ -15742,27 +15350,6 @@
"util.promisify": "^1.0.0"
}
},
"redent": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
"integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
"dev": true,
"requires": {
"indent-string": "^2.1.0",
"strip-indent": "^1.0.1"
},
"dependencies": {
"indent-string": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
"integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
"dev": true,
"requires": {
"repeating": "^2.0.0"
}
}
}
},
"reduce": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/reduce/-/reduce-1.0.2.tgz",
@ -16401,157 +15988,13 @@
}
}
},
"sass-graph": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz",
"integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=",
"sass": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.29.0.tgz",
"integrity": "sha512-ZpwAUFgnvAUCdkjwPREny+17BpUj8nh5Yr6zKPGtLNTLrmtoRYIjm7njP24COhjJldjwW1dcv52Lpf4tNZVVRA==",
"dev": true,
"requires": {
"glob": "^7.0.0",
"lodash": "^4.0.0",
"scss-tokenizer": "^0.2.3",
"yargs": "^7.0.0"
},
"dependencies": {
"camelcase": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
"dev": true
},
"find-up": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
"dev": true,
"requires": {
"path-exists": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^2.2.0",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0",
"strip-bom": "^2.0.0"
}
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"dev": true,
"requires": {
"lcid": "^1.0.0"
}
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
"dev": true,
"requires": {
"error-ex": "^1.2.0"
}
},
"path-exists": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
"dev": true,
"requires": {
"pinkie-promise": "^2.0.0"
}
},
"path-type": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
"dev": true,
"requires": {
"load-json-file": "^1.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^1.0.0"
}
},
"read-pkg-up": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
"dev": true,
"requires": {
"find-up": "^1.0.0",
"read-pkg": "^1.0.0"
}
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
"requires": {
"is-utf8": "^0.2.0"
}
},
"which-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
"integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
"dev": true
},
"yargs": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
"integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
"dev": true,
"requires": {
"camelcase": "^3.0.0",
"cliui": "^3.2.0",
"decamelize": "^1.1.1",
"get-caller-file": "^1.0.1",
"os-locale": "^1.4.0",
"read-pkg-up": "^1.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
"string-width": "^1.0.2",
"which-module": "^1.0.0",
"y18n": "^3.2.1",
"yargs-parser": "^5.0.0"
}
},
"yargs-parser": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
"integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
"dev": true,
"requires": {
"camelcase": "^3.0.0"
}
}
"chokidar": ">=2.0.0 <4.0.0"
}
},
"sax": {
@ -16570,27 +16013,6 @@
"ajv-keywords": "^3.4.1"
}
},
"scss-tokenizer": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
"integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
"dev": true,
"requires": {
"js-base64": "^2.1.8",
"source-map": "^0.4.2"
},
"dependencies": {
"source-map": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
"dev": true,
"requires": {
"amdefine": ">=0.0.4"
}
}
}
},
"section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
@ -17374,15 +16796,6 @@
}
}
},
"stdout-stream": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
"integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
"dev": true,
"requires": {
"readable-stream": "^2.0.1"
}
},
"stealthy-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
@ -17653,23 +17066,6 @@
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
"dev": true
},
"strip-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
"integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
"dev": true,
"requires": {
"get-stdin": "^4.0.1"
},
"dependencies": {
"get-stdin": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
"integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
"dev": true
}
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@ -17907,17 +17303,6 @@
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
"dev": true
},
"tar": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
"integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
"dev": true,
"requires": {
"block-stream": "*",
"fstream": "^1.0.12",
"inherits": "2"
}
},
"term-size": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz",
@ -18261,12 +17646,6 @@
"integrity": "sha512-E0ZosSWYK2mkSu+KEtQ9/KqarVjA9HztOSX+9FDdNacRAq29RRV6ZQNgob3iuW8Htar9vAfEa6yyt5qBAHZDBA==",
"dev": true
},
"trim-newlines": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
"integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
"dev": true
},
"trim-right": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
@ -18285,15 +17664,6 @@
"integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
"dev": true
},
"true-case-path": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
"integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
"dev": true,
"requires": {
"glob": "^7.1.2"
}
},
"tslib": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
@ -20249,15 +19619,6 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
"wide-align": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"dev": true,
"requires": {
"string-width": "^1.0.2 || 2"
}
},
"widest-line": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",

10
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Free and Open Source Web Builder Framework",
"version": "0.16.27",
"version": "0.16.30",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",
@ -20,7 +20,7 @@
"backbone": "1.3.3",
"backbone-undo": "^0.2.5",
"cash-dom": "^2.3.9",
"codemirror": "^5.49.2",
"codemirror": "^5.58.2",
"codemirror-formatting": "^1.0.0",
"keymaster": "^1.6.2",
"promise-polyfill": "^8.1.3",
@ -40,9 +40,9 @@
"husky": "^2.7.0",
"jest": "^24.9.0",
"lint-staged": "^8.2.1",
"node-sass": "^4.13.0",
"npm-run-all": "^4.1.5",
"prettier": "^1.18.2",
"sass": "^1.29.0",
"sinon": "^7.5.0",
"string-replace-loader": "^2.2.0",
"vuepress": "^1.5.4",
@ -124,11 +124,11 @@
"build-n": "npm run check && npm run build:css && npm run build-prod",
"build-dev": "webpack --env=dev && npm run build:css && npm run build:locale",
"build-prod": "webpack --env=prod",
"build:css": "node-sass src/styles/scss/main.scss dist/css/grapes.min.css --output-style compressed",
"build:css": "sass src/styles/scss/main.scss dist/css/grapes.min.css --no-source-map --style=compressed --load-path=node_modules",
"build:locale": "rm -rf ./locale && node scripts/build-locale.js && babel locale -d locale --copy-files --no-comments",
"v:patch": "npm version --no-git-tag-version patch",
"start": "run-p start:*",
"start:css": "npm run build:css -- -w",
"start:css": "npm run build:css -- --watch",
"start:js": "webpack-dev-server --open --progress --colors",
"stats": "webpack --env=prod --profile --json > stats.json && webpack-bundle-analyzer stats.json",
"format": "prettier --single-quote --write './{src,test}/**/*.js'",

9
src/asset_manager/index.js

@ -347,6 +347,15 @@ export default () => {
*/
onDblClick(func) {
c.onDblClick = func;
},
destroy() {
assets.reset();
fu.collection.reset();
fu.remove();
am.remove();
[assets, am, fu].forEach(i => (i = null));
c = {};
}
};
};

10
src/block_manager/index.js

@ -255,6 +255,16 @@ export default () => {
}
return this.getContainer();
},
destroy() {
blocks.reset();
blocks.stopListening();
blocksVisible.reset();
categories.reset();
blocksView && blocksView.remove();
[blocks, blocksVisible, categories, blocksView].forEach(i => (i = null));
c = {};
}
};
};

20
src/canvas/index.js

@ -30,26 +30,15 @@
* @module Canvas
*/
import {
on,
off,
hasDnd,
getElement,
getPointerEvent,
getViewEl
} from 'utils/mixins';
import { debounce } from 'underscore';
import { hasDnd, getElement, getViewEl } from 'utils/mixins';
import Droppable from 'utils/Droppable';
import defaults from './config/config';
import Canvas from './model/Canvas';
import canvasView from './view/CanvasView';
const { requestAnimationFrame } = window;
export default () => {
let c = {};
let canvas;
let frameRect;
let CanvasView;
return {
@ -684,6 +673,13 @@ export default () => {
em: this.em
}
);
},
destroy() {
canvas.stopListening();
CanvasView.remove();
[c, canvas, CanvasView].forEach(i => (i = {}));
['em', 'model', 'droppable'].forEach(i => (this[i] = {}));
}
};
};

4
src/canvas/view/CanvasView.js

@ -63,6 +63,10 @@ export default Backbone.View.extend({
},
remove() {
const frm = this.model.get('frames');
frm.remove(frm.models);
this.frames.remove();
this.frames = {};
Backbone.View.prototype.remove.apply(this, arguments);
this.toggleListeners();
},

6
src/canvas/view/FrameView.js

@ -1,5 +1,5 @@
import Backbone from 'backbone';
import { bindAll, isString, debounce } from 'underscore';
import { bindAll, isString, debounce, isUndefined } from 'underscore';
import CssRulesView from 'css_composer/view/CssRulesView';
import ComponentView from 'dom_components/view/ComponentView';
import {
@ -162,11 +162,12 @@ export default Backbone.View.extend({
autoscroll() {
if (this.dragging) {
const { lastClientY } = this;
const canvas = this.em.get('Canvas');
const win = this.getWindow();
const body = this.getBody();
const actualTop = body.scrollTop;
const clientY = this.lastClientY || 0;
const clientY = lastClientY || 0;
const limitTop = canvas.getConfig().autoscrollLimit;
const limitBottom = this.getRect().height - limitTop;
let nextTop = actualTop;
@ -180,6 +181,7 @@ export default Backbone.View.extend({
}
if (
!isUndefined(lastClientY) && // Fixes #3134
nextTop !== actualTop &&
nextTop > 0 &&
nextTop < this.lastMaxHeight

4
src/canvas/view/FrameWrapView.js

@ -35,6 +35,7 @@ export default Backbone.View.extend({
this.listenTo(model, 'loaded', this.frameLoaded);
this.listenTo(model, 'change:x change:y', this.updatePos);
this.listenTo(model, 'change:width change:height', this.updateSize);
this.listenTo(model, 'destroy remove', this.remove);
this.updatePos();
this.setupDragger();
},
@ -69,8 +70,9 @@ export default Backbone.View.extend({
},
remove() {
Backbone.View.prototype.remove.apply(this, arguments);
this.frame.remove();
this.frame = {};
Backbone.View.prototype.remove.apply(this, arguments);
return this;
},

6
src/code_manager/index.js

@ -219,6 +219,12 @@ export default () => {
for (var id in defViewers) this.addViewer(id, defViewers[id]);
return this;
},
destroy() {
[c, generators, defGenerators, viewers, defViewers].forEach(
i => (i = {})
);
}
};
};

57
src/commands/index.js

@ -32,38 +32,39 @@ import CommandAbstract from './view/CommandAbstract';
import defaults from './config/config';
import { eventDrag } from 'dom_components/model/Component';
const commandsDef = [
['preview', 'Preview', 'preview'],
['resize', 'Resize', 'resize'],
['fullscreen', 'Fullscreen', 'fullscreen'],
['copy', 'CopyComponent'],
['paste', 'PasteComponent'],
['canvas-move', 'CanvasMove'],
['canvas-clear', 'CanvasClear'],
['open-code', 'ExportTemplate', 'export-template'],
['open-layers', 'OpenLayers', 'open-layers'],
['open-styles', 'OpenStyleManager', 'open-sm'],
['open-traits', 'OpenTraitManager', 'open-tm'],
['open-blocks', 'OpenBlocks', 'open-blocks'],
['open-assets', 'OpenAssets', 'open-assets'],
['component-select', 'SelectComponent', 'select-comp'],
['component-outline', 'SwitchVisibility', 'sw-visibility'],
['component-offset', 'ShowOffset', 'show-offset'],
['component-move', 'MoveComponent', 'move-comp'],
['component-next', 'ComponentNext'],
['component-prev', 'ComponentPrev'],
['component-enter', 'ComponentEnter'],
['component-exit', 'ComponentExit', 'select-parent'],
['component-delete', 'ComponentDelete'],
['component-style-clear', 'ComponentStyleClear'],
['component-drag', 'ComponentDrag']
];
export default () => {
let em;
let c = {};
const commands = {};
const defaultCommands = {};
const active = {};
const commandsDef = [
['preview', 'Preview', 'preview'],
['resize', 'Resize', 'resize'],
['fullscreen', 'Fullscreen', 'fullscreen'],
['copy', 'CopyComponent'],
['paste', 'PasteComponent'],
['canvas-move', 'CanvasMove'],
['canvas-clear', 'CanvasClear'],
['open-code', 'ExportTemplate', 'export-template'],
['open-layers', 'OpenLayers', 'open-layers'],
['open-styles', 'OpenStyleManager', 'open-sm'],
['open-traits', 'OpenTraitManager', 'open-tm'],
['open-blocks', 'OpenBlocks', 'open-blocks'],
['open-assets', 'OpenAssets', 'open-assets'],
['component-select', 'SelectComponent', 'select-comp'],
['component-outline', 'SwitchVisibility', 'sw-visibility'],
['component-offset', 'ShowOffset', 'show-offset'],
['component-move', 'MoveComponent', 'move-comp'],
['component-next', 'ComponentNext'],
['component-prev', 'ComponentPrev'],
['component-enter', 'ComponentEnter'],
['component-exit', 'ComponentExit', 'select-parent'],
['component-delete', 'ComponentDelete'],
['component-style-clear', 'ComponentStyleClear'],
['component-drag', 'ComponentDrag']
];
// Need it here as it would be used below
const add = function(id, obj) {
@ -424,6 +425,10 @@ export default () => {
if (!command.stop) command.noStop = 1;
const cmd = CommandAbstract.extend(command);
return new cmd(c);
},
destroy() {
[em, c, commands, defaultCommands, active].forEach(i => (i = {}));
}
};
};

5
src/commands/view/CopyComponent.js

@ -2,9 +2,6 @@ export default {
run(ed) {
const em = ed.getModel();
const models = [...ed.getSelectedAll()];
if (models.length) {
em.set('clipboard', models);
}
models.length && em.set('clipboard', models);
}
};

19
src/commands/view/SelectComponent.js

@ -157,6 +157,15 @@ export default {
if (el.ownerDocument === this.currentDoc) this.elHovered = result;
});
} else {
this.currentDoc = null;
this.elHovered = 0;
this.updateToolsLocal();
this.canvas.getFrames().forEach(frame => {
const { view } = frame;
const el = view && view.getToolsEl();
el && this.toggleToolsEl(0, 0, { el });
});
}
},
@ -209,15 +218,7 @@ export default {
},
onOut() {
this.currentDoc = null;
this.em.setHovered(0);
this.elHovered = 0;
this.updateToolsLocal();
this.canvas.getFrames().forEach(frame => {
const { view } = frame;
const el = view && view.getToolsEl();
el && this.toggleToolsEl(0, 0, { el });
});
},
toggleToolsEl(on, view, opts = {}) {
@ -730,9 +731,9 @@ export default {
stop(ed, sender, opts = {}) {
const { em, editor } = this;
this.onHovered(); // force to hide toolbar
this.stopSelectComponent();
!opts.preserveSelected && em.setSelected(null);
this.onOut();
this.toggleToolsEl();
editor && editor.stopCommand('resize');
}

26
src/css_composer/index.js

@ -373,6 +373,24 @@ export default () => {
);
},
/**
* Find rules, in different states (eg. like `:hover`) and media queries, matching the selector.
* @param {string} selector Selector, eg. '.myclass'
* @returns {Array<CssRule>}
* @example
* // Common scenario, take all the component specific rules
* const id = someComponent.getId();
* const rules = cc.getRules(`#${id}`);
* console.log(rules.map(rule => rule.toCSS()))
*/
getRules(selector) {
const rules = this.getAll();
const result = rules.filter(
r => r.getSelectors().getFullString() === selector
);
return result;
},
/**
* Add/update the CSS rule with id selector
* @param {string} name Id selector name, eg. 'my-id'
@ -462,6 +480,14 @@ export default () => {
*/
render() {
return rulesView.render().el;
},
destroy() {
rules.reset();
rules.stopListening();
rulesView.remove();
[em, rules, rulesView].forEach(i => (i = null));
c = {};
}
};
};

28
src/css_composer/model/CssRule.js

@ -41,18 +41,36 @@ export default Backbone.Model.extend(Styleable).extend({
initialize(c, opt = {}) {
this.config = c || {};
this.opt = opt;
this.em = opt.em;
this.ensureSelectors();
},
clone() {
const opts = { ...this.opt };
const attr = { ...this.attributes };
attr.selectors = this.get('selectors').map(s => s.clone());
return new this.constructor(attr, opts);
},
ensureSelectors() {
const { em } = this;
const result = [];
const sm = em && em.get('SelectorManager');
const selectors = this.getSelectors();
const toInit = Array.isArray(selectors);
selectors.forEach(sel => result.push(sm ? sm.add(sel) : sel));
toInit && this.set('selectors', new Selectors(result));
const toListen = [this, 'change:selectors', this.ensureSelectors];
let sels = this.getSelectors();
this.stopListening(...toListen);
if (sels.models) {
sels = [...sels.models];
}
if (Array.isArray(sels)) {
const res = sels.filter(i => i).map(i => (sm ? sm.add(i) : i));
sels = new Selectors(res);
}
this.set('selectors', sels);
this.listenTo(...toListen);
},
/**

2
src/css_composer/model/CssRules.js

@ -16,7 +16,7 @@ export default Backbone.Collection.extend({
},
onAdd(model) {
model.ensureSelectors();
model.ensureSelectors(); // required for undo
},
onRemove(removed) {

8
src/device_manager/index.js

@ -124,6 +124,14 @@ export default () => {
*/
render() {
return view.render().el;
},
destroy() {
devices.reset();
devices.stopListening();
view.remove();
[devices, view].forEach(i => (i = null));
c = {};
}
};
};

20
src/dom_components/index.js

@ -344,12 +344,13 @@ export default () => {
const handleChanges = this.handleChanges.bind(this);
const handleRemoves = this.handleRemoves.bind(this);
um.add(coll);
[[coll, 'add', handleChanges], [coll, 'remove', handleRemoves]].forEach(
els => {
em.stopListening(els[0], els[1], els[2]);
em.listenTo(els[0], els[1], els[2]);
}
);
[
[coll, 'add', handleChanges],
[coll, 'remove', handleRemoves]
].forEach(els => {
em.stopListening(els[0], els[1], els[2]);
em.listenTo(els[0], els[1], els[2]);
});
}
},
@ -733,6 +734,13 @@ export default () => {
allById() {
return componentsById;
},
destroy() {
this.clear();
componentView.remove();
[c, em, componentsById, component, componentView].forEach(i => (i = {}));
this.em = {};
}
};
};

205
src/dom_components/model/Component.js

@ -9,9 +9,10 @@ import {
isString,
forEach,
result,
bindAll,
keys
} from 'underscore';
import { shallowDiff, capitalize } from 'utils/mixins';
import { shallowDiff, capitalize, isEmptyObj } from 'utils/mixins';
import Styleable from 'domain_abstract/model/Styleable';
import Backbone from 'backbone';
import Components from './Components';
@ -142,6 +143,7 @@ const Component = Backbone.Model.extend(Styleable).extend(
removed() {},
initialize(props = {}, opt = {}) {
bindAll(this, '__upSymbProps', '__upSymbCls', '__upSymbComps');
const em = opt.em;
// Propagate properties from parent if indicated
@ -190,6 +192,7 @@ const Component = Backbone.Model.extend(Styleable).extend(
this.listenTo(this, 'change:attributes:id', this._idUpdated);
this.set('status', '');
this.views = [];
this.__isSymbol() && this.__initSymb();
// Register global updates for collection properties
['classes', 'traits', 'components'].forEach(name => {
@ -320,6 +323,26 @@ const Component = Backbone.Model.extend(Styleable).extend(
return parent;
},
/**
* The method returns a Boolean value indicating whether the passed
* component is a descendant of a given component
* @param {Component} component Component to check
* @returns {Boolean}
*/
contains(component) {
let result = !1;
if (!component) return result;
const contains = components => {
!result &&
components.forEach(item => {
if (item === component) result = !0;
!result && contains(item.components());
});
};
contains(this.components());
return result;
},
/**
* Once the tag is updated I have to remove the node and replace it
* @private
@ -552,6 +575,95 @@ const Component = Backbone.Model.extend(Styleable).extend(
return classStr ? classStr.split(' ') : [];
},
__initSymb() {
if (this.__symbReady) return;
this.on('change', this.__upSymbProps);
this.__symbReady = 1;
},
__isSymbol() {
return isArray(this.get('__symbol'));
},
__isSymbolTop() {
const parent = this.parent();
return this.__isSymbol() && parent && !parent.__isSymbol();
},
__getSymbolOf() {
return this.get('__symbolOf');
},
__getSymbToUp() {
const symbol = this.get('__symbol');
return !this.__isSymbol()
? []
: symbol.filter(item => item.collection || item.prevColl);
},
__getSymbTop(opts) {
const isSymbol = this.__isSymbol();
let result = this;
let parent = this.parent(opts);
while (
parent &&
(isSymbol ? parent.__isSymbol() : parent.__getSymbolOf())
) {
result = parent;
parent = parent.parent(opts);
}
return result;
},
__upSymbProps() {
const changed = this.changedAttributes();
const attrs = changed.attributes || {};
delete changed.status;
delete changed.open;
delete changed.__symbol;
delete changed.__symbolOf;
delete changed.attributes;
delete attrs.id;
if (!isEmptyObj(attrs)) changed.attributes = attrs;
!isEmptyObj(changed) &&
this.__getSymbToUp().forEach(child => child.set(changed));
},
__upSymbCls() {
this.__getSymbToUp().forEach(child => {
child.set({ classes: this.get('classes') });
});
},
__upSymbComps(m, c, o) {
if (!o) {
// Reset
this.__getSymbToUp().forEach(item => {
const newMods = m.models.map(mod => mod.clone({ symbol: 1 }));
item.components().reset(newMods, c);
});
} else if (o.add) {
// Add
const addedInstances = m.__getSymbToUp();
// console.log('Added', m.getId(), m.toHTML(), o, 'toUp', addedInstances);
this.__getSymbToUp().forEach(symbInst => {
const symbTop = symbInst.__getSymbTop();
const inner = addedInstances.filter(addedInst => {
const addedTop = addedInst.__getSymbTop({ prev: 1 });
return symbTop && addedTop && addedTop === symbTop;
})[0];
const toAppend = inner || m.clone({ symbol: 1 });
// console.log('Added inner', toAppend.getId(), toAppend.toHTML(), inner);
symbInst.append(toAppend, o);
});
} else {
// Remove
m.__getSymbToUp().forEach(item => item.remove(o));
}
},
initClasses() {
const event = 'change:classes';
const attrCls = this.get('attributes').class || [];
@ -563,6 +675,7 @@ const Component = Backbone.Model.extend(Styleable).extend(
const selectors = new Selectors([]);
this.set('classes', selectors);
selectors.add(classes);
selectors.on('add remove reset', this.__upSymbCls);
this.listenTo(...toListen);
return this;
},
@ -579,7 +692,11 @@ const Component = Backbone.Model.extend(Styleable).extend(
const addChild = !this.opt.avoidChildren;
this.set('components', comps);
addChild &&
comps.add(isFunction(components) ? components(this) : components);
comps.add(
isFunction(components) ? components(this) : components,
this.opt
);
comps.on('add remove reset', this.__upSymbComps);
this.listenTo(...toListen);
return this;
},
@ -664,8 +781,8 @@ const Component = Backbone.Model.extend(Styleable).extend(
* component.parent();
* // -> Component
*/
parent() {
const coll = this.collection;
parent(opts = {}) {
const coll = this.collection || (opts.prev && this.prevColl);
return coll && coll.parent;
},
@ -788,7 +905,7 @@ const Component = Backbone.Model.extend(Styleable).extend(
*/
getTraitIndex(id) {
const trait = this.getTrait(id);
return trait ? this.get('traits').indexOf(trait) : trait;
return trait ? this.get('traits').indexOf(trait) : -1;
},
/**
@ -835,23 +952,12 @@ const Component = Backbone.Model.extend(Styleable).extend(
* @private
*/
normalizeClasses(arr) {
var res = [];
const em = this.em;
if (!em) return;
var clm = em.get('SelectorManager');
const res = [];
const { em } = this;
const clm = em && em.get('SelectorManager');
if (!clm) return;
arr.forEach(val => {
var name = '';
if (typeof val === 'string') name = val;
else name = val.name;
var model = clm.add(name);
res.push(model);
});
if (arr.models) return [...arr.models];
arr.forEach(val => res.push(clm.add(val)));
return res;
},
@ -859,19 +965,24 @@ const Component = Backbone.Model.extend(Styleable).extend(
* Override original clone method
* @private
*/
clone() {
clone(opt = {}) {
const em = this.em;
const style = this.getStyle();
const attr = { ...this.attributes };
const opts = { ...this.opt };
const id = this.getId();
const cssc = em && em.get('CssComposer');
attr.attributes = { ...attr.attributes };
delete attr.attributes.id;
attr.components = [];
attr.classes = [];
attr.traits = [];
if (this.__isSymbolTop()) {
opt.symbol = 1;
}
this.get('components').each((md, i) => {
attr.components[i] = md.clone();
attr.components[i] = md.clone({ ...opt, _inner: 1 });
});
this.get('traits').each((md, i) => {
attr.traits[i] = md.clone();
@ -884,11 +995,29 @@ const Component = Backbone.Model.extend(Styleable).extend(
attr.view = '';
opts.collection = null;
if (em && em.getConfig('avoidInlineStyle') && !isEmpty(style)) {
attr.style = style;
const cloned = new this.constructor(attr, opts);
// Clone component specific rules
const newId = `#${cloned.getId()}`;
const rulesToClone = cssc ? cssc.getRules(`#${id}`) : [];
rulesToClone.forEach(rule => {
const newRule = rule.clone();
newRule.set('selectors', [newId]);
cssc.getAll().add(newRule);
});
// Symbols
// If I clone an inner symbol, I have to reset it
cloned.unset('__symbol');
if (opt.symbol) {
// TODO Check if trying to clone a Symbol (check if parent is symbol)
const symbols = this.get('__symbol') || [];
symbols.push(cloned);
this.set('__symbol', symbols);
this.__initSymb();
cloned.set('__symbolOf', this);
}
const cloned = new this.constructor(attr, opts);
const event = 'component:clone';
em && em.trigger(event, cloned);
this.trigger(event, cloned);
@ -1021,12 +1150,22 @@ const Component = Backbone.Model.extend(Styleable).extend(
* @return {Object}
* @private
*/
toJSON(...args) {
const obj = Backbone.Model.prototype.toJSON.apply(this, args);
toJSON(opts = {}) {
const obj = Backbone.Model.prototype.toJSON.call(this, opts);
obj.attributes = this.getAttributes();
delete obj.attributes.class;
delete obj.toolbar;
delete obj.traits;
delete obj.status;
if (!opts.keepSymbols) {
if (obj.__symbol) {
obj.__symbol = this.__getSymbToUp().map(i => i.getId());
}
if (obj.__symbolOf) {
obj.__symbolOf = obj.__symbolOf.getId();
}
}
if (this.em.getConfig('avoidDefaults')) {
this.getChangedProps(obj);
@ -1043,7 +1182,7 @@ const Component = Backbone.Model.extend(Styleable).extend(
const defaults = result(this, 'defaults');
forEach(defaults, (value, key) => {
if (['type', 'content'].indexOf(key) === -1 && obj[key] === value) {
if (['type'].indexOf(key) === -1 && obj[key] === value) {
delete obj[key];
}
});
@ -1195,9 +1334,9 @@ const Component = Backbone.Model.extend(Styleable).extend(
* Remove the component
* @return {this}
*/
remove() {
remove(opts = {}) {
const coll = this.collection;
return coll && coll.remove(this);
return coll && coll.remove(this, opts);
},
/**
@ -1238,7 +1377,7 @@ const Component = Backbone.Model.extend(Styleable).extend(
const list = Component.getList(this);
// If the ID already exists I need to rollback to the old one
if (list[id]) {
if (list[id] || (!id && idPrev)) {
return this.setId(idPrev, { idUpdate: 1 });
}

60
src/dom_components/model/Components.js

@ -6,14 +6,27 @@ import {
each,
includes,
extend,
flatten
flatten,
debounce
} from 'underscore';
let Component;
const getIdsToKeep = prev => {
const getIdsToKeep = (prev, res = []) => {
const pr = prev || [];
return pr.map(comp => comp.getId());
pr.forEach(comp => {
res.push(comp.getId());
getIdsToKeep(comp.components(), res);
});
return res;
};
const getNewIds = (items, res = []) => {
items.map(item => {
res.push(item.getId());
getNewIds(item.components(), res);
});
return res;
};
export default Backbone.Collection.extend({
@ -31,7 +44,7 @@ export default Backbone.Collection.extend({
const coll = this;
const prev = opts.previousModels || [];
const toRemove = prev.filter(prev => !models.get(prev.cid));
const newIds = models.map(i => i.getId());
const newIds = getNewIds(models);
opts.keepIds = getIdsToKeep(prev).filter(pr => newIds.indexOf(pr) >= 0);
toRemove.forEach(md => this.removeChildren(md, coll, opts));
models.each(model => this.onAdd(model));
@ -46,8 +59,10 @@ export default Backbone.Collection.extend({
const { domc, em } = this;
const allByID = domc ? domc.allById() : {};
const isTemp = opts.temporary;
removed.prevColl = this; // This one is required for symbols
if (!opts.temporary) {
if (!isTemp) {
// Remove the component from the global list
const id = removed.getId();
const sels = em.get('SelectorManager').getAll();
@ -159,8 +174,9 @@ export default Backbone.Collection.extend({
.filter(i => i)
.map(model => this.processDef(model));
models = isMult ? flatten(models, 1) : models[0];
return Backbone.Collection.prototype.add.apply(this, [models, opt]);
const result = Backbone.Collection.prototype.add.apply(this, [models, opt]);
this.__firstAdd = result;
return result;
},
/**
@ -235,5 +251,33 @@ export default Backbone.Collection.extend({
model.setStyle({});
model.addClass(name);
}
}
this.__onAddEnd();
},
__onAddEnd: debounce(function() {
const { domc } = this;
const allComp = (domc && domc.allById()) || {};
const firstAdd = this.__firstAdd;
const toCheck = isArray(firstAdd) ? firstAdd : [firstAdd];
const silent = { silent: true };
const onAll = comps => {
comps.forEach(comp => {
const symbol = comp.get('__symbol');
const symbolOf = comp.get('__symbolOf');
if (symbol && isArray(symbol) && isString(symbol[0])) {
comp.set(
'__symbol',
symbol.map(smb => allComp[smb]).filter(i => i),
silent
);
}
if (isString(symbolOf)) {
comp.set('__symbolOf', allComp[symbolOf], silent);
}
onAll(comp.components());
});
};
onAll(toCheck);
})
});

2
src/dom_components/view/ComponentTextView.js

@ -131,8 +131,6 @@ export default ComponentView.extend({
model.get('components').each(model => clean(model));
};
// Avoid re-render on reset with silent option
!opts.silent && model.trigger('change:content', model, '', contentOpt);
comps.reset(content, opts);
comps.each(model => clean(model));
comps.trigger('resetNavigator');

5
src/domain_abstract/ui/Input.js

@ -68,13 +68,14 @@ export default Backbone.View.extend({
*/
getInputEl() {
if (!this.inputEl) {
const { model } = this;
const { model, opts } = this;
const type = opts.type || 'text';
const plh =
model.get('placeholder') ||
model.get('defaults') ||
model.get('default') ||
'';
this.inputEl = $(`<input type="text" placeholder="${plh}">`);
this.inputEl = $(`<input type="${type}" placeholder="${plh}">`);
}
return this.inputEl.get(0);

5
src/domain_abstract/ui/InputColor.js

@ -28,6 +28,11 @@ export default Input.extend({
return `${this.ppfx}input-holder`;
},
remove() {
Input.prototype.remove.apply(this, arguments);
this.colorEl.spectrum('destroy');
},
/**
* Set value to the model
* @param {string} val

26
src/domain_abstract/ui/InputNumber.js

@ -11,7 +11,8 @@ export default Input.extend({
'change select': 'handleUnitChange',
'click [data-arrow-up]': 'upArrowClick',
'click [data-arrow-down]': 'downArrowClick',
'mousedown [data-arrows]': 'downIncrement'
'mousedown [data-arrows]': 'downIncrement',
keydown: 'handleKeyDown'
},
template() {
@ -81,6 +82,21 @@ export default Input.extend({
this.elementUpdated();
},
/**
* Handled when user uses keyboard
*/
handleKeyDown(e) {
if (e.key === 'ArrowUp') {
e.preventDefault();
this.upArrowClick();
}
if (e.key === 'ArrowDown') {
e.preventDefault();
this.downArrowClick();
}
},
/**
* Fired when the element of the property is updated
*/
@ -235,6 +251,8 @@ export default Input.extend({
var unit = model.get('unit') || (units.length && units[0]) || '';
var max = model.get('max');
var min = model.get('min');
var limitlessMax = !!model.get('limitlessMax');
var limitlessMin = !!model.get('limitlessMin');
if (opt.deepCheck) {
var fixed = model.get('fixedValues') || [];
@ -258,8 +276,10 @@ export default Input.extend({
}
}
if (!isUndefined(max) && max !== '') val = val > max ? max : val;
if (!isUndefined(min) && min !== '') val = val < min ? min : val;
if (!limitlessMax && !isUndefined(max) && max !== '')
val = val > max ? max : val;
if (!limitlessMax && !isUndefined(min) && min !== '')
val = val < min ? min : val;
return {
force,

25
src/editor/model/Editor.js

@ -750,29 +750,18 @@ export default Backbone.Model.extend({
const { config } = this;
const editor = this.getEditor();
const { editors = [] } = config.grapesjs || {};
const {
DomComponents,
CssComposer,
UndoManager,
Panels,
Canvas,
Keymaps,
RichTextEditor,
LayerManager
} = this.attributes;
this.stopDefault();
DomComponents.clear();
CssComposer.clear();
UndoManager.clear().removeAll();
Panels.getPanels().reset();
Canvas.getCanvasView().remove();
Keymaps.removeAll();
RichTextEditor.destroy();
LayerManager.destroy();
this.get('modules')
.slice()
.reverse()
.forEach(mod => mod.destroy());
this.view.remove();
this.stopListening();
this.clear({ silent: true });
this.destroyed = 1;
['config', 'view', '_previousAttributes', '_events', '_listeners'].forEach(
i => (this[i] = {})
);
editors.splice(editors.indexOf(editor), 1);
$(config.el)
.empty()

5
src/i18n/index.js

@ -242,6 +242,11 @@ export default () => {
_debug(str, opts = {}) {
const { em, config } = this;
(opts.debug || config.debug) && em && em.logWarning(str);
},
destroy() {
this.config = config;
this.em = {};
}
};
};

198
src/i18n/locale/ca.js

@ -0,0 +1,198 @@
const traitInputAttr = { placeholder: 'ex. Text aquí' };
export default {
assetManager: {
addButton: 'Afegir imatge',
inputPlh: 'http://ruta/a/la/imatge.jpg',
modalTitle: 'Escollir imatge',
uploadTitle: 'Arrossega els fitxers aquí o fes clic per a pujar-ne'
},
// Here just as a reference, GrapesJS core doesn't contain any block,
// so this should be omitted from other local files
blockManager: {
labels: {
// 'block-id': 'Block Label',
},
categories: {
// 'category-id': 'Category Label',
}
},
domComponents: {
names: {
'': 'Capsa',
wrapper: 'Cos',
text: 'Text',
comment: 'Comentari',
image: 'Imatge',
video: 'Vídeo',
label: 'Etiqueta',
link: 'Enllaç',
map: 'Mapa',
tfoot: 'Peu de la taula',
tbody: 'Cos de la taula',
thead: 'Capçalera de la taula',
table: 'Taula',
row: 'Fila de la taula',
cell: 'Cel·la de la taula'
}
},
deviceManager: {
device: 'Dispositius',
devices: {
desktop: 'Escriptori',
tablet: 'Tauleta',
mobileLandscape: 'Mòbil en horitzontal',
mobilePortrait: 'Mòbil en vertical'
}
},
panels: {
buttons: {
titles: {
preview: 'Vista prèvia',
fullscreen: 'Pantalla sencera',
'sw-visibility': 'Veure components',
'export-template': 'Veure codi',
'open-sm': 'Obrir Administrador d\'estils',
'open-tm': 'Configuració',
'open-layers': 'Obrir Aministrador de capes',
'open-blocks': 'Obrir Blocs'
}
}
},
selectorManager: {
label: 'Classes',
selected: 'Seleccionat',
emptyState: '- Estat -',
states: {
hover: 'A sobre',
active: 'Clic',
'nth-of-type(2n)': 'Parell/Senar'
}
},
styleManager: {
empty: 'Escull un element abans d\'utilitzar l\'Administrador d\'estils',
layer: 'Capa',
fileButton: 'Imatges',
sectors: {
general: 'General',
layout: 'Disseny',
typography: 'Tipografia',
decorations: 'Decoracions',
extra: 'Extres',
flex: 'Flex',
dimension: 'Tamany'
},
// The core library generates the name by their `property` name
properties: {
float: 'Flotant',
display: 'Vista',
position: 'Posició',
top: 'Superior',
right: 'Dreta',
left: 'Esquerra',
bottom: 'Inferior',
width: 'Ample',
height: 'Alt',
'max-width': 'Ample màx.',
'max-height': 'Alt màx.',
margin: 'Marge',
'margin-top': 'Marge superior',
'margin-right': 'Marge dret',
'margin-left': 'Marge esquerra',
'margin-bottom': 'Marge inferior',
padding: 'Padding',
'padding-top': 'Padding superior',
'padding-left': 'Padding esquerra',
'padding-right': 'Padding dret',
'padding-bottom': 'Padding inferior',
'font-family': 'Tipus de lletra',
'font-size': 'Tamany de la font',
'font-weight': 'Pes',
'letter-spacing': 'Espai entre lletres',
color: 'Color',
'line-height': 'Interlineat',
'text-align': 'Alineació del text',
'text-shadow': 'Ombra del text',
'text-shadow-h': 'Ombra del text: horizontal',
'text-shadow-v': 'Ombra del text: vertical',
'text-shadow-blur': 'Desenfocament de l\'ombra del text',
'text-shadow-color': 'Color de l\'ombra del text',
'border-top-left': 'Marc superior esquerra',
'border-top-right': 'Marc superior dret',
'border-bottom-left': 'Marc inferior esquerra',
'border-bottom-right': 'Marc inferior dret',
'border-radius-top-left': 'Radi del marc superior esquerra',
'border-radius-top-right': 'Radi del marc superior dret',
'border-radius-bottom-left': 'Radi del marc inferior esquerra',
'border-radius-bottom-right': 'Radi del marc inferior dret',
'border-radius': 'Radi del marc',
border: 'Marc',
'border-width': 'Ample del marc',
'border-style': 'Estil del marc',
'border-color': 'Color del marc',
'box-shadow': 'Ombra de la capsa',
'box-shadow-h': 'Ombra de la capsa: horizontal',
'box-shadow-v': 'Ombra de la capsa: vertical',
'box-shadow-blur': 'Desenfocament de l\'ombra de la capsa',
'box-shadow-spread': 'Propagació de l\'ombra de la capsa',
'box-shadow-color': 'Color de l\'ombra de la capsa',
'box-shadow-type': 'Tipus de l\'ombra de la capsa',
background: 'Fons',
'background-image': 'Imatge de fons',
'background-repeat': 'Repetir fons',
'background-position': 'Posició del fons',
'background-attachment': 'Desplaçament del fons',
'background-size': 'Tamany del fons',
transition: 'Transició',
'transition-property': 'Tipus de transició',
'transition-duration': 'Temps de transició',
'transition-timing-function': 'Funció de temps de la transición',
perspective: 'Perspectiva',
transform: 'Transformació',
'transform-rotate-x': 'Rotació horitzontal',
'transform-rotate-y': 'Rotació vertical',
'transform-rotate-z': 'Rotació profunditat',
'transform-scale-x': 'Escalar horitzontalment',
'transform-scale-y': 'Escalar verticalment',
'transform-scale-z': 'Escalar profunditat',
'flex-direction': 'Direcció flex',
'flex-wrap': 'Distribució flex',
'justify-content': 'Justificar contingut',
'align-items': 'Alinear elements',
'align-content': 'Alinear contingut',
order: 'Ordre',
'flex-basis': 'Base flex',
'flex-grow': 'Creixement flex',
'flex-shrink': 'Contracció flex',
'align-self': 'Alineació pròpia',
'background-color': 'Color de fons'
}
},
traitManager: {
empty: 'Escull un element abans d\'usar l\'Administrador de característiques',
label: 'Configuració de components',
traits: {
// The core library generates the name by their `name` property
labels: {
id: 'Identificador',
alt: 'Títol alternatiu',
title: 'Títol',
href: 'Enllaç'
},
// In a simple trait, like text input, these are used on input attributes
attributes: {
id: traitInputAttr,
alt: traitInputAttr,
title: traitInputAttr,
href: { placeholder: 'ex. https://google.com' }
},
// In a trait like select, these are used to translate option names
options: {
target: {
false: 'Mateixa pestanya/finestra',
_blank: 'Nova pestanya/finestra'
}
}
}
}
};

8
src/keymaps/index.js

@ -200,7 +200,7 @@ export default () => {
if (keymap) {
delete keymaps[id];
keymaster.unbind(keymap.keys);
keymap.keys.split(', ').forEach(k => keymaster.unbind(k.trim()));
em && em.trigger('keymap:remove', keymap);
return keymap;
}
@ -213,6 +213,12 @@ export default () => {
removeAll() {
Object.keys(keymaps).forEach(keymap => this.remove(keymap));
return this;
},
destroy() {
this.removeAll();
[em, config, keymaps].forEach(i => (i = {}));
this.em = {};
}
};
};

6
src/modal_dialog/index.js

@ -202,6 +202,12 @@ export default () => {
*/
render() {
return modal.render().$el;
},
destroy() {
modal.remove();
[c, model, modal].forEach(i => (i = {}));
this.em = {};
}
};
};

3
src/navigator/index.js

@ -99,7 +99,8 @@ export default () => {
},
destroy() {
return layers && layers.remove();
layers && layers.remove();
[em, layers, config].forEach(i => (i = {}));
}
};
};

7
src/navigator/view/ItemView.js

@ -15,6 +15,7 @@ export default Backbone.View.extend({
'click [data-toggle-visible]': 'toggleVisibility',
'click [data-toggle-select]': 'handleSelect',
'mouseover [data-toggle-select]': 'handleHover',
'mouseout [data-toggle-select]': 'handleHoverOut',
'click [data-toggle-open]': 'toggleOpening',
'dblclick [data-name]': 'handleEdit',
'focusout [data-name]': 'handleEditEnd'
@ -249,6 +250,12 @@ export default Backbone.View.extend({
em && config.showHover && em.setHovered(model, { fromLayers: 1 });
},
handleHoverOut(ev) {
ev.stopPropagation();
const { em, config } = this;
em && config.showHover && em.setHovered(0, { fromLayers: 1 });
},
/**
* Delegate to sorter
* @param Event

8
src/panels/index.js

@ -28,7 +28,6 @@
import defaults from './config/config';
import Panel from './model/Panel';
import Panels from './model/Panels';
import PanelView from './view/PanelView';
import PanelsView from './view/PanelsView';
export default () => {
@ -233,6 +232,13 @@ export default () => {
});
},
destroy() {
panels.reset();
panels.stopListening();
PanelsViewObj.remove();
[c, panels, PanelsViewObj].forEach(i => (i = {}));
},
Panel
};
};

20
src/panels/view/ButtonView.js

@ -89,6 +89,8 @@ export default Backbone.View.extend({
const commandName = model.get('command');
let command = {};
if (!commandName) return;
if (commands && isString(commandName)) {
command = commands.get(commandName) || {};
} else if (isFunction(commandName)) {
@ -133,15 +135,16 @@ export default Backbone.View.extend({
* @return void
* */
clicked(e) {
if (this.model.get('bntsVis')) return;
const { model } = this;
if (this.model.get('disable')) return;
if (model.get('bntsVis') || model.get('disable') || !model.get('command'))
return;
this.toggleActive();
},
toggleActive() {
const { model } = this;
const { model, em } = this;
const { active, togglable } = model.attributes;
if (active && !togglable) return;
@ -149,19 +152,18 @@ export default Backbone.View.extend({
model.set('active', !active);
// If the stop is requested
var command = this.em.get('Commands').get('select-comp');
if (active) {
if (model.get('runDefaultCommand')) this.em.runDefault();
if (model.get('runDefaultCommand')) em.runDefault();
} else {
if (model.get('stopDefaultCommand')) this.em.stopDefault();
if (model.get('stopDefaultCommand')) em.stopDefault();
}
},
render() {
const label = this.model.get('label');
const { model } = this;
const label = model.get('label');
const { $el } = this;
$el.empty();
!model.get('el') && $el.empty();
this.updateAttributes();
label && $el.append(label);
this.checkActive();

11
src/panels/view/ButtonsView.js

@ -31,15 +31,16 @@ export default Backbone.View.extend({
* @return Object Object created
* */
addToCollection(model, fragmentEl) {
var fragment = fragmentEl || null;
var viewObject = ButtonView;
var view = new viewObject({
const fragment = fragmentEl || null;
const viewObject = ButtonView;
const el = model.get('el');
const view = new viewObject({
el,
model,
config: this.config,
parentM: this.parentM
});
var rendered = view.render().el;
const rendered = view.render().el;
if (fragment) {
fragment.appendChild(rendered);

5
src/parser/index.js

@ -72,6 +72,11 @@ export default () => {
*/
parseCss(str) {
return pCss.parse(str);
},
destroy() {
[conf, pHtml, pCss].forEach(i => (i = {}));
['em', 'parserCss', 'parserHtml'].forEach(i => (this[i] = {}));
}
};
};

2
src/parser/model/ParserHtml.js

@ -202,7 +202,7 @@ export default config => {
// just make it content of the current node
if (nodeChild === 1 && firstChild.nodeType === 3) {
!model.type && (model.type = 'text');
model.content = firstChild.nodeValue;
model.components = firstChild.nodeValue;
} else {
model.components = this.parseNode(node);
}

5
src/rich_text_editor/index.js

@ -87,10 +87,11 @@ export default () => {
const { customRte } = this;
globalRte && globalRte.destroy();
customRte && customRte.destroy && customRte.destroy();
toolbar = 0;
globalRte = 0;
this.actionbar = 0;
this.actions = 0;
[config, toolbar, actions, lastEl, lastElPos, globalRte].forEach(
i => (i = {})
);
},
/**

9
src/selector_manager/index.js

@ -312,6 +312,15 @@ export default config => {
});
return this.selectorTags.render().el;
} else return this.selectorTags.render().el;
},
destroy() {
selectors.reset();
selectors.stopListening();
this.selectorTags.remove();
[c, selectors].forEach(i => (i = {}));
this.em = {};
this.selectorTags = {};
}
};
};

35
src/selector_manager/model/Selector.js

@ -1,9 +1,11 @@
import Backbone from 'backbone';
import { result, forEach, keys } from 'underscore';
const TYPE_CLASS = 1;
const TYPE_ID = 2;
const { Model } = Backbone;
const Selector = Backbone.Model.extend(
const Selector = Model.extend(
{
idAttribute: 'name',
@ -43,6 +45,7 @@ const Selector = Backbone.Model.extend(
? escapeName(namePreEsc)
: Selector.escapeName(namePreEsc);
this.set('name', nameEsc);
this.em = config.em;
},
/**
@ -64,6 +67,36 @@ const Selector = Backbone.Model.extend(
}
return init + (escape ? escape(name) : name);
},
toJSON(opts = {}) {
const { em } = this;
let obj = Model.prototype.toJSON.call(this, [opts]);
const defaults = result(this, 'defaults');
if (em && em.getConfig('avoidDefaults')) {
forEach(defaults, (value, key) => {
if (obj[key] === value) {
delete obj[key];
}
});
if (obj.label === obj.name) {
delete obj.label;
}
const objLen = keys(obj).length;
if (objLen === 1 && obj.name) {
obj = obj.name;
}
if (objLen === 2 && obj.name && obj.type) {
obj = this.getFullName();
}
}
return obj;
}
},
{

11
src/storage_manager/index.js

@ -36,14 +36,15 @@ import defaults from './config/config';
import LocalStorage from './model/LocalStorage';
import RemoteStorage from './model/RemoteStorage';
const eventStart = 'storage:start';
const eventEnd = 'storage:end';
const eventError = 'storage:error';
export default () => {
var c = {};
let em;
var storages = {};
var defaultStorages = {};
const eventStart = 'storage:start';
const eventEnd = 'storage:end';
const eventError = 'storage:error';
return {
/**
@ -331,6 +332,10 @@ export default () => {
canAutoload() {
const storage = this.getCurrentStorage();
return storage && this.getConfig().autoload;
},
destroy() {
[c, em, storages, defaultStorages].forEach(i => (i = {}));
}
};
};

10
src/style_manager/index.js

@ -414,6 +414,16 @@ export default () => {
_logNoSector(sectorId) {
const { em } = this;
em && em.logWarning(`'${sectorId}' sector not found`);
},
destroy() {
[properties, sectors].forEach(coll => {
coll.reset();
coll.stopListening();
});
SectView.remove();
[c, properties, sectors, SectView].forEach(i => (i = {}));
this.em = {};
}
};
};

11
src/style_manager/model/Sectors.js

@ -2,5 +2,14 @@ import Backbone from 'backbone';
import Sector from './Sector';
export default Backbone.Collection.extend({
model: Sector
model: Sector,
initialize() {
this.listenTo(this, 'reset', this.onReset);
},
onReset(models, opts = {}) {
const prev = opts.previousModels || [];
prev.forEach(sect => sect.get('properties').reset());
}
});

6
src/style_manager/view/PropertyColorView.js

@ -7,6 +7,12 @@ export default PropertyIntegerView.extend({
this.inputInst.setValue(value, opts);
},
remove() {
PropertyIntegerView.prototype.remove.apply(this, arguments);
this.inputInst.remove();
['inputInst', '$color'].forEach(i => (this[i] = {}));
},
onRender() {
if (!this.input) {
const ppfx = this.ppfx;

6
src/style_manager/view/PropertyCompositeView.js

@ -27,6 +27,12 @@ export default PropertyView.extend({
PropertyView.prototype.clear.apply(this, arguments);
},
remove() {
this.model.get('properties').reset();
PropertyView.prototype.remove.apply(this, arguments);
['properties', 'props', '$props'].forEach(i => (this[i] = {}));
},
/**
* Renders input
* */

4
src/style_manager/view/PropertyStackView.js

@ -191,7 +191,7 @@ export default PropertyCompositeView.extend({
const layers = this.getLayers();
const detached = model.get('detached');
const property = model.get('property');
const target = this.getTarget();
const target = this.getFirstTarget();
const valueComput = this.getComputedValue();
const selected = em.getSelected();
const updateOpts = { fromTarget: 1 };
@ -281,7 +281,7 @@ export default PropertyCompositeView.extend({
getTargetValue(opts = {}) {
const { model } = this;
const { detached } = model.attributes;
const target = this.getTarget();
const target = this.getFirstTarget();
let result = PropertyCompositeView.prototype.getTargetValue.call(
this,
opts

15
src/style_manager/view/PropertyView.js

@ -95,6 +95,9 @@ export default Backbone.View.extend({
remove() {
Backbone.View.prototype.remove.apply(this, arguments);
['em', 'target', 'input', '$input', 'propTarget', 'sector'].forEach(
i => (this[i] = {})
);
this.__destroyFn(this._getClbOpts());
},
@ -167,6 +170,10 @@ export default Backbone.View.extend({
return targets || [this.getTarget()];
},
getFirstTarget() {
return this.getTargets()[0];
},
/**
* Returns Styleable model
* @return {Model|null}
@ -209,7 +216,7 @@ export default Backbone.View.extend({
emitUpdateTarget: debounce(function() {
const em = this.config.em;
em && em.trigger('styleManager:update:target', this.getTarget());
em && em.trigger('styleManager:update:target', this.getFirstTarget());
}),
_getTargetData() {
@ -342,7 +349,7 @@ export default Backbone.View.extend({
getTargetValue(opts = {}) {
let result;
const { model } = this;
const target = this.getTargetModel();
const target = this.getFirstTarget();
const customFetchValue = this.customValue;
if (!target) {
@ -460,7 +467,7 @@ export default Backbone.View.extend({
*/
updateTargetStyle(value, name = '', opts = {}) {
const property = name || this.model.get('property');
const target = opts.target || this.getTarget();
const target = opts.target || this.getFirstTarget();
const style = target.getStyle();
if (value) {
@ -489,7 +496,7 @@ export default Backbone.View.extend({
* @return {Boolean}
*/
isTargetStylable(target) {
const trg = target || this.getTarget();
const trg = target || this.getFirstTarget();
const model = this.model;
const id = model.get('id');
const property = model.get('property');

12
src/style_manager/view/SectorsView.js

@ -31,6 +31,11 @@ export default Backbone.View.extend({
this.listenTo(this.target, events, this.targetUpdated);
},
remove() {
Backbone.View.prototype.remove.apply(this, arguments);
['target', 'config', 'propTarget'].forEach(i => (this[i] = {}));
},
/**
* Add to collection
* @param {Object} model Model
@ -95,7 +100,8 @@ export default Backbone.View.extend({
pt.helper = helperRule;
};
model = em.get('StyleManager').getModelToStyle(model);
const sm = em.get('StyleManager');
model = sm.getModelToStyle(model);
if (state) {
appendStateRule(model.getStyle());
@ -103,7 +109,9 @@ export default Backbone.View.extend({
}
pt.model = model;
if (componentFirst) pt.targets = targets;
if (componentFirst) {
pt.targets = targets.map(t => sm.getModelToStyle(t)).filter(Boolean);
}
pt.trigger('update');
},

10
src/styles/scss/_gjs_inputs.scss

@ -68,6 +68,16 @@
}
}
input[type=number] {
-moz-appearance: textfield;
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
&-range {
flex: 9 1 auto;
}

6
src/styles/scss/main.scss

@ -1,7 +1,7 @@
/* stylelint-disable */
@import "../../../node_modules/spectrum-colorpicker/spectrum";
@import "../../../node_modules/codemirror/lib/codemirror";
@import "../../../node_modules/codemirror/theme/hopscotch";
@import "spectrum-colorpicker/spectrum";
@import "codemirror/lib/codemirror";
@import "codemirror/theme/hopscotch";
@import "gjs_variables.scss";

5
src/trait_manager/index.js

@ -81,6 +81,11 @@ export default () => {
render() {
return TraitsViewer.render().el;
},
destroy() {
TraitsViewer.remove();
[c, TraitsViewer].forEach(i => (i = {}));
}
};
};

14
src/trait_manager/view/TraitNumberView.js

@ -18,16 +18,18 @@ export default TraitView.extend({
*/
getInputEl() {
if (!this.input) {
var value = this.getModelValue();
var inputNumber = new InputNumber({
contClass: this.ppfx + 'field-int',
model: this.model,
ppfx: this.ppfx
const { ppfx, model } = this;
const value = this.getModelValue();
const inputNumber = new InputNumber({
contClass: `${ppfx}field-int`,
type: 'number',
model: model,
ppfx
});
this.input = inputNumber.render();
this.$input = this.input.inputEl;
this.$unit = this.input.unitEl;
this.model.set('value', value, { fromTarget: 1 });
model.set('value', value, { fromTarget: 1 });
this.$input.val(value);
this.input = inputNumber.el;
}

8
src/undo_manager/index.js

@ -81,7 +81,7 @@ export default () => {
const result = {
object,
before: beforeCache,
after: object.toJSON()
after: object.toJSON({ keepSymbols: 1 })
};
beforeCache = null;
return result;
@ -293,6 +293,12 @@ export default () => {
getInstance() {
return um;
},
destroy() {
this.clear().removeAll();
[em, um, config, beforeCache].forEach(i => (i = {}));
this.em = {};
}
};
};

2
src/utils/index.js

@ -18,6 +18,8 @@ export default () => {
return this;
},
destroy() {},
Sorter,
Resizer,
Dragger

2
src/utils/mixins.js

@ -212,6 +212,7 @@ const getKeyChar = ev => String.fromCharCode(getKeyCode(ev));
const isEscKey = ev => getKeyCode(ev) === 27;
const isObject = val =>
val !== null && !Array.isArray(val) && typeof val === 'object';
const isEmptyObj = val => Object.keys(val).length <= 0;
const capitalize = str => str && str.charAt(0).toUpperCase() + str.substring(1);
const isComponent = obj => obj && obj.toHTML;
@ -245,6 +246,7 @@ export {
setViewEl,
appendStyles,
isObject,
isEmptyObj,
isComponent,
isRule
};

11
test/specs/css_composer/e2e/CssComposer.js

@ -128,16 +128,7 @@ describe('E2E tests', () => {
// ruleOut is a Model
ruleOut = JSON.parse(JSON.stringify(ruleOut));
var ruleResult = {
selectors: [
{
active: true,
label: 'test1',
name: 'test1',
type: clsm.Selector.TYPE_CLASS,
private: false,
protected: false
}
],
selectors: ['test1'],
style: {
color: 'red',
width: '10px'

6
test/specs/dom_components/model/Component.js

@ -274,9 +274,9 @@ describe('Component', () => {
});
test('setAttributes overwrites correctly', () => {
obj.setAttributes({ id: 'test', 'data-test': 'value', a: 'b' });
obj.setAttributes({ 'data-test': 'value2' });
expect(obj.getAttributes()).toEqual({ 'data-test': 'value2' });
obj.setAttributes({ id: 'test', 'data-test': 'value', a: 'b', b: 'c' });
obj.setAttributes({ id: 'test2', 'data-test': 'value2' });
expect(obj.getAttributes()).toEqual({ id: 'test2', 'data-test': 'value2' });
});
test('append() returns always an array', () => {

17
test/specs/editor/index.js

@ -4,9 +4,10 @@ const { keys } = Object;
const initComps = 1;
describe('Editor', () => {
const editor = new Editor();
let editor;
beforeEach(() => {
editor = new Editor();
editor.init();
});
@ -47,8 +48,8 @@ describe('Editor', () => {
test('Components are correctly tracked on add', () => {
const all = editor.Components.allById();
const wrapper = editor.getWrapper();
wrapper.append('<div>Component</div>');
expect(keys(all).length).toBe(1 + initComps);
wrapper.append('<div>Component</div>'); // Div component + textnode
expect(keys(all).length).toBe(2 + initComps);
});
test('Components are correctly tracked on add and remove', () => {
@ -58,13 +59,13 @@ describe('Editor', () => {
<div>Component 1</div>
<div></div>
`);
expect(keys(all).length).toBe(2 + initComps);
expect(keys(all).length).toBe(3 + initComps);
const secComp = added[1];
secComp.append(`
<div>Component 2</div>
<div>Component 3</div>
`);
expect(keys(all).length).toBe(4 + initComps);
expect(keys(all).length).toBe(7 + initComps);
wrapper.empty();
expect(wrapper.components().length).toBe(0);
expect(keys(all).length).toBe(initComps);
@ -83,7 +84,7 @@ describe('Editor', () => {
expect(umStack.length).toBe(2);
expect(keys(all).length).toBe(initComps);
um.undo(false);
expect(keys(all).length).toBe(1 + initComps);
expect(keys(all).length).toBe(2 + initComps);
});
test('Components are correctly tracked with UndoManager and mutiple operations', () => {
@ -98,7 +99,7 @@ describe('Editor', () => {
<div>Component 2</div>
</div>`);
expect(umStack.length).toBe(1); // UM counts first children
expect(keys(all).length).toBe(3 + initComps);
expect(keys(all).length).toBe(5 + initComps);
wrapper
.components()
.at(0)
@ -108,7 +109,7 @@ describe('Editor', () => {
// 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);
expect(keys(all).length).toBe(3 + initComps);
wrapper.empty();
expect(umStack.length).toBe(4);
expect(keys(all).length).toBe(initComps);

2
test/specs/grapesjs/index.js

@ -85,7 +85,7 @@ describe('GrapesJS', () => {
expect(editor.getStyle().length).toEqual(0);
});
test.only('Editor canvas baseCSS can be overwritten', () => {
test('Editor canvas baseCSS can be overwritten', () => {
config.components = htmlString;
config.baseCss = '#wrapper { background-color: #eee; }';
config.protectedCss = '';

2
test/specs/panels/view/ButtonView.js

@ -8,7 +8,7 @@ describe('ButtonView', () => {
var btnClass = 'btn';
beforeEach(() => {
model = new Button();
model = new Button({ command: 'fake-command' });
view = new ButtonView({
model: model
});

32
test/specs/parser/model/ParserHtml.js

@ -130,7 +130,7 @@ describe('ParserHtml', () => {
tagName: 'div',
attributes: { id: 'test1' },
type: 'text',
content: 'test2 '
components: 'test2 '
}
];
expect(obj.parse(str).html).toEqual(result);
@ -158,7 +158,7 @@ describe('ParserHtml', () => {
tagName: ''
},
{
content: 'b',
components: 'b',
type: 'text',
tagName: 'b'
},
@ -168,7 +168,7 @@ describe('ParserHtml', () => {
tagName: ''
},
{
content: 'i',
components: 'i',
tagName: 'i',
type: 'text'
},
@ -178,7 +178,7 @@ describe('ParserHtml', () => {
tagName: ''
},
{
content: 'u',
components: 'u',
tagName: 'u',
type: 'text'
},
@ -208,7 +208,7 @@ describe('ParserHtml', () => {
tagName: ''
},
{
content: 'b',
components: 'b',
tagName: 'b',
type: 'text'
},
@ -218,7 +218,7 @@ describe('ParserHtml', () => {
tagName: ''
},
{
content: 'i',
components: 'i',
tagName: 'i',
type: 'text'
},
@ -230,7 +230,7 @@ describe('ParserHtml', () => {
{
tagName: 'div',
type: 'text',
content: 'ABC'
components: 'ABC'
},
{
content: ' ',
@ -238,7 +238,7 @@ describe('ParserHtml', () => {
tagName: ''
},
{
content: 'i',
components: 'i',
tagName: 'i',
type: 'text'
},
@ -248,7 +248,7 @@ describe('ParserHtml', () => {
tagName: ''
},
{
content: 'u',
components: 'u',
tagName: 'u',
type: 'text'
},
@ -313,7 +313,7 @@ describe('ParserHtml', () => {
{
tagName: 'div',
type: 'text',
content: 'nested'
components: 'nested'
},
{
tagName: '',
@ -343,7 +343,7 @@ describe('ParserHtml', () => {
{
tagName: 'span',
type: 'text',
content: 'nested'
components: 'nested'
}
]
},
@ -448,7 +448,7 @@ describe('ParserHtml', () => {
},
{
tagName: 'p',
content: 'TestText',
components: 'TestText',
type: 'text'
},
{
@ -475,7 +475,7 @@ describe('ParserHtml', () => {
'data-test': 'test-value'
},
type: 'text',
content: 'test2 '
components: 'test2 '
}
];
expect(obj.parse(str).html).toEqual(result);
@ -494,7 +494,7 @@ describe('ParserHtml', () => {
'data-test': 'test-value'
},
type: 'text',
content: 'test2 '
components: 'test2 '
}
];
expect(obj.parse(str).html).toEqual(result);
@ -512,7 +512,7 @@ describe('ParserHtml', () => {
prop2: 10,
prop3: true
},
content: 'test2 '
components: 'test2 '
}
];
expect(obj.parse(str).html).toEqual(result);
@ -526,7 +526,7 @@ describe('ParserHtml', () => {
attributes: {},
type: 'text',
test: ['value1', 'value2'],
content: 'test2 '
components: 'test2 '
}
];
expect(obj.parse(str).html).toEqual(result);

38
test/specs/selector_manager/e2e/ClassManager.js

@ -1,3 +1,4 @@
import Selector from 'selector_manager/model/Selector';
import Selectors from 'selector_manager/model/Selectors';
import ClassTagsView from 'selector_manager/view/ClassTagsView';
@ -117,5 +118,42 @@ describe('E2E tests', () => {
tagEl.addNewTag('test2');
expect(spy.called).toEqual(true);
});
test('Selectors are properly transformed to JSON', () => {
const model = components.add({
classes: [
'test1',
'.test1a',
'#test2',
{ name: 'test3', label: 'test3' },
{ name: 'test4', label: 'test4a' },
{ name: 'test5' },
{ name: 'test6', type: Selector.TYPE_CLASS },
{ name: 'test7', type: Selector.TYPE_ID },
{ name: 'test8', type: Selector.TYPE_CLASS, protected: 1 },
{ name: 'test9', type: Selector.TYPE_ID, protected: 1 },
{ label: 'test10' },
{ label: 'test11', type: Selector.TYPE_ID },
{ label: 'test12', protected: 1 }
]
});
const modelTr = JSON.parse(JSON.stringify(model));
expect(modelTr.classes).toEqual([
'test1',
'test1a',
'#test2',
'test3',
{ name: 'test4', label: 'test4a' },
'test5',
'test6',
'#test7',
{ name: 'test8', protected: 1 },
{ name: 'test9', type: Selector.TYPE_ID, protected: 1 },
'test10',
'#test11',
{ name: 'test12', protected: 1 }
]);
});
});
});

Loading…
Cancel
Save