Merge "ArticleTarget: Change rendering of category preview"

This commit is contained in:
jenkins-bot 2018-05-15 13:28:57 +00:00 committed by Gerrit Code Review
commit 4ca3f1661d
5 changed files with 112 additions and 45 deletions

View file

@ -589,6 +589,8 @@
"colon-separator",
"newsectionsummary",
"pagecategories",
"pagecategorieslink",
"hidden-categories",
"parentheses",
"redirectto",
"tooltip-minoredit",

View file

@ -877,36 +877,22 @@ ve.init.mw.DesktopArticleTarget.prototype.onMetaItemRemoved = function ( metaIte
/**
* Redisplay the category list on the page
*
* This is used for the preview while editing. Leaving the editor either restores the initial
* categories, or uses the ones generated by the save API.
*
* @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.
this.getContentApi().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 );
mw.hook( 'wikipage.categories' ).fire( $categories );
$( '#catlinks' ).replaceWith( $categories );
this.renderCategories( categoryItems ).done( function ( $categories ) {
// Clone the existing catlinks for any specific properties which might
// be needed by the rest of the page. Also gives us a not-attached
// version, which we can pass to wikipage.categories as it requests.
var $catlinks = $( '#catlinks' ).clone().empty().append( $categories.children() );
target.transformCategoryLinks( $catlinks );
mw.hook( 'wikipage.categories' ).fire( $catlinks );
$( '#catlinks' ).replaceWith( $catlinks );
ve.init.platform.linkCache.styleParsoidElements( $catlinks, target.doc );
} );
};

View file

@ -2583,3 +2583,78 @@ ve.init.mw.ArticleTarget.prototype.updateRedirectInterface = function ( $sub, $m
$( '#mw-content-text' ).before( $msg );
}
};
/**
* Render a list of categories
*
* @param {ve.dm.MetaItem[]} categoryItems Array of category metaitems to display
* @return {jQuery.Promise} A promise which will be resolved with the rendered categories
*/
ve.init.mw.ArticleTarget.prototype.renderCategories = function ( categoryItems ) {
var $normal, $hidden,
promises = [],
categories = { hidden: [], normal: [] };
categoryItems.forEach( function ( categoryItem ) {
var attributes = ve.cloneObject( ve.getProp( categoryItem, 'element', 'attributes' ) );
promises.push( ve.init.platform.linkCache.get( attributes.category ).done( function ( result ) {
if ( result.hidden ) {
categories.hidden.push( attributes );
} else {
categories.normal.push( attributes );
}
} ) );
} );
return $.when.apply( $, promises ).then( function () {
var $output = $( '<div class="catlinks" />' );
function renderPageLink( page ) {
var title = mw.Title.newFromText( page.category || page );
return $( '<a>' ).attr( 'rel', 'mw:WikiLink' ).attr( 'href', title.getUrl() ).text( title.getMainText() );
}
function renderPageLinks( pages ) {
var i, $list = $( '<ul />' );
for ( i = 0; i < pages.length; i++ ) {
$list.append( $( '<li />' ).append( renderPageLink( pages[ i ] ) ) );
}
return $list;
}
function categorySort( a, b ) {
var sortA = a.sortkey || a.category,
sortB = b.sortkey || b.category;
if ( sortA < sortB ) {
return -1;
}
if ( sortA > sortB ) {
return 1;
}
return 0;
}
if ( categories.normal.length ) {
categories.normal.sort( categorySort );
$normal = $( '<div class="mw-normal-catlinks" />' );
$normal.append(
renderPageLink( ve.msg( 'pagecategorieslink' ) ).text( ve.msg( 'pagecategories', categories.normal.length ) ),
ve.msg( 'colon-separator' ),
renderPageLinks( categories.normal )
);
$output.append( $normal );
}
if ( categories.hidden.length ) {
categories.hidden.sort( categorySort );
$hidden = $( '<div class="mw-hidden-catlinks" />' );
if ( mw.user.options.get( 'showhiddencats' ) ) {
$hidden.addClass( 'mw-hidden-cats-user-shown' );
} else if ( mw.config.get( 'wgNamespaceIds' ).category === mw.config.get( 'wgNamespaceNumber' ) ) {
$hidden.addClass( 'mw-hidden-cats-ns-shown' );
} else {
$hidden.addClass( 'mw-hidden-cats-hidden' );
}
$hidden.append(
ve.msg( 'hidden-categories', categories.hidden.length ),
ve.msg( 'colon-separator' ),
renderPageLinks( categories.hidden )
);
$output.append( $hidden );
}
return $output;
} );
};

View file

@ -56,6 +56,7 @@ ve.init.mw.LinkCache.static.processPage = function ( page ) {
known: page.known !== undefined,
redirect: page.redirect !== undefined,
disambiguation: ve.getProp( page, 'pageprops', 'disambiguation' ) !== undefined,
hidden: ve.getProp( page, 'pageprops', 'hiddencat' ) !== undefined,
imageUrl: ve.getProp( page, 'thumbnail', 'source' ),
description: page.description
};
@ -191,7 +192,7 @@ ve.init.mw.LinkCache.prototype.getRequestPromise = function ( subqueue ) {
prop: 'info|pageprops|pageimages|description',
pithumbsize: 80,
pilimit: subqueue.length,
ppprop: 'disambiguation',
ppprop: 'disambiguation|hiddencat',
titles: subqueue,
'continue': ''
} );

