PluginProbe
Sharing Image / 2.0.17
Sharing Image v2.0.17
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.17, at assets/scripts/settings.js

3,671 lines 90.8 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.', 'sharing-image'),
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 gif: wp.i18n.__('GIF', 'sharing-image')
2430 },
2431 attributes: {
2432 name: config_params.name + '[format]'
2433 },
2434 selected: data.format || 'jpg'
2435 }, {
2436 group: 'input',
2437 classes: ['sharing-image-config-control-range'],
2438 attributes: {
2439 type: 'range',
2440 name: config_params.name + '[quality]',
2441 min: 10,
2442 max: 100,
2443 step: 5,
2444 value: data.quality || '90',
2445 disabled: 'disabled'
2446 },
2447 label: wp.i18n.__('Image quality', 'sharing-image')
2448 }],
2449 append: options
2450 }); // Find control format select.
2451
2452 const format = control.querySelector('select'); // Find control quiality input.
2453
2454 const quality = control.querySelector('input');
2455
2456 if ('jpg' === format.value) {
2457 quality.disabled = false;
2458 }
2459
2460 format.addEventListener('change', () => {
2461 quality.disabled = true;
2462
2463 if ('jpg' === format.value) {
2464 quality.disabled = false;
2465 }
2466 });
2467 }
2468 /**
2469 * Create autogenerate poster options.
2470 *
2471 * @param {HTMLElement} options Options form element.
2472 * @param {Object} data Config data object.
2473 * @param {Array} templates List of templates.
2474 */
2475
2476
2477 function createAutogenerateOptions(options, data, templates) {
2478 const fields = {}; // Add the option for disabling feature.
2479
2480 fields.manual = wp.i18n.__('Disable auto generation', 'sharing-image');
2481 templates.forEach((template, i) => {
2482 fields[i] = template.title || wp.i18n.__('Untitled', 'sharing-image');
2483 });
2484 let selected = data.autogenerate;
2485
2486 if (typeof selected === 'undefined') {
2487 selected = 'manual';
2488 }
2489
2490 builders.control({
2491 classes: ['sharing-image-config-control'],
2492 label: wp.i18n.__('Auto generate poster', 'sharing-image'),
2493 help: wp.i18n.__('This template will be applied automatically on post save.', 'sharing-image'),
2494 fields: [{
2495 group: 'select',
2496 classes: ['sharing-image-config-control-select'],
2497 options: fields,
2498 attributes: {
2499 name: config_params.name + '[autogenerate]'
2500 },
2501 selected: String(selected)
2502 }],
2503 append: options
2504 });
2505 }
2506 /**
2507 * Create required form meta fields.
2508 *
2509 * @param {HTMLElement} options Options form element.
2510 */
2511
2512
2513 function createMetaFields(options) {
2514 builders.element('input', {
2515 attributes: {
2516 type: 'hidden',
2517 name: 'action',
2518 value: config_params.name
2519 },
2520 append: options
2521 });
2522 builders.element('input', {
2523 attributes: {
2524 type: 'hidden',
2525 name: 'sharing_image_nonce',
2526 value: config_params.nonce
2527 },
2528 append: options
2529 });
2530 builders.element('button', {
2531 text: wp.i18n.__('Save changes', 'sharing-image'),
2532 classes: ['button', 'button-primary'],
2533 attributes: {
2534 type: 'submit'
2535 },
2536 append: options
2537 });
2538 }
2539 /**
2540 * Create templates catalog from options.
2541 *
2542 * @param {HTMLElement} content Settings content element.
2543 * @param {Object} settings Global settings field.
2544 */
2545
2546
2547 function createConfig(content, settings) {
2548 config_params = settings; // Set params name for template form fields.
2549
2550 config_params.name = 'sharing_image_config'; // Find config element
2551
2552 const config = content.querySelector('.sharing-image-config');
2553
2554 if (null === config) {
2555 return;
2556 }
2557
2558 const options = builders.element('form', {
2559 classes: ['sharing-image-config-options'],
2560 attributes: {
2561 action: config_params.links.action,
2562 method: 'POST'
2563 },
2564 append: config
2565 });
2566 const data = config_params.config || {};
2567 const templates = config_params.templates || []; // Poster image options.
2568
2569 createImageOptions(options, data); // Autogenerate poster.
2570
2571 createAutogenerateOptions(options, data, templates); // Uploads directory options.
2572
2573 createUploadsOptions(options, data); // Default poster.
2574
2575 createDefaultOptions(options, data); // Create required form fields
2576
2577 createMetaFields(options);
2578 }
2579
2580 /* harmony default export */ const config = (createConfig);
2581 ;// CONCATENATED MODULE: ./src/scripts/sections/premium.js
2582 /**
2583 * Premium settings tab.
2584 */
2585
2586 /* global ajaxurl:true */
2587 // Store global scriot object for settings page.
2588
2589 let premium_params = null; // Premium HTML emelent.
2590
2591 let premium = null;
2592 /**
2593 * Parse error code from settings or AJAX response.
2594 *
2595 * @param {string} code Error code from settings or AJAX response.
2596 * @param {string} title Prepended error title. Optional.
2597 */
2598
2599 function parseErrorCode(code, title) {
2600 const message = [];
2601
2602 if (undefined === title) {
2603 title = wp.i18n.__('Verification failed.', 'sharing-image');
2604 }
2605
2606 message.push(title);
2607
2608 switch (code) {
2609 case 'LIMIT_EXCEEDED':
2610 message.push(wp.i18n.__('The number of licenses for this key has been exceeded.', 'sharing-image'));
2611 break;
2612
2613 case 'KEY_NOT_FOUND':
2614 message.push(wp.i18n.__('Premium key is invalid or expired.', 'sharing-image'));
2615 break;
2616
2617 case 'SERVER_ERROR':
2618 message.push(wp.i18n.__('Unable to get a response from the verification server.', 'sharing-image'));
2619 break;
2620 }
2621
2622 return message.join(' ');
2623 }
2624 /**
2625 * Show premium warning message.
2626 *
2627 * @param {string} message Warning message.
2628 */
2629
2630
2631 function showPremiumError(message) {
2632 // Try to find warning element.
2633 const warning = premium.querySelector('.sharing-image-premium-warning');
2634
2635 if (null === warning) {
2636 return;
2637 }
2638
2639 warning.classList.add('warning-visible');
2640 warning.textContent = message || wp.i18n.__('Unknown request error', 'sharing-image');
2641 }
2642 /**
2643 * Remove warning message block.
2644 */
2645
2646
2647 function hidePremiumError() {
2648 // Try to find warning element.
2649 const warning = premium.querySelector('.sharing-image-premium-warning');
2650
2651 if (null === warning) {
2652 return;
2653 }
2654
2655 warning.classList.remove('warning-visible');
2656 }
2657 /**
2658 * Revoke Premium key.
2659 *
2660 * @param {HTMLElement} access Access form element.
2661 */
2662
2663
2664 function revokePremium(access) {
2665 access.classList.add('access-loader');
2666 const request = new XMLHttpRequest();
2667 request.open('POST', ajaxurl);
2668 request.responseType = 'json'; // Create data bundle using form data.
2669
2670 const bundle = new window.FormData(access);
2671 bundle.set('action', 'sharing_image_revoke');
2672 hidePremiumError();
2673 request.addEventListener('load', () => {
2674 const response = request.response || {}; // Hide form loader class.
2675
2676 access.classList.remove('access-loader');
2677
2678 if (!response.data) {
2679 return showPremiumError();
2680 }
2681
2682 if (!response.success) {
2683 return showPremiumError(response.data);
2684 }
2685
2686 premium_params.license = response.data; // Refresh premium fields.
2687
2688 preparePremiumFields();
2689 });
2690 request.addEventListener('error', () => {
2691 showPremiumError(); // Hide form loader class.
2692
2693 access.classList.remove('access-loader');
2694 });
2695 request.send(bundle);
2696 }
2697 /**
2698 * Verify Premium key.
2699 *
2700 * @param {HTMLElement} access Access form element.
2701 */
2702
2703
2704 function verifyPremium(access) {
2705 access.classList.add('access-loader');
2706 const request = new XMLHttpRequest();
2707 request.open('POST', ajaxurl);
2708 request.responseType = 'json'; // Create data bundle using form data.
2709
2710 const bundle = new window.FormData(access);
2711 bundle.set('action', 'sharing_image_verify');
2712 hidePremiumError();
2713 request.addEventListener('load', () => {
2714 const response = request.response || {}; // Hide form loader class.
2715
2716 access.classList.remove('access-loader');
2717
2718 if (!response.data) {
2719 return showPremiumError();
2720 }
2721
2722 if (!response.success) {
2723 return showPremiumError(parseErrorCode(response.code, response.data));
2724 }
2725
2726 premium_params.license = response.data; // Refresh premium fields.
2727
2728 preparePremiumFields();
2729 });
2730 request.addEventListener('error', () => {
2731 showPremiumError(); // Hide form loader class.
2732
2733 access.classList.remove('access-loader');
2734 });
2735 request.send(bundle);
2736 }
2737 /**
2738 * Show verify form if stil not premium.
2739 *
2740 * @param {HTMLElement} access Access HTML element.
2741 * @param {Object} license License data.
2742 */
2743
2744
2745 function showVerifyForm(access, license) {
2746 if (license.error) {
2747 showPremiumError(parseErrorCode(license.error));
2748 }
2749
2750 builders.element('strong', {
2751 text: wp.i18n.__('Do you already have a key? Enter it here', 'sharing-image'),
2752 append: access
2753 });
2754 const verify = builders.element('div', {
2755 classes: ['sharing-image-premium-verify'],
2756 append: access
2757 });
2758 builders.element('input', {
2759 label: wp.i18n.__('Your Premium key', 'sharing-image'),
2760 attributes: {
2761 type: 'text',
2762 name: 'sharing_image_key',
2763 value: license.key
2764 },
2765 append: verify
2766 });
2767 builders.element('button', {
2768 classes: ['button'],
2769 text: wp.i18n.__('Submit', 'sharing-image'),
2770 attributes: {
2771 type: 'submit'
2772 },
2773 append: verify
2774 });
2775 builders.element('span', {
2776 classes: ['spinner'],
2777 append: verify
2778 });
2779 access.addEventListener('submit', e => {
2780 e.preventDefault();
2781 verifyPremium(access);
2782 });
2783 }
2784 /**
2785 * Show alert for develop license mode.
2786 */
2787
2788
2789 function showDevelopAlert() {
2790 showPremiumError(wp.i18n.__('Using plugin with a development license is prohibited in production.', 'sharing-image'));
2791 }
2792 /**
2793 * Show revoke Premium button.
2794 *
2795 * @param {HTMLElement} access Access HTML element.
2796 */
2797
2798
2799 function showRevokeButton(access) {
2800 const revoke = builders.element('div', {
2801 classes: ['sharing-image-premium-revoke'],
2802 append: access
2803 });
2804 const description = [];
2805 description.push(wp.i18n.__('Disabling premium mode will not remove the license for this domain.', 'sharing-image'));
2806 description.push(wp.i18n.__('Your current key will also be saved in the plugin settings.', 'sharing-image'));
2807 description.push(wp.i18n.__('Use key management tool to delete the license for the site.', 'sharing-image'));
2808 builders.element('p', {
2809 text: description.join(' '),
2810 append: revoke
2811 });
2812 builders.element('button', {
2813 classes: ['button'],
2814 text: wp.i18n.__('Disable Premium'),
2815 attributes: {
2816 type: 'submit'
2817 },
2818 append: revoke
2819 });
2820 builders.element('span', {
2821 classes: ['spinner'],
2822 append: revoke
2823 });
2824 access.addEventListener('submit', e => {
2825 e.preventDefault();
2826 revokePremium(access);
2827 });
2828 }
2829 /**
2830 * Show permit information.
2831 *
2832 * @param {HTMLElement} access Access HTML element.
2833 * @param {string} key License key from settings.
2834 */
2835
2836
2837 function showLicenseInfo(access, key) {
2838 const permit = builders.element('div', {
2839 classes: ['sharing-image-premium-permit'],
2840 append: access
2841 });
2842 const button = builders.element('button', {
2843 classes: ['sharing-image-premium-show', 'button'],
2844 text: wp.i18n.__('Show License key'),
2845 attributes: {
2846 type: 'button'
2847 },
2848 append: permit
2849 });
2850 button.addEventListener('click', () => {
2851 permit.classList.toggle('permit-visible');
2852 });
2853 builders.element('strong', {
2854 text: key,
2855 append: permit
2856 });
2857 return permit;
2858 }
2859 /**
2860 * Show fields if user has the license.
2861 *
2862 * @param {HTMLElement} access Access HTML element.
2863 * @param {Object} license License data.
2864 */
2865
2866
2867 function showPremiumData(access, license) {
2868 premium.classList.add('premium-enabled');
2869
2870 if (license.develop) {
2871 return showDevelopAlert();
2872 }
2873
2874 if (license.key) {
2875 showLicenseInfo(access, license.key);
2876 }
2877
2878 showRevokeButton(access);
2879 }
2880 /**
2881 * Set premium fields according settings.
2882 */
2883
2884
2885 function preparePremiumFields() {
2886 let access = premium.querySelector('.sharing-image-premium-access');
2887
2888 if (null !== access) {
2889 premium.removeChild(access);
2890 }
2891
2892 access = builders.element('form', {
2893 classes: ['sharing-image-premium-access'],
2894 attributes: {
2895 action: '',
2896 method: 'POST'
2897 },
2898 append: premium
2899 });
2900 premium.classList.remove('premium-enabled');
2901 builders.element('input', {
2902 attributes: {
2903 type: 'hidden',
2904 name: 'sharing_image_nonce',
2905 value: premium_params.nonce
2906 },
2907 append: access
2908 });
2909 const license = premium_params.license || {}; // Show fields if user has the license.
2910
2911 if (license.premium || license.develop) {
2912 return showPremiumData(access, license);
2913 }
2914
2915 return showVerifyForm(access, license);
2916 }
2917 /**
2918 * Create templates catalog from options.
2919 *
2920 * @param {HTMLElement} content Settings content element.
2921 * @param {Object} settings Global settings field.
2922 */
2923
2924
2925 function createPremium(content, settings) {
2926 premium_params = settings; // Find premium element
2927
2928 premium = content.querySelector('.sharing-image-premium');
2929
2930 if (null === premium) {
2931 return;
2932 }
2933
2934 builders.element('div', {
2935 classes: ['sharing-image-premium-warning'],
2936 append: premium
2937 });
2938 preparePremiumFields();
2939 }
2940
2941 /* harmony default export */ const sections_premium = (createPremium);
2942 ;// CONCATENATED MODULE: ./src/scripts/sections/picker.js
2943 /**
2944 * Metabox handler.
2945 */
2946
2947 /* global ajaxurl:true */
2948 // Store global script object for metabox.
2949
2950 let picker_params = null; // Poster HTML element.
2951
2952 let poster = null; // Is gutenberg editor used.
2953
2954 let gutenberg = false;
2955 /**
2956 * Show picker warning message.
2957 *
2958 * @param {string} message Warning message.
2959 */
2960
2961 function showPickerError(message) {
2962 const picker = poster.parentNode; // Try to find warning element.
2963
2964 const warning = picker.querySelector('.sharing-image-picker-warning');
2965
2966 if (null === warning) {
2967 return;
2968 }
2969
2970 warning.classList.add('warning-visible');
2971 warning.textContent = message || wp.i18n.__('Unknown generation error', 'sharing-image');
2972 }
2973 /**
2974 * Remove warning message block.
2975 */
2976
2977
2978 function hidePickerError() {
2979 const picker = poster.parentNode; // Try to find warning element.
2980
2981 const warning = picker.querySelector('.sharing-image-picker-warning');
2982
2983 if (null === warning) {
2984 return;
2985 }
2986
2987 warning.classList.remove('warning-visible');
2988 }
2989 /**
2990 * Handle poster generation action.
2991 *
2992 * @param {HTMLElement} picker Picker element.
2993 */
2994
2995
2996 function generatePoster(picker) {
2997 const request = new XMLHttpRequest();
2998 request.open('POST', ajaxurl);
2999 request.responseType = 'json';
3000 poster.classList.add('poster-loader'); // Create data form data bundle.
3001
3002 const bundle = new window.FormData();
3003 bundle.set('action', 'sharing_image_generate');
3004 picker.querySelectorAll('[name]').forEach(field => {
3005 bundle.append(field.name, field.value);
3006 });
3007 hidePickerError();
3008 request.addEventListener('load', () => {
3009 const response = request.response || {}; // Hide preview loader on request complete.
3010
3011 poster.classList.remove('poster-loader');
3012
3013 if (!response.data) {
3014 return showPickerError();
3015 }
3016
3017 if (!response.success) {
3018 return showPickerError(response.data);
3019 }
3020
3021 for (const key in response.data) {
3022 // Find all poster input fields and set response data value.
3023 poster.querySelectorAll('input').forEach(input => {
3024 const name = picker_params.name + '[' + key + ']';
3025
3026 if (name === input.name) {
3027 input.value = response.data[key];
3028 }
3029 });
3030 }
3031
3032 let image = poster.querySelector('img');
3033
3034 if (null === image) {
3035 image = builders.element('img', {
3036 append: poster
3037 });
3038 }
3039
3040 image.src = response.data.poster; // Show the poster.
3041
3042 poster.classList.add('poster-visible');
3043 });
3044 request.addEventListener('error', () => {
3045 showPickerError(); // Hide preview loader on request complete.
3046
3047 poster.classList.remove('poster-loader');
3048 });
3049 request.send(bundle);
3050 }
3051 /**
3052 * Create designer template selector.
3053 *
3054 * @param {HTMLElement} picker Picker element.
3055 * @param {HTMLElement} designer Designer element.
3056 * @param {Object} selected Seleted template.
3057 */
3058
3059
3060 function createTemplate(picker, designer, selected) {
3061 const fields = {};
3062 picker_params.templates.forEach((template, i) => {
3063 fields[i] = template.title || wp.i18n.__('Untitled', 'sharing-image');
3064 });
3065 const template = builders.select({
3066 classes: ['sharing-image-picker-template'],
3067 options: fields,
3068 attributes: {
3069 name: picker_params.name + '[template]'
3070 },
3071 selected: String(selected)
3072 }, picker);
3073 template.addEventListener('change', () => {
3074 const fieldset = designer.childNodes;
3075
3076 for (let i = 0; i < fieldset.length; i++) {
3077 fieldset[i].classList.remove('fieldset-visible');
3078
3079 if (i === parseInt(template.value)) {
3080 fieldset[i].classList.add('fieldset-visible');
3081 }
3082 }
3083 });
3084 return template;
3085 }
3086 /**
3087 * Prefill caption fields for classic editor.
3088 *
3089 * @param {HTMLElement} textarea Caption textarea field.
3090 * @param {string} preset Preset field.
3091 */
3092
3093
3094 function fillClassicEditorPreset(textarea, preset) {
3095 const source = document.getElementById(preset);
3096
3097 if (null === source) {
3098 return;
3099 }
3100
3101 const updateCaption = () => {
3102 textarea.value = source.value;
3103 };
3104
3105 source.addEventListener('change', updateCaption); // Stop textarea update after first user input.
3106
3107 textarea.addEventListener('change', () => {
3108 source.removeEventListener('change', updateCaption);
3109 });
3110 updateCaption();
3111 }
3112 /**
3113 * Prefill caption fields for block editor.
3114 *
3115 * @param {HTMLElement} textarea Caption textarea field.
3116 * @param {string} preset Preset field.
3117 */
3118
3119
3120 function fillBlockEditorPreset(textarea, preset) {
3121 const getAttribute = () => {
3122 return wp.data.select('core/editor').getEditedPostAttribute(preset);
3123 };
3124
3125 let attribute = getAttribute();
3126 wp.data.subscribe(() => {
3127 const updated = getAttribute();
3128
3129 if (attribute !== updated) {
3130 textarea.textContent = updated;
3131 }
3132
3133 attribute = updated;
3134 });
3135 }
3136 /**
3137 * Try to prefill caption field.
3138 *
3139 * @param {HTMLElement} textarea Caption textarea field.
3140 * @param {string} preset Preset field.
3141 */
3142
3143
3144 function fillCaptionPreset(textarea, preset) {
3145 if (gutenberg) {
3146 return fillBlockEditorPreset(textarea, preset);
3147 }
3148
3149 fillClassicEditorPreset(textarea, preset);
3150 }
3151 /**
3152 * Create designer attachment field for dynamic background.
3153 *
3154 * @param {HTMLElement} fieldset Fieldset element.
3155 * @param {Object} template Template data.
3156 * @param {Array} values Template fieldset values.
3157 * @param {string} name Field name attribute.
3158 */
3159
3160
3161 function createDesignerAttachment(fieldset, template, values, name) {
3162 if ('dynamic' !== template.background) {
3163 return;
3164 }
3165
3166 builders.media({
3167 name: name + '[attachment]',
3168 classes: ['sharing-image-picker-media'],
3169 value: values.attachment,
3170 link: picker_params.links.uploads,
3171 labels: {
3172 button: wp.i18n.__('Upload background', 'sharing-image'),
3173 heading: wp.i18n.__('Select background image', 'sharing-image'),
3174 details: wp.i18n.__('Attachment', 'sharing-image')
3175 },
3176 append: fieldset
3177 });
3178 }
3179 /**
3180 * Create designer captions for text layers.
3181 *
3182 * @param {HTMLElement} fieldset Fieldset element.
3183 * @param {Object} template Template data.
3184 * @param {Array} values Template fieldset values.
3185 * @param {string} name Field name attribute.
3186 */
3187
3188
3189 function createDesignerCaptions(fieldset, template, values, name) {
3190 const captions = values.captions || []; // Set default layers list.
3191
3192 template.layers = template.layers || [];
3193 template.layers.forEach((layer, n) => {
3194 if ('text' !== layer.type || !layer.dynamic) {
3195 return;
3196 }
3197
3198 const textarea = builders.textarea({
3199 classes: ['sharing-image-picker-caption'],
3200 label: layer.title || null,
3201 attributes: {
3202 name: name + `[captions][${n}]`
3203 }
3204 }, fieldset);
3205
3206 if (!captions[n]) {
3207 fillCaptionPreset(textarea, layer.preset);
3208 }
3209
3210 textarea.textContent = captions[n];
3211 });
3212 }
3213 /**
3214 * Create fields designer.
3215 *
3216 * @param {HTMLElement} picker Picker element.
3217 * @param {Object} data Picker data object.
3218 */
3219
3220
3221 function picker_createDesigner(picker, data) {
3222 const designer = builders.element('div', {
3223 classes: ['sharing-image-picker-designer']
3224 });
3225 let selected = data.template || 0; // Reset selected template if index undefined.
3226
3227 if (!picker_params.templates[selected]) {
3228 selected = 0;
3229 } // Create designer fields
3230
3231
3232 picker_params.templates.forEach((template, i) => {
3233 // Set default layers list.
3234 template.layers = template.layers || [];
3235 const fieldset = builders.element('div', {
3236 classes: ['sharing-image-picker-fieldset'],
3237 append: designer
3238 });
3239
3240 if (i === parseInt(selected)) {
3241 fieldset.classList.add('fieldset-visible');
3242 }
3243
3244 let values = {};
3245
3246 if (data.fieldset && data.fieldset[i]) {
3247 values = data.fieldset[i];
3248 }
3249
3250 const name = picker_params.name + `[fieldset][${i}]`;
3251 builders.element('input', {
3252 attributes: {
3253 type: 'hidden',
3254 name: name
3255 },
3256 append: fieldset
3257 }); // Create attachment field.
3258
3259 createDesignerAttachment(fieldset, template, values, name); // Create all caption fields.
3260
3261 createDesignerCaptions(fieldset, template, values, name);
3262 }); // Create template selector.
3263
3264 if (picker_params.templates.length > 1) {
3265 createTemplate(picker, designer, selected);
3266 }
3267
3268 picker.appendChild(designer);
3269 }
3270 /**
3271 * Create button to generate new metabox poster.
3272 *
3273 * @param {HTMLElement} picker Picker element.
3274 * @param {HTMLElement} manager Manager element.
3275 */
3276
3277
3278 function picker_createGenerateButton(picker, manager) {
3279 const button = builders.element('button', {
3280 classes: ['sharing-image-picker-generate', 'button'],
3281 text: wp.i18n.__('Generate', 'sharing-image'),
3282 attributes: {
3283 type: 'button'
3284 },
3285 append: manager
3286 });
3287 button.addEventListener('click', () => {
3288 generatePoster(picker);
3289 });
3290 }
3291 /**
3292 * Create button to delete current metabox poster.
3293 *
3294 * @param {HTMLElement} manager Manager element.
3295 */
3296
3297
3298 function picker_createDeleteButton(manager) {
3299 const button = builders.element('button', {
3300 classes: ['sharing-image-picker-delete', 'button', 'button-delete'],
3301 text: wp.i18n.__('Remove', 'sharing-image'),
3302 attributes: {
3303 type: 'button'
3304 },
3305 append: manager
3306 });
3307 button.addEventListener('click', () => {
3308 const image = poster.querySelector('img');
3309
3310 if (null !== image) {
3311 poster.removeChild(image);
3312 }
3313
3314 poster.querySelectorAll('input').forEach(input => {
3315 input.value = '';
3316 });
3317 poster.classList.remove('poster-visible');
3318 });
3319 }
3320 /**
3321 * Create picker manager.
3322 *
3323 * @param {HTMLElement} picker Picker element.
3324 */
3325
3326
3327 function createManager(picker) {
3328 const manager = builders.element('div', {
3329 classes: ['sharing-image-picker-manager'],
3330 append: picker
3331 }); // Create poster generation button.
3332
3333 picker_createGenerateButton(picker, manager); // Create poster removing button.
3334
3335 picker_createDeleteButton(manager);
3336 builders.element('span', {
3337 classes: ['sharing-image-picker-spinner', 'spinner'],
3338 append: manager
3339 });
3340 }
3341 /**
3342 * Create poster block.
3343 *
3344 * @param {HTMLElement} picker Picker element.
3345 * @param {Object} data Picker data object.
3346 */
3347
3348
3349 function createPoster(picker, data) {
3350 poster = builders.element('div', {
3351 classes: ['sharing-image-picker-poster'],
3352 append: picker
3353 });
3354
3355 if (data.poster) {
3356 builders.element('img', {
3357 attributes: {
3358 src: data.poster,
3359 alt: ''
3360 },
3361 append: poster
3362 });
3363 poster.classList.add('poster-visible');
3364 }
3365
3366 builders.element('input', {
3367 attributes: {
3368 type: 'hidden',
3369 name: picker_params.name + '[poster]',
3370 value: data.poster
3371 },
3372 append: poster
3373 });
3374 builders.element('input', {
3375 attributes: {
3376 type: 'hidden',
3377 name: picker_params.name + '[width]',
3378 value: data.width
3379 },
3380 append: poster
3381 });
3382 builders.element('input', {
3383 attributes: {
3384 type: 'hidden',
3385 name: picker_params.name + '[height]',
3386 value: data.height
3387 },
3388 append: poster
3389 });
3390 return poster;
3391 }
3392 /**
3393 * Check that the poster sizes are set or show an error message.
3394 *
3395 * @param {Object} data Picker data object.
3396 */
3397
3398
3399 function showSizesWarning(data) {
3400 if (!data.poster) {
3401 return;
3402 }
3403
3404 if (!data.width || !data.height) {
3405 showPickerError(wp.i18n.__('Image sizes are not set. Regenerate the poster.', 'sharing-image'));
3406 }
3407 }
3408 /**
3409 * Get new config with AJAX call and reinit metabox.
3410 *
3411 * @param {HTMLElement} widget Widget element.
3412 */
3413
3414
3415 const rebuildPicker = widget => {
3416 const request = new XMLHttpRequest();
3417 request.open('POST', ajaxurl);
3418 request.responseType = 'json';
3419 poster.classList.add('poster-loader'); // We need post ID for this request.
3420
3421 const postId = wp.data.select('core/editor').getCurrentPostId(); // Create data form data bundle.
3422
3423 const bundle = new window.FormData();
3424 bundle.set('action', 'sharing_image_rebuild');
3425 bundle.set('post', postId); // Find picker child.
3426
3427 const picker = widget.querySelector('.sharing-image-picker');
3428 picker.querySelectorAll('[name]').forEach(field => {
3429 if ('sharing_image_nonce' === field.name) {
3430 bundle.append(field.name, field.value);
3431 }
3432 });
3433 hidePickerError();
3434 request.addEventListener('load', () => {
3435 const response = request.response || {}; // Hide preview loader on request complete.
3436
3437 poster.classList.remove('poster-loader');
3438
3439 if (!response.data) {
3440 return showPickerError();
3441 }
3442
3443 if (!response.success) {
3444 return showPickerError(response.data);
3445 }
3446
3447 buildPicker(widget, response.data);
3448 });
3449 request.addEventListener('error', () => {
3450 showPickerError(); // Hide preview loader on request complete.
3451
3452 poster.classList.remove('poster-loader');
3453 });
3454 request.send(bundle);
3455 };
3456 /**
3457 * Wait Gutenberg post saving and reinit tasks list.
3458 *
3459 * @param {HTMLElement} widget Widget element.
3460 */
3461
3462
3463 const subscribeOnSaving = widget => {
3464 let wasSavingPost = wp.data.select('core/edit-post').isSavingMetaBoxes();
3465 wp.data.subscribe(() => {
3466 const isSavingPost = wp.data.select('core/edit-post').isSavingMetaBoxes();
3467
3468 if (wasSavingPost && !isSavingPost) {
3469 rebuildPicker(widget);
3470 }
3471
3472 wasSavingPost = isSavingPost;
3473 });
3474 };
3475 /**
3476 * Build metabox fields.
3477 *
3478 * @param {HTMLElement} widget Widget element.
3479 * @param {Object} settings Global settings object.
3480 */
3481
3482
3483 function buildPicker(widget, settings) {
3484 picker_params = settings; // Set params name for template form fields.
3485
3486 picker_params.name = 'sharing_image_picker';
3487
3488 while (widget.firstChild) {
3489 widget.removeChild(widget.lastChild);
3490 }
3491
3492 if ('term' === picker_params.context) {
3493 const title = builders.element('div', {
3494 classes: ['sharing-image-title'],
3495 append: widget
3496 });
3497 builders.element('strong', {
3498 text: wp.i18n.__('Sharing Image', 'sharing-image'),
3499 append: title
3500 });
3501 }
3502
3503 const picker = builders.element('div', {
3504 classes: ['sharing-image-picker'],
3505 append: widget
3506 });
3507 const data = picker_params.meta || {}; // Create poster block.
3508
3509 createPoster(picker, data); // Create fields designer.
3510
3511 picker_createDesigner(picker, data);
3512 builders.element('div', {
3513 classes: ['sharing-image-picker-warning'],
3514 append: picker
3515 }); // Show unset poster sizes warning.
3516
3517 showSizesWarning(data); // Create metabox manager block.
3518
3519 createManager(picker);
3520 builders.element('input', {
3521 attributes: {
3522 type: 'hidden',
3523 name: 'sharing_image_nonce',
3524 value: picker_params.nonce
3525 },
3526 append: picker
3527 });
3528 builders.element('input', {
3529 attributes: {
3530 type: 'hidden',
3531 name: 'sharing_image_screen',
3532 value: picker_params.screen
3533 },
3534 append: picker
3535 });
3536 builders.element('input', {
3537 attributes: {
3538 type: 'hidden',
3539 name: 'sharing_image_context',
3540 value: picker_params.context
3541 },
3542 append: picker
3543 });
3544 }
3545 /**
3546 * Create metabox generator picker and subscribe to events.
3547 *
3548 * @param {HTMLElement} widget Widget element.
3549 * @param {Object} settings Global settings object.
3550 */
3551
3552
3553 function createPicker(widget, settings) {
3554 if (wp.data && wp.data.select('core/editor')) {
3555 gutenberg = true;
3556 }
3557
3558 buildPicker(widget, settings);
3559
3560 if (gutenberg) {
3561 subscribeOnSaving(widget);
3562 }
3563 }
3564
3565 /* harmony default export */ const picker = (createPicker);
3566 ;// CONCATENATED MODULE: ./src/scripts/sections/index.js
3567
3568
3569
3570
3571
3572 const Section = {
3573 catalog: catalog,
3574 editor: sections_editor,
3575 config: config,
3576 premium: sections_premium,
3577 picker: picker
3578 };
3579 /* harmony default export */ const sections = (Section);
3580 ;// CONCATENATED MODULE: ./src/scripts/settings.js
3581
3582
3583 /**
3584 * Init premium settings tab.
3585 *
3586 * @param {HTMLElement} content Settings content element.
3587 * @param {Object} settings Global settings object.
3588 */
3589
3590 function initPremiumTab(content, settings) {
3591 sections.premium(content, settings);
3592 }
3593 /**
3594 * Init config settings tab.
3595 *
3596 * @param {HTMLElement} content Settings content element.
3597 * @param {Object} settings Global settings object.
3598 */
3599
3600
3601 function initConfigTab(content, settings) {
3602 sections.config(content, settings);
3603 }
3604 /**
3605 * Init config settings tab.
3606 *
3607 * @param {HTMLElement} content Settings content element.
3608 * @param {Object} settings Global settings object.
3609 */
3610
3611
3612 function initTemplatesTab(content, settings) {
3613 // Get index from URL search parameter.
3614 let index = null; // Set default templates empty list.
3615
3616 settings.templates = settings.templates || [];
3617
3618 if (helpers.param('template')) {
3619 index = parseInt(helpers.param('template')) - 1;
3620 }
3621
3622 const data = settings.templates[index]; // Create editor for existing template.
3623
3624 if (undefined !== data) {
3625 return sections.editor(content, settings, index, data);
3626 } // Create editor for new template.
3627
3628
3629 if (settings.templates.length === index) {
3630 return sections.editor(content, settings, index);
3631 }
3632
3633 sections.catalog(content, settings);
3634 }
3635 /**
3636 * Init settings page handler.
3637 */
3638
3639
3640 (function () {
3641 if (typeof 'undefined' === wp) {
3642 return;
3643 }
3644
3645 let object = window.sharingImageSettings || {}; // Add default required values to object.
3646
3647 object = helpers.defaults(object, ['links', 'fonts', 'config', 'templates', 'license']); // Find settings content element.
3648
3649 const content = document.querySelector('#sharing-image-settings .sharing-image-content');
3650
3651 if (null === content) {
3652 return;
3653 }
3654
3655 content.classList.add('content-visible');
3656
3657 switch (helpers.param('tab')) {
3658 case 'config':
3659 initConfigTab(content, object);
3660 break;
3661
3662 case 'premium':
3663 initPremiumTab(content, object);
3664 break;
3665
3666 default:
3667 initTemplatesTab(content, object);
3668 }
3669 })();
3670 /******/ })()
3671 ;