Popups Reloaded

This script is a re-imagined version of Navigation Popups.

It is alpha-grade: expect bugs, use with care In particular, the API for config and adding hook can and probably will change.

There are a few WS-centric tools included, and eventually it will be possible to add your own.

Example of the popups on a Wikisource page link

Installation edit

The basic script can be installed by adding the following to your Common.js page:

mw.loader.load('//en.wikisource.org/w/index.php?title=User:Inductiveload/popups reloaded.js&action=raw&ctype=text/javascript');
mw.loader.load("//en.wikisource.org/w/index.php?title=User:Inductiveload/popups_reloaded.css&action=raw&ctype=text/css", 'text/css');

Features edit

  • Quickly preview and access information about pages
  • View raw Wikitext of pages
  • Perform some streamlined actions
  • Handles links to any wiki in the WMF (Wikipedia, Commons, Wikidata, etc)
  • WS-specific features:
    • Page image previews
    • Direct links to the files for indexes

Configuration edit

Configuration is via the ext.gadget.popups-reloaded.config hook:

	mw.hook( 'ext.gadget.popups-reloaded.config' ).add( function ( cfg ) {
		cfg.showTimeout = 500;
	} );

Basic config edit

Simple configuration options are provided, and are set directly on the cfg object passed to your hook handler:

  • showTimeout the time you have to hover to get a popup
  • skinDenylist the list of skins to not have popups in
  • userContribsByDefault show a users contribution list on their username instead of their user page
  • logLimit how many log items to show:
    • default the value used if a more specific one is not set (default: 25)
  • linkLimit how many linkLimit items to show:
    • default the value used if a more specific one is not set (default: 25)
  • nsLinkList namespaces to show shortcut links for in some actions:
    • default the value used if a more specific one is not set
  • rcTypes, watchlistTypes: List of entries to show in the default RC/watchlists views. The default is [ 'edit', 'new', 'log' ]. You can add categorize.
  • blocks: pre-set block shortcuts
  • delete: pre-set deletion shortcuts

Custom hooks edit

The core feature of Popups Reloaded is a simple, but powerful, action framework. These are handled though a set of "hooks". There are three kinds of hook:

  • Recogniser hooks: look at a given HTML element (probably a link) and decide what kind of link it is (e.g. a link to a wiki article, a third-party link, etc.)
  • Action hooks: for a given element, generate a list of further actions (e.g. edit, history, etc). These are shown at the top of the popup. Multiple action hooks can fire on one link.
  • Content hooks: for a given element, generate some kind of preview content (for example, render a wiki page). Only one content hook can be fired on a single link.

Hooks are checked against a link by "scores". If you want to add a hook, you have to make sure, for content and recogniser hooks, that you outscore any other hook for the links you want, and for action hooks, you should set the score so the order is correct.

Recogniser hooks edit

These have the following structure:

{
	score: function ( $l, cache ) {
		return Promise.resolve( 0 );
	},
	canonical: function ( $l, cache ) {
		return Promise.resolve( {
			type: 'basic',
			href: $l.attr( 'href' ),
			display: $l.text()
		} );
	}
}

The score function runs first, and decides how well this recogniser matches the given element ($l). Returns a value (or a Promise that resolves a value) to be considered for a match, or undefined to declare the link doesn't match at all. The highest scoring hook will be be used.

The cache object is provided so that the hook can pre-compute or cache values for this element, to be used by action or content hooks/

The canonical function of the highest-scored recogniser will be run and resolves with an object:

  • type a type string which will be passed to the action and content hooks
  • href a "canonical" URL for the link (e.g. perhaps a URL fragment can be stripped, or useless query params stripped to make it easier to match with action or content hooks).
  • display a human-readable display text.

Built-in recogniser:

A generic URL, score 0
  • type: basic
  • href: the link's original href
  • text: the link's original text

The "link" recognizer adds some values to the cache as cache.link:

  • cache.link.href the href of the link (might not be a complete URL)
  • cache.link.url the complete URL if there is one
  • cache.link.getParam(param) get the given param, if available
  • cache.link.hasAllParams(listOfParams) does the link contain all the params listed?
A URL to a known wiki, score 100
  • type:
    • wiki_local: the link is to a normal wiki page
    • wiki_hash: the link is to a "hash" link that ends /#
    • wikitext: the link is to plain wikitext
  • href: the link's original href
  • text: the link's original text

The "wiki" recogniser adds useful things to the cache which can be used by action and content hooks to decide if they apply:

  • cache.wiki.title the complete title
  • cache.wiki.titleNoNs the title without any namespace prefix
  • cache.wiki.baseName the base name (i.e. everything before the first / if there is one, else the entire title)
  • cache.wiki.namespace the namespace, e.g. File
  • cache.wiki.section the section of a link (i.e. after #)
  • cache.wiki.local true if the link is to this wiki
  • cache.wiki.user the user associated with a given link (e.g. a link to Special:UserContributions), or undefined

Action hooks edit

{
	name: 'diff',
    onlyType: 'wiki_local',
	score: function ( $l, cache ) {
		if ( cache.has_param( 'oldid' ) ) {
			return 2000;
		}
		return null;
	}
	actions: function ( $l, cache, callback ) {
        return [
            [ a1, b1, [ c1, d1 ] ],
            [ a2, b2 ]
        ];
	}
}

The name is a human-readable name to assist in debugging, as it can tell you which hook is running on which link.

The score function is similar except that instead of the best scored function, all non-null scoring hooks will be used, in order of the score. The cache object can be consulted for pre-computed values.

onlyType is a string or array of strings declaring the recogniser types this action hook is compatible with. The hook's score function will only be run for matching types.

The actions function returns (or resolves) a list of action lists. Each action list will be a line of options. These options can also be lists, then they look like (A | B).

Every action item has a format like this:

{
    text: 'revert to',
    href: revert_to_url,
    nopopup: true,
    class: [ 'class_name' ]
};
  • text: the text of the link for the action
  • href: the href for the action
  • nopopup: optional, set to true to suppress further popups on this action
  • class: optional, extra classes to set on the action link (can be used by hooks on the action link)

Content hooks edit

{
	name: 'diff',
    onlyType: 'wiki_local',
	score: function ( $l, cache ) {
		if ( cache.has_param( 'oldid' ) ) {
			return 2000;
		}
		return null;
	}
	content: function ( $l, cache, callback ) {
	}
}

The name is a human-readable name to assist in debugging, as it can tell you which hook is running on which link.

onlyType is as for an action hook: only matching recogniser types will be inspected by score()

The score() function is as for a recogniser hook: the best-scored content hook will be used.

The content() function is run on the best-scored content hook. $l is the originating element, cache is as provided by the recogniser. Returns or resolves with content for the popup. This will be inserted into the body of the popup.

The score() function can add things to the cache for use by the content() function to avoid re-computation. For example, set cache.foo = "Bar" in score() and you can read it back in content()

Privacy edit

Requests to WMF wikis (e.g. Wikisource, Commons and Wikidata) are, as always, covered by the WMF Privacy Policy.

If you hover over external links, the tool may attempt a request to those links.

Links edit