diff --git a/toolkit/components/viewsource/content/viewPartialSource.js b/toolkit/components/viewsource/content/viewPartialSource.js index 8cb761cd60ad..feda67de9186 100644 --- a/toolkit/components/viewsource/content/viewPartialSource.js +++ b/toolkit/components/viewsource/content/viewPartialSource.js @@ -123,71 +123,78 @@ function viewPartialSourceForSelection(selection) var endPath = getPath(ancestorContainer, endContainer); // clone the fragment of interest and reset everything to be relative to it - // note: it is with the clone that we operate from now on + // note: it is with the clone that we operate/munge from now on ancestorContainer = ancestorContainer.cloneNode(true); startContainer = ancestorContainer; endContainer = ancestorContainer; - var i; - for (i = startPath ? startPath.length-1 : -1; i >= 0; i--) { - startContainer = startContainer.childNodes.item(startPath[i]); - } - for (i = endPath ? endPath.length-1 : -1; i >= 0; i--) { - endContainer = endContainer.childNodes.item(endPath[i]); - } - // add special markers to record the extent of the selection - // note: |startOffset| and |endOffset| are interpreted either as - // offsets in the text data or as child indices (see the Range spec) - // (here, munging the end point first to keep the start point safe...) - var tmpNode; - if (endContainer.nodeType == Node.TEXT_NODE || - endContainer.nodeType == Node.CDATA_SECTION_NODE) { - // do some extra tweaks to try to avoid the view-source output to look like - // ...]... or ...]... (where ']' marks the end of the selection). - // To get a neat output, the idea here is to remap the end point from: - // 1. ...]... to ...]... - // 2. ...]... to ...]... - if ((endOffset > 0 && endOffset < endContainer.data.length) || - !endContainer.parentNode || !endContainer.parentNode.parentNode) - endContainer.insertData(endOffset, MARK_SELECTION_END); + // Only bother with the selection if it can be remapped. Don't mess with + // leaf elements (such as ) that secretly use anynomous content + // for their display appearance. + var canDrawSelection = ancestorContainer.hasChildNodes(); + if (canDrawSelection) { + var i; + for (i = startPath ? startPath.length-1 : -1; i >= 0; i--) { + startContainer = startContainer.childNodes.item(startPath[i]); + } + for (i = endPath ? endPath.length-1 : -1; i >= 0; i--) { + endContainer = endContainer.childNodes.item(endPath[i]); + } + + // add special markers to record the extent of the selection + // note: |startOffset| and |endOffset| are interpreted either as + // offsets in the text data or as child indices (see the Range spec) + // (here, munging the end point first to keep the start point safe...) + var tmpNode; + if (endContainer.nodeType == Node.TEXT_NODE || + endContainer.nodeType == Node.CDATA_SECTION_NODE) { + // do some extra tweaks to try to avoid the view-source output to look like + // ...]... or ...]... (where ']' marks the end of the selection). + // To get a neat output, the idea here is to remap the end point from: + // 1. ...]... to ...]... + // 2. ...]... to ...]... + if ((endOffset > 0 && endOffset < endContainer.data.length) || + !endContainer.parentNode || !endContainer.parentNode.parentNode) + endContainer.insertData(endOffset, MARK_SELECTION_END); + else { + tmpNode = doc.createTextNode(MARK_SELECTION_END); + endContainer = endContainer.parentNode; + if (endOffset == 0) + endContainer.parentNode.insertBefore(tmpNode, endContainer); + else + endContainer.parentNode.insertBefore(tmpNode, endContainer.nextSibling); + } + } else { tmpNode = doc.createTextNode(MARK_SELECTION_END); - endContainer = endContainer.parentNode; - if (endOffset == 0) - endContainer.parentNode.insertBefore(tmpNode, endContainer); - else - endContainer.parentNode.insertBefore(tmpNode, endContainer.nextSibling); + endContainer.insertBefore(tmpNode, endContainer.childNodes.item(endOffset)); } - } - else { - tmpNode = doc.createTextNode(MARK_SELECTION_END); - endContainer.insertBefore(tmpNode, endContainer.childNodes.item(endOffset)); - } - if (startContainer.nodeType == Node.TEXT_NODE || - startContainer.nodeType == Node.CDATA_SECTION_NODE) { - // do some extra tweaks to try to avoid the view-source output to look like - // ...[... or ...[... (where '[' marks the start of the selection). - // To get a neat output, the idea here is to remap the start point from: - // 1. ...[... to ...[... - // 2. ...[... to ...[... - if ((startOffset > 0 && startOffset < startContainer.data.length) || - !startContainer.parentNode || !startContainer.parentNode.parentNode || - startContainer != startContainer.parentNode.lastChild) - startContainer.insertData(startOffset, MARK_SELECTION_START); + if (startContainer.nodeType == Node.TEXT_NODE || + startContainer.nodeType == Node.CDATA_SECTION_NODE) { + // do some extra tweaks to try to avoid the view-source output to look like + // ...[... or ...[... (where '[' marks the start of the selection). + // To get a neat output, the idea here is to remap the start point from: + // 1. ...[... to ...[... + // 2. ...[... to ...[... + if ((startOffset > 0 && startOffset < startContainer.data.length) || + !startContainer.parentNode || !startContainer.parentNode.parentNode || + startContainer != startContainer.parentNode.lastChild) + startContainer.insertData(startOffset, MARK_SELECTION_START); + else { + tmpNode = doc.createTextNode(MARK_SELECTION_START); + startContainer = startContainer.parentNode; + if (startOffset == 0) + startContainer.parentNode.insertBefore(tmpNode, startContainer); + else + startContainer.parentNode.insertBefore(tmpNode, startContainer.nextSibling); + } + } else { tmpNode = doc.createTextNode(MARK_SELECTION_START); - startContainer = startContainer.parentNode; - if (startOffset == 0) - startContainer.parentNode.insertBefore(tmpNode, startContainer); - else - startContainer.parentNode.insertBefore(tmpNode, startContainer.nextSibling); + startContainer.insertBefore(tmpNode, startContainer.childNodes.item(startOffset)); } } - else { - tmpNode = doc.createTextNode(MARK_SELECTION_START); - startContainer.insertBefore(tmpNode, startContainer.childNodes.item(startOffset)); - } // now extract and display the syntax highlighted source tmpNode = doc.createElementNS(NS_XHTML, 'div'); @@ -195,7 +202,9 @@ function viewPartialSourceForSelection(selection) // the load is aynchronous and so we will wait until the view-source DOM is done // before drawing the selection. - window.document.getElementById("appcontent").addEventListener("load", drawSelection, true); + if (canDrawSelection) { + window.document.getElementById("appcontent").addEventListener("load", drawSelection, true); + } // all our content is held by the data:URI and URIs are internally stored as utf-8 (see nsIURI.idl) var loadFlags = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; diff --git a/xpfe/browser/resources/content/viewPartialSource.js b/xpfe/browser/resources/content/viewPartialSource.js index 67ecd3f93253..190f7eec39cc 100644 --- a/xpfe/browser/resources/content/viewPartialSource.js +++ b/xpfe/browser/resources/content/viewPartialSource.js @@ -119,71 +119,78 @@ function viewPartialSourceForSelection(selection) var endPath = getPath(ancestorContainer, endContainer); // clone the fragment of interest and reset everything to be relative to it - // note: it is with the clone that we operate from now on + // note: it is with the clone that we operate/munge from now on ancestorContainer = ancestorContainer.cloneNode(true); startContainer = ancestorContainer; endContainer = ancestorContainer; - var i; - for (i = startPath ? startPath.length-1 : -1; i >= 0; i--) { - startContainer = startContainer.childNodes.item(startPath[i]); - } - for (i = endPath ? endPath.length-1 : -1; i >= 0; i--) { - endContainer = endContainer.childNodes.item(endPath[i]); - } - // add special markers to record the extent of the selection - // note: |startOffset| and |endOffset| are interpreted either as - // offsets in the text data or as child indices (see the Range spec) - // (here, munging the end point first to keep the start point safe...) - var tmpNode; - if (endContainer.nodeType == Node.TEXT_NODE || - endContainer.nodeType == Node.CDATA_SECTION_NODE) { - // do some extra tweaks to try to avoid the view-source output to look like - // ...]... or ...]... (where ']' marks the end of the selection). - // To get a neat output, the idea here is to remap the end point from: - // 1. ...]... to ...]... - // 2. ...]... to ...]... - if ((endOffset > 0 && endOffset < endContainer.data.length) || - !endContainer.parentNode || !endContainer.parentNode.parentNode) - endContainer.insertData(endOffset, MARK_SELECTION_END); + // Only bother with the selection if it can be remapped. Don't mess with + // leaf elements (such as ) that secretly use anynomous content + // for their display appearance. + var canDrawSelection = ancestorContainer.hasChildNodes(); + if (canDrawSelection) { + var i; + for (i = startPath ? startPath.length-1 : -1; i >= 0; i--) { + startContainer = startContainer.childNodes.item(startPath[i]); + } + for (i = endPath ? endPath.length-1 : -1; i >= 0; i--) { + endContainer = endContainer.childNodes.item(endPath[i]); + } + + // add special markers to record the extent of the selection + // note: |startOffset| and |endOffset| are interpreted either as + // offsets in the text data or as child indices (see the Range spec) + // (here, munging the end point first to keep the start point safe...) + var tmpNode; + if (endContainer.nodeType == Node.TEXT_NODE || + endContainer.nodeType == Node.CDATA_SECTION_NODE) { + // do some extra tweaks to try to avoid the view-source output to look like + // ...]... or ...]... (where ']' marks the end of the selection). + // To get a neat output, the idea here is to remap the end point from: + // 1. ...]... to ...]... + // 2. ...]... to ...]... + if ((endOffset > 0 && endOffset < endContainer.data.length) || + !endContainer.parentNode || !endContainer.parentNode.parentNode) + endContainer.insertData(endOffset, MARK_SELECTION_END); + else { + tmpNode = doc.createTextNode(MARK_SELECTION_END); + endContainer = endContainer.parentNode; + if (endOffset == 0) + endContainer.parentNode.insertBefore(tmpNode, endContainer); + else + endContainer.parentNode.insertBefore(tmpNode, endContainer.nextSibling); + } + } else { tmpNode = doc.createTextNode(MARK_SELECTION_END); - endContainer = endContainer.parentNode; - if (endOffset == 0) - endContainer.parentNode.insertBefore(tmpNode, endContainer); - else - endContainer.parentNode.insertBefore(tmpNode, endContainer.nextSibling); + endContainer.insertBefore(tmpNode, endContainer.childNodes.item(endOffset)); } - } - else { - tmpNode = doc.createTextNode(MARK_SELECTION_END); - endContainer.insertBefore(tmpNode, endContainer.childNodes.item(endOffset)); - } - if (startContainer.nodeType == Node.TEXT_NODE || - startContainer.nodeType == Node.CDATA_SECTION_NODE) { - // do some extra tweaks to try to avoid the view-source output to look like - // ...[... or ...[... (where '[' marks the start of the selection). - // To get a neat output, the idea here is to remap the start point from: - // 1. ...[... to ...[... - // 2. ...[... to ...[... - if ((startOffset > 0 && startOffset < startContainer.data.length) || - !startContainer.parentNode || !startContainer.parentNode.parentNode || - startContainer != startContainer.parentNode.lastChild) - startContainer.insertData(startOffset, MARK_SELECTION_START); + if (startContainer.nodeType == Node.TEXT_NODE || + startContainer.nodeType == Node.CDATA_SECTION_NODE) { + // do some extra tweaks to try to avoid the view-source output to look like + // ...[... or ...[... (where '[' marks the start of the selection). + // To get a neat output, the idea here is to remap the start point from: + // 1. ...[... to ...[... + // 2. ...[... to ...[... + if ((startOffset > 0 && startOffset < startContainer.data.length) || + !startContainer.parentNode || !startContainer.parentNode.parentNode || + startContainer != startContainer.parentNode.lastChild) + startContainer.insertData(startOffset, MARK_SELECTION_START); + else { + tmpNode = doc.createTextNode(MARK_SELECTION_START); + startContainer = startContainer.parentNode; + if (startOffset == 0) + startContainer.parentNode.insertBefore(tmpNode, startContainer); + else + startContainer.parentNode.insertBefore(tmpNode, startContainer.nextSibling); + } + } else { tmpNode = doc.createTextNode(MARK_SELECTION_START); - startContainer = startContainer.parentNode; - if (startOffset == 0) - startContainer.parentNode.insertBefore(tmpNode, startContainer); - else - startContainer.parentNode.insertBefore(tmpNode, startContainer.nextSibling); + startContainer.insertBefore(tmpNode, startContainer.childNodes.item(startOffset)); } } - else { - tmpNode = doc.createTextNode(MARK_SELECTION_START); - startContainer.insertBefore(tmpNode, startContainer.childNodes.item(startOffset)); - } // now extract and display the syntax highlighted source tmpNode = doc.createElementNS(NS_XHTML, 'div'); @@ -191,7 +198,9 @@ function viewPartialSourceForSelection(selection) // the load is aynchronous and so we will wait until the view-source DOM is done // before drawing the selection. - window.document.getElementById("appcontent").addEventListener("load", drawSelection, true); + if (canDrawSelection) { + window.document.getElementById("appcontent").addEventListener("load", drawSelection, true); + } // all our content is held by the data:URI and URIs are internally stored as utf-8 (see nsIURI.idl) var loadFlags = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;