User:Matma Rex/whynotboth.js

// Two-pane editor, with visual and source modes side by side. (async function {

mw.util.addCSS` .ve-init-mw-desktopArticleTarget-originalContent > .ve-ui-surface { display: grid; grid-template-columns: 50% 50%; grid-template-rows: 100%; }

.paragraphspacer:before { content: ''; height: var(--paragraphspacer-height); display: block; transition: background-color 500ms; }

.paragraphspacer:hover:before, background-color: #eee; } ` // You can't do this! // .paragraphspacer::before:hover { // 	background-color: #eee; // }
 * hover + .paragraphspacer:before {

var title = mw.config.get('wgPageName') var revid = mw.config.get('wgRevisionId')

var wikitext = '';

var veSelection = false; var wtSelection = false; var scrollPos = false;

wikitext = await (new mw.Api).get({	action: 'query',	format: 'json',	prop: 'revisions',	titles: title,	formatversion: '2',	rvprop: 'content',	rvslots: 'main',	rvlimit: '1', }).then( function ( resp ) {	return resp.query.pages[0].revisions[0].slots.main.content } )

async function initEditors { await mw.loader.load('ext.visualEditor.mwwikitext'); var [_, tid, isStash] = ve.init.target.etag.match(/^(?:W\/)?"\d+\/(.+?)(\/stash)?"$/) var dataParsoidUrl = `https://en.wikipedia.org/api/rest_v1/page/data-parsoid/${title}/${revid}/${tid}` var dataParsoid = await $.ajax(dataParsoidUrl) // weird API… if ( dataParsoid["data-parsoid"] ) { dataParsoid = dataParsoid["data-parsoid"].body }

// console.log(dataParsoid.counter)

var veTarget = ve.init.target var wtTarget;

function savePosition { veSelection = JSON.stringify( veTarget.surface.model.getSelection ); wtSelection = JSON.stringify( wtTarget.surface.model.getSelection ); scrollPos = window.scrollTop; }

function restorePosition { if ( scrollPos === false ) { return; }		veTarget.surface.model.setSelection( ve.dm.Selection.static.newFromJSON( veSelection ) ); wtTarget.surface.model.setSelection( ve.dm.Selection.static.newFromJSON( wtSelection ) ); window.scrollTop = scrollPos; }

var mwString = mw.loader.require('mediawiki.String') function calcOffset( str, utf8ByteOffset ) { var i = 0, j = 0, x = 0, y = 0;

x = utf8ByteOffset; while ( i < x ) { i += mwString.byteLength( str[j] ); j += 1; }		return j;	}

function addSourcePane { var wtTargetWidget = veTarget.createTargetWidget({ modes: [ 'source' ], defaultMode: 'source' }) wtTargetWidget.setDocument(			ve.dm.sourceConverter.getDataFromSourceText( wikitext )				.concat( [ { type: 'internalList' }, { type: '/internalList' } ] )		) wtTarget = wtTargetWidget.target veTarget.surface.$element.append( wtTarget.surface.$element )

var veNodesCe = veTarget.surface.view.documentView.documentNode.getChildren var lastWikitextTrim = '';

for(var veNodeCe of veNodesCe) { // console.log(veNodeCe.$element[0]) var $veNodeOrig = veNodeCe.model.getOriginalDomElements( veTarget.surface.model.documentModel.store ) if ( !$veNodeOrig[0] ) { continue; }			var id = $veNodeOrig[0].getAttribute('id'); var wtRange = dataParsoid.ids[id]?.dsr // console.log(wtRange) if ( !wtRange ) { continue; }			var wtOffsetBytes = wtRange[0] // wtRange is in utf-8 bytes. (TODO check "offsetType":"byte" in response?) // need to convert to utf-16 bytes for javascript. this looks like a very slow way to do it :D // lastWikitextTrim = mwString.trimByteLength(lastWikitextTrim, wikitext, wtOffsetBytes).newVal; // var wtOffset = lastWikitextTrim.length var wtOffset = calcOffset( wikitext, wtOffsetBytes )

var wtEditorOffset = wtTarget.surface.model.getOffsetFromSourceOffset( wtOffset ) var wtNodeCe = wtTarget.surface.view.documentView.getBranchNodeFromOffset( wtEditorOffset ) // console.log(wtNodeCe.$element[0])

wtNodeCe.$element.css('clear', 'both') veNodeCe.$element.css('clear', 'both') if(!veNodeCe.$element[0]) { // invisible element continue; }			veNodePos = veNodeCe.$element[0].getBoundingClientRect.top if(!veNodePos) { // invisible element continue; }			wtNodePos = wtNodeCe.$element[0].getBoundingClientRect.top diff = veNodePos - wtNodePos // console.log(diff) if ( veNodePos > wtNodePos ) { // wtNodeCe.$element.css('padding-top', '+='+diff) wtNodeCe.$element.addClass('paragraphspacer').css('--paragraphspacer-height', diff+'px') } else { // veNodeCe.$element.css('padding-top', '-='+diff) veNodeCe.$element.addClass('paragraphspacer').css('--paragraphspacer-height', -diff+'px') }		}

// Inspired by: reloadSurface, switchToVisualEditor wtTarget.surface.model.on( 'documentUpdate', ve.debounce( function { savePosition; wikitext = wtTarget.getSurface.getDom

var dataPromise = mw.libs.ve.targetLoader.requestParsoidData( title, {				oldId: veTarget.revid,				targetName: 'matmarex',				modified: true,				// wikitext: wtTarget.getDocToSave,				wikitext: wikitext,				section: veTarget.section			} );

veTarget.reloadSurface( 'visual', dataPromise ) // veTarget.once( 'surfaceReady', function {			// 	initEditors			// } ) // veTarget.clearDiff; // veTarget.load( dataPromise ); }, 2000 ) );	}

addSourcePane

restorePosition;

veTarget.surface.model.on( 'documentUpdate', ve.debounce( function { savePosition; var dataPromise = veTarget.getWikitextDataPromiseForDoc( true ); dataPromise.then( function ( resp ) {			// // clean up old source pane			// wtTarget.surface.$element.detach			// wtTarget.destroy

// var veNodesCe = veTarget.surface.view.documentView.documentNode.getChildren // for(var veNodeCe of veNodesCe) { // 	veNodeCe.$element.css('margin-top', '') // }

// addSourcePane( resp.visualeditoredit.content )

wikitext = resp.visualeditoredit.content var dataPromise = mw.libs.ve.targetLoader.requestParsoidData( title, {				oldId: veTarget.revid,				targetName: 'matmarex',				modified: true,				// wikitext: wtTarget.getDocToSave,				wikitext: wikitext,				section: veTarget.section			} );

veTarget.reloadSurface( 'visual', dataPromise ) } )	}, 2000 ) );

}

mw.hook( 've.activationComplete' ).add( function {	if ( ve.init.target.defaultMode === 'visual' ) {		initEditors;	} } );

});