PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.4
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.4
3.4.4 3.4.3 3.4.2 3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 All 197 releases
← All changes | resources/backend/js/gutenberg-block-formatters.js +165 -187 2.2.0 → 3.4.4 View file →
@@ -2,23 +2,25 @@
2 2 * Registers formatters in the Block Toolbar in the Gutenberg editor.
3 3 *
4 4 * @since 2.2.0
5 5 *
6 - * @package ConvertKit
7 6 * @author ConvertKit
8 7 */
9 8
9 +/**
10 + * @typedef {import('@wordpress/element').WPElement} WPElement
11 + */
12 +
10 13 // Register Gutenberg Block Toolbar formatters if the Gutenberg Editor is loaded on screen.
11 14 // This prevents JS errors if this script is accidentally enqueued on a non-
12 15 // Gutenberg editor screen, or the Classic Editor Plugin is active.
13 -if ( typeof wp !== 'undefined' &&
14 - typeof wp.blocks !== 'undefined' ) {
15 -
16 +if (convertKitGutenbergEnabled()) {
16 17 // Register each ConvertKit formatter in Gutenberg.
17 - for ( const formatter in convertkit_block_formatters ) {
18 - convertKitGutenbergRegisterBlockFormatter( convertkit_block_formatters[ formatter ] );
18 + for (const formatter in convertkit_block_formatters) {
19 + convertKitGutenbergRegisterBlockFormatter(
20 + convertkit_block_formatters[formatter]
21 + );
19 22 }
20 -
21 23 }
22 24
23 25 /**
24 26 * Registers the given formatter in Gutenberg.
@@ -24,35 +26,23 @@
24 26 * Registers the given formatter in Gutenberg.
25 27 *
26 28 * @since 2.2.0
27 29 *
28 - * @param object formatter Block formatter.
30 + * @param {Object} formatter Block formatter.
29 31 */
30 -function convertKitGutenbergRegisterBlockFormatter( formatter ) {
31 -
32 - ( function( editor, richText, element, components ) {
33 -
32 +function convertKitGutenbergRegisterBlockFormatter(formatter) {
33 + (function (editor, richText, element, components) {
34 34 // Define the Gutenberg/React components to use.
35 + const { Fragment, useState, createElement } = element;
35 36 const {
36 - Fragment,
37 - useState,
38 - createElement
39 - } = element;
40 - const {
41 37 registerFormatType,
42 38 toggleFormat,
43 39 applyFormat,
44 - useAnchorRef
40 + useAnchorRef,
41 + useAnchor,
45 42 } = richText;
46 - const {
47 - BlockControls,
48 - RichTextToolbarButton,
49 - } = editor;
50 - const {
51 - Button,
52 - Popover,
53 - SelectControl
54 - } = components;
43 + const { RichTextToolbarButton } = editor;
44 + const { Popover, SelectControl } = components;
55 45
56 46 /**
57 47 * Returns the icon to display in the block toolbar for this formatter, depending
58 48 * on the supplied formatter's configuration.
@@ -58,31 +48,27 @@
58 48 * on the supplied formatter's configuration.
59 49 *
60 50 * @since 2.2.0
61 51 *
62 - * @return element|string
52 + * @return {WPElement|string} Either a WordPress element (RawHTML) or a dashicon string.
63 53 */
64 - const getIcon = function() {
65 -
54 + const getIcon = function () {
66 55 // Return a fallback default icon if none is specified for this block formatter.
67 - if ( typeof formatter.gutenberg_icon === 'undefined' ) {
56 + if (typeof formatter.gutenberg_icon === 'undefined') {
68 57 return 'dashicons-tablet';
69 58 }
70 59
71 60 // Return HTML element if the icon is an SVG string.
72 - if ( formatter.gutenberg_icon.search( 'svg' ) >= 0 ) {
73 - return element.RawHTML(
74 - {
75 - children: formatter.gutenberg_icon
76 - }
77 - );
61 + if (formatter.gutenberg_icon.search('svg') >= 0) {
62 + return element.RawHTML({
63 + children: formatter.gutenberg_icon,
64 + });
78 65 }
79 66
80 67 // Just return the string, as it's a dashicon CSS class.
81 68 return formatter.gutenberg_icon;
69 + };
82 70
83 - }
84 -
85 71 /**
86 72 * Returns an object of this formatter's attributes if this formatter
87 73 * has been used on the selected text.
88 74 *
@@ -90,44 +76,45 @@
90 76 * selected text.
91 77 *
92 78 * @since 2.2.0
93 79 *
94 - * @param object activeFormats All active formatters applied to the selected text.
95 - * @return object
80 + * @param {Object} activeFormats All active formatters applied to the selected text.
81 + * @return {Object} Attributes.
96 82 */
97 - const getAttributes = function( activeFormats ) {
98 -
83 + const getAttributes = function (activeFormats) {
99 84 // Define the attribute object.
100 - let attributes = {};
101 - for ( let attribute in formatter.attributes ) {
102 - attributes[ attribute ] = '';
85 + const attributes = {};
86 + for (const attribute in formatter.attributes) {
87 + attributes[attribute] = '';
103 88 }
104 89
105 90 // Return if no active formats have been applied to the selected text.
106 - if ( typeof activeFormats === 'undefined' ) {
91 + if (typeof activeFormats === 'undefined') {
107 92 return attributes;
108 93 }
109 94
110 95 // Return if this formatter has not been used on the selected text.
111 - const formats = activeFormats.filter( format => 'convertkit/' + formatter.name === format['type'] );
112 - if ( formats.length === 0 ) {
96 + const formats = activeFormats.filter(
97 + (format) => 'convertkit/' + formatter.name === format.type
98 + );
99 + if (formats.length === 0) {
113 100 return attributes;
114 101 }
115 102
116 103 // This formatter has been applied to the selected text.
117 104 // Build the object of attributes and return.
118 - for ( let attribute in formatter.attributes ) {
119 - if ( typeof formats[0].unregisteredAttributes !== 'undefined' ) {
120 - attributes[ attribute ] = formats[0].unregisteredAttributes[ attribute ];
121 - } else if ( typeof formats[0].attributes !== 'undefined' ) {
122 - attributes[ attribute ] = formats[0].attributes[ attribute ];
105 + for (const attribute in formatter.attributes) {
106 + if (typeof formats[0].unregisteredAttributes !== 'undefined') {
107 + attributes[attribute] =
108 + formats[0].unregisteredAttributes[attribute];
109 + } else if (typeof formats[0].attributes !== 'undefined') {
110 + attributes[attribute] = formats[0].attributes[attribute];
123 111 }
124 112 }
125 113
126 114 return attributes;
115 + };
127 116
128 - }
129 -
130 117 /**
131 118 * Updates the block formatter's attributes when a field in the
132 119 * formatter's popover modal has its value changed.
133 120 *
@@ -132,53 +119,45 @@
132 119 * formatter's popover modal has its value changed.
133 120 *
134 121 * @since 2.2.0
135 122 *
136 - * @param object props Block formatter properties.
137 - * @param array field Field definition.
138 - * @param string newValue New value
123 + * @param {Object} props Block formatter properties.
124 + * @param {Object} field Field definition.
125 + * @param {string} newValue New value.
139 126 */
140 - const setAttributes = function( props, field, newValue ) {
141 -
127 + const setAttributes = function (props, field, newValue) {
142 128 // Define properties and functions to use.
143 129 const { onChange, value } = props;
144 130
145 131 // If no value exists, remove the formatter.
146 - if ( newValue === '' ) {
132 + if (newValue === '') {
147 133 return onChange(
148 - toggleFormat(
149 - value,
150 - {
151 - type: 'convertkit/' + formatter.name
152 - }
153 - )
134 + toggleFormat(value, {
135 + type: 'convertkit/' + formatter.name,
136 + })
154 137 );
155 138 }
156 139
157 140 // Build object of new attributes.
158 - let attributes = {};
159 - for ( let attribute in formatter.attributes ) {
141 + const attributes = {};
142 + for (const attribute in formatter.attributes) {
160 143 // If 'None' selected, blank the attribute's value.
161 - if ( newValue === '' ) {
162 - attributes[ attribute ] = '';
144 + if (newValue === '') {
145 + attributes[attribute] = '';
163 146 } else {
164 - attributes[ attribute ] = field.data[ newValue ][ attribute ];
147 + attributes[attribute] = field.data[newValue][attribute];
165 148 }
166 149 }
167 150
168 151 // Apply formatter with new attributes.
169 152 return onChange(
170 - applyFormat(
171 - value,
172 - {
173 - type: 'convertkit/' + formatter.name,
174 - attributes: attributes
175 - }
176 - )
153 + applyFormat(value, {
154 + type: 'convertkit/' + formatter.name,
155 + attributes,
156 + })
177 157 );
158 + };
178 159
179 - }
180 -
181 160 /**
182 161 * Return an array of field elements to display in the popover modal when
183 162 * this formatter is active.
184 163 *
@@ -183,84 +162,71 @@
183 162 * this formatter is active.
184 163 *
185 164 * @since 2.2.0
186 165 *
187 - * @param object props Block formatter properties.
188 - * @param object setShowPopover Function to toggle showing/hiding the popover.
189 - * @param object attributes Field attributes.
190 - * @return array Field elements
166 + * @param {Object} props Block formatter properties.
167 + * @param {Function} setShowPopover Function to toggle showing/hiding the popover.
168 + * @param {Object} attributes Field attributes.
169 + * @return {Array} Field elements
191 170 */
192 - const getFields = function( props, setShowPopover, attributes ) {
193 -
171 + const getFields = function (props, setShowPopover, attributes) {
194 172 // Define array of field elements.
195 - let elements = [];
173 + const elements = [];
196 174
197 175 // Return if no fields exist.
198 - if ( formatter.fields.length === 0 ) {
176 + if (formatter.fields.length === 0) {
199 177 return elements;
200 178 }
201 179
202 180 // Iterate through the formatter's fields, adding a field element for each.
203 - for ( let fieldName in formatter.fields ) {
204 - const field = formatter.fields[ fieldName ];
181 + for (const fieldName in formatter.fields) {
182 + const field = formatter.fields[fieldName];
205 183
206 184 // Build options for <select> input.
207 - let fieldOptions = [
185 + const fieldOptions = [
208 186 {
209 187 label: '(None)',
210 - value: ''
211 - }
188 + value: '',
189 + },
212 190 ];
213 - for ( let fieldValue in field.values ) {
214 - fieldOptions.push(
215 - {
216 - label: field.values[ fieldValue ],
217 - value: fieldValue
218 - }
219 - );
191 + for (const fieldValue in field.values) {
192 + fieldOptions.push({
193 + label: field.values[fieldValue],
194 + value: fieldValue,
195 + });
220 196 }
221 197
222 198 // Sort field's options alphabetically by label.
223 - fieldOptions.sort(
224 - function ( x, y ) {
199 + fieldOptions.sort(function (x, y) {
200 + const a = x.label.toUpperCase(),
201 + b = y.label.toUpperCase();
202 + return a.localeCompare(b);
203 + });
225 204
226 - let a = x.label.toUpperCase(),
227 - b = y.label.toUpperCase();
228 - return a.localeCompare( b );
229 -
230 - }
231 - );
232 -
233 205 // Add field to array.
234 206 elements.push(
235 - createElement(
236 - SelectControl,
237 - {
238 - key: 'convertkit_' + formatter.name + '_' + fieldName,
239 - id: 'convertkit-' + formatter.name + '-' + fieldName,
240 - label: field.label,
241 - value: attributes[ fieldName ],
242 - help: field.description,
243 - options: fieldOptions,
244 - onChange: function( newValue ) {
207 + createElement(SelectControl, {
208 + key: 'convertkit_' + formatter.name + '_' + fieldName,
209 + id: 'convertkit-' + formatter.name + '-' + fieldName,
210 + label: field.label,
211 + value: attributes[fieldName],
212 + help: field.description,
213 + options: fieldOptions,
214 + onChange(newValue) {
215 + // Hide popover.
216 + setShowPopover(false);
245 217
246 - // Hide popover.
247 - setShowPopover( false );
248 -
249 - // Update and apply attributes to the selected text.
250 - setAttributes( props, field, newValue );
251 -
252 - }
253 - }
254 - )
218 + // Update and apply attributes to the selected text.
219 + setAttributes(props, field, newValue);
220 + },
221 + })
255 222 );
256 223 }
257 224
258 225 // Return elements.
259 226 return elements;
227 + };
260 228
261 - }
262 -
263 229 /**
264 230 * Display modal when the formatter's button is clicked, and save
265 231 * changes that are made.
266 232 *
@@ -265,84 +231,96 @@
265 231 * changes that are made.
266 232 *
267 233 * @since 2.2.0
268 234 *
269 - * @param object props Block formatter properties.
270 - * @return object Block formatter button and modal elements
235 + * @param {Object} props Block formatter properties.
236 + * @return {Object} Block formatter button and modal elements
271 237 */
272 - const editFormatType = function( props ) {
238 + const EditFormatType = function (props) {
239 + // Get props.
240 + const { contentRef, isActive, value } = props;
241 + const { activeFormats } = value;
242 + let anchorRef;
273 243
274 - // Get props and anchor reference to the text.
275 - const { contentRef, isActive, value } = props;
276 - const { activeFormats } = value;
277 - const anchorRef = useAnchorRef( { ref: contentRef, value } );
244 + // Get anchor reference to the text.
245 + if (typeof useAnchor === 'undefined') {
246 + // Use WordPress 6.0 and lower useAnchorRef(), as useAnchor() isn't available.
247 + anchorRef = useAnchorRef({ ref: contentRef, value }); // eslint-disable-line react-hooks/rules-of-hooks
248 + } else {
249 + // Use WordPress 6.1+ useAnchor(), as useAnchorRef() is deprecated in 6.2+.
250 + // eslint-disable-next-line react-hooks/rules-of-hooks
251 + anchorRef = useAnchor({
252 + editableContentElement: contentRef.current,
253 + value,
254 + });
255 + }
278 256
279 257 // State to show popover.
280 - const [ showPopover, setShowPopover ] = useState( false );
258 + const [showPopover, setShowPopover] = useState(false);
281 259
282 260 // Get attributes.
283 - let attributes = getAttributes( activeFormats );
261 + const attributes = getAttributes(activeFormats);
284 262
285 263 // Define fields to display in the popover modal.
286 - let popoverModalElements = getFields( props, setShowPopover, attributes );
264 + const popoverModalElements = getFields(
265 + props,
266 + setShowPopover,
267 + attributes
268 + );
287 269
288 270 // Return block toolbar button and its modal.
289 - return (
290 - createElement(
291 - Fragment,
292 - {
293 - key: 'convertkit_' + formatter.name + '_rich_text_toolbar_fragment'
271 + return createElement(
272 + Fragment,
273 + {
274 + key:
275 + 'convertkit_' +
276 + formatter.name +
277 + '_rich_text_toolbar_fragment',
278 + },
279 + // Register the button in the rich text toolbar.
280 + createElement(RichTextToolbarButton, {
281 + key:
282 + 'convertkit_' +
283 + formatter.name +
284 + '_rich_text_toolbar_button',
285 + icon: getIcon(formatter),
286 + title: formatter.title,
287 + isActive,
288 + onClick() {
289 + setShowPopover(true);
294 290 },
295 - // Register the button in the rich text toolbar.
291 + }),
292 + // Popover which displays fields when the button is active.
293 + showPopover &&
296 294 createElement(
297 - RichTextToolbarButton,
298 - {
299 - key: 'convertkit_' + formatter.name + '_rich_text_toolbar_button',
300 - icon: getIcon( formatter ),
301 - title: formatter.title,
302 - isActive: isActive,
303 - onClick: function() {
304 - setShowPopover( true );
305 - }
306 - },
307 - ),
308 - // Popover which displays fields when the button is active.
309 - showPopover && ( createElement(
310 295 Popover,
311 296 {
312 - key: 'convertkit_' + formatter.name + '_popover',
313 - className: 'convertkit-popover',
314 - anchor: anchorRef,
315 - onClose: function() {
316 - setShowPopover( false );
317 - }
297 + key: 'convertkit_' + formatter.name + '_popover',
298 + className: 'convertkit-popover',
299 + anchor: anchorRef,
300 + onClose() {
301 + setShowPopover(false);
302 + },
318 303 },
319 304 popoverModalElements
320 - ) )
321 - )
305 + )
322 306 );
307 + };
323 308
324 - }
325 -
326 309 // Register Format Type.
327 - registerFormatType(
328 - 'convertkit/' + formatter.name,
329 - {
330 - title: formatter.title,
310 + registerFormatType('convertkit/' + formatter.name, {
311 + title: formatter.title,
331 312
332 - // The tagName and className combination allow Gutenberg to uniquely identify
333 - // whether this formatter has been used on the selected text.
334 - tagName: formatter.tag,
335 - className: 'convertkit-' + formatter.name,
336 - attributes: formatter.attributes,
337 - edit: editFormatType,
338 - }
339 - );
340 -
341 - } (
313 + // The tagName and className combination allow Gutenberg to uniquely identify
314 + // whether this formatter has been used on the selected text.
315 + tagName: formatter.tag,
316 + className: 'convertkit-' + formatter.name,
317 + attributes: formatter.attributes,
318 + edit: EditFormatType,
319 + });
320 + })(
342 321 window.wp.blockEditor,
343 322 window.wp.richText,
344 323 window.wp.element,
345 324 window.wp.components
346 - ) );
347 -
325 + );
348 326 }