View file

@ -189,10 +189,11 @@ ve.ui.MWSaveDialog.prototype.setDiffAndReview = function ( wikitextDiffPromise,
* @param {HTMLDocument} [baseDoc] Base document against which to normalise links, if document provided
*/
ve.ui.MWSaveDialog.prototype.showPreview = function ( docOrMsg, baseDoc ) {
var body, contents, $heading, redirectMeta,
var body, contents, $heading, redirectMeta, deferred,
$redirect = $(),
categories = [],
modules = [];
modules = [],
dialog = this;
if ( docOrMsg instanceof HTMLDocument ) {
// Extract required modules for stylesheet tags (avoids re-loading styles)
@ -210,7 +211,7 @@ ve.ui.MWSaveDialog.prototype.showPreview = function ( docOrMsg, baseDoc ) {
body = docOrMsg.body;
// Take a snapshot of all categories
Array.prototype.forEach.call( body.querySelectorAll( 'link[rel~="mw:PageProp/Category"]' ), function ( element ) {
categories.push( ve.dm.MWCategoryMetaItem.static.toDataElement( [ element ] ).attributes.category );
categories.push( ve.dm.nodeFactory.createFromElement( ve.dm.MWCategoryMetaItem.static.toDataElement( [ element ] ) ) );
} );
// Import body to current document, then resolve attributes against original document (parseDocument called #fixBase)
document.adoptNode( body );
@ -258,25 +259,27 @@ ve.ui.MWSaveDialog.prototype.showPreview = function ( docOrMsg, baseDoc ) {
)
);
if ( categories.length ) {
// Simple category list rendering
this.$previewViewer.append(
$( '<div>' ).addClass( 'catlinks' ).append(
document.createTextNode( ve.msg( 'pagecategories', categories.length ) + ve.msg( 'colon-separator' ) ),
$( '<ul>' ).append( categories.map( function ( category ) {
var title = mw.Title.newFromText( category );
return $( '<li>' ).append( $( '<a>' ).attr( 'rel', 'mw:WikiLink' ).attr( 'href', title.getUrl() ).text( title.getMainText() ) );
} ) )
)
);
}
ve.targetLinksToNewWindow( this.$previewViewer[ 0 ] );
// Add styles so links render with their appropriate classes
ve.init.platform.linkCache.styleParsoidElements( this.$previewViewer, baseDoc );
// Run hooks so other things can alter the document
mw.hook( 'wikipage.content' ).fire( this.$previewViewer );
if ( categories.length ) {
// If there are categories, we need to render them. This involves
// a delay, since they might be hidden categories.
deferred = ve.init.target.renderCategories( categories ).done( function ( $categories ) {
dialog.$previewViewer.append( $categories );
ve.targetLinksToNewWindow( $categories[ 0 ] );
// Add styles so links render with their appropriate classes
ve.init.platform.linkCache.styleParsoidElements( $categories, baseDoc );
} );
} else {
deferred = $.Deferred.resolve();
}
deferred.done( function () {
// Run hooks so other things can alter the document
mw.hook( 'wikipage.content' ).fire( dialog.$previewViewer );
} );
} else {
this.$previewViewer.empty().append(
$( '<em>' ).text( docOrMsg )