jenkins-bot has submitted this change and it was merged.
Change subject: Ref in references support
......................................................................
Ref in references support
When we encounter a ref tag inside the mw-data of a references
tag, we pass it off to the converter and store it as nested data.
In toDomElements we convert any nested children and write them
back to mw-data if changed.
As refs in references are invisible we exclude them when generating
the references list in ve.ce.MWReferenceListNode.
Bug: 51741
Change-Id: I31d06616849a00449df0fc77f3b33e46207cdc7f
---
M modules/ve-mw/ce/nodes/ve.ce.MWReferenceListNode.js
M modules/ve-mw/dm/nodes/ve.dm.MWReferenceListNode.js
M modules/ve-mw/test/dm/ve.dm.mwExample.js
3 files changed, 179 insertions(+), 102 deletions(-)
Approvals:
Catrope: Looks good to me, approved
jenkins-bot: Verified
diff --git a/modules/ve-mw/ce/nodes/ve.ce.MWReferenceListNode.js
b/modules/ve-mw/ce/nodes/ve.ce.MWReferenceListNode.js
index 0cf90c9..0c7b908 100644
--- a/modules/ve-mw/ce/nodes/ve.ce.MWReferenceListNode.js
+++ b/modules/ve-mw/ce/nodes/ve.ce.MWReferenceListNode.js
@@ -149,12 +149,27 @@
index = nodes.indexOrder[i];
firstNode = nodes.firstNodes[index];
- $li = $( '<li>' );
-
key = internalList.keys[index];
keyedNodes = nodes.keyedNodes[key] || [];
- for ( j = 0, jLen = keyedNodes.length; j < jLen; j++ ) {
- if ( keyedNodes.length > 1 ) {
+ // Exclude references defined inside the reference list
node
+ /*jshint loopfunc:true */
+ keyedNodes = keyedNodes.filter( function ( node ) {
+ while ( ( node = node.parent ) && node !== null
) {
+ if ( node instanceof
ve.dm.MWReferenceListNode ) {
+ return false;
+ }
+ }
+ return true;
+ } );
+
+ if ( !keyedNodes.length ) {
+ continue;
+ }
+
+ $li = $( '<li>' );
+
+ if ( keyedNodes.length > 1 ) {
+ for ( j = 0, jLen = keyedNodes.length; j <
jLen; j++ ) {
$li.append(
$( '<sup>' ).append(
$( '<a>' ).text( ( i +
1 ) + '.' + j )
diff --git a/modules/ve-mw/dm/nodes/ve.dm.MWReferenceListNode.js
b/modules/ve-mw/dm/nodes/ve.dm.MWReferenceListNode.js
index bd5f82d..771d8ac 100644
--- a/modules/ve-mw/dm/nodes/ve.dm.MWReferenceListNode.js
+++ b/modules/ve-mw/dm/nodes/ve.dm.MWReferenceListNode.js
@@ -9,23 +9,25 @@
* DataModel MediaWiki reference list node.
*
* @class
- * @extends ve.dm.LeafNode
+ * @extends ve.dm.BranchNode
* @constructor
* @param {number} [length] Length of content data in document; ignored and
overridden to 0
* @param {Object} [element] Reference to element in linear model
*/
ve.dm.MWReferenceListNode = function VeDmMWReferenceListNode( length, element
) {
// Parent constructor
- ve.dm.LeafNode.call( this, 0, element );
+ ve.dm.BranchNode.call( this, 0, element );
};
/* Inheritance */
-ve.inheritClass( ve.dm.MWReferenceListNode, ve.dm.LeafNode );
+ve.inheritClass( ve.dm.MWReferenceListNode, ve.dm.BranchNode );
/* Static members */
ve.dm.MWReferenceListNode.static.name = 'mwReferenceList';
+
+ve.dm.MWReferenceListNode.static.handlesOwnChildren = true;
ve.dm.MWReferenceListNode.static.matchTagNames = null;
@@ -33,13 +35,14 @@
ve.dm.MWReferenceListNode.static.storeHtmlAttributes = false;
-ve.dm.MWReferenceListNode.static.toDataElement = function ( domElements ) {
- var mwDataJSON = domElements[0].getAttribute( 'data-mw' ),
+ve.dm.MWReferenceListNode.static.toDataElement = function ( domElements,
converter ) {
+ var referenceListData, $contents, contentsData,
+ mwDataJSON = domElements[0].getAttribute( 'data-mw' ),
mwData = mwDataJSON ? JSON.parse( mwDataJSON ) : {},
refGroup = mwData.attrs && mwData.attrs.group || '',
listGroup = 'mwReference/' + refGroup;
- return {
+ referenceListData = {
'type': this.name,
'attributes': {
'mw': mwData,
@@ -50,11 +53,23 @@
'listGroup': listGroup
}
};
+ if ( mwData.body && mwData.body.html ) {
+ $contents = $( '<div>' ).append( mwData.body.html );
+ contentsData = converter.getDataFromDomRecursionClean(
$contents[0] );
+ return [ referenceListData ].
+ concat( contentsData ).
+ concat( [ { 'type': '/' + this.name } ] );
+ } else {
+ return referenceListData;
+ }
+
};
-ve.dm.MWReferenceListNode.static.toDomElements = function ( dataElement, doc )
{
- var el, els, mwData, originalMw,
- attribs = dataElement.attributes;
+ve.dm.MWReferenceListNode.static.toDomElements = function ( data, doc,
converter ) {
+ var el, els, mwData, originalMw, wrapper, contentsHtml, originalHtml,
+ dataElement = data[0],
+ attribs = dataElement.attributes,
+ contentsData = data.slice( 1, -1 );
if ( attribs.domElements ) {
// If there's more than 1 element, preserve entire array, not
just first element
@@ -80,6 +95,17 @@
}
el.setAttribute( 'typeof', 'mw:Extension/references' );
+ if ( contentsData.length > 2 ) {
+ wrapper = doc.createElement( 'div' );
+ converter.getDomSubtreeFromData( data.slice( 1, -1 ), wrapper );
+ contentsHtml = $( wrapper ).html(); // Returns '' if wrapper is
empty
+ originalHtml = ve.getProp( mwData, 'body', 'html' ) || '';
+ // Only set body.html if contentsHtml and originalHtml are
actually different
+ if ( !$( '<div>' ).html( originalHtml ).get( 0 ).isEqualNode(
wrapper ) ) {
+ ve.setProp( mwData, 'body', 'html', contentsHtml );
+ }
+ }
+
// If mwData and originalMw are the same, use originalMw to prevent
reserialization.
// Reserialization has the potential to reorder keys and so change the
DOM unnecessarily
originalMw = attribs.originalMw;
diff --git a/modules/ve-mw/test/dm/ve.dm.mwExample.js
b/modules/ve-mw/test/dm/ve.dm.mwExample.js
index 073c2d0..a81d1da 100644
--- a/modules/ve-mw/test/dm/ve.dm.mwExample.js
+++ b/modules/ve-mw/test/dm/ve.dm.mwExample.js
@@ -126,6 +126,18 @@
'value': $( ve.dm.mwExample.MWTransclusion.mixed ).toArray()
};
+ve.dm.mwExample.MWReference = {
+ 'referenceList':
+ '<ol class="references" typeof="mw:Extension/references"
about="#mwt7" data-parsoid="{}"' +
+
'data-mw="{"name":"references","body":{' +
+ '"extsrc":"<ref
name=\\"foo\\">Ref in refs</ref>' +
+ '","html":"<span
about=\\"#mwt8\\" class=\\"reference\\" ' +
+
'data-mw=\\"{&quot;name&quot;:&quot;ref&quot;,&quot;body&quot;:{&quot;html&quot;:&quot;Ref
in refs&quot;},' +
+
'&quot;attrs&quot;:{&quot;name&quot;:&quot;foo&quot;}}\\"
' +
+ 'rel=\\"dc:references\\"
typeof=\\"mw:Extension/ref\\">' +
+ '<a
href=\\"#cite_note-foo-3\\">[3]</a></span>"},"attrs":{}}"></ol>'
+};
+
ve.dm.mwExample.mwNowikiAnnotation = {
'type': 'mwNowiki',
'attributes': {
@@ -823,45 +835,35 @@
]
},
'mw:Reference': {
+ // Wikitext:
+ // Foo<ref name="bar" /> Baz<ref name="quux">Quux</ref>
Whee<ref name="bar">[[Bar]]</ref> Yay<ref group="g1">No name</ref> Quux<ref
name="bar">Different content</ref> Foo<ref group="g1">No name</ref> Bar<ref
name="foo" />
+ // <references><ref name="foo">Ref in refs</ref></references>
'html':
'<body>' +
'<p>Foo' +
- '<span id="cite_ref-bar-1-0"
class="reference" about="#mwt5" typeof="mw:Extension/ref" ' +
- 'data-parsoid="{}" ' +
-
'data-mw="{"name":"ref","attrs":{"name":"bar"}}">'
+
- '<a href="#cite_note-bar-1"
data-parsoid="{}">[1]</a>' +
+ '<span about="#mwt1" class="reference"
data-mw="{"name":"ref","attrs":{"name":"bar"}}"
id="cite_ref-bar-1-0" rel="dc:references" typeof="mw:Extension/ref"
data-parsoid="{}">' +
+ '<a
href="#cite_note-bar-1">[1]</a>' +
'</span>' +
' Baz' +
- '<span id="cite_ref-quux-2-0"
class="reference" about="#mwt6" typeof="mw:Extension/ref" ' +
- 'data-parsoid="{}" ' +
-
'data-mw="{"name":"ref","body":{"html":"Quux"},"attrs":{"name":"quux"}}">'
+
- '<a href="#cite_note-quux-2"
data-parsoid="{}">[2]</a>' +
+ '<span about="#mwt2" class="reference"
data-mw="{"name":"ref","body":{"html":"Quux"},"attrs":{"name":"quux"}}"
id="cite_ref-quux-2-0" rel="dc:references" typeof="mw:Extension/ref"
data-parsoid="{}">' +
'</span>' +
' Whee' +
- '<span id="cite_ref-bar-1-1"
class="reference" about="#mwt7" typeof="mw:Extension/ref" ' +
- 'data-parsoid="{}" ' +
-
'data-mw="{"name":"ref","body":{"html":"<a
rel=\\"mw:WikiLink\\" ' +
-
'href=\\"./Bar\\">Bar</a>"},"attrs":{"name":"bar"}}">'
+
- '<a href="#cite_note-bar-1"
data-parsoid="{}">[1]</a>' +
+ '<span about="#mwt3" class="reference"
data-mw="{"name":"ref","body":{"html":"'
+
+ '<a rel=\\"mw:WikiLink\\"
href=\\"./Bar\\">Bar' +
+
'</a>"},"attrs":{"name":"bar"}}"
id="cite_ref-bar-1-1" rel="dc:references" typeof="mw:Extension/ref"
data-parsoid="{}">' +
'</span>' +
' Yay' +
- '<span id="cite_ref-3-0"
class="reference" about="#mwt8" typeof="mw:Extension/ref" ' +
- 'data-parsoid="{}" ' +
-
'data-mw="{"name":"ref","body":{"html":"No
name"},"attrs":{"group":"g1"}}">' +
- '<a href="#cite_note-3"
data-parsoid="{}">[3]</a>' +
+ '<span about="#mwt4" class="reference"
data-mw="{"name":"ref","body":{"html":"No
name"},"attrs":{"group":"g1"}}"
id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"
data-parsoid="{}">' +
'</span>' +
' Quux' +
- '<span id="cite_ref-bar-1-2"
class="reference" about="#mwt9" typeof="mw:Extension/ref" ' +
- 'data-parsoid="{}" ' +
-
'data-mw="{"name":"ref","body":{"html":"Different
content"},"attrs":{"name":"bar"}}">' +
- '<a href="#cite_note-bar-1"
data-parsoid="{}">[1]</a>'+
+ '<span about="#mwt5" class="reference"
data-mw="{"name":"ref","body":{"html":"Different
content"},"attrs":{"name":"bar"}}"
id="cite_ref-bar-1-2" rel="dc:references" typeof="mw:Extension/ref"
data-parsoid="{}">' +
+ '</span>' +
+ ' Foo' +
+ '<span about="#mwt6" class="reference"
data-mw="{"name":"ref","attrs":{"name":"foo"}}"
' +
+ 'id="cite_ref-foo-3-0"
rel="dc:references" typeof="mw:Extension/ref" data-parsoid="{}">' +
'</span>' +
'</p>' +
- '<ol class="references" about="#mwt12"
typeof="mw:Extension/references" ' +
-
'data-mw="{"name":"references","attrs":{}}" ' +
- 'data-parsoid="{}">' +
- '<li id="cite_note-quux-2"><a
href="#cite_ref-quux-2-0">u2191</a>Quux</li>' +
- '</ol>' +
+ ve.dm.mwExample.MWReference.referenceList +
'</body>',
'data': [
{ 'type': 'paragraph' },
@@ -869,31 +871,31 @@
{
'type': 'mwReference',
'attributes': {
- 'about': '#mwt5',
+ 'about': '#mwt1',
'listIndex': 0,
'listGroup': 'mwReference/',
'listKey': 'bar',
'refGroup': '',
'mw': { 'name': 'ref', 'attrs': {
'name': 'bar' } },
'originalMw':
'{"name":"ref","attrs":{"name":"bar"}}',
- 'childDomElements': $( '<a
href="#cite_note-bar-1" data-parsoid="{}">[1]</a>' ).toArray(),
+ 'childDomElements': $( '<a
href="#cite_note-bar-1">[1]</a>' ).toArray(),
'contentsUsed': false
},
'htmlAttributes': [
{
'values': {
- 'about': '#mwt5',
+ 'about': '#mwt1',
'class': 'reference',
'data-mw':
'{"name":"ref","attrs":{"name":"bar"}}',
'data-parsoid': '{}',
'id':
'cite_ref-bar-1-0',
+ 'rel': 'dc:references',
'typeof':
'mw:Extension/ref'
},
'children': [
{
'values': {
- 'href':
'#cite_note-bar-1',
-
'data-parsoid': '{}'
+ 'href':
'#cite_note-bar-1'
}
}
]
@@ -905,34 +907,27 @@
{
'type': 'mwReference',
'attributes': {
- 'about': '#mwt6',
+ 'about': '#mwt2',
'listIndex': 1,
'listGroup': 'mwReference/',
'listKey': 'quux',
'refGroup': '',
'mw': { 'name': 'ref', 'body': {
'html': 'Quux' }, 'attrs': { 'name': 'quux' } },
'originalMw':
'{"name":"ref","body":{"html":"Quux"},"attrs":{"name":"quux"}}',
- 'childDomElements': $( '<a
href="#cite_note-quux-2" data-parsoid="{}">[2]</a>' ).toArray(),
+ 'childDomElements': [],
'contentsUsed': true
},
'htmlAttributes': [
{
'values': {
- 'about': '#mwt6',
+ 'about': '#mwt2',
'class': 'reference',
'data-mw':
'{"name":"ref","body":{"html":"Quux"},"attrs":{"name":"quux"}}',
'data-parsoid': '{}',
'id':
'cite_ref-quux-2-0',
+ 'rel': 'dc:references',
'typeof':
'mw:Extension/ref'
- },
- 'children': [
- {
- 'values': {
- 'href':
'#cite_note-quux-2',
-
'data-parsoid': '{}'
- }
- }
- ]
+ }
}
]
},
@@ -941,34 +936,27 @@
{
'type': 'mwReference',
'attributes': {
- 'about': '#mwt7',
+ 'about': '#mwt3',
'listIndex': 0,
'listGroup': 'mwReference/',
'listKey': 'bar',
'refGroup': '',
'mw': { 'name': 'ref', 'body': {
'html': '<a rel="mw:WikiLink" href="./Bar">Bar</a>' }, 'attrs': { 'name': 'bar'
} },
'originalMw':
'{"name":"ref","body":{"html":"<a rel=\\"mw:WikiLink\\"
href=\\"./Bar\\">Bar</a>"},"attrs":{"name":"bar"}}',
- 'childDomElements': $( '<a
href="#cite_note-bar-1" data-parsoid="{}">[1]</a>' ).toArray(),
+ 'childDomElements': [],
'contentsUsed': true
},
'htmlAttributes': [
{
'values': {
- 'about': '#mwt7',
+ 'about': '#mwt3',
'class': 'reference',
'data-mw':
'{"name":"ref","body":{"html":"<a rel=\\"mw:WikiLink\\"
href=\\"./Bar\\">Bar</a>"},"attrs":{"name":"bar"}}',
'data-parsoid': '{}',
'id':
'cite_ref-bar-1-1',
+ 'rel': 'dc:references',
'typeof':
'mw:Extension/ref'
- },
- 'children': [
- {
- 'values': {
- 'href':
'#cite_note-bar-1',
-
'data-parsoid': '{}'
- }
- }
- ]
+ }
}
]
},
@@ -977,34 +965,27 @@
{
'type': 'mwReference',
'attributes': {
- 'about': '#mwt8',
+ 'about': '#mwt4',
'listIndex': 2,
'listGroup': 'mwReference/g1',
'listKey': null,
'refGroup': 'g1',
'mw': { 'name': 'ref', 'body': {
'html': 'No name' }, 'attrs': { 'group': 'g1' } },
'originalMw':
'{"name":"ref","body":{"html":"No name"},"attrs":{"group":"g1"}}',
- 'childDomElements': $( '<a
href="#cite_note-3" data-parsoid="{}">[3]</a>' ).toArray(),
+ 'childDomElements': [],
'contentsUsed': true
},
'htmlAttributes': [
{
'values': {
- 'about': '#mwt8',
+ 'about': '#mwt4',
'class': 'reference',
'data-mw':
'{"name":"ref","body":{"html":"No name"},"attrs":{"group":"g1"}}',
'data-parsoid': '{}',
- 'id': 'cite_ref-3-0',
+ 'id': 'cite_ref-1-0',
+ 'rel': 'dc:references',
'typeof':
'mw:Extension/ref'
- },
- 'children': [
- {
- 'values': {
- 'href':
'#cite_note-3',
-
'data-parsoid': '{}'
- }
- }
- ]
+ }
}
]
},
@@ -1013,34 +994,56 @@
{
'type': 'mwReference',
'attributes': {
- 'about': '#mwt9',
+ 'about': '#mwt5',
'listIndex': 0,
'listGroup': 'mwReference/',
'listKey': 'bar',
'refGroup': '',
'mw': { 'name': 'ref', 'body': {
'html': 'Different content' }, 'attrs': { 'name': 'bar' } },
'originalMw':
'{"name":"ref","body":{"html":"Different content"},"attrs":{"name":"bar"}}',
- 'childDomElements': $( '<a
href="#cite_note-bar-1" data-parsoid="{}">[1]</a>' ).toArray(),
+ 'childDomElements': [],
'contentsUsed': false
},
'htmlAttributes': [
{
'values': {
- 'about': '#mwt9',
+ 'about': '#mwt5',
'class': 'reference',
'data-mw':
'{"name":"ref","body":{"html":"Different content"},"attrs":{"name":"bar"}}',
'data-parsoid': '{}',
'id':
'cite_ref-bar-1-2',
+ 'rel': 'dc:references',
'typeof':
'mw:Extension/ref'
- },
- 'children': [
- {
- 'values': {
- 'href':
'#cite_note-bar-1',
-
'data-parsoid': '{}'
- }
- }
- ]
+ }
+ }
+ ]
+ },
+ { 'type': '/mwReference' },
+ ' ', 'F', 'o', 'o',
+ {
+ 'type': 'mwReference',
+ 'attributes': {
+ 'about': '#mwt6',
+ 'listGroup': 'mwReference/',
+ 'listIndex': 3,
+ 'listKey': 'foo',
+ 'refGroup': '',
+ 'mw': { 'name': 'ref', 'attrs': {
'name': 'foo' } },
+ 'originalMw':
'{"name":"ref","attrs":{"name":"foo"}}',
+ 'childDomElements': [],
+ 'contentsUsed': false
+ },
+ 'htmlAttributes': [
+ {
+ 'values': {
+ 'about': '#mwt6',
+ 'class': 'reference',
+ 'data-mw':
'{"name":"ref","attrs":{"name":"foo"}}',
+ 'data-parsoid': '{}',
+ 'id':
'cite_ref-foo-3-0',
+ 'rel': 'dc:references',
+ 'typeof':
'mw:Extension/ref'
+ }
}
]
},
@@ -1049,22 +1052,50 @@
{
'type': 'mwReferenceList',
'attributes': {
- 'about': '#mwt12',
+ 'about': '#mwt7',
'mw': {
'name': 'references',
- 'attrs': {}
+ 'attrs': {},
+ 'body': {
+ 'extsrc': '<ref
name="foo">Ref in refs</ref>',
+ 'html': '<span
about="#mwt8" class="reference"
data-mw="{"name":"ref","body":{"html":"Ref
in refs"},"attrs":{"name":"foo"}}"
rel="dc:references" typeof="mw:Extension/ref"><a
href="#cite_note-foo-3">[3]</a></span>'
+ }
},
- 'originalMw':
'{"name":"references","attrs":{}}',
- 'domElements': $(
- '<ol class="references"
about="#mwt12" typeof="mw:Extension/references" '+
-
'data-mw="{"name":"references","attrs":{}}" ' +
- 'data-parsoid="{}">'+
- '<li
id="cite_note-quux-2"><a href="#cite_ref-quux-2-0">u2191</a>Quux</li>' +
- '</ol>' ).toArray(),
+ 'originalMw':
'{"name":"references","body":{"extsrc":"<ref name=\\"foo\\">Ref in
refs</ref>","html":"<span about=\\"#mwt8\\" class=\\"reference\\"
data-mw=\\"{"name":"ref","body":{"html":"Ref
in refs"},"attrs":{"name":"foo"}}\\"
rel=\\"dc:references\\" typeof=\\"mw:Extension/ref\\"><a
href=\\"#cite_note-foo-3\\">[3]</a></span>"},"attrs":{}}',
+ 'domElements': $(
ve.dm.mwExample.MWReference.referenceList ).toArray(),
'listGroup': 'mwReference/',
'refGroup': ''
}
},
+ { 'type': 'paragraph', 'internal': { 'generated':
'wrapper' } },
+ {
+ 'type': 'mwReference',
+ 'attributes': {
+ 'about': '#mwt8',
+ 'childDomElements': $( '<a
href="#cite_note-foo-3">[3]</a>' ).toArray(),
+ 'contentsUsed': true,
+ 'listGroup': 'mwReference/',
+ 'listIndex': 3,
+ 'listKey': 'foo',
+ 'mw': { 'name': 'ref', 'attrs': {
'name': 'foo' }, 'body': { 'html': 'Ref in refs' } },
+ 'originalMw':
'{"name":"ref","body":{"html":"Ref in refs"},"attrs":{"name":"foo"}}',
+ 'refGroup': ''
+ },
+ 'htmlAttributes': [ {
+ 'children': [ { 'values': {
+ 'href': '#cite_note-foo-3'
+ } } ],
+ 'values': {
+ 'about': '#mwt8',
+ 'class': 'reference',
+ 'data-mw':
'{"name":"ref","body":{"html":"Ref in refs"},"attrs":{"name":"foo"}}',
+ 'rel': 'dc:references',
+ 'typeof': 'mw:Extension/ref'
+ }
+ } ]
+ },
+ { 'type': '/mwReference' },
+ { 'type': '/paragraph' },
{ 'type': '/mwReferenceList' },
{ 'type': 'internalList' },
{ 'type': 'internalItem' },
@@ -1129,6 +1160,11 @@
'N', 'o', ' ', 'n', 'a', 'm', 'e',
{ 'type': '/paragraph' },
{ 'type': '/internalItem' },
+ { 'type': 'internalItem' },
+ { 'type': 'paragraph', 'internal': { 'generated':
'wrapper' } },
+ 'R', 'e', 'f', ' ', 'i', 'n', ' ', 'r', 'e', 'f', 's',
+ { 'type': '/paragraph' },
+ { 'type': '/internalItem' },
{ 'type': '/internalList' }
]
},
--
To view, visit https://gerrit.wikimedia.org/r/75912
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I31d06616849a00449df0fc77f3b33e46207cdc7f
Gerrit-PatchSet: 4
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits