On redirects update the URL to that of the target page with JavaScript

Redirects to sections will now update the URL in browser's address bar
using the HTML5 History API. When [[Dog]] redirects to [[Animals#Dog]],
the user will now see "Animals#Dog" in their browser instead of "Dog#Dog".

The target URL is generated server-side to avoid pulling in dependencies
in the client-side RL module, which is loaded in the top queue.

Browsers that do not support the History API are still supported, the
way they always were.

Given the following three pages:
* A: #REDIRECT [[C]]
* B: #REDIRECT [[C#Section]]
* C: ==Section== \n ==Other section== \n

The following links should behave as follows:
* A                →  C
* B                →  C#Section
* A#Other_section  →  C#Other_section
* B#Other_section  →  C#Other_section

The code also supports forwarding query parameters like 'debug=1'.

Bug: 35045
Bug: 39328
Change-Id: I9d8d834762e19b836b7e35122b6c4cef0f91b7f0
This commit is contained in:
Bartosz Dziewoński 2014-07-08 02:50:37 +02:00
parent 417bd4e92a
commit c49bd9cb14
5 changed files with 95 additions and 43 deletions

View file

@ -163,6 +163,9 @@ production.
log in, rather than being shown a page asking them to log in and having to click
another link to actually get to the login page.
* A JSONContent and JSONContentHandler were added for extensions to extend.
* (bug 35045) Redirects to sections will now update the URL in browser's address
bar using the HTML5 History API. When [[Dog]] redirects to [[Animals#Dog]],
the user will now see "Animals#Dog" in their browser instead of "Dog#Dog".
=== Bug fixes in 1.24 ===
* (bug 50572) MediaWiki:Blockip should support gender

View file

@ -975,7 +975,14 @@ class Article implements Page {
global $wgRedirectSources;
$outputPage = $this->getContext()->getOutput();
$rdfrom = $this->getContext()->getRequest()->getVal( 'rdfrom' );
$request = $this->getContext()->getRequest();
$rdfrom = $request->getVal( 'rdfrom' );
// Construct a URL for the current page view, but with the target title
$query = $request->getValues();
unset( $query['rdfrom'] );
unset( $query['title'] );
$redirectTargetUrl = $this->getTitle()->getLinkURL( $query );
if ( isset( $this->mRedirectedFrom ) ) {
// This is an internally redirected page view.
@ -990,11 +997,12 @@ class Article implements Page {
$outputPage->addSubtitle( wfMessage( 'redirectedfrom' )->rawParams( $redir ) );
// Set the fragment if one was specified in the redirect
if ( $this->getTitle()->hasFragment() ) {
$outputPage->addJsConfigVars( 'wgRedirectToFragment', $this->getTitle()->getFragmentForURL() );
$outputPage->addModules( 'mediawiki.action.view.redirectToFragment' );
}
// Add the script to update the displayed URL and
// set the fragment if one was specified in the redirect
$outputPage->addJsConfigVars( array(
'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
) );
$outputPage->addModules( 'mediawiki.action.view.redirect' );
// Add a <link rel="canonical"> tag
$outputPage->setCanonicalUrl( $this->getTitle()->getLocalURL() );
@ -1011,6 +1019,12 @@ class Article implements Page {
$redir = Linker::makeExternalLink( $rdfrom, $rdfrom );
$outputPage->addSubtitle( wfMessage( 'redirectedfrom' )->rawParams( $redir ) );
// Add the script to update the displayed URL
$outputPage->addJsConfigVars( array(
'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
) );
$outputPage->addModules( 'mediawiki.action.view.redirect' );
return true;
}
}

View file

@ -1045,13 +1045,18 @@ return array(
'postedit-confirmation-saved',
),
),
'mediawiki.action.view.redirectToFragment' => array(
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.redirectToFragment.js',
'mediawiki.action.view.redirect' => array(
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.redirect.js',
'dependencies' => array(
'jquery.client',
),
'position' => 'top',
),
// Deployment hack for compatibility with cached HTML, remove before 1.24 release
'mediawiki.action.view.redirectToFragment' => array(
'dependencies' => 'mediawiki.action.view.redirect',
'position' => 'top',
),
'mediawiki.action.view.rightClickEdit' => array(
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.rightClickEdit.js',
),

View file

@ -0,0 +1,65 @@
/*!
* JavaScript to update page URL when a redirect is viewed, ensuring that the
* page is scrolled to the id when it's a redirect with fragment.
*
* This is loaded in the top queue, so avoid unnecessary dependencies
* like mediawiki.Title or mediawiki.Uri.
*/
( function ( mw, $ ) {
var profile = $.client.profile(),
canonical = mw.config.get( 'wgInternalRedirectTargetUrl' ),
fragment = null,
shouldChangeFragment, index;
// Clear internal mw.config entries, so that no one tries to depend on them
mw.config.set( 'wgInternalRedirectTargetUrl', null );
// Deployment hack for compatibility with cached HTML, remove before 1.24 release
if ( !canonical ) {
canonical = mw.config.get( 'wgRedirectToFragment' );
}
index = canonical.indexOf( '#' );
if ( index !== -1 ) {
fragment = canonical.slice( index );
}
// Never override the fragment if the user intended to look at a different section
shouldChangeFragment = fragment && !location.hash;
// Replace the whole URL if possible, otherwise just change the fragment
if ( canonical && history.replaceState ) {
if ( !shouldChangeFragment ) {
// If the current page view has a fragment already, don't override it
canonical = canonical.replace( /#.*$/, '' );
canonical += location.hash;
}
// This will also cause the browser to scroll to given fragment
history.replaceState( /*data=*/ history.state, /*title=*/ document.title, /*url=*/ canonical );
} else if ( shouldChangeFragment ) {
if ( profile.layout === 'webkit' && profile.layoutVersion < 420 ) {
// Released Safari w/ WebKit 418.9.1 messes up horribly
// Nightlies of 420+ are ok
return;
}
location.hash = fragment;
}
if ( shouldChangeFragment && profile.layout === 'gecko' ) {
// Mozilla needs to wait until after load, otherwise the window doesn't
// scroll. See <https://bugzilla.mozilla.org/show_bug.cgi?id=516293>.
// There's no obvious way to detect this programmatically, so we use
// version-testing. If Firefox fixes the bug, they'll jump twice, but
// better twice than not at all, so make the fix hit future versions as
// well.
$( function () {
if ( location.hash === fragment ) {
location.hash = fragment;
}
} );
}
}( mediaWiki, jQuery ) );

View file

@ -1,35 +0,0 @@
/*!
* JavaScript to scroll the page to an id, when a redirect with fragment is viewed.
*/
( function ( mw, $ ) {
var profile = $.client.profile(),
fragment = mw.config.get( 'wgRedirectToFragment' );
if ( fragment === null ) {
// nothing to do
return;
}
if ( profile.layout === 'webkit' && profile.layoutVersion < 420 ) {
// Released Safari w/ WebKit 418.9.1 messes up horribly
// Nightlies of 420+ are ok
return;
}
if ( !window.location.hash ) {
window.location.hash = fragment;
// Mozilla needs to wait until after load, otherwise the window doesn't
// scroll. See <https://bugzilla.mozilla.org/show_bug.cgi?id=516293>.
// There's no obvious way to detect this programmatically, so we use
// version-testing. If Firefox fixes the bug, they'll jump twice, but
// better twice than not at all, so make the fix hit future versions as
// well.
if ( profile.layout === 'gecko' ) {
$( function () {
if ( window.location.hash === fragment ) {
window.location.hash = fragment;
}
} );
}
}
}( mediaWiki, jQuery ) );