_ _    _ _____  ___   __                       
 __      _(_) | _(_)___ / ( _ ) / /_   ___ ___  _ __ ___  
 \ \ /\ / / | |/ / | |_ \ / _ \| '_ \ / __/ _ \| '_ ` _ \ 
  \ V  V /| |   <| |___) | (_) | (_) | (_| (_) | | | | | |
   \_/\_/ |_|_|\_\_|____/ \___/ \___(_)___\___/|_| |_| |_|

User:TheDJ/ActualLivePreview.js

In this article we are going to address the topic of User:TheDJ/ActualLivePreview.js in an exhaustive and detailed way. User:TheDJ/ActualLivePreview.js is a topic that has captured the attention of many people in recent years, and its importance and impact on society is undeniable. Throughout this article, we will analyze different aspects related to User:TheDJ/ActualLivePreview.js, from its origin and evolution to its implications today. In addition, we will explore different opinions and perspectives on User:TheDJ/ActualLivePreview.js, with the aim of offering our readers a broad and complete vision of this very relevant topic. Without a doubt, User:TheDJ/ActualLivePreview.js is a topic that deserves close examination, and we hope that this article serves as an informative and enlightening guide for all those interested in learning more about User:TheDJ/ActualLivePreview.js.
( function ( mw, $ ) {
	function dependenciesChecked() {

		if ( ( mw.config.get( 'wgAction' ) !== 'edit' && mw.config.get( 'wgAction' ) !== 'submit' ) ||
			!mw.user.options.get( 'previewontop' ) || !mw.user.options.get( 'uselivepreview' ) ||
			mw.config.get( 'wgPageContentModel' ) !== 'wikitext' )
		{
			return;
		}
		// TODO Give the spinner an 'id'/class
		mw.loader.using(  ).done( function() {
			mw.util.addCSS( '@media all and (min-width:1200px) { #mw-content-text { position: relative; } #editform { width: 50%; height: 100%; } #wpTextbox1 { height: 70%; height: 70vh; } #wikiPreview, #wikiDiff, .mw-spinner-preview { position: absolute; width: 50%; left: 50%; padding: 0 1em; box-sizing: border-box; } #wikiPreview { height: 100%; height: 100vh; overflow-y: scroll; } } .mw-spinner-preview { top: 2em; position: absolute; z-index: 1; }' );
		} );

		function initActualLivePreview () {
			var scrollTop = 0,
				oldScrollPos,
				$previewButton = $( '#wpPreview' ),
				$previewArea = $( '#wikiPreview' ),
				$wpTextbox1 = $( '#wpTextbox1' );

			// 1: after settling, call preview JS.
			// TODO, add some hook in live preview code, to know that it is done.
			window.setTimeout( function () {
				if( $( 'body' ).width() > 1200 ) {
					$previewButton.click();
				}
			}, 2000 );
			// 2: After input debounce, call preview JS
			// TODO, might wanna expose some of the preview api functions here
			$wpTextbox1.on( 'input', mw.util.debounce( 500, function () {
				if ( $( 'body' ).width() > 1200 ) {
					scrollTop = $previewArea.scrollTop();
					oldScrollPos = $wpTextbox1.scrollTop();
					$previewButton.click();
				}
			} ) ).on( 'scroll', mw.util.debounce( 100, function ( ) {
				if ( $( 'body' ).width() > 1200 ) {
					var height = $wpTextbox1.prop( 'scrollHeight' );
					var previewHeight = $previewArea.prop( 'scrollHeight' );
					var factor = previewHeight / height;
					if ( factor > 0 ) {
						var newScrollPos = $wpTextbox1.scrollTop();
						var offset = (newScrollPos - oldScrollPos)*factor;
						$previewArea.scrollTop( $previewArea.scrollTop() + offset );
						oldScrollPos = newScrollPos;
					}
				}
			} ) );
			// 3: Every time live preview is done rendering, try to scroll it to
			// its previous position
			// TODO, add some hook in live preview code, to know that it is done
			mw.hook( 'wikipage.content' ).add( function () {
				if( $( 'body' ).width() > 1200 ) {
					window.setTimeout( function () {
						$previewArea.scrollTop( scrollTop );
					}, 300 );
				}
			} );
		}
		$.when( $.ready, mw.loader.using( 'jquery.throttle-debounce' ) ).done( initActualLivePreview );
	}
	mw.loader.using(  ).done( dependenciesChecked );
} )( mediaWiki, jQuery );