From c49bd9cb14a9af678b155d1faecc93413945a8de Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bartosz=20Dziewo=C5=84ski?= Date: Tue, 8 Jul 2014 02:50:37 +0200 Subject: [PATCH] On redirects update the URL to that of the target page with JavaScript MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- RELEASE-NOTES-1.24 | 3 + includes/page/Article.php | 26 ++++++-- resources/Resources.php | 9 ++- .../mediawiki.action.view.redirect.js | 65 +++++++++++++++++++ ...ediawiki.action.view.redirectToFragment.js | 35 ---------- 5 files changed, 95 insertions(+), 43 deletions(-) create mode 100644 resources/src/mediawiki.action/mediawiki.action.view.redirect.js delete mode 100644 resources/src/mediawiki.action/mediawiki.action.view.redirectToFragment.js diff --git a/RELEASE-NOTES-1.24 b/RELEASE-NOTES-1.24 index b354cc0d6f..01f8b0a6ca 100644 --- a/RELEASE-NOTES-1.24 +++ b/RELEASE-NOTES-1.24 @@ -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 diff --git a/includes/page/Article.php b/includes/page/Article.php index da88a69c1d..984b01d15e 100644 --- a/includes/page/Article.php +++ b/includes/page/Article.php @@ -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 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; } } diff --git a/resources/Resources.php b/resources/Resources.php index 092660c0f6..24e377d49f 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -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', ), diff --git a/resources/src/mediawiki.action/mediawiki.action.view.redirect.js b/resources/src/mediawiki.action/mediawiki.action.view.redirect.js new file mode 100644 index 0000000000..c87ff7cbc6 --- /dev/null +++ b/resources/src/mediawiki.action/mediawiki.action.view.redirect.js @@ -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 . + // 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 ) ); diff --git a/resources/src/mediawiki.action/mediawiki.action.view.redirectToFragment.js b/resources/src/mediawiki.action/mediawiki.action.view.redirectToFragment.js deleted file mode 100644 index cbfd7b559b..0000000000 --- a/resources/src/mediawiki.action/mediawiki.action.view.redirectToFragment.js +++ /dev/null @@ -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 . - // 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 ) ); -- 2.20.1