PluginProbe
Sharing Image / 2.0.8
Sharing Image v2.0.8
3.10 trunk 2.0 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.17 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 3.0 3.1 3.2 3.3 All 29 releases
sharing-image / assets / scripts / widget.js

widget.js in Sharing Image 2.0.8, at assets/scripts/widget.js

3,594 lines 88.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (() => { // webpackBootstrap
2 /******/ "use strict";
3 var __webpack_exports__ = {};
4
5 ;// CONCATENATED MODULE: ./src/scripts/builders/element.js
6 /**
7 * Helper to create new DOM element.
8 *
9 * @param {string} tag Element tagname.
10 * @param {Object} args List of element options.
11 */
12 function buildElement(tag, args) {
13 const element = document.createElement(tag); // Set class list
14
15 if (args.hasOwnProperty('classes')) {
16 args.classes.forEach(cl => {
17 element.classList.add(cl);
18 });
19 } // Set textContent
20
21
22 if (args.hasOwnProperty('text')) {
23 element.textContent = args.text;
24 } // Set innerHTML
25
26
27 if (args.hasOwnProperty('html')) {
28 element.innerHTML = args.html;
29 } // Set attributes
30
31
32 if (args.hasOwnProperty('attributes')) {
33 for (const key in args.attributes) {
34 const value = args.attributes[key];
35
36 if (undefined === value) {
37 continue;
38 }
39
40 element.setAttribute(key, value);
41 }
42 } // Set data attributes
43
44
45 if (args.hasOwnProperty('dataset')) {
46 for (const key in args.dataset) {
47 element.setAttribute('data-' + key, args.dataset[key]);
48 }
49 } // Append child
50
51
52 if (args.hasOwnProperty('append')) {
53 args.append.appendChild(element);
54 } // Prepend child
55
56
57 if (args.hasOwnProperty('prepend')) {
58 args.prepend.insertBefore(element, args.prepend.firstChild);
59 }
60
61 return element;
62 }
63
64 /* harmony default export */ const builders_element = (buildElement);
65 ;// CONCATENATED MODULE: ./src/scripts/builders/input.js
66
67
68 /**
69 * Helper to create input field.
70 *
71 * @param {Object} args List of control options.
72 * @param {HTMLElement} parent Parent HTML element to append this field.
73 */
74
75 function buildInput(args, parent) {
76 const field = builders_element('div', {
77 classes: args.classes || [],
78 append: parent
79 });
80
81 if (args.hasOwnProperty('label')) {
82 const label = builders_element('h4', {
83 text: args.label
84 });
85
86 if (null !== args.label) {
87 field.appendChild(label);
88 }
89 }
90
91 const input = builders_element('input', {
92 attributes: {
93 type: 'text'
94 },
95 dataset: args.dataset || {},
96 append: field
97 }); // Set attributes.
98
99 if (args.hasOwnProperty('attributes')) {
100 for (const key in args.attributes) {
101 const value = args.attributes[key];
102
103 if (undefined === value) {
104 continue;
105 }
106
107 input.setAttribute(key, value);
108 }
109 }
110
111 if ('range' === input.type) {
112 const counter = builders.element('em', {
113 text: input.value,
114 append: field
115 });
116 input.addEventListener('change', () => {
117 counter.textContent = input.value;
118 });
119 input.addEventListener('input', () => {
120 counter.textContent = input.value;
121 });
122 }
123
124 return input;
125 }
126
127 /* harmony default export */ const input = (buildInput);
128 ;// CONCATENATED MODULE: ./src/scripts/builders/checkbox.js
129
130 /**
131 * Helper to create radio field.
132 *
133 * @param {Object} args List of control options.
134 * @param {HTMLElement} parent Parent HTML element to append this field.
135 */
136
137 function buildCheckbox(args, parent) {
138 const field = builders_element('label', {
139 classes: args.classes || [],
140 append: parent
141 });
142 const checkbox = builders_element('input', {
143 attributes: {
144 type: 'checkbox'
145 },
146 dataset: args.dataset || {},
147 append: field
148 }); // Set attributes
149
150 if (args.hasOwnProperty('attributes')) {
151 for (const key in args.attributes) {
152 const value = args.attributes[key];
153
154 if (undefined === value) {
155 continue;
156 }
157
158 checkbox.setAttribute(key, value);
159 }
160 }
161
162 if (args.hasOwnProperty('checked')) {
163 const checked = args.checked;
164
165 if (checked && checked === checkbox.value) {
166 checkbox.setAttribute('checked', 'checked');
167 }
168 }
169
170 if (args.hasOwnProperty('label')) {
171 const label = builders_element('span', {
172 text: args.label
173 });
174
175 if (null !== args.label) {
176 field.appendChild(label);
177 }
178 }
179
180 return checkbox;
181 }
182
183 /* harmony default export */ const builders_checkbox = (buildCheckbox);
184 ;// CONCATENATED MODULE: ./src/scripts/builders/radio.js
185
186 /**
187 * Helper to create radio field.
188 *
189 * @param {Object} args List of control options.
190 * @param {HTMLElement} parent Parent HTML element to append this field.
191 */
192
193 function buildRadio(args, parent) {
194 const field = builders_element('label', {
195 classes: args.classes || [],
196 append: parent
197 });
198 const radio = builders_element('input', {
199 attributes: {
200 type: 'radio'
201 },
202 dataset: args.dataset || {},
203 append: field
204 }); // Set attributes
205
206 if (args.hasOwnProperty('attributes')) {
207 for (const key in args.attributes) {
208 const value = args.attributes[key];
209
210 if (undefined === value) {
211 continue;
212 }
213
214 radio.setAttribute(key, value);
215 }
216 }
217
218 if (args.hasOwnProperty('checked')) {
219 const checked = args.checked;
220
221 if (checked && checked === radio.value) {
222 radio.setAttribute('checked', 'checked');
223 }
224 }
225
226 if (args.hasOwnProperty('label')) {
227 const label = builders_element('span', {
228 text: args.label
229 });
230
231 if (null !== args.label) {
232 field.appendChild(label);
233 }
234 }
235
236 if (args.hasOwnProperty('help')) {
237 builders_element('small', {
238 text: args.help,
239 append: field
240 });
241 }
242
243 return radio;
244 }
245
246 /* harmony default export */ const builders_radio = (buildRadio);
247 ;// CONCATENATED MODULE: ./src/scripts/builders/select.js
248
249 /**
250 * Helper to create select field.
251 *
252 * @param {Object} args List of control options.
253 * @param {HTMLElement} parent Parent HTML element to append this field.
254 */
255
256 function buildSelect(args, parent) {
257 const field = builders_element('div', {
258 classes: args.classes || [],
259 append: parent
260 });
261
262 if (args.hasOwnProperty('label')) {
263 const label = builders_element('h4', {
264 text: args.label
265 });
266
267 if (null !== args.label) {
268 field.appendChild(label);
269 }
270 }
271
272 const select = builders_element('select', {
273 dataset: args.dataset || {},
274 append: field
275 }); // Set attributes
276
277 if (args.hasOwnProperty('attributes')) {
278 for (const key in args.attributes) {
279 const value = args.attributes[key];
280
281 if (undefined === value) {
282 continue;
283 }
284
285 select.setAttribute(key, value);
286 }
287 }
288
289 const options = args.options || {};
290
291 for (const key in options) {
292 const option = builders_element('option', {
293 text: options[key],
294 attributes: {
295 value: key
296 },
297 append: select
298 });
299
300 if (args.hasOwnProperty('selected')) {
301 const selected = args.selected;
302
303 if (selected && selected === option.value) {
304 option.setAttribute('selected', 'selected');
305 }
306 }
307 }
308
309 return select;
310 }
311
312 /* harmony default export */ const builders_select = (buildSelect);
313 ;// CONCATENATED MODULE: ./src/scripts/builders/textarea.js
314
315 /**
316 * Helper to create input field.
317 *
318 * @param {Object} args List of control options.
319 * @param {HTMLElement} parent Parent HTML element to append this field.
320 */
321
322 function buildTextarea(args, parent) {
323 const field = builders_element('div', {
324 classes: args.classes || [],
325 append: parent
326 });
327
328 if (args.hasOwnProperty('label')) {
329 const label = builders_element('h4', {
330 text: args.label
331 });
332
333 if (null !== args.label) {
334 field.appendChild(label);
335 }
336 }
337
338 const textarea = builders_element('textarea', {
339 dataset: args.dataset || {},
340 append: field
341 }); // Set attributes
342
343 if (args.hasOwnProperty('attributes')) {
344 for (const key in args.attributes) {
345 const value = args.attributes[key];
346
347 if (undefined === value) {
348 continue;
349 }
350
351 textarea.setAttribute(key, value);
352 }
353 } // Set content
354
355
356 if (args.hasOwnProperty('content')) {
357 const content = args.content;
358
359 if (undefined !== content) {
360 textarea.innerHTML = content;
361 }
362 }
363
364 return textarea;
365 }
366
367 /* harmony default export */ const builders_textarea = (buildTextarea);
368 ;// CONCATENATED MODULE: ./src/scripts/builders/control.js
369
370
371
372
373
374
375 /**
376 * Helper to create control.
377 *
378 * @param {Object} args List of control options.
379 */
380
381 function buildControl(args) {
382 const control = builders_element('div', {
383 classes: args.classes || []
384 });
385
386 if (args.hasOwnProperty('append')) {
387 args.append.appendChild(control);
388 }
389
390 if (args.hasOwnProperty('prepend')) {
391 args.prepend.insertBefore(control, args.prepend.firstChild);
392 }
393
394 if (args.hasOwnProperty('label')) {
395 builders_element('h3', {
396 text: args.label,
397 append: control
398 });
399 }
400
401 if (args.hasOwnProperty('description')) {
402 builders_element('p', {
403 text: args.description,
404 append: control
405 });
406 }
407
408 if (args.hasOwnProperty('fields')) {
409 args.fields.forEach(field => {
410 switch (field.group) {
411 case 'input':
412 input(field, control);
413 break;
414
415 case 'textarea':
416 builders_textarea(field, control);
417 break;
418
419 case 'radio':
420 builders_radio(field, control);
421 break;
422
423 case 'select':
424 builders_select(field, control);
425 break;
426
427 case 'checkbox':
428 builders_checkbox(field, control);
429 break;
430 }
431 });
432 }
433
434 if (args.hasOwnProperty('help')) {
435 builders_element('small', {
436 text: args.help,
437 append: control
438 });
439 }
440
441 return control;
442 }
443
444 /* harmony default export */ const control = (buildControl);
445 ;// CONCATENATED MODULE: ./src/scripts/builders/layer.js
446
447 /**
448 * Helper to create layer.
449 *
450 * @param {Object} args List of layer options.
451 */
452
453 function buildLayer(args) {
454 const layer = builders_element('div', {
455 classes: args.classes || []
456 });
457
458 if (args.hasOwnProperty('append')) {
459 args.append.appendChild(layer);
460 }
461
462 if (args.hasOwnProperty('prepend')) {
463 args.prepend.insertBefore(layer, args.prepend.firstChild);
464 }
465
466 if (!args.hasOwnProperty('label')) {
467 args.label = '';
468 }
469
470 builders_element('h2', {
471 text: args.label,
472 append: layer
473 });
474
475 if (args.hasOwnProperty('description')) {
476 builders_element('h5', {
477 text: args.description,
478 append: layer
479 });
480 }
481
482 return layer;
483 }
484
485 /* harmony default export */ const builders_layer = (buildLayer);
486 ;// CONCATENATED MODULE: ./src/scripts/helpers/param.js
487 /**
488 * Get current location search parameter.
489 *
490 * @param {string} key URL parameter key.
491 */
492 function getSearchParam(key) {
493 const params = new URL(document.location.href);
494 return params.searchParams.get(key);
495 }
496
497 /* harmony default export */ const param = (getSearchParam);
498 ;// CONCATENATED MODULE: ./src/scripts/helpers/attachment.js
499 /**
500 * Upload media frame.
501 *
502 * @param {string} header Frame header text.
503 * @param {Function} callback Callback function.
504 */
505 function uploadMedia(header, callback) {
506 const frame = wp.media({
507 title: header,
508 multiple: false
509 });
510 frame.on('select', () => {
511 const selection = frame.state().get('selection').first().toJSON();
512
513 if (selection.id) {
514 callback(selection.id);
515 }
516 });
517 frame.open();
518 }
519
520 /* harmony default export */ const attachment = (uploadMedia);
521 ;// CONCATENATED MODULE: ./src/scripts/helpers/defaults.js
522 /**
523 * Append empty default properties to object if not exist.
524 *
525 * @param {Object} object Source object.
526 * @param {Array} defaults Required defaults properties.
527 */
528 function intersectDefaults(object, defaults) {
529 defaults.forEach(item => {
530 if (undefined === object[item]) {
531 object[item] = {};
532 }
533 });
534 return object;
535 }
536
537 /* harmony default export */ const defaults = (intersectDefaults);
538 ;// CONCATENATED MODULE: ./src/scripts/helpers/index.js
539
540
541
542 const Helper = {
543 param: param,
544 attachment: attachment,
545 defaults: defaults
546 };
547 /* harmony default export */ const helpers = (Helper);
548 ;// CONCATENATED MODULE: ./src/scripts/builders/media.js
549
550
551
552 /**
553 * Helper to create media block.
554 *
555 * @param {Object} args List of media options.
556 */
557
558 function buildMedia(args) {
559 const media = control({
560 classes: args.classes || []
561 });
562
563 if (args.hasOwnProperty('append')) {
564 args.append.appendChild(media);
565 }
566
567 if (args.hasOwnProperty('prepend')) {
568 args.prepend.insertBefore(media, args.prepend.firstChild);
569 } // Labels are required.
570
571
572 args.labels = args.labels || {};
573 const attachment = builders_element('input', {
574 attributes: {
575 type: 'hidden',
576 name: args.name
577 },
578 append: media
579 });
580 const upload = builders_element('button', {
581 classes: ['button'],
582 text: args.labels.button,
583 attributes: {
584 type: 'button'
585 },
586 append: media
587 });
588 const details = builders_element('a', {
589 classes: ['hidden'],
590 text: args.labels.details,
591 attributes: {
592 target: '_blank'
593 }
594 });
595
596 if (args.hasOwnProperty('link')) {
597 media.appendChild(details);
598 } // Helper function to update attachment value.
599
600
601 const setAttachment = id => {
602 attachment.setAttribute('value', id);
603 attachment.dispatchEvent(new Event('change', {
604 bubbles: true
605 }));
606 let link = null;
607
608 if (args.hasOwnProperty('link')) {
609 link = new URL(args.link);
610 link.searchParams.set('item', id);
611 details.setAttribute('href', link.href);
612 }
613
614 if (args.remove) {
615 upload.textContent = args.labels.remove;
616 }
617
618 details.classList.remove('hidden');
619 }; // Helper function to remove attachment value.
620
621
622 const removeAttachment = () => {
623 attachment.setAttribute('value', '');
624 attachment.dispatchEvent(new Event('change', {
625 bubbles: true
626 })); // Set default button title.
627
628 upload.textContent = args.labels.button;
629 details.classList.add('hidden');
630 }; // Update fields if this layer has attachment.
631
632
633 if (args.value) {
634 setAttachment(args.value);
635 }
636
637 upload.addEventListener('click', () => {
638 if (args.remove && attachment.value) {
639 return removeAttachment();
640 }
641
642 helpers.attachment(args.labels.heading, id => {
643 setAttachment(id);
644 });
645 });
646 return media;
647 }
648
649 /* harmony default export */ const media = (buildMedia);
650 ;// CONCATENATED MODULE: ./src/scripts/builders/index.js
651
652
653
654
655
656
657
658
659
660 const Build = {
661 element: builders_element,
662 control: control,
663 layer: builders_layer,
664 checkbox: builders_checkbox,
665 media: media,
666 input: input,
667 textarea: builders_textarea,
668 radio: builders_radio,
669 select: builders_select
670 };
671 /* harmony default export */ const builders = (Build);
672 ;// CONCATENATED MODULE: ./src/scripts/sections/catalog.js
673
674 const {
675 __
676 } = wp.i18n; // Store global scriot object for settings page.
677
678 let params = null;
679 /**
680 * Create template card in catalog.
681 *
682 * @param {HTMLElement} catalog Catalog HTML element.
683 * @param {number} index Current card index.
684 * @param {Object} option List of template options.
685 */
686
687 function createCard(catalog, index, option) {
688 const card = builders.element('div', {
689 classes: ['sharing-image-catalog-card'],
690 append: catalog
691 });
692 const preview = builders.element('figure', {
693 classes: ['sharing-image-catalog-preview'],
694 append: card
695 });
696
697 if (option.preview) {
698 builders.element('img', {
699 attributes: {
700 src: option.preview,
701 alt: ''
702 },
703 append: preview
704 });
705 }
706
707 const footer = builders.element('footer', {
708 classes: ['sharing-image-catalog-footer'],
709 append: card
710 });
711 builders.element('h2', {
712 text: option.title || __('Untitled', 'sharing-image'),
713 append: footer
714 });
715 const link = new URL(document.location.href);
716 link.searchParams.set('template', index);
717 builders.element('a', {
718 classes: ['button'],
719 text: __('Edit template', 'sharing-image'),
720 attributes: {
721 href: link.href
722 },
723 append: footer
724 });
725 }
726 /**
727 * Create new template button in catalog.
728 *
729 * @param {HTMLElement} catalog Catalog HTML element.
730 * @param {number} index New card index.
731 */
732
733
734 function createNewButton(catalog, index) {
735 const link = new URL(document.location.href);
736 link.searchParams.set('template', index);
737 const button = builders.element('a', {
738 classes: ['sharing-image-catalog-new'],
739 attributes: {
740 href: link.href
741 },
742 append: catalog
743 });
744 const title = builders.element('h2', {
745 append: button
746 });
747 builders.element('strong', {
748 text: __('Add new template', 'sharing-image'),
749 append: title
750 }); // Restrict new template creation for not Premium users.
751
752 if (params.templates.length === 0) {
753 return;
754 }
755
756 const license = params.license || {};
757
758 if (license.premium || license.develop) {
759 return;
760 }
761
762 builders.element('span', {
763 text: __('(Availible for Premium only)', 'sharing-image'),
764 append: title
765 });
766
767 if (params.links.premium) {
768 button.href = params.links.premium;
769 }
770 }
771 /**
772 * Create templates catalog from options.
773 *
774 * @param {HTMLElement} content Settings content element.
775 * @param {Object} settings Global settings field.
776 */
777
778
779 function createCatalog(content, settings) {
780 params = settings;
781 const catalog = builders.element('div', {
782 classes: ['sharing-image-catalog'],
783 append: content
784 });
785 let index = 1;
786 settings.templates.forEach(template => {
787 createCard(catalog, index++, template);
788 });
789 createNewButton(catalog, index);
790 }
791
792 /* harmony default export */ const catalog = (createCatalog);
793 ;// CONCATENATED MODULE: ./src/scripts/sections/editor.js
794 /**
795 * Editor settings.
796 */
797
798 /* global ajaxurl:true */
799
800 const {
801 __: editor_
802 } = wp.i18n; // Store global scriot object for settings page.
803
804 let editor_params = null; // Preview element.
805
806 let preview = null; // Root editor element.
807
808 let editor = null;
809 /**
810 * Show template warning message.
811 *
812 * @param {string} message Warning message.
813 */
814
815 function showTemplateError(message) {
816 const viewport = preview.parentNode; // Try to find warning element.
817
818 const warning = viewport.querySelector('.sharing-image-editor-warning');
819
820 if (null === warning) {
821 return;
822 }
823
824 warning.classList.add('warning-visible');
825 warning.textContent = message || editor_('Unknown generation error', 'sharing-image');
826 }
827 /**
828 * Remove warning message block.
829 */
830
831
832 function hideTemplateError() {
833 const viewport = preview.parentNode; // Try to find warning element.
834
835 const warning = viewport.querySelector('.sharing-image-editor-warning');
836
837 if (null === warning) {
838 return;
839 }
840
841 warning.classList.remove('warning-visible');
842 }
843 /**
844 * Geneate template using editor data.
845 */
846
847
848 function generateTemplate() {
849 preview.classList.add('preview-loader');
850 const request = new XMLHttpRequest();
851 request.open('POST', ajaxurl);
852 request.responseType = 'blob'; // Create data bundle using form data.
853
854 const bundle = new window.FormData(editor);
855 bundle.set('action', 'sharing_image_show');
856 hideTemplateError(); // Set blob for success response.
857
858 request.addEventListener('readystatechange', () => {
859 if (request.readyState === 2) {
860 request.responseType = 'json';
861
862 if (request.status === 200) {
863 request.responseType = 'blob';
864 }
865 }
866 });
867 request.addEventListener('load', () => {
868 const response = request.response || {}; // Hide preview loader on request complete.
869
870 preview.classList.remove('preview-blank', 'preview-loader');
871
872 if (200 !== request.status) {
873 return showTemplateError(response.data);
874 }
875
876 let image = preview.querySelector('img');
877
878 if (null === image) {
879 image = builders.element('img', {
880 append: preview
881 });
882 } // Set new blob image source.
883
884
885 image.src = window.URL.createObjectURL(response);
886 });
887 request.addEventListener('error', () => {
888 showTemplateError(); // Hide preview loader on request complete.
889
890 preview.classList.remove('preview-blank', 'preview-loader');
891 });
892 request.send(bundle);
893 }
894 /**
895 * Save template while editor submiting.
896 */
897
898
899 function saveTemplate() {
900 const request = new XMLHttpRequest();
901 request.open('POST', ajaxurl);
902 request.responseType = 'json';
903 preview.classList.add('preview-loader'); // Create data bundle using editor data.
904
905 const bundle = new window.FormData(editor);
906 bundle.set('action', 'sharing_image_save');
907 request.addEventListener('load', () => {
908 const response = request.response || {};
909
910 if (!response.data) {
911 return showTemplateError();
912 }
913
914 if (!response.success) {
915 // Hide preview loader on request complete.
916 preview.classList.remove('preview-loader');
917 return showTemplateError(response.data);
918 }
919
920 const input = preview.querySelector('input');
921
922 if (null !== input) {
923 input.value = response.data;
924 }
925
926 editor.submit();
927 });
928 request.addEventListener('error', () => {
929 // Hide preview loader on request complete.
930 preview.classList.remove('preview-loader');
931 showTemplateError();
932 });
933 request.send(bundle);
934 }
935 /**
936 * Update form fields name attributes for layers
937 *
938 * @param {HTMLElement} designer Layouts designer element.
939 */
940
941
942 function reorderLayers(designer) {
943 const layers = designer.children;
944
945 for (let index = 0; index < layers.length; index++) {
946 const fields = layers[index].querySelectorAll('[name]');
947 fields.forEach(field => {
948 let name = field.getAttribute('name'); // Try to find layer index.
949
950 const match = name.match(/(.+?\[layers\])\[(\d+)\](\[.+?\])$/);
951
952 if (null !== match) {
953 name = match[1] + `[${index}]` + match[3];
954 }
955
956 field.name = name;
957 });
958 }
959 }
960 /**
961 * Update template background settings with custom logic.
962 *
963 * @param {HTMLElement} fieldset Fieldset HTML element.
964 * @param {Object} data Current template data.
965 */
966
967
968 function createPermanentAttachment(fieldset, data) {
969 data.background = data.background || null; // Create background settings control.
970
971 const control = builders.control({
972 classes: ['sharing-image-editor-control', 'control-reduced'],
973 label: editor_('Template background settings', 'sharing-image'),
974 fields: [{
975 group: 'radio',
976 classes: ['sharing-image-editor-control-radio'],
977 attributes: {
978 name: editor_params.name + '[background]',
979 value: 'blank'
980 },
981 label: editor_('Do not use background image', 'sharing-image'),
982 checked: data.background
983 }, {
984 group: 'radio',
985 classes: ['sharing-image-editor-control-radio'],
986 attributes: {
987 name: editor_params.name + '[background]',
988 value: 'dynamic'
989 },
990 label: editor_('Select for each post separately', 'sharing-image'),
991 help: editor_('Post thumbnail will be used if autogenerate', 'sharing-image'),
992 checked: data.background
993 }, {
994 group: 'radio',
995 classes: ['sharing-image-editor-control-radio'],
996 attributes: {
997 name: editor_params.name + '[background]',
998 value: 'permanent'
999 },
1000 label: editor_('Upload permanent background', 'sharing-image'),
1001 checked: data.background
1002 }],
1003 append: fieldset
1004 });
1005 const media = builders.media({
1006 name: editor_params.name + '[attachment]',
1007 classes: ['sharing-image-editor-control', 'control-media'],
1008 value: data.attachment,
1009 link: editor_params.links.uploads,
1010 labels: {
1011 button: editor_('Upload image', 'sharing-image'),
1012 heading: editor_('Select background image', 'sharing-image'),
1013 details: editor_('Attachment details', 'sharing-image')
1014 },
1015 append: fieldset
1016 });
1017 const upload = media.querySelector('button');
1018 upload.disabled = true;
1019 builders.control({
1020 classes: ['sharing-image-editor-control'],
1021 label: editor_('Fill color', 'sharing-image'),
1022 fields: [{
1023 group: 'input',
1024 classes: ['sharing-image-editor-control-color'],
1025 attributes: {
1026 name: editor_params.name + '[fill]',
1027 type: 'color',
1028 value: data.fill
1029 }
1030 }],
1031 append: fieldset
1032 });
1033 control.querySelectorAll('input').forEach(radio => {
1034 if ('radio' !== radio.type) {
1035 return;
1036 } // Show upload button for checked permanent radio.
1037
1038
1039 if (radio.checked && 'permanent' === radio.value) {
1040 upload.disabled = false;
1041 }
1042
1043 radio.addEventListener('change', () => {
1044 upload.disabled = true;
1045
1046 if ('permanent' === radio.value) {
1047 upload.disabled = false;
1048 }
1049 });
1050 });
1051 }
1052 /**
1053 * Text layer dynamic/static fields manager.
1054 *
1055 * @param {HTMLElement} layer Current layer element.
1056 * @param {string} name Fields name attribute prefix.
1057 * @param {Object} data Layer data object.
1058 */
1059
1060
1061 function createDynamicFields(layer, name, data) {
1062 const control = builders.control({
1063 classes: ['sharing-image-editor-control'],
1064 append: layer
1065 });
1066 const checkbox = builders.checkbox({
1067 classes: ['sharing-image-editor-control-checkbox'],
1068 attributes: {
1069 name: name + '[dynamic]',
1070 value: 'dynamic'
1071 },
1072 label: editor_('Dynamic field. Filled in the post editing screen.', 'sharing-image'),
1073 checked: data.dynamic
1074 }, control);
1075 const fields = [];
1076 fields[fields.length] = builders.control({
1077 classes: ['sharing-image-editor-control', 'control-extend', 'control-hidden'],
1078 help: editor_('Displayed only in the metabox.', 'sharing-image'),
1079 fields: [{
1080 group: 'input',
1081 classes: ['sharing-image-editor-control-input'],
1082 attributes: {
1083 name: name + '[title]',
1084 value: data.title
1085 },
1086 label: editor_('Field name', 'sharing-image')
1087 }],
1088 append: layer
1089 });
1090 fields[fields.length] = builders.control({
1091 classes: ['sharing-image-editor-control', 'control-extend', 'control-hidden'],
1092 help: editor_('This field is used for example only, to see how the editor will look.', 'sharing-image'),
1093 fields: [{
1094 group: 'textarea',
1095 classes: ['sharing-image-editor-control-textarea'],
1096 content: data.sample || 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
1097 attributes: {
1098 name: name + '[sample]',
1099 rows: 2
1100 },
1101 label: editor_('Text sample', 'sharing-image')
1102 }],
1103 append: layer
1104 });
1105 fields[fields.length] = builders.control({
1106 classes: ['sharing-image-editor-control', 'control-hidden'],
1107 label: editor_('Preset text field', 'sharing-image'),
1108 fields: [{
1109 group: 'radio',
1110 classes: ['sharing-image-editor-control-radio'],
1111 attributes: {
1112 name: name + '[preset]',
1113 value: 'none'
1114 },
1115 dataset: {
1116 persistent: true
1117 },
1118 label: editor_('Fill in manually', 'sharing-image'),
1119 checked: data.preset || 'none'
1120 }, {
1121 group: 'radio',
1122 classes: ['sharing-image-editor-control-radio'],
1123 attributes: {
1124 name: name + '[preset]',
1125 value: 'title'
1126 },
1127 dataset: {
1128 persistent: true
1129 },
1130 label: editor_('Take from post title', 'sharing-image'),
1131 checked: data.preset || 'none'
1132 }, {
1133 group: 'radio',
1134 classes: ['sharing-image-editor-control-radio'],
1135 attributes: {
1136 name: name + '[preset]',
1137 value: 'excerpt'
1138 },
1139 dataset: {
1140 persistent: true
1141 },
1142 label: editor_('Use post excerpt text', 'sharing-image'),
1143 checked: data.preset || 'none'
1144 }],
1145 append: layer
1146 });
1147 fields[fields.length] = builders.control({
1148 classes: ['sharing-image-editor-control', 'control-extend'],
1149 help: editor_('You can use non-breaking spaces to manage your string position.', 'sharing-image'),
1150 fields: [{
1151 group: 'textarea',
1152 classes: ['sharing-image-editor-control-textarea'],
1153 content: data.content,
1154 attributes: {
1155 name: name + '[content]',
1156 rows: 2
1157 },
1158 label: editor_('Content', 'sharing-image')
1159 }],
1160 append: layer
1161 }); // Helper function to toggle contols visibility.
1162
1163 const toggleClasses = () => {
1164 fields.forEach(field => {
1165 field.classList.toggle('control-hidden');
1166 });
1167 };
1168
1169 if (checkbox.checked) {
1170 toggleClasses();
1171 }
1172
1173 checkbox.addEventListener('change', () => {
1174 toggleClasses();
1175 });
1176 }
1177 /**
1178 * Text layer more options fields manager.
1179 *
1180 * @param {HTMLElement} layer Current layer element.
1181 * @param {string} name Fields name attribute prefix.
1182 * @param {Object} data Layer data object.
1183 */
1184
1185
1186 function createMoreFields(layer, name, data) {
1187 const fields = [];
1188 fields[fields.length] = createFontField(layer, name, data);
1189 fields[fields.length] = builders.control({
1190 classes: ['sharing-image-editor-control', 'control-hidden'],
1191 fields: [{
1192 group: 'input',
1193 classes: ['sharing-image-editor-control-color'],
1194 attributes: {
1195 type: 'color',
1196 name: name + '[color]',
1197 value: data.color || '#ffffff'
1198 },
1199 label: editor_('Text color', 'sharing-image')
1200 }],
1201 append: layer
1202 });
1203 fields[fields.length] = builders.control({
1204 classes: ['sharing-image-editor-control', 'control-series', 'control-hidden'],
1205 fields: [{
1206 group: 'select',
1207 classes: ['sharing-image-editor-control-select'],
1208 options: {
1209 left: editor_('Left', 'sharing-image'),
1210 center: editor_('Center', 'sharing-image'),
1211 right: editor_('Right', 'sharing-image')
1212 },
1213 attributes: {
1214 name: name + '[horizontal]'
1215 },
1216 label: editor_('Horizontal alignment', 'sharing-image'),
1217 selected: data.horizontal
1218 }, {
1219 group: 'select',
1220 classes: ['sharing-image-editor-control-select'],
1221 options: {
1222 top: editor_('Top', 'sharing-image'),
1223 center: editor_('Center', 'sharing-image'),
1224 bottom: editor_('Bottom', 'sharing-image')
1225 },
1226 attributes: {
1227 name: name + '[vertical]'
1228 },
1229 label: editor_('Vertical alignment', 'sharing-image'),
1230 selected: data.vertical
1231 }],
1232 append: layer
1233 });
1234 const control = builders.control({
1235 classes: ['sharing-image-editor-control'],
1236 append: layer
1237 });
1238 const button = builders.element('button', {
1239 classes: ['sharing-image-editor-more'],
1240 text: editor_('More options', 'sharing-image'),
1241 attributes: {
1242 type: 'button'
1243 },
1244 append: control
1245 });
1246 button.addEventListener('click', () => {
1247 fields.forEach(field => {
1248 field.classList.remove('control-hidden');
1249 }); // Remove button on expand.
1250
1251 layer.removeChild(control);
1252 }); // Open more fields for existing layers.
1253
1254 if (Object.keys(data).length > 0) {
1255 button.click();
1256 }
1257 }
1258 /**
1259 * Create font field in text layer.
1260 *
1261 * @param {HTMLElement} layer Current layer element.
1262 * @param {string} name Fields name attribute prefix.
1263 * @param {Object} data Layer data object.
1264 */
1265
1266
1267 function createFontField(layer, name, data) {
1268 const control = builders.control({
1269 classes: ['sharing-image-editor-control', 'control-upload', 'control-hidden'],
1270 append: layer
1271 });
1272 const select = builders.select({
1273 classes: ['sharing-image-editor-control-select'],
1274 options: editor_params.fonts,
1275 attributes: {
1276 name: name + '[fontname]'
1277 },
1278 label: editor_('Font family', 'sharing-image'),
1279 selected: data.fontname
1280 }, control);
1281 const media = builders.media({
1282 name: name + '[fontfile]',
1283 classes: ['sharing-image-editor-control-media'],
1284 value: data.fontfile,
1285 link: editor_params.links.uploads,
1286 labels: {
1287 button: editor_('Upload custom font', 'sharing-image'),
1288 heading: editor_('Upload custom font', 'sharing-image'),
1289 details: editor_('Font attachment', 'sharing-image'),
1290 remove: editor_('Remove font', 'sharing-image')
1291 },
1292 remove: true,
1293 append: control
1294 });
1295 builders.element('small', {
1296 text: editor_('Custom font can only be in .ttf format.'),
1297 append: control
1298 });
1299
1300 if (data.fontfile) {
1301 select.disabled = true;
1302 } // Find media attachment input.
1303
1304
1305 const input = media.querySelector('input');
1306 input.addEventListener('change', () => {
1307 select.disabled = false;
1308
1309 if (input.value) {
1310 select.disabled = true;
1311 }
1312 });
1313 return control;
1314 }
1315 /**
1316 * Rectangle layer outline option.
1317 *
1318 * @param {HTMLElement} layer Current layer element.
1319 * @param {string} name Fields name attribute prefix.
1320 * @param {Object} data Layer data object.
1321 */
1322
1323
1324 function createRectangleOutline(layer, name, data) {
1325 const control = builders.control({
1326 classes: ['sharing-image-editor-control'],
1327 append: layer
1328 });
1329 const checkbox = builders.checkbox({
1330 classes: ['sharing-image-editor-control-checkbox'],
1331 attributes: {
1332 name: name + '[outline]',
1333 value: 'outline'
1334 },
1335 label: editor_('Outline rectangle.', 'sharing-image'),
1336 checked: data.outline
1337 }, control);
1338 const range = builders.control({
1339 classes: ['sharing-image-editor-control', 'control-hidden'],
1340 fields: [{
1341 group: 'input',
1342 classes: ['sharing-image-editor-control-range'],
1343 attributes: {
1344 type: 'range',
1345 name: name + '[thickness]',
1346 min: 0,
1347 max: 50,
1348 step: 1,
1349 value: data.thickness || '0'
1350 },
1351 label: editor_('Border width', 'sharing-image')
1352 }],
1353 append: layer
1354 });
1355
1356 if (data.outline) {
1357 range.classList.remove('control-hidden');
1358 }
1359
1360 checkbox.addEventListener('change', () => {
1361 range.classList.add('control-hidden');
1362
1363 if (checkbox.checked) {
1364 range.classList.remove('control-hidden');
1365 }
1366 });
1367 }
1368 /**
1369 * Create catalog button in footer.
1370 *
1371 * @param {HTMLElement} footer Footer HTML element.
1372 */
1373
1374
1375 function createCatalogButton(footer) {
1376 const link = new URL(document.location.href);
1377 link.searchParams.delete('template');
1378 builders.element('a', {
1379 classes: ['button'],
1380 text: editor_('← Back to Catalog', 'sharing-image'),
1381 attributes: {
1382 href: link.href
1383 },
1384 append: footer
1385 });
1386 }
1387 /**
1388 * Create template deletion button in footer.
1389 *
1390 * @param {HTMLElement} footer Footer HTML element.
1391 */
1392
1393
1394 function createDeleteButton(footer) {
1395 const href = new URL(document.location.href); // Get template index from current link.
1396
1397 const index = href.searchParams.get('template'); // Set template index to delete link.
1398
1399 const link = new URL(editor.getAttribute('action'));
1400 link.searchParams.set('action', 'sharing_image_delete');
1401 link.searchParams.set('template', index);
1402 link.searchParams.set('nonce', editor_params.nonce);
1403 builders.element('a', {
1404 classes: ['sharing-image-editor-delete'],
1405 text: editor_('Delete template', 'sharing-image'),
1406 attributes: {
1407 href: link.href
1408 },
1409 append: footer
1410 });
1411 }
1412 /**
1413 * Create preview element.
1414 *
1415 * @param {HTMLElement} viewport Monitor viewport element.
1416 * @param {Object} data Template data object.
1417 */
1418
1419
1420 function createPreview(viewport, data) {
1421 preview = builders.element('div', {
1422 classes: ['sharing-image-editor-preview', 'preview-blank'],
1423 append: viewport
1424 });
1425
1426 if (data.preview) {
1427 builders.element('img', {
1428 attributes: {
1429 src: data.preview,
1430 alt: ''
1431 },
1432 append: preview
1433 });
1434 preview.classList.remove('preview-blank');
1435 }
1436
1437 builders.element('span', {
1438 classes: ['sharing-image-editor-loader'],
1439 append: preview
1440 });
1441 builders.element('input', {
1442 attributes: {
1443 type: 'hidden',
1444 name: editor_params.name + '[preview]',
1445 value: data.preview
1446 },
1447 append: preview
1448 });
1449 return preview;
1450 }
1451 /**
1452 *
1453 * @param {*} designer
1454 * @param {*} layer
1455 */
1456
1457
1458 function createCollapseButton(designer, layer) {
1459 const label = layer.querySelector('h2');
1460 const button = builders.element('button', {
1461 classes: ['sharing-image-editor-collapse'],
1462 attributes: {
1463 type: 'button',
1464 title: editor_('Collapse layer', 'sharing-image')
1465 },
1466 append: label
1467 });
1468 button.addEventListener('click', e => {
1469 e.preventDefault(); // Set default button title.
1470
1471 button.setAttribute('title', editor_('Collapse layer', 'sharing-image'));
1472 layer.classList.toggle('layer-collapsed'); // Check if new class is collapsed.
1473
1474 const collapsed = layer.classList.contains('layer-collapsed');
1475
1476 if (collapsed) {
1477 button.setAttribute('title', editor_('Expand layer', 'sharing-image'));
1478 }
1479 });
1480 }
1481 /**
1482 * Create button inside layer box to change order.
1483 *
1484 * @param {HTMLElement} designer Layers designer HTML element.
1485 * @param {HTMLElement} layer Current layer HTML emelemt.
1486 */
1487
1488
1489 function createOrderLayersButton(designer, layer) {
1490 const button = builders.element('button', {
1491 classes: ['sharing-image-editor-order'],
1492 attributes: {
1493 type: 'button',
1494 title: editor_('Raise higher', 'sharing-image')
1495 },
1496 append: layer
1497 });
1498 button.addEventListener('click', () => {
1499 if (layer.previousSibling) {
1500 designer.insertBefore(layer, layer.previousSibling);
1501 } // Update fields name attributes.
1502
1503
1504 reorderLayers(designer);
1505
1506 if (editor.classList.contains('editor-suspend')) {
1507 return;
1508 }
1509
1510 generateTemplate();
1511 });
1512 }
1513 /**
1514 * Create button to delete layer.
1515 *
1516 * @param {HTMLElement} designer Layers designer HTML element.
1517 * @param {HTMLElement} layer Current layer HTML emelemt.
1518 */
1519
1520
1521 function createDeleteLayerButton(designer, layer) {
1522 const control = builders.control({
1523 classes: ['sharing-image-editor-control', 'control-footer'],
1524 append: layer
1525 });
1526 const button = builders.element('button', {
1527 classes: ['sharing-image-editor-delete'],
1528 text: editor_('Delete layer', 'sharing-image'),
1529 attributes: {
1530 type: 'button'
1531 },
1532 append: control
1533 });
1534 button.addEventListener('click', () => {
1535 designer.removeChild(layer); // Update fields name attributes.
1536
1537 reorderLayers(designer);
1538
1539 if (editor.classList.contains('editor-suspend')) {
1540 return;
1541 }
1542
1543 generateTemplate();
1544 });
1545 }
1546 /**
1547 * Create image layer.
1548 *
1549 * @param {number} index Current layer index.
1550 * @param {Object} data Current template layer data.
1551 */
1552
1553
1554 function createLayerImage(index, data) {
1555 const description = [];
1556 description.push(editor_('Use jpg, gif or png image formats.', 'sharing-image'));
1557 description.push(editor_('Leave width and height fields blank to use the original image size.', 'sharing-image'));
1558 description.push(editor_('Sizes are calculated proportionally if not filled.', 'sharing-image'));
1559 const layer = builders.layer({
1560 classes: ['sharing-image-editor-layer', 'layer-image'],
1561 label: editor_('Image', 'sharing-image'),
1562 description: description.join(' ')
1563 }); // Form fields name for this layer.
1564
1565 const name = editor_params.name + `[layers][${index}]`;
1566 builders.element('input', {
1567 attributes: {
1568 type: 'hidden',
1569 name: name + '[type]',
1570 value: 'image'
1571 },
1572 append: layer
1573 });
1574 builders.media({
1575 name: name + '[attachment]',
1576 classes: ['sharing-image-editor-control', 'control-media'],
1577 value: data.attachment,
1578 link: editor_params.links.uploads,
1579 labels: {
1580 button: editor_('Upload image', 'sharing-image'),
1581 heading: editor_('Select layer image', 'sharing-image'),
1582 details: editor_('Attachment details', 'sharing-image')
1583 },
1584 append: layer
1585 });
1586 builders.control({
1587 classes: ['sharing-image-editor-control', 'control-sizes'],
1588 fields: [{
1589 group: 'input',
1590 classes: ['sharing-image-editor-control-input'],
1591 attributes: {
1592 name: name + '[x]',
1593 value: data.x,
1594 placeholder: '10'
1595 },
1596 label: editor_('X', 'sharing-image')
1597 }, {
1598 group: 'input',
1599 classes: ['sharing-image-editor-control-input'],
1600 attributes: {
1601 name: name + '[y]',
1602 value: data.y,
1603 placeholder: '10'
1604 },
1605 label: editor_('Y', 'sharing-image')
1606 }, {
1607 group: 'input',
1608 classes: ['sharing-image-editor-control-input'],
1609 attributes: {
1610 name: name + '[width]',
1611 value: data.width
1612 },
1613 label: editor_('Width', 'sharing-image')
1614 }, {
1615 group: 'input',
1616 classes: ['sharing-image-editor-control-input'],
1617 attributes: {
1618 name: name + '[height]',
1619 value: data.height
1620 },
1621 label: editor_('Height', 'sharing-image')
1622 }],
1623 append: layer
1624 });
1625 return layer;
1626 }
1627 /**
1628 * Create text layer.
1629 *
1630 * @param {number} index Current layer index.
1631 * @param {Object} data Current template data.
1632 */
1633
1634
1635 function createLayerText(index, data) {
1636 const description = [];
1637 description.push(editor_('Write a text to the current image.', 'sharing-image'));
1638 description.push(editor_('If the font does not fit within your limits, its size will decrease.', 'sharing-image'));
1639 description.push(editor_('Avoid using large font sizes for long text – this affects performance.', 'sharing-image'));
1640 const layer = builders.layer({
1641 classes: ['sharing-image-editor-layer', 'layer-text'],
1642 label: editor_('Text', 'sharing-image'),
1643 description: description.join(' ')
1644 }); // Form fields name for this layer.
1645
1646 const name = editor_params.name + `[layers][${index}]`;
1647 builders.element('input', {
1648 attributes: {
1649 type: 'hidden',
1650 name: name + '[type]',
1651 value: 'text'
1652 },
1653 append: layer
1654 });
1655 builders.control({
1656 classes: ['sharing-image-editor-control', 'control-sizes'],
1657 fields: [{
1658 group: 'input',
1659 classes: ['sharing-image-editor-control-input'],
1660 attributes: {
1661 type: 'text',
1662 name: name + '[x]',
1663 value: data.x,
1664 placeholder: '10'
1665 },
1666 label: editor_('X', 'sharing-image')
1667 }, {
1668 group: 'input',
1669 classes: ['sharing-image-editor-control-input'],
1670 attributes: {
1671 type: 'text',
1672 name: name + '[y]',
1673 value: data.y,
1674 placeholder: '10'
1675 },
1676 label: editor_('Y', 'sharing-image')
1677 }, {
1678 group: 'input',
1679 classes: ['sharing-image-editor-control-input'],
1680 attributes: {
1681 type: 'text',
1682 name: name + '[width]',
1683 value: data.width,
1684 placeholder: '1000'
1685 },
1686 label: editor_('Width', 'sharing-image')
1687 }, {
1688 group: 'input',
1689 classes: ['sharing-image-editor-control-input'],
1690 attributes: {
1691 type: 'text',
1692 name: name + '[height]',
1693 value: data.height
1694 },
1695 label: editor_('Height', 'sharing-image')
1696 }],
1697 append: layer
1698 }); // Create static/dynamic text fields.
1699
1700 createDynamicFields(layer, name, data); // Create more options.
1701
1702 createMoreFields(layer, name, data);
1703 builders.control({
1704 classes: ['sharing-image-editor-control', 'control-series'],
1705 fields: [{
1706 group: 'input',
1707 classes: ['sharing-image-editor-control-range'],
1708 attributes: {
1709 type: 'range',
1710 name: name + '[fontsize]',
1711 min: 10,
1712 max: 200,
1713 step: 1,
1714 value: data.fontsize || '48'
1715 },
1716 label: editor_('Font size', 'sharing-image')
1717 }, {
1718 group: 'input',
1719 classes: ['sharing-image-editor-control-range'],
1720 attributes: {
1721 type: 'range',
1722 name: name + '[lineheight]',
1723 min: 0,
1724 max: 4,
1725 step: 0.125,
1726 value: data.lineheight || '1.5'
1727 },
1728 label: editor_('Line height', 'sharing-image')
1729 }],
1730 append: layer
1731 });
1732 return layer;
1733 }
1734 /**
1735 * Create filter layer.
1736 *
1737 * @param {number} index Current layer index.
1738 * @param {Object} data Current template data.
1739 */
1740
1741
1742 function createLayerFilter(index, data) {
1743 const description = [];
1744 description.push(editor_('Filters are applied one after another to the entire editor image.', 'sharing-image'));
1745 description.push(editor_('If you want to control their order, create multiple layers.', 'sharing-image'));
1746 const layer = builders.layer({
1747 classes: ['sharing-image-editor-layer', 'layer-text'],
1748 label: editor_('Filter', 'sharing-image'),
1749 description: description.join(' ')
1750 }); // Form fields name for this layer.
1751
1752 const name = editor_params.name + `[layers][${index}]`;
1753 builders.element('input', {
1754 attributes: {
1755 type: 'hidden',
1756 name: name + '[type]',
1757 value: 'filter'
1758 },
1759 append: layer
1760 });
1761 builders.control({
1762 classes: ['sharing-image-editor-control'],
1763 fields: [{
1764 group: 'checkbox',
1765 classes: ['sharing-image-editor-control-checkbox'],
1766 attributes: {
1767 name: name + '[grayscale]',
1768 value: 'grayscale'
1769 },
1770 label: editor_('Turns image into a grayscale version', 'sharing-image'),
1771 checked: data.grayscale
1772 }],
1773 append: layer
1774 });
1775 builders.control({
1776 classes: ['sharing-image-editor-control'],
1777 fields: [{
1778 group: 'checkbox',
1779 classes: ['sharing-image-editor-control-checkbox'],
1780 attributes: {
1781 name: name + '[blur]',
1782 value: 'blur'
1783 },
1784 label: editor_('Blur image by Gaussian effect', 'sharing-image'),
1785 checked: data.blur
1786 }],
1787 append: layer
1788 });
1789 builders.control({
1790 classes: ['sharing-image-editor-control'],
1791 fields: [{
1792 group: 'input',
1793 classes: ['sharing-image-editor-control-range'],
1794 attributes: {
1795 type: 'range',
1796 name: name + '[contrast]',
1797 min: -50,
1798 max: 50,
1799 step: 5,
1800 value: data.contrast || '0'
1801 },
1802 label: editor_('Contrast', 'sharing-image')
1803 }],
1804 append: layer
1805 });
1806 builders.control({
1807 classes: ['sharing-image-editor-control'],
1808 fields: [{
1809 group: 'input',
1810 classes: ['sharing-image-editor-control-range'],
1811 attributes: {
1812 type: 'range',
1813 name: name + '[brightness]',
1814 min: -50,
1815 max: 50,
1816 step: 5,
1817 value: data.brightness || '0'
1818 },
1819 label: editor_('Brightness', 'sharing-image')
1820 }],
1821 append: layer
1822 });
1823 builders.control({
1824 classes: ['sharing-image-editor-control'],
1825 fields: [{
1826 group: 'input',
1827 classes: ['sharing-image-editor-control-range'],
1828 attributes: {
1829 type: 'range',
1830 name: name + '[blackout]',
1831 min: 0,
1832 max: 100,
1833 step: 5,
1834 value: data.blackout || '0'
1835 },
1836 label: editor_('Blackout', 'sharing-image')
1837 }],
1838 append: layer
1839 });
1840 return layer;
1841 }
1842 /**
1843 * Create rectangle layer.
1844 *
1845 * @param {number} index Current layer index.
1846 * @param {Object} data Current template data.
1847 */
1848
1849
1850 function createLayerRectangle(index, data) {
1851 const description = [];
1852 description.push(editor_('Draw a colored rectangle on current image.', 'sharing-image'));
1853 description.push(editor_('You can get filled or outlined figure with custom color and opacity.', 'sharing-image'));
1854 description.push(editor_('Use small height to draw the line.', 'sharing-image'));
1855 const layer = builders.layer({
1856 classes: ['sharing-image-editor-layer', 'layer-text'],
1857 label: editor_('Rectangle', 'sharing-image'),
1858 description: description.join(' ')
1859 }); // Form fields name for this layer.
1860
1861 const name = editor_params.name + `[layers][${index}]`;
1862 builders.element('input', {
1863 attributes: {
1864 type: 'hidden',
1865 name: name + '[type]',
1866 value: 'rectangle'
1867 },
1868 append: layer
1869 });
1870 builders.control({
1871 classes: ['sharing-image-editor-control'],
1872 fields: [{
1873 group: 'input',
1874 classes: ['sharing-image-editor-control-color'],
1875 attributes: {
1876 type: 'color',
1877 name: name + '[color]',
1878 value: data.color || '#ffffff'
1879 },
1880 label: editor_('Rectangle color', 'sharing-image')
1881 }],
1882 append: layer
1883 });
1884 builders.control({
1885 classes: ['sharing-image-editor-control', 'control-sizes'],
1886 fields: [{
1887 group: 'input',
1888 classes: ['sharing-image-editor-control-input'],
1889 attributes: {
1890 type: 'text',
1891 name: name + '[x]' || 0,
1892 value: data.x
1893 },
1894 label: editor_('X', 'sharing-image')
1895 }, {
1896 group: 'input',
1897 classes: ['sharing-image-editor-control-input'],
1898 attributes: {
1899 type: 'text',
1900 name: name + '[y]' || 0,
1901 value: data.y
1902 },
1903 label: editor_('Y', 'sharing-image')
1904 }, {
1905 group: 'input',
1906 classes: ['sharing-image-editor-control-input'],
1907 attributes: {
1908 type: 'text',
1909 name: name + '[width]',
1910 value: data.width
1911 },
1912 label: editor_('Width', 'sharing-image')
1913 }, {
1914 group: 'input',
1915 classes: ['sharing-image-editor-control-input'],
1916 attributes: {
1917 type: 'text',
1918 name: name + '[height]',
1919 value: data.height
1920 },
1921 label: editor_('Height', 'sharing-image')
1922 }],
1923 append: layer
1924 });
1925 createRectangleOutline(layer, name, data);
1926 builders.control({
1927 classes: ['sharing-image-editor-control'],
1928 fields: [{
1929 group: 'input',
1930 classes: ['sharing-image-editor-control-range'],
1931 attributes: {
1932 type: 'range',
1933 name: name + '[opacity]',
1934 min: 0,
1935 max: 100,
1936 step: 5,
1937 value: data.opacity || '0'
1938 },
1939 label: editor_('Opacity', 'sharing-image')
1940 }],
1941 append: layer
1942 });
1943 return layer;
1944 }
1945 /**
1946 * Create new layer.
1947 *
1948 * @param {HTMLElement} designer Designer HTML element.
1949 * @param {string} type New layer type.
1950 * @param {number} index Layer index.
1951 * @param {Object} data New layer data.
1952 */
1953
1954
1955 function createLayer(designer, type, index) {
1956 let data = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1957 let layer = null;
1958
1959 switch (type) {
1960 case 'image':
1961 layer = createLayerImage(index, data);
1962 break;
1963
1964 case 'text':
1965 layer = createLayerText(index, data);
1966 break;
1967
1968 case 'filter':
1969 layer = createLayerFilter(index, data);
1970 break;
1971
1972 case 'rectangle':
1973 layer = createLayerRectangle(index, data);
1974 break;
1975 }
1976
1977 if (null === layer) {
1978 return;
1979 }
1980
1981 designer.insertBefore(layer, designer.firstChild); // Delete this layer button.
1982
1983 createDeleteLayerButton(designer, layer); // Create collapse button.
1984
1985 createCollapseButton(designer, layer); // Reorder layers button.
1986
1987 createOrderLayersButton(designer, layer);
1988 }
1989 /**
1990 * Create layers designer control.
1991 *
1992 * @param {HTMLElement} fieldset Fieldset HTML element.
1993 * @param {Object} data Current template data.
1994 */
1995
1996
1997 function createDesigner(fieldset, data) {
1998 const control = builders.control({
1999 classes: ['sharing-image-editor-control', 'control-select', 'control-compact'],
2000 fields: [{
2001 group: 'select',
2002 classes: ['sharing-image-editor-control-select'],
2003 options: {
2004 text: editor_('Text', 'sharing-image'),
2005 image: editor_('Image', 'sharing-image'),
2006 filter: editor_('Filter', 'sharing-image'),
2007 rectangle: editor_('Rectangle', 'sharing-image')
2008 }
2009 }],
2010 append: fieldset
2011 });
2012 const button = builders.element('button', {
2013 classes: ['button'],
2014 text: editor_('Add new', 'sharing-image'),
2015 attributes: {
2016 type: 'button'
2017 },
2018 append: control
2019 });
2020 const designer = builders.element('div', {
2021 classes: ['sharing-image-editor-designer'],
2022 append: fieldset
2023 }); // Set default layers set.
2024
2025 let layers = data.layers || [];
2026 layers = layers.reverse();
2027 layers.forEach((layer, index) => {
2028 if (layer.hasOwnProperty('type')) {
2029 createLayer(designer, layer.type, index++, layer);
2030 }
2031 });
2032 button.addEventListener('click', () => {
2033 const select = control.querySelector('select');
2034
2035 if (null === select) {
2036 return;
2037 }
2038
2039 createLayer(designer, select.value, designer.children.length);
2040 });
2041 }
2042 /**
2043 * Create common settings on template editor screen.
2044 *
2045 * @param {Object} data Current template data.
2046 */
2047
2048
2049 function createFieldset(data) {
2050 const fieldset = builders.element('div', {
2051 classes: ['sharing-image-editor-fieldset'],
2052 append: editor
2053 }); // Create template title control.
2054
2055 builders.control({
2056 classes: ['sharing-image-editor-control', 'control-compact', 'control-extend'],
2057 help: editor_('Used only in the admin panel', 'sharing-image'),
2058 fields: [{
2059 group: 'input',
2060 classes: ['sharing-image-editor-control-input'],
2061 attributes: {
2062 name: editor_params.name + '[title]',
2063 value: data.title
2064 },
2065 dataset: {
2066 persistent: true
2067 },
2068 label: editor_('Template title', 'sharing-image')
2069 }],
2070 append: fieldset
2071 }); // Create background settings with custom logic.
2072
2073 createPermanentAttachment(fieldset, data); // Create width/height settings control.
2074
2075 builders.control({
2076 classes: ['sharing-image-editor-control', 'control-compact', 'control-sizes'],
2077 fields: [{
2078 group: 'input',
2079 classes: ['sharing-image-editor-control-input'],
2080 attributes: {
2081 name: editor_params.name + '[width]',
2082 value: data.width || '1200',
2083 placeholder: '1200'
2084 },
2085 label: editor_('Editor width', 'sharing-image')
2086 }, {
2087 group: 'input',
2088 classes: ['sharing-image-editor-control-input'],
2089 attributes: {
2090 name: editor_params.name + '[height]',
2091 value: data.height || '630',
2092 placeholder: '630'
2093 },
2094 label: editor_('Editor height', 'sharing-image')
2095 }],
2096 append: fieldset
2097 });
2098 const description = [];
2099 description.push(editor_('You can add multiple layers on your editor.', 'sharing-image'));
2100 description.push(editor_('Note that the stacking order of the layers is important.', 'sharing-image'));
2101 description.push(editor_('You can change the order using the arrows in the corner of each box.', 'sharing-image'));
2102 builders.control({
2103 classes: ['sharing-image-editor-control', 'control-reduced'],
2104 label: editor_('Add layers', 'sharing-image'),
2105 description: description.join(' '),
2106 append: fieldset
2107 }); // Create layers designer block.
2108
2109 createDesigner(fieldset, data);
2110 const footer = builders.control({
2111 classes: ['sharing-image-editor-control', 'control-footer'],
2112 append: fieldset
2113 }); // Create back to catalog button.
2114
2115 createCatalogButton(footer); // Create template deletion button.
2116
2117 createDeleteButton(footer);
2118 fieldset.addEventListener('change', e => {
2119 if (editor.classList.contains('editor-suspend')) {
2120 return;
2121 }
2122
2123 const target = e.target; // Skip fields that don't affect the poster.
2124
2125 if (target.hasAttribute('data-persistent')) {
2126 return;
2127 }
2128
2129 if (!target.hasAttribute('name')) {
2130 return;
2131 }
2132
2133 generateTemplate();
2134 });
2135 }
2136 /**
2137 * Create button to submit editor form.
2138 *
2139 * @param {HTMLElement} manager Manager element.
2140 */
2141
2142
2143 function createSubmitButton(manager) {
2144 builders.element('button', {
2145 text: editor_('Save changes', 'sharing-image'),
2146 classes: ['button', 'button-primary'],
2147 attributes: {
2148 type: 'submit'
2149 },
2150 append: manager
2151 });
2152 }
2153 /**
2154 * Create button to generate new template manually.
2155 *
2156 * @param {HTMLElement} manager Manager element.
2157 */
2158
2159
2160 function createGenerateButton(manager) {
2161 const button = builders.element('button', {
2162 text: editor_('Generate preview', 'sharing-image'),
2163 classes: ['button'],
2164 attributes: {
2165 type: 'button'
2166 },
2167 append: manager
2168 });
2169 button.addEventListener('click', () => {
2170 generateTemplate();
2171 });
2172 }
2173 /**
2174 * Create disable live-reloading checkbox.
2175 *
2176 * @param {HTMLElement} manager Manager element.
2177 * @param {Object} data Template data.
2178 */
2179
2180
2181 function createSuspendCheckbox(manager, data) {
2182 const checkbox = builders.checkbox({
2183 classes: ['sharing-image-editor-suspend'],
2184 attributes: {
2185 name: editor_params.name + '[suspend]',
2186 value: 'suspend'
2187 },
2188 label: editor_('Disable live-reload', 'sharing-image'),
2189 checked: data.suspend
2190 }, manager);
2191
2192 if (data.suspend) {
2193 editor.classList.add('editor-suspend');
2194 }
2195
2196 checkbox.addEventListener('change', () => {
2197 editor.classList.remove('editor-suspend');
2198
2199 if (checkbox.checked) {
2200 editor.classList.add('editor-suspend');
2201 }
2202 });
2203 }
2204 /**
2205 * Create template settings preview.
2206 *
2207 * @param {Object} data Current template data.
2208 */
2209
2210
2211 function createMonitor(data) {
2212 const monitor = builders.element('div', {
2213 classes: ['sharing-image-editor-monitor'],
2214 append: editor
2215 });
2216 const viewport = builders.element('div', {
2217 classes: ['sharing-image-editor-viewport'],
2218 append: monitor
2219 });
2220 createPreview(viewport, data);
2221 builders.element('div', {
2222 classes: ['sharing-image-editor-warning'],
2223 append: viewport
2224 });
2225 const manager = builders.element('div', {
2226 classes: ['sharing-image-editor-manager'],
2227 append: viewport
2228 }); // Create live-reload manager checkbox.
2229
2230 createSuspendCheckbox(manager, data); // Create submit form button.
2231
2232 createSubmitButton(manager); // Create template generator button.
2233
2234 createGenerateButton(manager);
2235 }
2236 /**
2237 * Create form hidden settings fields.
2238 *
2239 * @param {HTMLElement} content Settings content element.
2240 * @param {number} index Current option index.
2241 */
2242
2243
2244 function prepareEditor(content, index) {
2245 editor_params.name = 'sharing_image_editor';
2246 const form = builders.element('form', {
2247 classes: ['sharing-image-editor'],
2248 attributes: {
2249 action: editor_params.links.action,
2250 method: 'POST'
2251 },
2252 append: content
2253 });
2254 builders.element('input', {
2255 attributes: {
2256 type: 'hidden',
2257 name: 'action',
2258 value: editor_params.name
2259 },
2260 append: form
2261 });
2262 builders.element('input', {
2263 attributes: {
2264 type: 'hidden',
2265 name: 'sharing_image_index',
2266 value: index
2267 },
2268 append: form
2269 });
2270 builders.element('input', {
2271 attributes: {
2272 type: 'hidden',
2273 name: 'sharing_image_nonce',
2274 value: editor_params.nonce
2275 },
2276 append: form
2277 });
2278 form.addEventListener('submit', e => {
2279 e.preventDefault();
2280 saveTemplate();
2281 });
2282 return form;
2283 }
2284 /**
2285 * Create template editor page.
2286 *
2287 * @param {HTMLElement} content Settings content element.
2288 * @param {Object} settings Global settings object.
2289 * @param {number} index Current option index.
2290 * @param {Object} data Template data.
2291 */
2292
2293
2294 function createEditor(content, settings, index) {
2295 let data = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
2296 editor_params = settings; // Prepare form with hidden fields and events.
2297
2298 editor = prepareEditor(content, index); // Create monitor section part.
2299
2300 createMonitor(data); // Create fieldset section part.
2301
2302 createFieldset(data);
2303 }
2304
2305 /* harmony default export */ const sections_editor = (createEditor);
2306 ;// CONCATENATED MODULE: ./src/scripts/sections/config.js
2307 /**
2308 * Config settings tab.
2309 */
2310
2311 const {
2312 __: config_
2313 } = wp.i18n; // Store global scriot object for settings page.
2314
2315 let config_params = null;
2316 /**
2317 * Create default poster option.
2318 *
2319 * @param {HTMLElement} options Options form element.
2320 * @param {Object} data Config data object.
2321 */
2322
2323 function createDefaultOptions(options, data) {
2324 const control = builders.control({
2325 classes: ['sharing-image-config-control'],
2326 label: config_('Default poster', 'sharing-image'),
2327 append: options
2328 });
2329 builders.media({
2330 name: config_params.name + '[default]',
2331 classes: ['sharing-image-config-control-media'],
2332 label: config_('Default poster', 'sharing-image'),
2333 value: data.default,
2334 link: config_params.links.uploads,
2335 labels: {
2336 button: config_('Upload image', 'sharing-image'),
2337 heading: config_('Select default poster', 'sharing-image'),
2338 details: config_('Attachment details', 'sharing-image'),
2339 remove: config_('Remove image', 'sharing-image')
2340 },
2341 remove: true,
2342 append: control
2343 });
2344 const description = [];
2345 description.push(config_('The default poster is used on pages where there is no generated.', 'sharing-image'));
2346 description.push(config_('Best image size: 1200×630 pixels.', 'sharing-image'));
2347 builders.element('small', {
2348 text: description.join(' '),
2349 append: control
2350 });
2351 }
2352 /**
2353 * Create uploads directory option.
2354 *
2355 * @param {HTMLElement} options Options form element.
2356 * @param {Object} data Config data object.
2357 */
2358
2359
2360 function createUploadsOptions(options, data) {
2361 const control = builders.control({
2362 classes: ['sharing-image-config-control'],
2363 label: config_('Upload directory', 'sharing-image'),
2364 append: options
2365 });
2366 const fieldset = builders.element('div', {
2367 classes: ['sharing-image-config-control-fieldset'],
2368 append: control
2369 });
2370 builders.radio({
2371 classes: ['sharing-image-config-control-radio'],
2372 attributes: {
2373 name: config_params.name + '[uploads]',
2374 value: 'default'
2375 },
2376 label: config_('Use default uploads directory', 'sharing-image'),
2377 checked: data.uploads || 'default'
2378 }, fieldset);
2379 builders.radio({
2380 classes: ['sharing-image-config-control-radio'],
2381 attributes: {
2382 name: config_params.name + '[uploads]',
2383 value: 'custom'
2384 },
2385 label: config_('Choose custom storage for posters', 'sharing-image'),
2386 checked: data.uploads || 'default'
2387 }, fieldset);
2388 const input = builders.input({
2389 classes: ['sharing-image-config-control-input'],
2390 attributes: {
2391 name: config_params.name + '[storage]',
2392 value: data.storage || config_params.links.storage,
2393 disabled: 'disabled'
2394 }
2395 }, control);
2396 builders.element('small', {
2397 text: config_('Use relative path from site root. Directory should be writeable.', 'sharing-image'),
2398 append: control
2399 });
2400 control.querySelectorAll('input').forEach(radio => {
2401 if ('radio' !== radio.type) {
2402 return;
2403 } // Show storage input for checked custom radio.
2404
2405
2406 if (radio.checked && 'custom' === radio.value) {
2407 input.disabled = false;
2408 }
2409
2410 radio.addEventListener('change', () => {
2411 input.disabled = true;
2412
2413 if ('custom' === radio.value) {
2414 input.disabled = false;
2415 }
2416 });
2417 });
2418 }
2419 /**
2420 * Create format and quality poster options.
2421 *
2422 * @param {HTMLElement} options Options form element.
2423 * @param {Object} data Config data object.
2424 */
2425
2426
2427 function createImageOptions(options, data) {
2428 const control = builders.control({
2429 classes: ['sharing-image-config-control', 'control-extra'],
2430 label: config_('Poster image format', 'sharing-image'),
2431 help: config_('The higher the value, the less compression. Availible for JPEG only.', 'sharing-image'),
2432 fields: [{
2433 group: 'select',
2434 classes: ['sharing-image-config-control-select'],
2435 options: {
2436 jpg: config_('JPEG', 'sharing-image'),
2437 png: config_('PNG', 'sharing-image')
2438 },
2439 attributes: {
2440 name: config_params.name + '[format]'
2441 },
2442 selected: data.format || 'jpg'
2443 }, {
2444 group: 'input',
2445 classes: ['sharing-image-config-control-range'],
2446 attributes: {
2447 type: 'range',
2448 name: config_params.name + '[quality]',
2449 min: 10,
2450 max: 100,
2451 step: 5,
2452 value: data.quality || '90',
2453 disabled: 'disabled'
2454 },
2455 label: config_('Image quality', 'sharing-image')
2456 }],
2457 append: options
2458 }); // Find control format select.
2459
2460 const format = control.querySelector('select'); // Find control quiality input.
2461
2462 const quality = control.querySelector('input');
2463
2464 if ('jpg' === format.value) {
2465 quality.disabled = false;
2466 }
2467
2468 format.addEventListener('change', () => {
2469 quality.disabled = true;
2470
2471 if ('jpg' === format.value) {
2472 quality.disabled = false;
2473 }
2474 });
2475 }
2476 /**
2477 * Create autogenerate poster options.
2478 *
2479 * @param {HTMLElement} options Options form element.
2480 * @param {Object} data Config data object.
2481 * @param {Array} templates List of templates.
2482 */
2483
2484
2485 function createAutogenerateOptions(options, data, templates) {
2486 const fields = {}; // Add the option for disabling feature.
2487
2488 fields.manual = config_('Disable auto generation', 'sharing-image');
2489 templates.forEach((template, i) => {
2490 fields[i] = template.title || config_('Untitled', 'sharing-image');
2491 });
2492 builders.control({
2493 classes: ['sharing-image-config-control'],
2494 label: config_('Auto generate poster', 'sharing-image'),
2495 help: config_('This template will be applied automatically on post save.', 'sharing-image'),
2496 fields: [{
2497 group: 'select',
2498 classes: ['sharing-image-config-control-select'],
2499 options: fields,
2500 attributes: {
2501 name: config_params.name + '[autogenerate]'
2502 },
2503 selected: String(data.autogenerate) || 'manual'
2504 }],
2505 append: options
2506 });
2507 }
2508 /**
2509 * Create required form meta fields.
2510 *
2511 * @param {HTMLElement} options Options form element.
2512 */
2513
2514
2515 function createMetaFields(options) {
2516 builders.element('input', {
2517 attributes: {
2518 type: 'hidden',
2519 name: 'action',
2520 value: config_params.name
2521 },
2522 append: options
2523 });
2524 builders.element('input', {
2525 attributes: {
2526 type: 'hidden',
2527 name: 'sharing_image_nonce',
2528 value: config_params.nonce
2529 },
2530 append: options
2531 });
2532 builders.element('button', {
2533 text: config_('Save changes', 'sharing-image'),
2534 classes: ['button', 'button-primary'],
2535 attributes: {
2536 type: 'submit'
2537 },
2538 append: options
2539 });
2540 }
2541 /**
2542 * Create templates catalog from options.
2543 *
2544 * @param {HTMLElement} content Settings content element.
2545 * @param {Object} settings Global settings field.
2546 */
2547
2548
2549 function createConfig(content, settings) {
2550 config_params = settings; // Set params name for template form fields.
2551
2552 config_params.name = 'sharing_image_config'; // Find config element
2553
2554 const config = content.querySelector('.sharing-image-config');
2555
2556 if (null === config) {
2557 return;
2558 }
2559
2560 const options = builders.element('form', {
2561 classes: ['sharing-image-config-options'],
2562 attributes: {
2563 action: config_params.links.action,
2564 method: 'POST'
2565 },
2566 append: config
2567 });
2568 const data = config_params.config || {};
2569 const templates = config_params.templates || []; // Poster image options.
2570
2571 createImageOptions(options, data); // Autogenerate poster.
2572
2573 createAutogenerateOptions(options, data, templates); // Uploads directory options.
2574
2575 createUploadsOptions(options, data); // Default poster.
2576
2577 createDefaultOptions(options, data); // Create required form fields
2578
2579 createMetaFields(options);
2580 }
2581
2582 /* harmony default export */ const config = (createConfig);
2583 ;// CONCATENATED MODULE: ./src/scripts/sections/premium.js
2584 /**
2585 * Premium settings tab.
2586 */
2587
2588 /* global ajaxurl:true */
2589
2590 const {
2591 __: premium_
2592 } = wp.i18n; // Store global scriot object for settings page.
2593
2594 let premium_params = null; // Premium HTML emelent.
2595
2596 let premium = null;
2597 /**
2598 * Parse error code from settings or AJAX response.
2599 *
2600 * @param {string} code Error code from settings or AJAX response.
2601 * @param {string} title Prepended error title. Optional.
2602 */
2603
2604 function parseErrorCode(code, title) {
2605 const message = [];
2606
2607 if (undefined === title) {
2608 title = premium_('Verification failed.', 'sharing-image');
2609 }
2610
2611 message.push(title);
2612
2613 switch (code) {
2614 case 'LIMIT_EXCEEDED':
2615 message.push(premium_('The number of valid licenses for this key has been exceeded.', 'sharing-image'));
2616 break;
2617
2618 case 'KEY_NOT_FOUND':
2619 message.push(premium_('Premium key is invalid or expired.', 'sharing-image'));
2620 break;
2621
2622 case 'SERVER_ERROR':
2623 message.push(premium_('Unable to get a response from the verification server.', 'sharing-image'));
2624 break;
2625 }
2626
2627 return message.join(' ');
2628 }
2629 /**
2630 * Show premium warning message.
2631 *
2632 * @param {string} message Warning message.
2633 */
2634
2635
2636 function showPremiumError(message) {
2637 // Try to find warning element.
2638 const warning = premium.querySelector('.sharing-image-premium-warning');
2639
2640 if (null === warning) {
2641 return;
2642 }
2643
2644 warning.classList.add('warning-visible');
2645 warning.textContent = message || premium_('Unknown request error', 'sharing-image');
2646 }
2647 /**
2648 * Remove warning message block.
2649 */
2650
2651
2652 function hidePremiumError() {
2653 // Try to find warning element.
2654 const warning = premium.querySelector('.sharing-image-premium-warning');
2655
2656 if (null === warning) {
2657 return;
2658 }
2659
2660 warning.classList.remove('warning-visible');
2661 }
2662 /**
2663 * Revoke Premium key.
2664 *
2665 * @param {HTMLElement} access Access form element.
2666 */
2667
2668
2669 function revokePremium(access) {
2670 access.classList.add('access-loader');
2671 const request = new XMLHttpRequest();
2672 request.open('POST', ajaxurl);
2673 request.responseType = 'json'; // Create data bundle using form data.
2674
2675 const bundle = new window.FormData(access);
2676 bundle.set('action', 'sharing_image_revoke');
2677 hidePremiumError();
2678 request.addEventListener('load', () => {
2679 const response = request.response || {}; // Hide form loader class.
2680
2681 access.classList.remove('access-loader');
2682
2683 if (!response.data) {
2684 return showPremiumError();
2685 }
2686
2687 if (!response.success) {
2688 return showPremiumError(response.data);
2689 }
2690
2691 premium_params.license = response.data; // Refresh premium fields.
2692
2693 preparePremiumFields();
2694 });
2695 request.addEventListener('error', () => {
2696 showPremiumError(); // Hide form loader class.
2697
2698 access.classList.remove('access-loader');
2699 });
2700 request.send(bundle);
2701 }
2702 /**
2703 * Verify Premium key.
2704 *
2705 * @param {HTMLElement} access Access form element.
2706 */
2707
2708
2709 function verifyPremium(access) {
2710 access.classList.add('access-loader');
2711 const request = new XMLHttpRequest();
2712 request.open('POST', ajaxurl);
2713 request.responseType = 'json'; // Create data bundle using form data.
2714
2715 const bundle = new window.FormData(access);
2716 bundle.set('action', 'sharing_image_verify');
2717 hidePremiumError();
2718 request.addEventListener('load', () => {
2719 const response = request.response || {}; // Hide form loader class.
2720
2721 access.classList.remove('access-loader');
2722
2723 if (!response.data) {
2724 return showPremiumError();
2725 }
2726
2727 if (!response.success) {
2728 return showPremiumError(parseErrorCode(response.code, response.data));
2729 }
2730
2731 premium_params.license = response.data; // Refresh premium fields.
2732
2733 preparePremiumFields();
2734 });
2735 request.addEventListener('error', () => {
2736 showPremiumError(); // Hide form loader class.
2737
2738 access.classList.remove('access-loader');
2739 });
2740 request.send(bundle);
2741 }
2742 /**
2743 * Show verify form if stil not premium.
2744 *
2745 * @param {HTMLElement} access Access HTML element.
2746 * @param {Object} license License data.
2747 */
2748
2749
2750 function showVerifyForm(access, license) {
2751 if (license.error) {
2752 showPremiumError(parseErrorCode(license.error));
2753 }
2754
2755 builders.element('strong', {
2756 text: premium_('Do you already have a key? Enter it here', 'sharing-image'),
2757 append: access
2758 });
2759 const verify = builders.element('div', {
2760 classes: ['sharing-image-premium-verify'],
2761 append: access
2762 });
2763 builders.element('input', {
2764 label: premium_('Your Premium key', 'sharing-image'),
2765 attributes: {
2766 type: 'text',
2767 name: 'sharing_image_key',
2768 value: license.key
2769 },
2770 append: verify
2771 });
2772 builders.element('button', {
2773 classes: ['button'],
2774 text: premium_('Submit', 'sharing-image'),
2775 attributes: {
2776 type: 'submit'
2777 },
2778 append: verify
2779 });
2780 builders.element('span', {
2781 classes: ['spinner'],
2782 append: verify
2783 });
2784 access.addEventListener('submit', e => {
2785 e.preventDefault();
2786 verifyPremium(access);
2787 });
2788 }
2789 /**
2790 * Show alert for develop license mode.
2791 */
2792
2793
2794 function showDevelopAlert() {
2795 showPremiumError(premium_('Using plugin with a development license is prohibited in production.', 'sharing-image'));
2796 }
2797 /**
2798 * Show revoke Premium button.
2799 *
2800 * @param {HTMLElement} access Access HTML element.
2801 */
2802
2803
2804 function showRevokeButton(access) {
2805 const revoke = builders.element('div', {
2806 classes: ['sharing-image-premium-revoke'],
2807 append: access
2808 });
2809 const description = [];
2810 description.push(premium_('Disabling premium mode will not remove the license for this domain.', 'sharing-image'));
2811 description.push(premium_('Your current key will also be saved in the plugin settings.', 'sharing-image'));
2812 description.push(premium_('Use key management tool to delete the license for the site.', 'sharing-image'));
2813 builders.element('p', {
2814 text: description.join(' '),
2815 append: revoke
2816 });
2817 builders.element('button', {
2818 classes: ['button'],
2819 text: premium_('Disable Premium'),
2820 attributes: {
2821 type: 'submit'
2822 },
2823 append: revoke
2824 });
2825 builders.element('span', {
2826 classes: ['spinner'],
2827 append: revoke
2828 });
2829 access.addEventListener('submit', e => {
2830 e.preventDefault();
2831 revokePremium(access);
2832 });
2833 }
2834 /**
2835 * Show permit information.
2836 *
2837 * @param {HTMLElement} access Access HTML element.
2838 * @param {string} key License key from settings.
2839 */
2840
2841
2842 function showLicenseInfo(access, key) {
2843 const permit = builders.element('div', {
2844 classes: ['sharing-image-premium-permit'],
2845 append: access
2846 });
2847 const button = builders.element('button', {
2848 classes: ['sharing-image-premium-show', 'button'],
2849 text: premium_('Show License key'),
2850 attributes: {
2851 type: 'button'
2852 },
2853 append: permit
2854 });
2855 button.addEventListener('click', () => {
2856 permit.classList.toggle('permit-visible');
2857 });
2858 builders.element('strong', {
2859 text: key,
2860 append: permit
2861 });
2862 return permit;
2863 }
2864 /**
2865 * Show fields if user has the license.
2866 *
2867 * @param {HTMLElement} access Access HTML element.
2868 * @param {Object} license License data.
2869 */
2870
2871
2872 function showPremiumData(access, license) {
2873 premium.classList.add('premium-enabled');
2874
2875 if (license.develop) {
2876 return showDevelopAlert();
2877 }
2878
2879 if (license.key) {
2880 showLicenseInfo(access, license.key);
2881 }
2882
2883 showRevokeButton(access);
2884 }
2885 /**
2886 * Set premium fields according settings.
2887 */
2888
2889
2890 function preparePremiumFields() {
2891 let access = premium.querySelector('.sharing-image-premium-access');
2892
2893 if (null !== access) {
2894 premium.removeChild(access);
2895 }
2896
2897 access = builders.element('form', {
2898 classes: ['sharing-image-premium-access'],
2899 attributes: {
2900 action: '',
2901 method: 'POST'
2902 },
2903 append: premium
2904 });
2905 premium.classList.remove('premium-enabled');
2906 builders.element('input', {
2907 attributes: {
2908 type: 'hidden',
2909 name: 'sharing_image_nonce',
2910 value: premium_params.nonce
2911 },
2912 append: access
2913 });
2914 const license = premium_params.license || {}; // Show fields if user has the license.
2915
2916 if (license.premium || license.develop) {
2917 return showPremiumData(access, license);
2918 }
2919
2920 return showVerifyForm(access, license);
2921 }
2922 /**
2923 * Create templates catalog from options.
2924 *
2925 * @param {HTMLElement} content Settings content element.
2926 * @param {Object} settings Global settings field.
2927 */
2928
2929
2930 function createPremium(content, settings) {
2931 premium_params = settings; // Find premium element
2932
2933 premium = content.querySelector('.sharing-image-premium');
2934
2935 if (null === premium) {
2936 return;
2937 }
2938
2939 builders.element('div', {
2940 classes: ['sharing-image-premium-warning'],
2941 append: premium
2942 });
2943 preparePremiumFields();
2944 }
2945
2946 /* harmony default export */ const sections_premium = (createPremium);
2947 ;// CONCATENATED MODULE: ./src/scripts/sections/picker.js
2948 /**
2949 * Metabox handler.
2950 */
2951
2952 /* global ajaxurl:true */
2953
2954 const {
2955 __: picker_
2956 } = wp.i18n; // Store global script object for metabox.
2957
2958 let picker_params = null; // Poster HTML element.
2959
2960 let poster = null; // Is gutenberg editor used.
2961
2962 let gutenberg = false;
2963 /**
2964 * Show picker warning message.
2965 *
2966 * @param {string} message Warning message.
2967 */
2968
2969 function showPickerError(message) {
2970 const picker = poster.parentNode; // Try to find warning element.
2971
2972 const warning = picker.querySelector('.sharing-image-picker-warning');
2973
2974 if (null === warning) {
2975 return;
2976 }
2977
2978 warning.classList.add('warning-visible');
2979 warning.textContent = message || picker_('Unknown generation error', 'sharing-image');
2980 }
2981 /**
2982 * Remove warning message block.
2983 */
2984
2985
2986 function hidePickerError() {
2987 const picker = poster.parentNode; // Try to find warning element.
2988
2989 const warning = picker.querySelector('.sharing-image-picker-warning');
2990
2991 if (null === warning) {
2992 return;
2993 }
2994
2995 warning.classList.remove('warning-visible');
2996 }
2997 /**
2998 * Handle poster generation action.
2999 *
3000 * @param {HTMLElement} picker Picker element.
3001 */
3002
3003
3004 function generatePoster(picker) {
3005 const request = new XMLHttpRequest();
3006 request.open('POST', ajaxurl);
3007 request.responseType = 'json';
3008 poster.classList.add('poster-loader'); // Create data form data bundle.
3009
3010 const bundle = new window.FormData();
3011 bundle.set('action', 'sharing_image_generate');
3012 picker.querySelectorAll('[name]').forEach(field => {
3013 bundle.append(field.name, field.value);
3014 });
3015 hidePickerError();
3016 request.addEventListener('load', () => {
3017 const response = request.response || {}; // Hide preview loader on request complete.
3018
3019 poster.classList.remove('poster-loader');
3020
3021 if (!response.data) {
3022 return showPickerError();
3023 }
3024
3025 if (!response.success) {
3026 return showPickerError(response.data);
3027 }
3028
3029 for (const key in response.data) {
3030 // Find all poster input fields and set response data value.
3031 poster.querySelectorAll('input').forEach(input => {
3032 const name = picker_params.name + '[' + key + ']';
3033
3034 if (name === input.name) {
3035 input.value = response.data[key];
3036 }
3037 });
3038 }
3039
3040 let image = poster.querySelector('img');
3041
3042 if (null === image) {
3043 image = builders.element('img', {
3044 append: poster
3045 });
3046 }
3047
3048 image.src = response.data.poster; // Show the poster.
3049
3050 poster.classList.add('poster-visible');
3051 });
3052 request.addEventListener('error', () => {
3053 showPickerError(); // Hide preview loader on request complete.
3054
3055 poster.classList.remove('poster-loader');
3056 });
3057 request.send(bundle);
3058 }
3059 /**
3060 * Create designer template selector.
3061 *
3062 * @param {HTMLElement} picker Picker element.
3063 * @param {HTMLElement} designer Designer element.
3064 * @param {Object} selected Seleted template.
3065 */
3066
3067
3068 function createTemplate(picker, designer, selected) {
3069 const fields = {};
3070 picker_params.templates.forEach((template, i) => {
3071 fields[i] = template.title || picker_('Untitled', 'sharing-image');
3072 });
3073 const template = builders.select({
3074 classes: ['sharing-image-picker-template'],
3075 options: fields,
3076 attributes: {
3077 name: picker_params.name + '[template]'
3078 },
3079 selected: String(selected)
3080 }, picker);
3081 template.addEventListener('change', () => {
3082 const fieldset = designer.childNodes;
3083
3084 for (let i = 0; i < fieldset.length; i++) {
3085 fieldset[i].classList.remove('fieldset-visible');
3086
3087 if (i === parseInt(template.value)) {
3088 fieldset[i].classList.add('fieldset-visible');
3089 }
3090 }
3091 });
3092 return template;
3093 }
3094 /**
3095 * Prefill caption fields for classic editor.
3096 *
3097 * @param {HTMLElement} textarea Caption textarea field.
3098 * @param {string} preset Preset field.
3099 */
3100
3101
3102 function fillClassicEditorPreset(textarea, preset) {
3103 const source = document.getElementById(preset);
3104
3105 if (null === source) {
3106 return;
3107 }
3108
3109 const updateCaption = () => {
3110 textarea.value = source.value;
3111 };
3112
3113 source.addEventListener('change', updateCaption); // Stop textarea update after first user input.
3114
3115 textarea.addEventListener('change', () => {
3116 source.removeEventListener('change', updateCaption);
3117 });
3118 updateCaption();
3119 }
3120 /**
3121 * Prefill caption fields for block editor.
3122 *
3123 * @param {HTMLElement} textarea Caption textarea field.
3124 * @param {string} preset Preset field.
3125 */
3126
3127
3128 function fillBlockEditorPreset(textarea, preset) {
3129 const getAttribute = () => {
3130 return wp.data.select('core/editor').getEditedPostAttribute(preset);
3131 };
3132
3133 let attribute = getAttribute();
3134 wp.data.subscribe(() => {
3135 const updated = getAttribute();
3136
3137 if (attribute !== updated) {
3138 textarea.textContent = updated;
3139 }
3140
3141 attribute = updated;
3142 });
3143 }
3144 /**
3145 * Try to prefill caption field.
3146 *
3147 * @param {HTMLElement} textarea Caption textarea field.
3148 * @param {string} preset Preset field.
3149 */
3150
3151
3152 function fillCaptionPreset(textarea, preset) {
3153 if (gutenberg) {
3154 return fillBlockEditorPreset(textarea, preset);
3155 }
3156
3157 fillClassicEditorPreset(textarea, preset);
3158 }
3159 /**
3160 * Create designer attachment field for dynamic background.
3161 *
3162 * @param {HTMLElement} fieldset Fieldset element.
3163 * @param {Object} template Template data.
3164 * @param {Array} values Template fieldset values.
3165 * @param {string} name Field name attribute.
3166 */
3167
3168
3169 function createDesignerAttachment(fieldset, template, values, name) {
3170 if ('dynamic' !== template.background) {
3171 return;
3172 }
3173
3174 builders.media({
3175 name: name + '[attachment]',
3176 classes: ['sharing-image-picker-media'],
3177 value: values.attachment,
3178 link: picker_params.links.uploads,
3179 labels: {
3180 button: picker_('Upload background', 'sharing-image'),
3181 heading: picker_('Select background image', 'sharing-image'),
3182 details: picker_('Attachment', 'sharing-image')
3183 },
3184 append: fieldset
3185 });
3186 }
3187 /**
3188 * Create designer captions for text layers.
3189 *
3190 * @param {HTMLElement} fieldset Fieldset element.
3191 * @param {Object} template Template data.
3192 * @param {Array} values Template fieldset values.
3193 * @param {string} name Field name attribute.
3194 */
3195
3196
3197 function createDesignerCaptions(fieldset, template, values, name) {
3198 const captions = values.captions || []; // Set default layers list.
3199
3200 template.layers = template.layers || [];
3201 template.layers.forEach((layer, n) => {
3202 if ('text' !== layer.type || !layer.dynamic) {
3203 return;
3204 }
3205
3206 const textarea = builders.textarea({
3207 classes: ['sharing-image-picker-caption'],
3208 label: layer.title || null,
3209 attributes: {
3210 name: name + `[captions][${n}]`
3211 }
3212 }, fieldset);
3213
3214 if (!captions[n]) {
3215 fillCaptionPreset(textarea, layer.preset);
3216 }
3217
3218 textarea.textContent = captions[n];
3219 });
3220 }
3221 /**
3222 * Create fields designer.
3223 *
3224 * @param {HTMLElement} picker Picker element.
3225 * @param {Object} data Picker data object.
3226 */
3227
3228
3229 function picker_createDesigner(picker, data) {
3230 const designer = builders.element('div', {
3231 classes: ['sharing-image-picker-designer']
3232 });
3233 let selected = data.template || 0; // Reset selected template if index undefined.
3234
3235 if (!picker_params.templates[selected]) {
3236 selected = 0;
3237 } // Create designer fields
3238
3239
3240 picker_params.templates.forEach((template, i) => {
3241 // Set default layers list.
3242 template.layers = template.layers || [];
3243 const fieldset = builders.element('div', {
3244 classes: ['sharing-image-picker-fieldset'],
3245 append: designer
3246 });
3247
3248 if (i === parseInt(selected)) {
3249 fieldset.classList.add('fieldset-visible');
3250 }
3251
3252 let values = {};
3253
3254 if (data.fieldset && data.fieldset[i]) {
3255 values = data.fieldset[i];
3256 }
3257
3258 const name = picker_params.name + `[fieldset][${i}]`;
3259 builders.element('input', {
3260 attributes: {
3261 type: 'hidden',
3262 name: name
3263 },
3264 append: fieldset
3265 }); // Create attachment field.
3266
3267 createDesignerAttachment(fieldset, template, values, name); // Create all caption fields.
3268
3269 createDesignerCaptions(fieldset, template, values, name);
3270 }); // Create template selector.
3271
3272 if (picker_params.templates.length > 1) {
3273 createTemplate(picker, designer, selected);
3274 }
3275
3276 picker.appendChild(designer);
3277 }
3278 /**
3279 * Create button to generate new metabox poster.
3280 *
3281 * @param {HTMLElement} picker Picker element.
3282 * @param {HTMLElement} manager Manager element.
3283 */
3284
3285
3286 function picker_createGenerateButton(picker, manager) {
3287 const button = builders.element('button', {
3288 classes: ['sharing-image-picker-generate', 'button'],
3289 text: picker_('Generate', 'sharing-image'),
3290 attributes: {
3291 type: 'button'
3292 },
3293 append: manager
3294 });
3295 button.addEventListener('click', () => {
3296 generatePoster(picker);
3297 });
3298 }
3299 /**
3300 * Create button to delete current metabox poster.
3301 *
3302 * @param {HTMLElement} manager Manager element.
3303 */
3304
3305
3306 function picker_createDeleteButton(manager) {
3307 const button = builders.element('button', {
3308 classes: ['sharing-image-picker-delete', 'button', 'button-delete'],
3309 text: picker_('Remove', 'sharing-image'),
3310 attributes: {
3311 type: 'button'
3312 },
3313 append: manager
3314 });
3315 button.addEventListener('click', () => {
3316 const image = poster.querySelector('img');
3317
3318 if (null !== image) {
3319 poster.removeChild(image);
3320 }
3321
3322 poster.querySelectorAll('input').forEach(input => {
3323 input.value = '';
3324 });
3325 poster.classList.remove('poster-visible');
3326 });
3327 }
3328 /**
3329 * Create picker manager.
3330 *
3331 * @param {HTMLElement} picker Picker element.
3332 */
3333
3334
3335 function createManager(picker) {
3336 const manager = builders.element('div', {
3337 classes: ['sharing-image-picker-manager'],
3338 append: picker
3339 }); // Create poster generation button.
3340
3341 picker_createGenerateButton(picker, manager); // Create poster removing button.
3342
3343 picker_createDeleteButton(manager);
3344 builders.element('span', {
3345 classes: ['sharing-image-picker-spinner', 'spinner'],
3346 append: manager
3347 });
3348 }
3349 /**
3350 * Create poster block.
3351 *
3352 * @param {HTMLElement} picker Picker element.
3353 * @param {Object} data Picker data object.
3354 */
3355
3356
3357 function createPoster(picker, data) {
3358 poster = builders.element('div', {
3359 classes: ['sharing-image-picker-poster'],
3360 append: picker
3361 });
3362
3363 if (data.poster) {
3364 builders.element('img', {
3365 attributes: {
3366 src: data.poster,
3367 alt: ''
3368 },
3369 append: poster
3370 });
3371 poster.classList.add('poster-visible');
3372 }
3373
3374 builders.element('input', {
3375 attributes: {
3376 type: 'hidden',
3377 name: picker_params.name + '[poster]',
3378 value: data.poster
3379 },
3380 append: poster
3381 });
3382 builders.element('input', {
3383 attributes: {
3384 type: 'hidden',
3385 name: picker_params.name + '[width]',
3386 value: data.width
3387 },
3388 append: poster
3389 });
3390 builders.element('input', {
3391 attributes: {
3392 type: 'hidden',
3393 name: picker_params.name + '[height]',
3394 value: data.height
3395 },
3396 append: poster
3397 });
3398 return poster;
3399 }
3400 /**
3401 * Check that the poster sizes are set or show an error message.
3402 *
3403 * @param {Object} data Picker data object.
3404 */
3405
3406
3407 function showSizesWarning(data) {
3408 if (!data.poster) {
3409 return;
3410 }
3411
3412 if (!data.width || !data.height) {
3413 showPickerError(picker_('Image sizes are not set. Regenerate the poster.', 'sharing-image'));
3414 }
3415 }
3416 /**
3417 * Get new config with AJAX call and reinit metabox.
3418 *
3419 * @param {HTMLElement} widget Widget element.
3420 */
3421
3422
3423 const rebuildPicker = widget => {
3424 const request = new XMLHttpRequest();
3425 request.open('POST', ajaxurl);
3426 request.responseType = 'json';
3427 poster.classList.add('poster-loader'); // We need post ID for this request.
3428
3429 const postId = wp.data.select('core/editor').getCurrentPostId(); // Create data form data bundle.
3430
3431 const bundle = new window.FormData();
3432 bundle.set('action', 'sharing_image_rebuild');
3433 bundle.set('post', postId); // Find picker child.
3434
3435 const picker = widget.querySelector('.sharing-image-picker');
3436 picker.querySelectorAll('[name]').forEach(field => {
3437 if ('sharing_image_nonce' === field.name) {
3438 bundle.append(field.name, field.value);
3439 }
3440 });
3441 hidePickerError();
3442 request.addEventListener('load', () => {
3443 const response = request.response || {}; // Hide preview loader on request complete.
3444
3445 poster.classList.remove('poster-loader');
3446
3447 if (!response.data) {
3448 return showPickerError();
3449 }
3450
3451 if (!response.success) {
3452 return showPickerError(response.data);
3453 }
3454
3455 buildPicker(widget, response.data);
3456 });
3457 request.addEventListener('error', () => {
3458 showPickerError(); // Hide preview loader on request complete.
3459
3460 poster.classList.remove('poster-loader');
3461 });
3462 request.send(bundle);
3463 };
3464 /**
3465 * Wait Gutenberg post saving and reinit tasks list.
3466 *
3467 * @param {HTMLElement} widget Widget element.
3468 */
3469
3470
3471 const subscribeOnSaving = widget => {
3472 let wasSavingPost = wp.data.select('core/edit-post').isSavingMetaBoxes();
3473 wp.data.subscribe(() => {
3474 const isSavingPost = wp.data.select('core/edit-post').isSavingMetaBoxes();
3475
3476 if (wasSavingPost && !isSavingPost) {
3477 rebuildPicker(widget);
3478 }
3479
3480 wasSavingPost = isSavingPost;
3481 });
3482 };
3483 /**
3484 * Build metabox fields.
3485 *
3486 * @param {HTMLElement} widget Widget element.
3487 * @param {Object} settings Global settings object.
3488 */
3489
3490
3491 function buildPicker(widget, settings) {
3492 picker_params = settings; // Set params name for template form fields.
3493
3494 picker_params.name = 'sharing_image_picker';
3495
3496 while (widget.firstChild) {
3497 widget.removeChild(widget.lastChild);
3498 }
3499
3500 if ('taxonomy' === picker_params.context) {
3501 const title = builders.element('div', {
3502 classes: ['sharing-image-title'],
3503 append: widget
3504 });
3505 builders.element('strong', {
3506 text: picker_('Sharing Image', 'sharing-image'),
3507 append: title
3508 });
3509 }
3510
3511 const picker = builders.element('div', {
3512 classes: ['sharing-image-picker'],
3513 append: widget
3514 });
3515 const data = picker_params.meta || {}; // Create poster block.
3516
3517 createPoster(picker, data); // Create fields designer.
3518
3519 picker_createDesigner(picker, data);
3520 builders.element('div', {
3521 classes: ['sharing-image-picker-warning'],
3522 append: picker
3523 }); // Show unset poster sizes warning.
3524
3525 showSizesWarning(data); // Create metabox manager block.
3526
3527 createManager(picker);
3528 builders.element('input', {
3529 attributes: {
3530 type: 'hidden',
3531 name: 'sharing_image_nonce',
3532 value: picker_params.nonce
3533 },
3534 append: picker
3535 });
3536 }
3537 /**
3538 * Create metabox generator picker and subscribe to events.
3539 *
3540 * @param {HTMLElement} widget Widget element.
3541 * @param {Object} settings Global settings object.
3542 */
3543
3544
3545 function createPicker(widget, settings) {
3546 buildPicker(widget, settings);
3547 gutenberg = wp.data && wp.data.select('core/editor');
3548
3549 if (gutenberg) {
3550 subscribeOnSaving(widget);
3551 }
3552 }
3553
3554 /* harmony default export */ const picker = (createPicker);
3555 ;// CONCATENATED MODULE: ./src/scripts/sections/index.js
3556
3557
3558
3559
3560
3561 const Section = {
3562 catalog: catalog,
3563 editor: sections_editor,
3564 config: config,
3565 premium: sections_premium,
3566 picker: picker
3567 };
3568 /* harmony default export */ const sections = (Section);
3569 ;// CONCATENATED MODULE: ./src/scripts/widget.js
3570
3571 /**
3572 * Init metabox handler.
3573 */
3574
3575 (function () {
3576 if (typeof 'undefined' === wp) {
3577 return;
3578 }
3579
3580 const object = window.sharingImageWidget || {}; // Set default templates empty list.
3581
3582 object.templates = object.templates || []; // Find metabox element.
3583
3584 const widgets = document.querySelectorAll('.sharing-image-widget');
3585 widgets.forEach(widget => {
3586 if (object.context) {
3587 widget.classList.add(`widget-${object.context}`);
3588 }
3589
3590 sections.picker(widget, object);
3591 });
3592 })();
3593 /******/ })()
3594 ;