{"version":3,"file":"index.mjs","sources":["../src/ElFinderPicker.ts","../src/helpers.ts"],"sourcesContent":["'use strict';\n\nimport './styles.css';\nimport type {\n  ElFinderPickerConfig,\n  ElFinderFile,\n  FilePickerCallback,\n  PickerMessage,\n  NavigateToFileMessage\n} from './types';\n\nclass ElFinderPicker {\n  private settings: { url: string; title: string };\n  private callback: FilePickerCallback | null;\n  private popup: HTMLElement | null;\n  private iframe: HTMLIFrameElement | null;\n  private _messageHandler: (event: MessageEvent<PickerMessage>) => void;\n\n  constructor(config: ElFinderPickerConfig = {}) {\n    this.settings = {\n      url: config.url || '',\n      title: config.title || 'File Manager',\n    };\n    this.callback = null;\n    this.popup = null;\n    this.iframe = null;\n    this._messageHandler = this._handleMessage.bind(this);\n  }\n\n  /**\n   * Handle postMessage from iframe\n   * @private\n   */\n  private _handleMessage(event: MessageEvent<PickerMessage>): void {\n    // Security check - verify message is from our iframe\n    if (!this.iframe || event.source !== this.iframe.contentWindow) return;\n\n    // Check if this is an elFinder file selection\n    if (event.data && event.data.action === 'FILE_SELECTED' && 'file' in event.data) {\n      this.onSelect(event.data.file);\n    }\n  }\n\n  /**\n   * Open the file picker\n   * @param cb - Callback function that receives file object\n   * @param v - Optional initial file path to navigate to\n   * @returns The popup element\n   */\n  open(cb: FilePickerCallback, v?: string): HTMLElement | null {\n    this.callback = cb;\n\n    if (this.popup) {\n      this.show();\n      // Send navigation message if value provided\n      if (v && this.iframe) {\n        this._sendNavigationMessage(v);\n      }\n    } else {\n      this.createPopup();\n      window.addEventListener('message', this._messageHandler);\n\n      // Send navigation message after iframe loads\n      if (v && this.iframe) {\n        this.iframe.addEventListener('load', () => {\n          // Small delay to ensure elFinder is initialized\n          setTimeout(() => this._sendNavigationMessage(v), 500);\n        }, { once: true });\n      }\n    }\n\n    return this.popup;\n  }\n\n  /**\n   * Send navigation message to iframe\n   * @private\n   */\n  private _sendNavigationMessage(path: string): void {\n    if (this.iframe && this.iframe.contentWindow) {\n      const message: NavigateToFileMessage = {\n        action: 'NAVIGATE_TO_FILE',\n        path: path\n      };\n      this.iframe.contentWindow.postMessage(message, '*');\n    }\n  }\n\n  /**\n   * Create the popup DOM structure\n   * @private\n   */\n  private createPopup(): void {\n    const popupHTML = `\n      <div class='elfinder-picker'>\n        <div class='elfinder-picker-backdrop'></div>\n        <div class='elfinder-picker-content'>\n          <h3 class='elfinder-picker-title'>${this.settings.title}</h3>\n          <div class='elfinder-picker-close'>&times;</div>\n          <iframe class='elfinder-picker-iframe' src='${this.settings.url}' allowfullscreen data-mode='select'></iframe>\n        </div>\n      </div>\n    `;\n\n    const tempDiv = document.createElement('div');\n    tempDiv.innerHTML = popupHTML.trim();\n    this.popup = tempDiv.firstChild as HTMLElement;\n\n    document.body.appendChild(this.popup);\n\n    // Store reference to iframe for postMessage communication\n    this.iframe = this.popup.querySelector('.elfinder-picker-iframe');\n\n    // Add event listeners\n    const closeBtn = this.popup.querySelector('.elfinder-picker-close');\n    const backdrop = this.popup.querySelector('.elfinder-picker-backdrop');\n\n    closeBtn?.addEventListener('click', () => this.close());\n    backdrop?.addEventListener('click', () => this.close());\n  }\n\n  /**\n   * Show the popup\n   * @private\n   */\n  private show(): void {\n    if (this.popup) {\n      this.popup.style.display = 'block';\n    }\n  }\n\n  /**\n   * Handle file selection from elFinder\n   * @param file - Raw file object from elFinder\n   */\n  private onSelect(file: ElFinderFile): void {\n    // URL normalization\n    let url = file.url;\n    const reg = /\\/[^/]+?\\/\\.\\.\\//;\n    while (url.match(reg)) {\n      url = url.replace(reg, '/');\n    }\n\n    // Remove double slashes (but preserve protocol://)\n    url = url.replace(/([^:]\\/)\\/+/g, '$1');\n\n    // Create normalized file object with clean data\n    const normalizedFile: ElFinderFile = {\n      url: url,\n      name: file.name,\n      mime: file.mime || 'application/octet-stream'\n    };\n\n    // Return raw file data - let the user decide how to handle it\n    if (this.callback) {\n      this.callback(normalizedFile);\n    }\n\n    this.close();\n  }\n\n  /**\n   * Close the popup\n   */\n  close(): void {\n    if (this.popup) {\n      this.popup.style.display = 'none';\n    }\n  }\n\n  /**\n   * Destroy the popup and clean up\n   */\n  destroy(): void {\n    // Remove message listener\n    window.removeEventListener('message', this._messageHandler);\n\n    if (this.popup && this.popup.parentNode) {\n      this.popup.parentNode.removeChild(this.popup);\n      this.popup = null;\n    }\n    this.iframe = null;\n    this.callback = null;\n  }\n}\n\nexport default ElFinderPicker;\n","'use strict';\n\nimport type {\n  ElFinderFile,\n  ElFinderInstance,\n  FilePickerCallbackOptions,\n  FileSelectedMessage,\n  NavigateToFileMessage\n} from './types';\n\n/**\n * Helper function for elFinder's getFileCallback\n * Use this directly in your elFinder configuration\n * Also sets up listener for navigation messages from parent\n *\n * @example\n * // In your elFinder page:\n * import { filePickerCallback } from 'elfinder-picker';\n *\n * $('#elfinder').elfinder({\n *   url: '/connector.php',\n *   getFileCallback: filePickerCallback\n * });\n */\nexport function filePickerCallback(\n  file: ElFinderFile,\n  fm?: ElFinderInstance,\n  options: FilePickerCallbackOptions = {}\n): void {\n  // Check if we're in an iframe (select mode)\n  if (!window.parent || window.parent === window) {\n    return; // Not in iframe, do nothing\n  }\n\n  const origin = options.origin || '*';\n\n  // Set up listener for navigation messages from parent (only once)\n  if (!(window as any)._isListenining) {\n    (window as any)._isListenining = true;\n    window.addEventListener('message', (event: MessageEvent<NavigateToFileMessage>) => {\n      // Handle NAVIGATE_TO_FILE message\n      if (event.data && event.data.action === 'NAVIGATE_TO_FILE' && event.data.path) {\n        if (fm && typeof fm.exec === 'function') {\n          // Use elFinder's exec method to open the file\n          fm.exec('open', event.data.path);\n        }\n      }\n    });\n  }\n\n  // Send file data to parent window\n  const message: FileSelectedMessage = {\n    action: 'FILE_SELECTED',\n    file: {\n      url: file.url,\n      name: file.name,\n      mime: file.mime || 'application/octet-stream'\n    }\n  };\n  window.parent.postMessage(message, origin);\n}\n\n/**\n * Create a configured file picker callback with custom options\n *\n * @param options - Configuration options\n * @returns Configured callback function\n * @example\n * import { createFilePickerCallback } from 'elfinder-picker';\n *\n * const callback = createFilePickerCallback({\n *   origin: 'https://yourdomain.com'\n * });\n *\n * $('#elfinder').elfinder({\n *   url: '/connector.php',\n *   getFileCallback: callback\n * });\n */\nexport function createFilePickerCallback(\n  options: FilePickerCallbackOptions = {}\n): (file: ElFinderFile, fm?: ElFinderInstance) => void {\n  return function(file: ElFinderFile, fm?: ElFinderInstance) {\n    filePickerCallback(file, fm, options);\n  };\n}\n"],"names":["ElFinderPicker","config","event","cb","v","path","message","popupHTML","tempDiv","closeBtn","backdrop","file","url","reg","normalizedFile","filePickerCallback","fm","options","origin","createFilePickerCallback"],"mappings":"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"}