# sharing-image/2.0.16/assets/scripts/settings.js

Sharing Image, version 2.0.16. 3,671 lines.

- Page: https://pluginprobe.com/plugins/sharing-image/2.0.16/code/assets/scripts/settings.js
- Raw: https://pluginprobe.com/plugins/sharing-image/2.0.16/raw/assets/scripts/settings.js
- Modified: 2023-05-25T20:38:20+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/sharing-image/2.0.16/code/assets/scripts/settings.js#L10-L20`.

```javascript
/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
var __webpack_exports__ = {};

;// CONCATENATED MODULE: ./src/scripts/helpers/param.js
/**
 * Get current location search parameter.
 *
 * @param {string} key URL parameter key.
 */
function getSearchParam(key) {
  const params = new URL(document.location.href);
  return params.searchParams.get(key);
}

/* harmony default export */ const param = (getSearchParam);
;// CONCATENATED MODULE: ./src/scripts/helpers/attachment.js
/**
 * Upload media frame.
 *
 * @param {string}   header   Frame header text.
 * @param {Function} callback Callback function.
 */
function uploadMedia(header, callback) {
  const frame = wp.media({
    title: header,
    multiple: false
  });
  frame.on('select', () => {
    const selection = frame.state().get('selection').first().toJSON();

    if (selection.id) {
      callback(selection.id);
    }
  });
  frame.open();
}

/* harmony default export */ const attachment = (uploadMedia);
;// CONCATENATED MODULE: ./src/scripts/helpers/defaults.js
/**
 * Append empty default properties to object if not exist.
 *
 * @param {Object} object   Source object.
 * @param {Array}  defaults Required defaults properties.
 */
function intersectDefaults(object, defaults) {
  defaults.forEach(item => {
    if (undefined === object[item]) {
      object[item] = {};
    }
  });
  return object;
}

/* harmony default export */ const defaults = (intersectDefaults);
;// CONCATENATED MODULE: ./src/scripts/helpers/index.js



const Helper = {
  param: param,
  attachment: attachment,
  defaults: defaults
};
/* harmony default export */ const helpers = (Helper);
;// CONCATENATED MODULE: ./src/scripts/builders/element.js
/**
 * Helper to create new DOM element.
 *
 * @param {string} tag  Element tagname.
 * @param {Object} args List of element options.
 */
function buildElement(tag, args) {
  const element = document.createElement(tag); // Set class list

  if (args.hasOwnProperty('classes')) {
    args.classes.forEach(cl => {
      element.classList.add(cl);
    });
  } // Set textContent


  if (args.hasOwnProperty('text')) {
    element.textContent = args.text;
  } // Set innerHTML


  if (args.hasOwnProperty('html')) {
    element.innerHTML = args.html;
  } // Set attributes


  if (args.hasOwnProperty('attributes')) {
    for (const key in args.attributes) {
      const value = args.attributes[key];

      if (undefined === value) {
        continue;
      }

      element.setAttribute(key, value);
    }
  } // Set data attributes


  if (args.hasOwnProperty('dataset')) {
    for (const key in args.dataset) {
      element.setAttribute('data-' + key, args.dataset[key]);
    }
  } // Append child


  if (args.hasOwnProperty('append')) {
    args.append.appendChild(element);
  } // Prepend child


  if (args.hasOwnProperty('prepend')) {
    args.prepend.insertBefore(element, args.prepend.firstChild);
  }

  return element;
}

/* harmony default export */ const builders_element = (buildElement);
;// CONCATENATED MODULE: ./src/scripts/builders/input.js


/**
 * Helper to create input field.
 *
 * @param {Object}      args   List of control options.
 * @param {HTMLElement} parent Parent HTML element to append this field.
 */

function buildInput(args, parent) {
  const field = builders_element('div', {
    classes: args.classes || [],
    append: parent
  });

  if (args.hasOwnProperty('label')) {
    const label = builders_element('h4', {
      text: args.label
    });

    if (null !== args.label) {
      field.appendChild(label);
    }
  }

  const input = builders_element('input', {
    attributes: {
      type: 'text'
    },
    dataset: args.dataset || {},
    append: field
  }); // Set attributes.

  if (args.hasOwnProperty('attributes')) {
    for (const key in args.attributes) {
      const value = args.attributes[key];

      if (undefined === value) {
        continue;
      }

      input.setAttribute(key, value);
    }
  }

  if ('range' === input.type) {
    const counter = builders.element('em', {
      text: input.value,
      append: field
    });
    input.addEventListener('change', () => {
      counter.textContent = input.value;
    });
    input.addEventListener('input', () => {
      counter.textContent = input.value;
    });
  }

  return input;
}

/* harmony default export */ const input = (buildInput);
;// CONCATENATED MODULE: ./src/scripts/builders/checkbox.js

/**
 * Helper to create radio field.
 *
 * @param {Object}      args   List of control options.
 * @param {HTMLElement} parent Parent HTML element to append this field.
 */

function buildCheckbox(args, parent) {
  const field = builders_element('label', {
    classes: args.classes || [],
    append: parent
  });
  const checkbox = builders_element('input', {
    attributes: {
      type: 'checkbox'
    },
    dataset: args.dataset || {},
    append: field
  }); // Set attributes

  if (args.hasOwnProperty('attributes')) {
    for (const key in args.attributes) {
      const value = args.attributes[key];

      if (undefined === value) {
        continue;
      }

      checkbox.setAttribute(key, value);
    }
  }

  if (args.hasOwnProperty('checked')) {
    const checked = args.checked;

    if (checked && checked === checkbox.value) {
      checkbox.setAttribute('checked', 'checked');
    }
  }

  if (args.hasOwnProperty('label')) {
    const label = builders_element('span', {
      text: args.label
    });

    if (null !== args.label) {
      field.appendChild(label);
    }
  }

  return checkbox;
}

/* harmony default export */ const builders_checkbox = (buildCheckbox);
;// CONCATENATED MODULE: ./src/scripts/builders/radio.js

/**
 * Helper to create radio field.
 *
 * @param {Object}      args   List of control options.
 * @param {HTMLElement} parent Parent HTML element to append this field.
 */

function buildRadio(args, parent) {
  const field = builders_element('label', {
    classes: args.classes || [],
    append: parent
  });
  const radio = builders_element('input', {
    attributes: {
      type: 'radio'
    },
    dataset: args.dataset || {},
    append: field
  }); // Set attributes

  if (args.hasOwnProperty('attributes')) {
    for (const key in args.attributes) {
      const value = args.attributes[key];

      if (undefined === value) {
        continue;
      }

      radio.setAttribute(key, value);
    }
  }

  if (args.hasOwnProperty('checked')) {
    const checked = args.checked;

    if (checked && checked === radio.value) {
      radio.setAttribute('checked', 'checked');
    }
  }

  if (args.hasOwnProperty('label')) {
    const label = builders_element('span', {
      text: args.label
    });

    if (null !== args.label) {
      field.appendChild(label);
    }
  }

  if (args.hasOwnProperty('help')) {
    builders_element('small', {
      text: args.help,
      append: field
    });
  }

  return radio;
}

/* harmony default export */ const builders_radio = (buildRadio);
;// CONCATENATED MODULE: ./src/scripts/builders/select.js

/**
 * Helper to create select field.
 *
 * @param {Object}      args   List of control options.
 * @param {HTMLElement} parent Parent HTML element to append this field.
 */

function buildSelect(args, parent) {
  const field = builders_element('div', {
    classes: args.classes || [],
    append: parent
  });

  if (args.hasOwnProperty('label')) {
    const label = builders_element('h4', {
      text: args.label
    });

    if (null !== args.label) {
      field.appendChild(label);
    }
  }

  const select = builders_element('select', {
    dataset: args.dataset || {},
    append: field
  }); // Set attributes

  if (args.hasOwnProperty('attributes')) {
    for (const key in args.attributes) {
      const value = args.attributes[key];

      if (undefined === value) {
        continue;
      }

      select.setAttribute(key, value);
    }
  }

  const options = args.options || {};

  for (const key in options) {
    const option = builders_element('option', {
      text: options[key],
      attributes: {
        value: key
      },
      append: select
    });

    if (args.hasOwnProperty('selected')) {
      const selected = args.selected;

      if (selected && selected === option.value) {
        option.setAttribute('selected', 'selected');
      }
    }
  }

  return select;
}

/* harmony default export */ const builders_select = (buildSelect);
;// CONCATENATED MODULE: ./src/scripts/builders/textarea.js

/**
 * Helper to create input field.
 *
 * @param {Object}      args   List of control options.
 * @param {HTMLElement} parent Parent HTML element to append this field.
 */

function buildTextarea(args, parent) {
  const field = builders_element('div', {
    classes: args.classes || [],
    append: parent
  });

  if (args.hasOwnProperty('label')) {
    const label = builders_element('h4', {
      text: args.label
    });

    if (null !== args.label) {
      field.appendChild(label);
    }
  }

  const textarea = builders_element('textarea', {
    dataset: args.dataset || {},
    append: field
  }); // Set attributes

  if (args.hasOwnProperty('attributes')) {
    for (const key in args.attributes) {
      const value = args.attributes[key];

      if (undefined === value) {
        continue;
      }

      textarea.setAttribute(key, value);
    }
  } // Set content


  if (args.hasOwnProperty('content')) {
    const content = args.content;

    if (undefined !== content) {
      textarea.innerHTML = content;
    }
  }

  return textarea;
}

/* harmony default export */ const builders_textarea = (buildTextarea);
;// CONCATENATED MODULE: ./src/scripts/builders/control.js






/**
 * Helper to create control.
 *
 * @param {Object} args List of control options.
 */

function buildControl(args) {
  const control = builders_element('div', {
    classes: args.classes || []
  });

  if (args.hasOwnProperty('append')) {
    args.append.appendChild(control);
  }

  if (args.hasOwnProperty('prepend')) {
    args.prepend.insertBefore(control, args.prepend.firstChild);
  }

  if (args.hasOwnProperty('label')) {
    builders_element('h3', {
      text: args.label,
      append: control
    });
  }

  if (args.hasOwnProperty('description')) {
    builders_element('p', {
      text: args.description,
      append: control
    });
  }

  if (args.hasOwnProperty('fields')) {
    args.fields.forEach(field => {
      switch (field.group) {
        case 'input':
          input(field, control);
          break;

        case 'textarea':
          builders_textarea(field, control);
          break;

        case 'radio':
          builders_radio(field, control);
          break;

        case 'select':
          builders_select(field, control);
          break;

        case 'checkbox':
          builders_checkbox(field, control);
          break;
      }
    });
  }

  if (args.hasOwnProperty('help')) {
    builders_element('small', {
      text: args.help,
      append: control
    });
  }

  return control;
}

/* harmony default export */ const control = (buildControl);
;// CONCATENATED MODULE: ./src/scripts/builders/layer.js

/**
 * Helper to create layer.
 *
 * @param {Object} args List of layer options.
 */

function buildLayer(args) {
  const layer = builders_element('div', {
    classes: args.classes || []
  });

  if (args.hasOwnProperty('append')) {
    args.append.appendChild(layer);
  }

  if (args.hasOwnProperty('prepend')) {
    args.prepend.insertBefore(layer, args.prepend.firstChild);
  }

  if (!args.hasOwnProperty('label')) {
    args.label = '';
  }

  builders_element('h2', {
    text: args.label,
    append: layer
  });

  if (args.hasOwnProperty('description')) {
    builders_element('h5', {
      text: args.description,
      append: layer
    });
  }

  return layer;
}

/* harmony default export */ const builders_layer = (buildLayer);
;// CONCATENATED MODULE: ./src/scripts/builders/media.js



/**
 * Helper to create media block.
 *
 * @param {Object} args List of media options.
 */

function buildMedia(args) {
  const media = control({
    classes: args.classes || []
  });

  if (args.hasOwnProperty('append')) {
    args.append.appendChild(media);
  }

  if (args.hasOwnProperty('prepend')) {
    args.prepend.insertBefore(media, args.prepend.firstChild);
  } // Labels are required.


  args.labels = args.labels || {};
  const attachment = builders_element('input', {
    attributes: {
      type: 'hidden',
      name: args.name
    },
    append: media
  });
  const upload = builders_element('button', {
    classes: ['button'],
    text: args.labels.button,
    attributes: {
      type: 'button'
    },
    append: media
  });
  const details = builders_element('a', {
    classes: ['hidden'],
    text: args.labels.details,
    attributes: {
      target: '_blank'
    }
  });

  if (args.hasOwnProperty('link')) {
    media.appendChild(details);
  } // Helper function to update attachment value.


  const setAttachment = id => {
    attachment.setAttribute('value', id);
    attachment.dispatchEvent(new Event('change', {
      bubbles: true
    }));
    let link = null;

    if (args.hasOwnProperty('link')) {
      link = new URL(args.link);
      link.searchParams.set('item', id);
      details.setAttribute('href', link.href);
    }

    if (args.remove) {
      upload.textContent = args.labels.remove;
    }

    details.classList.remove('hidden');
  }; // Helper function to remove attachment value.


  const removeAttachment = () => {
    attachment.setAttribute('value', '');
    attachment.dispatchEvent(new Event('change', {
      bubbles: true
    })); // Set default button title.

    upload.textContent = args.labels.button;
    details.classList.add('hidden');
  }; // Update fields if this layer has attachment.


  if (args.value) {
    setAttachment(args.value);
  }

  upload.addEventListener('click', () => {
    if (args.remove && attachment.value) {
      return removeAttachment();
    }

    helpers.attachment(args.labels.heading, id => {
      setAttachment(id);
    });
  });
  return media;
}

/* harmony default export */ const media = (buildMedia);
;// CONCATENATED MODULE: ./src/scripts/builders/index.js









const Build = {
  element: builders_element,
  control: control,
  layer: builders_layer,
  checkbox: builders_checkbox,
  media: media,
  input: input,
  textarea: builders_textarea,
  radio: builders_radio,
  select: builders_select
};
/* harmony default export */ const builders = (Build);
;// CONCATENATED MODULE: ./src/scripts/sections/catalog.js
 // Store global scriot object for settings page.

let params = null;
/**
 * Create template card in catalog.
 *
 * @param {HTMLElement} catalog Catalog HTML element.
 * @param {number}      index   Current card index.
 * @param {Object}      option  List of template options.
 */

function createCard(catalog, index, option) {
  const card = builders.element('div', {
    classes: ['sharing-image-catalog-card'],
    append: catalog
  });
  const preview = builders.element('figure', {
    classes: ['sharing-image-catalog-preview'],
    append: card
  });

  if (option.preview) {
    builders.element('img', {
      attributes: {
        src: option.preview,
        alt: ''
      },
      append: preview
    });
  }

  const footer = builders.element('footer', {
    classes: ['sharing-image-catalog-footer'],
    append: card
  });
  builders.element('h2', {
    text: option.title || wp.i18n.__('Untitled', 'sharing-image'),
    append: footer
  });
  const link = new URL(document.location.href);
  link.searchParams.set('template', index);
  builders.element('a', {
    classes: ['button'],
    text: wp.i18n.__('Edit template', 'sharing-image'),
    attributes: {
      href: link.href
    },
    append: footer
  });
}
/**
 * Create new template button in catalog.
 *
 * @param {HTMLElement} catalog Catalog HTML element.
 * @param {number}      index   New card index.
 */


function createNewButton(catalog, index) {
  const link = new URL(document.location.href);
  link.searchParams.set('template', index);
  const button = builders.element('a', {
    classes: ['sharing-image-catalog-new'],
    attributes: {
      href: link.href
    },
    append: catalog
  });
  const title = builders.element('h2', {
    append: button
  });
  builders.element('strong', {
    text: wp.i18n.__('Add new template', 'sharing-image'),
    append: title
  }); // Restrict new template creation for not Premium users.

  if (params.templates.length === 0) {
    return;
  }

  const license = params.license || {};

  if (license.premium || license.develop) {
    return;
  }

  builders.element('span', {
    text: wp.i18n.__('(Availible for Premium only)', 'sharing-image'),
    append: title
  });

  if (params.links.premium) {
    button.href = params.links.premium;
  }
}
/**
 * Create templates catalog from options.
 *
 * @param {HTMLElement} content  Settings content element.
 * @param {Object}      settings Global settings field.
 */


function createCatalog(content, settings) {
  params = settings;
  const catalog = builders.element('div', {
    classes: ['sharing-image-catalog'],
    append: content
  });
  let index = 1;
  settings.templates.forEach(template => {
    createCard(catalog, index++, template);
  });
  createNewButton(catalog, index);
}

/* harmony default export */ const catalog = (createCatalog);
;// CONCATENATED MODULE: ./src/scripts/sections/editor.js
/**
 * Editor settings.
 */

/* global ajaxurl:true */
 // Store global scriot object for settings page.

let editor_params = null; // Preview element.

let preview = null; // Root editor element.

let editor = null;
/**
 * Show template warning message.
 *
 * @param {string} message Warning message.
 */

function showTemplateError(message) {
  const viewport = preview.parentNode; // Try to find warning element.

  const warning = viewport.querySelector('.sharing-image-editor-warning');

  if (null === warning) {
    return;
  }

  warning.classList.add('warning-visible');
  warning.textContent = message || wp.i18n.__('Unknown generation error', 'sharing-image');
}
/**
 * Remove warning message block.
 */


function hideTemplateError() {
  const viewport = preview.parentNode; // Try to find warning element.

  const warning = viewport.querySelector('.sharing-image-editor-warning');

  if (null === warning) {
    return;
  }

  warning.classList.remove('warning-visible');
}
/**
 * Geneate template using editor data.
 */


function generateTemplate() {
  preview.classList.add('preview-loader');
  const request = new XMLHttpRequest();
  request.open('POST', ajaxurl);
  request.responseType = 'blob'; // Create data bundle using form data.

  const bundle = new window.FormData(editor);
  bundle.set('action', 'sharing_image_show');
  hideTemplateError(); // Set blob for success response.

  request.addEventListener('readystatechange', () => {
    if (request.readyState === 2) {
      request.responseType = 'json';

      if (request.status === 200) {
        request.responseType = 'blob';
      }
    }
  });
  request.addEventListener('load', () => {
    const response = request.response || {}; // Hide preview loader on request complete.

    preview.classList.remove('preview-blank', 'preview-loader');

    if (200 !== request.status) {
      return showTemplateError(response.data);
    }

    let image = preview.querySelector('img');

    if (null === image) {
      image = builders.element('img', {
        append: preview
      });
    } // Set new blob image source.


    image.src = window.URL.createObjectURL(response);
  });
  request.addEventListener('error', () => {
    showTemplateError(); // Hide preview loader on request complete.

    preview.classList.remove('preview-blank', 'preview-loader');
  });
  request.send(bundle);
}
/**
 * Save template while editor submiting.
 */


function saveTemplate() {
  const request = new XMLHttpRequest();
  request.open('POST', ajaxurl);
  request.responseType = 'json';
  preview.classList.add('preview-loader'); // Create data bundle using editor data.

  const bundle = new window.FormData(editor);
  bundle.set('action', 'sharing_image_save');
  request.addEventListener('load', () => {
    const response = request.response || {};

    if (!response.data) {
      return showTemplateError();
    }

    if (!response.success) {
      // Hide preview loader on request complete.
      preview.classList.remove('preview-loader');
      return showTemplateError(response.data);
    }

    const input = preview.querySelector('input');

    if (null !== input) {
      input.value = response.data;
    }

    editor.submit();
  });
  request.addEventListener('error', () => {
    // Hide preview loader on request complete.
    preview.classList.remove('preview-loader');
    showTemplateError();
  });
  request.send(bundle);
}
/**
 * Update form fields name attributes for layers
 *
 * @param {HTMLElement} designer Layouts designer element.
 */


function reorderLayers(designer) {
  const layers = designer.children;

  for (let index = 0; index < layers.length; index++) {
    const fields = layers[index].querySelectorAll('[name]');
    fields.forEach(field => {
      let name = field.getAttribute('name'); // Try to find layer index.

      const match = name.match(/(.+?\[layers\])\[(\d+)\](\[.+?\])$/);

      if (null !== match) {
        name = match[1] + `[${index}]` + match[3];
      }

      field.name = name;
    });
  }
}
/**
 * Update template background settings with custom logic.
 *
 * @param {HTMLElement} fieldset Fieldset HTML element.
 * @param {Object}      data     Current template data.
 */


function createPermanentAttachment(fieldset, data) {
  data.background = data.background || null; // Create background settings control.

  const control = builders.control({
    classes: ['sharing-image-editor-control', 'control-reduced'],
    label: wp.i18n.__('Template background settings', 'sharing-image'),
    fields: [{
      group: 'radio',
      classes: ['sharing-image-editor-control-radio'],
      attributes: {
        name: editor_params.name + '[background]',
        value: 'blank'
      },
      label: wp.i18n.__('Do not use background image', 'sharing-image'),
      checked: data.background
    }, {
      group: 'radio',
      classes: ['sharing-image-editor-control-radio'],
      attributes: {
        name: editor_params.name + '[background]',
        value: 'dynamic'
      },
      label: wp.i18n.__('Select for each post separately', 'sharing-image'),
      help: wp.i18n.__('Post thumbnail will be used if autogenerate', 'sharing-image'),
      checked: data.background
    }, {
      group: 'radio',
      classes: ['sharing-image-editor-control-radio'],
      attributes: {
        name: editor_params.name + '[background]',
        value: 'permanent'
      },
      label: wp.i18n.__('Upload permanent background', 'sharing-image'),
      checked: data.background
    }],
    append: fieldset
  });
  const media = builders.media({
    name: editor_params.name + '[attachment]',
    classes: ['sharing-image-editor-control', 'control-media'],
    value: data.attachment,
    link: editor_params.links.uploads,
    labels: {
      button: wp.i18n.__('Upload image', 'sharing-image'),
      heading: wp.i18n.__('Select background image', 'sharing-image'),
      details: wp.i18n.__('Attachment details', 'sharing-image')
    },
    append: fieldset
  });
  const upload = media.querySelector('button');
  upload.disabled = true;
  builders.control({
    classes: ['sharing-image-editor-control'],
    label: wp.i18n.__('Fill color', 'sharing-image'),
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-color'],
      attributes: {
        name: editor_params.name + '[fill]',
        type: 'color',
        value: data.fill
      }
    }],
    append: fieldset
  });
  control.querySelectorAll('input').forEach(radio => {
    if ('radio' !== radio.type) {
      return;
    } // Show upload button for checked permanent radio.


    if (radio.checked && 'permanent' === radio.value) {
      upload.disabled = false;
    }

    radio.addEventListener('change', () => {
      upload.disabled = true;

      if ('permanent' === radio.value) {
        upload.disabled = false;
      }
    });
  });
}
/**
 * Text layer dynamic/static fields manager.
 *
 * @param {HTMLElement} layer Current layer element.
 * @param {string}      name  Fields name attribute prefix.
 * @param {Object}      data  Layer data object.
 */


function createDynamicFields(layer, name, data) {
  const control = builders.control({
    classes: ['sharing-image-editor-control'],
    append: layer
  });
  const checkbox = builders.checkbox({
    classes: ['sharing-image-editor-control-checkbox'],
    attributes: {
      name: name + '[dynamic]',
      value: 'dynamic'
    },
    label: wp.i18n.__('Dynamic field. Filled in the post editing screen.', 'sharing-image'),
    checked: data.dynamic
  }, control);
  const fields = [];
  fields[fields.length] = builders.control({
    classes: ['sharing-image-editor-control', 'control-extend', 'control-hidden'],
    help: wp.i18n.__('Displayed only in the metabox.', 'sharing-image'),
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        name: name + '[title]',
        value: data.title
      },
      label: wp.i18n.__('Field name', 'sharing-image')
    }],
    append: layer
  });
  fields[fields.length] = builders.control({
    classes: ['sharing-image-editor-control', 'control-extend', 'control-hidden'],
    help: wp.i18n.__('This field is used for example only, to see how the editor will look.', 'sharing-image'),
    fields: [{
      group: 'textarea',
      classes: ['sharing-image-editor-control-textarea'],
      content: data.sample || 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
      attributes: {
        name: name + '[sample]',
        rows: 2
      },
      label: wp.i18n.__('Text sample', 'sharing-image')
    }],
    append: layer
  });
  fields[fields.length] = builders.control({
    classes: ['sharing-image-editor-control', 'control-hidden'],
    label: wp.i18n.__('Preset text field', 'sharing-image'),
    fields: [{
      group: 'radio',
      classes: ['sharing-image-editor-control-radio'],
      attributes: {
        name: name + '[preset]',
        value: 'none'
      },
      dataset: {
        persistent: true
      },
      label: wp.i18n.__('Fill in manually', 'sharing-image'),
      checked: data.preset || 'none'
    }, {
      group: 'radio',
      classes: ['sharing-image-editor-control-radio'],
      attributes: {
        name: name + '[preset]',
        value: 'title'
      },
      dataset: {
        persistent: true
      },
      label: wp.i18n.__('Take from post title', 'sharing-image'),
      checked: data.preset || 'none'
    }, {
      group: 'radio',
      classes: ['sharing-image-editor-control-radio'],
      attributes: {
        name: name + '[preset]',
        value: 'excerpt'
      },
      dataset: {
        persistent: true
      },
      label: wp.i18n.__('Use post excerpt text', 'sharing-image'),
      checked: data.preset || 'none'
    }],
    append: layer
  });
  fields[fields.length] = builders.control({
    classes: ['sharing-image-editor-control', 'control-extend'],
    help: wp.i18n.__('You can use non-breaking spaces to manage your string position.', 'sharing-image'),
    fields: [{
      group: 'textarea',
      classes: ['sharing-image-editor-control-textarea'],
      content: data.content,
      attributes: {
        name: name + '[content]',
        rows: 2
      },
      label: wp.i18n.__('Content', 'sharing-image')
    }],
    append: layer
  }); // Helper function to toggle contols visibility.

  const toggleClasses = () => {
    fields.forEach(field => {
      field.classList.toggle('control-hidden');
    });
  };

  if (checkbox.checked) {
    toggleClasses();
  }

  checkbox.addEventListener('change', () => {
    toggleClasses();
  });
}
/**
 * Text layer more options fields manager.
 *
 * @param {HTMLElement} layer Current layer element.
 * @param {string}      name  Fields name attribute prefix.
 * @param {Object}      data  Layer data object.
 */


function createMoreFields(layer, name, data) {
  const fields = [];
  fields[fields.length] = createFontField(layer, name, data);
  fields[fields.length] = builders.control({
    classes: ['sharing-image-editor-control', 'control-hidden'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-color'],
      attributes: {
        type: 'color',
        name: name + '[color]',
        value: data.color || '#ffffff'
      },
      label: wp.i18n.__('Text color', 'sharing-image')
    }],
    append: layer
  });
  fields[fields.length] = builders.control({
    classes: ['sharing-image-editor-control', 'control-series', 'control-hidden'],
    fields: [{
      group: 'select',
      classes: ['sharing-image-editor-control-select'],
      options: {
        left: wp.i18n.__('Left', 'sharing-image'),
        center: wp.i18n.__('Center', 'sharing-image'),
        right: wp.i18n.__('Right', 'sharing-image')
      },
      attributes: {
        name: name + '[horizontal]'
      },
      label: wp.i18n.__('Horizontal alignment', 'sharing-image'),
      selected: data.horizontal
    }, {
      group: 'select',
      classes: ['sharing-image-editor-control-select'],
      options: {
        top: wp.i18n.__('Top', 'sharing-image'),
        center: wp.i18n.__('Center', 'sharing-image'),
        bottom: wp.i18n.__('Bottom', 'sharing-image')
      },
      attributes: {
        name: name + '[vertical]'
      },
      label: wp.i18n.__('Vertical alignment', 'sharing-image'),
      selected: data.vertical
    }],
    append: layer
  });
  const control = builders.control({
    classes: ['sharing-image-editor-control'],
    append: layer
  });
  const button = builders.element('button', {
    classes: ['sharing-image-editor-more'],
    text: wp.i18n.__('More options', 'sharing-image'),
    attributes: {
      type: 'button'
    },
    append: control
  });
  button.addEventListener('click', () => {
    fields.forEach(field => {
      field.classList.remove('control-hidden');
    }); // Remove button on expand.

    layer.removeChild(control);
  }); // Open more fields for existing layers.

  if (Object.keys(data).length > 0) {
    button.click();
  }
}
/**
 * Create font field in text layer.
 *
 * @param {HTMLElement} layer Current layer element.
 * @param {string}      name  Fields name attribute prefix.
 * @param {Object}      data  Layer data object.
 */


function createFontField(layer, name, data) {
  const control = builders.control({
    classes: ['sharing-image-editor-control', 'control-upload', 'control-hidden'],
    append: layer
  });
  const select = builders.select({
    classes: ['sharing-image-editor-control-select'],
    options: editor_params.fonts,
    attributes: {
      name: name + '[fontname]'
    },
    label: wp.i18n.__('Font family', 'sharing-image'),
    selected: data.fontname
  }, control);
  const media = builders.media({
    name: name + '[fontfile]',
    classes: ['sharing-image-editor-control-media'],
    value: data.fontfile,
    link: editor_params.links.uploads,
    labels: {
      button: wp.i18n.__('Upload custom font', 'sharing-image'),
      heading: wp.i18n.__('Upload custom font', 'sharing-image'),
      details: wp.i18n.__('Font attachment', 'sharing-image'),
      remove: wp.i18n.__('Remove font', 'sharing-image')
    },
    remove: true,
    append: control
  });
  builders.element('small', {
    text: wp.i18n.__('Custom font can only be in .ttf format.'),
    append: control
  });

  if (data.fontfile) {
    select.disabled = true;
  } // Find media attachment input.


  const input = media.querySelector('input');
  input.addEventListener('change', () => {
    select.disabled = false;

    if (input.value) {
      select.disabled = true;
    }
  });
  return control;
}
/**
 * Rectangle layer outline option.
 *
 * @param {HTMLElement} layer Current layer element.
 * @param {string}      name  Fields name attribute prefix.
 * @param {Object}      data  Layer data object.
 */


function createRectangleOutline(layer, name, data) {
  const control = builders.control({
    classes: ['sharing-image-editor-control'],
    append: layer
  });
  const checkbox = builders.checkbox({
    classes: ['sharing-image-editor-control-checkbox'],
    attributes: {
      name: name + '[outline]',
      value: 'outline'
    },
    label: wp.i18n.__('Outline rectangle.', 'sharing-image'),
    checked: data.outline
  }, control);
  const range = builders.control({
    classes: ['sharing-image-editor-control', 'control-hidden'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-range'],
      attributes: {
        type: 'range',
        name: name + '[thickness]',
        min: 0,
        max: 50,
        step: 1,
        value: data.thickness || '0'
      },
      label: wp.i18n.__('Border width', 'sharing-image')
    }],
    append: layer
  });

  if (data.outline) {
    range.classList.remove('control-hidden');
  }

  checkbox.addEventListener('change', () => {
    range.classList.add('control-hidden');

    if (checkbox.checked) {
      range.classList.remove('control-hidden');
    }
  });
}
/**
 * Create catalog button in footer.
 *
 * @param {HTMLElement} footer Footer HTML element.
 */


function createCatalogButton(footer) {
  const link = new URL(document.location.href);
  link.searchParams.delete('template');
  builders.element('a', {
    classes: ['button'],
    text: wp.i18n.__('← Back to Catalog', 'sharing-image'),
    attributes: {
      href: link.href
    },
    append: footer
  });
}
/**
 * Create template deletion button in footer.
 *
 * @param {HTMLElement} footer Footer HTML element.
 */


function createDeleteButton(footer) {
  const href = new URL(document.location.href); // Get template index from current link.

  const index = href.searchParams.get('template'); // Set template index to delete link.

  const link = new URL(editor.getAttribute('action'));
  link.searchParams.set('action', 'sharing_image_delete');
  link.searchParams.set('template', index);
  link.searchParams.set('nonce', editor_params.nonce);
  builders.element('a', {
    classes: ['sharing-image-editor-delete'],
    text: wp.i18n.__('Delete template', 'sharing-image'),
    attributes: {
      href: link.href
    },
    append: footer
  });
}
/**
 * Create preview element.
 *
 * @param {HTMLElement} viewport Monitor viewport element.
 * @param {Object}      data     Template data object.
 */


function createPreview(viewport, data) {
  preview = builders.element('div', {
    classes: ['sharing-image-editor-preview', 'preview-blank'],
    append: viewport
  });

  if (data.preview) {
    builders.element('img', {
      attributes: {
        src: data.preview,
        alt: ''
      },
      append: preview
    });
    preview.classList.remove('preview-blank');
  }

  builders.element('span', {
    classes: ['sharing-image-editor-loader'],
    append: preview
  });
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: editor_params.name + '[preview]',
      value: data.preview
    },
    append: preview
  });
  return preview;
}
/**
 *
 * @param {*} designer
 * @param {*} layer
 */


function createCollapseButton(designer, layer) {
  const label = layer.querySelector('h2');
  const button = builders.element('button', {
    classes: ['sharing-image-editor-collapse'],
    attributes: {
      type: 'button',
      title: wp.i18n.__('Collapse layer', 'sharing-image')
    },
    append: label
  });
  button.addEventListener('click', e => {
    e.preventDefault(); // Set default button title.

    button.setAttribute('title', wp.i18n.__('Collapse layer', 'sharing-image'));
    layer.classList.toggle('layer-collapsed'); // Check if new class is collapsed.

    const collapsed = layer.classList.contains('layer-collapsed');

    if (collapsed) {
      button.setAttribute('title', wp.i18n.__('Expand layer', 'sharing-image'));
    }
  });
}
/**
 * Create button inside layer box to change order.
 *
 * @param {HTMLElement} designer Layers designer HTML element.
 * @param {HTMLElement} layer    Current layer HTML emelemt.
 */


function createOrderLayersButton(designer, layer) {
  const button = builders.element('button', {
    classes: ['sharing-image-editor-order'],
    attributes: {
      type: 'button',
      title: wp.i18n.__('Raise higher', 'sharing-image')
    },
    append: layer
  });
  button.addEventListener('click', () => {
    if (layer.previousSibling) {
      designer.insertBefore(layer, layer.previousSibling);
    } // Update fields name attributes.


    reorderLayers(designer);

    if (editor.classList.contains('editor-suspend')) {
      return;
    }

    generateTemplate();
  });
}
/**
 * Create button to delete layer.
 *
 * @param {HTMLElement} designer Layers designer HTML element.
 * @param {HTMLElement} layer    Current layer HTML emelemt.
 */


function createDeleteLayerButton(designer, layer) {
  const control = builders.control({
    classes: ['sharing-image-editor-control', 'control-footer'],
    append: layer
  });
  const button = builders.element('button', {
    classes: ['sharing-image-editor-delete'],
    text: wp.i18n.__('Delete layer', 'sharing-image'),
    attributes: {
      type: 'button'
    },
    append: control
  });
  button.addEventListener('click', () => {
    designer.removeChild(layer); // Update fields name attributes.

    reorderLayers(designer);

    if (editor.classList.contains('editor-suspend')) {
      return;
    }

    generateTemplate();
  });
}
/**
 * Create image layer.
 *
 * @param {number} index Current layer index.
 * @param {Object} data  Current template layer data.
 */


function createLayerImage(index, data) {
  const description = [];
  description.push(wp.i18n.__('Use jpg, gif or png image formats.', 'sharing-image'));
  description.push(wp.i18n.__('Leave width and height fields blank to use the original image size.', 'sharing-image'));
  description.push(wp.i18n.__('Sizes are calculated proportionally if not filled.', 'sharing-image'));
  const layer = builders.layer({
    classes: ['sharing-image-editor-layer', 'layer-image'],
    label: wp.i18n.__('Image', 'sharing-image'),
    description: description.join(' ')
  }); // Form fields name for this layer.

  const name = editor_params.name + `[layers][${index}]`;
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: name + '[type]',
      value: 'image'
    },
    append: layer
  });
  builders.media({
    name: name + '[attachment]',
    classes: ['sharing-image-editor-control', 'control-media'],
    value: data.attachment,
    link: editor_params.links.uploads,
    labels: {
      button: wp.i18n.__('Upload image', 'sharing-image'),
      heading: wp.i18n.__('Select layer image', 'sharing-image'),
      details: wp.i18n.__('Attachment details', 'sharing-image')
    },
    append: layer
  });
  builders.control({
    classes: ['sharing-image-editor-control', 'control-sizes'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        name: name + '[x]',
        value: data.x,
        placeholder: '10'
      },
      label: wp.i18n.__('X', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        name: name + '[y]',
        value: data.y,
        placeholder: '10'
      },
      label: wp.i18n.__('Y', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        name: name + '[width]',
        value: data.width
      },
      label: wp.i18n.__('Width', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        name: name + '[height]',
        value: data.height
      },
      label: wp.i18n.__('Height', 'sharing-image')
    }],
    append: layer
  });
  return layer;
}
/**
 * Create text layer.
 *
 * @param {number} index Current layer index.
 * @param {Object} data  Current template data.
 */


function createLayerText(index, data) {
  const description = [];
  description.push(wp.i18n.__('Write a text to the current image.', 'sharing-image'));
  description.push(wp.i18n.__('If the font does not fit within your limits, its size will decrease.', 'sharing-image'));
  description.push(wp.i18n.__('Avoid using large font sizes for long text – this affects performance.', 'sharing-image'));
  const layer = builders.layer({
    classes: ['sharing-image-editor-layer', 'layer-text'],
    label: wp.i18n.__('Text', 'sharing-image'),
    description: description.join(' ')
  }); // Form fields name for this layer.

  const name = editor_params.name + `[layers][${index}]`;
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: name + '[type]',
      value: 'text'
    },
    append: layer
  });
  builders.control({
    classes: ['sharing-image-editor-control', 'control-sizes'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        type: 'text',
        name: name + '[x]',
        value: data.x,
        placeholder: '10'
      },
      label: wp.i18n.__('X', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        type: 'text',
        name: name + '[y]',
        value: data.y,
        placeholder: '10'
      },
      label: wp.i18n.__('Y', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        type: 'text',
        name: name + '[width]',
        value: data.width,
        placeholder: '1000'
      },
      label: wp.i18n.__('Width', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        type: 'text',
        name: name + '[height]',
        value: data.height
      },
      label: wp.i18n.__('Height', 'sharing-image')
    }],
    append: layer
  }); // Create static/dynamic text fields.

  createDynamicFields(layer, name, data); // Create more options.

  createMoreFields(layer, name, data);
  builders.control({
    classes: ['sharing-image-editor-control', 'control-series'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-range'],
      attributes: {
        type: 'range',
        name: name + '[fontsize]',
        min: 10,
        max: 200,
        step: 1,
        value: data.fontsize || '48'
      },
      label: wp.i18n.__('Font size', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-range'],
      attributes: {
        type: 'range',
        name: name + '[lineheight]',
        min: 0,
        max: 4,
        step: 0.125,
        value: data.lineheight || '1.5'
      },
      label: wp.i18n.__('Line height', 'sharing-image')
    }],
    append: layer
  });
  return layer;
}
/**
 * Create filter layer.
 *
 * @param {number} index Current layer index.
 * @param {Object} data  Current template data.
 */


function createLayerFilter(index, data) {
  const description = [];
  description.push(wp.i18n.__('Filters are applied one after another to the entire editor image.', 'sharing-image'));
  description.push(wp.i18n.__('If you want to control their order, create multiple layers.', 'sharing-image'));
  const layer = builders.layer({
    classes: ['sharing-image-editor-layer', 'layer-text'],
    label: wp.i18n.__('Filter', 'sharing-image'),
    description: description.join(' ')
  }); // Form fields name for this layer.

  const name = editor_params.name + `[layers][${index}]`;
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: name + '[type]',
      value: 'filter'
    },
    append: layer
  });
  builders.control({
    classes: ['sharing-image-editor-control'],
    fields: [{
      group: 'checkbox',
      classes: ['sharing-image-editor-control-checkbox'],
      attributes: {
        name: name + '[grayscale]',
        value: 'grayscale'
      },
      label: wp.i18n.__('Turns image into a grayscale version', 'sharing-image'),
      checked: data.grayscale
    }],
    append: layer
  });
  builders.control({
    classes: ['sharing-image-editor-control'],
    fields: [{
      group: 'checkbox',
      classes: ['sharing-image-editor-control-checkbox'],
      attributes: {
        name: name + '[blur]',
        value: 'blur'
      },
      label: wp.i18n.__('Blur image by Gaussian effect', 'sharing-image'),
      checked: data.blur
    }],
    append: layer
  });
  builders.control({
    classes: ['sharing-image-editor-control'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-range'],
      attributes: {
        type: 'range',
        name: name + '[contrast]',
        min: -50,
        max: 50,
        step: 5,
        value: data.contrast || '0'
      },
      label: wp.i18n.__('Contrast', 'sharing-image')
    }],
    append: layer
  });
  builders.control({
    classes: ['sharing-image-editor-control'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-range'],
      attributes: {
        type: 'range',
        name: name + '[brightness]',
        min: -50,
        max: 50,
        step: 5,
        value: data.brightness || '0'
      },
      label: wp.i18n.__('Brightness', 'sharing-image')
    }],
    append: layer
  });
  builders.control({
    classes: ['sharing-image-editor-control'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-range'],
      attributes: {
        type: 'range',
        name: name + '[blackout]',
        min: 0,
        max: 100,
        step: 5,
        value: data.blackout || '0'
      },
      label: wp.i18n.__('Blackout', 'sharing-image')
    }],
    append: layer
  });
  return layer;
}
/**
 * Create rectangle layer.
 *
 * @param {number} index Current layer index.
 * @param {Object} data  Current template data.
 */


function createLayerRectangle(index, data) {
  const description = [];
  description.push(wp.i18n.__('Draw a colored rectangle on current image.', 'sharing-image'));
  description.push(wp.i18n.__('You can get filled or outlined figure with custom color and opacity.', 'sharing-image'));
  description.push(wp.i18n.__('Use small height to draw the line.', 'sharing-image'));
  const layer = builders.layer({
    classes: ['sharing-image-editor-layer', 'layer-text'],
    label: wp.i18n.__('Rectangle', 'sharing-image'),
    description: description.join(' ')
  }); // Form fields name for this layer.

  const name = editor_params.name + `[layers][${index}]`;
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: name + '[type]',
      value: 'rectangle'
    },
    append: layer
  });
  builders.control({
    classes: ['sharing-image-editor-control'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-color'],
      attributes: {
        type: 'color',
        name: name + '[color]',
        value: data.color || '#ffffff'
      },
      label: wp.i18n.__('Rectangle color', 'sharing-image')
    }],
    append: layer
  });
  builders.control({
    classes: ['sharing-image-editor-control', 'control-sizes'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        type: 'text',
        name: name + '[x]' || 0,
        value: data.x
      },
      label: wp.i18n.__('X', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        type: 'text',
        name: name + '[y]' || 0,
        value: data.y
      },
      label: wp.i18n.__('Y', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        type: 'text',
        name: name + '[width]',
        value: data.width
      },
      label: wp.i18n.__('Width', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        type: 'text',
        name: name + '[height]',
        value: data.height
      },
      label: wp.i18n.__('Height', 'sharing-image')
    }],
    append: layer
  });
  createRectangleOutline(layer, name, data);
  builders.control({
    classes: ['sharing-image-editor-control'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-range'],
      attributes: {
        type: 'range',
        name: name + '[opacity]',
        min: 0,
        max: 100,
        step: 5,
        value: data.opacity || '0'
      },
      label: wp.i18n.__('Opacity', 'sharing-image')
    }],
    append: layer
  });
  return layer;
}
/**
 * Create new layer.
 *
 * @param {HTMLElement} designer Designer HTML element.
 * @param {string}      type     New layer type.
 * @param {number}      index    Layer index.
 * @param {Object}      data     New layer data.
 */


function createLayer(designer, type, index) {
  let data = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
  let layer = null;

  switch (type) {
    case 'image':
      layer = createLayerImage(index, data);
      break;

    case 'text':
      layer = createLayerText(index, data);
      break;

    case 'filter':
      layer = createLayerFilter(index, data);
      break;

    case 'rectangle':
      layer = createLayerRectangle(index, data);
      break;
  }

  if (null === layer) {
    return;
  }

  designer.insertBefore(layer, designer.firstChild); // Delete this layer button.

  createDeleteLayerButton(designer, layer); // Create collapse button.

  createCollapseButton(designer, layer); // Reorder layers button.

  createOrderLayersButton(designer, layer);
}
/**
 * Create layers designer control.
 *
 * @param {HTMLElement} fieldset Fieldset HTML element.
 * @param {Object}      data     Current template data.
 */


function createDesigner(fieldset, data) {
  const control = builders.control({
    classes: ['sharing-image-editor-control', 'control-select', 'control-compact'],
    fields: [{
      group: 'select',
      classes: ['sharing-image-editor-control-select'],
      options: {
        text: wp.i18n.__('Text', 'sharing-image'),
        image: wp.i18n.__('Image', 'sharing-image'),
        filter: wp.i18n.__('Filter', 'sharing-image'),
        rectangle: wp.i18n.__('Rectangle', 'sharing-image')
      }
    }],
    append: fieldset
  });
  const button = builders.element('button', {
    classes: ['button'],
    text: wp.i18n.__('Add new', 'sharing-image'),
    attributes: {
      type: 'button'
    },
    append: control
  });
  const designer = builders.element('div', {
    classes: ['sharing-image-editor-designer'],
    append: fieldset
  }); // Set default layers set.

  let layers = data.layers || [];
  layers = layers.reverse();
  layers.forEach((layer, index) => {
    if (layer.hasOwnProperty('type')) {
      createLayer(designer, layer.type, index++, layer);
    }
  });
  button.addEventListener('click', () => {
    const select = control.querySelector('select');

    if (null === select) {
      return;
    }

    createLayer(designer, select.value, designer.children.length);
  });
}
/**
 * Create common settings on template editor screen.
 *
 * @param {Object} data Current template data.
 */


function createFieldset(data) {
  const fieldset = builders.element('div', {
    classes: ['sharing-image-editor-fieldset'],
    append: editor
  }); // Create template title control.

  builders.control({
    classes: ['sharing-image-editor-control', 'control-compact', 'control-extend'],
    help: wp.i18n.__('Used only in the admin panel', 'sharing-image'),
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        name: editor_params.name + '[title]',
        value: data.title
      },
      dataset: {
        persistent: true
      },
      label: wp.i18n.__('Template title', 'sharing-image')
    }],
    append: fieldset
  }); // Create background settings with custom logic.

  createPermanentAttachment(fieldset, data); // Create width/height settings control.

  builders.control({
    classes: ['sharing-image-editor-control', 'control-compact', 'control-sizes'],
    fields: [{
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        name: editor_params.name + '[width]',
        value: data.width || '1200',
        placeholder: '1200'
      },
      label: wp.i18n.__('Editor width', 'sharing-image')
    }, {
      group: 'input',
      classes: ['sharing-image-editor-control-input'],
      attributes: {
        name: editor_params.name + '[height]',
        value: data.height || '630',
        placeholder: '630'
      },
      label: wp.i18n.__('Editor height', 'sharing-image')
    }],
    append: fieldset
  });
  const description = [];
  description.push(wp.i18n.__('You can add multiple layers on your editor.', 'sharing-image'));
  description.push(wp.i18n.__('Note that the stacking order of the layers is important.', 'sharing-image'));
  description.push(wp.i18n.__('You can change the order using the arrows in the corner of each box.', 'sharing-image'));
  builders.control({
    classes: ['sharing-image-editor-control', 'control-reduced'],
    label: wp.i18n.__('Add layers', 'sharing-image'),
    description: description.join(' '),
    append: fieldset
  }); // Create layers designer block.

  createDesigner(fieldset, data);
  const footer = builders.control({
    classes: ['sharing-image-editor-control', 'control-footer'],
    append: fieldset
  }); // Create back to catalog button.

  createCatalogButton(footer); // Create template deletion button.

  createDeleteButton(footer);
  fieldset.addEventListener('change', e => {
    if (editor.classList.contains('editor-suspend')) {
      return;
    }

    const target = e.target; // Skip fields that don't affect the poster.

    if (target.hasAttribute('data-persistent')) {
      return;
    }

    if (!target.hasAttribute('name')) {
      return;
    }

    generateTemplate();
  });
}
/**
 * Create button to submit editor form.
 *
 * @param {HTMLElement} manager Manager element.
 */


function createSubmitButton(manager) {
  builders.element('button', {
    text: wp.i18n.__('Save changes', 'sharing-image'),
    classes: ['button', 'button-primary'],
    attributes: {
      type: 'submit'
    },
    append: manager
  });
}
/**
 * Create button to generate new template manually.
 *
 * @param {HTMLElement} manager Manager element.
 */


function createGenerateButton(manager) {
  const button = builders.element('button', {
    text: wp.i18n.__('Generate preview', 'sharing-image'),
    classes: ['button'],
    attributes: {
      type: 'button'
    },
    append: manager
  });
  button.addEventListener('click', () => {
    generateTemplate();
  });
}
/**
 * Create disable live-reloading checkbox.
 *
 * @param {HTMLElement} manager Manager element.
 * @param {Object}      data    Template data.
 */


function createSuspendCheckbox(manager, data) {
  const checkbox = builders.checkbox({
    classes: ['sharing-image-editor-suspend'],
    attributes: {
      name: editor_params.name + '[suspend]',
      value: 'suspend'
    },
    label: wp.i18n.__('Disable live-reload', 'sharing-image'),
    checked: data.suspend
  }, manager);

  if (data.suspend) {
    editor.classList.add('editor-suspend');
  }

  checkbox.addEventListener('change', () => {
    editor.classList.remove('editor-suspend');

    if (checkbox.checked) {
      editor.classList.add('editor-suspend');
    }
  });
}
/**
 * Create template settings preview.
 *
 * @param {Object} data Current template data.
 */


function createMonitor(data) {
  const monitor = builders.element('div', {
    classes: ['sharing-image-editor-monitor'],
    append: editor
  });
  const viewport = builders.element('div', {
    classes: ['sharing-image-editor-viewport'],
    append: monitor
  });
  createPreview(viewport, data);
  builders.element('div', {
    classes: ['sharing-image-editor-warning'],
    append: viewport
  });
  const manager = builders.element('div', {
    classes: ['sharing-image-editor-manager'],
    append: viewport
  }); // Create live-reload manager checkbox.

  createSuspendCheckbox(manager, data); // Create submit form button.

  createSubmitButton(manager); // Create template generator button.

  createGenerateButton(manager);
}
/**
 * Create form hidden settings fields.
 *
 * @param {HTMLElement} content Settings content element.
 * @param {number}      index   Current option index.
 */


function prepareEditor(content, index) {
  editor_params.name = 'sharing_image_editor';
  const form = builders.element('form', {
    classes: ['sharing-image-editor'],
    attributes: {
      action: editor_params.links.action,
      method: 'POST'
    },
    append: content
  });
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: 'action',
      value: editor_params.name
    },
    append: form
  });
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: 'sharing_image_index',
      value: index
    },
    append: form
  });
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: 'sharing_image_nonce',
      value: editor_params.nonce
    },
    append: form
  });
  form.addEventListener('submit', e => {
    e.preventDefault();
    saveTemplate();
  });
  return form;
}
/**
 * Create template editor page.
 *
 * @param {HTMLElement} content  Settings content element.
 * @param {Object}      settings Global settings object.
 * @param {number}      index    Current option index.
 * @param {Object}      data     Template data.
 */


function createEditor(content, settings, index) {
  let data = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
  editor_params = settings; // Prepare form with hidden fields and events.

  editor = prepareEditor(content, index); // Create monitor section part.

  createMonitor(data); // Create fieldset section part.

  createFieldset(data);
}

/* harmony default export */ const sections_editor = (createEditor);
;// CONCATENATED MODULE: ./src/scripts/sections/config.js
/**
 * Config settings tab.
 */
 // Store global scriot object for settings page.

let config_params = null;
/**
 * Create default poster option.
 *
 * @param {HTMLElement} options Options form element.
 * @param {Object}      data    Config data object.
 */

function createDefaultOptions(options, data) {
  const control = builders.control({
    classes: ['sharing-image-config-control'],
    label: wp.i18n.__('Default poster', 'sharing-image'),
    append: options
  });
  builders.media({
    name: config_params.name + '[default]',
    classes: ['sharing-image-config-control-media'],
    label: wp.i18n.__('Default poster', 'sharing-image'),
    value: data.default,
    link: config_params.links.uploads,
    labels: {
      button: wp.i18n.__('Upload image', 'sharing-image'),
      heading: wp.i18n.__('Select default poster', 'sharing-image'),
      details: wp.i18n.__('Attachment details', 'sharing-image'),
      remove: wp.i18n.__('Remove image', 'sharing-image')
    },
    remove: true,
    append: control
  });
  const description = [];
  description.push(wp.i18n.__('The default poster is used on pages where there is no generated.', 'sharing-image'));
  description.push(wp.i18n.__('Best image size: 1200×630 pixels.', 'sharing-image'));
  builders.element('small', {
    text: description.join(' '),
    append: control
  });
}
/**
 * Create uploads directory option.
 *
 * @param {HTMLElement} options Options form element.
 * @param {Object}      data    Config data object.
 */


function createUploadsOptions(options, data) {
  const control = builders.control({
    classes: ['sharing-image-config-control'],
    label: wp.i18n.__('Upload directory', 'sharing-image'),
    append: options
  });
  const fieldset = builders.element('div', {
    classes: ['sharing-image-config-control-fieldset'],
    append: control
  });
  builders.radio({
    classes: ['sharing-image-config-control-radio'],
    attributes: {
      name: config_params.name + '[uploads]',
      value: 'default'
    },
    label: wp.i18n.__('Use default uploads directory', 'sharing-image'),
    checked: data.uploads || 'default'
  }, fieldset);
  builders.radio({
    classes: ['sharing-image-config-control-radio'],
    attributes: {
      name: config_params.name + '[uploads]',
      value: 'custom'
    },
    label: wp.i18n.__('Choose custom storage for posters', 'sharing-image'),
    checked: data.uploads || 'default'
  }, fieldset);
  const input = builders.input({
    classes: ['sharing-image-config-control-input'],
    attributes: {
      name: config_params.name + '[storage]',
      value: data.storage || config_params.links.storage,
      disabled: 'disabled'
    }
  }, control);
  builders.element('small', {
    text: wp.i18n.__('Use relative path from site root. Directory should be writeable.', 'sharing-image'),
    append: control
  });
  control.querySelectorAll('input').forEach(radio => {
    if ('radio' !== radio.type) {
      return;
    } // Show storage input for checked custom radio.


    if (radio.checked && 'custom' === radio.value) {
      input.disabled = false;
    }

    radio.addEventListener('change', () => {
      input.disabled = true;

      if ('custom' === radio.value) {
        input.disabled = false;
      }
    });
  });
}
/**
 * Create format and quality poster options.
 *
 * @param {HTMLElement} options Options form element.
 * @param {Object}      data    Config data object.
 */


function createImageOptions(options, data) {
  const control = builders.control({
    classes: ['sharing-image-config-control', 'control-extra'],
    label: wp.i18n.__('Poster image format', 'sharing-image'),
    help: wp.i18n.__('The higher the value, the less compression. Availible for JPEG only.', 'sharing-image'),
    fields: [{
      group: 'select',
      classes: ['sharing-image-config-control-select'],
      options: {
        jpg: wp.i18n.__('JPEG', 'sharing-image'),
        png: wp.i18n.__('PNG', 'sharing-image'),
        gif: wp.i18n.__('GIF', 'sharing-image')
      },
      attributes: {
        name: config_params.name + '[format]'
      },
      selected: data.format || 'jpg'
    }, {
      group: 'input',
      classes: ['sharing-image-config-control-range'],
      attributes: {
        type: 'range',
        name: config_params.name + '[quality]',
        min: 10,
        max: 100,
        step: 5,
        value: data.quality || '90',
        disabled: 'disabled'
      },
      label: wp.i18n.__('Image quality', 'sharing-image')
    }],
    append: options
  }); // Find control format select.

  const format = control.querySelector('select'); // Find control quiality input.

  const quality = control.querySelector('input');

  if ('jpg' === format.value) {
    quality.disabled = false;
  }

  format.addEventListener('change', () => {
    quality.disabled = true;

    if ('jpg' === format.value) {
      quality.disabled = false;
    }
  });
}
/**
 * Create autogenerate poster options.
 *
 * @param {HTMLElement} options   Options form element.
 * @param {Object}      data      Config data object.
 * @param {Array}       templates List of templates.
 */


function createAutogenerateOptions(options, data, templates) {
  const fields = {}; // Add the option for disabling feature.

  fields.manual = wp.i18n.__('Disable auto generation', 'sharing-image');
  templates.forEach((template, i) => {
    fields[i] = template.title || wp.i18n.__('Untitled', 'sharing-image');
  });
  let selected = data.autogenerate;

  if (typeof selected === 'undefined') {
    selected = 'manual';
  }

  builders.control({
    classes: ['sharing-image-config-control'],
    label: wp.i18n.__('Auto generate poster', 'sharing-image'),
    help: wp.i18n.__('This template will be applied automatically on post save.', 'sharing-image'),
    fields: [{
      group: 'select',
      classes: ['sharing-image-config-control-select'],
      options: fields,
      attributes: {
        name: config_params.name + '[autogenerate]'
      },
      selected: String(selected)
    }],
    append: options
  });
}
/**
 * Create required form meta fields.
 *
 * @param {HTMLElement} options Options form element.
 */


function createMetaFields(options) {
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: 'action',
      value: config_params.name
    },
    append: options
  });
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: 'sharing_image_nonce',
      value: config_params.nonce
    },
    append: options
  });
  builders.element('button', {
    text: wp.i18n.__('Save changes', 'sharing-image'),
    classes: ['button', 'button-primary'],
    attributes: {
      type: 'submit'
    },
    append: options
  });
}
/**
 * Create templates catalog from options.
 *
 * @param {HTMLElement} content  Settings content element.
 * @param {Object}      settings Global settings field.
 */


function createConfig(content, settings) {
  config_params = settings; // Set params name for template form fields.

  config_params.name = 'sharing_image_config'; // Find config element

  const config = content.querySelector('.sharing-image-config');

  if (null === config) {
    return;
  }

  const options = builders.element('form', {
    classes: ['sharing-image-config-options'],
    attributes: {
      action: config_params.links.action,
      method: 'POST'
    },
    append: config
  });
  const data = config_params.config || {};
  const templates = config_params.templates || []; // Poster image options.

  createImageOptions(options, data); // Autogenerate poster.

  createAutogenerateOptions(options, data, templates); // Uploads directory options.

  createUploadsOptions(options, data); // Default poster.

  createDefaultOptions(options, data); // Create required form fields

  createMetaFields(options);
}

/* harmony default export */ const config = (createConfig);
;// CONCATENATED MODULE: ./src/scripts/sections/premium.js
/**
 * Premium settings tab.
 */

/* global ajaxurl:true */
 // Store global scriot object for settings page.

let premium_params = null; // Premium HTML emelent.

let premium = null;
/**
 * Parse error code from settings or AJAX response.
 *
 * @param {string} code  Error code from settings or AJAX response.
 * @param {string} title Prepended error title. Optional.
 */

function parseErrorCode(code, title) {
  const message = [];

  if (undefined === title) {
    title = wp.i18n.__('Verification failed.', 'sharing-image');
  }

  message.push(title);

  switch (code) {
    case 'LIMIT_EXCEEDED':
      message.push(wp.i18n.__('The number of licenses for this key has been exceeded.', 'sharing-image'));
      break;

    case 'KEY_NOT_FOUND':
      message.push(wp.i18n.__('Premium key is invalid or expired.', 'sharing-image'));
      break;

    case 'SERVER_ERROR':
      message.push(wp.i18n.__('Unable to get a response from the verification server.', 'sharing-image'));
      break;
  }

  return message.join(' ');
}
/**
 * Show premium warning message.
 *
 * @param {string} message Warning message.
 */


function showPremiumError(message) {
  // Try to find warning element.
  const warning = premium.querySelector('.sharing-image-premium-warning');

  if (null === warning) {
    return;
  }

  warning.classList.add('warning-visible');
  warning.textContent = message || wp.i18n.__('Unknown request error', 'sharing-image');
}
/**
 * Remove warning message block.
 */


function hidePremiumError() {
  // Try to find warning element.
  const warning = premium.querySelector('.sharing-image-premium-warning');

  if (null === warning) {
    return;
  }

  warning.classList.remove('warning-visible');
}
/**
 * Revoke Premium key.
 *
 * @param {HTMLElement} access Access form element.
 */


function revokePremium(access) {
  access.classList.add('access-loader');
  const request = new XMLHttpRequest();
  request.open('POST', ajaxurl);
  request.responseType = 'json'; // Create data bundle using form data.

  const bundle = new window.FormData(access);
  bundle.set('action', 'sharing_image_revoke');
  hidePremiumError();
  request.addEventListener('load', () => {
    const response = request.response || {}; // Hide form loader class.

    access.classList.remove('access-loader');

    if (!response.data) {
      return showPremiumError();
    }

    if (!response.success) {
      return showPremiumError(response.data);
    }

    premium_params.license = response.data; // Refresh premium fields.

    preparePremiumFields();
  });
  request.addEventListener('error', () => {
    showPremiumError(); // Hide form loader class.

    access.classList.remove('access-loader');
  });
  request.send(bundle);
}
/**
 * Verify Premium key.
 *
 * @param {HTMLElement} access Access form element.
 */


function verifyPremium(access) {
  access.classList.add('access-loader');
  const request = new XMLHttpRequest();
  request.open('POST', ajaxurl);
  request.responseType = 'json'; // Create data bundle using form data.

  const bundle = new window.FormData(access);
  bundle.set('action', 'sharing_image_verify');
  hidePremiumError();
  request.addEventListener('load', () => {
    const response = request.response || {}; // Hide form loader class.

    access.classList.remove('access-loader');

    if (!response.data) {
      return showPremiumError();
    }

    if (!response.success) {
      return showPremiumError(parseErrorCode(response.code, response.data));
    }

    premium_params.license = response.data; // Refresh premium fields.

    preparePremiumFields();
  });
  request.addEventListener('error', () => {
    showPremiumError(); // Hide form loader class.

    access.classList.remove('access-loader');
  });
  request.send(bundle);
}
/**
 * Show verify form if stil not premium.
 *
 * @param {HTMLElement} access  Access HTML element.
 * @param {Object}      license License data.
 */


function showVerifyForm(access, license) {
  if (license.error) {
    showPremiumError(parseErrorCode(license.error));
  }

  builders.element('strong', {
    text: wp.i18n.__('Do you already have a key? Enter it here', 'sharing-image'),
    append: access
  });
  const verify = builders.element('div', {
    classes: ['sharing-image-premium-verify'],
    append: access
  });
  builders.element('input', {
    label: wp.i18n.__('Your Premium key', 'sharing-image'),
    attributes: {
      type: 'text',
      name: 'sharing_image_key',
      value: license.key
    },
    append: verify
  });
  builders.element('button', {
    classes: ['button'],
    text: wp.i18n.__('Submit', 'sharing-image'),
    attributes: {
      type: 'submit'
    },
    append: verify
  });
  builders.element('span', {
    classes: ['spinner'],
    append: verify
  });
  access.addEventListener('submit', e => {
    e.preventDefault();
    verifyPremium(access);
  });
}
/**
 * Show alert for develop license mode.
 */


function showDevelopAlert() {
  showPremiumError(wp.i18n.__('Using plugin with a development license is prohibited in production.', 'sharing-image'));
}
/**
 * Show revoke Premium button.
 *
 * @param {HTMLElement} access Access HTML element.
 */


function showRevokeButton(access) {
  const revoke = builders.element('div', {
    classes: ['sharing-image-premium-revoke'],
    append: access
  });
  const description = [];
  description.push(wp.i18n.__('Disabling premium mode will not remove the license for this domain.', 'sharing-image'));
  description.push(wp.i18n.__('Your current key will also be saved in the plugin settings.', 'sharing-image'));
  description.push(wp.i18n.__('Use key management tool to delete the license for the site.', 'sharing-image'));
  builders.element('p', {
    text: description.join(' '),
    append: revoke
  });
  builders.element('button', {
    classes: ['button'],
    text: wp.i18n.__('Disable Premium'),
    attributes: {
      type: 'submit'
    },
    append: revoke
  });
  builders.element('span', {
    classes: ['spinner'],
    append: revoke
  });
  access.addEventListener('submit', e => {
    e.preventDefault();
    revokePremium(access);
  });
}
/**
 * Show permit information.
 *
 * @param {HTMLElement} access Access HTML element.
 * @param {string}      key    License key from settings.
 */


function showLicenseInfo(access, key) {
  const permit = builders.element('div', {
    classes: ['sharing-image-premium-permit'],
    append: access
  });
  const button = builders.element('button', {
    classes: ['sharing-image-premium-show', 'button'],
    text: wp.i18n.__('Show License key'),
    attributes: {
      type: 'button'
    },
    append: permit
  });
  button.addEventListener('click', () => {
    permit.classList.toggle('permit-visible');
  });
  builders.element('strong', {
    text: key,
    append: permit
  });
  return permit;
}
/**
 * Show fields if user has the license.
 *
 * @param {HTMLElement} access  Access HTML element.
 * @param {Object}      license License data.
 */


function showPremiumData(access, license) {
  premium.classList.add('premium-enabled');

  if (license.develop) {
    return showDevelopAlert();
  }

  if (license.key) {
    showLicenseInfo(access, license.key);
  }

  showRevokeButton(access);
}
/**
 * Set premium fields according settings.
 */


function preparePremiumFields() {
  let access = premium.querySelector('.sharing-image-premium-access');

  if (null !== access) {
    premium.removeChild(access);
  }

  access = builders.element('form', {
    classes: ['sharing-image-premium-access'],
    attributes: {
      action: '',
      method: 'POST'
    },
    append: premium
  });
  premium.classList.remove('premium-enabled');
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: 'sharing_image_nonce',
      value: premium_params.nonce
    },
    append: access
  });
  const license = premium_params.license || {}; // Show fields if user has the license.

  if (license.premium || license.develop) {
    return showPremiumData(access, license);
  }

  return showVerifyForm(access, license);
}
/**
 * Create templates catalog from options.
 *
 * @param {HTMLElement} content  Settings content element.
 * @param {Object}      settings Global settings field.
 */


function createPremium(content, settings) {
  premium_params = settings; // Find premium element

  premium = content.querySelector('.sharing-image-premium');

  if (null === premium) {
    return;
  }

  builders.element('div', {
    classes: ['sharing-image-premium-warning'],
    append: premium
  });
  preparePremiumFields();
}

/* harmony default export */ const sections_premium = (createPremium);
;// CONCATENATED MODULE: ./src/scripts/sections/picker.js
/**
 * Metabox handler.
 */

/* global ajaxurl:true */
 // Store global script object for metabox.

let picker_params = null; // Poster HTML element.

let poster = null; // Is gutenberg editor used.

let gutenberg = false;
/**
 * Show picker warning message.
 *
 * @param {string} message Warning message.
 */

function showPickerError(message) {
  const picker = poster.parentNode; // Try to find warning element.

  const warning = picker.querySelector('.sharing-image-picker-warning');

  if (null === warning) {
    return;
  }

  warning.classList.add('warning-visible');
  warning.textContent = message || wp.i18n.__('Unknown generation error', 'sharing-image');
}
/**
 * Remove warning message block.
 */


function hidePickerError() {
  const picker = poster.parentNode; // Try to find warning element.

  const warning = picker.querySelector('.sharing-image-picker-warning');

  if (null === warning) {
    return;
  }

  warning.classList.remove('warning-visible');
}
/**
 * Handle poster generation action.
 *
 * @param {HTMLElement} picker Picker element.
 */


function generatePoster(picker) {
  const request = new XMLHttpRequest();
  request.open('POST', ajaxurl);
  request.responseType = 'json';
  poster.classList.add('poster-loader'); // Create data form data bundle.

  const bundle = new window.FormData();
  bundle.set('action', 'sharing_image_generate');
  picker.querySelectorAll('[name]').forEach(field => {
    bundle.append(field.name, field.value);
  });
  hidePickerError();
  request.addEventListener('load', () => {
    const response = request.response || {}; // Hide preview loader on request complete.

    poster.classList.remove('poster-loader');

    if (!response.data) {
      return showPickerError();
    }

    if (!response.success) {
      return showPickerError(response.data);
    }

    for (const key in response.data) {
      // Find all poster input fields and set response data value.
      poster.querySelectorAll('input').forEach(input => {
        const name = picker_params.name + '[' + key + ']';

        if (name === input.name) {
          input.value = response.data[key];
        }
      });
    }

    let image = poster.querySelector('img');

    if (null === image) {
      image = builders.element('img', {
        append: poster
      });
    }

    image.src = response.data.poster; // Show the poster.

    poster.classList.add('poster-visible');
  });
  request.addEventListener('error', () => {
    showPickerError(); // Hide preview loader on request complete.

    poster.classList.remove('poster-loader');
  });
  request.send(bundle);
}
/**
 * Create designer template selector.
 *
 * @param {HTMLElement} picker   Picker element.
 * @param {HTMLElement} designer Designer element.
 * @param {Object}      selected Seleted template.
 */


function createTemplate(picker, designer, selected) {
  const fields = {};
  picker_params.templates.forEach((template, i) => {
    fields[i] = template.title || wp.i18n.__('Untitled', 'sharing-image');
  });
  const template = builders.select({
    classes: ['sharing-image-picker-template'],
    options: fields,
    attributes: {
      name: picker_params.name + '[template]'
    },
    selected: String(selected)
  }, picker);
  template.addEventListener('change', () => {
    const fieldset = designer.childNodes;

    for (let i = 0; i < fieldset.length; i++) {
      fieldset[i].classList.remove('fieldset-visible');

      if (i === parseInt(template.value)) {
        fieldset[i].classList.add('fieldset-visible');
      }
    }
  });
  return template;
}
/**
 * Prefill caption fields for classic editor.
 *
 * @param {HTMLElement} textarea Caption textarea field.
 * @param {string}      preset   Preset field.
 */


function fillClassicEditorPreset(textarea, preset) {
  const source = document.getElementById(preset);

  if (null === source) {
    return;
  }

  const updateCaption = () => {
    textarea.value = source.value;
  };

  source.addEventListener('change', updateCaption); // Stop textarea update after first user input.

  textarea.addEventListener('change', () => {
    source.removeEventListener('change', updateCaption);
  });
  updateCaption();
}
/**
 * Prefill caption fields for block editor.
 *
 * @param {HTMLElement} textarea Caption textarea field.
 * @param {string}      preset   Preset field.
 */


function fillBlockEditorPreset(textarea, preset) {
  const getAttribute = () => {
    return wp.data.select('core/editor').getEditedPostAttribute(preset);
  };

  let attribute = getAttribute();
  wp.data.subscribe(() => {
    const updated = getAttribute();

    if (attribute !== updated) {
      textarea.textContent = updated;
    }

    attribute = updated;
  });
}
/**
 * Try to prefill caption field.
 *
 * @param {HTMLElement} textarea Caption textarea field.
 * @param {string}      preset   Preset field.
 */


function fillCaptionPreset(textarea, preset) {
  if (gutenberg) {
    return fillBlockEditorPreset(textarea, preset);
  }

  fillClassicEditorPreset(textarea, preset);
}
/**
 * Create designer attachment field for dynamic background.
 *
 * @param {HTMLElement} fieldset Fieldset element.
 * @param {Object}      template Template data.
 * @param {Array}       values   Template fieldset values.
 * @param {string}      name     Field name attribute.
 */


function createDesignerAttachment(fieldset, template, values, name) {
  if ('dynamic' !== template.background) {
    return;
  }

  builders.media({
    name: name + '[attachment]',
    classes: ['sharing-image-picker-media'],
    value: values.attachment,
    link: picker_params.links.uploads,
    labels: {
      button: wp.i18n.__('Upload background', 'sharing-image'),
      heading: wp.i18n.__('Select background image', 'sharing-image'),
      details: wp.i18n.__('Attachment', 'sharing-image')
    },
    append: fieldset
  });
}
/**
 * Create designer captions for text layers.
 *
 * @param {HTMLElement} fieldset Fieldset element.
 * @param {Object}      template Template data.
 * @param {Array}       values   Template fieldset values.
 * @param {string}      name     Field name attribute.
 */


function createDesignerCaptions(fieldset, template, values, name) {
  const captions = values.captions || []; // Set default layers list.

  template.layers = template.layers || [];
  template.layers.forEach((layer, n) => {
    if ('text' !== layer.type || !layer.dynamic) {
      return;
    }

    const textarea = builders.textarea({
      classes: ['sharing-image-picker-caption'],
      label: layer.title || null,
      attributes: {
        name: name + `[captions][${n}]`
      }
    }, fieldset);

    if (!captions[n]) {
      fillCaptionPreset(textarea, layer.preset);
    }

    textarea.textContent = captions[n];
  });
}
/**
 * Create fields designer.
 *
 * @param {HTMLElement} picker Picker element.
 * @param {Object}      data   Picker data object.
 */


function picker_createDesigner(picker, data) {
  const designer = builders.element('div', {
    classes: ['sharing-image-picker-designer']
  });
  let selected = data.template || 0; // Reset selected template if index undefined.

  if (!picker_params.templates[selected]) {
    selected = 0;
  } // Create designer fields


  picker_params.templates.forEach((template, i) => {
    // Set default layers list.
    template.layers = template.layers || [];
    const fieldset = builders.element('div', {
      classes: ['sharing-image-picker-fieldset'],
      append: designer
    });

    if (i === parseInt(selected)) {
      fieldset.classList.add('fieldset-visible');
    }

    let values = {};

    if (data.fieldset && data.fieldset[i]) {
      values = data.fieldset[i];
    }

    const name = picker_params.name + `[fieldset][${i}]`;
    builders.element('input', {
      attributes: {
        type: 'hidden',
        name: name
      },
      append: fieldset
    }); // Create attachment field.

    createDesignerAttachment(fieldset, template, values, name); // Create all caption fields.

    createDesignerCaptions(fieldset, template, values, name);
  }); // Create template selector.

  if (picker_params.templates.length > 1) {
    createTemplate(picker, designer, selected);
  }

  picker.appendChild(designer);
}
/**
 * Create button to generate new metabox poster.
 *
 * @param {HTMLElement} picker  Picker element.
 * @param {HTMLElement} manager Manager element.
 */


function picker_createGenerateButton(picker, manager) {
  const button = builders.element('button', {
    classes: ['sharing-image-picker-generate', 'button'],
    text: wp.i18n.__('Generate', 'sharing-image'),
    attributes: {
      type: 'button'
    },
    append: manager
  });
  button.addEventListener('click', () => {
    generatePoster(picker);
  });
}
/**
 * Create button to delete current metabox poster.
 *
 * @param {HTMLElement} manager Manager element.
 */


function picker_createDeleteButton(manager) {
  const button = builders.element('button', {
    classes: ['sharing-image-picker-delete', 'button', 'button-delete'],
    text: wp.i18n.__('Remove', 'sharing-image'),
    attributes: {
      type: 'button'
    },
    append: manager
  });
  button.addEventListener('click', () => {
    const image = poster.querySelector('img');

    if (null !== image) {
      poster.removeChild(image);
    }

    poster.querySelectorAll('input').forEach(input => {
      input.value = '';
    });
    poster.classList.remove('poster-visible');
  });
}
/**
 * Create picker manager.
 *
 * @param {HTMLElement} picker Picker element.
 */


function createManager(picker) {
  const manager = builders.element('div', {
    classes: ['sharing-image-picker-manager'],
    append: picker
  }); // Create poster generation button.

  picker_createGenerateButton(picker, manager); // Create poster removing button.

  picker_createDeleteButton(manager);
  builders.element('span', {
    classes: ['sharing-image-picker-spinner', 'spinner'],
    append: manager
  });
}
/**
 * Create poster block.
 *
 * @param {HTMLElement} picker Picker element.
 * @param {Object}      data   Picker data object.
 */


function createPoster(picker, data) {
  poster = builders.element('div', {
    classes: ['sharing-image-picker-poster'],
    append: picker
  });

  if (data.poster) {
    builders.element('img', {
      attributes: {
        src: data.poster,
        alt: ''
      },
      append: poster
    });
    poster.classList.add('poster-visible');
  }

  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: picker_params.name + '[poster]',
      value: data.poster
    },
    append: poster
  });
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: picker_params.name + '[width]',
      value: data.width
    },
    append: poster
  });
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: picker_params.name + '[height]',
      value: data.height
    },
    append: poster
  });
  return poster;
}
/**
 * Check that the poster sizes are set or show an error message.
 *
 * @param {Object} data Picker data object.
 */


function showSizesWarning(data) {
  if (!data.poster) {
    return;
  }

  if (!data.width || !data.height) {
    showPickerError(wp.i18n.__('Image sizes are not set. Regenerate the poster.', 'sharing-image'));
  }
}
/**
 * Get new config with AJAX call and reinit metabox.
 *
 * @param {HTMLElement} widget Widget element.
 */


const rebuildPicker = widget => {
  const request = new XMLHttpRequest();
  request.open('POST', ajaxurl);
  request.responseType = 'json';
  poster.classList.add('poster-loader'); // We need post ID for this request.

  const postId = wp.data.select('core/editor').getCurrentPostId(); // Create data form data bundle.

  const bundle = new window.FormData();
  bundle.set('action', 'sharing_image_rebuild');
  bundle.set('post', postId); // Find picker child.

  const picker = widget.querySelector('.sharing-image-picker');
  picker.querySelectorAll('[name]').forEach(field => {
    if ('sharing_image_nonce' === field.name) {
      bundle.append(field.name, field.value);
    }
  });
  hidePickerError();
  request.addEventListener('load', () => {
    const response = request.response || {}; // Hide preview loader on request complete.

    poster.classList.remove('poster-loader');

    if (!response.data) {
      return showPickerError();
    }

    if (!response.success) {
      return showPickerError(response.data);
    }

    buildPicker(widget, response.data);
  });
  request.addEventListener('error', () => {
    showPickerError(); // Hide preview loader on request complete.

    poster.classList.remove('poster-loader');
  });
  request.send(bundle);
};
/**
 * Wait Gutenberg post saving and reinit tasks list.
 *
 * @param {HTMLElement} widget Widget element.
 */


const subscribeOnSaving = widget => {
  let wasSavingPost = wp.data.select('core/edit-post').isSavingMetaBoxes();
  wp.data.subscribe(() => {
    const isSavingPost = wp.data.select('core/edit-post').isSavingMetaBoxes();

    if (wasSavingPost && !isSavingPost) {
      rebuildPicker(widget);
    }

    wasSavingPost = isSavingPost;
  });
};
/**
 * Build metabox fields.
 *
 * @param {HTMLElement} widget   Widget element.
 * @param {Object}      settings Global settings object.
 */


function buildPicker(widget, settings) {
  picker_params = settings; // Set params name for template form fields.

  picker_params.name = 'sharing_image_picker';

  while (widget.firstChild) {
    widget.removeChild(widget.lastChild);
  }

  if ('term' === picker_params.context) {
    const title = builders.element('div', {
      classes: ['sharing-image-title'],
      append: widget
    });
    builders.element('strong', {
      text: wp.i18n.__('Sharing Image', 'sharing-image'),
      append: title
    });
  }

  const picker = builders.element('div', {
    classes: ['sharing-image-picker'],
    append: widget
  });
  const data = picker_params.meta || {}; // Create poster block.

  createPoster(picker, data); // Create fields designer.

  picker_createDesigner(picker, data);
  builders.element('div', {
    classes: ['sharing-image-picker-warning'],
    append: picker
  }); // Show unset poster sizes warning.

  showSizesWarning(data); // Create metabox manager block.

  createManager(picker);
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: 'sharing_image_nonce',
      value: picker_params.nonce
    },
    append: picker
  });
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: 'sharing_image_screen',
      value: picker_params.screen
    },
    append: picker
  });
  builders.element('input', {
    attributes: {
      type: 'hidden',
      name: 'sharing_image_context',
      value: picker_params.context
    },
    append: picker
  });
}
/**
 * Create metabox generator picker and subscribe to events.
 *
 * @param {HTMLElement} widget   Widget element.
 * @param {Object}      settings Global settings object.
 */


function createPicker(widget, settings) {
  if (wp.data && wp.data.select('core/editor')) {
    gutenberg = true;
  }

  buildPicker(widget, settings);

  if (gutenberg) {
    subscribeOnSaving(widget);
  }
}

/* harmony default export */ const picker = (createPicker);
;// CONCATENATED MODULE: ./src/scripts/sections/index.js





const Section = {
  catalog: catalog,
  editor: sections_editor,
  config: config,
  premium: sections_premium,
  picker: picker
};
/* harmony default export */ const sections = (Section);
;// CONCATENATED MODULE: ./src/scripts/settings.js


/**
 * Init premium settings tab.
 *
 * @param {HTMLElement} content  Settings content element.
 * @param {Object}      settings Global settings object.
 */

function initPremiumTab(content, settings) {
  sections.premium(content, settings);
}
/**
 * Init config settings tab.
 *
 * @param {HTMLElement} content  Settings content element.
 * @param {Object}      settings Global settings object.
 */


function initConfigTab(content, settings) {
  sections.config(content, settings);
}
/**
 * Init config settings tab.
 *
 * @param {HTMLElement} content  Settings content element.
 * @param {Object}      settings Global settings object.
 */


function initTemplatesTab(content, settings) {
  // Get index from URL search parameter.
  let index = null; // Set default templates empty list.

  settings.templates = settings.templates || [];

  if (helpers.param('template')) {
    index = parseInt(helpers.param('template')) - 1;
  }

  const data = settings.templates[index]; // Create editor for existing template.

  if (undefined !== data) {
    return sections.editor(content, settings, index, data);
  } // Create editor for new template.


  if (settings.templates.length === index) {
    return sections.editor(content, settings, index);
  }

  sections.catalog(content, settings);
}
/**
 * Init settings page handler.
 */


(function () {
  if (typeof 'undefined' === wp) {
    return;
  }

  let object = window.sharingImageSettings || {}; // Add default required values to object.

  object = helpers.defaults(object, ['links', 'fonts', 'config', 'templates', 'license']); // Find settings content element.

  const content = document.querySelector('#sharing-image-settings .sharing-image-content');

  if (null === content) {
    return;
  }

  content.classList.add('content-visible');

  switch (helpers.param('tab')) {
    case 'config':
      initConfigTab(content, object);
      break;

    case 'premium':
      initPremiumTab(content, object);
      break;

    default:
      initTemplatesTab(content, object);
  }
})();
/******/ })()
;
```
