{"version":3,"file":"126.mass-edit.js","mappings":"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","sources":["webpack://multi-token-edit/./multi-token-edit/scripts/presets/browser/savedSearches.js"],"sourcesContent":["import { MODULE_ID } from '../../constants.js';\r\nimport { PresetBrowser } from './browserApp.js';\r\n\r\nconst { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;\r\n\r\n/**\r\n * Application to handle Preset Browser search state saving and loading.\r\n */\r\nexport default class SavedSearches extends HandlebarsApplicationMixin(ApplicationV2) {\r\n  constructor(browserApp) {\r\n    const parentPosition = browserApp.position;\r\n    super({\r\n      position: {\r\n        left: parentPosition.left + parentPosition.width + 5,\r\n        top: parentPosition.top,\r\n      },\r\n    });\r\n    this._browserApp = browserApp;\r\n    this._saveSettings = {\r\n      label: '',\r\n      color: '',\r\n    };\r\n  }\r\n\r\n  /** @override */\r\n  static DEFAULT_OPTIONS = {\r\n    id: 'mass-edit-presets-saved-searches',\r\n    tag: 'form',\r\n    form: {\r\n      handler: SavedSearches._onSubmit,\r\n      submitOnChange: true,\r\n      closeOnSubmit: false,\r\n    },\r\n    window: {\r\n      contentClasses: ['standard-form'],\r\n      title: 'Saved Searches',\r\n      resizable: true,\r\n      icon: 'fa-solid fa-bookmark',\r\n    },\r\n    position: {\r\n      width: 325,\r\n      height: 500,\r\n    },\r\n    actions: {\r\n      save: SavedSearches._onSaveSearch,\r\n      toggle: SavedSearches._onToggleSearch,\r\n      remove: SavedSearches._onRemove,\r\n    },\r\n  };\r\n\r\n  /** @override */\r\n  static PARTS = {\r\n    main: { template: `modules/${MODULE_ID}/templates/preset/saved-searches.hbs` },\r\n  };\r\n\r\n  /**\r\n   * Called by preset browser in response to search input change\r\n   * @param {string} query\r\n   */\r\n  updateQuery(query) {\r\n    this.element.querySelector('.search').value = query;\r\n  }\r\n\r\n  /** @override */\r\n  async _prepareContext(options) {\r\n    const searches = foundry.utils.deepClone(PresetBrowser.CONFIG.savedSearches).map((search) => {\r\n      return {\r\n        ...search,\r\n        textColor: this._getContrastColor(search.color),\r\n      };\r\n    });\r\n\r\n    return { searches, search: { ...this._saveSettings, query: this._browserApp.lastSearch } };\r\n  }\r\n\r\n  /**\r\n   * Determine most contrasting text font color on the provided background color\r\n   * @param {string} bgColor\r\n   * @returns {string} 'white' | 'black'\r\n   */\r\n  _getContrastColor(bgColor) {\r\n    if (!bgColor?.trim()) return 'white';\r\n\r\n    const srgb = Color.fromString(bgColor).linear.rgb; // Linear RGB\r\n    const L = 0.2126 * srgb[0] + 0.7152 * srgb[1] + 0.0722 * srgb[2]; // Relative luminance\r\n    return L > 0.179 ? 'black' : 'white'; // WCAG-recommended threshold\r\n  }\r\n\r\n  /**\r\n   * Handle request to save the current Preset Browser search state\r\n   * @param {*} event\r\n   * @returns\r\n   */\r\n  static async _onSaveSearch(event) {\r\n    const formData = new foundry.applications.ux.FormDataExtended(this.form);\r\n    const search = formData.object;\r\n\r\n    ['color', 'label', 'query'].forEach((field) => (search[field] = search[field].trim()));\r\n    if (!search.query) {\r\n      ui.notifications.warn('Search field cannot be empty.');\r\n      return;\r\n    }\r\n\r\n    if (!search.label) search.label = search.query;\r\n    if (!search.color) search.color = '#000000';\r\n\r\n    const savedSearches = PresetBrowser.CONFIG.savedSearches;\r\n\r\n    if (savedSearches.find((s) => s.label === search.label)) {\r\n      ui.notifications.warn('Search with this label/query already exists.');\r\n      return;\r\n    }\r\n\r\n    // Copy other browser settings relevant to the search\r\n    ['switchLayer', 'autoScale', 'externalCompendiums', 'virtualDirectory'].forEach((setting) => {\r\n      search[setting] = PresetBrowser.CONFIG[setting];\r\n    });\r\n    search.documentName = this._browserApp.documentName;\r\n\r\n    savedSearches.push(search);\r\n    await PresetBrowser.setSetting('savedSearches', savedSearches);\r\n\r\n    this._saveSettings = search;\r\n    this.render(true);\r\n  }\r\n\r\n  /**\r\n   * Handle a click of a saved search\r\n   * @param {Event} event\r\n   * @param {HTMLElement} element\r\n   */\r\n  static _onToggleSearch(event, element) {\r\n    const search = PresetBrowser.CONFIG.savedSearches[Number(element.closest('.search').dataset.index)];\r\n    this._saveSettings = search;\r\n    this.render(true);\r\n    this._browserApp.loadSavedSearch(search);\r\n  }\r\n\r\n  /**\r\n   * Handle removal of a saved search\r\n   * @param {Event} event\r\n   * @param {HTMLElement} element\r\n   */\r\n  static async _onRemove(event, element) {\r\n    const index = Number(element.closest('.search').dataset.index);\r\n    const savedSearches = PresetBrowser.CONFIG.savedSearches;\r\n    savedSearches.splice(index, 1);\r\n    await PresetBrowser.setSetting('savedSearches', savedSearches);\r\n    this.render(true);\r\n  }\r\n\r\n  /** @override */\r\n  static _onSubmit(event, form, formData) {\r\n    this._saveSettings = formData.object;\r\n  }\r\n\r\n  /** @override */\r\n  _attachFrameListeners() {\r\n    super._attachFrameListeners();\r\n\r\n    // Listeners to handle saved search drag/drop to change their order\r\n    const html = $(this.element);\r\n    html.on('dragstart', '.search', (event) => {\r\n      event.originalEvent.dataTransfer.clearData();\r\n      event.originalEvent.dataTransfer.setData('text/plain', `${event.currentTarget.closest('.search').dataset.index}`);\r\n    });\r\n    html.on('drop', '.search', (event) => {\r\n      const fromIndex = foundry.applications.ux.TextEditor.implementation.getDragEventData(event.originalEvent);\r\n      if (!Number.isInteger(fromIndex)) return;\r\n      this._onSort(fromIndex, Number(event.currentTarget.closest('.search').dataset.index));\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Change order of a saved search at index 'fromIndex'\r\n   * @param {Number} fromIndex saved search index to move\r\n   * @param {Number} toIndex index to move to\r\n   */\r\n  async _onSort(fromIndex, toIndex) {\r\n    if (fromIndex === toIndex) return;\r\n    const savedSearches = PresetBrowser.CONFIG.savedSearches;\r\n    if (toIndex === savedSearches.length - 1) toIndex++;\r\n    savedSearches.splice(toIndex, 0, savedSearches[fromIndex]);\r\n    savedSearches.splice(fromIndex + (toIndex < fromIndex ? 1 : 0), 1);\r\n    await PresetBrowser.setSetting('savedSearches', savedSearches);\r\n    this.render(true);\r\n  }\r\n\r\n  async close(options = {}) {\r\n    this._browserApp._savedSearches = null;\r\n    return super.close(options);\r\n  }\r\n}\r\n"],"names":["HandlebarsApplicationMixin","ApplicationV2","foundry","applications","api","SavedSearches","constructor","browserApp","parentPosition","position","super","left","width","top","this","_browserApp","_saveSettings","label","color","static","id","tag","form","handler","_onSubmit","submitOnChange","closeOnSubmit","window","contentClasses","title","resizable","icon","height","actions","save","_onSaveSearch","toggle","_onToggleSearch","remove","_onRemove","main","template","updateQuery","query","element","querySelector","value","_prepareContext","options","searches","utils","deepClone","CONFIG","savedSearches","map","search","textColor","_getContrastColor","lastSearch","bgColor","trim","srgb","Color","fromString","linear","rgb","event","ux","FormDataExtended","object","forEach","field","ui","notifications","warn","find","s","setting","documentName","push","setSetting","render","Number","closest","dataset","index","loadSavedSearch","splice","formData","_attachFrameListeners","html","$","on","originalEvent","dataTransfer","clearData","setData","currentTarget","fromIndex","TextEditor","implementation","getDragEventData","isInteger","_onSort","toIndex","length","close","_savedSearches"],"sourceRoot":""}