/*! * VisualEditor MediaWiki DesktopArticleTarget init. * * This file must remain as widely compatible as the base compatibility * for MediaWiki itself (see mediawiki/core:/resources/startup.js). * Avoid use of: SVG, HTML5 DOM, ContentEditable etc. * * @copyright See AUTHORS.txt * @license The MIT License (MIT); see LICENSE.txt */ /* eslint-disable no-jquery/no-global-selector */ // TODO: ve.now and ve.track should be moved to mw.libs.ve /* global ve */ /** * Platform preparation for the MediaWiki view page. This loads (when user needs it) the * actual MediaWiki integration and VisualEditor library. * * @class mw.libs.ve * @alternateClassName ve.init.mw.DesktopArticleTarget.init * @singleton */ ( function () { var conf, tabMessages, url, pageExists, viewUrl, veEditUrl, veEditSourceUrl, init, targetPromise, tabPreference, initialWikitext, oldId, isLoading, tempWikitextEditor, tempWikitextEditorData, $toolbarPlaceholder, $toolbarPlaceholderBar, contentTop, wasFloating, configData = require( './data.json' ), veactionToMode = { edit: 'visual', editsource: 'source' }, availableModes = [], active = false, targetLoaded = false, plugins = [], welcomeDialogDisabled = false, educationPopupsDisabled = false, // Defined after document-ready below $targetContainer = null; if ( mw.config.get( 'wgMFMode' ) ) { mw.log.warn( 'Attempted to load desktop target on mobile.' ); return; } /** * Show the loading progress bar * * @return {string} mode Edit mode, 'visual' or 'source' */ function showLoading() { if ( isLoading ) { return; } isLoading = true; $( 'html' ).addClass( 've-activated ve-loading' ); if ( !init.$loading ) { init.progressBar = new mw.libs.ve.ProgressBarWidget(); init.$loading = $( '
' ) .addClass( 've-init-mw-desktopArticleTarget-loading-overlay' ) .append( init.progressBar.$element ); } $( document ).on( 'keydown', onDocumentKeyDown ); $toolbarPlaceholderBar.append( init.$loading ); } /** * Increment loading progress by one step * * See mw.libs.ve.ProgressBarWidget for steps. */ function incrementLoadingProgress() { init.progressBar.incrementLoadingProgress(); } /** * Clear and hide the loading progress bar */ function clearLoading() { init.progressBar.clearLoading(); isLoading = false; $( document ).off( 'keydown', onDocumentKeyDown ); $( 'html' ).removeClass( 've-loading' ); if ( init.$loading ) { init.$loading.detach(); } if ( tempWikitextEditor ) { teardownTempWikitextEditor(); } hideToolbarPlaceholder(); } /** * Handle window scroll events * * @param {Event} e */ function onWindowScroll() { var scrollTop = $( document.documentElement ).scrollTop(); var floating = scrollTop > contentTop; if ( floating !== wasFloating ) { var width = $targetContainer.outerWidth(); $toolbarPlaceholder.toggleClass( 've-init-mw-desktopArticleTarget-toolbarPlaceholder-floating', floating ); $toolbarPlaceholderBar.css( 'width', width ); wasFloating = floating; } } var onWindowScrollListener = mw.util.throttle( onWindowScroll, 250 ); /** * Show a placeholder for the VE toolbar */ function showToolbarPlaceholder() { if ( !$toolbarPlaceholder ) { // Create an equal-height placeholder for the toolbar to avoid vertical jump // when the real toolbar is ready. $toolbarPlaceholder = $( '
' ).addClass( 've-init-mw-desktopArticleTarget-toolbarPlaceholder' ); $toolbarPlaceholderBar = $( '
' ).addClass( 've-init-mw-desktopArticleTarget-toolbarPlaceholder-bar' ); $toolbarPlaceholder.append( $toolbarPlaceholderBar ); } // Toggle -floating class before append (if required) to avoid content moving later contentTop = $targetContainer.offset().top; wasFloating = null; onWindowScroll(); var scrollTopBefore = $( document.documentElement ).scrollTop(); $targetContainer.prepend( $toolbarPlaceholder ); window.addEventListener( 'scroll', onWindowScrollListener, { passive: true } ); if ( wasFloating ) { // Browser might not support scroll anchoring: // https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-anchor/Guide_to_scroll_anchoring // ...so compute the new scroll offset ourselves. window.scrollTo( 0, scrollTopBefore + $toolbarPlaceholder.outerHeight() ); } // Add class for transition after first render setTimeout( function () { $toolbarPlaceholder.addClass( 've-init-mw-desktopArticleTarget-toolbarPlaceholder-open' ); } ); } /** * Hide the placeholder for the VE toolbar */ function hideToolbarPlaceholder() { if ( $toolbarPlaceholder ) { window.removeEventListener( 'scroll', onWindowScrollListener ); $toolbarPlaceholder.detach(); $toolbarPlaceholder.removeClass( 've-init-mw-desktopArticleTarget-toolbarPlaceholder-open' ); } } /** * Create a temporary `