contents to
p = doc.createElement( 'p' );
while ( list.firstChild.firstChild ) {
// If contents is a block element, place outside the paragraph
// and start a new paragraph after
if ( list.firstChild.firstChild instanceof HTMLElement && ve.isBlockElement( list.firstChild.firstChild ) ) {
if ( p.firstChild ) {
insertBefore = referenceNode.nextSibling;
referenceNode = p;
container.insertBefore( p, insertBefore );
}
insertBefore = referenceNode.nextSibling;
referenceNode = list.firstChild.firstChild;
container.insertBefore( list.firstChild.firstChild, insertBefore );
p = doc.createElement( 'p' );
} else {
p.appendChild( list.firstChild.firstChild );
}
}
if ( p.firstChild ) {
insertBefore = referenceNode.nextSibling;
referenceNode = p;
container.insertBefore( p, insertBefore );
}
list.removeChild( list.firstChild );
} else {
// Text node / comment node, probably empty
insertBefore = referenceNode.nextSibling;
referenceNode = list.firstChild;
container.insertBefore( list.firstChild, insertBefore );
}
}
container.removeChild( list );
}
/**
* Add another list item after the given one.
*
* @param {HTMLElement} previousItem
* @return {HTMLElement}
*/
function addSiblingListItem( previousItem ) {
var listItem = previousItem.ownerDocument.createElement( previousItem.tagName );
whitespaceParsoidHack( listItem );
previousItem.parentNode.insertBefore( listItem, previousItem.nextSibling );
return listItem;
}
// TODO: No longer used in the client
function createWikitextNode( doc, wt ) {
var span = doc.createElement( 'span' );
span.setAttribute( 'typeof', 'mw:Transclusion' );
span.setAttribute( 'data-mw', JSON.stringify( { parts: [ wt ] } ) );
return span;
}
/**
* Check whether wikitext contains a user signature.
*
* @param {string} wikitext
* @return {boolean}
*/
function isWikitextSigned( wikitext ) {
wikitext = utils.htmlTrim( wikitext );
// Contains ~~~~ (four tildes), but not ~~~~~ (five tildes), at the end.
return /([^~]|^)~~~~$/.test( wikitext );
}
/**
* Check whether HTML node contains a user signature.
*
* @param {HTMLElement} container
* @return {boolean}
*/
function isHtmlSigned( container ) {
var matches, lastSig, node;
// Good enough?…
matches = container.querySelectorAll( 'span[typeof="mw:Transclusion"][data-mw*="~~~~"]' );
if ( matches.length === 0 ) {
return false;
}
lastSig = matches[ matches.length - 1 ];
// Signature must be at the end of the comment - there must be no sibling following this node, or its parents
node = lastSig;
while ( node ) {
// Skip over whitespace nodes
while (
node.nextSibling &&
node.nextSibling.nodeType === Node.TEXT_NODE &&
utils.htmlTrim( node.nextSibling.textContent ) === ''
) {
node = node.nextSibling;
}
if ( node.nextSibling ) {
return false;
}
node = node.parentNode;
}
return true;
}
/**
* Append a user signature to the comment in the container.
*
* @param {HTMLElement} container
*/
function appendSignature( container ) {
var doc = container.ownerDocument;
// If the last node isn't a paragraph (e.g. it's a list created in visual mode), then
// add another paragraph to contain the signature.
if ( container.lastChild.nodeName.toLowerCase() !== 'p' ) {
container.appendChild( doc.createElement( 'p' ) );
}
// Sign the last line
// TODO: When we implement posting new topics, the leading space will create an indent-pre
container.lastChild.appendChild(
createWikitextNode( doc, mw.msg( 'discussiontools-signature-prefix' ) + '~~~~' )
);
}
/**
* Add a reply to a specific comment
*
* TODO: No longer used in the client
*
* @param {CommentItem} comment Comment being replied to
* @param {HTMLElement} container Container of comment DOM nodes
*/
function addReply( comment, container ) {
var newParsoidItem;
// Transfer comment DOM to Parsoid DOM
// Wrap every root node of the document in a new list item (dd/li).
// In wikitext mode every root node is a paragraph.
// In visual mode the editor takes care of preventing problematic nodes
// like
or from ever occurring in the comment.
while ( container.childNodes.length ) {
if ( !newParsoidItem ) {
newParsoidItem = addListItem( comment );
} else {
newParsoidItem = addSiblingListItem( newParsoidItem );
}
newParsoidItem.appendChild( container.firstChild );
}
}
/**
* Create a container of comment DOM nodes from wikitext
*
* TODO: No longer used in the client
*
* @param {CommentItem} comment Comment being replied to
* @param {string} wikitext Wikitext
*/
function addWikitextReply( comment, wikitext ) {
var doc = comment.range.endContainer.ownerDocument,
container = doc.createElement( 'div' );
wikitext = sanitizeWikitextLinebreaks( wikitext );
wikitext.split( '\n' ).forEach( function ( line ) {
var p = doc.createElement( 'p' );
p.appendChild( createWikitextNode( doc, line ) );
container.appendChild( p );
} );
if ( !isWikitextSigned( wikitext ) ) {
appendSignature( container );
}
addReply( comment, container );
}
/**
* Create a container of comment DOM nodes from HTML
*
* TODO: No longer used in the client
*
* @param {CommentItem} comment Comment being replied to
* @param {string} html HTML
*/
function addHtmlReply( comment, html ) {
var doc = comment.range.endContainer.ownerDocument,
childNodeList,
container = doc.createElement( 'div' );
container.innerHTML = html;
// Remove empty lines
// This should really be anything that serializes to empty string in wikitext,
// (e.g. ) but this will catch most cases
// Create a non-live child node list, so we don't have to worry about it changing
// as nodes are removed.
childNodeList = Array.prototype.slice.call( container.childNodes );
childNodeList.forEach( function ( node ) {
if ( node.nodeName.toLowerCase() === 'p' && !utils.htmlTrim( node.innerHTML ) ) {
container.removeChild( node );
}
} );
if ( !isHtmlSigned( container ) ) {
appendSignature( container );
}
addReply( comment, container );
}
module.exports = {
addReplyLink: addReplyLink,
addListItem: addListItem,
removeAddedListItem: removeAddedListItem,
addSiblingListItem: addSiblingListItem,
unwrapList: unwrapList,
createWikitextNode: createWikitextNode,
addWikitextReply: addWikitextReply,
addHtmlReply: addHtmlReply,
isWikitextSigned: isWikitextSigned,
isHtmlSigned: isHtmlSigned,
sanitizeWikitextLinebreaks: sanitizeWikitextLinebreaks
};