Merge "[refactor] switch reflist rendering source of truth"

This commit is contained in:
jenkins-bot 2024-07-03 09:54:52 +00:00 committed by Gerrit Code Review
commit 30de08bfe9
4 changed files with 84 additions and 10 deletions

View file

@ -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",

View file

@ -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"

View file

@ -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 );

View 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;
}, {} );
};