DesktopArticleTarget: Rebuild the category links when they're edited

This has to go to the API, because it's skinnable. Also, separates out a few
of the initial page setup functions so they can be re-applied to the new
content inserted.

Bug: T151651
Change-Id: I8d5a6504edc2e0486a0b4f016d8ee6d9a6228de9
This commit is contained in:
David Lynch 2016-12-01 14:06:19 -06:00
parent 8a253c6405
commit af8aad0483

View file

@ -597,6 +597,7 @@ ve.init.mw.DesktopArticleTarget.prototype.cancel = function ( trackMechanism ) {
// Move original content back out of the target
target.$element.parent().append( target.$originalContent.children() );
$( '#catlinks' ).replaceWith( target.$originalCategories );
$( '.ve-init-mw-desktopArticleTarget-uneditableContent' )
.off( '.ve-target' )
.removeClass( 've-init-mw-desktopArticleTarget-uneditableContent' );
@ -742,45 +743,51 @@ ve.init.mw.DesktopArticleTarget.prototype.surfaceReady = function () {
* @param {boolean} [loading=false] Whether VE is loading.
*/
ve.init.mw.DesktopArticleTarget.prototype.onMetaItemInserted = function ( metaItem, loading ) {
var title, target, $link;
if ( metaItem.getType() === '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 );
var title, target, $link,
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' ) )
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' ) );
.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' ) );
break;
case 'mwCategory':
this.rebuildCategories( metaList.getItemsInGroup( 'mwCategory' ) );
break;
}
};
@ -792,12 +799,55 @@ ve.init.mw.DesktopArticleTarget.prototype.onMetaItemInserted = function ( metaIt
* @param {number} index Index within that offset the item was at
*/
ve.init.mw.DesktopArticleTarget.prototype.onMetaItemRemoved = function ( metaItem ) {
if ( metaItem.getType() === 'mwRedirect' ) {
this.$originalContent.find( '.redirectMsg' ).remove();
$( '#contentSub #redirectsub, #contentSub #redirectsub + br' ).remove();
var metaList = this.surface.getModel().getMetaList();
switch ( metaItem.getType() ) {
case 'mwRedirect':
this.$originalContent.find( '.redirectMsg' ).remove();
$( '#contentSub #redirectsub, #contentSub #redirectsub + br' ).remove();
break;
case 'mwCategory':
this.rebuildCategories( metaList.getItemsInGroup( 'mwCategory' ) );
break;
}
};
/**
* Redisplay the category list on the page
*
* @param {ve.dm.MetaItem[]} categoryItems Array of category metaitems to display
*/
ve.init.mw.DesktopArticleTarget.prototype.rebuildCategories = function ( categoryItems ) {
var target = this;
// We need to fetch this from the API because the category list is skin-
// dependent, so the HTML output could be absolutely anything.
new mw.Api().post( {
formatversion: 2,
action: 'parse',
contentmodel: 'wikitext',
text: categoryItems.map( function ( categoryItem ) {
// TODO: wikitext-building is a bad smell here, but is done
// because there's no other API call that will get the category
// markup. Adding such an API, if other use cases for it emerge,
// might make sense.
if ( categoryItem.getAttribute( 'sortkey' ) ) {
return '[[' + categoryItem.getAttribute( 'category' ) + '|' + categoryItem.getAttribute( 'sortkey' ) + ']]';
}
return '[[' + categoryItem.getAttribute( 'category' ) + ']]';
} ).join( '\n' ),
prop: 'categorieshtml'
} ).then( function ( response ) {
var $categories;
if ( !response || !response.parse || !response.parse.categorieshtml ) {
return;
}
$categories = $( $.parseHTML( response.parse.categorieshtml ) );
target.transformCategoryLinks( $categories );
target.disableUneditableContent( $categories );
mw.hook( 'wikipage.categories' ).fire( $categories );
$( '#catlinks' ).replaceWith( $categories );
} );
};
/**
* Handle Escape key presses.
*
@ -1126,8 +1176,7 @@ ve.init.mw.DesktopArticleTarget.prototype.restoreDocumentTitle = function () {
* Page modifications for switching to edit mode.
*/
ve.init.mw.DesktopArticleTarget.prototype.transformPage = function () {
var target = this,
$content;
var $content;
this.updateTabs( true );
this.emit( 'transformPage' );
@ -1136,6 +1185,7 @@ ve.init.mw.DesktopArticleTarget.prototype.transformPage = function () {
// Move all native content inside the target
this.$originalContent.append( this.$element.siblings() );
this.$originalCategories = $( '#catlinks' ).clone( true );
// Mark every non-direct ancestor between editableContent and the container as uneditable
$content = this.$editableContent;
@ -1145,22 +1195,41 @@ ve.init.mw.DesktopArticleTarget.prototype.transformPage = function () {
$content = $content.parent();
}
this.transformCategoryLinks( $( '.catlinks' ) );
this.disableUneditableContent();
this.updateHistoryState();
};
/**
* Category link section transformations for switching to edit mode. Broken out
* so it can be re-applied when displaying changes to the categories.
*
* @param {jQuery} $catlinks Category links container element
*/
ve.init.mw.DesktopArticleTarget.prototype.transformCategoryLinks = function ( $catlinks ) {
var target = this;
// Un-disable the catlinks wrapper, but not the links
$( '.catlinks' )
.removeClass( 've-init-mw-desktopArticleTarget-uneditableContent' )
$catlinks.removeClass( 've-init-mw-desktopArticleTarget-uneditableContent' )
.on( 'click.ve-target', function () {
var windowAction = ve.ui.actionFactory.create( 'window', target.getSurface() );
windowAction.open( 'meta', { page: 'categories' } );
return false;
} )
.find( 'a' ).addClass( 've-init-mw-desktopArticleTarget-uneditableContent' );
};
$( '.ve-init-mw-desktopArticleTarget-uneditableContent' ).on( 'click.ve-target', function ( e ) {
/**
* Disabling of non-editable content, in a given context
*
* @param {jQuery|string} [context] Context to disable in
*/
ve.init.mw.DesktopArticleTarget.prototype.disableUneditableContent = function ( context ) {
$( '.ve-init-mw-desktopArticleTarget-uneditableContent', context ).on( 'click.ve-target', function ( e ) {
// Support IE9: Prevent default, but don't stop propagation
e.preventDefault();
} );
this.updateHistoryState();
};
/**
@ -1223,6 +1292,10 @@ ve.init.mw.DesktopArticleTarget.prototype.restorePage = function () {
this.$originalRedirectSub = undefined;
}
if ( this.$originalCategories ) {
$( '#catlinks' ).replaceWith( this.$originalCategories );
}
mw.hook( 've.deactivate' ).fire();
this.emit( 'restorePage' );
@ -1306,7 +1379,7 @@ ve.init.mw.DesktopArticleTarget.prototype.replacePageContent = function (
html, categoriesHtml, displayTitle, lastModified, contentSub, isRedirect
) {
var $content = $( $.parseHTML( html ) ),
$veSectionLinks;
$veSectionLinks, $categories;
if ( lastModified ) {
// If we were not viewing the most recent revision before (a requirement
@ -1346,7 +1419,9 @@ ve.init.mw.DesktopArticleTarget.prototype.replacePageContent = function (
if ( displayTitle ) {
$( '#content #firstHeading' ).html( displayTitle );
}
$( '#catlinks' ).replaceWith( categoriesHtml );
$categories = $( $.parseHTML( categoriesHtml ) );
mw.hook( 'wikipage.categories' ).fire( $categories );
$( '#catlinks' ).replaceWith( $categories );
$( '#contentSub' ).html( contentSub );
if ( isRedirect ) {