(Install package: clbiwiki-mainpage-attached-section-bottom-visible-gap-2px-20260717 / PortalSectionNav.js) |
(Install package: clbiwiki-portal-frame-display-fix-20260717 / js/PortalSectionNav.js) |
||
| 7번째 줄: | 7번째 줄: | ||
'use strict'; | 'use strict'; | ||
var XLINK_NS = 'http://www.w3.org/1999/xlink'; | var XLINK_NS = 'http://www.w3.org/1999/xlink'; | ||
var COMPONENT = 'portal-section-nav'; | var COMPONENT = 'portal-section-nav'; | ||
var VERSION = '20260717- | var VERSION = '20260717-shared-frame-phase-001'; | ||
var renderTimer = 0; | var renderTimer = 0; | ||
var ITEMS = [ | var ITEMS = [ | ||
{ key:'black-ice', label:'블랙 아이스', title:'대문' }, | { key:'black-ice', label:'블랙 아이스', title:'대문' }, | ||
{ | { key:'anecdote', label:'에넥도트', href:'/index.php/특수:모든문서?namespace=3000' } | ||
]; | ]; | ||
function | function api() { | ||
return | return window.CLBI && window.CLBI.frame; | ||
} | } | ||
function buildWikiPath(title) { | function buildWikiPath(title) { | ||
if (typeof window.buildWikiPath === 'function') | if (typeof window.buildWikiPath === 'function') return window.buildWikiPath(title); | ||
return '/index.php/' + encodeURI(String(title || '').replace(/ /g, '_')); | return '/index.php/' + encodeURI(String(title || '').replace(/ /g, '_')); | ||
} | } | ||
function ensureMount(portal, topMount) { | function ensureMount(portal, topMount) { | ||
var mount = portal.querySelector('[data-component="' + COMPONENT + '"]'); | var mount = portal.querySelector('[data-component="' + COMPONENT + '"]'); | ||
if (!mount) { | if (!mount) { | ||
mount = document.createElement('div'); | mount = document.createElement('div'); | ||
mount.setAttribute('data-component', COMPONENT); | mount.setAttribute('data-component', COMPONENT); | ||
} | } | ||
if (mount.parentNode !== topMount.parentNode || topMount.nextSibling !== mount) { | if (mount.parentNode !== topMount.parentNode || topMount.nextSibling !== mount) { | ||
topMount.parentNode.insertBefore(mount, topMount.nextSibling); | topMount.parentNode.insertBefore(mount, topMount.nextSibling); | ||
| 139번째 줄: | 37번째 줄: | ||
} | } | ||
function | function outerGeometry(seams) { | ||
var | var frame = api(); | ||
var d = frame.DIMENSIONS; | |||
var phase = seams.bottomStartAbsY % frame.FRAME.SLANT_RISE; | |||
var leftSeamX = frame.slantX( | |||
seams.settingsLeftTopX, | |||
seams.bottomStartAbsY, | |||
seams.settingsLeftDir, | |||
0 | |||
); | |||
var rightSeamX = frame.slantX( | |||
seams.corpRightTopX, | |||
seams.bottomStartAbsY, | |||
seams.corpRightDir, | |||
0 | |||
); | |||
var | |||
var | |||
var | |||
return { | return { | ||
phase:phase, | |||
leftSeamX:leftSeamX, | |||
rightSeamX:rightSeamX, | |||
leftDir:seams.settingsLeftDir, | |||
rightDir:seams.corpRightDir, | |||
points:frame.segment( | |||
leftSeamX, | |||
rightSeamX, | |||
d.ROW_HEIGHT, | |||
seams.settingsLeftDir, | |||
seams.corpRightDir, | |||
phase | |||
) | |||
}; | }; | ||
} | } | ||
function appendFrame(svg, | function appendFrame(svg, geometry) { | ||
var | var frame = api(); | ||
var | var f = frame.FRAME; | ||
var | var d = frame.DIMENSIONS; | ||
var | var group = frame.create('g', 'portal-section-frame'); | ||
var | var surface = frame.segmentAt( | ||
geometry.leftSeamX, | |||
geometry.rightSeamX, | |||
f.BORDER, | |||
d.ROW_HEIGHT - f.BORDER, | |||
geometry.leftDir, | |||
geometry.rightDir, | |||
geometry.phase, | |||
var | f.BORDER, | ||
f.BORDER | |||
); | |||
var well = frame.segmentAt( | |||
geometry.leftSeamX, | |||
geometry.rightSeamX, | |||
f.FRAME_FACE, | |||
d.ROW_HEIGHT - f.FRAME_FACE, | |||
geometry.leftDir, | |||
geometry.rightDir, | |||
geometry.phase, | |||
f.FRAME_FACE, | |||
f.FRAME_FACE | |||
); | |||
var joinCover = frame.segmentAt( | |||
geometry.leftSeamX, | |||
geometry.rightSeamX, | |||
0, | |||
d.OVERLAP, | |||
geometry.leftDir, | |||
geometry.rightDir, | |||
geometry.phase, | |||
0, | |||
0 | |||
); | |||
var sideBevel = frame.segmentAt( | |||
geometry.leftSeamX, | |||
geometry.rightSeamX, | |||
d.OVERLAP, | |||
d.ROW_HEIGHT - f.BORDER, | |||
geometry.leftDir, | |||
geometry.rightDir, | |||
geometry.phase, | |||
f.BORDER + f.BEVEL, | |||
f.BORDER + f.BEVEL | |||
); | |||
group. | group.appendChild(frame.polygon('portal-section-frame-edge', geometry.points)); | ||
group.appendChild(frame.polygon('portal-section-frame-surface', surface)); | |||
group.appendChild( | group.appendChild(frame.polygon('portal-section-frame-well', well)); | ||
group.appendChild( | group.appendChild(frame.polygon('portal-section-join-side-cover', joinCover)); | ||
group.appendChild(frame.line('portal-section-frame-shadow', sideBevel[3], sideBevel[0])); | |||
group.appendChild(frame.line('portal-section-frame-highlight', sideBevel[1], sideBevel[2])); | |||
group.appendChild( | group.appendChild(frame.line('portal-section-well-shadow', well[0], well[1])); | ||
group.appendChild( | group.appendChild(frame.line('portal-section-well-shadow', well[1], well[2])); | ||
group.appendChild(frame.line('portal-section-well-highlight', well[3], well[0])); | |||
group.appendChild(frame.line('portal-section-well-highlight', well[2], well[3])); | |||
group.appendChild( | |||
group.appendChild( | |||
group.appendChild( | |||
group.appendChild( | |||
group.appendChild( | |||
svg.appendChild(group); | svg.appendChild(group); | ||
} | } | ||
function splitButtons( | function splitButtons(geometry) { | ||
var | var frame = api(); | ||
var topMid = ( | var f = frame.FRAME; | ||
var | var d = frame.DIMENSIONS; | ||
var leftBase = geometry.leftSeamX + f.FRAME_FACE + f.GAP; | |||
var rightBase = geometry.rightSeamX - f.FRAME_FACE - f.GAP; | |||
var leftTop = frame.slantX(leftBase, d.BUTTON_TOP, geometry.leftDir, geometry.phase); | |||
var rightTop = frame.slantX(rightBase, d.BUTTON_TOP, geometry.rightDir, geometry.phase); | |||
var topMid = Math.round((leftTop + rightTop) / 2); | |||
var halfGap = f.GAP / 2; | |||
return [ | return [ | ||
{ | |||
leftTopX:leftBase, | |||
rightTopX:topMid - halfGap, | |||
leftDir:geometry.leftDir, | |||
rightDir:0, | |||
phase:geometry.phase | |||
}, | |||
{ | |||
leftTopX:topMid + halfGap, | |||
rightTopX:rightBase, | |||
leftDir:0, | |||
rightDir:geometry.rightDir, | |||
phase:geometry.phase | |||
} | |||
]; | ]; | ||
} | } | ||
function appendButton(svg, item, | function appendButton(svg, item, button) { | ||
var | var frame = api(); | ||
var | var f = frame.FRAME; | ||
var | var d = frame.DIMENSIONS; | ||
var points = frame.segmentAt( | |||
button.leftTopX, | |||
button.rightTopX, | |||
d.BUTTON_TOP, | |||
d.BUTTON_BOTTOM, | |||
button.leftDir, | |||
button.rightDir, | |||
button.phase, | |||
0, | |||
0 | |||
); | ); | ||
var | var surface = frame.segmentAt( | ||
button.leftTopX, | |||
button.rightTopX, | |||
d.BUTTON_TOP + f.BORDER, | |||
d.BUTTON_BOTTOM - f.BORDER, | |||
button.leftDir, | |||
button.rightDir, | |||
button.phase, | |||
f.BORDER, | |||
f.BORDER | |||
); | ); | ||
var | var bevel = frame.segmentAt( | ||
var | button.leftTopX, | ||
var hit = | button.rightTopX, | ||
d.BUTTON_TOP + f.BORDER + f.BEVEL, | |||
d.BUTTON_BOTTOM - f.BORDER - f.BEVEL, | |||
button.leftDir, | |||
button.rightDir, | |||
button.phase, | |||
f.BORDER + f.BEVEL, | |||
f.BORDER + f.BEVEL | |||
); | |||
var anchor = frame.create('a', 'portal-cat-anchor portal-section-anchor'); | |||
var group = frame.create('g', 'portal-section-button-geometry'); | |||
var hit = frame.polygon('portal-cat-hit', points); | |||
var text = frame.create('text', 'portal-cat-label portal-section-label'); | |||
var href = item.href || buildWikiPath(item.title); | var href = item.href || buildWikiPath(item.title); | ||
anchor.setAttribute('data-category-key', item.key); | anchor.setAttribute('data-category-key', item.key); | ||
anchor.setAttribute('href', href); | anchor.setAttribute('href', href); | ||
anchor.setAttributeNS(XLINK_NS, 'xlink:href', href); | anchor.setAttributeNS(XLINK_NS, 'xlink:href', href); | ||
anchor.setAttribute('aria-label', item.label); | anchor.setAttribute('aria-label', item.label); | ||
group.appendChild(frame.polygon('portal-cat-edge', points)); | |||
group.appendChild(frame.polygon('portal-cat-surface', surface)); | |||
group.appendChild(frame.line('portal-cat-inset portal-cat-inset-top', bevel[0], bevel[1])); | |||
group.appendChild(frame.line('portal-cat-inset portal-cat-inset-right', bevel[1], bevel[2])); | |||
group.appendChild(frame.line('portal-cat-inset portal-cat-inset-bottom', bevel[2], bevel[3])); | |||
group.appendChild(frame.line('portal-cat-inset portal-cat-inset-left', bevel[3], bevel[0])); | |||
hit.setAttribute('pointer-events', 'all'); | hit.setAttribute('pointer-events', 'all'); | ||
group.appendChild(hit); | |||
anchor.appendChild(group); | |||
text.setAttribute(' | text.setAttribute('x', frame.centerX(surface)); | ||
text.setAttribute(' | text.setAttribute('y', Math.round((d.BUTTON_TOP + d.BUTTON_BOTTOM) / 2) + 1); | ||
text.setAttribute(' | text.setAttribute('font-size', '12'); | ||
text.setAttribute('font-weight', '700'); | |||
text.setAttribute('text-anchor', 'middle'); | |||
text.setAttribute('dominant-baseline', 'middle'); | |||
text.textContent = item.label; | text.textContent = item.label; | ||
anchor.appendChild(text); | anchor.appendChild(text); | ||
svg.appendChild(anchor); | svg.appendChild(anchor); | ||
} | } | ||
function renderPortal(portal) { | function renderPortal(portal, seams) { | ||
var | var frame = api(); | ||
var current = seams || (frame && frame.seams); | |||
var topMount; | |||
var mount; | var mount; | ||
var | var nav; | ||
var | var svg; | ||
var geometry; | var geometry; | ||
var buttons; | var buttons; | ||
if (! | if (!frame || !portal || !current || !current.width) return false; | ||
topMount = portal.querySelector('[data-component="category-nav"]'); | |||
if (!topMount) return false; | |||
mount = ensureMount(portal, topMount); | mount = ensureMount(portal, topMount); | ||
geometry = outerGeometry(current); | |||
buttons = splitButtons(geometry); | |||
geometry = | |||
buttons = splitButtons( | |||
nav = document.createElement('nav'); | nav = document.createElement('nav'); | ||
nav.className = 'portal-section-nav'; | nav.className = 'portal-section-nav'; | ||
nav.setAttribute('aria-label', '작품 영역'); | nav.setAttribute('aria-label', '작품 영역'); | ||
svg. | svg = frame.create('svg', 'portal-section-svg'); | ||
svg.setAttribute('viewBox', '0 0 ' + width + ' ' + ROW_HEIGHT); | svg.setAttribute('viewBox', '0 0 ' + current.width + ' ' + frame.DIMENSIONS.ROW_HEIGHT); | ||
svg.setAttribute('width', '100%'); | svg.setAttribute('width', '100%'); | ||
svg.setAttribute('height', | svg.setAttribute('height', frame.DIMENSIONS.ROW_HEIGHT); | ||
svg.setAttribute('preserveAspectRatio', 'none'); | svg.setAttribute('preserveAspectRatio', 'none'); | ||
svg.setAttribute('data-frame-width', current.width); | |||
appendFrame(svg | appendFrame(svg, geometry); | ||
ITEMS.forEach(function (item, index) { | ITEMS.forEach(function (item, index) { appendButton(svg, item, buttons[index]); }); | ||
nav.appendChild(svg); | nav.appendChild(svg); | ||
mount.replaceChildren(nav); | mount.replaceChildren(nav); | ||
mount.setAttribute('data-portal-section-rendered', '1'); | mount.setAttribute('data-portal-section-rendered', '1'); | ||
mount.setAttribute('data-portal-section-width', String(width)); | mount.setAttribute('data-portal-section-width', String(current.width)); | ||
mount.setAttribute('data-portal-section-phase', String(geometry.phase)); | |||
return true; | return true; | ||
} | } | ||
| 436번째 줄: | 270번째 줄: | ||
var scope = root && root.querySelectorAll ? root : document; | var scope = root && root.querySelectorAll ? root : document; | ||
var portals = []; | var portals = []; | ||
if (scope.matches && scope.matches('.main-portal')) portals.push(scope); | if (scope.matches && scope.matches('.main-portal')) portals.push(scope); | ||
Array.prototype.forEach.call(scope.querySelectorAll('.main-portal'), function (portal) { | Array.prototype.forEach.call(scope.querySelectorAll('.main-portal'), function (portal) { | ||
| 444번째 줄: | 277번째 줄: | ||
} | } | ||
function renderAll(root) { | function renderAll(root, seams) { | ||
var rendered = 0; | var rendered = 0; | ||
collectPortals(root).forEach(function (portal) { | collectPortals(root).forEach(function (portal) { | ||
if (renderPortal(portal)) rendered += 1; | if (renderPortal(portal, seams)) rendered += 1; | ||
}); | }); | ||
return rendered; | return rendered; | ||
} | } | ||
function | function schedule(root, seams) { | ||
window.clearTimeout(renderTimer); | window.clearTimeout(renderTimer); | ||
renderTimer = window.setTimeout(function () { | renderTimer = window.setTimeout(function () { | ||
renderTimer = 0; | renderTimer = 0; | ||
renderAll(root || document); | renderAll(root || document, seams); | ||
}, 0); | }, 0); | ||
} | } | ||
if (api()) api().onSeams(function (seams) { schedule(document, seams); }); | |||
if (mw && mw.hook) { | if (mw && mw.hook) { | ||
mw.hook('wikipage.content').add(function (content) { | mw.hook('wikipage.content').add(function (content) { | ||
schedule(content && content[0] ? content[0] : document); | |||
}); | }); | ||
} | } | ||
window.PortalSectionNav = { | |||
window.PortalSectionNav = { | |||
version:VERSION, | version:VERSION, | ||
init: | init:renderAll, | ||
render:renderPortal, | render:renderPortal, | ||
renderAll:renderAll | renderAll:renderAll | ||
}; | }; | ||
}(window, document, window.mw)); | }(window, document, window.mw)); | ||
2026년 7월 17일 (금) 10:35 판
/* =========================================
PortalSectionNav
대문 상단 카테고리 하단 부착형 섹션 버튼
========================================= */
(function (window, document, mw) {
'use strict';
var XLINK_NS = 'http://www.w3.org/1999/xlink';
var COMPONENT = 'portal-section-nav';
var VERSION = '20260717-shared-frame-phase-001';
var renderTimer = 0;
var ITEMS = [
{ key:'black-ice', label:'블랙 아이스', title:'대문' },
{ key:'anecdote', label:'에넥도트', href:'/index.php/특수:모든문서?namespace=3000' }
];
function api() {
return window.CLBI && window.CLBI.frame;
}
function buildWikiPath(title) {
if (typeof window.buildWikiPath === 'function') return window.buildWikiPath(title);
return '/index.php/' + encodeURI(String(title || '').replace(/ /g, '_'));
}
function ensureMount(portal, topMount) {
var mount = portal.querySelector('[data-component="' + COMPONENT + '"]');
if (!mount) {
mount = document.createElement('div');
mount.setAttribute('data-component', COMPONENT);
}
if (mount.parentNode !== topMount.parentNode || topMount.nextSibling !== mount) {
topMount.parentNode.insertBefore(mount, topMount.nextSibling);
}
return mount;
}
function outerGeometry(seams) {
var frame = api();
var d = frame.DIMENSIONS;
var phase = seams.bottomStartAbsY % frame.FRAME.SLANT_RISE;
var leftSeamX = frame.slantX(
seams.settingsLeftTopX,
seams.bottomStartAbsY,
seams.settingsLeftDir,
0
);
var rightSeamX = frame.slantX(
seams.corpRightTopX,
seams.bottomStartAbsY,
seams.corpRightDir,
0
);
return {
phase:phase,
leftSeamX:leftSeamX,
rightSeamX:rightSeamX,
leftDir:seams.settingsLeftDir,
rightDir:seams.corpRightDir,
points:frame.segment(
leftSeamX,
rightSeamX,
d.ROW_HEIGHT,
seams.settingsLeftDir,
seams.corpRightDir,
phase
)
};
}
function appendFrame(svg, geometry) {
var frame = api();
var f = frame.FRAME;
var d = frame.DIMENSIONS;
var group = frame.create('g', 'portal-section-frame');
var surface = frame.segmentAt(
geometry.leftSeamX,
geometry.rightSeamX,
f.BORDER,
d.ROW_HEIGHT - f.BORDER,
geometry.leftDir,
geometry.rightDir,
geometry.phase,
f.BORDER,
f.BORDER
);
var well = frame.segmentAt(
geometry.leftSeamX,
geometry.rightSeamX,
f.FRAME_FACE,
d.ROW_HEIGHT - f.FRAME_FACE,
geometry.leftDir,
geometry.rightDir,
geometry.phase,
f.FRAME_FACE,
f.FRAME_FACE
);
var joinCover = frame.segmentAt(
geometry.leftSeamX,
geometry.rightSeamX,
0,
d.OVERLAP,
geometry.leftDir,
geometry.rightDir,
geometry.phase,
0,
0
);
var sideBevel = frame.segmentAt(
geometry.leftSeamX,
geometry.rightSeamX,
d.OVERLAP,
d.ROW_HEIGHT - f.BORDER,
geometry.leftDir,
geometry.rightDir,
geometry.phase,
f.BORDER + f.BEVEL,
f.BORDER + f.BEVEL
);
group.appendChild(frame.polygon('portal-section-frame-edge', geometry.points));
group.appendChild(frame.polygon('portal-section-frame-surface', surface));
group.appendChild(frame.polygon('portal-section-frame-well', well));
group.appendChild(frame.polygon('portal-section-join-side-cover', joinCover));
group.appendChild(frame.line('portal-section-frame-shadow', sideBevel[3], sideBevel[0]));
group.appendChild(frame.line('portal-section-frame-highlight', sideBevel[1], sideBevel[2]));
group.appendChild(frame.line('portal-section-well-shadow', well[0], well[1]));
group.appendChild(frame.line('portal-section-well-shadow', well[1], well[2]));
group.appendChild(frame.line('portal-section-well-highlight', well[3], well[0]));
group.appendChild(frame.line('portal-section-well-highlight', well[2], well[3]));
svg.appendChild(group);
}
function splitButtons(geometry) {
var frame = api();
var f = frame.FRAME;
var d = frame.DIMENSIONS;
var leftBase = geometry.leftSeamX + f.FRAME_FACE + f.GAP;
var rightBase = geometry.rightSeamX - f.FRAME_FACE - f.GAP;
var leftTop = frame.slantX(leftBase, d.BUTTON_TOP, geometry.leftDir, geometry.phase);
var rightTop = frame.slantX(rightBase, d.BUTTON_TOP, geometry.rightDir, geometry.phase);
var topMid = Math.round((leftTop + rightTop) / 2);
var halfGap = f.GAP / 2;
return [
{
leftTopX:leftBase,
rightTopX:topMid - halfGap,
leftDir:geometry.leftDir,
rightDir:0,
phase:geometry.phase
},
{
leftTopX:topMid + halfGap,
rightTopX:rightBase,
leftDir:0,
rightDir:geometry.rightDir,
phase:geometry.phase
}
];
}
function appendButton(svg, item, button) {
var frame = api();
var f = frame.FRAME;
var d = frame.DIMENSIONS;
var points = frame.segmentAt(
button.leftTopX,
button.rightTopX,
d.BUTTON_TOP,
d.BUTTON_BOTTOM,
button.leftDir,
button.rightDir,
button.phase,
0,
0
);
var surface = frame.segmentAt(
button.leftTopX,
button.rightTopX,
d.BUTTON_TOP + f.BORDER,
d.BUTTON_BOTTOM - f.BORDER,
button.leftDir,
button.rightDir,
button.phase,
f.BORDER,
f.BORDER
);
var bevel = frame.segmentAt(
button.leftTopX,
button.rightTopX,
d.BUTTON_TOP + f.BORDER + f.BEVEL,
d.BUTTON_BOTTOM - f.BORDER - f.BEVEL,
button.leftDir,
button.rightDir,
button.phase,
f.BORDER + f.BEVEL,
f.BORDER + f.BEVEL
);
var anchor = frame.create('a', 'portal-cat-anchor portal-section-anchor');
var group = frame.create('g', 'portal-section-button-geometry');
var hit = frame.polygon('portal-cat-hit', points);
var text = frame.create('text', 'portal-cat-label portal-section-label');
var href = item.href || buildWikiPath(item.title);
anchor.setAttribute('data-category-key', item.key);
anchor.setAttribute('href', href);
anchor.setAttributeNS(XLINK_NS, 'xlink:href', href);
anchor.setAttribute('aria-label', item.label);
group.appendChild(frame.polygon('portal-cat-edge', points));
group.appendChild(frame.polygon('portal-cat-surface', surface));
group.appendChild(frame.line('portal-cat-inset portal-cat-inset-top', bevel[0], bevel[1]));
group.appendChild(frame.line('portal-cat-inset portal-cat-inset-right', bevel[1], bevel[2]));
group.appendChild(frame.line('portal-cat-inset portal-cat-inset-bottom', bevel[2], bevel[3]));
group.appendChild(frame.line('portal-cat-inset portal-cat-inset-left', bevel[3], bevel[0]));
hit.setAttribute('pointer-events', 'all');
group.appendChild(hit);
anchor.appendChild(group);
text.setAttribute('x', frame.centerX(surface));
text.setAttribute('y', Math.round((d.BUTTON_TOP + d.BUTTON_BOTTOM) / 2) + 1);
text.setAttribute('font-size', '12');
text.setAttribute('font-weight', '700');
text.setAttribute('text-anchor', 'middle');
text.setAttribute('dominant-baseline', 'middle');
text.textContent = item.label;
anchor.appendChild(text);
svg.appendChild(anchor);
}
function renderPortal(portal, seams) {
var frame = api();
var current = seams || (frame && frame.seams);
var topMount;
var mount;
var nav;
var svg;
var geometry;
var buttons;
if (!frame || !portal || !current || !current.width) return false;
topMount = portal.querySelector('[data-component="category-nav"]');
if (!topMount) return false;
mount = ensureMount(portal, topMount);
geometry = outerGeometry(current);
buttons = splitButtons(geometry);
nav = document.createElement('nav');
nav.className = 'portal-section-nav';
nav.setAttribute('aria-label', '작품 영역');
svg = frame.create('svg', 'portal-section-svg');
svg.setAttribute('viewBox', '0 0 ' + current.width + ' ' + frame.DIMENSIONS.ROW_HEIGHT);
svg.setAttribute('width', '100%');
svg.setAttribute('height', frame.DIMENSIONS.ROW_HEIGHT);
svg.setAttribute('preserveAspectRatio', 'none');
svg.setAttribute('data-frame-width', current.width);
appendFrame(svg, geometry);
ITEMS.forEach(function (item, index) { appendButton(svg, item, buttons[index]); });
nav.appendChild(svg);
mount.replaceChildren(nav);
mount.setAttribute('data-portal-section-rendered', '1');
mount.setAttribute('data-portal-section-width', String(current.width));
mount.setAttribute('data-portal-section-phase', String(geometry.phase));
return true;
}
function collectPortals(root) {
var scope = root && root.querySelectorAll ? root : document;
var portals = [];
if (scope.matches && scope.matches('.main-portal')) portals.push(scope);
Array.prototype.forEach.call(scope.querySelectorAll('.main-portal'), function (portal) {
if (portals.indexOf(portal) === -1) portals.push(portal);
});
return portals;
}
function renderAll(root, seams) {
var rendered = 0;
collectPortals(root).forEach(function (portal) {
if (renderPortal(portal, seams)) rendered += 1;
});
return rendered;
}
function schedule(root, seams) {
window.clearTimeout(renderTimer);
renderTimer = window.setTimeout(function () {
renderTimer = 0;
renderAll(root || document, seams);
}, 0);
}
if (api()) api().onSeams(function (seams) { schedule(document, seams); });
if (mw && mw.hook) {
mw.hook('wikipage.content').add(function (content) {
schedule(content && content[0] ? content[0] : document);
});
}
window.PortalSectionNav = {
version:VERSION,
init:renderAll,
render:renderPortal,
renderAll:renderAll
};
}(window, document, window.mw));