User:Novem Linguae/Scripts/VisualEditorEverywhere.js

//

// TODO: fix the race condition. still present as of 08/31/22. got it when clicking from WT:NPPC to WP:NPPC. not consistently reproducible. use mw.hook( 've.activationComplete' )? list of VE hooks: https://codesearch.wmcloud.org/deployed/?q=mw%5C.hook.*%5C.fire&files=&excludeFiles=&repos=mediawiki%2Fextensions%2FVisualEditor

// TODO: add support for [edit] links in diffs

class VisualEditorEverywhere {

execute() {

this.articleName = mw.config.get( 'wgPageName' );

this.articleName = encodeURIComponent( this.articleName ); // fix bug involving & not getting converted to &

const pageIsUserScript = this.articleName.match( /(?:\.js|\.css)$/ );

const veTabIsPresent = $( '#ca-ve-edit' ).length;

if ( !veTabIsPresent && !pageIsUserScript ) {

this.insertVETab();

}

// we also need to check if section links are present. if you save a VE edit, the VETab will already be present, but the VESectionLinks will not be present and need to be added back

const veSectionLinkIsPresent = $( '.mw-editsection-visualeditor' ).length;

if ( !veSectionLinkIsPresent && !pageIsUserScript ) {

this.insertVESectionLink();

}

}

/** Insert Edit tab at top of page */

insertVETab() {

const skin = mw.config.get( 'skin' );

let htmlToInsert;

switch ( skin ) {

case 'timeless':

htmlToInsert =

`

  • VEdit

  • `;

    break;

    case 'vector-2022':

    htmlToInsert =

    `

  • VEdit

  • `;

    break;

    case 'modern':

    htmlToInsert =

    `

  • VEdit

  • `;

    break;

    case 'minerva':

    htmlToInsert =

    `VEdit`;

    break;

    case 'vector':

    case 'monobook':

    default:

    htmlToInsert =

    `

  • VEdit

  • `;

    break;

    }

    $( '#ca-edit' ).before( htmlToInsert );

    $( '#ca-ve-edit' ).show();

    }

    /** Insert [ vedit ] by each section */

    insertVESectionLink() {

    // Foreach edit button

    $( '.mw-editsection' ).each( function () {

    // Generate visual editor section link for this element

    // Credit to Bartosz Dziewoński (WMF) for this fix

    const veEditHref = $( this ).find( 'a' ).attr( 'href' ).replace( '&action=edit', '&veaction=edit' );

    // Generate HTML to insert

    let htmlToInsert;

    const skin = mw.config.get( 'skin' );

    switch ( skin ) {

    case 'minerva':

    // Generate HTML to insert

    htmlToInsert = 'vedit';

    $( this ).prepend( htmlToInsert );

    break;

    default:

    // Generate HTML to insert

    htmlToInsert = `vedit

    |

    `; // line break here is intentional. needed to render a space after the pipe

    // Insert the HTML right after

    // Inline tags such as do not work with :nth-child, .before(), etc. Must use :first-of-type.

    $( this ).children( 'span:first-of-type' ).after( htmlToInsert );

    break;

    }

    // Inject our generated URL for the edit button

    $( this ).find( '.mw-editsection-visualeditor' ).attr( 'href', veEditHref );

    } );

    this.showVEEditLink();

    // Doesn't work :(

    // Good test case is https://en.wikipedia.org/wiki/User_talk:Onel5969?useskin=minerva. Ctrl-F5. 25-50% of the time it will not show the vedit section links.

    /*

    // Fixes a race condition. There's some code in core somewhere that hides visual editor links pretty late in the page load process. Sometimes this user script inserts its links before that code runs.

    // TODO: switch from MutationObserver to mw.hook().add(). https://github.com/NovemLinguae/UserScripts/issues/167

    new MutationObserver(() => {

    showVEEditLink();

    console.log('VisualEditorEverywhere: Mutation observer fired. Race condition prevented.');

    }).observe($('.mw-editsection-visualeditor, .mw-editsection-divider')[0], {childList: true});

    */

    }

    showVEEditLink() {

    $( '.mw-editsection-visualeditor, .mw-editsection-divider' ).show();

    }

    }

    $( function () {

    // TODO: this should in theory fix the race condition bug. instead, it breaks the whole script (displays nothing). why? debug.

    // mw.hook( 've.activationComplete' ).add( function() {

    const vee = new VisualEditorEverywhere();

    vee.execute();

    // } );

    // when VE saves, the veSectionLinks should be put back

    mw.hook( 've.deactivationComplete' ).add( function () {

    const vee = new VisualEditorEverywhere();

    vee.execute();

    } );

    } );

    //