openvibers/openvibe.shared Commits
Shared 2.13.2: the navbar never loads a second ov-mark.js (a page's own async tag that had not run yet) (#32)
Changes
@@@ -4,6 +4,12 @@ All notable changes to `openvibe-shared`. Versions follow [semver](https://semvebreaking change to any exported module, browser global or served file name is a new major.A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).++## 2.13.2 — 2026-10-08++++- The navbar loads `ov-mark.js` only when no `<script src=".../ov-mark.js">` is on the page yet: a page carrying its own async++ tag that had not run when the navbar rendered got a second copy (ovhost browser-check "script requested twice" on++ openvibe.coupons, .reviews, .services, .vip and openre.stream, 2026-10-08).++## 2.13.1 — 2026-10-08- `showcase` code samples are a focus stop with a name (`<pre tabindex="0" aria-label="…">`): a sample that scrolls@@@ -1335,8 +1335,9 @@const loginHref = resolveLoginHref(currentHost(), window.location.href);const addAccountHref = `${_config.apiBase}/login?add_account=1&return=${encodeURIComponent(window.location.href)}`;-- // The OV brand mark is a self-contained drop-in (mounts every .ov-mark it finds).-- if (!window.__ovMark && !document.getElementById('ov-mark-loader')) {++ // The OV brand mark is a self-contained drop-in (mounts every .ov-mark it finds). A page may already carry its own++ // async <script src=".../ov-mark.js?v=…"> that has not run yet: never load a second copy.++ if (!window.__ovMark && !document.getElementById('ov-mark-loader') && !(document.querySelector && document.querySelector('script[src*="/ov-mark.js"]'))) {try { const sc = document.createElement('script'); sc.id = 'ov-mark-loader'; sc.src = sibling('ov-mark.js'); sc.async = true; document.head.appendChild(sc); } catch { /* */ }}nav.innerHTML = `@@@ -1,12 +1,12 @@{"name": "openvibe-shared",-- "version": "2.13.1",++ "version": "2.13.2","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-shared",-- "version": "2.13.1",++ "version": "2.13.2","license": "MIT","dependencies": {"jsonwebtoken": "^9.0.0"@@@ -1,6 +1,6 @@{"name": "openvibe-shared",-- "version": "2.13.1",++ "version": "2.13.2","description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site","main": "index.js","bin": {@@@ -120,6 +120,16 @@ function load(hostname, opts = {}) {assert.strictEqual(n3.brand().name, 'Custom Name');assert.strictEqual(n3.brand().variant, 'games');}++// ── ov-mark.js is loaded once: not when the page already carries its own (async) tag ────++{++ const { navbar, created } = load('openvibe.coupons');++ navbar.init({ service: 'coupons', user: null });++ assert.strictEqual(created.filter((e) => e.tag === 'script' && e.id === 'ov-mark-loader').length, 1, 'no tag on the page: the navbar loads the mark');++ const second = load('openvibe.coupons');++ global.document.querySelector = (sel) => (sel === 'script[src*="/ov-mark.js"]' ? { src: '/shared/ov-mark.js?v=1' } : null);++ second.navbar.init({ service: 'coupons', user: null });++ assert.strictEqual(second.created.filter((e) => e.tag === 'script' && e.id === 'ov-mark-loader').length, 0, 'the page\'s own tag: no second copy');++}// ── rendered markup carries the segments, compact attr and the variant ────{const { navbar, created } = load('pastes.openvibe.tools', { pathname: '/mine' });
@@ -4,6 +4,12 @@ All notable changes to `openvibe-shared`. Versions follow [semver](https://semve
@@ -4,6 +4,12 @@ All notable changes to `openvibe-shared`. Versions follow [semver](https://semve
breaking change to any exported module, browser global or served file name is a new major.
breaking change to any exported module, browser global or served file name is a new major.
A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
+## 2.13.2 — 2026-10-08
+
+- The navbar loads `ov-mark.js` only when no `<script src=".../ov-mark.js">` is on the page yet: a page carrying its own async
+ tag that had not run when the navbar rendered got a second copy (ovhost browser-check "script requested twice" on
+ openvibe.coupons, .reviews, .services, .vip and openre.stream, 2026-10-08).
+
## 2.13.1 — 2026-10-08
## 2.13.1 — 2026-10-08
- `showcase` code samples are a focus stop with a name (`<pre tabindex="0" aria-label="…">`): a sample that scrolls
- `showcase` code samples are a focus stop with a name (`<pre tabindex="0" aria-label="…">`): a sample that scrolls
@@ -1335,8 +1335,9 @@
@@ -1335,8 +1335,9 @@
const loginHref = resolveLoginHref(currentHost(), window.location.href);
const loginHref = resolveLoginHref(currentHost(), window.location.href);
const addAccountHref = `${_config.apiBase}/login?add_account=1&return=${encodeURIComponent(window.location.href)}`;
const addAccountHref = `${_config.apiBase}/login?add_account=1&return=${encodeURIComponent(window.location.href)}`;
- // The OV brand mark is a self-contained drop-in (mounts every .ov-mark it finds).
- if (!window.__ovMark && !document.getElementById('ov-mark-loader')) {
+ // The OV brand mark is a self-contained drop-in (mounts every .ov-mark it finds). A page may already carry its own
+ // async <script src=".../ov-mark.js?v=…"> that has not run yet: never load a second copy.
+ if (!window.__ovMark && !document.getElementById('ov-mark-loader') && !(document.querySelector && document.querySelector('script[src*="/ov-mark.js"]'))) {
try { const sc = document.createElement('script'); sc.id = 'ov-mark-loader'; sc.src = sibling('ov-mark.js'); sc.async = true; document.head.appendChild(sc); } catch { /* */ }
try { const sc = document.createElement('script'); sc.id = 'ov-mark-loader'; sc.src = sibling('ov-mark.js'); sc.async = true; document.head.appendChild(sc); } catch { /* */ }
}
}
nav.innerHTML = `
nav.innerHTML = `
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-shared",
"name": "openvibe-shared",
- "version": "2.13.1",
+ "version": "2.13.2",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-shared",
"name": "openvibe-shared",
- "version": "2.13.1",
+ "version": "2.13.2",
"license": "MIT",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0"
"jsonwebtoken": "^9.0.0"
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-shared",
"name": "openvibe-shared",
- "version": "2.13.1",
+ "version": "2.13.2",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"main": "index.js",
"main": "index.js",
"bin": {
"bin": {
@@ -120,6 +120,16 @@ function load(hostname, opts = {}) {
@@ -120,6 +120,16 @@ function load(hostname, opts = {}) {
assert.strictEqual(n3.brand().name, 'Custom Name');
assert.strictEqual(n3.brand().name, 'Custom Name');
assert.strictEqual(n3.brand().variant, 'games');
assert.strictEqual(n3.brand().variant, 'games');
}
}
+// ── ov-mark.js is loaded once: not when the page already carries its own (async) tag ────
+{
+ const { navbar, created } = load('openvibe.coupons');
+ navbar.init({ service: 'coupons', user: null });
+ assert.strictEqual(created.filter((e) => e.tag === 'script' && e.id === 'ov-mark-loader').length, 1, 'no tag on the page: the navbar loads the mark');
+ const second = load('openvibe.coupons');
+ global.document.querySelector = (sel) => (sel === 'script[src*="/ov-mark.js"]' ? { src: '/shared/ov-mark.js?v=1' } : null);
+ second.navbar.init({ service: 'coupons', user: null });
+ assert.strictEqual(second.created.filter((e) => e.tag === 'script' && e.id === 'ov-mark-loader').length, 0, 'the page\'s own tag: no second copy');
+}
// ── rendered markup carries the segments, compact attr and the variant ────
// ── rendered markup carries the segments, compact attr and the variant ────
{
{
const { navbar, created } = load('pastes.openvibe.tools', { pathname: '/mine' });
const { navbar, created } = load('pastes.openvibe.tools', { pathname: '/mine' });