<commit_before>/**
 * Selectors in GrapesJS are used in CSS Composer inside Rules and in Components as classes. To illustrate this concept let's take
 * a look at this code:
 *
 * ```css
 * span > #send-btn.btn{
 *  ...
 * }
 * ```
 * ```html
 * <span>
 *   <button id="send-btn" class="btn"></button>
 * </span>
 * ```
 *
 * In this scenario we get:
 * * span     -> selector of type `tag`
 * * send-btn -> selector of type `id`
 * * btn      -> selector of type `class`
 *
 * So, for example, being `btn` the same class entity it'll be easier to refactor and track things.
 *
 * You can customize the initial state of the module from the editor initialization, by passing the following [Configuration Object](https://github.com/artf/grapesjs/blob/master/src/selector_manager/config/config.js)
 * ```js
 * const editor = grapesjs.init({
 *  selectorManager: {
 *    // options
 *  }
 * })
 * ```
 *
 * Once the editor is instantiated you can use its API and listen to its events. Before using these methods, you should get the module from the instance.
 *
 * ```js
 * // Listen to events
 * editor.on('selector:add', (selector) => { ... });
 *
 * // Use the API
 * const sm = editor.Selectors;
 * sm.add(...);
 * ```
 *
 * ## Available Events
 * * `selector:add` - Selector added. The [Selector] is passed as an argument to the callback.
 * * `selector:remove` - Selector removed. The [Selector] is passed as an argument to the callback.
 * * `selector:update` - Selector updated. The [Selector] and the object containing changes are passed as arguments to the callback.
 * * `selector:state` - States changed. An object containing all the available data about the triggered event is passed as an argument to the callback.
 * * `selector` - Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback.
 *
 * ## Methods
 * * [getConfig](#getconfig)
 * * [add](#add)
 * * [get](#get)
 * * [remove](#remove)
 * * [getAll](#getall)
 * * [setState](#setstate)
 * * [getState](#getstate)
 * * [getStates](#getstates)
 * * [setStates](#setstates)
 * * [getSelected](#getselected)
 * * [addSelected](#addselected)
 * * [removeSelected](#removeselected)
 * * [getSelectedTargets](#getselectedtargets)
 * * [setComponentFirst](#setcomponentfirst)
 * * [getComponentFirst](#getcomponentfirst)
 *
 * [Selector]: selector.html
 * [State]: state.html
 * [Component]: component.html
 * [CssRule]: css_rule.html
 *
 * @module SelectorManager
 */

import { isString, debounce, isObject, isArray } from 'underscore';
import { isComponent, isRule } from 'utils/mixins';
import { Model, Collection } from 'common';
import Module from 'common/module';
import defaults from './config/config';
import Selector from './model/Selector';
import Selectors from './model/Selectors';
import State from './model/State';
import ClassTagsView from './view/ClassTagsView';

const isId = str => isString(str) && str[0] == '#';
const isClass = str => isString(str) && str[0] == '.';

export const evAll = 'selector';
export const evPfx = `${evAll}:`;
export const evAdd = `${evPfx}add`;
export const evUpdate = `${evPfx}update`;
export const evRemove = `${evPfx}remove`;
export const evRemoveBefore = `${evRemove}:before`;
export const evCustom = `${evPfx}custom`;
export const evState = `${evPfx}state`;

