Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F5991210
ve.dm.MWReferencesListNode.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
ve.dm.MWReferencesListNode.js
View Options
'use strict'
;
/*!
* VisualEditor DataModel MWReferencesListNode class.
*
* @copyright 2011-2018 VisualEditor Team's Cite sub-team and others; see AUTHORS.txt
* @license MIT
*/
const
MWDocumentReferences
=
require
(
'./ve.dm.MWDocumentReferences.js'
);
/**
* DataModel MediaWiki references list node.
*
* @constructor
* @extends ve.dm.BranchNode
* @mixes ve.dm.FocusableNode
* @param {Object} [element] Reference to element in linear model
* @param {ve.dm.Node[]} [children]
*/
ve
.
dm
.
MWReferencesListNode
=
function
VeDmMWReferencesListNode
()
{
// Parent constructor
ve
.
dm
.
MWReferencesListNode
.
super
.
apply
(
this
,
arguments
);
// Mixin constructors
ve
.
dm
.
FocusableNode
.
call
(
this
);
};
/* Inheritance */
OO
.
inheritClass
(
ve
.
dm
.
MWReferencesListNode
,
ve
.
dm
.
BranchNode
);
OO
.
mixinClass
(
ve
.
dm
.
MWReferencesListNode
,
ve
.
dm
.
FocusableNode
);
/* Methods */
ve
.
dm
.
MWReferencesListNode
.
prototype
.
isEditable
=
function
()
{
return
!
this
.
getAttribute
(
'templateGenerated'
);
};
/* Static members */
ve
.
dm
.
MWReferencesListNode
.
static
.
name
=
'mwReferencesList'
;
ve
.
dm
.
MWReferencesListNode
.
static
.
handlesOwnChildren
=
true
;
ve
.
dm
.
MWReferencesListNode
.
static
.
ignoreChildren
=
true
;
ve
.
dm
.
MWReferencesListNode
.
static
.
matchTagNames
=
null
;
ve
.
dm
.
MWReferencesListNode
.
static
.
matchRdfaTypes
=
[
'mw:Extension/references'
,
'mw:Transclusion'
];
// Allow TemplateStyles in the matching element
ve
.
dm
.
MWReferencesListNode
.
static
.
allowedRdfaTypes
=
[
'mw:Extension/templatestyles'
];
// e.g. with a {{reflist}} with TemplateStyles
ve
.
dm
.
MWReferencesListNode
.
static
.
enableAboutGrouping
=
true
;
// This node has the same specificity as ve.dm.MWTranslcusionNode and only matches
// ahead of it because it is registered later (via a dependency in ResourceLoader)
// TODO: Make this less fragile.
ve
.
dm
.
MWReferencesListNode
.
static
.
matchFunction
=
function
(
domElement
)
{
function
hasTypeof
(
el
,
type
)
{
return
(
el
.
getAttribute
(
'typeof'
)
||
''
).
includes
(
type
);
}
function
isRefList
(
el
)
{
return
el
&&
el
.
nodeType
===
Node
.
ELEMENT_NODE
&&
hasTypeof
(
el
,
'mw:Extension/references'
);
}
// If the template generated only a reference list, treat it as a ref list (T52769)
return
isRefList
(
domElement
)
||
// A div-wrapped reference list
(
domElement
.
children
.
length
===
1
&&
isRefList
(
domElement
.
children
[
0
]
)
)
||
// TemplateStyles, about-grouped to a div-wrapped reference list
(
hasTypeof
(
domElement
,
'mw:Extension/templatestyles'
)
&&
domElement
.
hasAttribute
(
'about'
)
&&
domElement
.
nextElementSibling
&&
domElement
.
nextElementSibling
.
getAttribute
(
'about'
)
===
domElement
.
getAttribute
(
'about'
)
&&
// A div-wrapped reference list
domElement
.
nextElementSibling
.
children
.
length
===
1
&&
isRefList
(
domElement
.
nextElementSibling
.
children
[
0
]
)
// TODO: We should probably check there aren't subsequent elements. This
// and the above checks would be easier if the matchFunction was passed
// all the elements in the about group.
);
};
ve
.
dm
.
MWReferencesListNode
.
static
.
preserveHtmlAttributes
=
false
;
/**
* Transform parsoid HTML DOM to constructor parameters for VE referenceList nodes.
*
* @param {Node[]} domElements DOM elements to convert
* @param {ve.dm.ModelFromDomConverter} converter
* @return {Object|Array|null} Data element or array of linear model data, or null to alienate
*/
ve
.
dm
.
MWReferencesListNode
.
static
.
toDataElement
=
function
(
domElements
,
converter
)
{
const
type
=
domElements
[
0
].
getAttribute
(
'typeof'
)
||
''
;
let
refListNode
;
// We may have matched a mw:Transclusion wrapping a reference list, so pull out the refListNode
if
(
type
.
includes
(
'mw:Extension/references'
)
)
{
refListNode
=
domElements
[
0
];
}
else
{
refListNode
=
domElements
[
0
].
querySelector
(
'[typeof*="mw:Extension/references"]'
)
||
// In the TemplateStyles case, the ref list is in the second element
domElements
[
1
].
querySelector
(
'[typeof*="mw:Extension/references"]'
);
}
const
mwDataJSON
=
refListNode
.
getAttribute
(
'data-mw'
);
const
mwData
=
mwDataJSON
?
JSON
.
parse
(
mwDataJSON
)
:
{};
const
mwAttrs
=
mwData
.
attrs
||
{};
const
refGroup
=
mwAttrs
.
group
||
''
;
const
responsiveAttr
=
mwAttrs
.
responsive
;
const
listGroup
=
'mwReference/'
+
refGroup
;
const
templateGenerated
=
type
.
includes
(
'mw:Transclusion'
);
const
isResponsiveDefault
=
mw
.
config
.
get
(
'wgCiteResponsiveReferences'
);
const
referencesListElement
=
{
type
:
this
.
name
,
attributes
:
{
mw
:
mwData
,
originalMw
:
mwDataJSON
,
refGroup
,
listGroup
,
isResponsive
:
responsiveAttr
!==
undefined
?
responsiveAttr
!==
'0'
:
isResponsiveDefault
,
templateGenerated
}
};
if
(
mwData
.
body
&&
mwData
.
body
.
html
&&
!
templateGenerated
)
{
// Process the nodes in .body.html as if they were this node's children
// Don't process template-generated reflists, that mangles the content (T209493)
const
contentsDiv
=
domElements
[
0
].
ownerDocument
.
createElement
(
'div'
);
contentsDiv
.
innerHTML
=
mwData
.
body
.
html
;
const
contentsData
=
converter
.
getDataFromDomClean
(
contentsDiv
);
return
[
referencesListElement
,
...
contentsData
,
{
type
:
'/'
+
this
.
name
}
];
}
return
referencesListElement
;
};
/**
* Transform referenceList data elements from the linear model to HTML DOM elements as input for
* the Parsoid parser.
*
* @param {Object[]} data
* @param {HTMLDocument} doc
* @param {ve.dm.DomFromModelConverter} converter
* @return {HTMLElement[]}
*/
ve
.
dm
.
MWReferencesListNode
.
static
.
toDomElements
=
function
(
data
,
doc
,
converter
)
{
const
dataElement
=
data
[
0
];
// TODO: handle transclusion edge case
// If we are sending a template generated ref back to Parsoid, output it as a
// template. This works because the dataElement already has mw, originalMw
// and originalDomIndex properties.
if
(
dataElement
.
attributes
.
templateGenerated
&&
converter
.
isForParser
()
)
{
return
ve
.
dm
.
MWTransclusionNode
.
static
.
toDomElements
.
call
(
this
,
dataElement
,
doc
,
converter
);
}
const
updatedMw
=
ve
.
dm
.
MWReferencesListNode
.
static
.
updatedMwForDom
(
data
,
doc
,
converter
);
let
domElements
=
[
doc
.
createElement
(
'div'
)
];
if
(
!
converter
.
isForParser
()
)
{
// Output needs to be read so re-render
const
modelNode
=
ve
.
dm
.
nodeFactory
.
createFromElement
(
dataElement
);
// Build from original doc's internal list to get all refs (T186407)
modelNode
.
setDocument
(
converter
.
originalDocInternalList
.
getDocument
()
);
const
viewNode
=
ve
.
ce
.
nodeFactory
.
createFromModel
(
modelNode
);
viewNode
.
modified
=
true
;
viewNode
.
update
();
domElements
[
0
].
appendChild
(
viewNode
.
$reflist
[
0
]
);
// Destroy the view node so it doesn't try to update the DOM node later
// (e.g. updateDebounced)
viewNode
.
destroy
();
}
else
if
(
dataElement
.
originalDomElementsHash
!==
undefined
&&
// don't get originalDamElements when there are changes, needed to update synthetic refs
!
updatedMw
)
{
// If there's more than 1 element, preserve entire array, not just first element
domElements
=
ve
.
copyDomElements
(
converter
.
getStore
().
value
(
dataElement
.
originalDomElementsHash
),
doc
);
}
else
{
domElements
[
0
].
appendChild
(
ve
.
dm
.
MWReferencesListNode
.
static
.
listToDomElement
(
dataElement
.
attributes
.
refGroup
||
''
,
doc
,
converter
)
);
}
domElements
[
0
].
setAttribute
(
'typeof'
,
'mw:Extension/references'
);
domElements
[
0
].
setAttribute
(
'data-mw'
,
// 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
!
updatedMw
?
dataElement
.
attributes
.
originalMw
:
updatedMw
);
return
domElements
;
};
/***
* Prepare mwData for conversion to DOM and check for changes
*
* @static
* @param {Object} data
* @param {Document} doc
* @param {ve.dm.DomFromModelConverter} converter
* @return {string|false} updated mwData as string or false if nothing changed
* */
ve
.
dm
.
MWReferencesListNode
.
static
.
updatedMwForDom
=
function
(
data
,
doc
,
converter
)
{
const
attributes
=
data
[
0
].
attributes
;
const
originalMw
=
attributes
.
originalMw
;
const
originalMwData
=
originalMw
&&
JSON
.
parse
(
originalMw
);
const
mwData
=
attributes
.
mw
?
ve
.
copy
(
attributes
.
mw
)
:
{};
mwData
.
name
=
'references'
;
if
(
attributes
.
refGroup
)
{
ve
.
setProp
(
mwData
,
'attrs'
,
'group'
,
attributes
.
refGroup
);
}
else
if
(
mwData
.
attrs
)
{
delete
mwData
.
attrs
.
group
;
}
const
originalResponsiveAttr
=
ve
.
getProp
(
originalMwData
,
'attrs'
,
'responsive'
);
const
isResponsiveDefault
=
mw
.
config
.
get
(
'wgCiteResponsiveReferences'
);
if
(
!
(
// The original "responsive" attribute hasn't had its meaning changed
originalResponsiveAttr
!==
undefined
&&
(
originalResponsiveAttr
!==
'0'
)
===
attributes
.
isResponsive
)
)
{
if
(
attributes
.
isResponsive
!==
isResponsiveDefault
)
{
ve
.
setProp
(
mwData
,
'attrs'
,
'responsive'
,
attributes
.
isResponsive
?
''
:
'0'
);
}
else
if
(
mwData
.
attrs
)
{
delete
mwData
.
attrs
.
responsive
;
}
}
// If this was an autogenerated reflist. We need to check whether changes
// have been made which make that no longer true. The reflist dialog
// handles unsetting this if changes to the properties have been made.
// Here we want to work out if it has been moved away from the end of
// the document.
if
(
mwData
.
autoGenerated
&&
!
ve
.
dm
.
MWReferencesListNode
.
static
.
isReflistLastElement
(
converter
.
documentData
,
data
)
)
{
delete
mwData
.
autoGenerated
;
}
// Add body.html to data-mw if applicable
const
contentsData
=
data
.
slice
(
1
,
-
1
);
if
(
contentsData
.
length
>
2
)
{
// get the current content html of the node
const
currentHtmlWrapper
=
doc
.
createElement
(
'div'
);
converter
.
getDomSubtreeFromData
(
contentsData
,
currentHtmlWrapper
);
// get the original content html of the node
const
originalHtmlWrapper
=
doc
.
createElement
(
'div'
);
originalHtmlWrapper
.
innerHTML
=
ve
.
getProp
(
mwData
,
'body'
,
'html'
)
||
''
;
// Only set body.html if contentsHtml and originalHtml are actually different
// FIXME?: Synthetic refs from main+details always seem to have different bodyHtml here
if
(
!
originalHtmlWrapper
.
isEqualNode
(
currentHtmlWrapper
)
)
{
ve
.
setProp
(
mwData
,
'body'
,
'html'
,
currentHtmlWrapper
.
innerHTML
);
}
}
return
originalMw
&&
ve
.
compare
(
mwData
,
originalMwData
)
?
false
:
JSON
.
stringify
(
mwData
);
};
/***
* Check the reflist is the last element in the DM
*
* @static
* @param {Array} documentData
* @param {Object} data
* @return {boolean}
* */
ve
.
dm
.
MWReferencesListNode
.
static
.
isReflistLastElement
=
function
(
documentData
,
data
)
{
// TODO: it would be better to do this without needing to fish through
// the converter's linear data. Use the DM tree instead?
let
nextIndex
=
documentData
.
indexOf
(
data
[
data
.
length
-
1
]
)
+
1
;
let
nextElement
;
while
(
(
nextElement
=
documentData
[
nextIndex
]
)
)
{
if
(
nextElement
.
type
[
0
]
!==
'/'
)
{
break
;
}
nextIndex
++
;
}
return
!
nextElement
||
nextElement
.
type
===
'internalList'
;
};
/***
* Create references list HTML DOM for Parsoid
*
* @static
* @param {string} refGroup
* @param {HTMLDocument} doc
* @param {ve.dm.Converter} converter
* @return {HTMLElement} <ol> element for the references list
* */
ve
.
dm
.
MWReferencesListNode
.
static
.
listToDomElement
=
function
(
refGroup
,
doc
,
converter
)
{
// Render all group refs
const
docRefs
=
MWDocumentReferences
.
static
.
refsForDoc
(
converter
.
internalList
.
document
);
const
groupRefs
=
docRefs
.
getGroupRefs
(
refGroup
);
const
$wrapper
=
$
(
'<ol>'
,
doc
);
$wrapper
.
append
(
groupRefs
.
getTopLevelKeysInReflistOrder
()
.
map
(
(
listKey
)
=>
ve
.
dm
.
MWReferencesListNode
.
static
.
listItemToDomElement
(
groupRefs
,
listKey
,
doc
,
converter
)
)
);
return
$wrapper
[
0
];
};
/***
* Create references list item HTML DOM for Parsoid
*
* @static
* @param {ve.dm.MWGroupReferences} groupRefs
* @param {string} listKey
* @param {HTMLDocument} doc
* @param {ve.dm.Converter} converter
* @return {jQuery} <li> element for the references listitem
* */
ve
.
dm
.
MWReferencesListNode
.
static
.
listItemToDomElement
=
function
(
groupRefs
,
listKey
,
doc
,
converter
)
{
const
internalItem
=
groupRefs
.
getInternalModelNode
(
listKey
);
const
subrefs
=
groupRefs
.
getSubrefs
(
listKey
);
const
$li
=
$
(
'<li>'
,
doc
);
if
(
internalItem
&&
internalItem
.
length
)
{
// make sure to find the node holding the refListItemId
const
refListNode
=
groupRefs
.
nodeGroup
.
getAllReuses
(
listKey
)
.
find
(
(
node
)
=>
node
.
getAttribute
(
'refListItemId'
)
);
const
htmlWrapper
=
doc
.
createElement
(
'span'
);
converter
.
getDomSubtreeFromData
(
internalItem
.
getDocument
().
getFullData
(
internalItem
.
getRange
(),
'roundTrip'
),
htmlWrapper
);
$li
.
append
(
$
(
htmlWrapper
)
.
attr
(
'typeof'
,
'mw:Extension/ref'
)
.
attr
(
'id'
,
refListNode
&&
refListNode
.
getAttribute
(
'refListItemId'
)
)
);
}
else
{
// TODO: What to do here?
$li
.
append
(
$
(
'<span>'
,
doc
)
).
addClass
(
've-ce-mwReferencesListNode-missingRef'
);
}
if
(
subrefs
.
length
)
{
$li
.
append
(
$
(
'<ol>'
,
doc
).
append
(
subrefs
.
map
(
(
subNode
)
=>
ve
.
dm
.
MWReferencesListNode
.
static
.
listItemToDomElement
(
groupRefs
,
subNode
.
getAttribute
(
'listKey'
),
doc
,
converter
)
)
)
);
}
return
$li
;
};
ve
.
dm
.
MWReferencesListNode
.
static
.
describeChange
=
function
(
key
,
change
)
{
if
(
key
===
'refGroup'
)
{
if
(
!
change
.
from
)
{
return
ve
.
htmlMsg
(
'cite-ve-changedesc-reflist-group-to'
,
this
.
wrapText
(
'ins'
,
change
.
to
)
);
}
else
if
(
!
change
.
to
)
{
return
ve
.
htmlMsg
(
'cite-ve-changedesc-reflist-group-from'
,
this
.
wrapText
(
'del'
,
change
.
from
)
);
}
else
{
return
ve
.
htmlMsg
(
'cite-ve-changedesc-reflist-group-both'
,
this
.
wrapText
(
'del'
,
change
.
from
),
this
.
wrapText
(
'ins'
,
change
.
to
)
);
}
}
if
(
key
===
'isResponsive'
)
{
if
(
change
.
from
)
{
return
ve
.
msg
(
'cite-ve-changedesc-reflist-responsive-unset'
);
}
return
ve
.
msg
(
'cite-ve-changedesc-reflist-responsive-set'
);
}
if
(
key
===
'originalMw'
)
{
return
null
;
}
return
null
;
};
ve
.
dm
.
MWReferencesListNode
.
static
.
getHashObject
=
function
(
dataElement
)
{
const
attributes
=
dataElement
.
attributes
;
return
{
type
:
dataElement
.
type
,
attributes
:
{
refGroup
:
attributes
.
refGroup
,
listGroup
:
attributes
.
listGroup
,
isResponsive
:
attributes
.
isResponsive
,
templateGenerated
:
attributes
.
templateGenerated
}
};
};
module
.
exports
=
ve
.
dm
.
MWReferencesListNode
;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Oct 4, 01:48 (4 w, 1 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
35/73/a944cb3bfab1b81a646f6f418d34
Default Alt Text
ve.dm.MWReferencesListNode.js (14 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment