mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Cite
synced 2024-11-27 16:30:12 +00:00
[refactor] switch reflist rendering source of truth
Pure refactor which shouldn't change output in production. Switches to interfacing with MWDocumentReferences to get refs in index order. Temporarily suppresses any subrefs, we only show top-level refs. Bug: T247921 Change-Id: I9c8347b064173027f436722c87e15e0381c958bd
This commit is contained in:
parent
d5a4ecd647
commit
d03d2d8d20
|
@ -71,6 +71,7 @@
|
|||
"localBasePath": "modules/ve-cite",
|
||||
"remoteExtPath": "Cite/modules/ve-cite",
|
||||
"scripts": [
|
||||
"ve.dm.MWDocumentReferences.js",
|
||||
"ve.dm.MWReferenceModel.js",
|
||||
"ve.dm.MWReferencesListNode.js",
|
||||
"ve.dm.MWReferenceNode.js",
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"mw.": "https://doc.wikimedia.org/mediawiki-core/master/js/{type}.html"
|
||||
},
|
||||
"prefixMapIgnore": [
|
||||
"ve.dm.MWDocumentReferences",
|
||||
"ve.dm.MWReference",
|
||||
"ve.ce.MWReference",
|
||||
"ve.ui.MWReference"
|
||||
|
|
|
@ -27,6 +27,7 @@ ve.ce.MWReferencesListNode = function VeCeMWReferencesListNode() {
|
|||
this.internalList = null;
|
||||
this.listNode = null;
|
||||
this.modified = false;
|
||||
this.docRefs = null;
|
||||
|
||||
// DOM changes
|
||||
this.$element.addClass( 've-ce-mwReferencesListNode' );
|
||||
|
@ -174,6 +175,7 @@ ve.ce.MWReferencesListNode.prototype.update = function () {
|
|||
return;
|
||||
}
|
||||
|
||||
this.docRefs = ve.dm.MWDocumentReferences.static.refsForDoc( model.getDocument() );
|
||||
const internalList = model.getDocument().internalList;
|
||||
const refGroup = model.getAttribute( 'refGroup' );
|
||||
const listGroup = model.getAttribute( 'listGroup' );
|
||||
|
@ -238,9 +240,11 @@ ve.ce.MWReferencesListNode.prototype.update = function () {
|
|||
this.$refmsg.text( emptyText );
|
||||
this.$element.append( this.$refmsg );
|
||||
} else {
|
||||
const groupedByParent = this.docRefs.getGroupRefsByParents( listGroup );
|
||||
const topLevelNodes = groupedByParent[ '' ] || [];
|
||||
this.$reflist.append(
|
||||
nodes.indexOrder.map( ( index ) => this.renderListItem(
|
||||
nodes, internalList, refGroup, index
|
||||
topLevelNodes.map( ( node ) => this.renderListItem(
|
||||
nodes, internalList, refGroup, node
|
||||
) )
|
||||
);
|
||||
|
||||
|
@ -256,11 +260,12 @@ ve.ce.MWReferencesListNode.prototype.update = function () {
|
|||
* @param {Object} nodes Node group object, containing nodes and key order array
|
||||
* @param {ve.dm.InternalList} internalList Internal list
|
||||
* @param {string} refGroup Reference group
|
||||
* @param {number} index Item index
|
||||
* @return {jQuery} List item
|
||||
* @param {ve.dm.MWReferenceNode} node Reference node to render as a footnote body
|
||||
* @return {jQuery} Rendered list item
|
||||
*/
|
||||
ve.ce.MWReferencesListNode.prototype.renderListItem = function ( nodes, internalList, refGroup, index ) {
|
||||
const key = internalList.keys[ index ];
|
||||
ve.ce.MWReferencesListNode.prototype.renderListItem = function ( nodes, internalList, refGroup, node ) {
|
||||
const listIndex = node.getAttribute( 'listIndex' );
|
||||
const key = internalList.keys[ listIndex ];
|
||||
const keyedNodes = ( nodes.keyedNodes[ key ] || [] )
|
||||
.filter(
|
||||
// Exclude placeholders and references defined inside the references list node
|
||||
|
@ -271,7 +276,7 @@ ve.ce.MWReferencesListNode.prototype.renderListItem = function ( nodes, internal
|
|||
.append( this.renderBacklinks( keyedNodes, refGroup ), ' ' );
|
||||
|
||||
// Generate reference HTML from first item in key
|
||||
const modelNode = internalList.getItemNode( index );
|
||||
const modelNode = internalList.getItemNode( listIndex );
|
||||
if ( modelNode && modelNode.length ) {
|
||||
const refPreview = new ve.ui.MWPreviewElement( modelNode, { useView: true } );
|
||||
$li.append(
|
||||
|
@ -285,8 +290,7 @@ ve.ce.MWReferencesListNode.prototype.renderListItem = function ( nodes, internal
|
|||
// TODO: attach to the singleton click handler on the surface
|
||||
$li.on( 'mousedown', ( e ) => {
|
||||
if ( ve.isUnmodifiedLeftClick( e ) && modelNode && modelNode.length ) {
|
||||
const firstNode = nodes.firstNodes[ index ];
|
||||
const items = ve.ui.contextItemFactory.getRelatedItems( [ firstNode ] )
|
||||
const items = ve.ui.contextItemFactory.getRelatedItems( [ node ] )
|
||||
.filter( ( item ) => item.name !== 'mobileActions' );
|
||||
if ( items.length ) {
|
||||
const contextItem = ve.ui.contextItemFactory.lookup( items[ 0 ].name );
|
||||
|
@ -296,7 +300,7 @@ ve.ce.MWReferencesListNode.prototype.renderListItem = function ( nodes, internal
|
|||
if ( command ) {
|
||||
const fragmentArgs = {
|
||||
fragment: surface.getModel()
|
||||
.getLinearFragment( firstNode.getOuterRange(), true ),
|
||||
.getLinearFragment( node.getOuterRange(), true ),
|
||||
selectFragmentOnClose: false
|
||||
};
|
||||
const newArgs = ve.copy( command.args );
|
||||
|
|
68
modules/ve-cite/ve.dm.MWDocumentReferences.js
Normal file
68
modules/ve-cite/ve.dm.MWDocumentReferences.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
'use strict';
|
||||
|
||||
/*!
|
||||
* @copyright 2024 VisualEditor Team's Cite sub-team and others; see AUTHORS.txt
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* A facade providing a simplified and safe interface to Cite `ref` and
|
||||
* `references` tags in a document.
|
||||
*
|
||||
* @constructor
|
||||
* @mixes OO.EventEmitter
|
||||
* @param {ve.dm.Document} doc The document that reference tags will be embedded in.
|
||||
*/
|
||||
ve.dm.MWDocumentReferences = function VeDmMWDocumentReferences( doc ) {
|
||||
// Mixin constructors
|
||||
OO.EventEmitter.call( this );
|
||||
|
||||
// Properties
|
||||
this.doc = doc;
|
||||
};
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
OO.mixinClass( ve.dm.MWDocumentReferences, OO.EventEmitter );
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
* Singleton MWDocumentReferences for a document.
|
||||
*
|
||||
* @param {ve.dm.Document} doc Source document associated with the singleton
|
||||
* @return {ve.dm.MWDocumentReferences} Singleton docRefs
|
||||
*/
|
||||
ve.dm.MWDocumentReferences.static.refsForDoc = function ( doc ) {
|
||||
let docRefs = doc.getStorage( 'document-references-store' );
|
||||
if ( docRefs === undefined ) {
|
||||
docRefs = new ve.dm.MWDocumentReferences( doc );
|
||||
doc.setStorage( 'document-references-store', docRefs );
|
||||
}
|
||||
return docRefs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all refs for a group, organized by parent ref
|
||||
*
|
||||
* This is appropriate when rendering a reflist organized hierarchically by
|
||||
* subrefs using the `extends` feature.
|
||||
*
|
||||
* @param {string} groupName Filter by this group.
|
||||
* @return {Object.<string, ve.dm.MWReferenceNode[]>} Mapping from parent ref
|
||||
* name to a list of its subrefs. Note that the top-level refs are under the
|
||||
* `null` value.
|
||||
*/
|
||||
ve.dm.MWDocumentReferences.prototype.getGroupRefsByParents = function ( groupName ) {
|
||||
const nodeGroup = this.doc.getInternalList().getNodeGroup( groupName );
|
||||
return ( nodeGroup ? nodeGroup.indexOrder : [] )
|
||||
.reduce( ( acc, index ) => {
|
||||
const node = nodeGroup.firstNodes[ index ];
|
||||
const extendsRef = node.element.attributes.extendsRef || '';
|
||||
if ( acc[ extendsRef ] === undefined ) {
|
||||
acc[ extendsRef ] = [];
|
||||
}
|
||||
acc[ extendsRef ].push( node );
|
||||
return acc;
|
||||
}, {} );
|
||||
};
|
Loading…
Reference in a new issue