PluginProbe
Sharing Image / 2.0.15
Sharing Image v2.0.15
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 / settings.js

settings.js in Sharing Image 2.0.15, at assets/scripts/settings.js

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