mediawiki-skins-Vector/resources/skins.vector.clientPreferences/clientPreferences.js
Jon Robson 0f354e3950 Fixes saving of limited width
Bug: T345363
Change-Id: I3fee7e2b3a063d86a8d91ffa832cca4b72b48610
2023-09-21 19:13:38 +00:00

137 lines
4 KiB
JavaScript

/**
* @typedef {Object} ClientPreference
* @property {string[]} options that are valid for this client preference
* @property {string} preferenceKey for registered users.
*/
const config = /** @type {Record<string,ClientPreference>} */( require( './config.json' ) );
let /** @type {MwApi} */ api;
/**
* @typedef {Object} PreferenceOption
* @property {string} label
* @property {string} value
*
*/
/**
* @return {string[]} of active client preferences
*/
function getClientPreferences() {
return Array.from( document.documentElement.classList ).filter(
( className ) => className.match( /-clientpref-/ )
).map( ( className ) => className.split( '-clientpref-' )[ 0 ] );
}
/**
* @param {Element} parent
* @param {string} featureName
* @param {ClientPreference} pref
* @param {string} value
* @param {string} currentValue
*/
function appendRadioToggle( parent, featureName, pref, value, currentValue ) {
const input = document.createElement( 'input' );
const name = `vector-client-pref-${featureName}-group`;
const id = `vector-client-pref-${featureName}-value-${value}`;
input.name = name;
input.id = id;
input.type = 'radio';
input.value = value;
if ( currentValue === value ) {
input.checked = true;
}
const label = document.createElement( 'label' );
// eslint-disable-next-line mediawiki/msg-doc
label.textContent = mw.msg( `${featureName}-${value}-label` );
label.setAttribute( 'for', id );
const container = document.createElement( 'div' );
container.appendChild( input );
container.appendChild( label );
parent.appendChild( container );
input.addEventListener( 'change', () => {
// @ts-ignore https://github.com/wikimedia/typescript-types/pull/44
mw.user.clientPrefs.set( featureName, value );
if ( mw.user.isNamed() ) {
mw.util.debounce( function () {
api = api || new mw.Api();
api.saveOption( pref.preferenceKey, value );
}, 100 )();
}
} );
}
/**
* @param {string} className
* @return {Element}
*/
function createRow( className ) {
const row = document.createElement( 'div' );
row.setAttribute( 'class', className );
return row;
}
/**
* adds a toggle button
*
* @param {string} featureName
* @param {string} label
* @return {Element|null}
*/
function makeClientPreferenceBinaryToggle( featureName, label ) {
const pref = config[ featureName ];
if ( !pref ) {
return null;
}
// @ts-ignore https://github.com/wikimedia/typescript-types/pull/44
const currentValue = mw.user.clientPrefs.get( featureName );
// The client preference was invalid. This shouldn't happen unless a gadget
// or script has modified the documentElement.
if ( !currentValue ) {
return null;
}
const row = createRow( '' );
const form = document.createElement( 'form' );
const labelNode = document.createElement( 'label' );
labelNode.textContent = label;
form.appendChild( labelNode );
const toggle = document.createElement( 'fieldset' );
pref.options.forEach( ( value ) => {
appendRadioToggle( toggle, featureName, pref, value, currentValue );
} );
form.appendChild( toggle );
row.appendChild( form );
return row;
}
/**
* @param {string} featureName
* @return {Element|null}
*/
function makeClientPreference( featureName ) {
// eslint-disable-next-line mediawiki/msg-doc
const labelMsg = mw.message( `${featureName}-name` );
// If the user is not debugging messages and no language exists exit as its a hidden client preference.
if ( !labelMsg.exists() && mw.config.get( 'wgUserLanguage' ) !== 'qqx' ) {
return null;
} else {
return makeClientPreferenceBinaryToggle( featureName, labelMsg.text() );
}
}
/**
* Fills the client side preference dropdown with controls.
*/
function fillClientPreferencesDropdown() {
const dropdownContents = document.querySelectorAll( '#vector-client-prefs .vector-dropdown-content' )[ 0 ];
if ( !dropdownContents ) {
return;
}
getClientPreferences().forEach( ( pref ) => {
const prefNode = makeClientPreference( pref );
if ( prefNode ) {
dropdownContents.appendChild( prefNode );
}
} );
}
module.exports = fillClientPreferencesDropdown;