User:Tokenzero/tinfoboxHelperData.js
/**
* @module tinfoboxHelperData
* Helper structures for infoboxJournal.js, storing info about parameter choices, messages, etc.
*/
import * as util from '/w/index.php?title=User:Tokenzero/tinfoboxUtil.js&action=raw&ctype=text%2Fjavascript';
import { TemplateData, TemplateDataParam } from '/w/index.php?title=User:Tokenzero/tinfoboxTemplateData.js&action=raw&ctype=text%2Fjavascript';
/** Structure for parameter values and choices. */
export class ParamChoice {
/**
* @param {object} templateData
*/
constructor(templateData) {
/**
* @constant
* @type {TemplateDataParam}
* Note this is also included in TemplateChoice.templateData (possibly as a deep copy).
*/
this.templateData = templateData;
/** @type {?string} */
this.originalKey = null;
/** @type {?string} */
this.originalValue = null;
/** @type {?string} */
this.proposedValue = null;
/** @type {boolean} */
this.preferOriginal = true;
/** @type {Array<{type: string, message: string}>} */
this.messages = [];
}
/**
* Serialize to simple object to be passed do JSON.stringify.
*
* @returns {object}
*/
toJSON() {
return {
templateData: this.templateData, // Recursively toJSON'ed by JSON.stringify.
originalKey: this.originalKey,
originalValue: this.originalValue,
proposedValue: this.proposedValue,
preferOriginal: this.preferOriginal,
messages: this.messages
};
}
/**
* Deserialize from simple object returned by JSON.parse.
*
* @param {object} jsonObject
* @returns {ParamChoice}
*/
static fromJSON(jsonObject) {
const templateData = TemplateDataParam.fromJSON(jsonObject.templateData);
delete jsonObject.templateData;
return Object.assign(new ParamChoice(templateData), jsonObject);
}
/**
* Return whether proposed value is empty or equal to original, default or autovalue.
*
* @returns {boolean}
*/
isProposedValueTrivial() {
return (
(!this.proposedValue) ||
(this.proposedValue === this.originalValue) ||
(this.proposedValue === this.templateData.default) ||
(this.proposedValue === this.templateData.autovalue) ||
(!this.proposedValue && !this.templateData.autovalue)
);
}
}
/** Data to preserve after redirecting: ParamChoice-s and messages. */
export class TemplateChoice {
/** @param {TemplateData} templateData */
constructor(templateData) {
/**
* @constant
* @type {TemplateData}
* Note that templateData for params are also included in ParamChoices,
* possibly as a deep copy.
*/
this.templateData = templateData;
/** @type {Map<string, ParamChoice>} from canonicalKey to its ParamChoice. */
this.paramChoices = new Map();
/** @type {Array<{type: string, message: string}>} messages about this template instance. */
this.messages = [];
}
/**
* Get or create ParamChoice for given canonicalKey.
*
* @param {string} canonicalKey
* @returns {ParamChoice}
*/
param(canonicalKey) {
if (!this.paramChoices.has(canonicalKey)) {
const paramChoice = new ParamChoice(this.templateData.param(canonicalKey));
this.paramChoices.set(canonicalKey, paramChoice);
}
return this.paramChoices.get(canonicalKey);
}
/**
* Serialize to object to be passed do JSON.stringify.
*
* @returns {object}
*/
toJSON() {
// JSON.stringify will recursively call .toJSON() in each entry.
return {
templateData: this.templateData,
paramChoices: util.objectFromEntries(this.paramChoices.entries()),
messages: this.messages
};
}
/**
* Deserialize from object returned by JSON.parse.
*
* @param {object} jsonObject
* @returns {TemplateChoice}
*/
static fromJSON(jsonObject) {
const templateData = TemplateData.fromJSON(jsonObject.templateData);
const result = new TemplateChoice(templateData);
result.paramChoices = new Map(Object.entries(jsonObject.paramChoices).map(
([key, value]) => [key, ParamChoice.fromJSON(value)]
));
result.messages = jsonObject.messages;
return result;
}
/**
* Build table listing parameters with their choices and messages.
*
* @returns {JQuery<HTMLElement>|''}
*/
buildParamTable() {
const changedList = [];
const proposedList = [];
const weaklySuggestedList = [];
const otherList = [];
const choices = this.templateData.reorder(this.paramChoices).entries();
for (const [canonicalKey, pc] of choices) {
if (pc.proposedValue === pc.originalValue && !pc.messages.length) {
if (pc.proposedValue && pc.proposedValue.replace(/<!--[^>]*-->/g, '')) {
console.log(
`Param ${canonicalKey} guessed correctly as "${pc.proposedValue}".`);
}
continue;
}
if (pc.originalValue === pc.proposedValue)
pc.preferOriginal = true;
const row = $('<tr>');
row.append($(`<td>${pc.originalKey || canonicalKey}=</td>`));
if (typeof pc.originalValue === 'string')
row.append($(`<td>${util.escapeHTML(pc.originalValue)}</td>`));
else
row.append($('<td>(absent)</td>').addClass('absent'));
if (pc.preferOriginal)
row.children().last().addClass('selected');
if (typeof pc.proposedValue === 'string')
row.append($(`<td>${util.escapeHTML(pc.proposedValue)}</td>`));
else if (!pc.preferOriginal)
row.append($('<td>(deleted)</td>').addClass('absent'));
else
row.append($('<td></td>').addClass('absent'));
if (!pc.preferOriginal)
row.children().last().addClass('selected');
if (!pc.isProposedValueTrivial())
row.children().last().addClass('nontrivial');
const messageTd = $('<td>');
const tooltip = $(`<span
class="ext-tinfobox-tooltip"
title="${util.escapeHTML(pc.templateData.description)}"
/>`);
if (pc.templateData.description)
messageTd.append(tooltip);
const messageWidget = HelperData.buildMessagesWidget(pc.messages);
if (messageWidget !== '')
messageTd.append(messageWidget);
else
messageTd.addClass('empty');
row.append(messageTd);
if (!pc.preferOriginal)
changedList.push(row);
else if (!pc.isProposedValueTrivial())
proposedList.push(row);
else if ((pc.templateData.suggested || pc.templateData.weaklySuggested) &&
pc.originalValue === null)
weaklySuggestedList.push(row);
else if (pc.messages.length)
otherList.push(row);
// Else: we prefer original, proposed value is trivial and not suggested as addition,
// and there are no messages, so we just don't show the param.
}
let rows = [];
rows.push($(`<tr>
<th></th><th>current value</th><th>new value/suggested</th><th></th>
</tr>`));
const makeHeadRow = (t) => $('<tr><th colspan="3">' + t + '</th></tr>');
if (changedList.length) {
rows.push(makeHeadRow('<strong>Changed parameters</strong> (please fill empty ones)'));
rows = rows.concat(changedList);
} else {
rows.push(makeHeadRow('No parameters were changed.'));
}
if (proposedList.length) {
rows.push(makeHeadRow('<strong>Suggested changes</strong> (currently unchanged)'));
rows = rows.concat(proposedList);
}
if (weaklySuggestedList.length) {
rows.push(makeHeadRow('<strong>Additional parameters</strong>' +
' (situational, omit by default)'));
rows = rows.concat(weaklySuggestedList);
}
if (otherList.length) {
rows.push(makeHeadRow('Other warnings'));
rows = rows.concat(otherList);
}
return $('<table>').append(rows);
}
}
/**
* Data to pass after redirect, including TemplateChoice-s.
*/
export class HelperData {
/** Constructor. */
constructor() {
/** @type {Array<TemplateChoice>} */
this.templateChoices = [];
/** @type {Array<{type: string, message: string}>} global messages. */
this.messages = [];
}
/**
* Serialize to JSON string.
*
* @returns {string}
*/
toJSONString() {
return JSON.stringify({
templateChoices: this.templateChoices,
messages: this.messages
});
}
/**
* Deserialize from JSON string to new HelperData object.
*
* @param {string} json
* @returns {HelperData}
*/
static fromJSONString(json) {
const result = Object.assign(new HelperData(), JSON.parse(json));
result.templateChoices = result.templateChoices.map(
(x) => TemplateChoice.fromJSON(x)
);
return result;
}
/**
* Create jQuery object showing a list of messages.
*
* @param {Array<{type: string, message: string}>} messages
* @returns {JQuery|''}
*/
static buildMessagesWidget(messages) {
if (!messages || !messages.length)
return '';
const result = $('<ul></ul>');
for (const m of messages) {
const entry = $('<li>');
entry.text(m.message);
entry.prepend(`<b>${m.type}</b>: `);
result.append(entry);
}
return result;
}
/**
* Build a box describing helperData (prefilled parameters and such).
*
* @returns {JQuery<HTMLElement>}
*/
buildWidget() {
const widget = $(`
<div class="ext-tinfobox-helper">
<h2>infoboxJournal.js</h2>
</div>
`);
let globalMessages = this.messages;
if (this.templateChoices.length === 1)
globalMessages = globalMessages.concat(this.templateChoices[0].messages);
widget.append(HelperData.buildMessagesWidget(globalMessages));
const many = (this.templateChoices.length > 1);
for (const [tcIndex, tc] of this.templateChoices.entries()) {
if (many) {
widget.append($(`<h3>Template #${tcIndex + 1}</h3>`));
widget.append(HelperData.buildMessagesWidget(tc.messages));
}
widget.append(tc.buildParamTable());
}
return widget;
}
}
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.