export default () => {
  return {
    ...Module,

    name: 'SelectorManager',

    Selector,

    Selectors,

    events: {
      all: evAll,
      update: evUpdate,
      add: evAdd,
      remove: evRemove,
      removeBefore: evRemoveBefore,
      state: evState,
      custom: evCustom
    },

    /**
     * Get configuration object
     * @name getConfig
     * @function
     * @return {Object}
     */

    init(conf = {}) {
      this.__initConfig(defaults, conf);
      const config = this.getConfig();
      const em = config.em;
      const ppfx = config.pStylePrefix;

      if (ppfx) {
        config.stylePrefix = ppfx + config.stylePrefix;
      }

      // Global selectors container
      this.all = new Selectors(config.selectors);
      this.selected = new Selectors([], { em, config });
      this.states = new Collection(config.states, { model: State });
      this.model = new Model({ cFirst: config.componentFirst, _undo: true });
      this.__initListen({
        collections: [this.states, this.selected],
        propagate: [{ entity: this.states, event: this.events.state }]
      });
      em.on('change:state', (m, value) => em.trigger('selector:state', value));
      this.model.on('change:cFirst', (m, value) =>
        em.trigger('selector:type', value)
      );
      const listenTo =
        'component:toggled component:update:classes styleManager:update selector:state selector:type';
      this.model.listenTo(em, listenTo, () => this.__update());

      return this;
    },

    __update: debounce(function() {
      this.__trgCustom();
    }),

    __trgCustom(opts) {
      this.em.trigger(this.events.custom, this.__customData(opts));
    },

    __customData(opts = {}) {
      const { container } = opts;
      return {
        states: this.getStates(),
        selected: this.getSelected(),
        container
      };
    },

    // postLoad() {
    //   this.__postLoad();
    //   const { em, model } = this;
    //   const um = em.get('UndoManager');
    //   um && um.add(model);<commit_msg>Trigger custom event on device change in Sector Manager<commit_after>/**
 * Selectors in GrapesJS are used in CSS Composer inside Rules and in Components as classes. To illustrate this concept let's take
 * a look at this code:
 *
 * ```css
 * span > #send-btn.btn{
 *  ...
 * }
 * ```
 * ```html
 * <span>
 *   <button id="send-btn" class="btn"></button>
 * </span>
 * ```
 *
 * In this scenario we get:
 * * span     -> selector of type `tag`
 * * send-btn -> selector of type `id`
 * * btn      -> selector of type `class`
 *
 * So, for example, being `btn` the same class entity it'll be easier to refactor and track things.
 *
 * You can customize the initial state of the module from the editor initialization, by passing the following [Configuration Object](https://github.com/artf/grapesjs/blob/master/src/selector_manager/config/config.js)
 * ```js
 * const editor = grapesjs.init({
 *  selectorManager: {
 *    // options
 *  }
 * })
 * ```
 *
 * Once the editor is instantiated you can use its API and listen to its events. Before using these methods, you should get the module from the instance.
 *
 * ```js
 * // Listen to events
 * editor.on('selector:add', (selector) => { ... });
 *
 * // Use the API
 * const sm = editor.Selectors;
 * sm.add(...);
 * ```
 *
 * ## Available Events
 * * `selector:add` - Selector added. The [Selector] is passed as an argument to the callback.
 * * `selector:remove` - Selector removed. The [Selector] is passed as an argument to the callback.
 * * `selector:update` - Selector updated. The [Selector] and the object containing changes are passed as arguments to the callback.
 * * `selector:state` - States changed. An object containing all the available data about the triggered event is passed as an argument to the callback.
 * * `selector` - Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback.
 *
 * ## Methods
 * * [getConfig](#getconfig)
 * * [add](#add)
 * * [get](#get)
 * * [remove](#remove)
 * * [getAll](#getall)
 * * [setState](#setstate)
 * * [getState](#getstate)
 * * [getStates](#getstates)
 * * [setStates](#setstates)
 * * [getSelected](#getselected)
 * * [addSelected](#addselected)
 * * [removeSelected](#removeselected)
 * * [getSelectedTargets](#getselectedtargets)
 * * [setComponentFirst](#setcomponentfirst)
 * * [getComponentFirst](#getcomponentfirst)
 *
 * [Selector]: selector.html
 * [State]: state.html
 * [Component]: component.html
 * [CssRule]: css_rule.html
 *
 * @module SelectorManager
 */

import { isString, debounce, isObject, isArray } from 'underscore';
import { isComponent, isRule } from 'utils/mixins';
import { Model, Collection } from 'common';
import Module from 'common/module';
import defaults from './config/config';
import Selector from './model/Selector';
import Selectors from './model/Selectors';
import State from './model/State';
import ClassTagsView from './view/ClassTagsView';

const isId = str => isString(str) && str[0] == '#';
const isClass = str => isString(str) && str[0] == '.';

export const evAll = 'selector';
export const evPfx = `${evAll}:`;
export const evAdd = `${evPfx}add`;
export const evUpdate = `${evPfx}update`;
export const evRemove = `${evPfx}remove`;
export const evRemoveBefore = `${evRemove}:before`;
export const evCustom = `${evPfx}custom`;
export const evState = `${evPfx}state`;

export default () => {
  return {
    ...Module,

    name: 'SelectorManager',

    Selector,

    Selectors,

    events: {
      all: evAll,
      update: evUpdate,
      add: evAdd,
      remove: evRemove,
      removeBefore: evRemoveBefore,
      state: evState,
      custom: evCustom
    },

    /**
     * Get configuration object
     * @name getConfig
     * @function
     * @return {Object}
     */

    init(conf = {}) {
      this.__initConfig(defaults, conf);
      const config = this.getConfig();
      const em = config.em;
      const ppfx = config.pStylePrefix;

      if (ppfx) {
        config.stylePrefix = ppfx + config.stylePrefix;
      }

      // Global selectors container
      this.all = new Selectors(config.selectors);
      this.selected = new Selectors([], { em, config });
      this.states = new Collection(config.states, { model: State });
      this.model = new Model({ cFirst: config.componentFirst, _undo: true });
      this.__initListen({
        collections: [this.states, this.selected],
        propagate: [{ entity: this.states, event: this.events.state }]
      });
      em.on('change:state', (m, value) => em.trigger('selector:state', value));
      this.model.on('change:cFirst', (m, value) =>
        em.trigger('selector:type', value)
      );
      const listenTo =
        'component:toggled component:update:classes change:device styleManager:update selector:state selector:type';
      this.model.listenTo(em, listenTo, () => this.__update());

      return this;
    },

    __update: debounce(function() {
      this.__trgCustom();
    }),

    __trgCustom(opts) {
      this.em.trigger(this.events.custom, this.__customData(opts));
    },

    __customData(opts = {}) {
      const { container } = opts;
      return {
        states: this.getStates(),
        selected: this.getSelected(),
        container
      };
    },

    // postLoad() {
    //   this.__postLoad();
    //   const { em, model } = this;
    //   const um = em.get('UndoManager');
    //   um && um.add(model);
{'fraction_non_alphanumeric': 0.1485394084144773, 'fraction_numerical': 0.00036744442403086535, 'mean_word_length': 3.1905311778290995, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 33, 'https://': 2, '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': '2620495', 'n_tokens_mistral': 3275, 'n_tokens_neox': 3239, 'n_words': 950}