PageSourceSearch

https://marketplace.onekeyco.com/assets/mmos_brand/js/mmos_brand.js

js onekeyco.com collected 2026-09-24 14:49:20 UTC 8,318 bytes, 208 lines download raw bytes

1/* =========================================================
2   MMOS Brand — global JS overrides for all Frappe apps
3   Injected via web_include_js / app_include_js
4   ========================================================= */
5
6(function () {
7  "use strict";
8
9  const ROOT    = "https://onekeyco.com";
10  const MAIL    = "https://mail.onekeyco.com/mail/";
11  const DOCS    = "https://onekeyco.com/docs";
12  const SUPPORT = "https://onekeyco.com/support";
13
14  // ── Link rewriting ──────────────────────────────────────
15  const REWRITE_MAP = [
16    { match: /frappe\.io/i,          replace: ROOT },
17    { match: /frappeframework/i,     replace: ROOT },
18    { match: /erpnext\.com/i,        replace: ROOT },
19    { match: /discuss\.frappe/i,     replace: SUPPORT },
20    { match: /github\.com\/frappe/i, replace: DOCS },
21    { match: /frappemail\.com/i,     replace: MAIL },
22  ];
23
24  function mapHref(href) {
25    if (!href || href.startsWith("#") || href.startsWith("mailto:")) return href;
26    try {
27      const u = new URL(href, window.location.origin);
28      const h = u.hostname.toLowerCase();
29      if (h.endsWith("onekeyco.com") || h === window.location.hostname) return href;
30      if (u.pathname.startsWith("/mail")) return MAIL;
31      for (const rule of REWRITE_MAP) {
32        if (rule.match.test(href)) return rule.replace;
33      }
34    } catch (_) {}
35    return href;
36  }
37
38  function rewriteLinks(root) {
39    (root || document).querySelectorAll("a[href]").forEach(function (a) {
40      const href = a.getAttribute("href");
41      if (!href) return;
42      if (a.dataset.mmosHref === href) return;
43      const next = mapHref(href);
44      if (next && next !== href) a.setAttribute("href", next);
45      a.dataset.mmosHref = a.getAttribute("href") || href;
46    });
47  }
48
49  function deferRewrite(root) {
50    if (window.requestIdleCallback) {
51      requestIdleCallback(function () { rewriteLinks(root); }, { timeout: 500 });
52      return;
53    }
54    setTimeout(function () { rewriteLinks(root); }, 60);
55  }
56
57  // ── Desk help menu override ─────────────────────────────
58  function patchHelpMenu() {
59    if (!window.frappe || !frappe.ui || !frappe.ui.toolbar) return;
60    const origHelp = frappe.ui.toolbar.show_help;
61    if (origHelp && !origHelp._mmos_patched) {
62      frappe.ui.toolbar.show_help = function () {
63        origHelp.apply(this, arguments);
64        deferRewrite();
65        setTimeout(function () {
66          const menu = document.querySelector(".navbar-help .dropdown-menu");
67          if (menu) rewriteLinks(menu);
68        }, 100);
69      };
70      frappe.ui.toolbar.show_help._mmos_patched = true;
71    }
72    // Also patch frappe.help_feedback_link
73    if (window.frappe) frappe.help_feedback_link = SUPPORT;
74  }
75
76  // ── Boot info override ──────────────────────────────────
77  function applyBootBranding() {
78    if (!window.frappe || !frappe.boot || !frappe.boot.mmos_branding) return;
79    const b = frappe.boot.mmos_branding;
80    if (b.brand_name) {
81      frappe.boot.app_name = b.brand_name;
82      document.title = document.title.replace(/\b(Frappe|ERPNext)\b/g, b.brand_name);
83    }
84    frappe.help_feedback_link = SUPPORT;
85  }
86
87  // ── Navbar brand text ───────────────────────────────────
88  function patchNavbarBrand() {
89    document.querySelectorAll(".navbar-brand .navbar-home span, .brand-name").forEach(function (el) {
90      if (el.textContent.trim() === "Frappe" || el.textContent.trim() === "ERPNext") {
91        el.textContent = "MMOS";
92      }
93    });
94  }
95
96  // ── Login page ──────────────────────────────────────────
97  function patchLoginPage() {
98    document.querySelectorAll(".login-footer, .login-content footer").forEach(function (el) {
99      el.innerHTML = '<small>Powered by <a href="' + ROOT + '">MMOS Platform</a></small>';
100    });
101  }
102
103  // ── Modal accessibility guard ──────────────────────────
104  function patchModalFocus() {
105    const handler = function (e) {
106      const modal = e && e.target;
107      const active = document.activeElement;
108      if (modal && active && modal.contains(active) && typeof active.blur === "function") {
109        active.blur();
110      }
111    };
112    document.addEventListener("hide.bs.modal", handler);
113    document.addEventListener("hidden.bs.modal", handler);
114  }
115
116  // ── MutationObserver for Vue/React SPAs ────────────────
117  function startObserver() {
118    if (!window.MutationObserver || !document.body) return;
119    new MutationObserver(function (mutations) {
120      mutations.forEach(function (m) {
121        m.addedNodes.forEach(function (node) {
122          if (node.nodeType === 1) deferRewrite(node);
123        });
124      });
125    }).observe(document.body, { childList: true, subtree: true });
126  }
127
128  // ── Init ────────────────────────────────────────────────
129  function init() {
130    rewriteLinks();
131    patchLoginPage();
132    patchNavbarBrand();
133    applyBootBranding();
134    patchHelpMenu();
135    startObserver();
136    patchModalFocus();
137  }
138
139  if (document.readyState === "loading") {
140    document.addEventListener("DOMContentLoaded", init);
141  } else {
142    init();
143  }
144
145  // Frappe desk fully booted
146  document.addEventListener("frappe:ready", function () {
147    applyBootBranding();
148    patchHelpMenu();
149    deferRewrite();
150  });
151
152  // Desk page navigation (frappe.router)
153  setTimeout(function () {
154    if (window.frappe && frappe.router && frappe.router.on) {
155      frappe.router.on("change", function () {
156        setTimeout(function () { deferRewrite(); patchNavbarBrand(); }, 120);
157      });
158    }
159  }, 2000);
160})();
161/* ── MMOS cookie banner (auto-iniettato solo dove esistono pagine legali) ── */
162(function () {
163  "use strict";
164  function ready(fn) {
165    if (document.readyState !== "loading") fn();
166    else document.addEventListener("DOMContentLoaded", fn);
167  }
168  ready(function () {
169    try {
170      if (localStorage.getItem("mmos_cookie_consent")) return;
171      // gating: mostra il banner solo se la pagina ha un link alle pagine legali
172      var hasLegal = document.querySelector('a[href="/privacy"], a[href$="/privacy"], a[href$="/privacy.html"]');
173      if (!hasLegal) return;
174      if (document.querySelector(".mmos-cookie")) return;
175      var el = document.createElement("div");
176      el.className = "mmos-cookie";
177      el.innerHTML = '<p>Usiamo solo cookie tecnici e funzionali. Dettagli nella ' +
178        '<a href="/cookie">Cookie Policy</a> e nella <a href="/privacy">Privacy Policy</a>.</p>' +
179        '<div class="mmos-cookie-actions">' +
180        '<button class="mmos-cookie-ok" type="button">Accetta</button>' +
181        '<button class="mmos-cookie-no" type="button">Rifiuta</button></div>';
182      document.body.appendChild(el);
183      setTimeout(function () { el.classList.add("is-visible"); }, 1000);
184      function close(v) { return function () { localStorage.setItem("mmos_cookie_consent", v); el.classList.remove("is-visible"); }; }
185      el.querySelector(".mmos-cookie-ok").addEventListener("click", close("accepted"));
186      el.querySelector(".mmos-cookie-no").addEventListener("click", close("rejected"));
187    } catch (e) {}
188  });
189})();
190
191/* ── Relabel del bottone social 'Login with Frappe' → MMOS ID ──
192   Scoped a /login e safe: se non c'è il bottone (siti senza SSO frappe) non fa nulla.
193   Sposta il bottone in cima e lo evidenzia. */
194(function () {
195  if (!/^\/login/.test(location.pathname)) return;
196  function relabel() {
197    var btn = document.querySelector('a.btn-frappe');
198    if (btn && !btn.dataset.mmosid) {
199      btn.dataset.mmosid = '1';
200      btn.textContent = '🔐 Accedi con MMOS ID';
201      btn.style.fontWeight = '600';
202    }
203  }
204  var obs = new MutationObserver(relabel);
205  obs.observe(document.documentElement, { childList: true, subtree: true });
206  document.addEventListener('DOMContentLoaded', relabel);
207  relabel();
208})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.