blocks to the clipboard correctly?
We\'ve noticed that IE7 has an odd behavor with code blocks posted on Stack Overflow. For example, this little code block:
public PageSizer(string href, int inde
This looks like a bug in IE, BR tags inside the PRE or CODE are not being converted into newlines in the plain text copy buffer. The rich text copy buffer is fine, so the paste works as expected for applications like wordpad.
The prettify script, that colours the code, removes all the whitespace and replaces it with HTML tags for spaces and new lines. The generated code looks something like this:
<pre><code>code<br/> code<br/> code<br/>code</code></pre>
The PRE and CODE tags are rendered by defaults with the CSS style of {whitespace: pre}. In this case, IE is failing to turn the BR tags into newlines. It would work on your original HTML because IE will successfully turn actual newlines into newlines.
In order to fix it you have 3 options. (I am presuming you want nice HTML and the ability to work well with and without javascript enabled on the client):
You could place the code inside a normal div and use CSS to render it using {whitespace: pre}. This is a simple solution, although might not please an HTML markup purist.
You could have two copies of the code, one using proper PRE / CODE tags and another in a normal div. In your CSS you hide the normal div. Using javascript you prettify the normal div and hide the pre/code version.
Modify the prettify script to recognise that it is acting on a PRE or CODE element and to not replace the whitespace in that event.
Notes:
What is important is not the HTML in your source, but the HTML that is generated after the prettify script has ran on it.
This bug is still present even if the white-space mode of the PRE is changed to normal using CSS.
Here's the issue:
Your code colorization script replaces line breaks with <br /> tags. When copying/pasting, IE7 apparently doesn't translate the <br /> tag into a linebreak like it does for the screen.
In other words, your code becomes this:
public PageSizer(string href, int index)<br />{<br /> HRef = href;<br /> PageIndex = index;<br /> }
But you want it to become this:
public PageSizer(string href, int index)<br />
{<br />
HRef = href;<br />
PageIndex = index;<br />
}<br />
In the latest version of prettify.js on Google Code, the line responsible is line 1001 (part of recombineTagsAndDecorations):
html.push(htmlChunk.replace(newlineRe, '<br />'));
Edited, based on the comments:
For IE7, this is what the line should probably be changed to:
html.push(htmlChunk.replace(newlineRe, '\n'));
(Assuming newlineRe is a placeholder).
This fix also holds up in Chrome, and FFX3... I'm not sure which (if any) browsers need the <br /> tags.
Update:
More information in my second response:
Why doesn't IE7 copy <pre><code> blocks to the clipboard correctly?
Remove the inner <code>
. IE's copy/paste behavior could see that as an inline tag and forget about the visible whitespace.
@Jeff Atwood It's the right idea, but the implementation still needs work. I guess my air code just didn't cut it :)
I suspect that the fix I mentioned earlier doesn't work because prettify is doing some additional processing on the text after line ~1000 is called.
Trying to track the content backwards from when it's added to the page, I came across this comment around line 1227:
// Replace <br>s with line-feeds so that copying and pasting works
// on IE 6.
// Doing this on other browsers breaks lots of stuff since \r\n is
// treated as two newlines on Firefox, and doing this also slows
// down rendering.
When I took the isIE6 condition off of the code, it mostly worked in IE7 (there was an extra line break at the top and bottom), and Firefox 3... But I'd assume that it causes issues with older versions of FFX.
At the very least, it appears that IE7 will require \r\n, instead of just \n. Figuring out exactly what will work with which browsers will take a more extensive test setup than I have handy at the moment.
Anyway, inserting the \r\n for IE7 appears to be basically what needs to happen. I'll keep poking around prettify to see if I can narrow it down further.
UPDATE: IE7 appears to strip newline characters (\r or \n) from strings that are assigned to an innerHTML property. It looks like they need to be added back in, around line 1227.
A correct solution would probably mean inserting a placeholder tag around line 1000, and then replacing it around line 1227.
bad news : none of the proposed fixes work. Modifying prettify.js around line 1000
html.push(htmlChunk.replace(newlineRe, '\n'));
This causes double-spacing in other browsers, and still doesn't solve the IE7 copy to notepad problem! So even if I selectively detected IE7, this "fix" doesn't fix anything.
I guess maybe it is simply a bug in IE7 having to do with JavaScript rebuilding a <pre>
element -- no matter how many \n newlines I put in there, nothing changes w/r/t to the paste to notepad behavior.
It seems that this is a known bug for IE6 and prettify.js has a workaround for it. Specifically it replaces the BR tags with '\r\n'.
By modifying the check to allow for IE6 or 7 then the cut-and-paste will work correctly from IE7, but it will render with a newline followed by a space. By checking for IE7 and providing just a '\r' instead of a '\r\n' it will continue to cut-and-paste and render correctly.
Add this code to prettify.js:
function _pr_isIE7() {
var isIE7 = navigator && navigator.userAgent &&
/\bMSIE 7\./.test(navigator.userAgent);
_pr_isIE7 = function () { return isIE7; };
return isIE7;
}
and then modify the prettyPrint function as follows:
function prettyPrint(opt_whenDone) {
var isIE6 = _pr_isIE6();
+ var isIE7 = _pr_isIE7();
...
- if (isIE6 && cs.tagName === 'PRE') {
+ if ((isIE6 || isIE7) && cs.tagName === 'PRE') {
var lineBreaks = cs.getElementsByTagName('br');
+ var newline;
+ if (isIE6) {
+ newline = '\r\n';
+ } else {
+ newline = '\r';
+ }
for (var j = lineBreaks.length; --j >= 0;) {
var lineBreak = lineBreaks[j];
lineBreak.parentNode.replaceChild(
- document.createTextNode('\r\n'), lineBreak);
+ document.createTextNode(newline), lineBreak);
}
You can see a working example here.
Note: I haven't tested the original workaround in IE6, so I'm guessing it renders without the space caused by the '\n' that is seen in IE7, otherwise the fix is simpler.