function render_range( new_sub_text, new_sub_range, range_info, range_data, options ) {
	// Its time to build the outer shell of the range we're recursing into.
	let new_container = null,
		new_classes = [],
		type_mappings;

	let range_info_type = range_info.type;

	if ( typeof range_info.type !== 'undefined' ) {
		type_mappings = {
			b: 'strong', // be strong, my friend
			i: 'em', // I am, don't worry
			noticon: 'gridicon',
		};

		// Replace unwanted tags with more popular and cool ones
		if ( range_info.type in type_mappings ) {
			range_info_type = type_mappings[ range_info.type ];
		}

		new_classes.push( `wpnc__${ range_info_type }` );
	}

	// We want to do different things depending on the range type.
	switch ( range_info_type ) {
		// The badges should have their height and width set on
		// the server-side, but just in case they aren't, give
		// good defaults here
		case 'badge':
			if ( ! range_info.hasOwnProperty( 'width' ) ) {
				range_info.width = 256;
			}
			if ( ! range_info.hasOwnProperty( 'height' ) ) {
				range_info.height = 256;
			}
		case 'image':
			// Images and badges are not recursed into
			new_container = document.createElement( 'img' );
			new_container.setAttribute( 'src', range_info.url );
			if ( range_info.hasOwnProperty( 'width' ) ) {
				new_container.setAttribute( 'width', range_info.width );
			}
			if ( range_info.hasOwnProperty( 'height' ) ) {
				new_container.setAttribute( 'height', range_info.height );
			}
			if ( new_sub_text.trim().length > 0 ) {
				new_container.setAttribute( 'alt', new_sub_text );
			}
			break;
		// All of the following are simple element types we want to create and then
		// recurse into for their constituent blocks or texts
		case 'blockquote':
		case 'code':
		case 'strong':
		case 'em':
		case 'list':
			switch ( range_info_type ) {
				case 'list':
					range_info_type = 'span';
					break;
			}
			new_container = document.createElement( range_info_type );
			build_chunks( new_sub_text, new_sub_range, range_data, new_container, options );
			break;
		case 'gridicon':
			// Gridicons have special text, and are thus not recursed into
			new_container = document.createElement( 'span' );
			new_container.innerHTML = ReactDOMServer.renderToStaticMarkup(
				React.createElement( Gridicon, {
					icon: noticon2gridicon( range_info.value ),
					size: 18,
				} )
			);
			break;
		case 'button':
			new_classes.push( 'is-primary' );
		default:
			// Most range types fall here
			if ( options.links && range_info.url ) {
				// We are a link of some sort...
				new_container = document.createElement( 'a' );

				new_container.setAttribute( 'href', range_info.url );
				if ( range_info_type == 'stat' ) {
					// Stat links should change the whole window/tab
					new_container.setAttribute( 'target', '_parent' );
				} else {
					// Other links should link into a new window/tab
					new_container.setAttribute( 'target', '_blank' );
				}

				if ( 'post' === range_info.type ) {
					new_container.setAttribute( 'data-post-id', range_info.id );
					new_container.setAttribute( 'data-site-id', range_info.site_id );
					new_container.setAttribute( 'data-link-type', 'post' );
					new_container.setAttribute( 'target', '_self' );
				} else if ( 'tracks' === range_info.type && range_info.context ) {
					new_container.setAttribute( 'data-link-type', 'tracks' );
					new_container.setAttribute( 'data-tracks-event', range_info.context );
				}

				build_chunks( new_sub_text, new_sub_range, range_data, new_container, options );
			} else {
				// Everything else is a span
				new_container = document.createElement( 'span' );
				if ( new_sub_text.length > 0 ) {
					build_chunks( new_sub_text, new_sub_range, range_data, new_container, options );
				}
			}
			break;
	}

	if ( new_classes.length > 0 ) {
		new_container.className = new_classes.join( ' ' );
	}

	return new_container;
}
function render_range( new_sub_text, new_sub_range, range_info, range_data, options ) {
	
	let new_container = null,
		new_classes = [],
		type_mappings;

	let range_info_type = range_info.type;

	if ( typeof range_info.type !== 'undefined' ) {
		type_mappings = {
			b: 'strong', 
			i: 'em', 
			noticon: 'gridicon',
		};

		
		if ( range_info.type in type_mappings ) {
			range_info_type = type_mappings[ range_info.type ];
		}

		new_classes.push( `wpnc__${ range_info_type }` );
	}

	
	switch ( range_info_type ) {
		
		
		
		case 'badge':
			if ( ! range_info.hasOwnProperty( 'width' ) ) {
				range_info.width = 256;
			}
			if ( ! range_info.hasOwnProperty( 'height' ) ) {
				range_info.height = 256;
			}
		case 'image':
			
			new_container = document.createElement( 'img' );
			new_container.setAttribute( 'src', range_info.url );
			if ( range_info.hasOwnProperty( 'width' ) ) {
				new_container.setAttribute( 'width', range_info.width );
			}
			if ( range_info.hasOwnProperty( 'height' ) ) {
				new_container.setAttribute( 'height', range_info.height );
			}
			if ( new_sub_text.trim().length > 0 ) {
				new_container.setAttribute( 'alt', new_sub_text );
			}
			break;
		
		
		case 'blockquote':
		case 'code':
		case 'strong':
		case 'em':
		case 'list':
			switch ( range_info_type ) {
				case 'list':
					range_info_type = 'span';
					break;
			}
			new_container = document.createElement( range_info_type );
			build_chunks( new_sub_text, new_sub_range, range_data, new_container, options );
			break;
		case 'gridicon':
			
			new_container = document.createElement( 'span' );
			new_container.innerHTML = ReactDOMServer.renderToStaticMarkup(
				React.createElement( Gridicon, {
					icon: noticon2gridicon( range_info.value ),
					size: 18,
				} )
			);
			break;
		case 'button':
			new_classes.push( 'is-primary' );
		default:
			
			if ( options.links && range_info.url ) {
				
				new_container = document.createElement( 'a' );

				new_container.setAttribute( 'href', range_info.url );
				if ( range_info_type == 'stat' ) {
					
					new_container.setAttribute( 'target', '_parent' );
				} else {
					
					new_container.setAttribute( 'target', '_blank' );
				}

				if ( 'post' === range_info.type ) {
					new_container.setAttribute( 'data-post-id', range_info.id );
					new_container.setAttribute( 'data-site-id', range_info.site_id );
					new_container.setAttribute( 'data-link-type', 'post' );
					new_container.setAttribute( 'target', '_self' );
				} else if ( 'tracks' === range_info.type && range_info.context ) {
					new_container.setAttribute( 'data-link-type', 'tracks' );
					new_container.setAttribute( 'data-tracks-event', range_info.context );
				}

				build_chunks( new_sub_text, new_sub_range, range_data, new_container, options );
			} else {
				
				new_container = document.createElement( 'span' );
				if ( new_sub_text.length > 0 ) {
					build_chunks( new_sub_text, new_sub_range, range_data, new_container, options );
				}
			}
			break;
	}

	if ( new_classes.length > 0 ) {
		new_container.className = new_classes.join( ' ' );
	}

	return new_container;
}
function render_range ( new_sub_text , new_sub_range , range_info , range_data , options ) { // Its time to build the outer shell of the range we're recursing into. let new_container = null , new_classes = [ ] , type_mappings ; let range_info_type = range_info . type ; if ( typeof range_info . type !== 'undefined' ) { type_mappings = { b : 'strong' , // be strong, my friend i : 'em' , // I am, don't worry noticon : 'gridicon' , } ; // Replace unwanted tags with more popular and cool ones if ( range_info . type in type_mappings ) { range_info_type = type_mappings [ range_info . type ] ; } new_classes . push ( ` ${ range_info_type } ` ) ; } // We want to do different things depending on the range type. switch ( range_info_type ) { // The badges should have their height and width set on // the server-side, but just in case they aren't, give // good defaults here case 'badge' : if ( ! range_info . hasOwnProperty ( 'width' ) ) { range_info . width = 256 ; } if ( ! range_info . hasOwnProperty ( 'height' ) ) { range_info . height = 256 ; } case 'image' : // Images and badges are not recursed into new_container = document . createElement ( 'img' ) ; new_container . setAttribute ( 'src' , range_info . url ) ; if ( range_info . hasOwnProperty ( 'width' ) ) { new_container . setAttribute ( 'width' , range_info . width ) ; } if ( range_info . hasOwnProperty ( 'height' ) ) { new_container . setAttribute ( 'height' , range_info . height ) ; } if ( new_sub_text . trim ( ) . length > 0 ) { new_container . setAttribute ( 'alt' , new_sub_text ) ; } break ; // All of the following are simple element types we want to create and then // recurse into for their constituent blocks or texts case 'blockquote' : case 'code' : case 'strong' : case 'em' : case 'list' : switch ( range_info_type ) { case 'list' : range_info_type = 'span' ; break ; } new_container = document . createElement ( range_info_type ) ; build_chunks ( new_sub_text , new_sub_range , range_data , new_container , options ) ; break ; case 'gridicon' : // Gridicons have special text, and are thus not recursed into new_container = document . createElement ( 'span' ) ; new_container . innerHTML = ReactDOMServer . renderToStaticMarkup ( React . createElement ( Gridicon , { icon : noticon2gridicon ( range_info . value ) , size : 18 , } ) ) ; break ; case 'button' : new_classes . push ( 'is-primary' ) ; default : // Most range types fall here if ( options . links && range_info . url ) { // We are a link of some sort... new_container = document . createElement ( 'a' ) ; new_container . setAttribute ( 'href' , range_info . url ) ; if ( range_info_type == 'stat' ) { // Stat links should change the whole window/tab new_container . setAttribute ( 'target' , '_parent' ) ; } else { // Other links should link into a new window/tab new_container . setAttribute ( 'target' , '_blank' ) ; } if ( 'post' === range_info . type ) { new_container . setAttribute ( 'data-post-id' , range_info . id ) ; new_container . setAttribute ( 'data-site-id' , range_info . site_id ) ; new_container . setAttribute ( 'data-link-type' , 'post' ) ; new_container . setAttribute ( 'target' , '_self' ) ; } else if ( 'tracks' === range_info . type && range_info . context ) { new_container . setAttribute ( 'data-link-type' , 'tracks' ) ; new_container . setAttribute ( 'data-tracks-event' , range_info . context ) ; } build_chunks ( new_sub_text , new_sub_range , range_data , new_container , options ) ; } else { // Everything else is a span new_container = document . createElement ( 'span' ) ; if ( new_sub_text . length > 0 ) { build_chunks ( new_sub_text , new_sub_range , range_data , new_container , options ) ; } } break ; } if ( new_classes . length > 0 ) { new_container . className = new_classes . join ( ' ' ) ; } return new_container ; }
Create the actual DOM nodes for a given piece of text/ranges and
recurse downward into the range tree if necessary.

@param {string} new_sub_text Plaintext on which ranges act
@param {Array} new_sub_range Position/applicable ranges array
@param {object} range_info The origin range data for this render
@param {Array} range_data All range data
@param {object} options
@returns {DocumentFragment} Computed DOM nodes for all levels at or below passed range
Create the actual DOM nodes for a given piece of text / ranges and recurse downward into the range tree if necessary .