Skip to content

Commit

Permalink
Handle default svg properly in component image when reloading from st…
Browse files Browse the repository at this point in the history
…orage (GrapesJS#4373)

* [FIX] handle default svg properly in ComponentImage

* edded tests

* remove relative src reference in test

* single qoute
  • Loading branch information
Singwai authored Jun 13, 2022
1 parent bb0d13f commit 5274e65
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 12 deletions.
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@babel/cli": "^7.15.7",
"@babel/preset-typescript": "^7.16.7",
"@types/backbone": "^1.4.15",
"@types/jest": "^28.1.1",
"@typescript-eslint/parser": "^5.22.0",
"@vuepress/plugin-google-analytics": "^1.8.2",
"documentation": "^13.2.5",
Expand Down Expand Up @@ -76,12 +77,17 @@
]
},
"jest": {
"moduleFileExtensions": [
"js",
"ts"
],
"verbose": true,
"testURL": "http://localhost/",
"modulePaths": [
"./src"
"<rootDir>/src"
],
"testMatch": [
"<rootDir>/test/specs/**/*.js"
"<rootDir>/test/specs/**/*.(t|j)s"
],
"setupFiles": [
"<rootDir>/test/setup.js"
Expand Down
13 changes: 9 additions & 4 deletions src/dom_components/model/ComponentImage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { result } from 'underscore';
import Component from './Component';
import { toLowerCase } from 'utils/mixins';
import { toLowerCase, buildBase64UrlFromSvg } from 'utils/mixins';

const svgAttrs =
'xmlns="http://www.w3.org/2000/svg" width="100" viewBox="0 0 24 24" style="fill: rgba(0,0,0,0.15); transform: scale(0.75)"';
Expand Down Expand Up @@ -35,7 +35,9 @@ export default Component.extend(
initialize(o, opt) {
Component.prototype.initialize.apply(this, arguments);
const { src } = this.get('attributes');
if (src) this.set('src', src, { silent: 1 });
if (src && buildBase64UrlFromSvg(this.defaults.src) !== src) {
this.set('src', src, { silent: 1 });
}
},

initToolbar(...args) {
Expand Down Expand Up @@ -86,14 +88,17 @@ export default Component.extend(
let result = src;

if (src && src.substr(0, 4) === '<svg') {
result = `data:image/svg+xml;base64,${window.btoa(src)}`;
result = buildBase64UrlFromSvg(src);
}

return result;
},

isDefaultSrc() {
return this.get('src') === result(this, 'defaults').src;
return (
this.get('src') === result(this, 'defaults').src ||
this.get('src') === buildBase64UrlFromSvg(result(this, 'defaults').src)
);
},

/**
Expand Down
7 changes: 7 additions & 0 deletions src/utils/mixins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,13 @@ const createId = (length = 16) => {
return result;
};

export const buildBase64UrlFromSvg = (svg: string) => {
if (svg && svg.substr(0, 4) === '<svg') {
return `data:image/svg+xml;base64,${window.btoa(svg)}`;
}
return svg
};

export {
on,
off,
Expand Down
37 changes: 33 additions & 4 deletions test/specs/dom_components/model/ComponentImage.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,42 @@
import Component from 'dom_components/model/Component';
import ComponentImage from 'dom_components/model/ComponentImage';
import Editor from 'editor/model/Editor';
import Backbone from 'backbone';
import { buildBase64UrlFromSvg } from 'utils/mixins';

const $ = Backbone.$;
describe('ComponentImage', () => {
let componentImage;
let dcomp;
let compOpts;
let em;

beforeEach(() => {
componentImage = new ComponentImage();
em = new Editor({ avoidDefaults: true });
dcomp = em.get('DomComponents');
em.get('PageManager').onLoad();
compOpts = {
em,
componentTypes: dcomp.componentTypes,
domc: dcomp,
};
componentImage = new ComponentImage({}, compOpts);
});

describe('.initialize', () => {
test('when a base 64 default image is provided, it uses the default image', () => {
let imageUrl = buildBase64UrlFromSvg(ComponentImage.getDefaults().src);
let componentImage = new ComponentImage({ attributes: { src: imageUrl } }, { ...compOpts });
expect(componentImage.get('src')).toEqual(ComponentImage.getDefaults().src);
expect(componentImage.isDefaultSrc()).toBeTruthy();
});

test('when a image url is provided, it uses the image url', () => {
let imageUrl = 'https://mock.com/image.png';
let componentImage = new ComponentImage({ attributes: { src: imageUrl } }, { ...compOpts });
expect(componentImage.get('src')).toEqual(imageUrl);
expect(componentImage.isDefaultSrc()).toBeFalsy();
});
});

test('`src` property is defined after initializing', () => {
Expand All @@ -17,9 +48,7 @@ describe('ComponentImage', () => {
const fakeAttributes = {};

beforeEach(() => {
spyOn(Component.prototype, 'getAttrToHTML').and.returnValue(
fakeAttributes
);
spyOn(Component.prototype, 'getAttrToHTML').and.returnValue(fakeAttributes);
getSrcResultSpy = spyOn(componentImage, 'getSrcResult');
});

Expand Down
2 changes: 1 addition & 1 deletion test/specs/navigator/view/ItemView.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ItemView from 'navigator/view/ItemView';
import config from 'navigator/config/config';
import EditorModel from '../../../../src/editor/model/Editor';
import EditorModel from 'editor/model/Editor';

describe('ItemView', () => {
let itemView, fakeModel, fakeModelStyle;
Expand Down
29 changes: 29 additions & 0 deletions test/specs/utils/Mixins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { buildBase64UrlFromSvg } from 'utils/mixins';

describe('.buildBase64UrlFromSvg', () => {
it('returns original when a none svg is provided', () => {
const input = 'something else';
expect(buildBase64UrlFromSvg(input)).toEqual(input)
})

it('returns base64 image when an svg is provided', () => {
const input = `<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6" />
<line x1="8" y1="2" x2="8" y2="18" />
<line x1="16" y1="6" x2="16" y2="22" />
</svg>`;

const output = 'data:image/svg+xml;base64,PHN2ZwogICAgICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgICAgIHdpZHRoPSIyNCIKICAgICAgaGVpZ2h0PSIyNCIKICAgICAgdmlld0JveD0iMCAwIDI0IDI0IgogICAgICBmaWxsPSJub25lIgogICAgICBzdHJva2U9ImN1cnJlbnRDb2xvciIKICAgICAgc3Ryb2tlLXdpZHRoPSIyIgogICAgICBzdHJva2UtbGluZWNhcD0icm91bmQiCiAgICAgIHN0cm9rZS1saW5lam9pbj0icm91bmQiCiAgICA+CiAgICAgIDxwb2x5Z29uIHBvaW50cz0iMSA2IDEgMjIgOCAxOCAxNiAyMiAyMyAxOCAyMyAyIDE2IDYgOCAyIDEgNiIgLz4KICAgICAgPGxpbmUgeDE9IjgiIHkxPSIyIiB4Mj0iOCIgeTI9IjE4IiAvPgogICAgICA8bGluZSB4MT0iMTYiIHkxPSI2IiB4Mj0iMTYiIHkyPSIyMiIgLz4KICAgIDwvc3ZnPg=='
expect(buildBase64UrlFromSvg(input)).toEqual(output)
})
});
2 changes: 1 addition & 1 deletion test/specs/utils/Sorter.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Backbone from 'backbone';
import Sorter from '../../../src/utils/Sorter.js';
import Sorter from 'utils/Sorter';
import ComponentTextView from 'dom_components/view/ComponentTextView';
import Component from 'dom_components/model/Component';
const $ = Backbone.$;
Expand Down
57 changes: 57 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,14 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"

"@types/jest@^28.1.1":
version "28.1.1"
resolved "https://registry.npmjs.org/@types/jest/-/jest-28.1.1.tgz#8c9ba63702a11f8c386ee211280e8b68cb093cd1"
integrity sha512-C2p7yqleUKtCkVjlOur9BWVA4HgUQmEj/HWCt5WzZ5mLXrWnyIfl0wGuArc+kBXsy0ZZfLp+7dywB4HtSVYGVA==
dependencies:
jest-matcher-utils "^27.0.0"
pretty-format "^27.0.0"

"@types/jquery@*":
version "3.5.14"
resolved "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz"
Expand Down Expand Up @@ -2191,6 +2199,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"

ansi-styles@^5.0.0:
version "5.2.0"
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==

any-observable@^0.3.0:
version "0.3.0"
resolved "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz"
Expand Down Expand Up @@ -4089,6 +4102,11 @@ diff-sequences@^24.9.0:
version "24.9.0"
resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz"

diff-sequences@^27.5.1:
version "27.5.1"
resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327"
integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==

diff@^3.5.0:
version "3.5.0"
resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz"
Expand Down Expand Up @@ -6535,6 +6553,16 @@ jest-diff@^24.9.0:
jest-get-type "^24.9.0"
pretty-format "^24.9.0"

jest-diff@^27.5.1:
version "27.5.1"
resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def"
integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==
dependencies:
chalk "^4.0.0"
diff-sequences "^27.5.1"
jest-get-type "^27.5.1"
pretty-format "^27.5.1"

jest-docblock@^24.3.0:
version "24.9.0"
resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz"
Expand Down Expand Up @@ -6576,6 +6604,11 @@ jest-get-type@^24.9.0:
version "24.9.0"
resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz"

jest-get-type@^27.5.1:
version "27.5.1"
resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1"
integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==

jest-haste-map@^24.9.0:
version "24.9.0"
resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz"
Expand Down Expand Up @@ -6631,6 +6664,16 @@ jest-matcher-utils@^24.9.0:
jest-get-type "^24.9.0"
pretty-format "^24.9.0"

jest-matcher-utils@^27.0.0:
version "27.5.1"
resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab"
integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==
dependencies:
chalk "^4.0.0"
jest-diff "^27.5.1"
jest-get-type "^27.5.1"
pretty-format "^27.5.1"

jest-message-util@^24.9.0:
version "24.9.0"
resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz"
Expand Down Expand Up @@ -9119,6 +9162,15 @@ pretty-format@^24.9.0:
ansi-styles "^3.2.0"
react-is "^16.8.4"

pretty-format@^27.0.0, pretty-format@^27.5.1:
version "27.5.1"
resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
dependencies:
ansi-regex "^5.0.1"
ansi-styles "^5.0.0"
react-is "^17.0.1"

pretty-time@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz"
Expand Down Expand Up @@ -9340,6 +9392,11 @@ react-is@^16.8.4:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"

react-is@^17.0.1:
version "17.0.2"
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==

read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz"
Expand Down

0 comments on commit 5274e65

Please sign in to comment.