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. I later realized I just needed to mutate the webpage by surrounding italic text with slashes. I would run a bookmarklet, then copy/paste. (Note: skip to the last code block 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”). After I realized this, 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.