跳转到内容

MediaWiki:Gadget-ilhpp.js

维基百科,自由的百科全书
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
/**!
 *  _________________________________________________________________________________
 * |                                                                                 |
 * |                      === WARNING: GLOBAL GADGET FILE ===                        |
 * |                    Changes to this page affect many users.                      |
 * |  Please discuss changes on the talk page, [[WP:VPT]] or GitHub before editing.  |
 * |_________________________________________________________________________________|
 *
 * Built from GitHub repository (https://github.com/diskdance/ilhpp), you should not make
 * changes directly here.
 *
 * See https://github.com/diskdance/ilhpp/blob/main/README.MD#%E9%83%A8%E7%BD%B2%E6%96%B9%E6%B3%95 for build instructions.
 */
// <nowiki>
"use strict";
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __async = (__this, __arguments, generator) => {
  return new Promise((resolve, reject) => {
    var fulfilled = (value) => {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    };
    var rejected = (value) => {
      try {
        step(generator.throw(value));
      } catch (e) {
        reject(e);
      }
    };
    var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
    step((generator = generator.apply(__this, __arguments)).next());
  });
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const ext_gadget_HanAssist = require("ext.gadget.HanAssist");
const messages = {
  "ilhpp-from": { "hans": "来自$1$2", "hant": "來自$1$2" },
  "ilhpp-wp": { "hans": "维基百科", "hant": "維基百科" },
  "ilhpp-more": { "hans": "阅读更多内容", "hant": "閱讀更多內容" },
  "ilhpp-cta": { "hans": '中文维基百科暂无“$1”条目,但您可以帮助我们<a href="/w/index.php?title=$2&action=edit&redlink=1">创建它</a>!', "hant": '中文維基百科暫無「$1」條目,但您可以幫助我們<a href="/w/index.php?title=$2&action=edit&redlink=1">建立它</a>!' },
  "ilhpp-settings": { "hans": "设置", "hant": "設定" },
  "ilhpp-settings-footer": { "hans": "跨语言链接设置", "hant": "跨語言連結設定" },
  "ilhpp-disam": { "hans": "页面标题涉及多个主题。", "hant": "頁面標題涉及多個主題。" },
  "ilhpp-disam-more": { "hans": "查看相似页面", "hant": "顯示類似的頁面" },
  "ilhpp-no-preview": { "hans": "该页面暂无预览。", "hant": "該頁面暫無預覽。" },
  "ilhpp-error-not-found": { "hans": '该页面不存在。<br>您可以<a href="/w/index.php?title=$1&action=edit">帮助我们修复该问题</a>。', "hant": '該頁面不存在。<br>您可以<a href="/w/index.php?title=$1&action=edit">幫助我們修復該問題</a>。' },
  "ilhpp-error": { "hans": "显示此预览时出现问题。", "hant": "顯示此頁面預覽時出現問題。" },
  "ilhpp-goto": { "hans": "前往该页面", "hant": "前往該頁面" },
  "ilhpp-close": { "hans": "关闭", "hant": "關閉" }
};
const DATA_ELEM_SELECTOR = ".ilh-all:not(.ilh-blue)";
const ORIG_A_SELECTOR = ".ilh-all:not(.ilh-blue) .ilh-page > a";
const FOREIGN_A_SELECTOR = `.ilh-all:not(.ilh-blue) .ilh-link > a`;
const ILH_LANG_SELECTOR = ".ilh-lang";
const ROOT_CLASS_DESKTOP = "ilhpp-popup-desktop";
const ROOT_CLASS_MOBILE = "ilhpp-popup-mobile";
const OVERLAY_CLASS_MOBILE = "ilhpp-mobile-overlay";
const PREF_KEY_LS = "ilhpp-prefs";
const PREF_KEY_MW = "userjs-ilhpp-prefs";
const RTL_LANGS = ["ar", "he", "fa", "ur", "ps", "sd", "ug", "dv", "syr"];
const LANG_WIKI_MAP = {
  gsw: "als",
  bho: "bh",
  rup: "roa-rup",
  lzh: "zh-classical",
  nan: "zh-min-nan",
  yue: "zh-yue"
};
const FOOTER_ANCHOR_ID = "ilhpp-footer-places-settings";
const DT_PTR_SHORT_SIDE_LENGTH_PX = 20;
const DT_PTR_WIDTH_PX = 8;
const DT_ATTACH_DELAY_MS = 300;
const DT_DETACH_DELAY_MS = 300;
const MB_SKELETON_STRIPE_COUNT = 6;
function isMobileDevice() {
  return !!mw.config.get("wgMFMode") && matchMedia("(hover: none), (pointer: coarse)").matches;
}
function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj));
}
function getDirection(langCode) {
  var _a;
  try {
    if (Intl.Locale.prototype.getTextInfo || Intl.Locale.prototype.textInfo) {
      const locale = new Intl.Locale(langCode);
      return ((_a = locale.getTextInfo()) != null ? _a : locale.textInfo).direction;
    }
  } catch (e) {
    return "ltr";
  }
  return RTL_LANGS.includes(langCode.split("-")[0].toLowerCase()) ? "rtl" : "ltr";
}
function normalizeTitle(title) {
  return title.replace(/_/g, " ");
}
function normalizeLang(lang) {
  return lang === "d" ? "en" : lang;
}
function normalizeWikiId(wikiId) {
  var _a;
  return (_a = LANG_WIKI_MAP[wikiId]) != null ? _a : wikiId;
}
function isWikipedia(wikiId) {
  return wikiId !== "d";
}
function haveConflicts() {
  return false;
}
function togglePageScroll(lock) {
  document.body.classList.toggle("ilhpp-scroll-locked", lock);
}
let idCounter = 1;
function getUniqueId() {
  return `ilhpp-${idCounter++}`;
}
var LinkMode = /* @__PURE__ */ ((LinkMode2) => {
  LinkMode2["Orig"] = "ORIG";
  LinkMode2["OrigAndUnlinkedForeign"] = "ORIG_N_UNLINKED_FOREIGN";
  LinkMode2["Foreign"] = "FOREIGN";
  LinkMode2["ForeignAndLangCode"] = "FOREIGN_N_LANG_CODE";
  return LinkMode2;
})(LinkMode || {});
var PopupMode = /* @__PURE__ */ ((PopupMode2) => {
  PopupMode2["Disabled"] = "DISABLED";
  PopupMode2["OnHover"] = "ON_HOVER";
  PopupMode2["OnClick"] = "ON_CLICK";
  return PopupMode2;
})(PopupMode || {});
var OrigLinkColor = /* @__PURE__ */ ((OrigLinkColor2) => {
  OrigLinkColor2["Red"] = "RED";
  OrigLinkColor2["Green"] = "GREEN";
  return OrigLinkColor2;
})(OrigLinkColor || {});
const DEFAULT_PREFS = {
  link: "ORIG",
  popup: "ON_HOVER",
  highlightExisting: false,
  origLinkColor: "GREEN"
  /* Green */
};
let currentPrefs = null;
function toCSSClassName(item) {
  return item.toLowerCase().replace(/_/g, "-");
}
function toCSSClassNames(prefs) {
  const result = [
    `ilhpp-pref-link-${toCSSClassName(prefs.link)}`,
    `ilhpp-pref-popup-${toCSSClassName(prefs.popup)}`,
    `ilhpp-pref-orig-link-color-${toCSSClassName(prefs.origLinkColor)}`
  ];
  if (prefs.highlightExisting) {
    result.push("ilhpp-pref-hl-existing");
  }
  return result;
}
function reflectChanges(prefs) {
  var _a, _b;
  document.documentElement.className = document.documentElement.className.replace(
    /\bilhpp-pref[\w-]+\b/g,
    ""
  );
  document.documentElement.classList.add(...toCSSClassNames(prefs));
  document.querySelectorAll(DATA_ELEM_SELECTOR).forEach((root) => {
    const origAnchor = root.querySelector(ORIG_A_SELECTOR);
    const foreignAnchor = root.querySelector(FOREIGN_A_SELECTOR);
    if (!origAnchor || !foreignAnchor) {
      return;
    }
    if (origAnchor.dataset.oldHref !== void 0) {
      origAnchor.href = origAnchor.dataset.oldHref;
    }
    delete origAnchor.dataset.oldHref;
    origAnchor.className = "new";
    if ([
      "FOREIGN_N_LANG_CODE",
      "FOREIGN"
      /* Foreign */
    ].includes(prefs.link)) {
      origAnchor.dataset.oldHref = origAnchor.href;
      origAnchor.href = foreignAnchor.href;
      origAnchor.className = "extiw";
    }
  });
  (_a = document.getElementById(FOOTER_ANCHOR_ID)) == null ? void 0 : _a.remove();
  if (prefs.popup === "DISABLED") {
    const li = document.createElement("li");
    li.id = FOOTER_ANCHOR_ID;
    const settingsAnchor = document.createElement("a");
    settingsAnchor.href = "#";
    settingsAnchor.innerText = mw.msg("ilhpp-settings-footer");
    settingsAnchor.addEventListener("click", (ev) => {
      ev.preventDefault();
      void (() => __async(this, null, function* () {
        const { showSettingsDialog } = yield mw.loader.using("ext.gadget.ilhpp-settings").then((require2) => require2("ext.gadget.ilhpp-settings"));
        showSettingsDialog();
      }))();
    });
    li.appendChild(settingsAnchor);
    (_b = document.getElementById("footer-places")) == null ? void 0 : _b.appendChild(li);
  }
}
function getPreferences() {
  var _a;
  if (currentPrefs) {
    return deepClone(currentPrefs);
  }
  let result = deepClone(DEFAULT_PREFS);
  try {
    const mwOptionSerialized = mw.user.options.get(PREF_KEY_MW);
    const localStorageSerialized = localStorage.getItem(PREF_KEY_LS);
    let mwOptionPrefs = null;
    let localStoragePrefs = null;
    if (mwOptionSerialized) {
      const maybePrefs = JSON.parse(mwOptionSerialized);
      if (Object.values(LinkMode).includes(maybePrefs.link) && Object.values(PopupMode).includes(maybePrefs.popup) && typeof maybePrefs.highlightExisting === "boolean" && Object.values(OrigLinkColor).includes(maybePrefs.origLinkColor)) {
        mwOptionPrefs = maybePrefs;
      }
    }
    if (localStorageSerialized) {
      const maybePrefs = JSON.parse(localStorageSerialized);
      if (Object.values(LinkMode).includes(maybePrefs.link) && Object.values(PopupMode).includes(maybePrefs.popup) && typeof maybePrefs.highlightExisting === "boolean" && Object.values(OrigLinkColor).includes(maybePrefs.origLinkColor)) {
        localStoragePrefs = maybePrefs;
      }
    }
    result = (_a = mwOptionPrefs != null ? mwOptionPrefs : localStoragePrefs) != null ? _a : result;
    if (!mwOptionPrefs) {
      if (mw.user.isNamed()) {
        void new mw.Api().saveOption(
          PREF_KEY_MW,
          // Only set good shaped local storage prefs
          JSON.stringify(localStoragePrefs != null ? localStoragePrefs : DEFAULT_PREFS)
        );
      }
      if (!localStoragePrefs) {
        localStorage.setItem(PREF_KEY_LS, JSON.stringify(DEFAULT_PREFS));
      }
    } else {
      localStorage.setItem(PREF_KEY_LS, JSON.stringify(mwOptionPrefs));
    }
  } catch (e) {
  }
  currentPrefs = result;
  reflectChanges(result);
  return result;
}
function setPreferences(prefs) {
  return __async(this, null, function* () {
    currentPrefs = deepClone(prefs);
    const serialized = JSON.stringify(prefs);
    if (mw.user.isNamed()) {
      const response = yield new mw.Api().saveOption(PREF_KEY_MW, serialized);
      if (response.options !== "success") {
        throw new Error("Failed to save options!");
      }
    }
    localStorage.setItem(PREF_KEY_LS, serialized);
    reflectChanges(prefs);
  });
}
const hostRest = location.hostname.endsWith("wmflabs.org") ? ".wikipedia.beta.wmflabs.org" : ".wikipedia.org";
function getPagePreview(wikiId, title, signal) {
  return __async(this, null, function* () {
    var _a;
    if (wikiId === "d") {
      throw new DOMException("No preview for this wiki", "NotSupportedError");
    }
    const resp = yield fetch(
      `https://${wikiId}${hostRest}/api/rest_v1/page/summary/${encodeURIComponent(title)}`,
      {
        signal,
        // Design decision: we want to minimize loading time as much as possible as it introduces
        // visual glitches, so uses cache if present regardless of its freshness
        cache: "force-cache"
        // FIXME: Need workaround, adding this causes CORS preflight requests
        /* headers: {
          'Api-User-Agent': API_USER_AGENT,
        }, */
      }
    );
    if (resp.status === 404) {
      throw new DOMException("Page not found", "NotFoundError");
    }
    if (!resp.ok) {
      throw new DOMException("Invalid response", "InvalidStateError");
    }
    const respJson = yield resp.json();
    if (!respJson.extract_html) {
      throw new DOMException("No preview for this page", "NotSupportedError");
    }
    const temp = document.createElement("div");
    temp.innerHTML = respJson.displaytitle;
    const displayTitle = (_a = temp.textContent) != null ? _a : "";
    return {
      isDisambiguation: respJson.type === "disambiguation",
      title: displayTitle,
      dir: respJson.dir,
      description: respJson.description,
      mainHtml: respJson.extract_html
    };
  });
}
function createPopupBase(anchor) {
  var _a;
  const dataElement = anchor.closest(DATA_ELEM_SELECTOR);
  if (!dataElement) {
    return null;
  }
  const foreignAnchor = dataElement.querySelector(FOREIGN_A_SELECTOR);
  if (!foreignAnchor) {
    return null;
  }
  const foreignHref = foreignAnchor.href;
  const origTitle = dataElement.dataset.origTitle;
  const wikiId = dataElement.dataset.langCode;
  const langCode = wikiId;
  const langName = (_a = dataElement.querySelector(ILH_LANG_SELECTOR)) == null ? void 0 : _a.innerText;
  const foreignTitle = dataElement.dataset.foreignTitle;
  if (!origTitle || !wikiId || !langCode || !langName || !foreignTitle) {
    return null;
  }
  return {
    origTitle,
    wikiId: normalizeWikiId(wikiId),
    langCode: normalizeLang(langCode),
    langName,
    foreignTitle: normalizeTitle(foreignTitle),
    foreignHref
  };
}
let overriddenPopupMode = null;
function setOverriddenPopupMode(popupMode) {
  overriddenPopupMode = popupMode;
}
function getOverriddenPopupMode() {
  const prefs = getPreferences();
  if (prefs.popup === PopupMode.OnHover) {
    return overriddenPopupMode != null ? overriddenPopupMode : prefs.popup;
  }
  return prefs.popup;
}
function getRealRect(elem) {
  const sandbox = document.createElement("div");
  sandbox.style.position = "absolute";
  sandbox.style.visibility = "hidden";
  sandbox.style.width = "0px";
  sandbox.style.height = "0px";
  sandbox.appendChild(elem);
  document.body.appendChild(sandbox);
  const result = elem.getBoundingClientRect();
  elem.remove();
  sandbox.remove();
  return result;
}
function getLayout(layoutParam) {
  var _a, _b;
  const pageScrollOffsetX = window.scrollX;
  const pageScrollOffsetY = window.scrollY;
  const viewpointWidth = document.documentElement.clientWidth;
  const viewpointHeight = document.documentElement.clientHeight;
  const width = layoutParam.popupRect.width;
  const height = layoutParam.popupRect.height;
  const cursorPageX = (_b = (_a = layoutParam.cursor) == null ? void 0 : _a.pageX) != null ? _b : layoutParam.anchorBoundingRect.left + DT_PTR_SHORT_SIDE_LENGTH_PX;
  const currentAnchorLineRect = layoutParam.cursor ? [...layoutParam.anchorRects].map(
    (rect) => [
      rect,
      Math.abs(
        pageScrollOffsetY + (rect.top + rect.bottom) / 2 - layoutParam.cursor.pageY
      )
    ]
  ).reduce((prev, curr) => curr[1] < prev[1] ? curr : prev)[0] : layoutParam.anchorBoundingRect;
  const anchorPageTop = currentAnchorLineRect.top + pageScrollOffsetY;
  const anchorPageBottom = currentAnchorLineRect.bottom + pageScrollOffsetY;
  const isRight = cursorPageX < pageScrollOffsetX + viewpointWidth / 2;
  const pageX = isRight ? cursorPageX - DT_PTR_SHORT_SIDE_LENGTH_PX : cursorPageX - width + DT_PTR_SHORT_SIDE_LENGTH_PX;
  const isBottom = anchorPageTop < pageScrollOffsetY + viewpointHeight / 2;
  const pageY = isBottom ? anchorPageBottom + DT_PTR_WIDTH_PX : anchorPageTop - height - DT_PTR_WIDTH_PX;
  return { pageX, pageY, isRight, isBottom };
}
function buildPopup$1(popup) {
  const root = popup.elem;
  root.id = getUniqueId();
  root.className = `${ROOT_CLASS_DESKTOP} ${ROOT_CLASS_DESKTOP}--foreign-${getDirection(popup.langCode)} ${ROOT_CLASS_DESKTOP}--loading`;
  root.setAttribute("role", "dialog");
  const header = document.createElement("a");
  header.id = getUniqueId();
  header.href = popup.foreignHref;
  header.className = `${ROOT_CLASS_DESKTOP}__header ilhpp-text-like ilhpp-auto-hyphen`;
  header.lang = popup.langCode;
  header.dir = "auto";
  header.innerText = popup.foreignTitle;
  root.setAttribute("aria-labelledby", header.id);
  const subheader = document.createElement("div");
  subheader.className = `${ROOT_CLASS_DESKTOP}__subheader`;
  subheader.dir = "auto";
  subheader.innerText = mw.msg(
    "ilhpp-from",
    popup.langName,
    isWikipedia(popup.wikiId) ? mw.msg("ilhpp-wp") : ""
  );
  const main = document.createElement("div");
  main.className = `${ROOT_CLASS_DESKTOP}__main ${ROOT_CLASS_DESKTOP}__main--loading`;
  const extract = document.createElement("a");
  extract.href = popup.foreignHref;
  extract.lang = popup.langCode;
  extract.className = `${ROOT_CLASS_DESKTOP}__main__extract ilhpp-text-like ilhpp-auto-hyphen ilhpp-extract`;
  extract.dir = "auto";
  const more = document.createElement("a");
  more.href = popup.foreignHref;
  more.className = `${ROOT_CLASS_DESKTOP}__main__more`;
  more.innerText = mw.msg("ilhpp-more");
  main.append(extract, more);
  const cta = document.createElement("footer");
  cta.className = `${ROOT_CLASS_DESKTOP}__cta`;
  const ctaInner = document.createElement("div");
  ctaInner.className = `${ROOT_CLASS_DESKTOP}__cta__inner`;
  ctaInner.innerHTML = mw.msg("ilhpp-cta", popup.origTitle, encodeURIComponent(popup.origTitle));
  const settingsButton = document.createElement("button");
  settingsButton.className = `${cta.className}__settings`;
  settingsButton.ariaLabel = settingsButton.title = mw.msg("ilhpp-settings");
  settingsButton.addEventListener("click", () => {
    void (() => __async(this, null, function* () {
      settingsButton.disabled = true;
      const { showSettingsDialog } = yield mw.loader.using("ext.gadget.ilhpp-settings").then((require2) => require2("ext.gadget.ilhpp-settings"));
      yield detachPopup$1(popup);
      showSettingsDialog();
    }))();
  });
  cta.append(ctaInner, settingsButton);
  root.append(header, subheader, main, cta);
  const rect = getRealRect(root);
  const layout = getLayout({
    popupRect: rect,
    anchorBoundingRect: popup.anchor.getBoundingClientRect(),
    anchorRects: popup.anchor.getClientRects(),
    cursor: popup.cursor
  });
  root.style.top = `${layout.pageY}px`;
  root.style.left = `${layout.pageX}px`;
  root.classList.add(`${ROOT_CLASS_DESKTOP}--${layout.isBottom ? "bottom" : "top"}`);
  root.classList.add(`${ROOT_CLASS_DESKTOP}--${layout.isRight ? "right" : "left"}`);
  if (!layout.isBottom) {
    const observer = new MutationObserver(() => {
      const newTop = layout.pageY + rect.height - root.clientHeight;
      root.style.top = `${newTop}px`;
    });
    observer.observe(popup.elem, { subtree: true, childList: true });
  }
  root.addEventListener("mouseleave", popup.detachHandler);
  root.addEventListener("mouseenter", popup.cancelDetachingHandler);
  void getPagePreview(popup.wikiId, popup.foreignTitle, popup.abortController.signal).then(
    (preview) => {
      root.classList.remove(`${ROOT_CLASS_DESKTOP}--loading`);
      header.innerText = preview.title;
      if (preview.isDisambiguation) {
        root.classList.add(`${ROOT_CLASS_DESKTOP}--disam`);
        extract.removeAttribute("lang");
        extract.innerText = mw.msg("ilhpp-disam");
        more.innerText = mw.msg("ilhpp-disam-more");
      } else {
        root.classList.add(`${ROOT_CLASS_DESKTOP}--standard`);
        extract.innerHTML = preview.mainHtml;
      }
    },
    (err) => {
      switch (err == null ? void 0 : err.name) {
        case "AbortError":
          break;
        case "NotSupportedError":
          root.classList.remove(`${ROOT_CLASS_DESKTOP}--loading`);
          root.classList.add(`${ROOT_CLASS_DESKTOP}--no-preview`);
          extract.removeAttribute("lang");
          extract.innerText = mw.msg("ilhpp-no-preview");
          more.innerText = mw.msg("ilhpp-goto");
          break;
        case "NotFoundError":
          root.classList.remove(`${ROOT_CLASS_DESKTOP}--loading`);
          root.classList.add(`${ROOT_CLASS_DESKTOP}--error`);
          extract.removeAttribute("lang");
          extract.innerHTML = mw.msg(
            "ilhpp-error-not-found",
            encodeURIComponent(mw.config.get("wgPageName"))
          );
          more.innerText = mw.msg("ilhpp-goto");
          break;
        default:
          root.classList.remove(`${ROOT_CLASS_DESKTOP}--loading`);
          root.classList.add(`${ROOT_CLASS_DESKTOP}--error`);
          extract.removeAttribute("lang");
          extract.innerText = mw.msg("ilhpp-error");
          more.innerText = mw.msg("ilhpp-goto");
          break;
      }
    }
  );
}
function attachPopup$1(anchor, oldTooltip, cursor) {
  const popupBase = createPopupBase(anchor);
  if (!popupBase) {
    return null;
  }
  let timeoutId;
  const popup = __spreadProps(__spreadValues({}, popupBase), {
    state: "attached",
    elem: document.createElement("div"),
    anchor,
    oldTooltip,
    cursor,
    // Support Safari 11.1: Partial support is enough for our use case
    // eslint-disable-next-line compat/compat
    abortController: new AbortController(),
    detachHandler() {
      if (getOverriddenPopupMode() === PopupMode.OnHover) {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
          void detachPopup$1(popup);
        }, DT_DETACH_DELAY_MS);
      }
    },
    cancelDetachingHandler() {
      if (getOverriddenPopupMode() === PopupMode.OnHover) {
        clearTimeout(timeoutId);
      }
    }
  });
  buildPopup$1(popup);
  popup.anchor.addEventListener("mouseleave", popup.detachHandler);
  popup.anchor.addEventListener("mouseenter", popup.cancelDetachingHandler);
  popup.anchor.setAttribute("aria-haspopup", "dialog");
  popup.anchor.setAttribute("aria-controls", popup.elem.id);
  document.body.appendChild(popup.elem);
  return popup;
}
function detachPopup$1(popup) {
  return __async(this, null, function* () {
    if (popup.state === "detached") {
      return;
    }
    popup.state = "detached";
    popup.abortController.abort();
    popup.elem.classList.add(`${ROOT_CLASS_DESKTOP}--out`);
    if (popup.oldTooltip !== null) {
      popup.anchor.title = popup.oldTooltip;
    }
    yield new Promise((resolve) => {
      popup.elem.addEventListener("animationend", resolve, { once: true });
    });
    popup.anchor.removeEventListener("mouseleave", popup.detachHandler);
    popup.anchor.removeEventListener("mouseenter", popup.cancelDetachingHandler);
    popup.anchor.removeAttribute("aria-haspopup");
    popup.anchor.removeAttribute("aria-controls");
    popup.elem.remove();
  });
}
let activePopup = null;
let activeAnchor = null;
let activeAnchorTooltip = null;
let mouseOverTimeoutId;
let isTabPressed = false;
function run$1() {
  [
    "pointercancel",
    "pointerdown",
    "pointermove",
    "pointerout",
    "pointerover",
    "pointerup"
  ].forEach((eventName) => {
    document.body.addEventListener(
      eventName,
      (ev) => {
        if (getPreferences().popup === PopupMode.OnHover) {
          setOverriddenPopupMode(ev.pointerType === "touch" ? PopupMode.OnClick : null);
        }
      },
      {
        passive: true,
        capture: true
        // Add at capture phase to be triggered as early as possible
      }
    );
  });
  document.body.addEventListener("mouseover", (ev) => {
    if (getOverriddenPopupMode() === PopupMode.OnHover && ev.target instanceof HTMLElement) {
      const targetAnchor = ev.target.closest(ORIG_A_SELECTOR);
      clearTimeout(mouseOverTimeoutId);
      if (activeAnchor && activeAnchorTooltip && (activePopup == null ? void 0 : activePopup.state) !== "attached") {
        activeAnchor.title = activeAnchorTooltip;
        activeAnchor = null;
        activeAnchorTooltip = null;
      }
      if (targetAnchor && ((activePopup == null ? void 0 : activePopup.state) === "attached" && (activePopup == null ? void 0 : activePopup.anchor) !== targetAnchor || (activePopup == null ? void 0 : activePopup.state) !== "attached")) {
        if (activePopup) {
          void detachPopup$1(activePopup);
        }
        activeAnchorTooltip = targetAnchor.getAttribute("title");
        targetAnchor.removeAttribute("title");
        activeAnchor = targetAnchor;
        mouseOverTimeoutId = setTimeout(() => {
          activePopup = attachPopup$1(targetAnchor, activeAnchorTooltip, {
            pageX: ev.pageX,
            pageY: ev.pageY
          });
        }, DT_ATTACH_DELAY_MS);
      }
    }
  });
  document.body.addEventListener(
    "click",
    (ev) => {
      if (getOverriddenPopupMode() === PopupMode.OnClick && ev.target instanceof HTMLElement) {
        const targetAnchor = ev.target.closest(ORIG_A_SELECTOR);
        if (targetAnchor && // When clicking on the same <a> with a popup, detach that popup
        ((activePopup == null ? void 0 : activePopup.state) === "attached" && (activePopup == null ? void 0 : activePopup.anchor) !== targetAnchor || (activePopup == null ? void 0 : activePopup.state) !== "attached")) {
          ev.stopImmediatePropagation();
          ev.preventDefault();
          if (activePopup && activePopup.state === "attached") {
            if (activePopup.anchor !== targetAnchor) {
              void detachPopup$1(activePopup);
            } else {
              return;
            }
          }
          const oldTooltip = targetAnchor.getAttribute("title");
          targetAnchor.removeAttribute("title");
          activePopup = attachPopup$1(targetAnchor, oldTooltip, {
            pageX: ev.pageX,
            pageY: ev.pageY
          });
        } else if (!(activePopup == null ? void 0 : activePopup.elem.contains(ev.target))) {
          if (activePopup && activePopup.state === "attached") {
            ev.stopImmediatePropagation();
            ev.preventDefault();
            void detachPopup$1(activePopup);
          }
        }
      }
    },
    {
      passive: false,
      capture: true
      // Add at capture phase to "mock an overlay"
    }
  );
  document.body.addEventListener("keydown", (ev) => {
    if (ev.key === "Tab") {
      isTabPressed = true;
    }
  });
  document.body.addEventListener("keyup", (ev) => {
    if (ev.key === "Tab") {
      isTabPressed = false;
    }
  });
  document.body.addEventListener("focusin", (ev) => {
    if (isTabPressed && getOverriddenPopupMode() !== PopupMode.Disabled && ev.target instanceof HTMLElement) {
      const targetAnchor = ev.target.closest(ORIG_A_SELECTOR);
      if (targetAnchor) {
        if ((activePopup == null ? void 0 : activePopup.state) === "attached" && (activePopup == null ? void 0 : activePopup.anchor) !== targetAnchor || (activePopup == null ? void 0 : activePopup.state) !== "attached") {
          if (activePopup && activePopup.state === "attached" && activePopup.anchor !== targetAnchor) {
            void detachPopup$1(activePopup);
          }
          const oldTooltip = targetAnchor.getAttribute("title");
          targetAnchor.removeAttribute("title");
          activePopup = attachPopup$1(targetAnchor, oldTooltip);
        }
      } else if (!(activePopup == null ? void 0 : activePopup.elem.contains(ev.target))) {
        if (activePopup && activePopup.state === "attached") {
          void detachPopup$1(activePopup);
        }
      }
    }
  });
}
function buildPopup(popup) {
  const dir = getDirection(popup.langCode);
  const root = popup.elem;
  root.id = getUniqueId();
  root.setAttribute("role", "dialog");
  root.setAttribute("aria-modal", "true");
  root.classList.add(
    ROOT_CLASS_MOBILE,
    `${ROOT_CLASS_MOBILE}--foreign-${dir}`,
    `${ROOT_CLASS_MOBILE}--loading`
  );
  let effectiveTouchInitialState = null;
  let touchOffset = 0;
  root.addEventListener("touchstart", (ev) => {
    var _a;
    if (((_a = window.getSelection()) == null ? void 0 : _a.type) === "Range") {
      return;
    }
    popup.overlay.classList.add("ilhpp-mobile-panned");
    root.classList.add("ilhpp-mobile-panned");
    if (!effectiveTouchInitialState) {
      effectiveTouchInitialState = ev.touches[0];
    }
  });
  root.addEventListener("touchmove", (ev) => {
    var _a;
    if (((_a = window.getSelection()) == null ? void 0 : _a.type) === "Range" || // Do not respond to touch actions if something is selected
    !effectiveTouchInitialState) {
      return;
    }
    const effectiveTouch = [...ev.changedTouches].find(
      (touch) => touch.identifier === effectiveTouchInitialState.identifier
    );
    if (!effectiveTouch) {
      return;
    }
    touchOffset = effectiveTouch.screenY - effectiveTouchInitialState.screenY;
    if (touchOffset >= 0) {
      root.style.transform = `translateY(${touchOffset}px)`;
      popup.overlay.style.opacity = `${1 - touchOffset / root.offsetHeight}`;
    } else {
      root.style.transform = `translateY(${Math.expm1(touchOffset / 100) * 20}px)`;
      popup.overlay.style.removeProperty("opacity");
    }
  });
  ["touchend", "touchcancel"].forEach((eventName) => {
    root.addEventListener(eventName, (ev) => {
      if (ev.touches.length === 0 && effectiveTouchInitialState) {
        popup.overlay.classList.remove("ilhpp-mobile-panned");
        root.classList.remove("ilhpp-mobile-panned");
        effectiveTouchInitialState = null;
        if (touchOffset / root.offsetHeight > 0.1) {
          void detachPopup(popup);
        } else {
          popup.overlay.style.removeProperty("opacity");
          root.style.removeProperty("transform");
        }
      }
    });
  });
  const header = document.createElement("a");
  header.id = getUniqueId();
  header.href = popup.foreignHref;
  header.className = `${ROOT_CLASS_MOBILE}__header ilhpp-text-like ilhpp-auto-hyphen`;
  header.lang = popup.langCode;
  header.dir = "auto";
  header.innerText = popup.foreignTitle;
  root.setAttribute("aria-labelledby", header.id);
  const subheader = document.createElement("div");
  subheader.className = `${ROOT_CLASS_MOBILE}__subheader`;
  subheader.dir = "auto";
  subheader.innerText = mw.msg(
    "ilhpp-from",
    popup.langName,
    isWikipedia(popup.wikiId) ? mw.msg("ilhpp-wp") : ""
  );
  const closeButton = document.createElement("button");
  closeButton.className = `${ROOT_CLASS_MOBILE}__close ilhpp-mobile-button`;
  closeButton.ariaLabel = closeButton.title = mw.msg("ilhpp-close");
  closeButton.addEventListener("click", () => {
    void detachPopup(popup);
  });
  const moreButton = document.createElement("a");
  moreButton.role = "button";
  moreButton.href = popup.foreignHref;
  moreButton.className = `${ROOT_CLASS_MOBILE}__more ilhpp-mobile-button ilhpp-mobile-button--primary-progressive`;
  moreButton.innerText = mw.msg("ilhpp-more");
  const extract = document.createElement("div");
  extract.lang = popup.langCode;
  extract.dir = "auto";
  extract.className = `${ROOT_CLASS_MOBILE}__extract ilhpp-auto-hyphen ilhpp-extract`;
  const skeletonContainer = document.createElement("div");
  skeletonContainer.setAttribute("aria-hidden", "true");
  skeletonContainer.className = `${ROOT_CLASS_MOBILE}__extract__skeleton-container`;
  Array.from({ length: MB_SKELETON_STRIPE_COUNT }).forEach(() => {
    const skeletonStripe = document.createElement("div");
    skeletonStripe.className = "ilhpp-mobile-skeleton";
    skeletonContainer.appendChild(skeletonStripe);
  });
  extract.appendChild(skeletonContainer);
  const cta = document.createElement("footer");
  cta.className = `${ROOT_CLASS_MOBILE}__cta`;
  const ctaInner = document.createElement("div");
  ctaInner.className = `${ROOT_CLASS_MOBILE}__cta__inner`;
  ctaInner.innerHTML = mw.msg("ilhpp-cta", popup.origTitle, encodeURIComponent(popup.origTitle));
  cta.append(ctaInner);
  const settingsButton = document.createElement("button");
  settingsButton.className = `${ROOT_CLASS_MOBILE}__settings ilhpp-mobile-button`;
  settingsButton.ariaLabel = settingsButton.title = mw.msg("ilhpp-settings");
  settingsButton.addEventListener("click", () => {
    void (() => __async(this, null, function* () {
      settingsButton.disabled = true;
      const { showSettingsDialog } = yield mw.loader.using("ext.gadget.ilhpp-settings").then((require2) => require2("ext.gadget.ilhpp-settings"));
      yield detachPopup(popup);
      showSettingsDialog();
    }))();
  });
  root.append(header, subheader, closeButton, extract, moreButton, cta, settingsButton);
  void getPagePreview(popup.wikiId, popup.foreignTitle, popup.abortController.signal).then(
    (preview) => {
      root.classList.remove(`${ROOT_CLASS_MOBILE}--loading`);
      header.innerText = preview.title;
      if (preview.isDisambiguation) {
        root.classList.add(`${ROOT_CLASS_MOBILE}--disam`);
        extract.removeAttribute("lang");
        extract.insertAdjacentText("beforeend", mw.msg("ilhpp-disam"));
        moreButton.innerText = mw.msg("ilhpp-disam-more");
      } else {
        root.classList.add(`${ROOT_CLASS_MOBILE}--standard`);
        extract.insertAdjacentHTML("beforeend", preview.mainHtml);
      }
    },
    (err) => {
      switch (err == null ? void 0 : err.name) {
        case "AbortError":
          break;
        case "NotSupportedError":
          root.classList.remove(`${ROOT_CLASS_MOBILE}--loading`);
          root.classList.add(`${ROOT_CLASS_MOBILE}--no-preview`);
          extract.removeAttribute("lang");
          extract.insertAdjacentText("beforeend", mw.msg("ilhpp-no-preview"));
          moreButton.innerText = mw.msg("ilhpp-goto");
          break;
        case "NotFoundError":
          root.classList.remove(`${ROOT_CLASS_MOBILE}--loading`);
          root.classList.add(`${ROOT_CLASS_MOBILE}--error`);
          extract.removeAttribute("lang");
          extract.insertAdjacentHTML(
            "beforeend",
            mw.msg("ilhpp-error-not-found", encodeURIComponent(mw.config.get("wgPageName")))
            // messages.json is trusted
          );
          moreButton.innerText = mw.msg("ilhpp-goto");
          break;
        default:
          root.classList.remove(`${ROOT_CLASS_MOBILE}--loading`);
          root.classList.add(`${ROOT_CLASS_MOBILE}--error`);
          extract.removeAttribute("lang");
          extract.insertAdjacentText("beforeend", mw.msg("ilhpp-error"));
          moreButton.innerText = mw.msg("ilhpp-goto");
          break;
      }
    }
  );
}
function attachPopup(anchor) {
  const popupBase = createPopupBase(anchor);
  if (!popupBase) {
    return null;
  }
  const abortController = new AbortController();
  const popup = __spreadProps(__spreadValues({}, popupBase), {
    overlay: document.createElement("div"),
    elem: document.createElement("div"),
    anchor,
    abortController
  });
  togglePageScroll(true);
  buildPopup(popup);
  popup.overlay.className = OVERLAY_CLASS_MOBILE;
  popup.overlay.setAttribute("aria-hidden", "true");
  popup.overlay.addEventListener("click", () => {
    void detachPopup(popup);
  });
  popup.anchor.setAttribute("aria-haspopup", "dialog");
  popup.anchor.setAttribute("aria-controls", popup.elem.id);
  document.body.append(popup.overlay, popup.elem);
  return popup;
}
function detachPopup(popup) {
  return __async(this, null, function* () {
    popup.abortController.abort();
    popup.overlay.classList.add(`${OVERLAY_CLASS_MOBILE}--out`);
    popup.elem.classList.add(`${ROOT_CLASS_MOBILE}--out`);
    yield Promise.all(
      [popup.overlay, popup.elem].map(
        (target) => new Promise((resolve) => {
          target.addEventListener("animationend", resolve, { once: true });
        }).then(() => {
          target.remove();
        })
      )
    );
    popup.anchor.removeAttribute("aria-haspopup");
    popup.anchor.removeAttribute("aria-controls");
    togglePageScroll(false);
  });
}
function run() {
  mw.hook("wikipage.content").add(($content) => {
    $content.each((_, root) => {
      root.addEventListener(
        "click",
        (ev) => {
          if (getPreferences().popup !== PopupMode.Disabled && ev.target instanceof HTMLElement) {
            const anchor = ev.target.closest(ORIG_A_SELECTOR);
            if (anchor) {
              ev.preventDefault();
              ev.stopImmediatePropagation();
              attachPopup(anchor);
            }
          }
        },
        true
        // Make it fire earlier than MF a.new handler
      );
    });
  });
}
mw.messages.set(ext_gadget_HanAssist.batchConv(messages, mw.config.get("wgUserVariant")));
getPreferences();
if (mw.config.get("wgMFMode")) {
  void mw.loader.using("mobile.startup").then((require2) => require2("mobile.startup")).then(({ getOverlayManager }) => {
    getOverlayManager();
    const overlayContainer = document.getElementsByClassName("mw-overlays-container")[0];
    if (!overlayContainer) {
      return;
    }
    const observer = new MutationObserver(() => {
      const veOverlay = overlayContainer.querySelector(".editor-overlay.editor-overlay-ve");
      document.documentElement.classList.toggle("ilhpp-inactive", !!veOverlay);
    });
    observer.observe(overlayContainer, {
      childList: true,
      attributes: true,
      attributeFilter: ["style"]
    });
  });
}
if (isMobileDevice()) {
  run();
} else {
  run$1();
}
exports.LinkMode = LinkMode;
exports.OrigLinkColor = OrigLinkColor;
exports.PopupMode = PopupMode;
exports.getPreferences = getPreferences;
exports.haveConflicts = haveConflicts;
exports.setPreferences = setPreferences;
// </nowiki>