From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

// Global to hold a reference to the OOUI.WindowManager.

var EasyLinks = {};



// Make sure the modules we need are loaded (will only load if not already)

mw.loader.using(['mediawiki.api', 'mediawiki.util', 'oojs-ui-core', 'oojs-ui-windows'], function () {



  // Wait for the page to be parsed

  $(document).ready(function () { 



    // TODO: Check for special pages and abort or…

    // TODO: …only whitelist namespaces known to make sense.



    // Let's at least disable Special:-pages by default to start.

    if (mw.config.get('wgCanonicalNamespace') === 'Special') {

      return;

    }



    // And on the Main Page

    if (mw.config.get('wgIsMainPage')) {

      return;

    }



    // Disable completely on mobile (and desktop users with Minerva)

    if ($('body').hasClass('skin-minerva')) {

      return;

    }





    // Create and append a window manager.

    EasyLinks.windowManager = new OO.ui.WindowManager();

    $('body').append(EasyLinks.windowManager.$element);





    // Predefine a dialog that we'll open by name when needed.

    // Specify common defaults here and we'll add the variable stuff when opening.

    EasyLinks.windowManager.addWindows({

      linkDialog: new OO.ui.MessageDialog({

        actions: 

          {

            action: 'accept',

            label: 'Dismiss',

            flags: 'primary'

          }

        

      })

    });



    // If URL params include &diff= then this is a diff page, so add diffLink portlet

    if (mw.util.getParamValue('diff')) {

      var diffPortlet = mw.util.addPortletLink(

        'p-cactions', '#', 'Get diff link', 'ca-getdiffwl', 'Get a wikilink to this diff'

      ); 

      $(diffPortlet).click(function (event) {

        event.preventDefault();

        doGetDiffWL();

      });

    }



    // Add permalink portlet unconditionally; if &oldid= is missing we use the

    // latest version of the page.

    var permalinkPortlet = mw.util.addPortletLink(

      'p-cactions', '#', 'Get permalink', 'ca-getpermalink', 'Get a permanent wikilink to this page'

    ); 

    $(permalinkPortlet).click(function (event) {

      event.preventDefault();

      doGetPermaWL();

    });



    // If wgAction is "history", add multidiff portlet

    if (mw.config.get('wgAction') === "history") {

      var multidiffPortlet = mw.util.addPortletLink(

        'p-cactions', '#', 'Get multiple diff links', 'ca-getmdiffwl', 'Get wikilinks for multiple diffs'

      ); 

      $(multidiffPortlet).click(function (e) {

        e.preventDefault();

        setupMultiDiff();

      });

    }



    // Add section link and permalink links to all headings (except page title)

    $('h2, h3, h4, h5, h6').has('.mw-headline').each(function() {

      var headline = $(this).children('span.mw-headline');

      var editsection = $(this).children('span.mw-editsection');



      var openbracket = $('<span>[ </span>');

      var closebracket = $('<span> ]</span>');

      var divider = $('<span> | </span>');



      var wlspan = $('<a class="getwikilink" href="#">link</a>').click(function(event) {

        event.preventDefault();

        doGetSectionWL($(headline).attr('id'));

      });

      var permaspan = $('<a class="getpermalink" href="#">permalink</span>').click(function(event) {

        event.preventDefault();

        doGetPermaSectionWL($(headline).attr('id'));

      });

      var containerspan = $('<span class="mw-editsection getlinks"></span>');

      $(containerspan).append(openbracket, wlspan, divider, permaspan, closebracket);

      if ($(editsection).length > 0) {

        $(containerspan).insertAfter(editsection);

      } else {

        $(containerspan).insertAfter(headline);

      }

    });

  }); // END: $(document).ready()



  // Format the timestamp.

  function getTimestring (timestamp) {

    const monthNames = "January", "February", "March", "April", "May", "June",

      "July", "August", "September", "October", "November", "December"];

    var t = new Date(timestamp);

    var Y = t.getUTCFullYear();

    var M = monthNamest.getUTCMonth()];

    var D = t.getUTCDate();

    var h = t.getUTCHours().padStart(2, '0');

    var m = t.getUTCMinutes().padStart(2, '0');

    var s = t.getUTCSeconds();

    return `${h}:${m}, ${D} ${M} ${Y}`;

  }



  // Cobble together the wikitext string for mdiff output.

  function formatMultiDiff(revid, user, revtime, summary) {

    var string = '';

    string += '*<small>{{noping|' + user + '}}@';

    string += '[[Special:Diff/' + revid + '|' + revtime + ']]: </small>';

    string += '<span class="easylinks-editsummary">' + summary + '</span>';

    string += "\n";

    return string;

  }



  // Format the edit summary.

  function getSummary (apicomment) {

    let summary = '';

    if (apicomment === '') {

      summary = '<small><span class="autocomment">[no edit summary provided]</span></small>';

    } else if (/^\/\*.*?\*\/$/.test(apicomment)) {

      summary = apicomment.replace(/^\/\*.*?\*\//, '<span class="autocomment">$&: </span>');

      summary += '<span class="autocomment">[no edit summary provided]</span>';

      summary = '<small>' + summary + '</small>';

    } else {

      summary = apicomment.replace(/^\/\*.*?\*\//, '<span class="autocomment">$&: </span>');

    }

    return summary;

  }



  // Common utility function to put the link(s) on the user's clipboard,

  // and pop up a notification that it happened.

  function copyAndNotify(title, description, data) {

    // Create a textInputWidget to hold the link, and a FieldLayout to wrap it.

    var textInput = new OO.ui.MultilineTextInputWidget({ 

      value: data,

      multiline: true,

      autosize: true,

    });

    var textField = new OO.ui.FieldLayout(textInput, {align: 'top', label: null});



    // Configure the message dialog when it is opened with the window manager's openWindow() method.

    var instance = EasyLinks.windowManager.openWindow('linkDialog', {

      title: title,

      message: textField.$element

    });



    // Select the link in the textInput for easy copying.

    // Has to happen after it's finished opening or the button will steal focus.

    instance.opened.then(function () {



      // Try to close dialog when the user hits Enter (since we steal focus from the button).

      textInput.on('enter', function () {

        EasyLinks.windowManager.getCurrentWindow().close({action: 'accept'});

      });



      // Try to close dialog on copy siince we no longer need it.

      textInput.on('copy', function () {

        EasyLinks.windowManager.getCurrentWindow().close({action: 'accept'});

      });



      // Select the link, copy it to the clipboard, notify the user, and close the dialog.

      textInput.select();

      console.log(window.getSelection().toString());

      if (document.execCommand('copy')) {

        mw.notify(

          description + ' was automatically copied to your clipboard.',

          {title: 'Link copied', type: 'info', tag: 'EasyLinksCopied'}

        );

        EasyLinks.windowManager.getCurrentWindow().close({action: 'accept'});

      } else {

        // Auto-copy failed; don't close the dialog to let the user copy manually.

      }

    });

  } // END: copyAndNotify()



  // Get the diff id from URL params and create a diff wikilink to that rev.

  function doGetDiffWL() {

    var diff = mw.config.get('wgDiffNewId');

    var diffLink = '[[Special:Diff/' + diff + '|' + diff + ']]';



    copyAndNotify(

      'Internal wikilink to this diff',

      'The wikilink for this diff',

      diffLink

    );

  } // END: doGetDiffWL()



  // Get the old rev id from URL params, if present, or the latest rev otherwise.

  function doGetPermaWL() {

    var oldid;

    let kind = '';

    if (mw.util.getParamValue('oldid')) {

      oldid = mw.util.getParamValue('oldid');

      kind = 'this';

    } else {

      oldid = mw.config.get('wgCurRevisionId');

      kind = 'the latest';

    }

    var oldidLink = '[[Special:PermanentLink/' + oldid + '|' + oldid + ']]';



    copyAndNotify(

      'Internal wikilink to this version',

      'A permanent wikilink to ' + kind + ' revision',

      oldidLink

    );

  } // END: doGetPermaWL()



  // Creare a wikilink to a section, irrespective of namespace.

  function doGetSectionWL(headlineid) {

    var h = $('#' + $.escapeSelector(headlineid));

    var title = $(h).text();

    var page = mw.config.get('wgPageName');



    var sectionLink = '[[' + page + '#' + headlineid + '|' + title + ']]';



    copyAndNotify(

      'Wikilink to this section',

      'A wikilink to this section',

      sectionLink

    );

  } // END: doGetSectionWL()



  // Create a permalink to a specific section.

  function doGetPermaSectionWL(headlineid) {

    var h = $('#' + $.escapeSelector(headlineid));

    var title = $(h).text();

    var oldid;



    // If url contains &oldid= then this is a specific revision of the page,

    // otherwise grab the latest revision and use that.

    let kind = '';

    if (mw.util.getParamValue('oldid')) {

      oldid = mw.util.getParamValue('oldid');

      kind = 'this';

    } else {

      oldid = mw.config.get('wgCurRevisionId');

      kind = 'the latest';

    }



    var permaSectionLink = '[[Special:PermanentLink/' + oldid + '#' + headlineid + '|' + title + ']]';



    copyAndNotify(

      'Permanent wikilink to this section',

      'A wikilink to this section at ' + kind + ' revision',

      permaSectionLink

    );

  } // END: doGetPermaSectionWL()



  // On history pages, let user pick multiple revisions and get a list of diffs

  // for those revisions. Unlike the other functions, this one is "modal": when

  // activated we pop up a dialog to prompt the user to pick revisions, and let

  // them cancel or confirm the selection.

  function setupMultiDiff() {

    $('ul#pagehistory > li').prepend(function() {

      let revid = $(this).data('mwRevid');

      let checkbox = $('<input type="checkbox" />')

        .addClass('mdiff-checkbox')

        .css('margin-left', '1em')

        .css('margin-right', '1em')

        .css('vertical-aliign', 'middle')

        .data('mdiff-revid', revid);

      let cspan = $('<span/>')

        .addClass('mdiff-span')

        .css('background', '#663399')

        .append(checkbox)

        .fadeIn(1000);

      return cspan;

    });



    var dialog = $('<div id="mdiff-dialog"><p>Choose the revisions for which you want diffs.</p></div>');

    dialog.dialog({

      autoOpen: false,

      title: 'Choose revisions',

      position: {my: 'right top', at: 'right top', of: '#mw-content-text'},

      buttons: {

        Cancel: function() {

          $('.mdiff-checkbox').remove();

          $(this).dialog('close');

        },

        Ok: function() {

          $(this).dialog('close');

          var selectedRevs = $('.mdiff-checkbox:checked');

          if (selectedRevs.length === 0) {

            // Nothing selected: remove checkboxes and abort.

            $('.mdiff-checkbox').remove();

            return;

          }

          let revisions = [];

          selectedRevs.each(function() {

            let rev = $(this).data('mdiff-revid');

            revisions.push(rev);

          });



          var diffLinks = '';

          var api = new mw.Api();

          api.get({

            action: 'query',

            prop: 'revisions',

            rvprop: 'ids', 'flags', 'timestamp', 'user', 'size', 'comment', 'tags'],

            revids: revisions

          }).done(function (apiResult) {

            Object.values(apiResult.query.pages).forEach(function(page) {

              page.revisions.forEach(function(p) {

                var revid   = p.revid;

                var user    = p.user;

                var revsize = p.size;

                var revtime = getTimestring(p.timestamp);

                var summary = getSummary(p.comment);

                diffLinks += formatMultiDiff(revid, user, revtime, summary);

              });

            });

            $('.mdiff-checkbox').remove();

            copyAndNotify(

              'Wikilinks for these diffs',

              'A list of wikilinks for these diffs',

              diffLinks

            );

          }); // END: api.get().done()

        } // END: Ok()

      } // END: buttons: {}

    }); // END: dialog.dialog()

    dialog.dialog('open');

  } // END: setupMultiDiff()



}); // END: mw.loader.using()
From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

