Blackout Poetry

Inspired by this question on SO: http://stackoverflow.com/questions/42288969/blackout-text-for-an-art-project#42289040

by godfrzero

HTML

<p class="interactive-blackout">
  It is not growing like a tree <br />
  in bulk, doth make Man better be; <br />
  or standing long an oak three hundred year, <br />
  to fall a log at last, dry, bald, and sere; <br />
</p>

<p class="interactive-blackout">
  A lily of a day <br />
  is fairer in May, <br />
  although it fall and die that night- <br />
  It was the plant and flower of Light. <br />
  In small proportions we just beauties see: <br />
  and in short measures life may perfect be. <br />
</p>

SCSS

.interactive-blackout {
	user-select: none;

	span {
		color: black;
		cursor: pointer;
		background: none;
		display: inline-block;
		
		&.is-blacked-out {
			background: black;
		}
		
		&:not(.is-blacked-out):hover {
			background: rgba(0, 0, 0, 0.2);
		}
	}
}

JavaScript

$('.interactive-blackout').each(function (_, source) {
	var $source = $(source);

	$source.each(function (_, src) {
		var $src = $(src),
			html = $src.html(),
			text = html.split(' '),
			wrapper = '<span>%s&nbsp;</span>',
			wrapped = '';
			
		text.length && text.forEach(function (token) {
			// Ignore things we want to ignore
			if (/^\s+$/.test(token)) { return; }

			// Rudimentary check for HTML tags, which we don't want to wrap
			// because that'd just be silly now, wouldn't it?
			!/^<[^>]+>(\s)?$/.test(token) &&

			// ...and let's wrap it up. lol.
			(wrapped += wrapper.replace('%s', token)) ||
			(wrapped += token);
		});

		$src
			// Store the original HTML, at some point in the future maybe we'll extend
			// this script to allow some kind of reset. Who knows?
			.data('original-html', html)
			// The usage of .html() here leaves this whole thing open to an XSS attack
			// so don't do any of this unless you trust the text source.
			.html(wrapped);
	});
});

$('body').on('click', '.interactive-blackout span', function (e) {
	$(e.currentTarget).toggleClass('is-blacked-out');
});