Motivation
I’m really lazy. Also, I used to get pretty bad wrist pain in both of my wrists, making both typing and clicking pretty painful, so the act of double-clicking or click-and-dragging page titles in MediaWiki was super frustrating to me. I really wanted a way to click a single button and get something in my clipboard.
So I wrote a gadget to give me buttons that do exactly this: when clicked, they’ll copy the page name to your clipboard. Because sometimes you want the full name of a page, and sometimes you want only the title (without namespace), there are two of them; the top one gives you the title and the bottom one gives you the full page name. My mnemonic for remembering which is which is that the “smaller” one is sitting on top of the “bigger” one, but if you wanted to you could pretty easily replace the icon in the buttons with some text, e.g. Copy title
& Copy page name
or Copy title
& Copy prefixed title
if you don’t have the $wg
variable names memorized.
It looks like this:
As this is a tool for myself, it is not accessible - you can’t tab to these buttons, and you can’t click them via keyboard shortcuts. Please don’t emulate this design for production-ready tools that anyone should be able to use.
Code
JS
|
|
CSS
|
|
Explanation
JS
First, we’re going to create an element with the following DOM structure:
|
|
We’ll do that using jQuery:
|
|
And then we’ll insert this to our document inside of the #firstHeading
div, first wrapping the existing content in its own small container, so that if we use a display:flex;
, the elements that are already there stay grouped together.
|
|
Next, we’ll do the copy:
|
|
Here’s the feedback to the user:
|
|
If you click the first one (#title-copy-content
), then we’ll copy the $wgTitle
variable (available via mw.config.get('wgTitle')
); and if you click the second one (#title-copy-all
) then we’ll copy $wgPageName
instead. Title
is defined as the title of the page (without namespace) and PageName
is defined as the title of the page (with namespace), so this is what we want.
(Unlike $wgTitle
, $wgPageName
comes with underscores instead of spaces, and probably that’s not what you actually want to copy, so for the full-page-name case we also replace _
with
.)
But there are a couple exceptions; namely, Special:WhatLinksHere
and Special:MovePage
. These are both common things to check or do with pages, and we might want to a copy a title from one of these two locations. But they aren’t technically actions (i.e. the URL isn’t in the form ?action=move
); the wgTitle
of Special:WhatLinksHere/User:RheingoldRiver
isn’t RheingoldRiver
, but rather WhatLinksHere/User:RheingoldRiver
. You can confirm this by typing mw.config.get('wgTitle')
at any Special:WhatLinksHere page.
To fix this issue, we’ll fudge things a bit and compute the intended values.1 For copying the wgTitle
of the page we actually want, we have this regex:
|
|
Here is what each part of that regex means:
Text | Meaning |
---|---|
(WhatLinksHere|MovePage) |
Either WhatLinksHere or MovePage (title must start with one of these). Because we’re replacing with the empty string, we don’t have to worry about capture groups, so we’re safe to write (content here) and not (?:content here) . |
\/ |
A literal / character. This has to be escaped, because in JS / is the quote character for regular expressions, like /regex here/ . |
()? |
An optional capture group; that is, if it’s found select it, but if not it’s ok, don’t cancel the entire match over it. |
.+? |
1 or more characters, but instead of selecting as many as possible, select as few as possible. For example, while ca+ matching caaaaaaaaaat returns caaaaaaaaaa , ca+? returns ca . This is called a “lazy” selector (as opposed to being “greedy”). |
: |
The literal : character. Because we are looking for .+?: we are going to remove only up to the first : character, so if you have a page called something like User:RheingoldRiver/Template:Kittens you’ll get RheingoldRiver/Template:Kittens (which is the actual page name) instead of Kittens . |
The wgPageName
case is similar, but we also remove Special:
at the start, since the wgPageName
of Special:WhatLinksHere/Template:SomeTemplate
includes Special:
at the start, and we want just Template:SomeTemplate
in this case. Also, $wgPageName
uses underscores instead of spaces, so we’ll globally replace _
with
: .replace(/_/g, " ")
.
CSS
|
|
First, we import the FontAwesome
font. FontAwesome provides a bunch of useful characters that are hosted for free so you can use them anywhere on the web. Think of it as a modern-day Wingdings for the internet.
For best compatibility, there are a bunch of imports in this list, but browsers will only load one of them.
We’re going to add a FontAwesome copy icon like so:
|
|
In the actual elements of #title-copy-content
and #title-copy-all
all we have to do is apply cursor:pointer;
to signify to the user they can click these things.
For container holding #title-copy-content
and #title-copy-all
, we need to apply a bit of spacing to the left and make super duper sure no one will accidentally copy these when using click-and-drag to copy text. The unprefixed support for this is actually pretty low so we have a bunch of variants to make sure it works in Webkit etc. I’m pretty sure I copied this list from StackOverflow.
|
|
Finally we’ll make the entire container flex and align stuff at the start; this is basically equivalent to making everything display:inline-block;
, but it’s a bit more extensible if we add more things in this toolbar later:
|
|
Conclusion
The most complicated part of this gadget is probably the regular expression to fix the text for Special:WhatLinksHere
and Special:MovePage
special cases. The other big idea here is using pseudoelements to display icons via CSS, which is a very powerful pattern especially when working with FontAwesome. Happy coding!
-
In fact as written the code doesn’t work exactly correctly in all cases; if you have a page called
NotANamespace:Some Title
, whereNotANamespace
isn’t a namespace, you’ll lose that prefix even when trying to copy the full page name, and if you have a namespace with a colon in it, thewgTitle
case will fail. That said, both of these cases are really terrible and you should make an effort to avoid either one (especially don’t put a:
in any namespace name or your wiki title (which is the project namespace name)!). ↩︎