` - this is
* necessary since an arbitrary HTML string might not have a jQuery representation).
*
* @param {string|HTMLElement|jQuery} html
* @return {jQuery}
*/
HUP.wrapAndJquerify = function ( html ) {
if ( this.isJQueryOrHTMLElement( html ) ) {
return $( '
' ).append( $( html ).clone() );
} else if ( typeof html === 'string' ) {
return $( '
' + html + '
' );
} else {
mw.log.warn( 'wrapAndJquerify: unknown type', html );
throw new Error( 'wrapAndJquerify: unknown type' );
}
};
/**
* Returns true of the object is a jQuery object or an HTMLElement, false otherwise
*
* @param {string|HTMLElement|jQuery} html
* @return {boolean}
*/
HUP.isJQueryOrHTMLElement = function ( html ) {
if ( html instanceof $ ) {
return true;
}
if ( window.HTMLElement ) {
if ( html instanceof HTMLElement ) {
return true;
}
}
return false;
};
/**
* Filters display:none and children of a node.
* The root element is never filtered, and generally ignored (i.e. whether the root element is
* visible won't affect the filtering).
* Works in place.
*
* @param {jQuery} $jq
*/
HUP.filterInvisible = function ( $jq ) {
// We are not using :visible because
// 1) it would require appending $jq to the document which makes things complicated;
// 2) the main difference is that it looks for CSS rules hiding the element;
// since this function is intended to be used on html originating from a different
// document, possibly a different site, that would probably have unexpected results.
$jq
.find( '[style]' )
.filter( function () { return this.style.display === 'none'; } )
.remove();
// TemplateStyles can generate inline style tags
$jq
.find( 'style' )
.remove();
};
/**
* Discards all nodes which do not match the whitelist,
* but keeps the text and whitelisted nodes inside them.
* Works in-place.
*
* @param {jQuery} $el
* @param {string} whitelist a jQuery selector string such as 'a, span, br'
*/
HUP.whitelistHtml = function ( $el, whitelist ) {
var child, $prev,
$child = $el.children().first();
while ( $child && $child.length ) {
child = $child.get( 0 );
if ( child.nodeType !== child.ELEMENT_NODE ) {
return;
}
this.whitelistHtml( $child, whitelist );
if ( !$child.is( whitelist ) ) {
$prev = $child.prev();
$child.replaceWith( $child.contents() );
} else {
$prev = $child;
}
if ( $prev && $prev.length === 1 ) {
$child = $prev.next();
} else {
$child = $el.children().first();
}
}
};
/**
* Adds a whitespace to block elements. This is useful if you want to convert the contents
* to text and don't want words that are visually separate (e.g. table cells) to be fused.
* Works in-place.
*
* @param {jQuery} $el
*/
HUP.appendWhitespaceToBlockElements = function ( $el ) {
// the list of what elements to add whitespace to is somewhat ad-hoc (not all of these
// are technically block-level elements, and a lot of block-level elements are missing)
// but will hopefully cover the common cases where text is fused together.
$el
.find( 'blockquote, dd, dl, dt, li, td' )
.before( ' ' )
.after( ' ' );
$el
.find( 'br, tr, p' )
.before( '\n' )
.after( '\n' );
};
/**
* Returns the HTML code for a jQuery element (only the first one if passed a set of elements).
* Unlike .html(), this includes HTML code for the outermost element; compare
* - `$('
').html() // ''`
* - `mw.mmv.HtmlUtils.jqueryToHtml( $('
') ) // '
'`
*
* @param {jQuery} $el
* @return {string}
*/
HUP.jqueryToHtml = function ( $el ) {
// There are two possible implementations for this:
// 1) load into a wrapper element and get its innerHTML;
// 2) use outerHTML.
// We go with 1) because it handles the case when a jQuery object contains something
// that is not an element (this can happen with e.g. $x.children() which returns text
// nodes as well).
return $( '