Skip to content

Commit 0e29e2e

Browse files
Added CallToAction Lexical Nodes
1 parent 5fa995f commit 0e29e2e

File tree

3 files changed

+223
-0
lines changed

3 files changed

+223
-0
lines changed

packages/kg-default-nodes/lib/kg-default-nodes.js

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as markdown from './nodes/markdown/MarkdownNode';
44
import * as video from './nodes/video/VideoNode';
55
import * as audio from './nodes/audio/AudioNode';
66
import * as callout from './nodes/callout/CalloutNode';
7+
import * as callToAction from './nodes/call-to-action/CallToActionNode';
78
import * as aside from './nodes/aside/AsideNode';
89
import * as horizontalrule from './nodes/horizontalrule/HorizontalRuleNode';
910
import * as html from './nodes/html/HtmlNode';
@@ -54,6 +55,7 @@ export * from './nodes/gallery/GalleryNode';
5455
export * from './nodes/email-cta/EmailCtaNode';
5556
export * from './nodes/signup/SignupNode';
5657
export * from './nodes/collection/CollectionNode';
58+
export * from './nodes/call-to-action/CallToActionNode';
5759
export * from './nodes/ExtendedTextNode';
5860
export * from './nodes/ExtendedHeadingNode';
5961
export * from './nodes/ExtendedQuoteNode';
@@ -89,6 +91,7 @@ export const DEFAULT_NODES = [
8991
video.VideoNode,
9092
audio.AudioNode,
9193
callout.CalloutNode,
94+
callToAction.CallToActionNode,
9295
aside.AsideNode,
9396
horizontalrule.HorizontalRuleNode,
9497
html.HtmlNode,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// eslint-disable-next-line ghost/filenames/match-exported-class
2+
import {generateDecoratorNode} from '../../generate-decorator-node';
3+
4+
export class CallToActionNode extends generateDecoratorNode({nodeType: 'call-to-action',
5+
properties: [
6+
{name: 'layout', default: 'immersive'},
7+
{name: 'textValue', default: '', wordCount: true},
8+
{name: 'showButton', default: false},
9+
{name: 'buttonText', default: ''},
10+
{name: 'buttonUrl', default: ''},
11+
{name: 'hasSponsorLabel', default: false},
12+
{name: 'hasBackground', default: false},
13+
{name: 'backgroundColor', default: '#123456'},
14+
{name: 'hasImage', default: false},
15+
{name: 'imageUrl', default: ''}
16+
]}
17+
) {
18+
/* override */
19+
constructor({
20+
layout,
21+
textValue,
22+
showButton,
23+
buttonText,
24+
buttonUrl,
25+
hasSponsorLabel,
26+
hasBackground,
27+
hasImage,
28+
imageUrl
29+
} = {}, key) {
30+
super(key);
31+
this.__layout = layout || 'immersive';
32+
this.__textValue = textValue || '';
33+
this.__showButton = showButton || false;
34+
this.__buttonText = buttonText || '';
35+
this.__buttonUrl = buttonUrl || '';
36+
this.__hasSponsorLabel = hasSponsorLabel || false;
37+
this.__hasBackground = hasBackground || false;
38+
this.__hasImage = hasImage || false;
39+
this.__imageUrl = imageUrl || '';
40+
}
41+
}
42+
43+
export const $createCallToActionNode = (dataset) => {
44+
return new CallToActionNode(dataset);
45+
};
46+
47+
export const $isCallToActionNode = (node) => {
48+
return node instanceof CallToActionNode;
49+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
const {createDocument, dom, html} = require('../test-utils');
2+
const {$getRoot} = require('lexical');
3+
const {createHeadlessEditor} = require('@lexical/headless');
4+
const {$generateNodesFromDOM} = require('@lexical/html');
5+
6+
const {CallToActionNode, $isCallToActionNode, $createCallToActionNode} = require('../../');
7+
8+
const editorNodes = [CallToActionNode];
9+
10+
describe('CallToActionNode', function () {
11+
let editor;
12+
let dataset;
13+
let exportOptions;
14+
15+
// NOTE: all tests should use this function, without it you need manual
16+
// try/catch and done handling to avoid assertion failures not triggering
17+
// failed tests
18+
const editorTest = testFn => function (done) {
19+
editor.update(() => {
20+
try {
21+
testFn();
22+
done();
23+
} catch (e) {
24+
done(e);
25+
}
26+
});
27+
};
28+
29+
beforeEach(function () {
30+
editor = createHeadlessEditor({nodes: editorNodes});
31+
dataset = {
32+
layout: 'immersive',
33+
textValue: 'This is a cool advertisement',
34+
showButton: true,
35+
buttonText: 'click me',
36+
buttonUrl: 'http://blog.com/post1',
37+
hasSponsorLabel: true,
38+
hasBackground: true,
39+
backgroundColor: '#123456',
40+
hasImage: true,
41+
imageUrl: 'http://blog.com/image1.jpg'
42+
};
43+
exportOptions = {
44+
dom
45+
};
46+
});
47+
48+
it('matches node with $isCallToActionNode', editorTest(function () {
49+
const callToActionNode = new CallToActionNode(dataset);
50+
$isCallToActionNode(callToActionNode).should.be.true();
51+
}));
52+
53+
describe('data access', function () {
54+
it('has getters for all properties', editorTest(function () {
55+
const callToActionNode = new CallToActionNode(dataset);
56+
57+
callToActionNode.layout.should.equal(dataset.layout);
58+
callToActionNode.textValue.should.equal(dataset.textValue);
59+
callToActionNode.showButton.should.equal(dataset.showButton);
60+
callToActionNode.buttonText.should.equal(dataset.buttonText);
61+
callToActionNode.buttonUrl.should.equal(dataset.buttonUrl);
62+
callToActionNode.hasSponsorLabel.should.equal(dataset.hasSponsorLabel);
63+
callToActionNode.hasBackground.should.equal(dataset.hasBackground);
64+
callToActionNode.hasImage.should.equal(dataset.hasImage);
65+
callToActionNode.imageUrl.should.equal(dataset.imageUrl);
66+
}));
67+
68+
it('has setters for all properties', editorTest(function () {
69+
const callToActionNode = new CallToActionNode();
70+
71+
callToActionNode.layout.should.equal('immersive');
72+
callToActionNode.layout = 'compact';
73+
callToActionNode.layout.should.equal('compact');
74+
75+
callToActionNode.textValue.should.equal('');
76+
callToActionNode.textValue = 'This is a cool advertisement';
77+
callToActionNode.textValue.should.equal('This is a cool advertisement');
78+
79+
callToActionNode.showButton.should.equal(false);
80+
callToActionNode.showButton = true;
81+
callToActionNode.showButton.should.equal(true);
82+
83+
callToActionNode.buttonText.should.equal('');
84+
callToActionNode.buttonText = 'click me';
85+
callToActionNode.buttonText.should.equal('click me');
86+
87+
callToActionNode.buttonUrl.should.equal('');
88+
callToActionNode.buttonUrl = 'http://blog.com/post1';
89+
callToActionNode.buttonUrl.should.equal('http://blog.com/post1');
90+
91+
callToActionNode.hasSponsorLabel.should.equal(false);
92+
callToActionNode.hasSponsorLabel = true;
93+
94+
callToActionNode.hasBackground.should.equal(false);
95+
callToActionNode.hasBackground = true;
96+
97+
callToActionNode.hasImage.should.equal(false);
98+
callToActionNode.hasImage = true;
99+
100+
callToActionNode.imageUrl.should.equal('');
101+
callToActionNode.imageUrl = 'http://blog.com/image1.jpg';
102+
}));
103+
104+
it('has getDataset() convenience method', editorTest(function () {
105+
const callToActionNode = new CallToActionNode(dataset);
106+
const callToActionNodeDataset = callToActionNode.getDataset();
107+
108+
callToActionNodeDataset.should.deepEqual({
109+
...dataset
110+
});
111+
}));
112+
});
113+
114+
describe('getType', function () {
115+
it('returns the correct node type', editorTest(function () {
116+
CallToActionNode.getType().should.equal('call-to-action');
117+
}));
118+
});
119+
120+
describe('clone', function () {
121+
it('returns a copy of the current node', editorTest(function () {
122+
const callToActionNode = new CallToActionNode(dataset);
123+
const callToActionNodeDataset = callToActionNode.getDataset();
124+
const clone = CallToActionNode.clone(callToActionNode);
125+
const cloneDataset = clone.getDataset();
126+
127+
cloneDataset.should.deepEqual({...callToActionNodeDataset});
128+
}));
129+
});
130+
131+
describe('urlTransformMap', function () {
132+
// not yet implemented
133+
});
134+
135+
describe('hasEditMode', function () {
136+
it('returns true', editorTest(function () {
137+
const callToActionNode = new CallToActionNode(dataset);
138+
callToActionNode.hasEditMode().should.be.true();
139+
}));
140+
});
141+
142+
describe('exportDOM', function () {
143+
// not yet implemented
144+
});
145+
146+
describe('exportJSON', function () {
147+
// not yet implemented
148+
});
149+
150+
describe('importJSON', function () {
151+
// not yet implemented
152+
});
153+
154+
describe('static properties', function () {
155+
it('getType', editorTest(function () {
156+
CallToActionNode.getType().should.equal('call-to-action');
157+
}));
158+
159+
it('urlTransformMap', editorTest(function () {
160+
// not yet implemented
161+
}));
162+
});
163+
164+
describe('importDom', function () {
165+
// not yet implemented
166+
});
167+
168+
describe('getTextContent', function () {
169+
// not yet implemented
170+
});
171+
});

0 commit comments

Comments
 (0)