「MediaWiki:MobileUI.js」の版間の差分
表示
細編集の要約なし タグ: モバイル編集 モバイルウェブ編集 |
編集の要約なし タグ: モバイル編集 モバイルウェブ編集 |
||
| 136行目: | 136行目: | ||
.$("<ul>") | .$("<ul>") | ||
.attr("id", group.id) | .attr("id", group.id) | ||
.addClass(group.class) | .addClass(group.class) | ||
.append(children); | .append(children); | ||
| 203行目: | 202行目: | ||
this | this | ||
.$("<div>") | .$("<div>") | ||
.addClass(["menu", "menu-right"]) | .addClass(["menu", "menu-right", "view-border-box"]) | ||
.append(rightGroups) | .append(rightGroups) | ||
.insertAfter(jqMenu); | .insertAfter(jqMenu); | ||
this | |||
.$(this.navElement) | |||
.attr("data-article-id", this.wgArticleId); | |||
} | } | ||
2019年6月25日 (火) 01:28時点における版
// @ts-check
/**
* @typedef {import("jquery")} _JQueryStatic
*/
/**
* @typedef MenuDataItemComponent
* @prop {string} [text]
* @prop {string} [title]
* @prop {string} [href]
* @prop {string} [id]
* @prop {string | string[]} [class]
* @prop {string} [dataEventName]
*/
/**
* @typedef MenuDataItem
* @prop {string} [id]
* @prop {string | string[]} [class]
* @prop {MenuDataItemComponent[]} components
*/
/**
* @typedef MenuDataGroup
* @prop {string} [id]
* @prop {string | string[]} [class]
* @prop {MenuDataItem[]} items
*/
/**
* @typedef MobileUI
* @prop {MenuDataGroup[]} leftGroups
* @prop {MenuDataGroup} leftShortURLGroup
* @prop {MenuDataGroup[]} rightGroups
*/
class MobileUIBuilder {
/**
* @param {any} mw
* @param {JQueryStatic} $
*/
constructor(mw, $) {
this.mw = mw;
this.$ = $;
/**
* @type {string}
*/
this.wgServer = mw.config.get("wgServer");
/**
* @type {string}
*/
this.wgScriptPath = mw.config.get("wgScriptPath");
/**
* @type {number}
*/
this.wgArticleId = mw.config.get("wgArticleId");
}
/**
* @param {MenuDataItemComponent} component
* @returns {string}
*/
hrefForMenuDataItemComponent(component) {
switch (component.id) {
case "mobile-ui-page-short-url":
return (
this.wgServer
+ this.wgScriptPath
+ "?curid="
+ String(this.wgArticleId)
);
default:
return component.title
? (this.wgScriptPath + "/" + component.title)
: component.href;
}
}
/**
* @param {MenuDataItemComponent} component
* @returns {JQuery<HTMLElement>}
*/
menuDataItemComponent(component) {
const href = this.hrefForMenuDataItemComponent(component);
return this
.$("<a>")
.text(component.text || href)
.attr("href", href)
.attr("id", component.id)
.addClass(component.class)
.attr("data-event-name", component.dataEventName);
}
/**
* @param {MenuDataItem} item
* @returns {JQuery<HTMLElement>}
*/
menuDataItem(item) {
/**
* @type {JQuery<HTMLElement>[]}
*/
const children = [];
for (const component of item.components) {
children.push(this.menuDataItemComponent(component));
}
return this
.$("<li>")
.attr("id", item.id)
.addClass(item.class)
.append(children);
}
/**
* @param {MenuDataGroup} group
* @returns {JQuery<HTMLElement>}
*/
menuDataGroup(group) {
/**
* @type {JQuery<HTMLElement>[]}
*/
const children = [];
for (const item of group.items) {
children.push(this.menuDataItem(item));
}
return this
.$("<ul>")
.attr("id", group.id)
.addClass(group.class)
.append(children);
}
/**
* @param {MenuDataGroup[]} groups
* @returns {JQuery<HTMLElement>[]}
*/
menuDataGroups(groups) {
/**
* @type {JQuery<HTMLElement>[]}
*/
const children = [];
for (const group of groups) {
children.push(this.menuDataGroup(group));
}
return children;
}
/**
* @param {Node} node
* @returns {HTMLElement | null}
*/
elementIfTarget(node) {
const element = /** @type {HTMLElement} */ (node);
const { classList } = element;
if (!classList) return null;
if (!classList.contains("menu")) return null;
if (classList.contains("menu-right")) return null;
return element;
}
/**
* @returns {HTMLElement}
*/
get navElement() {
return window.document.getElementById("mw-mf-page-left");
}
/**
* @returns {HTMLElement | null}
*/
get menuElement() {
return /** @type {HTMLElement} */ (
this.navElement.getElementsByClassName("menu").item(0)
);
}
/**
* @param {MobileUI} mobileUI
* @param {HTMLElement} menuElement
*/
modify(mobileUI, menuElement) {
const leftGroups = this.menuDataGroups(mobileUI.leftGroups);
const rightGroups = [];
const jqMenu = this.$(menuElement);
jqMenu.find("ul").first().remove();
jqMenu.prepend(leftGroups);
this
.$("<div>")
.addClass(["menu", "menu-right", "view-border-box"])
.append(rightGroups)
.insertAfter(jqMenu);
this
.$(this.navElement)
.attr("data-article-id", this.wgArticleId);
}
/**
* @param {MobileUI} mobileUI
*/
build(mobileUI) {
const element = this.menuElement;
if (element) {
this.modify(mobileUI, element);
return;
}
const observer = new MutationObserver((mutations, observer) => {
for (const record of mutations) {
for (const node of record.addedNodes) {
const element = this.elementIfTarget(node);
if (element) {
observer.disconnect();
this.modify(mobileUI, element);
return;
}
}
}
});
observer.observe(this.navElement, { childList: true });
}
}