const Vue = require("vue"); class BasePageListLoader { loadPageList() { return Promise.reject(new Error('Not implemented')); } parseHTMLString(txt) { try { let parser = new DOMParser(); let xmlDoc = parser.parseFromString(txt, "text/html"); return xmlDoc; } catch(e) { console.error(e.message); } return null; } loadPageContent(pageInfo) { return new Promise((resolve, reject) => { if (!pageInfo || !pageInfo.fullTitle) { return reject(new Error('pageInfo.fullTitle is null')); } let url = mw.util.getUrl(pageInfo.fullTitle); if (url.indexOf('?') >= 0) { url += '&'; } else { url += '?' } url += 'action=render'; $.get(url, (str) => { let $dom = $(this.parseHTMLString(str)); let $content = $dom.find('.mw-parser-output'); if ($content.length > 0) { //删除目录 $content.find('.toc').remove(); resolve($content.html()); } }, 'html'); }); } getPageUrl(pageInfo) { return new Promise((resolve, reject) => { if (!pageInfo || !pageInfo.fullTitle) { return reject(new Error('pageInfo.fullTitle is null')); } let url = mw.util.getUrl(pageInfo.fullTitle); resolve(url); }); } /** * 根据标题生成页面信息 * @param {string} title * @returns */ makePageInfoFromTitle(title) { let pageInfo = { fullTitle: title, title: title, subTitle: null }; if (title.indexOf('/') !== 0) { let splitPos = title.lastIndexOf('/'); pageInfo.title = title.substring(splitPos + 1); pageInfo.subTitle = title.substring(0, splitPos); } return pageInfo; } } class PresetPageListLoader extends BasePageListLoader { /** * 从页面列表加载页面 * @param {string[]} pageList */ constructor(pageList) { super(); this.pageList = pageList.map((pageTitle) => { return this.makePageInfoFromTitle(pageTitle); }); } /** * 加载页面列表 * @returns {Promise<*>} */ loadPageList() { return Promise.resolve(this.pageList); } } class CategoryPageListLoader extends BasePageListLoader { /** * 从分类加载页面 * @param {string} category */ constructor(category) { super(); this.category = category; this.api = new mw.Api(); } /** * 加载页面列表 * @returns {Promise<*>} */ loadPageList() { return new Promise((resolve, reject) => { this.api.get({ action: 'query', list: 'categorymembers', cmtitle: this.category, cmtype: 'page', cmnamespace: 0, cmlimit: 200, cmsort: 'sortkey', }).done((data) => { if(data.query && data.query.categorymembers){ let pageList = data.query.categorymembers.map((pageInfo) => { return this.makePageInfoFromTitle(pageInfo.title); }); resolve(pageList); } else if(data.error){ reject(new Error(data.error.info)); } else { reject(new Error(mw.message('isekai-discover-error-cannotload').parse())); } }).fail((data) => { reject(new Error(data.error.info)); }); }); } } function htmlDecode(input) { var doc = new DOMParser().parseFromString(input, "text/html"); return doc.documentElement.textContent; } let previewPageList = document.querySelectorAll('.isekai-preview-page-list-card'); if (previewPageList.length > 0) { const App = require("./PreviewPageList.vue"); previewPageList.forEach((previewPageListDom) => { try { let props = {}; let dataset = previewPageListDom.dataset; props.autoFocus = (dataset.autofocus == '1'); props.lazyLoad = (dataset.lazyload == '1'); switch (dataset.loader) { case 'pages': let pagesJsonEl = document.querySelector('script[type="application/json"][data-pages]'); let pageList = []; if (pagesJsonEl) { let jsonStr = htmlDecode(pagesJsonEl.innerText); pageList = JSON.parse(jsonStr); } props.pageListLoader = new PresetPageListLoader(pageList); break; case 'category': let category = dataset.category; props.pageListLoader = new CategoryPageListLoader(category); break; default: console.error('Unknown loader: ' + dataset.loader); } Vue.createMwApp(App, props).mount(previewPageListDom); } catch (e) { console.error(e); } }); }