/*
 * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
 * This devtool is neither made for production nor for readable output files.
 * It uses "eval()" calls to create a separate source file in the browser devtools.
 * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
 * or disable the default devtool with "devtool: false".
 * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
 */
/******/ (() => { // webpackBootstrap
/******/ 	var __webpack_modules__ = ({

/***/ "./dev/admin/modules/media-replace/media-replace.js":
/*!**********************************************************!*\
  !*** ./dev/admin/modules/media-replace/media-replace.js ***!
  \**********************************************************/
/***/ (() => {

eval("jQuery(document).ready(function ($) {\n  'use strict';\n\n  var l10n = typeof window.jltwp_adminify_ajax !== 'undefined' ? window.jltwp_adminify_ajax : {};\n  function showMessage($el, type, msg) {\n    if (!$el || !$el.length) {\n      return;\n    }\n    $el.stop(true, true).removeClass('is-info is-success is-error is-warning').addClass('is-' + type).html('<span class=\"jltwp-adminify-replace-message-text\">' + escapeHtml(msg) + '</span>').removeAttr('hidden').show();\n  }\n  function clearMessage($el) {\n    if ($el && $el.length) {\n      $el.attr('hidden', true).empty();\n    }\n  }\n  function escapeHtml(str) {\n    return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/'/g, '&#039;');\n  }\n  function formatBytes(bytes) {\n    if (!bytes && bytes !== 0) return '';\n    var units = ['B', 'KB', 'MB', 'GB'];\n    var i = 0;\n    var n = bytes;\n    while (n >= 1024 && i < units.length - 1) {\n      n /= 1024;\n      i++;\n    }\n    return (i === 0 ? n : n.toFixed(1)) + ' ' + units[i];\n  }\n  function validatePicked($wrap, file) {\n    var oldMime = String($wrap.attr('data-mime-type') || '');\n    var oldExt = String($wrap.attr('data-file-ext') || '').toLowerCase();\n    var $message = $wrap.find('.jltwp-adminify-replace-message');\n    if (oldMime && file.type && file.type !== oldMime) {\n      showMessage($message, 'error', 'File must be of the same type (' + oldMime + ').');\n      return false;\n    }\n    if (oldExt) {\n      var pickedExt = '';\n      if (file.name && file.name.lastIndexOf('.') !== -1) {\n        pickedExt = file.name.slice(file.name.lastIndexOf('.') + 1).toLowerCase();\n      }\n      var jpegPair = (oldExt === 'jpg' || oldExt === 'jpeg') && (pickedExt === 'jpg' || pickedExt === 'jpeg');\n      if (!jpegPair && pickedExt !== oldExt) {\n        showMessage($message, 'error', 'File extension must be .' + oldExt + ' (got .' + (pickedExt || 'unknown') + ').');\n        return false;\n      }\n    }\n    clearMessage($message);\n    return true;\n  }\n  function showConfirmation($wrap, file) {\n    var $confirm = $wrap.find('.jltwp-adminify-replace-confirm');\n    var $preview = $confirm.find('.jltwp-adminify-replace-confirm-preview');\n    var $img = $confirm.find('.jltwp-adminify-replace-preview-img');\n    var $name = $confirm.find('.jltwp-adminify-replace-preview-name');\n    var $size = $confirm.find('.jltwp-adminify-replace-preview-size');\n    $name.text(file.name);\n    $size.text(formatBytes(file.size));\n\n    // Revoke prior preview URL if any.\n    var prior = $img.attr('data-object-url');\n    if (prior) {\n      try {\n        URL.revokeObjectURL(prior);\n      } catch (e) {}\n      $img.removeAttr('data-object-url');\n    }\n    if (file.type && /^image\\//.test(file.type) && typeof URL !== 'undefined' && URL.createObjectURL) {\n      var url = URL.createObjectURL(file);\n      $img.attr('src', url).attr('data-object-url', url);\n      $preview.removeAttr('hidden');\n    } else {\n      $img.removeAttr('src');\n      $preview.removeAttr('hidden');\n    }\n    $wrap.find('.jltwp-adminify-replace-trigger-row').addClass('is-hidden');\n    $confirm.removeAttr('hidden');\n    // Force reflow then add open class for transition.\n    // eslint-disable-next-line no-unused-expressions\n    $confirm[0].offsetHeight;\n    $confirm.addClass('is-open');\n    $wrap[0].__jltwpPendingFile = file;\n  }\n  function closeConfirmation($wrap) {\n    var $confirm = $wrap.find('.jltwp-adminify-replace-confirm');\n    var $img = $confirm.find('.jltwp-adminify-replace-preview-img');\n    var prior = $img.attr('data-object-url');\n    if (prior) {\n      try {\n        URL.revokeObjectURL(prior);\n      } catch (e) {}\n      $img.removeAttr('data-object-url').removeAttr('src');\n    }\n    $confirm.removeClass('is-open');\n    setTimeout(function () {\n      $confirm.attr('hidden', true);\n      $confirm.find('.jltwp-adminify-replace-confirm-preview').attr('hidden', true);\n    }, 160);\n    $wrap.find('.jltwp-adminify-replace-trigger-row').removeClass('is-hidden');\n    $wrap.find('.jltwp-adminify-replace-file').val('');\n    $wrap[0].__jltwpPendingFile = null;\n  }\n  function startUpload($wrap, file) {\n    if (!file) {\n      return;\n    }\n    var attachmentId = parseInt($wrap.attr('data-attachment-id'), 10) || 0;\n    var $message = $wrap.find('.jltwp-adminify-replace-message');\n    var $confirmBtn = $wrap.find('.jltwp-adminify-replace-do');\n    var $cancelBtn = $wrap.find('.jltwp-adminify-replace-cancel');\n    if (!attachmentId) {\n      showMessage($message, 'error', 'Unable to determine attachment ID.');\n      return;\n    }\n    var formData = new FormData();\n    formData.append('action', 'jltwp_adminify_replace_media_upload');\n    formData.append('security', l10n.nonce || '');\n    formData.append('attachment_id', attachmentId);\n    formData.append('replacement_file', file);\n    $confirmBtn.prop('disabled', true).addClass('is-loading');\n    $cancelBtn.prop('disabled', true);\n    showMessage($message, 'info', 'Uploading 0%...');\n    $.ajax({\n      url: l10n.ajax_url || window.ajaxurl,\n      type: 'POST',\n      data: formData,\n      contentType: false,\n      processData: false,\n      dataType: 'json',\n      xhr: function xhr() {\n        var xhr = $.ajaxSettings.xhr();\n        if (xhr.upload) {\n          xhr.upload.addEventListener('progress', function (evt) {\n            if (evt.lengthComputable) {\n              var pct = Math.round(evt.loaded / evt.total * 100);\n              showMessage($message, 'info', 'Uploading ' + pct + '%...');\n            }\n          });\n        }\n        return xhr;\n      }\n    }).done(function (response) {\n      if (response && response.success) {\n        var msg = response.data && response.data.message ? response.data.message : 'Image replaced successfully.';\n        showMessage($message, 'success', msg);\n        setTimeout(reloadPreservingEditorState, 1200);\n      } else {\n        $confirmBtn.prop('disabled', false).removeClass('is-loading');\n        $cancelBtn.prop('disabled', false);\n        var err = response && response.data && response.data.message ? response.data.message : 'Error replacing media.';\n        showMessage($message, 'error', err);\n      }\n    }).fail(function (xhr) {\n      $confirmBtn.prop('disabled', false).removeClass('is-loading');\n      $cancelBtn.prop('disabled', false);\n      var err = 'Error replacing media.';\n      if (xhr && xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {\n        err = xhr.responseJSON.data.message;\n      }\n      showMessage($message, 'error', err);\n    });\n  }\n\n  // Open the native file picker.\n  $(document).on('click', '.jltwp-adminify-replace-trigger', function (e) {\n    e.preventDefault();\n    $(this).closest('.jltwp-adminify-replace-media-wrap').find('.jltwp-adminify-replace-file').val('').trigger('click');\n  });\n\n  // File picked → validate then show inline confirmation card.\n  $(document).on('change', '.jltwp-adminify-replace-file', function () {\n    var file = this.files && this.files[0];\n    if (!file) {\n      return;\n    }\n    var $wrap = $(this).closest('.jltwp-adminify-replace-media-wrap');\n    if (!validatePicked($wrap, file)) {\n      $(this).val('');\n      return;\n    }\n    showConfirmation($wrap, file);\n  });\n\n  // Cancel → revert to trigger button.\n  $(document).on('click', '.jltwp-adminify-replace-cancel', function (e) {\n    e.preventDefault();\n    closeConfirmation($(this).closest('.jltwp-adminify-replace-media-wrap'));\n  });\n\n  // Confirm → upload pending file.\n  $(document).on('click', '.jltwp-adminify-replace-do', function (e) {\n    e.preventDefault();\n    var $wrap = $(this).closest('.jltwp-adminify-replace-media-wrap');\n    var file = $wrap[0] && $wrap[0].__jltwpPendingFile;\n    if (!file) {\n      return;\n    }\n    startUpload($wrap, file);\n  });\n\n  /**\n   * Inject a \"Back to Original\" link into the Attachment Details actions row\n   * (next to View/Edit more details/Download/Delete) when a backup exists.\n   */\n  function getModel(attachmentId) {\n    if (!attachmentId || typeof window.wp === 'undefined' || !wp.media || !wp.media.attachment) {\n      return null;\n    }\n    try {\n      return wp.media.attachment(attachmentId);\n    } catch (err) {\n      return null;\n    }\n  }\n  function injectInto(actions, attachmentId, count) {\n    if (!actions || !attachmentId) {\n      return;\n    }\n    if (actions.querySelector('.jltwp-adminify-back-to-original')) {\n      return;\n    }\n    var sep = document.createElement('span');\n    sep.className = 'links-separator jltwp-adminify-back-separator';\n    sep.textContent = '|';\n    actions.appendChild(document.createTextNode(' '));\n    actions.appendChild(sep);\n    actions.appendChild(document.createTextNode(' '));\n    var link = document.createElement('a');\n    link.href = '#';\n    link.className = 'jltwp-adminify-back-to-original';\n    link.setAttribute('data-attachment-id', attachmentId);\n    link.textContent = l10n.back_to_original || 'Back to Original';\n    if (count && count > 1) {\n      var badge = document.createElement('span');\n      badge.className = 'count';\n      badge.textContent = ' (' + count + ')';\n      link.appendChild(badge);\n    }\n    actions.appendChild(link);\n  }\n  function scanAttachmentDetails() {\n    // The TwoColumn / Details views render `.attachment-details` WITHOUT data-id;\n    // pull the attachment ID off our own Replace-Media wrap rendered inside the\n    // compat-meta area of the same container.\n    var wraps = document.querySelectorAll('.jltwp-adminify-replace-media-wrap[data-attachment-id]');\n    for (var i = 0; i < wraps.length; i++) {\n      (function (wrap) {\n        var attachmentId = parseInt(wrap.getAttribute('data-attachment-id'), 10) || 0;\n        if (!attachmentId) {\n          return;\n        }\n        var container = wrap.closest('.attachment-details, .attachment-info');\n        if (!container) {\n          return;\n        }\n        var actions = container.querySelector('.actions');\n        if (!actions) {\n          return;\n        }\n        var model = getModel(attachmentId);\n        var hasBackup = !!(model && model.get && model.get('jltwpAdminifyHasBackup'));\n        var count = model && model.get ? parseInt(model.get('jltwpAdminifyBackupCount'), 10) || 0 : 0;\n        if (hasBackup) {\n          injectInto(actions, attachmentId, count);\n          return;\n        }\n\n        // Model not synced yet: subscribe to changes, force fetch once, then retry.\n        if (model && !model._jltwpWatcher) {\n          model._jltwpWatcher = true;\n          var retry = function retry() {\n            if (model.get('jltwpAdminifyHasBackup')) {\n              var c = parseInt(model.get('jltwpAdminifyBackupCount'), 10) || 0;\n              injectInto(actions, attachmentId, c);\n            }\n          };\n          model.on('change', retry);\n          model.on('sync', retry);\n          if (typeof model.fetch === 'function' && !model._jltwpFetched) {\n            model._jltwpFetched = true;\n            try {\n              model.fetch();\n            } catch (e) {}\n          }\n        }\n      })(wraps[i]);\n    }\n  }\n  if (typeof MutationObserver !== 'undefined') {\n    var injectObserver = new MutationObserver(scanAttachmentDetails);\n    injectObserver.observe(document.body, {\n      childList: true,\n      subtree: true\n    });\n  }\n  $(document).ready(scanAttachmentDetails);\n\n  /**\n   * Shadcn-style custom confirmation modal. Returns a Promise that resolves\n   * when the user confirms, rejects on cancel/escape/backdrop click.\n   */\n  function showRestoreModal(opts) {\n    opts = opts || {};\n    return new Promise(function (resolve, reject) {\n      var modal = document.createElement('div');\n      modal.className = 'jltwp-adminify-modal';\n      modal.setAttribute('role', 'dialog');\n      modal.setAttribute('aria-modal', 'true');\n      modal.innerHTML = '<div class=\"jltwp-adminify-modal-backdrop\"></div>' + '<div class=\"jltwp-adminify-modal-card\" role=\"document\">' + '<div class=\"jltwp-adminify-modal-icon\" aria-hidden=\"true\">' + '<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">' + '<path d=\"M3 12a9 9 0 1 0 3-6.7L3 8\"/><polyline points=\"3 3 3 8 8 8\"/>' + '</svg>' + '</div>' + '<div class=\"jltwp-adminify-modal-body\">' + '<h2 class=\"jltwp-adminify-modal-title\"></h2>' + '<p class=\"jltwp-adminify-modal-desc\"></p>' + '</div>' + '<div class=\"jltwp-adminify-modal-actions\">' + '<button type=\"button\" class=\"jltwp-adminify-btn jltwp-adminify-btn-ghost jltwp-adminify-modal-cancel\"></button>' + '<button type=\"button\" class=\"jltwp-adminify-btn jltwp-adminify-btn-primary jltwp-adminify-modal-confirm\"></button>' + '</div>' + '</div>';\n      modal.querySelector('.jltwp-adminify-modal-title').textContent = opts.title || 'Restore previous version?';\n      modal.querySelector('.jltwp-adminify-modal-desc').textContent = opts.desc || '';\n      modal.querySelector('.jltwp-adminify-modal-cancel').textContent = opts.cancelText || 'Cancel';\n      modal.querySelector('.jltwp-adminify-modal-confirm').textContent = opts.confirmText || 'Restore';\n      document.body.appendChild(modal);\n      // Force reflow before adding open class to trigger transition.\n      // eslint-disable-next-line no-unused-expressions\n      modal.offsetHeight;\n      modal.classList.add('is-open');\n      var done = false;\n      function close(confirmed) {\n        if (done) return;\n        done = true;\n        modal.classList.remove('is-open');\n        document.removeEventListener('keydown', onKey, true);\n        setTimeout(function () {\n          if (modal.parentNode) {\n            modal.parentNode.removeChild(modal);\n          }\n        }, 180);\n        if (confirmed) {\n          resolve();\n        } else {\n          reject();\n        }\n      }\n      function onKey(e) {\n        if (e.key === 'Escape') {\n          e.preventDefault();\n          close(false);\n        } else if (e.key === 'Enter') {\n          e.preventDefault();\n          close(true);\n        }\n      }\n      modal.querySelector('.jltwp-adminify-modal-cancel').addEventListener('click', function () {\n        close(false);\n      });\n      modal.querySelector('.jltwp-adminify-modal-confirm').addEventListener('click', function () {\n        close(true);\n      });\n      modal.querySelector('.jltwp-adminify-modal-backdrop').addEventListener('click', function () {\n        close(false);\n      });\n      document.addEventListener('keydown', onKey, true);\n      setTimeout(function () {\n        var btn = modal.querySelector('.jltwp-adminify-modal-confirm');\n        if (btn && typeof btn.focus === 'function') {\n          btn.focus();\n        }\n      }, 50);\n    });\n  }\n\n  /**\n   * Reload the page, but if Gutenberg's editor has unsaved changes save them\n   * first so the user does not lose work just because they replaced a file.\n   * Falls back to plain reload when not in the block editor.\n   */\n  function reloadPreservingEditorState() {\n    try {\n      if (window.wp && wp.data && typeof wp.data.select === 'function' && typeof wp.data.dispatch === 'function') {\n        var sel = wp.data.select('core/editor');\n        var disp = wp.data.dispatch('core/editor');\n        if (sel && disp && typeof sel.isEditedPostDirty === 'function' && sel.isEditedPostDirty() && typeof disp.savePost === 'function') {\n          var done = false;\n          var finish = function finish() {\n            if (done) return;\n            done = true;\n            window.location.reload();\n          };\n          disp.savePost().then(finish)[\"catch\"](finish);\n          // Safety net — never block the reload longer than 4s.\n          setTimeout(finish, 4000);\n          return;\n        }\n      }\n    } catch (e) {/* ignore — fall through to plain reload */}\n    window.location.reload();\n  }\n  function performRestore($link) {\n    var attachmentId = parseInt($link.attr('data-attachment-id'), 10) || 0;\n    if (!attachmentId) {\n      return;\n    }\n    var originalHtml = $link.html();\n    $link.text(l10n.restoring_text || 'Restoring...');\n    $.ajax({\n      url: l10n.ajax_url || window.ajaxurl,\n      type: 'POST',\n      dataType: 'json',\n      data: {\n        action: 'jltwp_adminify_restore_original',\n        security: l10n.nonce || '',\n        attachment_id: attachmentId\n      }\n    }).done(function (response) {\n      if (response && response.success) {\n        reloadPreservingEditorState();\n      } else {\n        $link.html(originalHtml);\n        var msg = response && response.data && response.data.message ? response.data.message : l10n.restore_error || 'Error restoring original.';\n        window.alert(msg);\n      }\n    }).fail(function () {\n      $link.html(originalHtml);\n      window.alert(l10n.restore_error || 'Error restoring original.');\n    });\n  }\n\n  /**\n   * Attachment edit screen (post.php?post=ID&action=edit): render an inline\n   * \"Back to Original\" button next to WP's \"Edit Image\" button when a backup\n   * exists. Backup state is provided server-side via l10n.current_attachment.\n   */\n  function injectEditScreenRestoreButton() {\n    var ctx = l10n.current_attachment;\n    if (!ctx || !ctx.id || !ctx.has_backup) {\n      return;\n    }\n    if (document.querySelector('.jltwp-adminify-edit-screen-restore')) {\n      return;\n    }\n\n    // Prefer the canonical Edit Image button id used by WP core.\n    var $editBtn = $('#imgedit-open-btn-' + ctx.id);\n    if (!$editBtn.length) {\n      $editBtn = $('input.button[id^=\"imgedit-open-btn-\"], a.button[id^=\"imgedit-open-btn-\"]').first();\n    }\n    var label = l10n.back_to_original || 'Back to Original';\n    if (ctx.count && ctx.count > 1) {\n      label += ' <span class=\"count\">(' + ctx.count + ')</span>';\n    }\n    var html = '<button type=\"button\" class=\"button jltwp-adminify-edit-screen-restore jltwp-adminify-back-to-original\" data-attachment-id=\"' + ctx.id + '\" style=\"margin-left:6px;\">' + '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" style=\"vertical-align:text-bottom;margin-right:4px;\"><path d=\"M3 12a9 9 0 1 0 3-6.7L3 8\"/><polyline points=\"3 3 3 8 8 8\"/></svg>' + '<span>' + label + '</span>' + '</button>';\n    if ($editBtn.length) {\n      $editBtn.after(' ').after(html);\n      return;\n    }\n\n    // Fallback: append into `.wp_attachment_holder` if no Edit Image button exists.\n    var $holder = $('.wp_attachment_holder').first();\n    if ($holder.length) {\n      $holder.append('<p class=\"hide-if-no-js\">' + html + '</p>');\n    }\n  }\n  $(document).ready(injectEditScreenRestoreButton);\n  // The WP image-editor view re-renders this section after an Edit Image session\n  // closes — re-run shortly after to keep our button visible.\n  $(document).on('imgedit:close', injectEditScreenRestoreButton);\n  setTimeout(injectEditScreenRestoreButton, 500);\n  $(document).on('click', '.jltwp-adminify-back-to-original', function (e) {\n    e.preventDefault();\n    e.stopPropagation();\n    var $link = $(this);\n    var attachmentId = parseInt($link.attr('data-attachment-id'), 10) || 0;\n    if (!attachmentId) {\n      return;\n    }\n    showRestoreModal({\n      title: l10n.confirm_restore_title || 'Restore previous version?',\n      desc: l10n.confirm_restore || 'The current file will be replaced with the most recent backup.',\n      confirmText: l10n.confirm_restore_btn || 'Yes, restore it',\n      cancelText: l10n.cancel || 'Cancel'\n    }).then(function () {\n      performRestore($link);\n    })[\"catch\"](function () {/* cancelled */});\n  });\n});\n\n// Backward-compat stub: legacy inline onclick handlers fall back to triggering the picker.\nif (typeof window !== 'undefined') {\n  window.jltwp_adminify_media_replace = function () {\n    var picker = document.querySelector('.jltwp-adminify-replace-file');\n    if (picker) {\n      picker.value = '';\n      picker.click();\n    }\n  };\n}\n\n//# sourceURL=webpack://adminify/./dev/admin/modules/media-replace/media-replace.js?");

/***/ })

/******/ 	});
/************************************************************************/
/******/ 	
/******/ 	// startup
/******/ 	// Load entry module and return exports
/******/ 	// This entry module can't be inlined because the eval devtool is used.
/******/ 	var __webpack_exports__ = {};
/******/ 	__webpack_modules__["./dev/admin/modules/media-replace/media-replace.js"]();
/******/ 	
/******/ })()
;