(Install package: clbiwiki-mainpage-visual-pixel-fix-20260712 / js/CategoryNav.js) |
(Install package: clbiwiki-frame-geometry-normalized-20260717 / js/CategoryNav.js) |
||
| 4번째 줄: | 4번째 줄: | ||
========================================= */ | ========================================= */ | ||
(function (window, document, mw) { | |||
(function () { | |||
'use strict'; | 'use strict'; | ||
var XLINK_NS = 'http://www.w3.org/1999/xlink'; | var XLINK_NS = 'http://www.w3.org/1999/xlink'; | ||
var ITEMS = [ | var ITEMS = [ | ||
{ key: 'era', label: '시대', title: '시대' }, | { key:'era', label:'시대', title:'시대' }, | ||
{ key: 'settings', label: '설정', title: '설정' }, | { key:'settings', label:'설정', title:'설정' }, | ||
{ key: 'project', label: '프로젝트', title: '프로젝트:소개' }, | { key:'project', label:'프로젝트', title:'프로젝트:소개' }, | ||
{ key: 'corporations', label: '기업 및 공동체', title: '기업_및_공동체' }, | { key:'corporations', label:'기업 및 공동체', title:'기업_및_공동체' }, | ||
{ key: 'military', label: '군, 정치집단', title: '군_정치집단' } | { key:'military', label:'군, 정치집단', title:'군_정치집단' } | ||
]; | ]; | ||
var BOUNDARY_DIRS = [0, 1, 1, -1, -1, 0]; | |||
var renderTimer = 0; | |||
function geometryApi() { | |||
return window.CLBI && window.CLBI.frame; | |||
} | |||
function buildPath(title) { | function buildPath(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 | function clearNode(node) { | ||
while (node && node.firstChild) node.removeChild(node.firstChild); | |||
} | } | ||
function calculateGeometry(width) { | function calculateGeometry(width) { | ||
var | var api = geometryApi(); | ||
var | var frame = api.FRAME; | ||
var | var dimensions = api.DIMENSIONS; | ||
var | var contentLeft = frame.FRAME_FACE; | ||
var | var contentWidth = Math.max(ITEMS.length, width - frame.FRAME_FACE * 2); | ||
var | var boundaries = []; | ||
var segments = []; | |||
var i; | var i; | ||
for (i = 0; i <= ITEMS.length; i++) { | |||
boundaries.push(contentLeft + Math.round(contentWidth * i / ITEMS.length)); | |||
} | |||
for (i = 0; i < | for (i = 0; i < ITEMS.length; i++) { | ||
var | var leftTopX = boundaries[i] + (i === 0 ? 0 : frame.GAP / 2); | ||
var rightTopX = boundaries[i + 1] - (i === ITEMS.length - 1 ? 0 : frame.GAP / 2); | |||
segments.push({ | |||
leftTopX:leftTopX, | |||
rightTopX:rightTopX, | |||
leftDir:BOUNDARY_DIRS[i], | |||
rightDir:BOUNDARY_DIRS[i + 1], | |||
points:api.segmentAt( | |||
leftTopX, | |||
rightTopX, | |||
dimensions.BUTTON_TOP, | |||
} | dimensions.BUTTON_BOTTOM, | ||
BOUNDARY_DIRS[i], | |||
BOUNDARY_DIRS[i + 1], | |||
0, | |||
0, | |||
0 | |||
) | |||
}); | |||
} | } | ||
return { | return { | ||
width: | width:width, | ||
boundaries:boundaries, | |||
segments:segments, | |||
dimensions:dimensions | |||
}; | }; | ||
} | } | ||
function | function appendFrame(svg, geometry) { | ||
var api = geometryApi(); | |||
var frame = api.FRAME; | |||
var d = geometry.dimensions; | |||
var width = geometry.width; | |||
var group = api.create('g', 'portal-category-frame'); | |||
group.appendChild(api.rect('portal-category-frame-edge', 0, 0, width, d.ROW_HEIGHT)); | |||
group.appendChild(api.rect('portal-category-frame-surface', 1, 1, width - 2, d.ROW_HEIGHT - 2)); | |||
group.appendChild(api.rect( | |||
'portal-category-frame-well', | |||
frame.FRAME_FACE, | |||
frame.FRAME_FACE, | |||
width - frame.FRAME_FACE * 2, | |||
d.ROW_HEIGHT - frame.FRAME_FACE * 2 | |||
)); | |||
group.appendChild(api.line('portal-category-frame-highlight', [1, 1], [width - 1, 1])); | |||
group.appendChild(api.line('portal-category-frame-highlight', [width - 1, 1], [width - 1, d.ROW_HEIGHT - 1])); | |||
group.appendChild(api.line('portal-category-frame-shadow', [1, d.ROW_HEIGHT - 1], [1, 1])); | |||
group.appendChild(api.line('portal-category-frame-shadow', [width - 1, d.ROW_HEIGHT - 1], [1, d.ROW_HEIGHT - 1])); | |||
group.appendChild(api.line( | |||
'portal-category-well-shadow', | |||
[frame.FRAME_FACE, frame.FRAME_FACE], | |||
[width - frame.FRAME_FACE, frame.FRAME_FACE] | |||
)); | |||
group.appendChild(api.line( | |||
'portal-category-well-shadow', | |||
[width - frame.FRAME_FACE, frame.FRAME_FACE], | |||
[width - frame.FRAME_FACE, d.ROW_HEIGHT - frame.FRAME_FACE] | |||
)); | |||
group.appendChild(api.line( | |||
'portal-category-well-highlight', | |||
[frame.FRAME_FACE, d.ROW_HEIGHT - frame.FRAME_FACE], | |||
[frame.FRAME_FACE, frame.FRAME_FACE] | |||
)); | |||
group.appendChild(api.line( | |||
line | 'portal-category-well-highlight', | ||
[width - frame.FRAME_FACE, d.ROW_HEIGHT - frame.FRAME_FACE], | |||
[frame.FRAME_FACE, d.ROW_HEIGHT - frame.FRAME_FACE] | |||
line | )); | ||
svg.appendChild(group); | |||
} | } | ||
function createSegment(item, index, geometry) { | function createSegment(item, index, geometry) { | ||
var | var api = geometryApi(); | ||
var | var frame = api.FRAME; | ||
var | var data = geometry.segments[index]; | ||
var | var d = geometry.dimensions; | ||
var | var anchor = api.create('a', 'portal-cat-anchor'); | ||
var | var outer = api.polygon('portal-cat-edge', data.points); | ||
var | var surfacePoints = api.segmentAt( | ||
var | data.leftTopX, | ||
data.rightTopX, | |||
d.BUTTON_TOP + frame.BORDER, | |||
var hit = | d.BUTTON_BOTTOM - frame.BORDER, | ||
var text = | data.leftDir, | ||
data.rightDir, | |||
0, | |||
frame.BORDER, | |||
frame.BORDER | |||
); | |||
var bevelPoints = api.segmentAt( | |||
data.leftTopX, | |||
data.rightTopX, | |||
d.BUTTON_TOP + frame.BORDER + frame.BEVEL, | |||
d.BUTTON_BOTTOM - frame.BORDER - frame.BEVEL, | |||
data.leftDir, | |||
data.rightDir, | |||
0, | |||
frame.BORDER + frame.BEVEL, | |||
frame.BORDER + frame.BEVEL | |||
); | |||
var hit = api.polygon('portal-cat-hit', data.points); | |||
var text = api.create('text', 'portal-cat-label'); | |||
var href = buildPath(item.title); | var href = buildPath(item.title); | ||
anchor.setAttribute('href', href); | anchor.setAttribute('href', href); | ||
anchor.setAttributeNS(XLINK_NS, 'xlink:href', href); | anchor.setAttributeNS(XLINK_NS, 'xlink:href', href); | ||
| 251번째 줄: | 158번째 줄: | ||
anchor.setAttribute('data-category-key', item.key); | anchor.setAttribute('data-category-key', item.key); | ||
outer. | anchor.appendChild(outer); | ||
anchor.appendChild(api.polygon('portal-cat-surface', surfacePoints)); | |||
anchor.appendChild(api.line('portal-cat-inset portal-cat-inset-top', bevelPoints[0], bevelPoints[1])); | |||
anchor.appendChild(api.line('portal-cat-inset portal-cat-inset-right', bevelPoints[1], bevelPoints[2])); | |||
anchor.appendChild(api.line('portal-cat-inset portal-cat-inset-bottom', bevelPoints[2], bevelPoints[3])); | |||
anchor.appendChild(api.line('portal-cat-inset portal-cat-inset-left', bevelPoints[3], bevelPoints[0])); | |||
hit.setAttribute('pointer-events', 'all'); | hit.setAttribute('pointer-events', 'all'); | ||
anchor.appendChild(hit); | |||
text.setAttribute('x', api.centerX(surfacePoints)); | |||
text.setAttribute('x', | text.setAttribute('y', Math.round((d.BUTTON_TOP + d.BUTTON_BOTTOM) / 2) + 1); | ||
text.setAttribute('y', Math.round( | |||
text.setAttribute('font-size', '12'); | text.setAttribute('font-size', '12'); | ||
text.setAttribute('font-weight', '700'); | text.setAttribute('font-weight', '700'); | ||
| 264번째 줄: | 175번째 줄: | ||
text.setAttribute('pointer-events', 'none'); | text.setAttribute('pointer-events', 'none'); | ||
text.textContent = item.label; | text.textContent = item.label; | ||
anchor.appendChild(text); | anchor.appendChild(text); | ||
return anchor; | return anchor; | ||
} | } | ||
function | function publishSeams(geometry) { | ||
var api = geometryApi(); | |||
var segments = geometry.segments; | |||
var d = geometry.dimensions; | |||
api.setSeams({ | |||
width:geometry.width, | |||
rowHeight:d.ROW_HEIGHT, | |||
buttonTop:d.BUTTON_TOP, | |||
buttonBottom:d.BUTTON_BOTTOM, | |||
overlap:d.OVERLAP, | |||
bottomStartAbsY:d.BOTTOM_START_ABS_Y, | |||
settingsLeftTopX:segments[1].leftTopX, | |||
settingsLeftDir:segments[1].leftDir, | |||
corpRightTopX:segments[3].rightTopX, | |||
corpRightDir:segments[3].rightDir, | |||
projectLeftTopX:segments[2].leftTopX, | |||
projectLeftDir:segments[2].leftDir, | |||
projectRightTopX:segments[2].rightTopX, | |||
projectRightDir:segments[2].rightDir | |||
}); | |||
} | } | ||
function buildSvg(width) { | function buildSvg(width) { | ||
var api = geometryApi(); | |||
var geometry = calculateGeometry(width); | var geometry = calculateGeometry(width); | ||
var svg = | var svg = api.create('svg', 'portal-category-svg'); | ||
svg.setAttribute('viewBox', '0 0 ' + geometry.width + ' ' + geometry.dimensions.ROW_HEIGHT); | |||
svg.setAttribute('viewBox', '0 0 ' + geometry.width + ' ' + geometry. | svg.setAttribute('width', geometry.width); | ||
svg.setAttribute('width', | svg.setAttribute('height', geometry.dimensions.ROW_HEIGHT); | ||
svg.setAttribute('height', | svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); | ||
svg.setAttribute('preserveAspectRatio', ' | |||
svg.setAttribute('aria-hidden', 'false'); | svg.setAttribute('aria-hidden', 'false'); | ||
svg.setAttribute('data-frame-width', geometry.width); | |||
appendFrame(svg, geometry); | |||
ITEMS.forEach(function (item, index) { | ITEMS.forEach(function (item, index) { | ||
svg.appendChild(createSegment(item, index, geometry)); | svg.appendChild(createSegment(item, index, geometry)); | ||
}); | }); | ||
return { | return { svg:svg, geometry:geometry }; | ||
} | } | ||
function | function renderMount(mount) { | ||
var | var api = geometryApi(); | ||
var width; | |||
var nav; | |||
var result; | |||
if ( | if (!mount || !api) return false; | ||
width = api.readWidth(mount); | |||
if (!width) { | |||
if (!mount.__categoryNavRetry) { | |||
mount.__categoryNavRetry = window.setTimeout(function () { | |||
mount.__categoryNavRetry = 0; | |||
renderMount(mount); | |||
}, 60); | |||
} | |||
return false; | |||
} | |||
if (mount.__categoryNavRetry) { | |||
window.clearTimeout(mount.__categoryNavRetry); | |||
nav. | mount.__categoryNavRetry = 0; | ||
} | |||
nav = mount.querySelector('.portal-category-nav'); | |||
if (!nav) { | |||
clearNode(mount); | |||
nav = document.createElement('nav'); | |||
nav.className = 'portal-category-nav'; | |||
nav. | nav.setAttribute('aria-label', 'Main categories'); | ||
mount.appendChild(nav); | |||
} | |||
if (nav.__frameWidth === width && nav.querySelector('.portal-category-svg')) { | |||
if ( | publishSeams(calculateGeometry(width)); | ||
return true; | |||
} | } | ||
result = buildSvg(width); | |||
nav.__frameWidth = width; | |||
clearNode(nav); | |||
nav. | nav.appendChild(result.svg); | ||
nav | |||
mount.setAttribute('data-category-nav-rendered', '1'); | mount.setAttribute('data-category-nav-rendered', '1'); | ||
publishSeams(result.geometry); | |||
if (window.ResizeObserver && !mount.__categoryNavObserver) { | |||
mount.__categoryNavObserver = new window.ResizeObserver(function () { | |||
schedule(mount); | |||
if (window.ResizeObserver | |||
mount.__categoryNavObserver = | |||
}); | }); | ||
mount.__categoryNavObserver.observe(mount); | |||
} | } | ||
return true; | |||
} | } | ||
function | function renderAll(root) { | ||
var scope = root | var scope = root && root.querySelectorAll ? root : document; | ||
var mounts = | var mounts = []; | ||
var rendered = 0; | |||
Array.prototype.forEach.call(mounts | if (scope.matches && scope.matches('[data-component="category-nav"]')) mounts.push(scope); | ||
Array.prototype.forEach.call(scope.querySelectorAll('[data-component="category-nav"]'), function (mount) { | |||
if (mounts.indexOf(mount) === -1) mounts.push(mount); | |||
}); | |||
mounts.forEach(function (mount) { | |||
if (renderMount(mount)) rendered += 1; | |||
}); | }); | ||
return rendered; | |||
} | } | ||
window. | function schedule(root) { | ||
window.clearTimeout(renderTimer); | |||
renderTimer = window.setTimeout(function () { | |||
renderTimer = 0; | |||
} | renderAll(root || document); | ||
}, 0); | |||
} | |||
if (document.readyState === 'loading') { | if (document.readyState === 'loading') { | ||
document.addEventListener('DOMContentLoaded', function () { | document.addEventListener('DOMContentLoaded', function () { renderAll(document); }); | ||
} else { | } else { | ||
renderAll(document); | |||
} | } | ||
if ( | if (mw && mw.hook) { | ||
mw.hook('wikipage.content').add(function ( | mw.hook('wikipage.content').add(function (content) { | ||
schedule(content && content[0] ? content[0] : document); | |||
}); | }); | ||
} | } | ||
}()); | |||
window.addEventListener('resize', function () { schedule(document); }); | |||
window.CategoryNav = { | |||
init:renderAll, | |||
renderAll:renderAll, | |||
renderMount:renderMount | |||
}; | |||
window.CLBI = window.CLBI || {}; | |||
window.CLBI.categoryNav = { | |||
init:renderAll, | |||
renderMount:renderMount | |||
}; | |||
}(window, document, window.mw)); | |||
2026년 7월 17일 (금) 10:15 판
/* =========================================
COASTLINE: BLACK ICE - CategoryNav
대문 카테고리 SVG 네비 생성기
========================================= */
(function (window, document, mw) {
'use strict';
var XLINK_NS = 'http://www.w3.org/1999/xlink';
var ITEMS = [
{ key:'era', label:'시대', title:'시대' },
{ key:'settings', label:'설정', title:'설정' },
{ key:'project', label:'프로젝트', title:'프로젝트:소개' },
{ key:'corporations', label:'기업 및 공동체', title:'기업_및_공동체' },
{ key:'military', label:'군, 정치집단', title:'군_정치집단' }
];
var BOUNDARY_DIRS = [0, 1, 1, -1, -1, 0];
var renderTimer = 0;
function geometryApi() {
return window.CLBI && window.CLBI.frame;
}
function buildPath(title) {
if (typeof window.buildWikiPath === 'function') return window.buildWikiPath(title);
return '/index.php/' + encodeURI(String(title || '').replace(/ /g, '_'));
}
function clearNode(node) {
while (node && node.firstChild) node.removeChild(node.firstChild);
}
function calculateGeometry(width) {
var api = geometryApi();
var frame = api.FRAME;
var dimensions = api.DIMENSIONS;
var contentLeft = frame.FRAME_FACE;
var contentWidth = Math.max(ITEMS.length, width - frame.FRAME_FACE * 2);
var boundaries = [];
var segments = [];
var i;
for (i = 0; i <= ITEMS.length; i++) {
boundaries.push(contentLeft + Math.round(contentWidth * i / ITEMS.length));
}
for (i = 0; i < ITEMS.length; i++) {
var leftTopX = boundaries[i] + (i === 0 ? 0 : frame.GAP / 2);
var rightTopX = boundaries[i + 1] - (i === ITEMS.length - 1 ? 0 : frame.GAP / 2);
segments.push({
leftTopX:leftTopX,
rightTopX:rightTopX,
leftDir:BOUNDARY_DIRS[i],
rightDir:BOUNDARY_DIRS[i + 1],
points:api.segmentAt(
leftTopX,
rightTopX,
dimensions.BUTTON_TOP,
dimensions.BUTTON_BOTTOM,
BOUNDARY_DIRS[i],
BOUNDARY_DIRS[i + 1],
0,
0,
0
)
});
}
return {
width:width,
boundaries:boundaries,
segments:segments,
dimensions:dimensions
};
}
function appendFrame(svg, geometry) {
var api = geometryApi();
var frame = api.FRAME;
var d = geometry.dimensions;
var width = geometry.width;
var group = api.create('g', 'portal-category-frame');
group.appendChild(api.rect('portal-category-frame-edge', 0, 0, width, d.ROW_HEIGHT));
group.appendChild(api.rect('portal-category-frame-surface', 1, 1, width - 2, d.ROW_HEIGHT - 2));
group.appendChild(api.rect(
'portal-category-frame-well',
frame.FRAME_FACE,
frame.FRAME_FACE,
width - frame.FRAME_FACE * 2,
d.ROW_HEIGHT - frame.FRAME_FACE * 2
));
group.appendChild(api.line('portal-category-frame-highlight', [1, 1], [width - 1, 1]));
group.appendChild(api.line('portal-category-frame-highlight', [width - 1, 1], [width - 1, d.ROW_HEIGHT - 1]));
group.appendChild(api.line('portal-category-frame-shadow', [1, d.ROW_HEIGHT - 1], [1, 1]));
group.appendChild(api.line('portal-category-frame-shadow', [width - 1, d.ROW_HEIGHT - 1], [1, d.ROW_HEIGHT - 1]));
group.appendChild(api.line(
'portal-category-well-shadow',
[frame.FRAME_FACE, frame.FRAME_FACE],
[width - frame.FRAME_FACE, frame.FRAME_FACE]
));
group.appendChild(api.line(
'portal-category-well-shadow',
[width - frame.FRAME_FACE, frame.FRAME_FACE],
[width - frame.FRAME_FACE, d.ROW_HEIGHT - frame.FRAME_FACE]
));
group.appendChild(api.line(
'portal-category-well-highlight',
[frame.FRAME_FACE, d.ROW_HEIGHT - frame.FRAME_FACE],
[frame.FRAME_FACE, frame.FRAME_FACE]
));
group.appendChild(api.line(
'portal-category-well-highlight',
[width - frame.FRAME_FACE, d.ROW_HEIGHT - frame.FRAME_FACE],
[frame.FRAME_FACE, d.ROW_HEIGHT - frame.FRAME_FACE]
));
svg.appendChild(group);
}
function createSegment(item, index, geometry) {
var api = geometryApi();
var frame = api.FRAME;
var data = geometry.segments[index];
var d = geometry.dimensions;
var anchor = api.create('a', 'portal-cat-anchor');
var outer = api.polygon('portal-cat-edge', data.points);
var surfacePoints = api.segmentAt(
data.leftTopX,
data.rightTopX,
d.BUTTON_TOP + frame.BORDER,
d.BUTTON_BOTTOM - frame.BORDER,
data.leftDir,
data.rightDir,
0,
frame.BORDER,
frame.BORDER
);
var bevelPoints = api.segmentAt(
data.leftTopX,
data.rightTopX,
d.BUTTON_TOP + frame.BORDER + frame.BEVEL,
d.BUTTON_BOTTOM - frame.BORDER - frame.BEVEL,
data.leftDir,
data.rightDir,
0,
frame.BORDER + frame.BEVEL,
frame.BORDER + frame.BEVEL
);
var hit = api.polygon('portal-cat-hit', data.points);
var text = api.create('text', 'portal-cat-label');
var href = buildPath(item.title);
anchor.setAttribute('href', href);
anchor.setAttributeNS(XLINK_NS, 'xlink:href', href);
anchor.setAttribute('aria-label', item.label);
anchor.setAttribute('data-category-key', item.key);
anchor.appendChild(outer);
anchor.appendChild(api.polygon('portal-cat-surface', surfacePoints));
anchor.appendChild(api.line('portal-cat-inset portal-cat-inset-top', bevelPoints[0], bevelPoints[1]));
anchor.appendChild(api.line('portal-cat-inset portal-cat-inset-right', bevelPoints[1], bevelPoints[2]));
anchor.appendChild(api.line('portal-cat-inset portal-cat-inset-bottom', bevelPoints[2], bevelPoints[3]));
anchor.appendChild(api.line('portal-cat-inset portal-cat-inset-left', bevelPoints[3], bevelPoints[0]));
hit.setAttribute('pointer-events', 'all');
anchor.appendChild(hit);
text.setAttribute('x', api.centerX(surfacePoints));
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.setAttribute('pointer-events', 'none');
text.textContent = item.label;
anchor.appendChild(text);
return anchor;
}
function publishSeams(geometry) {
var api = geometryApi();
var segments = geometry.segments;
var d = geometry.dimensions;
api.setSeams({
width:geometry.width,
rowHeight:d.ROW_HEIGHT,
buttonTop:d.BUTTON_TOP,
buttonBottom:d.BUTTON_BOTTOM,
overlap:d.OVERLAP,
bottomStartAbsY:d.BOTTOM_START_ABS_Y,
settingsLeftTopX:segments[1].leftTopX,
settingsLeftDir:segments[1].leftDir,
corpRightTopX:segments[3].rightTopX,
corpRightDir:segments[3].rightDir,
projectLeftTopX:segments[2].leftTopX,
projectLeftDir:segments[2].leftDir,
projectRightTopX:segments[2].rightTopX,
projectRightDir:segments[2].rightDir
});
}
function buildSvg(width) {
var api = geometryApi();
var geometry = calculateGeometry(width);
var svg = api.create('svg', 'portal-category-svg');
svg.setAttribute('viewBox', '0 0 ' + geometry.width + ' ' + geometry.dimensions.ROW_HEIGHT);
svg.setAttribute('width', geometry.width);
svg.setAttribute('height', geometry.dimensions.ROW_HEIGHT);
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
svg.setAttribute('aria-hidden', 'false');
svg.setAttribute('data-frame-width', geometry.width);
appendFrame(svg, geometry);
ITEMS.forEach(function (item, index) {
svg.appendChild(createSegment(item, index, geometry));
});
return { svg:svg, geometry:geometry };
}
function renderMount(mount) {
var api = geometryApi();
var width;
var nav;
var result;
if (!mount || !api) return false;
width = api.readWidth(mount);
if (!width) {
if (!mount.__categoryNavRetry) {
mount.__categoryNavRetry = window.setTimeout(function () {
mount.__categoryNavRetry = 0;
renderMount(mount);
}, 60);
}
return false;
}
if (mount.__categoryNavRetry) {
window.clearTimeout(mount.__categoryNavRetry);
mount.__categoryNavRetry = 0;
}
nav = mount.querySelector('.portal-category-nav');
if (!nav) {
clearNode(mount);
nav = document.createElement('nav');
nav.className = 'portal-category-nav';
nav.setAttribute('aria-label', 'Main categories');
mount.appendChild(nav);
}
if (nav.__frameWidth === width && nav.querySelector('.portal-category-svg')) {
publishSeams(calculateGeometry(width));
return true;
}
result = buildSvg(width);
nav.__frameWidth = width;
clearNode(nav);
nav.appendChild(result.svg);
mount.setAttribute('data-category-nav-rendered', '1');
publishSeams(result.geometry);
if (window.ResizeObserver && !mount.__categoryNavObserver) {
mount.__categoryNavObserver = new window.ResizeObserver(function () {
schedule(mount);
});
mount.__categoryNavObserver.observe(mount);
}
return true;
}
function renderAll(root) {
var scope = root && root.querySelectorAll ? root : document;
var mounts = [];
var rendered = 0;
if (scope.matches && scope.matches('[data-component="category-nav"]')) mounts.push(scope);
Array.prototype.forEach.call(scope.querySelectorAll('[data-component="category-nav"]'), function (mount) {
if (mounts.indexOf(mount) === -1) mounts.push(mount);
});
mounts.forEach(function (mount) {
if (renderMount(mount)) rendered += 1;
});
return rendered;
}
function schedule(root) {
window.clearTimeout(renderTimer);
renderTimer = window.setTimeout(function () {
renderTimer = 0;
renderAll(root || document);
}, 0);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { renderAll(document); });
} else {
renderAll(document);
}
if (mw && mw.hook) {
mw.hook('wikipage.content').add(function (content) {
schedule(content && content[0] ? content[0] : document);
});
}
window.addEventListener('resize', function () { schedule(document); });
window.CategoryNav = {
init:renderAll,
renderAll:renderAll,
renderMount:renderMount
};
window.CLBI = window.CLBI || {};
window.CLBI.categoryNav = {
init:renderAll,
renderMount:renderMount
};
}(window, document, window.mw));