Bartosz Dziewoński has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/345166 )
Change subject: ve.init.mw.DesktopArticleTarget: Refactor redirect interface
handling
......................................................................
ve.init.mw.DesktopArticleTarget: Refactor redirect interface handling
Redirect pages have two extra things not present on normal pages:
* Redirect subtitle: the "Redirect page" shown under the page heading.
* Redirect page content header: the "↳ Foo" at the beginning of content.
Our handling was pretty messy and had some bugs (T161614).
Notable behavior changes:
* Update 'wgIsRedirect' in mw.config after saving the page.
* Use #mw-content-text rather than .mw-jump for inserting the fake .redirectMsg.
.mw-jump is not guaranteed to exist on the page (it's a skin feature).
* Never replace the real .redirectMsg existing on the page, except by the
new HTML after a page is saved. Our fake is separate now.
Bug: T161614
Change-Id: I96a5e45a71bf10bf6a2b501dc0cf81e6c37060ec
---
M modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.js
1 file changed, 134 insertions(+), 83 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor
refs/changes/66/345166/1
diff --git a/modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.js
b/modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.js
index 25880a6..498bc58 100644
--- a/modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.js
+++ b/modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.js
@@ -749,7 +749,8 @@
ve.init.mw.DesktopArticleTarget.prototype.surfaceReady = function () {
var surface = this.getSurface(),
surfaceReadyTime = ve.now(),
- target = this;
+ target = this,
+ redirectMetaItems;
if ( !this.activating ) {
// Activation was aborted before we got here. Do nothing
@@ -791,6 +792,13 @@
// Parent method
ve.init.mw.DesktopArticleTarget.super.prototype.surfaceReady.apply(
this, arguments );
+ redirectMetaItems =
this.getSurface().getModel().getMetaList().getItemsInGroup( 'mwRedirect' );
+ if ( redirectMetaItems.length ) {
+ this.setFakeRedirectInterface( redirectMetaItems[ 0
].getAttribute( 'title' ) );
+ } else {
+ this.setFakeRedirectInterface( null );
+ }
+
this.setupUnloadHandlers();
if ( !this.suppressNormalStartupDialogs ) {
this.maybeShowWelcomeDialog();
@@ -804,53 +812,15 @@
};
/**
- * Add the redirect header when a redirect is inserted into the page.
+ * Update the redirect and category interfaces when a meta item is inserted
into the page.
*
* @param {ve.dm.MetaItem} metaItem Item that was inserted
- * @param {boolean} [loading=false] Whether VE is loading.
*/
-ve.init.mw.DesktopArticleTarget.prototype.onMetaItemInserted = function (
metaItem, loading ) {
- var title, target, $link,
- metaList = this.surface.getModel().getMetaList();
+ve.init.mw.DesktopArticleTarget.prototype.onMetaItemInserted = function (
metaItem ) {
+ var metaList = this.surface.getModel().getMetaList();
switch ( metaItem.getType() ) {
case 'mwRedirect':
- target = this;
- title = metaItem.getAttribute( 'title' );
- $link = $( '<a>' )
- .attr( 'title', mw.msg(
'visualeditor-redirect-description', title ) )
- .text( title );
- ve.init.platform.linkCache.styleElement( title, $link );
-
- if ( loading ) {
- this.$originalRedirectMsg = $( '.redirectMsg'
).clone();
- this.$originalRedirectSub = $( '#redirectsub,
#redirectsub + br' ).clone();
- }
- // Add redirect target header
- if ( !$( '#redirectsub' ).length ) {
- $( '#contentSub' ).append(
- $( '<span>' )
- .text( mw.msg(
'redirectpagesub' ) )
- .attr( 'id', 'redirectsub' ),
- $( '<br>' )
- );
- }
- $( '<div>' )
- // Bit of a hack: Make sure any redirect note
is styled
- .addClass( 'redirectMsg mw-content-' + $(
'html' ).attr( 'dir' ) )
-
- .addClass( 've-redirect-header' )
- .append(
- $( '<p>' ).text( mw.msg( 'redirectto' )
),
- $( '<ul>' )
- .addClass( 'redirectText' )
- .append( $( '<li>' ).append(
$link ) )
- )
- .click( function ( e ) {
- var windowAction =
ve.ui.actionFactory.create( 'window', target.getSurface() );
- windowAction.open( 'meta', { page:
'settings' } );
- e.preventDefault();
- } )
- .insertAfter( $( '.mw-jump' ) );
+ this.setFakeRedirectInterface( metaItem.getAttribute(
'title' ) );
break;
case 'mwCategory':
this.rebuildCategories( metaList.getItemsInGroup(
'mwCategory' ) );
@@ -859,7 +829,7 @@
};
/**
- * Remove the redirect header when a redirect is removed from the page.
+ * Update the redirect and category interfaces when a meta item is removed
from the page.
*
* @param {ve.dm.MetaItem} metaItem Item that was removed
* @param {number} offset Linear model offset that the item was at
@@ -869,8 +839,7 @@
var metaList = this.surface.getModel().getMetaList();
switch ( metaItem.getType() ) {
case 'mwRedirect':
- this.$originalContent.find( '.redirectMsg' ).remove();
- $( '#contentSub #redirectsub, #contentSub #redirectsub
+ br' ).remove();
+ this.setFakeRedirectInterface( null );
break;
case 'mwCategory':
this.rebuildCategories( metaList.getItemsInGroup(
'mwCategory' ) );
@@ -1010,14 +979,17 @@
mw.config.set( jsconfigvars );
mw.loader.load( modules );
+ mw.config.set( {
+ wgIsRedirect: !!isRedirect
+ } );
+
this.saveDialog.reset();
this.replacePageContent(
html,
categoriesHtml,
displayTitle,
lastModified,
- contentSub,
- !!isRedirect
+ contentSub
);
if ( newid !== undefined ) {
@@ -1357,19 +1329,8 @@
// In skins having #ca-view (like Vector), select that.
this.updateTabs( false );
- // Remove any VE-added redirectMsg
- if ( $( '.mw-body-content > .ve-redirect-header' ).length ) {
- $( '.mw-body-content > .ve-redirect-header' ).remove();
- $( '#contentSub #redirectsub, #contentSub #redirectsub + br'
).remove();
- }
-
// Restore any previous redirectMsg/redirectsub
- if ( this.$originalRedirectMsg ) {
- this.$originalRedirectMsg.prependTo( $( '#mw-content-text' ) );
- this.$originalRedirectSub.prependTo( $( '#contentSub' ) );
- this.$originalRedirectMsg = undefined;
- this.$originalRedirectSub = undefined;
- }
+ this.setRealRedirectInterface();
if ( this.$originalCategories ) {
$( '#catlinks' ).replaceWith( this.$originalCategories );
}
@@ -1451,10 +1412,9 @@
* @param {Object} lastModified Object containing user-formatted date
* and time strings, or undefined if we made no change.
* @param {string} contentSub HTML to show as the content subtitle
- * @param {boolean} isRedirect Whether the page is a redirect or not.
*/
ve.init.mw.DesktopArticleTarget.prototype.replacePageContent = function (
- html, categoriesHtml, displayTitle, lastModified, contentSub, isRedirect
+ html, categoriesHtml, displayTitle, lastModified, contentSub
) {
var $content = $( $.parseHTML( html ) ),
$veSectionLinks, $categories, $sections, editedSectionHeader;
@@ -1475,10 +1435,6 @@
lastModified.time
) );
}
- // Remove any VE-added ve-redirect-header
- $( '.redirectMsg' ).removeClass( 've-redirect-header' );
- this.$originalRedirectMsg = undefined;
- this.$originalRedirectSub = undefined;
// Re-set any edit section handlers now that the page content has been
replaced
if (
@@ -1505,20 +1461,7 @@
this.$originalCategories = null;
$( '#contentSub' ).html( contentSub );
-
- if ( isRedirect ) {
- $( '#contentSub' ).append(
- $( '<span>' )
- .text( mw.msg( 'redirectpagesub' ) )
- .attr( 'id', 'redirectsub' ),
- $( '<br>' )
- );
- }
-
- // Bit of a hack: Make sure any redirect note is styled
- $( '.redirectMsg' )
- .addClass( 'mw-content-' + $( 'html' ).attr( 'dir' ) )
- .addClass( 've-redirect-header' );
+ this.setRealRedirectInterface();
// Scroll the page to the edited section, if any
if ( this.section !== null ) {
@@ -1619,10 +1562,7 @@
redirectMetaItems =
this.getSurface().getModel().getMetaList().getItemsInGroup( 'mwRedirect' );
if ( redirectMetaItems.length ) {
- this.onMetaItemInserted( redirectMetaItems[ 0 ], true );
-
windowAction = ve.ui.actionFactory.create( 'window',
this.getSurface() );
-
windowAction.open( 'meta', { page: 'settings' } );
}
};
@@ -1735,6 +1675,117 @@
this.getSurface().getView().getDocument().getDocumentNode().$element.css(
'opacity', 1 );
};
+/**
+ * Return DOM for the redirect page subtitle (#redirectsub).
+ *
+ * @return {jQuery}
+ */
+ve.init.mw.DesktopArticleTarget.prototype.buildRedirectSub = function () {
+ // Page subtitle
+ // Compare: Article::view()
+ return $( '<span>' )
+ .attr( 'id', 'redirectsub' )
+ .append( mw.message( 'redirectpagesub' ).parseDom() );
+};
+
+/**
+ * Return DOM for the redirect page content header (.redirectMsg).
+ *
+ * @param {string} title Redirect target
+ * @return {jQuery}
+ */
+ve.init.mw.DesktopArticleTarget.prototype.buildRedirectMsg = function ( title
) {
+ var target = this,
+ $link;
+
+ $link = $( '<a>' )
+ .attr( 'title', mw.msg( 'visualeditor-redirect-description',
title ) )
+ .text( title );
+ ve.init.platform.linkCache.styleElement( title, $link );
+
+ // Page content header
+ // Compare: Article::getRedirectHeaderHtml()
+ return $( '<div>' )
+ .addClass( 'redirectMsg' )
+ // We need to be able to tell apart the real one and our fake
one
+ .addClass( 've-redirect-header' )
+ // Hack: This is normally inside #mw-content-text, but we
insert it before, so we need this.
+ .addClass( 'mw-content-' + $( 'html' ).attr( 'dir' ) )
+ .append(
+ $( '<p>' ).text( mw.msg( 'redirectto' ) ),
+ $( '<ul>' )
+ .addClass( 'redirectText' )
+ .append( $( '<li>' ).append( $link ) )
+ )
+ .click( function ( e ) {
+ var windowAction = ve.ui.actionFactory.create(
'window', target.getSurface() );
+ windowAction.open( 'meta', { page: 'settings' } );
+ e.preventDefault();
+ } );
+};
+
+/**
+ * Display the given redirect subtitle and redirect page content header on the
page.
+ *
+ * @param {jQuery} $sub Redirect subtitle, see #buildRedirectSub
+ * @param {jQuery} $msg Redirect page content header, see #buildRedirectMsg
+ */
+ve.init.mw.DesktopArticleTarget.prototype.updateRedirectInterface = function (
$sub, $msg ) {
+ var $currentSub, $currentMsg, $subtitle;
+
+ // For the subtitle, replace the real one with ours.
+ // This is more complicated than it should be because we have to fiddle
with the <br>.
+ $currentSub = $( '#redirectsub' );
+ if ( $currentSub.length ) {
+ if ( $sub.length ) {
+ $currentSub.replaceWith( $sub );
+ } else {
+ $currentSub.prev().filter( 'br' ).remove();
+ $currentSub.remove();
+ }
+ } else {
+ $subtitle = $( '#contentSub' );
+ if ( $sub.length ) {
+ if ( $subtitle.children().length ) {
+ $subtitle.append( $( '<br>' ) );
+ }
+ $subtitle.append( $sub );
+ }
+ }
+
+ // For the content header, the real one is hidden, insert ours before
it.
+ $currentMsg = $( '.ve-redirect-header' );
+ if ( $currentMsg.length ) {
+ $currentMsg.replaceWith( $msg );
+ } else {
+ // Hack: This is normally inside #mw-content-text, but that's
hidden while editing.
+ $( '#mw-content-text' ).before( $msg );
+ }
+};
+
+/**
+ * Set temporary redirect interface to match the current state of redirection
in the editor.
+ *
+ * @param {string|null} title Current redirect target, or null if none
+ */
+ve.init.mw.DesktopArticleTarget.prototype.setFakeRedirectInterface = function
( title ) {
+ this.updateRedirectInterface(
+ title ? this.buildRedirectSub() : $(),
+ title ? this.buildRedirectMsg( title ) : $()
+ );
+};
+
+/**
+ * Set the redirect interface to match the page's redirect state.
+ */
+ve.init.mw.DesktopArticleTarget.prototype.setRealRedirectInterface = function
() {
+ this.updateRedirectInterface(
+ mw.config.get( 'wgIsRedirect' ) ? this.buildRedirectSub() : $(),
+ // Remove our custom content header - the original one in
#mw-content-text will be shown
+ $()
+ );
+};
+
/* Registration */
ve.init.mw.targetFactory.register( ve.init.mw.DesktopArticleTarget );
--
To view, visit https://gerrit.wikimedia.org/r/345166
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I96a5e45a71bf10bf6a2b501dc0cf81e6c37060ec
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Bartosz Dziewoński <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits