const features = require( './features.js' ); const popupNotification = require( './popupNotification.js' ); const config = require( './config.json' ); const LIMITED_WIDTH_FEATURE_NAME = 'limited-width'; const AWARE_COOKIE_NAME = `${LIMITED_WIDTH_FEATURE_NAME}-aware`; const TOGGLE_ID = 'toggleWidth'; /** * Sets data attribute for click tracking purposes. * * @param {HTMLElement} toggleBtn */ function setDataAttribute( toggleBtn ) { toggleBtn.dataset.eventName = features.isEnabled( LIMITED_WIDTH_FEATURE_NAME ) ? 'limited-width-toggle-off' : 'limited-width-toggle-on'; } /** * Gets appropriate popup text based off the limited width feature flag * * @return {string} */ function getPopupText() { const label = features.isEnabled( LIMITED_WIDTH_FEATURE_NAME ) ? 'vector-limited-width-toggle-off-popup' : 'vector-limited-width-toggle-on-popup'; // possible messages: // * vector-limited-width-toggle-off-popup // * vector-limited-width-toggle-on-popup return mw.msg( label ); } /** * adds a toggle button */ function init() { const settings = /** @type {HTMLElement|null} */ ( document.querySelector( '.vector-settings' ) ); const toggle = /** @type {HTMLElement|null} */ ( document.querySelector( '.vector-limited-width-toggle' ) ); const toggleIcon = /** @type {HTMLElement|null} */ ( document.querySelector( '.vector-limited-width-toggle .mw-ui-icon' ) ); if ( !settings || !toggle || !toggleIcon ) { return; } setDataAttribute( toggle ); const userMayNotKnowTheyAreInExpandedMode = !mw.cookie.get( AWARE_COOKIE_NAME ); const dismiss = () => { mw.cookie.set( AWARE_COOKIE_NAME, '1' ); }; /** * check user has not disabled cookies by * reading the cookie and unsetting the cookie. * * @return {boolean} */ const areCookiesEnabled = () => { dismiss(); // @ts-ignore https://github.com/wikimedia/typescript-types/pull/39 const savedSuccessfully = mw.cookie.get( AWARE_COOKIE_NAME ) === '1'; mw.cookie.set( AWARE_COOKIE_NAME, null ); return savedSuccessfully; }; /** * @param {string} id this allows us to group notifications making sure only one is visible * at any given time. All existing popups associated with ID will be removed. * @param {number|false} timeout */ const showPopup = ( id, timeout = 4000 ) => { if ( !config.VectorLimitedWidthIndicator ) { return; } popupNotification.add( settings, getPopupText(), id, [], timeout, dismiss ) .then( ( popupWidget ) => { if ( popupWidget ) { popupNotification.show( popupWidget, timeout ); } } ); }; /** * FIXME: This currently loads OOUI on page load. It should be swapped out * for a more performance friendly version before being deployed. * See T334366. */ const showPageLoadPopups = () => { if ( !config.VectorLimitedWidthIndicator ) { return; } addLimitedWidthPopup( settings, getPopupText(), dismiss ); }; toggle.addEventListener( 'click', function () { const isLimitedWidth = features.isEnabled( LIMITED_WIDTH_FEATURE_NAME ); const oldIcon = isLimitedWidth ? 'fullScreen' : 'exitFullscreen'; const newIcon = isLimitedWidth ? 'exitFullscreen' : 'fullScreen'; features.toggle( LIMITED_WIDTH_FEATURE_NAME ); setDataAttribute( toggle ); toggleIcon.classList.remove( `mw-ui-icon-wikimedia-${oldIcon}` ); toggleIcon.classList.add( `mw-ui-icon-wikimedia-${newIcon}` ); window.dispatchEvent( new Event( 'resize' ) ); if ( isLimitedWidth ) { // Now is full width, show notification showPopup( TOGGLE_ID ); } } ); if ( userMayNotKnowTheyAreInExpandedMode ) { if ( areCookiesEnabled() ) { showPageLoadPopups(); } } } /** * @param {HTMLElement} container * @param {string} message * @param {Function} [onDismiss] */ function addLimitedWidthPopup( container, message, onDismiss = () => {} ) { const popupTemplateString = `

${message}

`; const popupFrag = document.createRange().createContextualFragment( popupTemplateString ); container.appendChild( popupFrag ); const closeButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-limited-width-popup-close-button' ) ); closeButton.addEventListener( 'click', () => { const popup = /** @type {HTMLElement} */ ( document.querySelector( '.vector-limited-width-popup' ) ); if ( popup && popup.parentElement ) { popup.parentElement.removeChild( popup ); } onDismiss(); }, { once: true } ); } module.exports = init;