зеркало из https://github.com/mozilla/pjs.git
Bug 409380, support 'unconnected' ranges , r+sr+a=sicking
This commit is contained in:
Родитель
673dcc3262
Коммит
6f63777235
|
@ -267,11 +267,13 @@ public:
|
|||
* node/offset pair
|
||||
* Returns -1 if point1 < point2, 1, if point1 > point2,
|
||||
* 0 if error or if point1 == point2.
|
||||
* NOTE! The two nodes MUST be in the same connected subtree!
|
||||
* if they are not the result is undefined.
|
||||
* NOTE! If the two nodes aren't in the same connected subtree,
|
||||
* the result is undefined, but the optional aDisconnected parameter
|
||||
* is set to PR_TRUE.
|
||||
*/
|
||||
static PRInt32 ComparePoints(nsINode* aParent1, PRInt32 aOffset1,
|
||||
nsINode* aParent2, PRInt32 aOffset2);
|
||||
nsINode* aParent2, PRInt32 aOffset2,
|
||||
PRBool* aDisconnected = nsnull);
|
||||
|
||||
/**
|
||||
* Find the first child of aParent with a resolved tag matching
|
||||
|
|
|
@ -1496,7 +1496,8 @@ nsContentUtils::ComparePosition(nsINode* aNode1,
|
|||
/* static */
|
||||
PRInt32
|
||||
nsContentUtils::ComparePoints(nsINode* aParent1, PRInt32 aOffset1,
|
||||
nsINode* aParent2, PRInt32 aOffset2)
|
||||
nsINode* aParent2, PRInt32 aOffset2,
|
||||
PRBool* aDisconnected)
|
||||
{
|
||||
if (aParent1 == aParent2) {
|
||||
return aOffset1 < aOffset2 ? -1 :
|
||||
|
@ -1519,8 +1520,12 @@ nsContentUtils::ComparePoints(nsINode* aParent1, PRInt32 aOffset1,
|
|||
PRUint32 pos1 = parents1.Length() - 1;
|
||||
PRUint32 pos2 = parents2.Length() - 1;
|
||||
|
||||
NS_ASSERTION(parents1.ElementAt(pos1) == parents2.ElementAt(pos2),
|
||||
NS_ASSERTION(parents1.ElementAt(pos1) == parents2.ElementAt(pos2) ||
|
||||
aDisconnected,
|
||||
"disconnected nodes");
|
||||
if (aDisconnected) {
|
||||
*aDisconnected = (parents1.ElementAt(pos1) != parents2.ElementAt(pos2));
|
||||
}
|
||||
|
||||
// Find where the parent chains differ
|
||||
nsINode* parent = parents1.ElementAt(pos1);
|
||||
|
|
|
@ -103,6 +103,7 @@ nsresult
|
|||
nsRange::CompareNodeToRange(nsIContent* aNode, nsIRange* aRange,
|
||||
PRBool *outNodeBefore, PRBool *outNodeAfter)
|
||||
{
|
||||
NS_ENSURE_STATE(aNode);
|
||||
// create a pair of dom points that expresses location of node:
|
||||
// NODE(start), NODE(end)
|
||||
// Let incoming range be:
|
||||
|
@ -142,14 +143,19 @@ nsRange::CompareNodeToRange(nsIContent* aNode, nsIRange* aRange,
|
|||
PRInt32 rangeEndOffset = range->EndOffset();
|
||||
|
||||
// is RANGE(start) <= NODE(start) ?
|
||||
PRBool disconnected = PR_FALSE;
|
||||
*outNodeBefore = nsContentUtils::ComparePoints(rangeStartParent,
|
||||
rangeStartOffset,
|
||||
parent, nodeStart) > 0;
|
||||
parent, nodeStart,
|
||||
&disconnected) > 0;
|
||||
NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
|
||||
|
||||
// is RANGE(end) >= NODE(end) ?
|
||||
*outNodeAfter = nsContentUtils::ComparePoints(rangeEndParent,
|
||||
rangeEndOffset,
|
||||
parent, nodeEnd) < 0;
|
||||
|
||||
parent, nodeEnd,
|
||||
&disconnected) < 0;
|
||||
NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -335,6 +341,18 @@ nsRange::NodeWillBeDestroyed(const nsINode* aNode)
|
|||
DoSetRange(nsnull, 0, nsnull, 0, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
nsRange::ParentChainChanged(nsIContent *aContent)
|
||||
{
|
||||
NS_ASSERTION(mRoot == aContent, "Wrong ParentChainChanged notification?");
|
||||
nsINode* newRoot = mRoot;
|
||||
nsINode* tmp;
|
||||
while ((tmp = newRoot->GetNodeParent())) {
|
||||
newRoot = tmp;
|
||||
}
|
||||
DoSetRange(mStartParent, mStartOffset, mEndParent, mEndOffset, newRoot);
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* Utilities for comparing points: API from nsIDOMNSRange
|
||||
********************************************************/
|
||||
|
@ -433,7 +451,9 @@ nsRange::DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
|
|||
(!aRoot->GetNodeParent() &&
|
||||
(aRoot->IsNodeOfType(nsINode::eDOCUMENT) ||
|
||||
aRoot->IsNodeOfType(nsINode::eATTRIBUTE) ||
|
||||
aRoot->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT))),
|
||||
aRoot->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
|
||||
/*For backward compatibility*/
|
||||
aRoot->IsNodeOfType(nsINode::eCONTENT))),
|
||||
"Bad root");
|
||||
|
||||
if (mRoot != aRoot) {
|
||||
|
@ -592,22 +612,14 @@ nsINode* nsRange::IsValidBoundary(nsINode* aNode)
|
|||
NS_ASSERTION(!root->IsNodeOfType(nsINode::eDOCUMENT),
|
||||
"GetCurrentDoc should have returned a doc");
|
||||
|
||||
if (root->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
|
||||
root->IsNodeOfType(nsINode::eATTRIBUTE)) {
|
||||
return root;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_smaug
|
||||
nsCOMPtr<nsIContent> cont = do_QueryInterface(root);
|
||||
if (cont) {
|
||||
nsAutoString name;
|
||||
cont->Tag()->ToString(name);
|
||||
printf("nsRange::IsValidBoundary: node is not a valid boundary point [%s]\n",
|
||||
NS_ConvertUTF16toUTF8(name).get());
|
||||
}
|
||||
NS_WARN_IF_FALSE(root->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
|
||||
root->IsNodeOfType(nsINode::eATTRIBUTE),
|
||||
"Creating a DOM Range using root which isn't in DOM!");
|
||||
#endif
|
||||
|
||||
return nsnull;
|
||||
// We allow this because of backward compatibility.
|
||||
return root;
|
||||
}
|
||||
|
||||
nsresult nsRange::SetStart(nsIDOMNode* aParent, PRInt32 aOffset)
|
||||
|
@ -1526,7 +1538,7 @@ nsresult nsRange::CloneContents(nsIDOMDocumentFragment** aReturn)
|
|||
tmpNode = clone;
|
||||
res = tmpNode->GetParentNode(getter_AddRefs(clone));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!node) return NS_ERROR_FAILURE;
|
||||
if (!clone) return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
commonCloneAncestor = clone;
|
||||
|
@ -1576,6 +1588,7 @@ nsresult nsRange::InsertNode(nsIDOMNode* aN)
|
|||
nsCOMPtr<nsIDOMNode> tSCParentNode;
|
||||
res = tStartContainer->GetParentNode(getter_AddRefs(tSCParentNode));
|
||||
if(NS_FAILED(res)) return res;
|
||||
NS_ENSURE_STATE(tSCParentNode);
|
||||
|
||||
PRBool isCollapsed;
|
||||
res = GetCollapsed(&isCollapsed);
|
||||
|
|
|
@ -110,6 +110,7 @@ public:
|
|||
nsIContent* aChild,
|
||||
PRInt32 aIndexInContainer);
|
||||
virtual void NodeWillBeDestroyed(const nsINode* aNode);
|
||||
virtual void ParentChainChanged(nsIContent *aContent);
|
||||
|
||||
private:
|
||||
// no copy's or assigns
|
||||
|
|
|
@ -164,6 +164,7 @@ _TEST_FILES = test_bug5141.html \
|
|||
test_bug403868.xml \
|
||||
test_bug405182.html \
|
||||
test_bug403841.html \
|
||||
test_bug409380.html \
|
||||
test_bug410229.html \
|
||||
test_bug415860.html \
|
||||
test_bug414190.html \
|
||||
|
|
|
@ -0,0 +1,379 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=409380
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 409380</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=409380">Mozilla Bug 409380</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 409380 **/
|
||||
|
||||
function runRangeTest()
|
||||
{
|
||||
// Bug 336381
|
||||
// This is a case which can't be supported (at least not at the moment)
|
||||
// because DOM Range requires that when the start boundary point is text node,
|
||||
// it must be splitted. But in this case boundary point doesn't have parent,
|
||||
// so splitting doesn't work.
|
||||
var zz = document.getElementById("connectedDiv").firstChild;
|
||||
zz.parentNode.removeChild(zz);
|
||||
var range = document.createRange();
|
||||
var hadException = false;
|
||||
try {
|
||||
range.setStart(zz, 0);
|
||||
range.setEnd(zz, 0);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException ,
|
||||
"It should be possible to select text node even if the node is not in DOM.");
|
||||
hadException = false;
|
||||
try {
|
||||
r.insertNode(document.createTextNode('5'));
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException,
|
||||
"It shouldn't be possible to insert text node to a detached range.");
|
||||
|
||||
// Bug 409380
|
||||
var element = document.createElement('div');
|
||||
var elementContent = "This is the element content";
|
||||
element.innerHTML = elementContent;
|
||||
range = element.ownerDocument.createRange();
|
||||
hadException = false;
|
||||
try {
|
||||
range.selectNodeContents(element);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException,
|
||||
"It should be possible to select node contents of a detached element.");
|
||||
ok(range.toString() == elementContent, "Wrong range selection");
|
||||
|
||||
// range.selectNode can't succeed because selectNode sets boundary points
|
||||
// to be parentNode, which in this testcase is null.
|
||||
element = document.createElement('div');
|
||||
range = element.ownerDocument.createRange();
|
||||
hadException = false;
|
||||
try {
|
||||
range.selectNode(element);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "It shouldn't be possible to select a detached element.");
|
||||
|
||||
// Testing contextual fragment.
|
||||
range = element.ownerDocument.createRange();
|
||||
var cf = null;
|
||||
var testContent = "<span>foo</span><span>bar</span>";
|
||||
try {
|
||||
range.selectNodeContents(element);
|
||||
cf = range.createContextualFragment(testContent);
|
||||
element.appendChild(cf);
|
||||
} catch (ex) {
|
||||
}
|
||||
ok(cf, "Creating contextual fragment didn't succeed!");
|
||||
ok(element.innerHTML == testContent, "Wrong innerHTML!");
|
||||
|
||||
element = document.createElement('div');
|
||||
element.textContent = "foobar";
|
||||
range = element.ownerDocument.createRange();
|
||||
try {
|
||||
range.selectNodeContents(element);
|
||||
element.firstChild.insertData(3, " ");
|
||||
} catch (ex) {
|
||||
}
|
||||
ok(range.toString() == "foo bar");
|
||||
|
||||
// Testing contextual fragment, but inserting element to document
|
||||
// after creating range.
|
||||
element = document.createElement('div');
|
||||
range = element.ownerDocument.createRange();
|
||||
document.body.appendChild(element);
|
||||
cf = null;
|
||||
testContent = "<span>foo</span><span>bar</span>";
|
||||
try {
|
||||
range.selectNodeContents(element);
|
||||
cf = range.createContextualFragment(testContent);
|
||||
element.appendChild(cf);
|
||||
} catch (ex) {
|
||||
}
|
||||
ok(cf, "Creating contextual fragment didn't succeed!");
|
||||
ok(element.innerHTML == testContent, "Wrong innerHTML!");
|
||||
|
||||
// Testing contextual fragment, but inserting element to document
|
||||
// before creating range.
|
||||
element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
range = element.ownerDocument.createRange();
|
||||
cf = null;
|
||||
testContent = "<span>foo</span><span>bar</span>";
|
||||
try {
|
||||
range.selectNodeContents(element);
|
||||
cf = range.createContextualFragment(testContent);
|
||||
element.appendChild(cf);
|
||||
} catch (ex) {
|
||||
}
|
||||
ok(cf, "Creating contextual fragment didn't succeed!");
|
||||
ok(element.innerHTML == testContent, "Wrong innerHTML!");
|
||||
|
||||
element = document.createElement('div');
|
||||
var range2 = element.ownerDocument.createRange();
|
||||
hadException = false;
|
||||
try {
|
||||
range2.selectNodeContents(element);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException,
|
||||
"It should be possible to select node contents of a detached element.");
|
||||
|
||||
// Now the boundary points of range are in DOM, but boundary points of
|
||||
// range2 aren't.
|
||||
hadException = false;
|
||||
try {
|
||||
range.compareBoundaryPoints(range.START_TO_START, range2);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range.compareBoundaryPoints(range.START_TO_END, range2);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range.compareBoundaryPoints(range.END_TO_START, range2);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range.compareBoundaryPoints(range.END_TO_END, range2);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range2.compareBoundaryPoints(range.START_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range2.compareBoundaryPoints(range.START_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range2.compareBoundaryPoints(range.END_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range2.compareBoundaryPoints(range.END_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
// range3 will be in document
|
||||
element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
range3 = element.ownerDocument.createRange();
|
||||
hadException = false;
|
||||
try {
|
||||
range3.selectNodeContents(element);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException,
|
||||
"It should be possible to select node contents of a detached element.");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range3.compareBoundaryPoints(range.START_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range3.compareBoundaryPoints(range.START_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range3.compareBoundaryPoints(range.END_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range3.compareBoundaryPoints(range.END_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
// range4 won't be in document
|
||||
element = document.createElement('div');
|
||||
var range4 = element.ownerDocument.createRange();
|
||||
hadException = false;
|
||||
try {
|
||||
range4.selectNodeContents(element);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException,
|
||||
"It should be possible to select node contents of a detached element.");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range4.compareBoundaryPoints(range.START_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range2.compareBoundaryPoints(range.START_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range4.compareBoundaryPoints(range.END_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range4.compareBoundaryPoints(range.END_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(hadException, "Should have got an exception!");
|
||||
|
||||
// Compare range to itself.
|
||||
hadException = false;
|
||||
try {
|
||||
range.compareBoundaryPoints(range.START_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range.compareBoundaryPoints(range.START_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range.compareBoundaryPoints(range.END_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range.compareBoundaryPoints(range.END_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
// Attach startContainer of range2 to document.
|
||||
ok(range2.startContainer == range2.endContainer, "Wrong container?");
|
||||
document.body.appendChild(range2.startContainer);
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range2.compareBoundaryPoints(range.START_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range2.compareBoundaryPoints(range.START_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range2.compareBoundaryPoints(range.END_TO_START, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
hadException = false;
|
||||
try {
|
||||
range2.compareBoundaryPoints(range.END_TO_END, range);
|
||||
} catch (ex) {
|
||||
hadException = true;
|
||||
}
|
||||
ok(!hadException, "Shouldn't have got an exception!");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(runRangeTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
<div id="connectedDiv">zz</div>
|
||||
</body>
|
||||
</html>
|
||||
|
Загрузка…
Ссылка в новой задаче