<commit_before>import { isUndefined, keys } from 'underscore';
import PropertyCompositeView from './PropertyCompositeView';
import LayersView from './LayersView';

export default PropertyCompositeView.extend({
  templateInput() {
    const pfx = this.pfx;
    const ppfx = this.ppfx;
    return `
      <div class="${pfx}field ${pfx}stack">
        <button type="button" id="${pfx}add" data-add-layer>+</button>
        <div data-layers-wrapper></div>
      </div>
    `;
  },

  init() {
    const model = this.model;
    const pfx = this.pfx;
    model.set('stackIndex', null);
    this.events[`click [data-add-layer]`] = 'addLayer';
    this.listenTo(model, 'change:stackIndex', this.indexChanged);
    this.listenTo(model, 'updateValue', this.inputValueChanged);
    this.delegateEvents();
  },

  /**
   * Fired when the target is updated.
   * With detached mode the component will be always empty as its value
   * so we gonna check all props and find if it has any difference
   * */
  targetUpdated(...args) {
    if (!this.model.get('detached')) {
      PropertyCompositeView.prototype.targetUpdated.apply(this, args);
    } else {
      const { status } = this._getTargetData();
      this.setStatus(status);
      this.checkVisibility();
    }

    this.refreshLayers();
  },

  /**
   * Returns the collection of layers
   * @return {Collection}
   */
  getLayers() {
    return this.model.get('layers');
  },

  /**
   * Triggered when another layer has been selected.
   * This allow to move all rendered properties to a new
   * selected layer
   * @param {Event}
   *
   * @return {Object}
   * */
  indexChanged(e) {
    const model = this.model;
    this.getLayers().active(model.get('stackIndex'));
  },

  addLayer() {
    const model = this.model;
    const layers = this.getLayers();
    const properties = model.get('properties').deepClone();
    properties.each(property => property.set('value', ''));
    const layer = layers.add({ properties });

    // In detached mode inputValueChanged will add new 'layer value'
    // to all subprops
    this.inputValueChanged();

    // This will set subprops with a new default values
    model.set('stackIndex', layers.indexOf(layer));
  },

  inputValueChanged() {
    const model = this.model;
    this.elementUpdated();

    // If not detached I'll just put all the values from layers to property
    // eg. background: layer1Value, layer2Value, layer3Value, ...
    if (!model.get('detached')) {
      model.set('value', this.getLayerValues());
    } else {
      model.get('properties').each(prop => prop.trigger('change:value'));
    }
  },

  /**
   * There is no need to handle input update by the property itself,
   * this will be done by layers
   * @private
   */
  setValue() {},

  /**
   * Create value by layers
   * @return string
   * */
  getLayerValues() {
    return this.getLayers().getFullValue();
  },

  /**
   * Refresh layers
   * */
  refreshLayers() {
    let layersObj = [];
    const { model, em } = this;
    const layers = this.getLayers();
    const detached = model.get('detached');
    const target = this.getTarget();
    let style, valueComput, targetAlt;

    // With detached layers values will be assigned to their properties
    if (detached) {
      const selected = em.getSelected();
      style = target ? target.getStyle() : 0;
      valueComput = this.getComputedValue();

      // If the style object is empty but the target has a computed value,
      // that means the style might exist in some other place
      if ((!style || !keys(style).length) && valueComput && selected) {
        // The target is a component but the style is in class rules
        targetAlt = em.get('StyleManager').getModelToStyle(selected, {
          skipAdd: 1,
          useClasses: 1
        });
        style = targetAlt !== selected ? targetAlt.getStyle() : 0;
      }

      layersObj = layers.getLayersFromStyle(style || {});
    } else {
      let value = this.getTargetValue({ ignoreDefault: 1 });

      if (!value) value = this.getComputedValue();

      value = value == model.getDefaultValue() ? '' : value;
      layersObj = layers.getLayersFromValue(value);
    }

    const toAdd = model.getLayersFromTarget(target) || layersObj;

    // const prop = this.model.get('property');
    // if (['background', 'box-shadow'].indexOf(prop) >= 0) {
    //   console.log('PROP', prop, {
    //     style,
    //     toAdd,
    //     layersObj,
    //     targetAlt,
    //     valueTrg: this.getTargetValue({ ignoreDefault: 1 }),
    //     valueComput: this.getComputedValue(),
    //   });
    // }

    layers.reset();
    layers.add(toAdd);
    model.set({ stackIndex: null }, { silent: true });
  },<commit_msg>Search alternative style target for not detached props<commit_after>import { isUndefined, keys } from 'underscore';
import PropertyCompositeView from './PropertyCompositeView';
import LayersView from './LayersView';

export default PropertyCompositeView.extend({
  templateInput() {
    const pfx = this.pfx;
    const ppfx = this.ppfx;
    return `
      <div class="${pfx}field ${pfx}stack">
        <button type="button" id="${pfx}add" data-add-layer>+</button>
        <div data-layers-wrapper></div>
      </div>
    `;
  },

  init() {
    const model = this.model;
    const pfx = this.pfx;
    model.set('stackIndex', null);
    this.events[`click [data-add-layer]`] = 'addLayer';
    this.listenTo(model, 'change:stackIndex', this.indexChanged);
    this.listenTo(model, 'updateValue', this.inputValueChanged);
    this.delegateEvents();
  },

  /**
   * Fired when the target is updated.
   * With detached mode the component will be always empty as its value
   * so we gonna check all props and find if it has any difference
   * */
  targetUpdated(...args) {
    if (!this.model.get('detached')) {
      PropertyCompositeView.prototype.targetUpdated.apply(this, args);
    } else {
      const { status } = this._getTargetData();
      this.setStatus(status);
      this.checkVisibility();
    }

    this.refreshLayers();
  },

  /**
   * Returns the collection of layers
   * @return {Collection}
   */
  getLayers() {
    return this.model.get('layers');
  },

  /**
   * Triggered when another layer has been selected.
   * This allow to move all rendered properties to a new
   * selected layer
   * @param {Event}
   *
   * @return {Object}
   * */
  indexChanged(e) {
    const model = this.model;
    this.getLayers().active(model.get('stackIndex'));
  },

  addLayer() {
    const model = this.model;
    const layers = this.getLayers();
    const properties = model.get('properties').deepClone();
    properties.each(property => property.set('value', ''));
    const layer = layers.add({ properties });

    // In detached mode inputValueChanged will add new 'layer value'
    // to all subprops
    this.inputValueChanged();

    // This will set subprops with a new default values
    model.set('stackIndex', layers.indexOf(layer));
  },

  inputValueChanged() {
    const model = this.model;
    this.elementUpdated();

    // If not detached I'll just put all the values from layers to property
    // eg. background: layer1Value, layer2Value, layer3Value, ...
    if (!model.get('detached')) {
      model.set('value', this.getLayerValues());
    } else {
      model.get('properties').each(prop => prop.trigger('change:value'));
    }
  },

  /**
   * There is no need to handle input update by the property itself,
   * this will be done by layers
   * @private
   */
  setValue() {},

  /**
   * Create value by layers
   * @return string
   * */
  getLayerValues() {
    return this.getLayers().getFullValue();
  },

  _getClassRule() {
    const { em } = this;
    const selected = em.getSelected();
    const targetAlt = em.get('StyleManager').getModelToStyle(selected, {
      skipAdd: 1,
      useClasses: 1
    });
    return targetAlt !== selected && targetAlt;
  },

  /**
   * Refresh layers
   * */
  refreshLayers() {
    let layersObj = [];
    const { model, em } = this;
    const layers = this.getLayers();
    const detached = model.get('detached');
    const property = model.get('property');
    const target = this.getTarget();
    const valueComput = this.getComputedValue();
    const selected = em.getSelected();
    let style, targetAlt;

    // With detached layers values will be assigned to their properties
    if (detached) {
      style = target ? target.getStyle() : 0;

      // If the style object is empty but the target has a computed value,
      // that means the style might exist in some other place
      if ((!style || !keys(style).length) && valueComput && selected) {
        // The target is a component but the style is in the class rules
        targetAlt = this._getClassRule();
        style = targetAlt ? targetAlt.getStyle() : 0;
      }

      layersObj = layers.getLayersFromStyle(style || {});
    } else {
      let value = this.getTargetValue({ ignoreDefault: 1 });

      if (!value && valueComput) {
        // Computed value is not always reliable due to the browser's CSSOM parser
        // so, at first, try to check the alternative target style
        targetAlt = this._getClassRule();
        value = targetAlt ? targetAlt.getStyle()[property] : valueComput;
      }

      value = value == model.getDefaultValue() ? '' : value;
      layersObj = layers.getLayersFromValue(value);
    }

    const toAdd = model.getLayersFromTarget(target) || layersObj;

    // const prop = this.model.get('property');
    // if (['background', 'box-shadow'].indexOf(prop) >= 0) {
    //   console.log('PROP', prop, {
    //     style,
    //     toAdd,
    //     layersObj,
    //     targetAlt,
    //     valueTrg: this.getTargetValue({ ignoreDefault: 1 }),
    //     valueComput: this.getComputedValue(),
    //   });
    // }

    layers.reset();
    layers.add(toAdd);
    model.set({ stackIndex: null }, { silent: true });
  },
{'fraction_non_alphanumeric': 0.13950679416205336, 'fraction_numerical': 0.0020130850528434826, 'mean_word_length': 2.707462686567164, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6950048', 'n_tokens_mistral': 2994, 'n_tokens_neox': 2907, 'n_words': 803}