// Global to hold a reference to the OOUI.WindowManager.

var EasyLinks = {};



// Make sure the modules we need are loaded (will only load if not already)

mw.loader.using(['mediawiki.api', 'mediawiki.util', 'oojs-ui-core', 'oojs-ui-windows'], function () {



  // Wait for the page to be parsed

  $(document).ready(function () { 



    // TODO: Check for special pages and abort or…

    // TODO: …only whitelist namespaces known to make sense.



    // Let's at least disable Special:-pages by default to start.

    if (mw.config.get('wgCanonicalNamespace') === 'Special') {

      return;

    }



    // And on the Main Page

    if (mw.config.get('wgIsMainPage')) {

      return;

    }



    // Disable completely on mobile (and desktop users with Minerva)

    if ($('body').hasClass('skin-minerva')) {

      return;

    }





    // Create and append a window manager.

    EasyLinks.windowManager = new OO.ui.WindowManager();

    $('body').append(EasyLinks.windowManager.$element);





    // Predefine a dialog that we'll open by name when needed.

    // Specify common defaults here and we'll add the variable stuff when opening.

    EasyLinks.windowManager.addWindows({

      linkDialog: new OO.ui.MessageDialog({

        actions: 

          {

            action: 'accept',

            label: 'Dismiss',

            flags: 'primary'

          }

        

      })

    });



    // If URL params include &diff= then this is a diff page, so add diffLink portlet

    if (mw.util.getParamValue('diff')) {

      var diffPortlet = mw.util.addPortletLink(

        'p-cactions', '#', 'Get diff link', 'ca-getdiffwl', 'Get a wikilink to this diff'

      ); 

      $(diffPortlet).click(function (event) {

        event.preventDefault();

        doGetDiffWL();

      });

    }



    // Add permalink portlet unconditionally; if &oldid= is missing we use the

    // latest version of the page.

    var permalinkPortlet = mw.util.addPortletLink(

      'p-cactions', '#', 'Get permalink', 'ca-getpermalink', 'Get a permanent wikilink to this page'

    ); 

    $(permalinkPortlet).click(function (event) {

      event.preventDefault();

      doGetPermaWL();

    });



    // If wgAction is "history", add multidiff portlet

    if (mw.config.get('wgAction') === "history") {

      var multidiffPortlet = mw.util.addPortletLink(

        'p-cactions', '#', 'Get multiple diff links', 'ca-getmdiffwl', 'Get wikilinks for multiple diffs'

      ); 

      $(multidiffPortlet).click(function (e) {

        e.preventDefault();

        setupMultiDiff();

      });

    }



    // Add section link and permalink links to all headings (except page title)

    $('h2, h3, h4, h5, h6').has('.mw-headline').each(function() {

      var headline = $(this).children('span.mw-headline');

      var editsection = $(this).children('span.mw-editsection');



      var openbracket = $('<span>[ </span>');

      var closebracket = $('<span> ]</span>');

      var divider = $('<span> | </span>');



      var wlspan = $('<a class="getwikilink" href="#">link</a>').click(function(event) {

        event.preventDefault();

        doGetSectionWL($(headline).attr('id'));

      });

      var permaspan = $('<a class="getpermalink" href="#">permalink</span>').click(function(event) {

        event.preventDefault();

        doGetPermaSectionWL($(headline).attr('id'));

      });

      var containerspan = $('<span class="mw-editsection getlinks"></span>');

      $(containerspan).append(openbracket, wlspan, divider, permaspan, closebracket);

      if ($(editsection).length > 0) {

        $(containerspan).insertAfter(editsection);

      } else {

        $(containerspan).insertAfter(headline);

      }

    });

  }); // END: $(document).ready()



  // Format the timestamp.

  function getTimestring (timestamp) {

    const monthNames = "January", "February", "March", "April", "May", "June",

      "July", "August", "September", "October", "November", "December"];

    var t = new Date(timestamp);

    var Y = t.getUTCFullYear();

    var M = monthNamest.getUTCMonth()];

    var D = t.getUTCDate();

    var h = t.getUTCHours().padStart(2, '0');

    var m = t.getUTCMinutes().padStart(2, '0');

    var s = t.getUTCSeconds();

    return `${h}:${m}, ${D} ${M} ${Y}`;

  }



  // Cobble together the wikitext string for mdiff output.

  function formatMultiDiff(revid, user, revtime, summary) {

    var string = '';

    string += '*<small>{{noping|' + user + '}}@';

    string += '[[Special:Diff/' + revid + '|' + revtime + ']]: </small>';

    string += '<span class="easylinks-editsummary">' + summary + '</span>';

    string += "\n";

    return string;

  }



  // Format the edit summary.

  function getSummary (apicomment) {

    let summary = '';

    if (apicomment === '') {

      summary = '<small><span class="autocomment">[no edit summary provided]</span></small>';

    } else if (/^\/\*.*?\*\/$/.test(apicomment)) {

      summary = apicomment.replace(/^\/\*.*?\*\//, '<span class="autocomment">$&: </span>');

      summary += '<span class="autocomment">[no edit summary provided]</span>';

      summary = '<small>' + summary + '</small>';

    } else {

      summary = apicomment.replace(/^\/\*.*?\*\//, '<span class="autocomment">$&: </span>');

    }

    return summary;

  }



  // Common utility function to put the link(s) on the user's clipboard,

  // and pop up a notification that it happened.

  function copyAndNotify(title, description, data) {

    // Create a textInputWidget to hold the link, and a FieldLayout to wrap it.

    var textInput = new OO.ui.MultilineTextInputWidget({ 

      value: data,

      multiline: true,

      autosize: true,

    });

    var textField = new OO.ui.FieldLayout(textInput, {align: 'top', label: null});



    // Configure the message dialog when it is opened with the window manager's openWindow() method.

    var instance = EasyLinks.windowManager.openWindow('linkDialog', {

      title: title,

      message: textField.$element

    });



    // Select the link in the textInput for easy copying.

    // Has to happen after it's finished opening or the button will steal focus.

    instance.opened.then(function () {



      // Try to close dialog when the user hits Enter (since we steal focus from the button).

      textInput.on('enter', function () {

        EasyLinks.windowManager.getCurrentWindow().close({action: 'accept'});

      });



      // Try to close dialog on copy siince we no longer need it.

      textInput.on('copy', function () {

        EasyLinks.windowManager.getCurrentWindow().close({action: 'accept'});

      });



      // Select the link, copy it to the clipboard, notify the user, and close the dialog.

      textInput.select();

      console.log(window.getSelection().toString());

      if (document.execCommand('copy')) {

        mw.notify(

          description + ' was automatically copied to your clipboard.',

          {title: 'Link copied', type: 'info', tag: 'EasyLinksCopied'}

        );

        EasyLinks.windowManager.getCurrentWindow().close({action: 'accept'});

      } else {

        // Auto-copy failed; don't close the dialog to let the user copy manually.

      }

    });

  } // END: copyAndNotify()



  // Get the diff id from URL params and create a diff wikilink to that rev.

  function doGetDiffWL() {

    var diff = mw.config.get('wgDiffNewId');

    var diffLink = '[[Special:Diff/' + diff + '|' + diff + ']]';



    copyAndNotify(

      'Internal wikilink to this diff',

      'The wikilink for this diff',

      diffLink

    );

  } // END: doGetDiffWL()



  // Get the old rev id from URL params, if present, or the latest rev otherwise.

  function doGetPermaWL() {

    var oldid;

    let kind = '';

    if (mw.util.getParamValue('oldid')) {

      oldid = mw.util.getParamValue('oldid');

      kind = 'this';

    } else {

      oldid = mw.config.get('wgCurRevisionId');

      kind = 'the latest';

    }

    var oldidLink = '[[Special:PermanentLink/' + oldid + '|' + oldid + ']]';



    copyAndNotify(

      'Internal wikilink to this version',

      'A permanent wikilink to ' + kind + ' revision',

      oldidLink

    );

  } // END: doGetPermaWL()



  // Creare a wikilink to a section, irrespective of namespace.

  function doGetSectionWL(headlineid) {

    var h = $('#' + $.escapeSelector(headlineid));

    var title = $(h).text();

    var page = mw.config.get('wgPageName');



    var sectionLink = '[[' + page + '#' + headlineid + '|' + title + ']]';



    copyAndNotify(

      'Wikilink to this section',

      'A wikilink to this section',

      sectionLink

    );

  } // END: doGetSectionWL()



  // Create a permalink to a specific section.

  function doGetPermaSectionWL(headlineid) {

    var h = $('#' + $.escapeSelector(headlineid));

    var title = $(h).text();

    var oldid;



    // If url contains &oldid= then this is a specific revision of the page,

    // otherwise grab the latest revision and use that.

    let kind = '';

    if (mw.util.getParamValue('oldid')) {

      oldid = mw.util.getParamValue('oldid');

      kind = 'this';

    } else {

      oldid = mw.config.get('wgCurRevisionId');

      kind = 'the latest';

    }



    var permaSectionLink = '[[Special:PermanentLink/' + oldid + '#' + headlineid + '|' + title + ']]';



    copyAndNotify(

      'Permanent wikilink to this section',

      'A wikilink to this section at ' + kind + ' revision',

      permaSectionLink

    );

  } // END: doGetPermaSectionWL()



  // On history pages, let user pick multiple revisions and get a list of diffs

  // for those revisions. Unlike the other functions, this one is "modal": when

  // activated we pop up a dialog to prompt the user to pick revisions, and let

  // them cancel or confirm the selection.

  function setupMultiDiff() {

    $('ul#pagehistory > li').prepend(function() {

      let revid = $(this).data('mwRevid');

      let checkbox = $('<input type="checkbox" />')

        .addClass('mdiff-checkbox')

        .css('margin-left', '1em')

        .css('margin-right', '1em')

        .css('vertical-aliign', 'middle')

        .data('mdiff-revid', revid);

      let cspan = $('<span/>')

        .addClass('mdiff-span')

        .css('background', '#663399')

        .append(checkbox)

        .fadeIn(1000);

      return cspan;

    });



    var dialog = $('<div id="mdiff-dialog"><p>Choose the revisions for which you want diffs.</p></div>');

    dialog.dialog({

      autoOpen: false,

      title: 'Choose revisions',

      position: {my: 'right top', at: 'right top', of: '#mw-content-text'},

      buttons: {

        Cancel: function() {

          $('.mdiff-checkbox').remove();

          $(this).dialog('close');

        },

        Ok: function() {

          $(this).dialog('close');

          var selectedRevs = $('.mdiff-checkbox:checked');

          if (selectedRevs.length === 0) {

            // Nothing selected: remove checkboxes and abort.

            $('.mdiff-checkbox').remove();

            return;

          }

          let revisions = [];

          selectedRevs.each(function() {

            let rev = $(this).data('mdiff-revid');

            revisions.push(rev);

          });



          var diffLinks = '';

          var api = new mw.Api();

          api.get({

            action: 'query',

            prop: 'revisions',

            rvprop: 'ids', 'flags', 'timestamp', 'user', 'size', 'comment', 'tags'],

            revids: revisions

          }).done(function (apiResult) {

            Object.values(apiResult.query.pages).forEach(function(page) {

              page.revisions.forEach(function(p) {

                var revid   = p.revid;

                var user    = p.user;

                var revsize = p.size;

                var revtime = getTimestring(p.timestamp);

                var summary = getSummary(p.comment);

                diffLinks += formatMultiDiff(revid, user, revtime, summary);

              });

            });

            $('.mdiff-checkbox').remove();

            copyAndNotify(

              'Wikilinks for these diffs',

              'A list of wikilinks for these diffs',

              diffLinks

            );

          }); // END: api.get().done()

        } // END: Ok()

      } // END: buttons: {}

    }); // END: dialog.dialog()

    dialog.dialog('open');

  } // END: setupMultiDiff()



}); // END: mw.loader.using()

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook