Preserving italics in pastes from webpages

Tired of losing italics in pastes from websites to your plain-text editor? For a while, I thought I needed to switch to a rich-text editor to handle these pastes, but that would be a pain for several reasons. A few days ago I realized I just needed to mutate the webpage by surrounding italic text with slashes. I would run a bookmarklet, then copy/paste. (Skip below for a working bookmarklet).

My first attempt at this used the :before and :after CSS pseudo-elements:

javascript:(function() {
	var newSS, styles='em:before, em:after, i:before, i:after { content: "/" }';
	if(document.createStyleSheet) {
		document.createStyleSheet("javascript:'" + styles + "'");
	} else {
		newSS = document.createElement('link');
		newSS.rel = 'stylesheet';
		newSS.href = 'data:text/css,' + escape(styles);
		document.getElementsByTagName("head")[0].appendChild(newSS);
	}
})();

If you run the above (paste into your URL bar and hit enter), it looks like it works until you try to paste the text containing slashes; neither Chrome 10 or Firefox 4 will put the slashes in your clipboard. I threw out the simple clean non-working code and went for a terrible hack:

javascript:(function() { document.body.innerHTML = document.body.innerHTML.
	replace(/<em(\s.*?)?>([\s\S]+?)<\/em>/gi, "/<em$1>$2</em>/").
	replace(/<i(\s.*?)?>([\s\S]+?)<\/i>/gi, "/<i$1>$2</i>/").
	replace(/<span style="font-style: italic;">([\s\S]+?)<\/span>/gi, '/<span style="font-style: italic;">$1</span>/').
	replace(/<strong(\s.*?)?>([\s\S]+?)<\/strong>/gi, "*<strong$1>$2</strong>*").
	replace(/<b(\s.*?)?>([\s\S]+?)<\/b>/gi, "*<b$1>$2</b>*"); })();

This above replaces document.body.innerHTML with a new string where italics are surrounded with “/” and bold surrounded by “*”. This is terrible in several ways: it may break or re-run JavaScript code on the page, or somehow make you vulnerable to XSS (in a manner likely similar to the IE8 XSS “blocker”). Only while writing this post did I realize the security implications of the above. I decided to implement it using DOM manipulation (requires CSS3 selectors and querySelectorAll):

javascript:(function() { 
	var wrapElements = function(selector, wrapperText) {
		var elements = document.querySelectorAll(selector);
		for(var i=0; i < elements.length; i++) {
			var surround = elements[i];
			if(surround.parentNode) {
				surround.parentNode.insertBefore(
					document.createTextNode(wrapperText), surround);
			}
			surround.appendChild(
				document.createTextNode(wrapperText));
		}
	};
 
	var getStyleAttrVariations = function(elem, property, value) {
		return [
			 elem + '[style="' + property + ': ' + value + ';"]'
			,elem + '[style="' + property + ': ' + value + '"]'
			,elem + '[style="' + property + ':'  + value + ';"]'
			,elem + '[style="' + property + ':'  + value + '"]'
		];
	};
 
	wrapElements('em, i, span[class~="emphasis"], span[class~="italic"]', '/');
	wrapElements(getStyleAttrVariations('span', 'font-style', 'italic').join(' ,'), '/');
 
	wrapElements('strong, b, span[class~="bold"]', '*');
	wrapElements(getStyleAttrVariations('span', 'font-weight', 'bold').join(' ,'), '*');
})();

If you don’t want to manually create a bookmark with the above code, you can drag this link to your toolbar or bookmarks:

Preserve italics and bold

I use a bookmark keyword in Firefox to activate it; keywords are not just for searches.

Here’s some bold and italic text so you know it’s working: bold, italic.

Comments are closed.