PluginProbe
VikAppointments Services Booking Calendar / 1.2.20
VikAppointments Services Booking Calendar v1.2.20
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / media / js / gutenberg-tools.js
gutenberg-tools.js
520 lines 12.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function(wp) {
2 'use strict';
3
4 /**
5 * Creates a control element according to the provided field data.
6 *
7 * @param object field The field structure.
8 * @param object props The block properties object.
9 *
10 * @return mixed A react control.
11 */
12 window.vapCreateControlElement = (field, props) => {
13 let fieldControl;
14
15 switch (field.layout) {
16 case 'html.form.fields.list':
17 fieldControl = field.class === 'btn-group btn-group-yesno'
18 ? new VAPWidgetBlockFieldCheckbox(field)
19 : new VAPWidgetBlockFieldList(field);
20 break;
21
22 case 'html.form.fields.groupedlist':
23 fieldControl = new VAPWidgetBlockFieldGroupedList(field);
24 break;
25
26 case 'html.form.fields.textarea':
27 fieldControl = new VAPWidgetBlockFieldTextarea(field);
28 break;
29
30 case 'html.form.fields.media':
31 fieldControl = new VAPWidgetBlockFieldMedia(field);
32 break;
33
34 case 'html.form.fields.number':
35 // Do not use NUMBER field yet because this control is experimental
36 // and might be subject to drastic and breaking changes
37 // fieldControl = new VAPWidgetBlockFieldNumber(field);
38 break;
39 }
40
41 if (!fieldControl) {
42 switch (field.type) {
43 case 'color':
44 fieldControl = new VAPWidgetBlockFieldColor(field);
45 break;
46
47 case 'editor':
48 fieldControl = new VAPWidgetBlockFieldTextarea(field);
49 break;
50
51 case 'html':
52 fieldControl = new VAPWidgetBlockFieldHtml(field);
53 break;
54
55 default:
56 // type not supported, use a text field
57 fieldControl = new VAPWidgetBlockFieldText(field);
58 }
59 }
60
61 return fieldControl.createElement(props);
62 }
63
64 /**
65 * Abstract field control.
66 */
67 const VAPWidgetBlockField = class VAPWidgetBlockField {
68 constructor(data) {
69 for (let key in data) {
70 if (data.hasOwnProperty(key)) {
71 this[key] = data[key];
72 }
73 }
74 }
75
76 shouldDisplay(props) {
77 if (!this.showon) {
78 return true;
79 }
80
81 // detect the conditions glue
82 let glue = this.showon.match(/\[OR\]/i) ? 'or' : 'and';
83
84 // extract all the conditions
85 let conditions = this.showon.split(/\[AND\]|\[OR\]/i);
86
87 let verified = false;
88
89 for (let condition of conditions) {
90 // extract the attribute [1], the comparator [2] and the comparison value [3]
91 let chunks = condition.match(/^([a-z0-9_\[\]]+)([!:]+)(.*$)$/i);
92
93 if (!chunks) {
94 // invalid condition
95 continue;
96 }
97
98 let fieldName = chunks[1];
99 let comparator = chunks[2];
100 let match = (chunks[3] === null || chunks[3] === undefined ? '' : chunks[3]).split(/\s*,\s*/);
101
102 if (!props.attributes.hasOwnProperty(fieldName)) {
103 // field not found
104 continue;
105 }
106
107 // validate condition
108 switch (comparator) {
109 case ':':
110 verified = match.indexOf(props.attributes[fieldName].toString()) !== -1;
111 break;
112
113 case '!:':
114 verified = match.indexOf(props.attributes[fieldName].toString()) === -1;
115 break;
116 }
117
118 if (!verified && glue === 'and') {
119 // all the conditions must be verified
120 return false;
121 }
122
123 if (verified && glue === 'or') {
124 // at least a condition can be verified
125 return true;
126 }
127 }
128
129 return verified;
130 }
131
132 createElement(props) {
133 if (this.shouldDisplay(props)) {
134 return this.buildElement(props);
135 }
136
137 return null;
138 }
139
140 buildElement(props) {
141 return null;
142 }
143 }
144
145 /**
146 * Text control field renderer.
147 *
148 * @see wp.components.TextControl
149 * @link https://developer.wordpress.org/block-editor/reference-guides/components/text-control/
150 */
151 const VAPWidgetBlockFieldText = class VAPWidgetBlockFieldText extends VAPWidgetBlockField {
152 buildElement(props) {
153 return wp.element.createElement(
154 wp.components.TextControl,
155 {
156 label: this.label,
157 help: this.description,
158 value: props.attributes[this.name],
159 placeholder: this.hint,
160 onChange: (value) => {
161 let attrs = {};
162 attrs[this.name] = value;
163
164 props.setAttributes(attrs);
165 },
166 __next40pxDefaultSize: true,
167 __nextHasNoMarginBottom: true,
168 }
169 );
170 }
171 }
172
173 /**
174 * Textarea control field renderer.
175 *
176 * @see wp.components.TextareaControl
177 * @link https://developer.wordpress.org/block-editor/reference-guides/components/text-control/
178 */
179 const VAPWidgetBlockFieldTextarea = class VAPWidgetBlockFieldTextarea extends VAPWidgetBlockField {
180 buildElement(props) {
181 return wp.element.createElement(
182 wp.components.TextareaControl,
183 {
184 label: this.label,
185 help: this.description,
186 value: props.attributes[this.name],
187 placeholder: this.hint,
188 onChange: (value) => {
189 let attrs = {};
190 attrs[this.name] = value;
191
192 props.setAttributes(attrs);
193 },
194 __next40pxDefaultSize: true,
195 __nextHasNoMarginBottom: true,
196 }
197 );
198 }
199 }
200
201 /**
202 * Number control field renderer.
203 *
204 * @see wp.components.NumberControl
205 * @link https://developer.wordpress.org/block-editor/reference-guides/components/number-control/
206 */
207 const VAPWidgetBlockFieldNumber = class VAPWidgetBlockFieldNumber extends VAPWidgetBlockField {
208 buildElement(props) {
209 return wp.element.createElement(
210 wp.components.__experimentalNumberControl,
211 {
212 label: this.label,
213 help: this.description,
214 value: props.attributes[this.name],
215 min: this.min !== 'undefined' ? this.min : Number.NEGATIVE_INFINITY,
216 max: this.max !== 'undefined' ? this.max : Number.POSITIVE_INFINITY,
217 step: this.step !== 'undefined' ? this.step : 'any',
218 onChange: (value) => {
219 let attrs = {};
220 attrs[this.name] = value;
221
222 props.setAttributes(attrs);
223 },
224 __next40pxDefaultSize: true,
225 __nextHasNoMarginBottom: true,
226 }
227 );
228 }
229 }
230
231 /**
232 * Color control field renderer.
233 *
234 * @see wp.components.ColorPicker
235 * @link https://developer.wordpress.org/block-editor/reference-guides/components/color-picker/
236 */
237 const VAPWidgetBlockFieldColor = class VAPWidgetBlockFieldColor extends VAPWidgetBlockField {
238 buildElement(props) {
239 return wp.element.createElement(
240 wp.components.BaseControl,
241 {
242 label: this.label,
243 help: this.description,
244 children: wp.element.createElement(
245 wp.components.ColorPicker,
246 {
247 color: props.attributes[this.name],
248 enableAlpha: true,
249 copyFormat: 'hex',
250 onChange: (value) => {
251 let attrs = {};
252 attrs[this.name] = value;
253
254 props.setAttributes(attrs);
255 }
256 }
257 ),
258 __next40pxDefaultSize: true,
259 __nextHasNoMarginBottom: true,
260 }
261 );
262 }
263 }
264
265 /**
266 * Checkbox control field renderer.
267 *
268 * @see wp.components.ToggleControl
269 * @link https://developer.wordpress.org/block-editor/reference-guides/components/toggle-control/
270 */
271 const VAPWidgetBlockFieldCheckbox = class VAPWidgetBlockFieldCheckbox extends VAPWidgetBlockField {
272 buildElement(props) {
273 return wp.element.createElement(
274 wp.components.ToggleControl,
275 {
276 label: this.label,
277 help: this.description,
278 checked: parseInt(props.attributes[this.name]) ? true : false,
279 onChange: (value) => {
280 let attrs = {};
281 attrs[this.name] = value ? 1 : 0;
282
283 props.setAttributes(attrs);
284 },
285 __next40pxDefaultSize: true,
286 __nextHasNoMarginBottom: true,
287 }
288 );
289 }
290 }
291
292 /**
293 * List control field renderer.
294 *
295 * @see wp.components.SelectControl
296 * @link https://developer.wordpress.org/block-editor/reference-guides/components/select-control/
297 */
298 const VAPWidgetBlockFieldList = class VAPWidgetBlockFieldList extends VAPWidgetBlockField {
299 buildElement(props) {
300 return wp.element.createElement(
301 wp.components.SelectControl,
302 {
303 label: this.label,
304 help: this.description,
305 value: props.attributes[this.name],
306 options: this.options,
307 multiple: this.multiple ? true : false,
308 onChange: (value) => {
309 let attrs = {};
310 attrs[this.name] = value;
311
312 props.setAttributes(attrs);
313 },
314 __next40pxDefaultSize: true,
315 __nextHasNoMarginBottom: true,
316 }
317 );
318 }
319 }
320
321 /**
322 * Grouped list control field renderer.
323 *
324 * @see wp.components.SelectControl
325 * @link https://developer.wordpress.org/block-editor/reference-guides/components/select-control/
326 */
327 const VAPWidgetBlockFieldGroupedList = class VAPWidgetBlockFieldGroupedList extends VAPWidgetBlockField {
328 constructor(data) {
329 super(data);
330
331 this.children = [];
332
333 for (let groupLabel in this.groups) {
334 if (!this.groups.hasOwnProperty(groupLabel)) {
335 continue;
336 }
337
338 let options = [];
339
340 this.groups[groupLabel].forEach((option) => {
341 options.push(
342 wp.element.createElement(
343 'option',
344 {
345 value: option.value,
346 },
347 option.text
348 )
349 );
350 });
351
352 this.children.push(
353 wp.element.createElement(
354 'optgroup',
355 {
356 label: groupLabel,
357 },
358 options
359 )
360 );
361 }
362 }
363
364 buildElement(props) {
365 return wp.element.createElement(
366 wp.components.SelectControl,
367 {
368 label: this.label,
369 help: this.description,
370 value: props.attributes[this.name],
371 children: this.children,
372 multiple: this.multiple ? true : false,
373 onChange: (value) => {
374 let attrs = {};
375 attrs[this.name] = value;
376
377 props.setAttributes(attrs);
378 },
379 __next40pxDefaultSize: true,
380 __nextHasNoMarginBottom: true,
381 }
382 );
383 }
384 }
385
386 /**
387 * Media manager control field renderer.
388 *
389 * @see wp.editor.MediaPlaceholder
390 * @link https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/media-placeholder/README.md
391 */
392 const VAPWidgetBlockFieldMedia = class VAPWidgetBlockFieldMedia extends VAPWidgetBlockField {
393 buildElement(props) {
394 let mediaPreview = null;
395
396 if (props.attributes[this.name]) {
397 let children = [];
398
399 // display image only in case the preview is not disabled
400 if (this.preview === undefined || this.preview) {
401 children.push(
402 wp.element.createElement(
403 'img',
404 {
405 src: props.attributes[this.name],
406 style: {
407 marginBottom: '10px',
408 },
409 }
410 )
411 );
412 }
413
414 // add button to clear the selected image
415 children.push(
416 wp.element.createElement(
417 wp.components.Button,
418 {
419 text: wp.i18n.__('Clear'),
420 isDestructive: true,
421 isSecondary: true,
422 style: {
423 marginBottom: '10px',
424 },
425 onClick: () => {
426 let attrs = {};
427 attrs[this.name] = '';
428
429 props.setAttributes(attrs);
430 },
431 }
432 )
433 );
434
435 mediaPreview = wp.element.createElement(
436 'div',
437 {},
438 children
439 );
440 }
441
442 return wp.element.createElement(
443 wp.components.BaseControl,
444 {
445 label: this.label,
446 help: this.description,
447 children: wp.element.createElement(
448 wp.blockEditor.MediaPlaceholder,
449 {
450 labels: { title: '' },
451 multiple: this.multiple ? true : false,
452 // value: props.attributes[this.name],
453 allowedTypes: ['image'],
454 mediaPreview: mediaPreview,
455 onSelect: (value) => {
456 let attrs = {};
457 attrs[this.name] = value.url;
458
459 props.setAttributes(attrs);
460 }
461 }
462 ),
463 __next40pxDefaultSize: true,
464 __nextHasNoMarginBottom: true,
465 }
466 );
467 }
468 }
469
470 /**
471 * Generic HTML control field renderer.
472 */
473 const VAPWidgetBlockFieldHtml = class VAPWidgetBlockFieldHtml extends VAPWidgetBlockField {
474 buildElement(props) {
475 return wp.element.createElement(
476 wp.components.BaseControl,
477 {
478 label: this.label,
479 help: this.description,
480 children: this.createTree(this.layout),
481 __next40pxDefaultSize: true,
482 __nextHasNoMarginBottom: true,
483 }
484 );
485 }
486
487 createTree(nodes) {
488 let children = [];
489
490 nodes.forEach((node) => {
491 let content = [];
492
493 if (node.content) {
494 content.push(node.content);
495 }
496
497 if (node.children) {
498 content = content.concat(this.createTree(node.children));
499 }
500
501 if (node.attributes && node.attributes.class) {
502 // remove any class that might render an element as a notice
503 node.attributes.class = node.attributes.class.replace(/\bnotice(-[a-z]+)?\b/g, '').trim();
504 // convert button classes
505 node.attributes.class = node.attributes.class.replace(/\bbtn\b/g, 'button');
506 }
507
508 children.push(
509 wp.element.createElement(
510 node.tag,
511 node.attributes || {},
512 content
513 )
514 );
515 });
516
517 return children;
518 }
519 }
520 })(window.wp);