|
|
| Line 1: |
Line 1: |
| (function () {
| |
| 'use strict';
| |
|
| |
| const urlCache = new Map();
| |
|
| |
| function getSize(element) {
| |
| const className = typeof element.className === 'string'
| |
| ? element.className
| |
| : '';
| |
|
| |
| const match = className.match(/model_size_(\d+)/);
| |
|
| |
| return match ? parseInt(match[1], 10) : 500;
| |
| }
| |
|
| |
| function getFileUrl(fileName) {
| |
| if (urlCache.has(fileName)) {
| |
| return urlCache.get(fileName);
| |
| }
| |
|
| |
| const apiUrl =
| |
| mw.config.get('wgScriptPath') +
| |
| '/api.php?action=query' +
| |
| '&titles=File:' + encodeURIComponent(fileName) +
| |
| '&prop=imageinfo' +
| |
| '&iiprop=url' +
| |
| '&format=json';
| |
|
| |
| const promise = fetch(apiUrl)
| |
| .then(function (response) {
| |
| if (!response.ok) {
| |
| throw new Error('API request failed');
| |
| }
| |
|
| |
| return response.json();
| |
| })
| |
| .then(function (data) {
| |
| const pages = data.query && data.query.pages;
| |
|
| |
| if (!pages) {
| |
| return null;
| |
| }
| |
|
| |
| const page = Object.values(pages)[0];
| |
|
| |
| if (!page || !page.imageinfo || !page.imageinfo[0]) {
| |
| return null;
| |
| }
| |
|
| |
| return page.imageinfo[0].url;
| |
| })
| |
| .catch(function () {
| |
| return null;
| |
| });
| |
|
| |
| urlCache.set(fileName, promise);
| |
|
| |
| return promise;
| |
| }
| |
|
| |
| function loadModel(preview) {
| |
| if (preview.dataset.loaded) {
| |
| return;
| |
| }
| |
|
| |
| preview.dataset.loaded = '1';
| |
|
| |
| const fileName = preview.dataset.model;
| |
|
| |
| if (!fileName) {
| |
| return;
| |
| }
| |
|
| |
| const displayName = preview.dataset.name || fileName;
| |
| const size = getSize(preview);
| |
|
| |
| getFileUrl(fileName + '.glb')
| |
| .then(function (url) {
| |
| if (!url || !preview.isConnected) {
| |
| return;
| |
| }
| |
|
| |
| const wrap = document.createElement('div');
| |
| wrap.className = 'model-viewer-wrap';
| |
|
| |
| const container = document.createElement('div');
| |
| container.className = 'model-viewer-container';
| |
| container.style.width = size + 'px';
| |
| container.style.height = size + 'px';
| |
|
| |
| const viewer = document.createElement('model-viewer');
| |
|
| |
| viewer.src = url;
| |
| viewer.setAttribute('camera-controls', '');
| |
| viewer.setAttribute('touch-action', 'pan-y');
| |
|
| |
| container.appendChild(viewer);
| |
| wrap.appendChild(container);
| |
|
| |
| const name = document.createElement('div');
| |
| name.className = 'model-name';
| |
| name.textContent = displayName;
| |
|
| |
| wrap.appendChild(name);
| |
|
| |
| preview.replaceWith(wrap);
| |
| });
| |
| }
| |
|
| |
| function initPreview(preview) {
| |
| if (
| |
| !preview ||
| |
| preview.dataset.initialized
| |
| ) {
| |
| return;
| |
| }
| |
|
| |
| preview.dataset.initialized = '1';
| |
|
| |
| const button = document.createElement('button');
| |
|
| |
| button.className = 'model-load-button';
| |
| button.type = 'button';
| |
|
| |
| button.addEventListener('click', function () {
| |
| loadModel(preview);
| |
| });
| |
|
| |
| preview.appendChild(button);
| |
| }
| |
|
| |
| function scan(root) {
| |
| if (!root) {
| |
| return;
| |
| }
| |
|
| |
| if (
| |
| root.nodeType === Node.ELEMENT_NODE &&
| |
| root.matches('.model-placeholder')
| |
| ) {
| |
| initPreview(root);
| |
| }
| |
|
| |
| if (root.querySelectorAll) {
| |
| root
| |
| .querySelectorAll('.model-placeholder')
| |
| .forEach(initPreview);
| |
| }
| |
| }
| |
|
| |
| function startObserver() {
| |
| if (!document.body) {
| |
| return;
| |
| }
| |
|
| |
| const observer = new MutationObserver(function (mutations) {
| |
| for (const mutation of mutations) {
| |
| for (const node of mutation.addedNodes) {
| |
| if (node.nodeType === Node.ELEMENT_NODE) {
| |
| scan(node);
| |
| }
| |
| }
| |
| }
| |
| });
| |
|
| |
| observer.observe(document.body, {
| |
| childList: true,
| |
| subtree: true
| |
| });
| |
| }
| |
|
| |
| function init() {
| |
| scan(document);
| |
| startObserver();
| |
| }
| |
|
| |
| mw.hook('wikipage.content').add(function ($content) {
| |
| scan($content[0]);
| |
| });
| |
|
| |
| if (document.readyState === 'loading') {
| |
| document.addEventListener('DOMContentLoaded', init, {
| |
| once: true
| |
| });
| |
| } else {
| |
| init();
| |
| }
| |
|
| |
| })();
| |
|
| |
|
|
| |
|