This commit is contained in:
Ms2ger 2012-05-18 13:32:20 +02:00
Родитель 2ed442b005 d7148ea84f
Коммит 94f9583d11
122 изменённых файлов: 81298 добавлений и 596 удалений

Просмотреть файл

@ -1498,7 +1498,7 @@ nsHyperTextAccessible::DeleteText(PRInt32 aStartPos, PRInt32 aEndPos)
nsresult rv = SetSelectionRange(aStartPos, aEndPos);
NS_ENSURE_SUCCESS(rv, rv);
return editor->DeleteSelection(nsIEditor::eNone);
return editor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
}
NS_IMETHODIMP

Просмотреть файл

@ -11275,7 +11275,7 @@ define("examples/textview/textStyler", ['orion/textview/annotations'], function(
"target", "target-name", "target-new", "target-position", "text-align", "text-align-last", "text-decoration", "text-emphasis",
"text-height", "text-indent", "text-justify", "text-outline", "text-shadow", "text-transform", "text-wrap", "top", "transform",
"transform-origin", "transform-style", "transition", "transition-delay", "transition-duration", "transition-property",
"transition-timing-function", "unicode-bidi", "vertical-align", "visibility", "voice-balance", "voice-duration", "voice-family",
"transition-timing-function", "unicode-bidi", "vector-effect", "vertical-align", "visibility", "voice-balance", "voice-duration", "voice-family",
"voice-pitch", "voice-pitch-range", "voice-rate", "voice-stress", "voice-volume", "volume", "white-space", "white-space-collapse",
"widows", "width", "word-break", "word-spacing", "word-wrap", "z-index"
];

Просмотреть файл

@ -1378,6 +1378,7 @@ GK_ATOM(y2, "y2")
GK_ATOM(yChannelSelector, "yChannelSelector")
GK_ATOM(z, "z")
GK_ATOM(zoomAndPan, "zoomAndPan")
GK_ATOM(vector_effect, "vector-effect")
GK_ATOM(accumulate, "accumulate")
GK_ATOM(additive, "additive")

Просмотреть файл

@ -628,6 +628,7 @@ nsIAtom** const kAttributesSVG[] = {
// v-ideographic
// v-mathematical
&nsGkAtoms::values, // values
&nsGkAtoms::vector_effect, // vector-effect
// vert-adv-y
// vert-origin-x
// vert-origin-y

Просмотреть файл

@ -1863,7 +1863,7 @@ nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput)
plaintextEditor->SetMaxTextLength(-1);
if (insertValue.IsEmpty()) {
mEditor->DeleteSelection(nsIEditor::eNone);
mEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
} else {
plaintextEditor->InsertText(insertValue);
}

Просмотреть файл

@ -281,6 +281,7 @@ nsSMILCSSProperty::IsPropertyAnimatable(nsCSSProperty aPropID)
case eCSSProperty_text_decoration:
case eCSSProperty_text_decoration_line:
case eCSSProperty_text_rendering:
case eCSSProperty_vector_effect:
case eCSSProperty_visibility:
case eCSSProperty_word_spacing:
return true;

Просмотреть файл

@ -463,6 +463,9 @@ var gFromToBundles = [
new TestcaseBundle(gPropList.unicode_bidi, [
new AnimTestcaseFromTo("embed", "bidi-override"),
]),
new TestcaseBundle(gPropList.vector_effect, [
new AnimTestcaseFromTo("none", "non-scaling-stroke"),
]),
new TestcaseBundle(gPropList.visibility, [
new AnimTestcaseFromTo("visible", "hidden"),
new AnimTestcaseFromTo("hidden", "collapse"),

Просмотреть файл

@ -116,6 +116,7 @@ var gPropList =
text_decoration: new NonAdditiveAttribute("text-decoration", "CSS", "text"),
text_rendering: new NonAdditiveAttribute("text-rendering", "CSS", "text"),
unicode_bidi: new NonAnimatableAttribute("unicode-bidi", "CSS", "text"),
vector_effect: new NonAdditiveAttribute("vector-effect", "CSS", "rect"),
visibility: new NonAdditiveAttribute("visibility", "CSS", "rect"),
word_spacing: new AdditiveAttribute("word-spacing", "CSS", "text"),
writing_mode:

Просмотреть файл

@ -931,6 +931,7 @@ nsSVGElement::sFillStrokeMap[] = {
{ &nsGkAtoms::stroke_miterlimit },
{ &nsGkAtoms::stroke_opacity },
{ &nsGkAtoms::stroke_width },
{ &nsGkAtoms::vector_effect },
{ nsnull }
};

Просмотреть файл

@ -20,6 +20,7 @@ text { font: 20px monospace; }
<g transform="scale(2)">
<rect id="rect3" x="25" y="80" width="50" height="50" fill="green"/>
<rect id="rect3a" x="25" y="80" width="50" height="50" fill="none" stroke-width="4" stroke="blue"/>
<rect id="rect3b" vector-effect="non-scaling-stroke" x="100" y="100" width="25" height="25" fill="orange" stroke-width="4" stroke="yellow"/>
</g>
<g transform="scale(2) rotate(45 175 75)">
<rect id="rect4" x="150" y="50" width="50" height="50" fill="yellow"/>

До

Ширина:  |  Высота:  |  Размер: 1.4 KiB

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Просмотреть файл

@ -93,6 +93,7 @@ function runTest()
var rect1aBounds = doc.getElementById("rect1a").getBoundingClientRect();
var rect2aBounds = doc.getElementById("rect2a").getBoundingClientRect();
var rect3aBounds = doc.getElementById("rect3a").getBoundingClientRect();
var rect3bBounds = doc.getElementById("rect3b").getBoundingClientRect();
var rect4aBounds = doc.getElementById("rect4a").getBoundingClientRect();
is(rect1aBounds.left, 48, "rect1a.getBoundingClientRect().left");
@ -111,6 +112,11 @@ function runTest()
is(rect3aBounds.width, 108, "rect3a.getBoundingClientRect().width");
is(rect3aBounds.height, 108, "rect3a.getBoundingClientRect().height");
is(rect3bBounds.left, 198, "rect3b.getBoundingClientRect().left");
is(rect3bBounds.top, 198, "rect3b.getBoundingClientRect().top");
is(rect3bBounds.width, 54, "rect3b.getBoundingClientRect().width");
is(rect3bBounds.height, 54, "rect3b.getBoundingClientRect().height");
rect = new Rect(350 - 108 * sin45, 150 - 108 * sin45, 108 * sin45 * 2, 108 * sin45 * 2);
isWithAbsTolerance(rect4aBounds.left, rect.left, 0.1, "rect4a.getBoundingClientRect().left");
isWithAbsTolerance(rect4aBounds.top, rect.top, 0.1, "rect4a.getBoundingClientRect().top");

Просмотреть файл

@ -9,8 +9,14 @@ VPATH = @srcdir@
relativesrcdir = dom/imported-tests
DIRS = \
failures/editing/conformancetest \
failures/editing/selecttest \
failures/webapps/WebStorage/tests/submissions/Ms2ger \
failures/webapps/WebStorage/tests/submissions/Infraware \
failures/webapps/DOMCore/tests/submissions/Opera \
$(NULL)
include $(srcdir)/editing.mk
include $(srcdir)/html.mk
include $(srcdir)/webapps.mk
include $(DEPTH)/config/autoconf.mk
@ -24,8 +30,5 @@ _SUPPORT_FILES = \
WebIDLParser.js \
$(NULL)
testharnessreport.js: testharnessreport.js.in writeReporter.py html.json webapps.json
$(PYTHON_PATH) $(srcdir)/writeReporter.py $<
libs:: $(_SUPPORT_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/resources

Просмотреть файл

@ -38,7 +38,7 @@ Source; Usage and purpose; License
<https://bitbucket.org/ms2ger/test-runner/raw/tip/manifests.txt>.
MIT License
* testharnessreport.js.in
* testharnessreport.js
Glue between testharness.js and our Mochitest runner.
MPL
@ -54,11 +54,10 @@ Source; Usage and purpose; License
includes a .mk file for each repository.
MPL
* failures.txt
List of JSON files with expected failures.
* html.json / webapps.json / ...
Expected failures for tests in the webapps repository.
* failures/
Expected failures for tests in each repository. Each test's failures, if
any, are in a file with the same path and name with .json appended. New
expected fail files currently needed to be added manually to makefiles.
* html.mk / webapps.mk / ...
Generated by importTestsuite.py from webapps.txt.
@ -74,11 +73,6 @@ Source; Usage and purpose; License
Actual tests.
W3C Test Suite License / W3C 3-clause BSD License
* writeReporter.py
Generates testharness.js from testharnessreport.js.in and the JSON files for
repositories listed in failures.txt.
MPL
=====================================================================
Importing an additional directory from an already-imported repository
@ -94,4 +88,5 @@ Importing a new test suite
==========================
Create a data file in the format documented above, and run the
importTestsuite.py script, passing the data file as its argument.
importTestsuite.py script, passing the data file as its argument. Add any
necessary files in failures/.

3
dom/imptests/editing.mk Normal file
Просмотреть файл

@ -0,0 +1,3 @@
DIRS += \
editing/ \
$(NULL)

2
dom/imptests/editing.txt Normal file
Просмотреть файл

@ -0,0 +1,2 @@
https://dvcs.w3.org/hg/editing|editing

Просмотреть файл

@ -0,0 +1,28 @@
# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/editing
DIRS = \
css \
conformancetest \
selecttest \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
$(NULL)
_TESTS += \
implementation.js \
tests.js \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,26 @@
# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/editing/conformancetest
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_runtest.html \
test_event.html \
$(NULL)
_TESTS += \
data.js \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,289 @@
<!doctype html>
<title>Editing event tests</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<div id=test></div>
<div id=log></div>
<script>
"use strict";
var div = document.querySelector("#test");
add_completion_callback(function() { div.parentNode.removeChild(div) });
function copyEvent(e) {
var ret = {};
ret.original = e;
["type", "target", "currentTarget", "eventPhase", "bubbles", "cancelable",
"defaultPrevented", "isTrusted", "command", "value"].forEach(function(k) {
ret[k] = e[k];
});
return ret;
}
var tests = [
{
name: "Simple editable div",
html: "<div contenteditable>foo<b>bar</b>baz</div>",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div.querySelector("b"), 1);
},
target: function() { return div.firstChild },
command: "bold",
value: "",
},
{
name: "Editable b",
html: "foo<b contenteditable>bar</b>baz",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div.querySelector("b"), 1);
},
target: function() { return div.querySelector("b") },
command: "bold",
value: "",
},
{
name: "No editable content",
html: "foo<b>bar</b>baz",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div.querySelector("b"), 1);
},
target: function() { return null },
command: "bold",
value: "",
},
{
name: "Partially-selected editable content",
html: "foo<b contenteditable>bar</b>baz",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div, 3);
},
target: function() { return null },
command: "bold",
value: "",
},
{
name: "Selection spans two editing hosts",
html: "<div contenteditable>foo</div><div contenteditable>bar</div>",
initRange: function(range) {
range.setStart(div.querySelector("div").firstChild, 2);
range.setEnd(div.querySelector("div + div").firstChild, 1);
},
target: function() { return null },
command: "bold",
value: "",
},
{
name: "Selection includes two editing hosts",
html: "foo<div contenteditable>bar</div>baz<div contenteditable>quz</div>qoz",
initRange: function(range) {
range.setStart(div.firstChild, 2);
range.setEnd(div.lastChild, 1);
},
target: function() { return null },
command: "bold",
value: "",
},
{
name: "Changing selection from handler",
html: "<div contenteditable>foo</div><div contenteditable>bar</div>",
initRange: function(range) {
range.setStart(div.querySelector("div").firstChild, 0);
range.setEnd(div.querySelector("div").firstChild, 3);
},
target: function() { return div.firstChild },
finalTarget: function() { return div.lastChild },
beforeInputAction: function() {
getSelection().removeAllRanges();
var range = document.createRange();
range.setStart(div.querySelector("div + div").firstChild, 0);
range.setEnd(div.querySelector("div + div").firstChild, 3);
getSelection().addRange(range);
},
command: "bold",
value: "",
},
];
var commandTests = {
backColor: ["green"],
createLink: ["http://www.w3.org/community/editing/"],
fontName: ["serif", "Helvetica"],
fontSize: ["6", "15px"],
foreColor: ["green"],
hiliteColor: ["green"],
italic: [],
removeFormat: [],
strikeThrough: [],
subscript: [],
superscript: [],
underline: [],
unlink: [],
delete: [],
formatBlock: ["p"],
forwardDelete: [],
indent: [],
insertHorizontalRule: ["id"],
insertHTML: ["<b>hi</b>"],
insertImage: ["http://example.com/some-image"],
insertLineBreak: [],
insertOrderedList: [],
insertParagraph: [],
insertText: ["abc"],
insertUnorderedList: [],
justifyCenter: [],
justifyFull: [],
justifyLeft: [],
justifyRight: [],
outdent: [],
redo: [],
selectAll: [],
styleWithCSS: [],
undo: [],
useCSS: [],
};
Object.keys(commandTests).forEach(function(command) {
commandTests[command] = ["", "quasit"].concat(commandTests[command]);
commandTests[command].forEach(function(value) {
tests.push({
name: "Command " + command + ", value " + format_value(value),
html: "<div contenteditable>foo<b>bar</b>baz</div>",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div.querySelector("b"), 1);
},
target: function() {
return ["redo", "selectAll", "styleWithCSS", "undo", "useCSS"]
.indexOf(command) == -1 ? div.firstChild : null;
},
command: command,
value: value,
});
});
});
tests.forEach(function(obj) {
[true, false].forEach(function(cancel) {
// Kill all event handlers first
var newDiv = div.cloneNode(false);
div.parentNode.insertBefore(newDiv, div);
div.parentNode.removeChild(div);
div = newDiv;
div.innerHTML = obj.html;
var originalContents = div.cloneNode(true);
getSelection().removeAllRanges();
var range = document.createRange();
obj.initRange(range);
getSelection().addRange(range);
var target = obj.target();
var finalTarget = "finalTarget" in obj ? obj.finalTarget() : target;
var command = obj.command;
var value = obj.value;
var beforeInputEvents = [];
var inputEvents = [];
div.addEventListener("beforeinput", function(e) {
var copied = copyEvent(e);
copied.inputEventsLength = inputEvents.length;
beforeInputEvents.push(copied);
if (cancel) {
e.preventDefault();
}
if ("beforeInputAction" in obj) {
obj.beforeInputAction();
}
});
div.addEventListener("input", function(e) { inputEvents.push(copyEvent(e)) });
// Uncomment this code instead of the execCommand() to make all the
// tests pass, as a sanity check
//var e = new Event("beforeinput", {bubbles: true, cancelable: true});
//e.command = command;
//e.value = value;
//var ret = target ? target.dispatchEvent(e) : false;
//if (ret) {
// var e = new Event("input", {bubbles: true});
// e.command = command;
// e.value = value;
// finalTarget.dispatchEvent(e);
//}
var exception = null;
try {
document.execCommand(command, false, value);
} catch(e) {
exception = e;
}
test(function() {
assert_equals(exception, null, "Unexpected exception");
}, obj.name + ": execCommand() must not throw, "
+ (cancel ? "canceled" : "uncanceled"));
test(function() {
assert_equals(beforeInputEvents.length, target ? 1 : 0,
"number of beforeinput events fired");
if (beforeInputEvents.length == 0) {
assert_equals(inputEvents.length, 0, "number of input events fired");
return;
}
var e = beforeInputEvents[0];
assert_equals(e.inputEventsLength, 0, "number of input events fired");
assert_equals(e.type, "beforeinput", "event.type");
assert_equals(e.target, target, "event.target");
assert_equals(e.currentTarget, div, "event.currentTarget");
assert_equals(e.eventPhase, Event.BUBBLING_PHASE, "event.eventPhase");
assert_equals(e.bubbles, true, "event.bubbles");
assert_equals(e.cancelable, true, "event.cancelable");
assert_equals(e.defaultPrevented, false, "event.defaultPrevented");
assert_equals(e.command, command, "e.command");
assert_equals(e.value, value, "e.value");
assert_own_property(window, "EditingBeforeInputEvent",
"window.EditingBeforeInputEvent must exist");
assert_equals(Object.getPrototypeOf(e.original),
EditingBeforeInputEvent.prototype,
"event prototype");
assert_true(originalContents.isEqualNode(div),
"div contents not yet changed");
assert_equals(e.isTrusted, true, "event.isTrusted");
}, obj.name + ": beforeinput event, " + (cancel ? "canceled" : "uncanceled"));
test(function() {
assert_equals(inputEvents.length, target && !cancel ? 1 : 0,
"number of input events fired");
if (!target || cancel) {
assert_true(originalContents.isEqualNode(div),
"div contents must not be changed");
return;
}
var e = inputEvents[0];
assert_equals(e.type, "input", "event.type");
assert_equals(e.target, finalTarget, "event.target");
assert_equals(e.currentTarget, div, "event.currentTarget");
assert_equals(e.eventPhase, Event.BUBBLING_PHASE, "event.eventPhase");
assert_equals(e.bubbles, true, "event.bubbles");
assert_equals(e.cancelable, false, "event.cancelable");
assert_equals(e.defaultPrevented, false, "event.defaultPrevented");
assert_equals(e.command, command, "e.command");
assert_equals(e.value, value, "e.value");
assert_own_property(window, "EditingInputEvent",
"window.EditingInputEvent must exist");
assert_equals(Object.getPrototypeOf(e.original),
EditingInputEvent.prototype,
"event prototype");
assert_equals(e.isTrusted, true, "event.isTrusted");
}, obj.name + ": input event, " + (cancel ? "canceled" : "uncanceled"));
});
});
// Thanks, Gecko.
document.body.bgColor = "";
</script>

Просмотреть файл

@ -0,0 +1,48 @@
<!doctype html>
<meta charset=utf-8>
<link rel=stylesheet href=../css/reset.css>
<title>HTML editing conformance tests</title>
<p>See the <a href=editing.html#tests>Tests</a> section of the specification
for documentation.
<p id=timing></p>
<div id=log></div>
<div id=test-container></div>
<script src=../implementation.js></script>
<script>var testsJsLibraryOnly = true</script>
<script src=../tests.js></script>
<script src=data.js></script>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
"use strict";
runTests();
function runTests() {
var startTime = Date.now();
// Make document.body.innerHTML more tidy by removing unnecessary things.
// We can't remove the testharness.js script, because at the time of this
// writing, for some reason that stops it from adding appropriate CSS.
[].forEach.call(document.querySelectorAll("script"), function(node) {
if (!/testharness\.js$/.test(node.src)) {
node.parentNode.removeChild(node);
}
});
browserTests.forEach(runConformanceTest);
document.getElementById("test-container").parentNode
.removeChild(document.getElementById("test-container"));
var elapsed = Math.round(Date.now() - startTime)/1000;
document.getElementById("timing").textContent =
"Time elapsed: " + Math.floor(elapsed/60) + ":"
+ ((elapsed % 60) < 10 ? "0" : "")
+ (elapsed % 60).toFixed(3) + " min.";
}
</script>

Просмотреть файл

@ -0,0 +1,24 @@
# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/editing/css
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
$(NULL)
_TESTS += \
reset.css \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,27 @@
/* Make sure various CSS values are what are expected, so that tests work
* right. */
body { font-family: serif }
/* http://www.w3.org/Bugs/Public/show_bug.cgi?id=12154
* https://bugzilla.mozilla.org/show_bug.cgi?id=589124
* https://bugs.webkit.org/show_bug.cgi?id=56400 */
b, strong { font-weight: bold }
.bold { font-weight: bold }
.notbold { font-weight: normal }
.underline { text-decoration: underline }
.line-through { text-decoration: line-through }
.underline-and-line-through { text-decoration: underline line-through }
#purple { color: purple }
/* https://bugs.webkit.org/show_bug.cgi?id=56670 */
dfn { font-style: italic }
/* Opera has weird default blockquote style */
blockquote { margin: 1em 40px }
/* Some tests assume links are blue, for the sake of argument, but they aren't
* blue in any browser. And :visited definitely isn't blue, except in engines
* like Gecko that lie.
*
* This should really be #00e, probably. See:
* http://www.w3.org/Bugs/Public/show_bug.cgi?id=13330 */
:link, :visited { color: blue }
/* http://www.w3.org/Bugs/Public/show_bug.cgi?id=14066
* https://bugs.webkit.org/show_bug.cgi?id=68392 */
quasit { text-align: inherit }

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,37 @@
# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/editing/selecttest
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_addRange.html \
test_collapse.html \
test_collapseToStartEnd.html \
test_deleteFromDocument.html \
test_Document-open.html \
test_extend.html \
test_getRangeAt.html \
test_getSelection.html \
test_interfaces.html \
test_isCollapsed.html \
test_removeAllRanges.html \
test_selectAllChildren.html \
$(NULL)
_TESTS += \
common.js \
test-iframe.html \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,952 @@
"use strict";
// TODO: iframes, contenteditable/designMode
// Everything is done in functions in this test harness, so we have to declare
// all the variables before use to make sure they can be reused.
var selection;
var testDiv, paras, detachedDiv, detachedPara1, detachedPara2,
foreignDoc, foreignPara1, foreignPara2, xmlDoc, xmlElement,
detachedXmlElement, detachedTextNode, foreignTextNode,
detachedForeignTextNode, xmlTextNode, detachedXmlTextNode,
processingInstruction, detachedProcessingInstruction, comment,
detachedComment, foreignComment, detachedForeignComment, xmlComment,
detachedXmlComment, docfrag, foreignDocfrag, xmlDocfrag, doctype,
foreignDoctype, xmlDoctype;
var testRanges, testPoints, testNodes;
function setupRangeTests() {
selection = getSelection();
testDiv = document.querySelector("#test");
if (testDiv) {
testDiv.parentNode.removeChild(testDiv);
}
testDiv = document.createElement("div");
testDiv.id = "test";
document.body.insertBefore(testDiv, document.body.firstChild);
// Test some diacritics, to make sure browsers are using code units here
// and not something like grapheme clusters.
testDiv.innerHTML = "<p id=a>A&#x308;b&#x308;c&#x308;d&#x308;e&#x308;f&#x308;g&#x308;h&#x308;\n"
+ "<p id=b style=display:none>Ijklmnop\n"
+ "<p id=c>Qrstuvwx"
+ "<p id=d style=display:none>Yzabcdef"
+ "<p id=e style=display:none>Ghijklmn";
paras = testDiv.querySelectorAll("p");
detachedDiv = document.createElement("div");
detachedPara1 = document.createElement("p");
detachedPara1.appendChild(document.createTextNode("Opqrstuv"));
detachedPara2 = document.createElement("p");
detachedPara2.appendChild(document.createTextNode("Wxyzabcd"));
detachedDiv.appendChild(detachedPara1);
detachedDiv.appendChild(detachedPara2);
// Opera doesn't automatically create a doctype for a new HTML document,
// contrary to spec. It also doesn't let you add doctypes to documents
// after the fact through any means I've tried. So foreignDoc in Opera
// will have no doctype, foreignDoctype will be null, and Opera will fail
// some tests somewhat mysteriously as a result.
foreignDoc = document.implementation.createHTMLDocument("");
foreignPara1 = foreignDoc.createElement("p");
foreignPara1.appendChild(foreignDoc.createTextNode("Efghijkl"));
foreignPara2 = foreignDoc.createElement("p");
foreignPara2.appendChild(foreignDoc.createTextNode("Mnopqrst"));
foreignDoc.body.appendChild(foreignPara1);
foreignDoc.body.appendChild(foreignPara2);
// Now we get to do really silly stuff, which nobody in the universe is
// ever going to actually do, but the spec defines behavior, so too bad.
// Testing is fun!
xmlDoctype = document.implementation.createDocumentType("qorflesnorf", "abcde", "x\"'y");
xmlDoc = document.implementation.createDocument(null, null, xmlDoctype);
detachedXmlElement = xmlDoc.createElement("everyone-hates-hyphenated-element-names");
detachedTextNode = document.createTextNode("Uvwxyzab");
detachedForeignTextNode = foreignDoc.createTextNode("Cdefghij");
detachedXmlTextNode = xmlDoc.createTextNode("Klmnopqr");
// PIs only exist in XML documents, so don't bother with document or
// foreignDoc.
detachedProcessingInstruction = xmlDoc.createProcessingInstruction("whippoorwill", "chirp chirp chirp");
detachedComment = document.createComment("Stuvwxyz");
// Hurrah, we finally got to "z" at the end!
detachedForeignComment = foreignDoc.createComment("אריה יהודה");
detachedXmlComment = xmlDoc.createComment("בן חיים אליעזר");
// We should also test with document fragments that actually contain stuff
// . . . but, maybe later.
docfrag = document.createDocumentFragment();
foreignDocfrag = foreignDoc.createDocumentFragment();
xmlDocfrag = xmlDoc.createDocumentFragment();
xmlElement = xmlDoc.createElement("igiveuponcreativenames");
xmlTextNode = xmlDoc.createTextNode("do re mi fa so la ti");
xmlElement.appendChild(xmlTextNode);
processingInstruction = xmlDoc.createProcessingInstruction("somePI", 'Did you know that ":syn sync fromstart" is very useful when using vim to edit large amounts of JavaScript embedded in HTML?');
xmlDoc.appendChild(xmlElement);
xmlDoc.appendChild(processingInstruction);
xmlComment = xmlDoc.createComment("I maliciously created a comment that will break incautious XML serializers, but Firefox threw an exception, so all I got was this lousy T-shirt");
xmlDoc.appendChild(xmlComment);
comment = document.createComment("Alphabet soup?");
testDiv.appendChild(comment);
foreignComment = foreignDoc.createComment('"Commenter" and "commentator" mean different things. I\'ve seen non-native speakers trip up on this.');
foreignDoc.appendChild(foreignComment);
foreignTextNode = foreignDoc.createTextNode("I admit that I harbor doubts about whether we really need so many things to test, but it's too late to stop now.");
foreignDoc.body.appendChild(foreignTextNode);
doctype = document.doctype;
foreignDoctype = foreignDoc.doctype;
testRanges = [
// Various ranges within the text node children of different
// paragraphs. All should be valid.
"[paras[0].firstChild, 0, paras[0].firstChild, 0]",
"[paras[0].firstChild, 0, paras[0].firstChild, 1]",
"[paras[0].firstChild, 2, paras[0].firstChild, 8]",
"[paras[0].firstChild, 2, paras[0].firstChild, 9]",
"[paras[1].firstChild, 0, paras[1].firstChild, 0]",
"[paras[1].firstChild, 0, paras[1].firstChild, 1]",
"[paras[1].firstChild, 2, paras[1].firstChild, 8]",
"[paras[1].firstChild, 2, paras[1].firstChild, 9]",
"[detachedPara1.firstChild, 0, detachedPara1.firstChild, 0]",
"[detachedPara1.firstChild, 0, detachedPara1.firstChild, 1]",
"[detachedPara1.firstChild, 2, detachedPara1.firstChild, 8]",
"[foreignPara1.firstChild, 0, foreignPara1.firstChild, 0]",
"[foreignPara1.firstChild, 0, foreignPara1.firstChild, 1]",
"[foreignPara1.firstChild, 2, foreignPara1.firstChild, 8]",
// Now try testing some elements, not just text nodes.
"[document.documentElement, 0, document.documentElement, 1]",
"[document.documentElement, 0, document.documentElement, 2]",
"[document.documentElement, 1, document.documentElement, 2]",
"[document.head, 1, document.head, 1]",
"[document.body, 0, document.body, 1]",
"[foreignDoc.documentElement, 0, foreignDoc.documentElement, 1]",
"[foreignDoc.head, 1, foreignDoc.head, 1]",
"[foreignDoc.body, 0, foreignDoc.body, 0]",
"[paras[0], 0, paras[0], 0]",
"[paras[0], 0, paras[0], 1]",
"[detachedPara1, 0, detachedPara1, 0]",
"[detachedPara1, 0, detachedPara1, 1]",
// Now try some ranges that span elements.
"[paras[0].firstChild, 0, paras[1].firstChild, 0]",
"[paras[0].firstChild, 0, paras[1].firstChild, 8]",
"[paras[0].firstChild, 3, paras[3], 1]",
// How about something that spans a node and its descendant?
"[paras[0], 0, paras[0].firstChild, 7]",
"[testDiv, 2, paras[4], 1]",
"[testDiv, 1, paras[2].firstChild, 5]",
"[document.documentElement, 1, document.body, 0]",
"[foreignDoc.documentElement, 1, foreignDoc.body, 0]",
// Then a few more interesting things just for good measure.
"[document, 0, document, 1]",
"[document, 0, document, 2]",
"[document, 1, document, 2]",
"[testDiv, 0, comment, 5]",
"[paras[2].firstChild, 4, comment, 2]",
"[paras[3], 1, comment, 8]",
"[foreignDoc, 0, foreignDoc, 0]",
"[foreignDoc, 1, foreignComment, 2]",
"[foreignDoc.body, 0, foreignTextNode, 36]",
"[xmlDoc, 0, xmlDoc, 0]",
// Opera 11 crashes if you extractContents() a range that ends at offset
// zero in a comment. Comment out this line to run the tests successfully.
"[xmlDoc, 1, xmlComment, 0]",
"[detachedTextNode, 0, detachedTextNode, 8]",
"[detachedForeignTextNode, 7, detachedForeignTextNode, 7]",
"[detachedForeignTextNode, 0, detachedForeignTextNode, 8]",
"[detachedXmlTextNode, 7, detachedXmlTextNode, 7]",
"[detachedXmlTextNode, 0, detachedXmlTextNode, 8]",
"[detachedComment, 3, detachedComment, 4]",
"[detachedComment, 5, detachedComment, 5]",
"[detachedForeignComment, 0, detachedForeignComment, 1]",
"[detachedForeignComment, 4, detachedForeignComment, 4]",
"[detachedXmlComment, 2, detachedXmlComment, 6]",
"[docfrag, 0, docfrag, 0]",
"[foreignDocfrag, 0, foreignDocfrag, 0]",
"[xmlDocfrag, 0, xmlDocfrag, 0]",
];
testPoints = [
// Various positions within the page, some invalid. Remember that
// paras[0] is visible, and paras[1] is display: none.
"[paras[0].firstChild, -1]",
"[paras[0].firstChild, 0]",
"[paras[0].firstChild, 1]",
"[paras[0].firstChild, 2]",
"[paras[0].firstChild, 8]",
"[paras[0].firstChild, 9]",
"[paras[0].firstChild, 10]",
"[paras[0].firstChild, 65535]",
"[paras[1].firstChild, -1]",
"[paras[1].firstChild, 0]",
"[paras[1].firstChild, 1]",
"[paras[1].firstChild, 2]",
"[paras[1].firstChild, 8]",
"[paras[1].firstChild, 9]",
"[paras[1].firstChild, 10]",
"[paras[1].firstChild, 65535]",
"[detachedPara1.firstChild, 0]",
"[detachedPara1.firstChild, 1]",
"[detachedPara1.firstChild, 8]",
"[detachedPara1.firstChild, 9]",
"[foreignPara1.firstChild, 0]",
"[foreignPara1.firstChild, 1]",
"[foreignPara1.firstChild, 8]",
"[foreignPara1.firstChild, 9]",
// Now try testing some elements, not just text nodes.
"[document.documentElement, -1]",
"[document.documentElement, 0]",
"[document.documentElement, 1]",
"[document.documentElement, 2]",
"[document.documentElement, 7]",
"[document.head, 1]",
"[document.body, 3]",
"[foreignDoc.documentElement, 0]",
"[foreignDoc.documentElement, 1]",
"[foreignDoc.head, 0]",
"[foreignDoc.body, 1]",
"[paras[0], 0]",
"[paras[0], 1]",
"[paras[0], 2]",
"[paras[1], 0]",
"[paras[1], 1]",
"[paras[1], 2]",
"[detachedPara1, 0]",
"[detachedPara1, 1]",
"[testDiv, 0]",
"[testDiv, 3]",
// Then a few more interesting things just for good measure.
"[document, -1]",
"[document, 0]",
"[document, 1]",
"[document, 2]",
"[document, 3]",
"[comment, -1]",
"[comment, 0]",
"[comment, 4]",
"[comment, 96]",
"[foreignDoc, 0]",
"[foreignDoc, 1]",
"[foreignComment, 2]",
"[foreignTextNode, 0]",
"[foreignTextNode, 36]",
"[xmlDoc, -1]",
"[xmlDoc, 0]",
"[xmlDoc, 1]",
"[xmlDoc, 5]",
"[xmlComment, 0]",
"[xmlComment, 4]",
"[processingInstruction, 0]",
"[processingInstruction, 5]",
"[processingInstruction, 9]",
"[detachedTextNode, 0]",
"[detachedTextNode, 8]",
"[detachedForeignTextNode, 0]",
"[detachedForeignTextNode, 8]",
"[detachedXmlTextNode, 0]",
"[detachedXmlTextNode, 8]",
"[detachedProcessingInstruction, 12]",
"[detachedComment, 3]",
"[detachedComment, 5]",
"[detachedForeignComment, 0]",
"[detachedForeignComment, 4]",
"[detachedXmlComment, 2]",
"[docfrag, 0]",
"[foreignDocfrag, 0]",
"[xmlDocfrag, 0]",
"[doctype, 0]",
"[doctype, -17]",
"[doctype, 1]",
"[foreignDoctype, 0]",
"[xmlDoctype, 0]",
];
testNodes = [
"paras[0]",
"paras[0].firstChild",
"paras[1]",
"paras[1].firstChild",
"foreignPara1",
"foreignPara1.firstChild",
"detachedPara1",
"detachedPara1.firstChild",
"detachedPara1",
"detachedPara1.firstChild",
"testDiv",
"document",
"detachedDiv",
"detachedPara2",
"foreignDoc",
"foreignPara2",
"xmlDoc",
"xmlElement",
"detachedXmlElement",
"detachedTextNode",
"foreignTextNode",
"detachedForeignTextNode",
"xmlTextNode",
"detachedXmlTextNode",
"processingInstruction",
"detachedProcessingInstruction",
"comment",
"detachedComment",
"foreignComment",
"detachedForeignComment",
"xmlComment",
"detachedXmlComment",
"docfrag",
"foreignDocfrag",
"xmlDocfrag",
"doctype",
"foreignDoctype",
"xmlDoctype",
];
}
if ("setup" in window) {
setup(setupRangeTests);
} else {
// Presumably we're running from within an iframe or something
setupRangeTests();
}
/**
* Return the length of a node as specified in DOM Range.
*/
function getNodeLength(node) {
if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
return 0;
}
if (node.nodeType == Node.TEXT_NODE || node.nodeType == Node.PROCESSING_INSTRUCTION_NODE || node.nodeType == Node.COMMENT_NODE) {
return node.length;
}
return node.childNodes.length;
}
/**
* Returns the furthest ancestor of a Node as defined by the spec.
*/
function furthestAncestor(node) {
var root = node;
while (root.parentNode != null) {
root = root.parentNode;
}
return root;
}
/**
* "The ancestor containers of a Node are the Node itself and all its
* ancestors."
*
* Is node1 an ancestor container of node2?
*/
function isAncestorContainer(node1, node2) {
return node1 == node2 ||
(node2.compareDocumentPosition(node1) & Node.DOCUMENT_POSITION_CONTAINS);
}
/**
* Returns the first Node that's after node in tree order, or null if node is
* the last Node.
*/
function nextNode(node) {
if (node.hasChildNodes()) {
return node.firstChild;
}
return nextNodeDescendants(node);
}
/**
* Returns the last Node that's before node in tree order, or null if node is
* the first Node.
*/
function previousNode(node) {
if (node.previousSibling) {
node = node.previousSibling;
while (node.hasChildNodes()) {
node = node.lastChild;
}
return node;
}
return node.parentNode;
}
/**
* Returns the next Node that's after node and all its descendants in tree
* order, or null if node is the last Node or an ancestor of it.
*/
function nextNodeDescendants(node) {
while (node && !node.nextSibling) {
node = node.parentNode;
}
if (!node) {
return null;
}
return node.nextSibling;
}
/**
* Returns the ownerDocument of the Node, or the Node itself if it's a
* Document.
*/
function ownerDocument(node) {
return node.nodeType == Node.DOCUMENT_NODE
? node
: node.ownerDocument;
}
/**
* Returns true if ancestor is an ancestor of descendant, false otherwise.
*/
function isAncestor(ancestor, descendant) {
if (!ancestor || !descendant) {
return false;
}
while (descendant && descendant != ancestor) {
descendant = descendant.parentNode;
}
return descendant == ancestor;
}
/**
* Returns true if descendant is a descendant of ancestor, false otherwise.
*/
function isDescendant(descendant, ancestor) {
return isAncestor(ancestor, descendant);
}
/**
* The position of two boundary points relative to one another, as defined by
* the spec.
*/
function getPosition(nodeA, offsetA, nodeB, offsetB) {
// "If node A is the same as node B, return equal if offset A equals offset
// B, before if offset A is less than offset B, and after if offset A is
// greater than offset B."
if (nodeA == nodeB) {
if (offsetA == offsetB) {
return "equal";
}
if (offsetA < offsetB) {
return "before";
}
if (offsetA > offsetB) {
return "after";
}
}
// "If node A is after node B in tree order, compute the position of (node
// B, offset B) relative to (node A, offset A). If it is before, return
// after. If it is after, return before."
if (nodeB.compareDocumentPosition(nodeA) & Node.DOCUMENT_POSITION_FOLLOWING) {
var pos = getPosition(nodeB, offsetB, nodeA, offsetA);
if (pos == "before") {
return "after";
}
if (pos == "after") {
return "before";
}
}
// "If node A is an ancestor of node B:"
if (nodeB.compareDocumentPosition(nodeA) & Node.DOCUMENT_POSITION_CONTAINS) {
// "Let child equal node B."
var child = nodeB;
// "While child is not a child of node A, set child to its parent."
while (child.parentNode != nodeA) {
child = child.parentNode;
}
// "If the index of child is less than offset A, return after."
if (indexOf(child) < offsetA) {
return "after";
}
}
// "Return before."
return "before";
}
/**
* "contained" as defined by DOM Range: "A Node node is contained in a range
* range if node's furthest ancestor is the same as range's root, and (node, 0)
* is after range's start, and (node, length of node) is before range's end."
*/
function isContained(node, range) {
var pos1 = getPosition(node, 0, range.startContainer, range.startOffset);
var pos2 = getPosition(node, getNodeLength(node), range.endContainer, range.endOffset);
return furthestAncestor(node) == furthestAncestor(range.startContainer)
&& pos1 == "after"
&& pos2 == "before";
}
/**
* "partially contained" as defined by DOM Range: "A Node is partially
* contained in a range if it is an ancestor container of the range's start but
* not its end, or vice versa."
*/
function isPartiallyContained(node, range) {
var cond1 = isAncestorContainer(node, range.startContainer);
var cond2 = isAncestorContainer(node, range.endContainer);
return (cond1 && !cond2) || (cond2 && !cond1);
}
/**
* Index of a node as defined by the spec.
*/
function indexOf(node) {
if (!node.parentNode) {
// No preceding sibling nodes, right?
return 0;
}
var i = 0;
while (node != node.parentNode.childNodes[i]) {
i++;
}
return i;
}
/**
* extractContents() implementation, following the spec. If an exception is
* supposed to be thrown, will return a string with the name (e.g.,
* "HIERARCHY_REQUEST_ERR") instead of a document fragment. It might also
* return an arbitrary human-readable string if a condition is hit that implies
* a spec bug.
*/
function myExtractContents(range) {
// "If the context object's detached flag is set, raise an
// INVALID_STATE_ERR exception and abort these steps."
try {
range.collapsed;
} catch (e) {
return "INVALID_STATE_ERR";
}
// "Let frag be a new DocumentFragment whose ownerDocument is the same as
// the ownerDocument of the context object's start node."
var ownerDoc = range.startContainer.nodeType == Node.DOCUMENT_NODE
? range.startContainer
: range.startContainer.ownerDocument;
var frag = ownerDoc.createDocumentFragment();
// "If the context object's start and end are the same, abort this method,
// returning frag."
if (range.startContainer == range.endContainer
&& range.startOffset == range.endOffset) {
return frag;
}
// "Let original start node, original start offset, original end node, and
// original end offset be the context object's start and end nodes and
// offsets, respectively."
var originalStartNode = range.startContainer;
var originalStartOffset = range.startOffset;
var originalEndNode = range.endContainer;
var originalEndOffset = range.endOffset;
// "If original start node and original end node are the same, and they are
// a Text or Comment node:"
if (range.startContainer == range.endContainer
&& (range.startContainer.nodeType == Node.TEXT_NODE
|| range.startContainer.nodeType == Node.COMMENT_NODE)) {
// "Let clone be the result of calling cloneNode(false) on original
// start node."
var clone = originalStartNode.cloneNode(false);
// "Set the data of clone to the result of calling
// substringData(original start offset, original end offset original
// start offset) on original start node."
clone.data = originalStartNode.substringData(originalStartOffset,
originalEndOffset - originalStartOffset);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Call deleteData(original start offset, original end offset
// original start offset) on original start node."
originalStartNode.deleteData(originalStartOffset,
originalEndOffset - originalStartOffset);
// "Abort this method, returning frag."
return frag;
}
// "Let common ancestor equal original start node."
var commonAncestor = originalStartNode;
// "While common ancestor is not an ancestor container of original end
// node, set common ancestor to its own parent."
while (!isAncestorContainer(commonAncestor, originalEndNode)) {
commonAncestor = commonAncestor.parentNode;
}
// "If original start node is an ancestor container of original end node,
// let first partially contained child be null."
var firstPartiallyContainedChild;
if (isAncestorContainer(originalStartNode, originalEndNode)) {
firstPartiallyContainedChild = null;
// "Otherwise, let first partially contained child be the first child of
// common ancestor that is partially contained in the context object."
} else {
for (var i = 0; i < commonAncestor.childNodes.length; i++) {
if (isPartiallyContained(commonAncestor.childNodes[i], range)) {
firstPartiallyContainedChild = commonAncestor.childNodes[i];
break;
}
}
if (!firstPartiallyContainedChild) {
throw "Spec bug: no first partially contained child!";
}
}
// "If original end node is an ancestor container of original start node,
// let last partially contained child be null."
var lastPartiallyContainedChild;
if (isAncestorContainer(originalEndNode, originalStartNode)) {
lastPartiallyContainedChild = null;
// "Otherwise, let last partially contained child be the last child of
// common ancestor that is partially contained in the context object."
} else {
for (var i = commonAncestor.childNodes.length - 1; i >= 0; i--) {
if (isPartiallyContained(commonAncestor.childNodes[i], range)) {
lastPartiallyContainedChild = commonAncestor.childNodes[i];
break;
}
}
if (!lastPartiallyContainedChild) {
throw "Spec bug: no last partially contained child!";
}
}
// "Let contained children be a list of all children of common ancestor
// that are contained in the context object, in tree order."
//
// "If any member of contained children is a DocumentType, raise a
// HIERARCHY_REQUEST_ERR exception and abort these steps."
var containedChildren = [];
for (var i = 0; i < commonAncestor.childNodes.length; i++) {
if (isContained(commonAncestor.childNodes[i], range)) {
if (commonAncestor.childNodes[i].nodeType
== Node.DOCUMENT_TYPE_NODE) {
return "HIERARCHY_REQUEST_ERR";
}
containedChildren.push(commonAncestor.childNodes[i]);
}
}
// "If original start node is an ancestor container of original end node,
// set new node to original start node and new offset to original start
// offset."
var newNode, newOffset;
if (isAncestorContainer(originalStartNode, originalEndNode)) {
newNode = originalStartNode;
newOffset = originalStartOffset;
// "Otherwise:"
} else {
// "Let reference node equal original start node."
var referenceNode = originalStartNode;
// "While reference node's parent is not null and is not an ancestor
// container of original end node, set reference node to its parent."
while (referenceNode.parentNode
&& !isAncestorContainer(referenceNode.parentNode, originalEndNode)) {
referenceNode = referenceNode.parentNode;
}
// "Set new node to the parent of reference node, and new offset to one
// plus the index of reference node."
newNode = referenceNode.parentNode;
newOffset = 1 + indexOf(referenceNode);
}
// "If first partially contained child is a Text or Comment node:"
if (firstPartiallyContainedChild
&& (firstPartiallyContainedChild.nodeType == Node.TEXT_NODE
|| firstPartiallyContainedChild.nodeType == Node.COMMENT_NODE)) {
// "Let clone be the result of calling cloneNode(false) on original
// start node."
var clone = originalStartNode.cloneNode(false);
// "Set the data of clone to the result of calling substringData() on
// original start node, with original start offset as the first
// argument and (length of original start node original start offset)
// as the second."
clone.data = originalStartNode.substringData(originalStartOffset,
getNodeLength(originalStartNode) - originalStartOffset);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Call deleteData() on original start node, with original start
// offset as the first argument and (length of original start node
// original start offset) as the second."
originalStartNode.deleteData(originalStartOffset,
getNodeLength(originalStartNode) - originalStartOffset);
// "Otherwise, if first partially contained child is not null:"
} else if (firstPartiallyContainedChild) {
// "Let clone be the result of calling cloneNode(false) on first
// partially contained child."
var clone = firstPartiallyContainedChild.cloneNode(false);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Let subrange be a new Range whose start is (original start node,
// original start offset) and whose end is (first partially contained
// child, length of first partially contained child)."
var subrange = ownerDoc.createRange();
subrange.setStart(originalStartNode, originalStartOffset);
subrange.setEnd(firstPartiallyContainedChild,
getNodeLength(firstPartiallyContainedChild));
// "Let subfrag be the result of calling extractContents() on
// subrange."
var subfrag = myExtractContents(subrange);
// "For each child of subfrag, in order, append that child to clone as
// its last child."
for (var i = 0; i < subfrag.childNodes.length; i++) {
clone.appendChild(subfrag.childNodes[i]);
}
}
// "For each contained child in contained children, append contained child
// as the last child of frag."
for (var i = 0; i < containedChildren.length; i++) {
frag.appendChild(containedChildren[i]);
}
// "If last partially contained child is a Text or Comment node:"
if (lastPartiallyContainedChild
&& (lastPartiallyContainedChild.nodeType == Node.TEXT_NODE
|| lastPartiallyContainedChild.nodeType == Node.COMMENT_NODE)) {
// "Let clone be the result of calling cloneNode(false) on original
// end node."
var clone = originalEndNode.cloneNode(false);
// "Set the data of clone to the result of calling substringData(0,
// original end offset) on original end node."
clone.data = originalEndNode.substringData(0, originalEndOffset);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Call deleteData(0, original end offset) on original end node."
originalEndNode.deleteData(0, originalEndOffset);
// "Otherwise, if last partially contained child is not null:"
} else if (lastPartiallyContainedChild) {
// "Let clone be the result of calling cloneNode(false) on last
// partially contained child."
var clone = lastPartiallyContainedChild.cloneNode(false);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Let subrange be a new Range whose start is (last partially
// contained child, 0) and whose end is (original end node, original
// end offset)."
var subrange = ownerDoc.createRange();
subrange.setStart(lastPartiallyContainedChild, 0);
subrange.setEnd(originalEndNode, originalEndOffset);
// "Let subfrag be the result of calling extractContents() on
// subrange."
var subfrag = myExtractContents(subrange);
// "For each child of subfrag, in order, append that child to clone as
// its last child."
for (var i = 0; i < subfrag.childNodes.length; i++) {
clone.appendChild(subfrag.childNodes[i]);
}
}
// "Set the context object's start and end to (new node, new offset)."
range.setStart(newNode, newOffset);
range.setEnd(newNode, newOffset);
// "Return frag."
return frag;
}
/**
* insertNode() implementation, following the spec. If an exception is
* supposed to be thrown, will return a string with the name (e.g.,
* "HIERARCHY_REQUEST_ERR") instead of a document fragment. It might also
* return an arbitrary human-readable string if a condition is hit that implies
* a spec bug.
*/
function myInsertNode(range, newNode) {
// "If the context object's detached flag is set, raise an
// INVALID_STATE_ERR exception and abort these steps."
//
// Assume that if accessing collapsed throws, it's detached.
try {
range.collapsed;
} catch (e) {
return "INVALID_STATE_ERR";
}
// "If the context object's start node is a Text or Comment node and its
// parent is null, raise an HIERARCHY_REQUEST_ERR exception and abort these
// steps."
if ((range.startContainer.nodeType == Node.TEXT_NODE
|| range.startContainer.nodeType == Node.COMMENT_NODE)
&& !range.startContainer.parentNode) {
return "HIERARCHY_REQUEST_ERR";
}
// "If the context object's start node is a Text node, run splitText() on
// it with the context object's start offset as its argument, and let
// reference node be the result."
var referenceNode;
if (range.startContainer.nodeType == Node.TEXT_NODE) {
// We aren't testing how ranges vary under mutations, and browsers vary
// in how they mutate for splitText, so let's just force the correct
// way.
var start = [range.startContainer, range.startOffset];
var end = [range.endContainer, range.endOffset];
referenceNode = range.startContainer.splitText(range.startOffset);
if (start[0] == end[0]
&& end[1] > start[1]) {
end[0] = referenceNode;
end[1] -= start[1];
} else if (end[0] == start[0].parentNode
&& end[1] > indexOf(referenceNode)) {
end[1]++;
}
range.setStart(start[0], start[1]);
range.setEnd(end[0], end[1]);
// "Otherwise, if the context object's start node is a Comment, let
// reference node be the context object's start node."
} else if (range.startContainer.nodeType == Node.COMMENT_NODE) {
referenceNode = range.startContainer;
// "Otherwise, let reference node be the child of the context object's
// start node with index equal to the context object's start offset, or
// null if there is no such child."
} else {
referenceNode = range.startContainer.childNodes[range.startOffset];
if (typeof referenceNode == "undefined") {
referenceNode = null;
}
}
// "If reference node is null, let parent node be the context object's
// start node."
var parentNode;
if (!referenceNode) {
parentNode = range.startContainer;
// "Otherwise, let parent node be the parent of reference node."
} else {
parentNode = referenceNode.parentNode;
}
// "Call insertBefore(newNode, reference node) on parent node, re-raising
// any exceptions that call raised."
try {
parentNode.insertBefore(newNode, referenceNode);
} catch (e) {
return getDomExceptionName(e);
}
}
/**
* Asserts that two nodes are equal, in the sense of isEqualNode(). If they
* aren't, tries to print a relatively informative reason why not. TODO: Move
* this to testharness.js?
*/
function assertNodesEqual(actual, expected, msg) {
if (!actual.isEqualNode(expected)) {
msg = "Actual and expected mismatch for " + msg + ". ";
while (actual && expected) {
assert_true(actual.nodeType === expected.nodeType
&& actual.nodeName === expected.nodeName
&& actual.nodeValue === expected.nodeValue
&& actual.childNodes.length === expected.childNodes.length,
"First differing node: expected " + format_value(expected)
+ ", got " + format_value(actual));
actual = nextNode(actual);
expected = nextNode(expected);
}
assert_unreached("DOMs were not equal but we couldn't figure out why");
}
}
/**
* Given a DOMException, return the name (e.g., "HIERARCHY_REQUEST_ERR"). In
* theory this should be just e.name, but in practice it's not. So I could
* legitimately just return e.name, but then every engine but WebKit would fail
* every test, since no one seems to care much for standardizing DOMExceptions.
* Instead I mangle it to account for browser bugs, so as not to fail
* insertNode() tests (for instance) for insertBefore() bugs. Of course, a
* standards-compliant browser will work right in any event.
*
* If the exception has no string property called "name" or "message", we just
* re-throw it.
*/
function getDomExceptionName(e) {
if (typeof e.name == "string"
&& /^[A-Z_]+_ERR$/.test(e.name)) {
// Either following the standard, or prefixing NS_ERROR_DOM (I'm
// looking at you, Gecko).
return e.name.replace(/^NS_ERROR_DOM_/, "");
}
if (typeof e.message == "string"
&& /^[A-Z_]+_ERR$/.test(e.message)) {
// Opera
return e.message;
}
if (typeof e.message == "string"
&& /^DOM Exception:/.test(e.message)) {
// IE
return /[A-Z_]+_ERR/.exec(e.message)[0];
}
throw e;
}
/**
* Given an array of endpoint data [start container, start offset, end
* container, end offset], returns a Range with those endpoints.
*/
function rangeFromEndpoints(endpoints) {
// If we just use document instead of the ownerDocument of endpoints[0],
// WebKit will throw on setStart/setEnd. This is a WebKit bug, but it's in
// range, not selection, so we don't want to fail anything for it.
var range = ownerDocument(endpoints[0]).createRange();
range.setStart(endpoints[0], endpoints[1]);
range.setEnd(endpoints[2], endpoints[3]);
return range;
}
/**
* Given an array of endpoint data [start container, start offset, end
* container, end offset], sets the selection to have those endpoints. Uses
* addRange, so the range will be forwards. Accepts an empty array for
* endpoints, in which case the selection will just be emptied.
*/
function setSelectionForwards(endpoints) {
selection.removeAllRanges();
if (endpoints.length) {
selection.addRange(rangeFromEndpoints(endpoints));
}
}
/**
* Given an array of endpoint data [start container, start offset, end
* container, end offset], sets the selection to have those endpoints, with the
* direction backwards. Uses extend, so it will throw in IE. Accepts an empty
* array for endpoints, in which case the selection will just be emptied.
*/
function setSelectionBackwards(endpoints) {
selection.removeAllRanges();
if (endpoints.length) {
selection.collapse(endpoints[2], endpoints[3]);
selection.extend(endpoints[0], endpoints[1]);
}
}

Просмотреть файл

@ -0,0 +1,33 @@
<!doctype html>
<title>Selection test iframe</title>
<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name>
<body>
<script src=common.js></script>
<script>
"use strict";
// This script only exists because we want to evaluate the range endpoints
// in each iframe using that iframe's local variables set up by common.js. It
// just creates a range with the endpoints given by
// eval(window.testRangeInput), and assigns the result to window.testRange. If
// there's an exception, it's assigned to window.unexpectedException.
// Everything else is to be done by the script that created the iframe.
window.unexpectedException = null;
function run() {
window.unexpectedException = null;
try {
window.testRange = rangeFromEndpoints(eval(window.testRangeInput));
} catch(e) {
window.unexpectedException = e;
}
}
// Remove the scripts so they don't run repeatedly when the iframe is
// reinitialized
[].forEach.call(document.querySelectorAll("script"), function(script) {
script.parentNode.removeChild(script);
});
testDiv.style.display = "none";
</script>

Просмотреть файл

@ -0,0 +1,44 @@
<!doctype html>
<title>Selection Document.open() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
"use strict";
// This tests the HTML spec requirement "Replace the Document's singleton
// objects with new instances of those objects. (This includes in particular
// the Window, Location, History, ApplicationCache, and Navigator, objects, the
// various BarProp objects, the two Storage objects, the various HTMLCollection
// objects, and objects defined by other specifications, like Selection and the
// document's UndoManager. It also includes all the Web IDL prototypes in the
// JavaScript binding, including the Document object's prototype.)" in the
// document.open() algorithm.
var iframe = document.createElement("iframe");
var t = async_test("Selection must be replaced with a new object after document.open()");
iframe.onload = function() {
t.step(function() {
var originalSelection = iframe.contentWindow.getSelection();
assert_equals(originalSelection.rangeCount, 0,
"Sanity check: rangeCount must be initially 0");
iframe.contentDocument.body.appendChild(
iframe.contentDocument.createTextNode("foo"));
var range = iframe.contentDocument.createRange();
range.selectNodeContents(iframe.contentDocument.body);
iframe.contentWindow.getSelection().addRange(range);
assert_equals(originalSelection.rangeCount, 1,
"Sanity check: rangeCount must be 1 after adding a range");
iframe.contentDocument.open();
assert_not_equals(iframe.contentWindow.getSelection(), originalSelection,
"After document.open(), the Selection object must no longer be the same");
assert_equals(iframe.contentWindow.getSelection().rangeCount, 0,
"After document.open(), rangeCount must be 0 again");
});
t.done();
document.body.removeChild(iframe);
};
document.body.appendChild(iframe);
</script>

Просмотреть файл

@ -0,0 +1,177 @@
<!doctype html>
<title>Selection.addRange() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
function testAddRange(exception, range, endpoints, qualifier, testName) {
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
selection.addRange(range);
assert_equals(range.startContainer, endpoints[0],
"addRange() must not modify the startContainer of the Range it's given");
assert_equals(range.startOffset, endpoints[1],
"addRange() must not modify the startOffset of the Range it's given");
assert_equals(range.endContainer, endpoints[2],
"addRange() must not modify the endContainer of the Range it's given");
assert_equals(range.endOffset, endpoints[3],
"addRange() must not modify the endOffset of the Range it's given");
}, testName + ": " + qualifier + " addRange() must not throw exceptions or modify the range it's given");
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_equals(selection.rangeCount, 1, "rangeCount must be 1");
}, testName + ": " + qualifier + " addRange() must result in rangeCount being 1");
// From here on out we check selection.getRangeAt(selection.rangeCount - 1)
// so as not to double-fail Gecko.
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
var newRange = selection.getRangeAt(selection.rangeCount - 1);
assert_not_equals(newRange, null,
"getRangeAt(rangeCount - 1) must not return null");
assert_equals(typeof newRange, "object",
"getRangeAt(rangeCount - 1) must return an object");
assert_equals(newRange.startContainer, range.startContainer,
"startContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.startOffset, range.startOffset,
"startOffset of the Selection's last Range must match the added Range");
assert_equals(newRange.endContainer, range.endContainer,
"endContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.endOffset, range.endOffset,
"endOffset of the Selection's last Range must match the added Range");
}, testName + ": " + qualifier + " addRange() must result in the selection's last range having the specified endpoints");
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
assert_equals(selection.getRangeAt(selection.rangeCount - 1), range,
"getRangeAt(rangeCount - 1) must return the same object we added");
}, testName + ": " + qualifier + " addRange() must result in the selection's last range being the same object we added");
// Let's not test many different modifications -- one should be enough.
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
if (range.startContainer == paras[0].firstChild
&& range.startOffset == 0
&& range.endContainer == paras[0].firstChild
&& range.endOffset == 2) {
// Just in case . . .
range.setStart(paras[0].firstChild, 1);
} else {
range.setStart(paras[0].firstChild, 0);
range.setEnd(paras[0].firstChild, 2);
}
var newRange = selection.getRangeAt(selection.rangeCount - 1);
assert_equals(newRange.startContainer, range.startContainer,
"After mutating the " + qualifier + " added Range, startContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.startOffset, range.startOffset,
"After mutating the " + qualifier + " added Range, startOffset of the Selection's last Range must match the added Range");
assert_equals(newRange.endContainer, range.endContainer,
"After mutating the " + qualifier + " added Range, endContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.endOffset, range.endOffset,
"After mutating the " + qualifier + " added Range, endOffset of the Selection's last Range must match the added Range");
}, testName + ": modifying the " + qualifier + " added range must modify the Selection's last Range");
// Now test the other way too.
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
var newRange = selection.getRangeAt(selection.rangeCount - 1);
if (newRange.startContainer == paras[0].firstChild
&& newRange.startOffset == 4
&& newRange.endContainer == paras[0].firstChild
&& newRange.endOffset == 6) {
newRange.setStart(paras[0].firstChild, 5);
} else {
newRange.setStart(paras[0].firstChild, 4);
newRange.setStart(paras[0].firstChild, 6);
}
assert_equals(newRange.startContainer, range.startContainer,
"After " + qualifier + " addRange(), after mutating the Selection's last Range, startContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.startOffset, range.startOffset,
"After " + qualifier + " addRange(), after mutating the Selection's last Range, startOffset of the Selection's last Range must match the added Range");
assert_equals(newRange.endContainer, range.endContainer,
"After " + qualifier + " addRange(), after mutating the Selection's last Range, endContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.endOffset, range.endOffset,
"After " + qualifier + " addRange(), after mutating the Selection's last Range, endOffset of the Selection's last Range must match the added Range");
}, testName + ": modifying the Selection's last Range must modify the " + qualifier + " added Range");
}
// Do only n evals, not n^2
var testRangesEvaled = testRanges.map(eval);
for (var i = 0; i < testRanges.length; i++) {
for (var j = 0; j < testRanges.length; j++) {
var testName = "Range " + i + " " + testRanges[i]
+ " followed by Range " + j + " " + testRanges[j];
var exception = null;
try {
selection.removeAllRanges();
var endpoints1 = testRangesEvaled[i];
var range1 = ownerDocument(endpoints1[0]).createRange();
range1.setStart(endpoints1[0], endpoints1[1]);
range1.setEnd(endpoints1[2], endpoints1[3]);
if (range1.startContainer !== endpoints1[0]) {
throw "Sanity check: the first Range we created must have the desired startContainer";
}
if (range1.startOffset !== endpoints1[1]) {
throw "Sanity check: the first Range we created must have the desired startOffset";
}
if (range1.endContainer !== endpoints1[2]) {
throw "Sanity check: the first Range we created must have the desired endContainer";
}
if (range1.endOffset !== endpoints1[3]) {
throw "Sanity check: the first Range we created must have the desired endOffset";
}
var endpoints2 = testRangesEvaled[j];
var range2 = ownerDocument(endpoints2[0]).createRange();
range2.setStart(endpoints2[0], endpoints2[1]);
range2.setEnd(endpoints2[2], endpoints2[3]);
if (range2.startContainer !== endpoints2[0]) {
throw "Sanity check: the second Range we created must have the desired startContainer";
}
if (range2.startOffset !== endpoints2[1]) {
throw "Sanity check: the second Range we created must have the desired startOffset";
}
if (range2.endContainer !== endpoints2[2]) {
throw "Sanity check: the second Range we created must have the desired endContainer";
}
if (range2.endOffset !== endpoints2[3]) {
throw "Sanity check: the second Range we created must have the desired endOffset";
}
} catch (e) {
exception = e;
}
testAddRange(exception, range1, endpoints1, "first", testName);
testAddRange(exception, range2, endpoints2, "second", testName);
}
}
testDiv.style.display = "none";
</script>

Просмотреть файл

@ -0,0 +1,87 @@
<!doctype html>
<title>Selection.collapse() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
function testCollapse(range, point) {
selection.removeAllRanges();
var addedRange;
if (range) {
addedRange = range.cloneRange();
selection.addRange(addedRange);
}
if (point[0].nodeType == Node.DOCUMENT_TYPE_NODE) {
assert_throws("INVALID_NODE_TYPE_ERR", function() {
selection.collapse(point[0], point[1]);
}, "Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType");
return;
}
if (point[1] < 0 || point[1] > getNodeLength(point[0])) {
assert_throws("INDEX_SIZE_ERR", function() {
selection.collapse(point[0], point[1]);
}, "Must throw INDEX_SIZE_ERR when collapse()ing if the offset is negative or greater than the node's length");
return;
}
selection.collapse(point[0], point[1]);
assert_equals(selection.rangeCount, 1,
"selection.rangeCount must equal 1 after collapse()");
assert_equals(selection.focusNode, point[0],
"focusNode must equal the node we collapse()d to");
assert_equals(selection.focusOffset, point[1],
"focusOffset must equal the offset we collapse()d to");
assert_equals(selection.focusNode, selection.anchorNode,
"focusNode and anchorNode must be equal after collapse()");
assert_equals(selection.focusOffset, selection.anchorOffset,
"focusOffset and anchorOffset must be equal after collapse()");
if (range) {
assert_equals(addedRange.startContainer, range.startContainer,
"collapse() must not change the startContainer of a preexisting Range");
assert_equals(addedRange.endContainer, range.endContainer,
"collapse() must not change the endContainer of a preexisting Range");
assert_equals(addedRange.startOffset, range.startOffset,
"collapse() must not change the startOffset of a preexisting Range");
assert_equals(addedRange.endOffset, range.endOffset,
"collapse() must not change the endOffset of a preexisting Range");
}
}
// Also test a selection with no ranges
testRanges.unshift("[]");
// Don't want to eval() each point a bazillion times
var testPointsCached = [];
for (var i = 0; i < testPoints.length; i++) {
testPointsCached.push(eval(testPoints[i]));
}
var tests = [];
for (var i = 0; i < testRanges.length; i++) {
var endpoints = eval(testRanges[i]);
var range;
test(function() {
if (endpoints.length) {
range = ownerDocument(endpoints[0]).createRange();
range.setStart(endpoints[0], endpoints[1]);
range.setEnd(endpoints[2], endpoints[3]);
} else {
// Empty selection
range = null;
}
}, "Set up range " + i + " " + testRanges[i]);
for (var j = 0; j < testPoints.length; j++) {
tests.push(["Range " + i + " " + testRanges[i] + ", point " + j + " " + testPoints[j], range, testPointsCached[j]]);
}
}
generate_tests(testCollapse, tests);
testDiv.style.display = "none";
</script>

Просмотреть файл

@ -0,0 +1,121 @@
<!doctype html>
<title>Selection.collapseTo(Start|End)() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
// Also test a selection with no ranges
testRanges.unshift("[]");
for (var i = 0; i < testRanges.length; i++) {
test(function() {
selection.removeAllRanges();
var endpoints = eval(testRanges[i]);
if (!endpoints.length) {
assert_throws("INVALID_STATE_ERR", function() {
selection.collapseToStart();
}, "Must throw InvalidStateErr if the selection's range is null");
return;
}
var addedRange = ownerDocument(endpoints[0]).createRange();
addedRange.setStart(endpoints[0], endpoints[1]);
addedRange.setEnd(endpoints[2], endpoints[3]);
selection.addRange(addedRange);
// We don't penalize browsers here for mishandling addRange() and
// adding a different range than we specified. They fail addRange()
// tests for that, and don't have to fail collapseToStart/End() tests
// too. They do fail if they throw unexpectedly, though. I also fail
// them if there's no range at all, because otherwise they could pass
// all tests if addRange() always does nothing and collapseToStart()
// always throws.
assert_equals(selection.rangeCount, 1,
"Sanity check: rangeCount must equal 1 after addRange()");
var expectedEndpoint = [
selection.getRangeAt(0).startContainer,
selection.getRangeAt(0).startOffset
];
selection.collapseToStart();
assert_equals(selection.rangeCount, 1,
"selection.rangeCount must equal 1");
assert_equals(selection.focusNode, expectedEndpoint[0],
"focusNode must equal the original start node");
assert_equals(selection.focusOffset, expectedEndpoint[1],
"focusOffset must equal the original start offset");
assert_equals(selection.anchorNode, expectedEndpoint[0],
"anchorNode must equal the original start node");
assert_equals(selection.anchorOffset, expectedEndpoint[1],
"anchorOffset must equal the original start offset");
assert_equals(addedRange.startContainer, endpoints[0],
"collapseToStart() must not change the startContainer of the selection's original range");
assert_equals(addedRange.startOffset, endpoints[1],
"collapseToStart() must not change the startOffset of the selection's original range");
assert_equals(addedRange.endContainer, endpoints[2],
"collapseToStart() must not change the endContainer of the selection's original range");
assert_equals(addedRange.endOffset, endpoints[3],
"collapseToStart() must not change the endOffset of the selection's original range");
}, "Range " + i + " " + testRanges[i] + " collapseToStart()");
// Copy-paste of above
test(function() {
selection.removeAllRanges();
var endpoints = eval(testRanges[i]);
if (!endpoints.length) {
assert_throws("INVALID_STATE_ERR", function() {
selection.collapseToEnd();
}, "Must throw InvalidStateErr if the selection's range is null");
return;
}
var addedRange = ownerDocument(endpoints[0]).createRange();
addedRange.setStart(endpoints[0], endpoints[1]);
addedRange.setEnd(endpoints[2], endpoints[3]);
selection.addRange(addedRange);
// We don't penalize browsers here for mishandling addRange() and
// adding a different range than we specified. They fail addRange()
// tests for that, and don't have to fail collapseToStart/End() tests
// too. They do fail if they throw unexpectedly, though. I also fail
// them if there's no range at all, because otherwise they could pass
// all tests if addRange() always does nothing and collapseToStart()
// always throws.
assert_equals(selection.rangeCount, 1,
"Sanity check: rangeCount must equal 1 after addRange()");
var expectedEndpoint = [
selection.getRangeAt(0).endContainer,
selection.getRangeAt(0).endOffset
];
selection.collapseToEnd();
assert_equals(selection.rangeCount, 1,
"selection.rangeCount must equal 1");
assert_equals(selection.focusNode, expectedEndpoint[0],
"focusNode must equal the original end node");
assert_equals(selection.focusOffset, expectedEndpoint[1],
"focusOffset must equal the original end offset");
assert_equals(selection.anchorNode, expectedEndpoint[0],
"anchorNode must equal the original end node");
assert_equals(selection.anchorOffset, expectedEndpoint[1],
"anchorOffset must equal the original end offset");
assert_equals(addedRange.startContainer, endpoints[0],
"collapseToEnd() must not change the startContainer of the selection's original range");
assert_equals(addedRange.startOffset, endpoints[1],
"collapseToEnd() must not change the startOffset of the selection's original range");
assert_equals(addedRange.endContainer, endpoints[2],
"collapseToEnd() must not change the endContainer of the selection's original range");
assert_equals(addedRange.endOffset, endpoints[3],
"collapseToEnd() must not change the endOffset of the selection's original range");
}, "Range " + i + " " + testRanges[i] + " collapseToEnd()");
}
testDiv.style.display = "none";
</script>

Просмотреть файл

@ -0,0 +1,97 @@
<!doctype html>
<title>Selection.deleteFromDocument() tests</title>
<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name>
<p>To debug test failures, add a query parameter with the test id (like
"?5"). Only that test will be run. Then you can look at the resulting
iframes in the DOM.
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
// We need to use explicit_done, because in Chrome 16 dev and Opera 12.00, the
// second iframe doesn't block the load event -- even though it is added before
// the load event.
setup({explicit_done: true});
// Specified by WebIDL
test(function() {
assert_equals(Selection.prototype.deleteFromDocument.length, 0,
"Selection.prototype.deleteFromDocument.length must equal 0");
}, "Selection.prototype.deleteFromDocument.length must equal 0");
testDiv.parentNode.removeChild(testDiv);
// Test an empty selection too
testRanges.unshift("empty");
var actualIframe = document.createElement("iframe");
var expectedIframe = document.createElement("iframe");
var referenceDoc = document.implementation.createHTMLDocument("");
referenceDoc.removeChild(referenceDoc.documentElement);
actualIframe.onload = function() {
expectedIframe.onload = function() {
for (var i = 0; i < testRanges.length; i++) {
if (location.search && i != Number(location.search)) {
continue;
}
test(function() {
initializeIframe(actualIframe, testRanges[i]);
initializeIframe(expectedIframe, testRanges[i]);
var actualRange = actualIframe.contentWindow.testRange;
var expectedRange = expectedIframe.contentWindow.testRange;
assert_equals(actualIframe.contentWindow.unexpectedException, null,
"Unexpected exception thrown when setting up Range for actual deleteFromDocument");
assert_equals(expectedIframe.contentWindow.unexpectedException, null,
"Unexpected exception thrown when setting up Range for simulated deleteFromDocument");
actualIframe.contentWindow.getSelection().removeAllRanges();
if (testRanges[i] != "empty") {
assert_equals(typeof actualRange, "object",
"Range produced in actual iframe must be an object");
assert_equals(typeof expectedRange, "object",
"Range produced in expected iframe must be an object");
assert_true(actualRange instanceof actualIframe.contentWindow.Range,
"Range produced in actual iframe must be instanceof Range");
assert_true(expectedRange instanceof expectedIframe.contentWindow.Range,
"Range produced in expected iframe must be instanceof Range");
actualIframe.contentWindow.getSelection().addRange(actualIframe.contentWindow.testRange);
expectedIframe.contentWindow.testRange.deleteContents();
}
actualIframe.contentWindow.getSelection().deleteFromDocument();
assertNodesEqual(actualIframe.contentDocument, expectedIframe.contentDocument, "DOM contents");
}, "Range " + i + ": " + testRanges[i]);
}
actualIframe.style.display = "none";
expectedIframe.style.display = "none";
done();
};
expectedIframe.src = "test-iframe.html";
document.body.appendChild(expectedIframe);
referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNode(true));
};
actualIframe.src = "test-iframe.html";
document.body.appendChild(actualIframe);
function initializeIframe(iframe, endpoints) {
while (iframe.contentDocument.firstChild) {
iframe.contentDocument.removeChild(iframe.contentDocument.lastChild);
}
iframe.contentDocument.appendChild(iframe.contentDocument.implementation.createDocumentType("html", "", ""));
iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true));
iframe.contentWindow.setupRangeTests();
if (endpoints != "empty") {
iframe.contentWindow.testRangeInput = endpoints;
iframe.contentWindow.run();
}
}
</script>

Просмотреть файл

@ -0,0 +1,148 @@
<!doctype html>
<title>Selection extend() tests</title>
<meta charset=utf-8>
<body>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<div id=log></div>
<script>
"use strict";
// Also test a selection with no ranges
testRanges.unshift("[]");
/**
* We test Selections that go both forwards and backwards here. In the latter
* case we need to use extend() to force it to go backwards, which is fair
* enough, since that's what we're testing. We test collapsed selections only
* once.
*/
for (var i = 0; i < testRanges.length; i++) {
var endpoints = eval(testRanges[i]);
for (var j = 0; j < testPoints.length; j++) {
if (endpoints[0] == endpoints[2]
&& endpoints[1] == endpoints[3]) {
// Test collapsed selections only once
test(function() {
setSelectionForwards(endpoints);
testExtend(endpoints, eval(testPoints[j]));
}, "extend() with range " + i + " " + testRanges[i]
+ " and point " + j + " " + testPoints[j]);
} else {
test(function() {
setSelectionForwards(endpoints);
testExtend(endpoints, eval(testPoints[j]));
}, "extend() forwards with range " + i + " " + testRanges[i]
+ " and point " + j + " " + testPoints[j]);
test(function() {
setSelectionBackwards(endpoints);
testExtend(endpoints, eval(testPoints[j]));
}, "extend() backwards with range " + i + " " + testRanges[i]
+ " and point " + j + " " + testPoints[j]);
}
}
}
function testExtend(endpoints, target) {
assert_equals(getSelection().rangeCount, endpoints.length/4,
"Sanity check: rangeCount must be correct");
var node = target[0];
var offset = target[1];
// "If the context object's range is null, throw an InvalidStateError
// exception and abort these steps."
if (getSelection().rangeCount == 0) {
assert_throws("INVALID_STATE_ERR", function() {
selection.extend(node, offset);
}, "extend() when rangeCount is 0 must throw InvalidStateError");
return;
}
assert_equals(getSelection().getRangeAt(0).startContainer, endpoints[0],
"Sanity check: startContainer must be correct");
assert_equals(getSelection().getRangeAt(0).startOffset, endpoints[1],
"Sanity check: startOffset must be correct");
assert_equals(getSelection().getRangeAt(0).endContainer, endpoints[2],
"Sanity check: endContainer must be correct");
assert_equals(getSelection().getRangeAt(0).endOffset, endpoints[3],
"Sanity check: endOffset must be correct");
// "Let anchor and focus be the context object's anchor and focus, and let
// new focus be the boundary point (node, offset)."
var anchorNode = getSelection().anchorNode;
var anchorOffset = getSelection().anchorOffset;
var focusNode = getSelection().focusNode;
var focusOffset = getSelection().focusOffset;
// "Let new range be a new range."
//
// We'll always be setting either new range's start or its end to new
// focus, so we'll always throw at some point. Test that now.
//
// From DOM4's "set the start or end of a range": "If node is a doctype,
// throw an "InvalidNodeTypeError" exception and terminate these steps."
if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
assert_throws("INVALID_NODE_TYPE_ERR", function() {
selection.extend(node, offset);
}, "extend() to a doctype must throw InvalidNodeTypeError");
return;
}
// From DOM4's "set the start or end of a range": "If offset is greater
// than node's length, throw an "IndexSizeError" exception and terminate
// these steps."
//
// FIXME: We should be casting offset to an unsigned int per WebIDL. Until
// we do, we need the offset < 0 check too.
if (offset < 0 || offset > getNodeLength(node)) {
assert_throws("INDEX_SIZE_ERR", function() {
selection.extend(node, offset);
}, "extend() to an offset that's greater than node length (" + getNodeLength(node) + ") must throw IndexSizeError");
return;
}
// Now back to the editing spec.
var originalRange = getSelection().getRangeAt(0);
// "If node's root is not the same as the context object's range's root,
// set new range's start and end to (node, offset)."
//
// "Otherwise, if anchor is before or equal to new focus, set new range's
// start to anchor, then set its end to new focus."
//
// "Otherwise, set new range's start to new focus, then set its end to
// anchor."
//
// "Set the context object's range to new range."
//
// "If new focus is before anchor, set the context object's direction to
// backwards. Otherwise, set it to forwards."
//
// The upshot of all these is summed up by just testing the anchor and
// offset.
getSelection().extend(node, offset);
if (furthestAncestor(anchorNode) == furthestAncestor(node)) {
assert_equals(getSelection().anchorNode, anchorNode,
"anchorNode must not change if the node passed to extend() has the same root as the original range");
assert_equals(getSelection().anchorOffset, anchorOffset,
"anchorOffset must not change if the node passed to extend() has the same root as the original range");
} else {
assert_equals(getSelection().anchorNode, node,
"anchorNode must be the node passed to extend() if it has a different root from the original range");
assert_equals(getSelection().anchorOffset, offset,
"anchorOffset must be the offset passed to extend() if the node has a different root from the original range");
}
assert_equals(getSelection().focusNode, node,
"focusNode must be the node passed to extend()");
assert_equals(getSelection().focusOffset, offset,
"focusOffset must be the offset passed to extend()");
assert_not_equals(getSelection().getRangeAt(0), originalRange,
"extend() must replace any existing range with a new one, not mutate the existing one");
}
testDiv.style.display = "none";
</script>

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<title>The getRangeAt method</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
test(function() {
var sel = getSelection();
var range = document.createRange();
sel.addRange(range);
assert_throws("INDEX_SIZE_ERR", function() { sel.getRangeAt(-1); })
assert_throws("INDEX_SIZE_ERR", function() { sel.getRangeAt(1); })
});
</script>

Просмотреть файл

@ -0,0 +1,160 @@
<!doctype html>
<title>getSelection() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
"use strict";
// TODO: Figure out more places where defaultView is or is not guaranteed to be
// null, and test whether getSelection() is null.
//
// TODO: Figure out a good way to test display: none iframes.
test(function() {
// Sanity checks like this are to flag known browser bugs with clearer
// error messages, instead of throwing inscrutable exceptions.
assert_true("Selection" in window,
"Sanity check: window must have Selection property");
assert_true(window.getSelection() instanceof Selection);
}, "window.getSelection() instanceof Selection");
test(function() {
assert_equals(window.getSelection(), window.getSelection());
}, "window.getSelection() === window.getSelection()");
test(function() {
assert_true("Selection" in window,
"Sanity check: window must have Selection property");
// This sanity check (which occurs a number of times below, too) is because
// document.getSelection() is supposed to return null if defaultView is
// null, so we need to figure out whether defaultView is null or not before
// we can make correct assertions about getSelection().
assert_not_equals(document.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_equals(typeof document.getSelection(), "object",
"document.getSelection() must be an object");
assert_true(document.getSelection() instanceof Selection);
}, "document.getSelection() instanceof Selection");
test(function() {
assert_not_equals(document.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_equals(document.getSelection(), document.getSelection());
}, "document.getSelection() === document.getSelection()");
test(function() {
assert_not_equals(document.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_equals(window.getSelection(), document.getSelection());
}, "window.getSelection() === document.getSelection()");
// "Each selection is associated with a single range, which may be null and is
// initially null."
//
// "The rangeCount attribute must return 0 if the context object's range is
// null, otherwise 1."
test(function() {
assert_equals(window.getSelection().rangeCount, 0,
"window.getSelection().rangeCount must initially be 0");
assert_equals(typeof document.getSelection(), "object",
"Sanity check: document.getSelection() must be an object");
assert_equals(document.getSelection().rangeCount, 0,
"document.getSelection().rangeCount must initially be 0");
}, "Selection's range must initially be null");
test(function() {
var doc = document.implementation.createHTMLDocument("");
assert_equals(doc.defaultView, null,
"Sanity check: defaultView of created HTML document must be null");
assert_equals(doc.getSelection(), null);
}, "getSelection() on HTML document with null defaultView must be null");
test(function() {
var xmlDoc = document.implementation.createDocument(null, "", null);
assert_true("getSelection" in xmlDoc, "XML document must have getSelection()");
assert_equals(xmlDoc.defaultView, null,
"Sanity check: defaultView of created XML document must be null");
assert_equals(xmlDoc.getSelection(), null);
}, "getSelection() on XML document with null defaultView must be null");
// Run a bunch of iframe tests, once immediately after the iframe is appended
// to the document and once onload. This makes a difference, because browsers
// differ (at the time of this writing) in whether they load about:blank in
// iframes synchronously or not. Per the HTML spec, there must be a browsing
// context associated with the iframe as soon as it's appended to the document,
// so there should be a selection too.
var iframe = document.createElement("iframe");
add_completion_callback(function() {
document.body.removeChild(iframe);
});
var testDescs = [];
var testFuncs = [];
testDescs.push("window.getSelection() instanceof Selection in an iframe");
testFuncs.push(function() {
assert_true("Selection" in iframe.contentWindow,
"Sanity check: window must have Selection property");
assert_not_equals(iframe.contentWindow.document.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_not_equals(iframe.contentWindow.getSelection(), null,
"window.getSelection() must not be null");
assert_true(iframe.contentWindow.getSelection() instanceof iframe.contentWindow.Selection);
});
testDescs.push("document.getSelection() instanceof Selection in an iframe");
testFuncs.push(function() {
assert_true("Selection" in iframe.contentWindow,
"Sanity check: window must have Selection property");
assert_not_equals(iframe.contentDocument.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_not_equals(iframe.contentDocument.getSelection(), null,
"document.getSelection() must not be null");
assert_equals(typeof iframe.contentDocument.getSelection(), "object",
"document.getSelection() must be an object");
assert_true(iframe.contentDocument.getSelection() instanceof iframe.contentWindow.Selection);
});
testDescs.push("window.getSelection() === document.getSelection() in an iframe");
testFuncs.push(function() {
assert_not_equals(iframe.contentDocument.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_equals(iframe.contentWindow.getSelection(), iframe.contentDocument.getSelection());
});
testDescs.push("getSelection() inside and outside iframe must return different objects");
testFuncs.push(function() {
assert_not_equals(iframe.contentWindow.getSelection(), getSelection());
});
testDescs.push("getSelection() on HTML document with null defaultView must be null inside an iframe");
testFuncs.push(function() {
var doc = iframe.contentDocument.implementation.createHTMLDocument("");
assert_equals(doc.defaultView, null,
"Sanity check: defaultView of created HTML document must be null");
assert_equals(doc.getSelection(), null);
});
var asyncTests = [];
testDescs.forEach(function(desc) {
asyncTests.push(async_test(desc + " onload"));
});
iframe.onload = function() {
asyncTests.forEach(function(t, i) {
t.step(testFuncs[i]);
t.done();
});
};
document.body.appendChild(iframe);
testDescs.forEach(function(desc, i) {
test(testFuncs[i], desc + " immediately after appendChild");
});
</script>

Просмотреть файл

@ -0,0 +1,41 @@
<!doctype html>
<title>Selection interface tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/WebIDLParser.js></script>
<script src=/resources/idlharness.js></script>
<script type=text/plain>
interface Selection {
readonly attribute Node? anchorNode;
readonly attribute unsigned long anchorOffset;
readonly attribute Node? focusNode;
readonly attribute unsigned long focusOffset;
readonly attribute boolean isCollapsed;
void collapse(Node node, unsigned long offset);
void collapseToStart();
void collapseToEnd();
void extend(Node node, unsigned long offset);
void selectAllChildren(Node node);
void deleteFromDocument();
readonly attribute unsigned long rangeCount;
Range getRangeAt(unsigned long index);
void addRange(Range range);
void removeRange(Range range);
void removeAllRanges();
stringifier;
};
</script>
<script>
"use strict";
var idlArray = new IdlArray();
idlArray.add_idls(document.querySelector("script[type=text\\/plain]").textContent);
idlArray.add_objects({Selection: ['getSelection()']});
idlArray.test();
</script>

Просмотреть файл

@ -0,0 +1,31 @@
<!doctype html>
<title>Selection.isCollapsed tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
test(function() {
selection.removeAllRanges();
assert_true(selection.isCollapsed, "isCollapsed must be true if both anchor and focus are null");
}, "Empty selection");
for (var i = 0; i < testRanges.length; i++) {
test(function() {
selection.removeAllRanges();
var endpoints = eval(testRanges[i]);
var range = ownerDocument(endpoints[0]).createRange();
range.setStart(endpoints[0], endpoints[1]);
range.setEnd(endpoints[2], endpoints[3]);
selection.addRange(range);
assert_equals(selection.isCollapsed,
endpoints[0] === endpoints[2] && endpoints[1] === endpoints[3],
"Value of isCollapsed");
}, "Range " + i + " " + testRanges[i]);
}
testDiv.style.display = "none";
</script>

Просмотреть файл

@ -0,0 +1,45 @@
<!doctype html>
<title>Selection.removeAllRanges() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
// Also test a selection with no ranges
testRanges.unshift("[]");
var range = rangeFromEndpoints([paras[0].firstChild, 0, paras[0].firstChild, 1]);
for (var i = 0; i < testRanges.length; i++) {
test(function() {
setSelectionForwards(eval(testRanges[i]));
selection.removeAllRanges();
assert_equals(selection.rangeCount, 0,
"After removeAllRanges(), rangeCount must be 0");
// Test that it's forwards
selection.addRange(range);
assert_equals(selection.anchorOffset, selection.getRangeAt(0).startOffset,
"After removeAllRanges(), addRange() must be forwards, so anchorOffset must equal startOffset rather than endOffset");
assert_equals(selection.focusOffset, selection.getRangeAt(0).endOffset,
"After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset");
}, "Range " + i + " " + testRanges[i] + " forwards");
// Copy-pasted from above
test(function() {
setSelectionBackwards(eval(testRanges[i]));
selection.removeAllRanges();
assert_equals(selection.rangeCount, 0,
"After removeAllRanges(), rangeCount must be 0");
// Test that it's forwards
selection.addRange(range);
assert_equals(selection.anchorOffset, selection.getRangeAt(0).startOffset,
"After removeAllRanges(), addRange() must be forwards, so anchorOffset must equal startOffset rather than endOffset");
assert_equals(selection.focusOffset, selection.getRangeAt(0).endOffset,
"After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset");
}, "Range " + i + " " + testRanges[i] + " backwards");
}
testDiv.style.display = "none";
</script>

Просмотреть файл

@ -0,0 +1,53 @@
<!doctype html>
<title>Selection.selectAllChildren tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
testRanges.unshift("[]");
for (var i = 0; i < testRanges.length; i++) {
var endpoints = eval(testRanges[i]);
for (var j = 0; j < testNodes.length; j++) {
var node = eval(testNodes[j]);
test(function() {
setSelectionForwards(endpoints);
var originalRange = getSelection().rangeCount
? getSelection().getRangeAt(0)
: null;
if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
assert_throws("INVALID_NODE_TYPE_ERR", function() {
selection.selectAllChildren(node);
}, "selectAllChildren() on a DocumentType must throw InvalidNodeTypeError");
return;
}
selection.selectAllChildren(node);
// This implicitly tests that the selection is forwards, by using
// anchorOffset/focusOffset instead of getRangeAt.
assert_equals(selection.rangeCount, 1,
"After selectAllChildren, rangeCount must be 1");
assert_equals(selection.anchorNode, node,
"After selectAllChildren, anchorNode must be the given node");
assert_equals(selection.anchorOffset, 0,
"After selectAllChildren, anchorOffset must be 0");
assert_equals(selection.focusNode, node,
"After selectAllChildren, focusNode must be the given node");
assert_equals(selection.focusOffset, node.childNodes.length,
"After selectAllChildren, focusOffset must be the given node's number of children");
if (originalRange) {
assert_not_equals(getSelection().getRangeAt(0), originalRange,
"selectAllChildren must replace any existing range, not mutate it");
}
}, "Range " + i + " " + testRanges[i] + ", node " + j + " " + testNodes[j]);
}
}
testDiv.style.display = "none";
</script>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,2 +0,0 @@
html
webapps

Просмотреть файл

@ -0,0 +1,20 @@
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/failures/editing/conformancetest
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_event.html.json \
test_runtest.html.json \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,310 @@
{
"Simple editable div: beforeinput event, canceled":true,
"Simple editable div: input event, canceled":true,
"Simple editable div: beforeinput event, uncanceled":true,
"Simple editable div: input event, uncanceled":true,
"Editable b: execCommand() must not throw, canceled":true,
"Editable b: beforeinput event, canceled":true,
"Editable b: input event, canceled":true,
"Editable b: execCommand() must not throw, uncanceled":true,
"Editable b: beforeinput event, uncanceled":true,
"Editable b: input event, uncanceled":true,
"No editable content: execCommand() must not throw, canceled":true,
"No editable content: execCommand() must not throw, uncanceled":true,
"Changing selection from handler: beforeinput event, canceled":true,
"Changing selection from handler: input event, canceled":true,
"Changing selection from handler: beforeinput event, uncanceled":true,
"Changing selection from handler: input event, uncanceled":true,
"Command backColor, value \"\": beforeinput event, canceled":true,
"Command backColor, value \"\": beforeinput event, uncanceled":true,
"Command backColor, value \"\": input event, uncanceled":true,
"Command backColor, value \"quasit\": beforeinput event, canceled":true,
"Command backColor, value \"quasit\": input event, canceled":true,
"Command backColor, value \"quasit\": beforeinput event, uncanceled":true,
"Command backColor, value \"quasit\": input event, uncanceled":true,
"Command backColor, value \"green\": beforeinput event, canceled":true,
"Command backColor, value \"green\": input event, canceled":true,
"Command backColor, value \"green\": beforeinput event, uncanceled":true,
"Command backColor, value \"green\": input event, uncanceled":true,
"Command createLink, value \"\": execCommand() must not throw, canceled":true,
"Command createLink, value \"\": beforeinput event, canceled":true,
"Command createLink, value \"\": execCommand() must not throw, uncanceled":true,
"Command createLink, value \"\": beforeinput event, uncanceled":true,
"Command createLink, value \"\": input event, uncanceled":true,
"Command createLink, value \"quasit\": beforeinput event, canceled":true,
"Command createLink, value \"quasit\": input event, canceled":true,
"Command createLink, value \"quasit\": beforeinput event, uncanceled":true,
"Command createLink, value \"quasit\": input event, uncanceled":true,
"Command createLink, value \"http://www.w3.org/community/editing/\": beforeinput event, canceled":true,
"Command createLink, value \"http://www.w3.org/community/editing/\": input event, canceled":true,
"Command createLink, value \"http://www.w3.org/community/editing/\": beforeinput event, uncanceled":true,
"Command createLink, value \"http://www.w3.org/community/editing/\": input event, uncanceled":true,
"Command fontName, value \"\": beforeinput event, canceled":true,
"Command fontName, value \"\": beforeinput event, uncanceled":true,
"Command fontName, value \"\": input event, uncanceled":true,
"Command fontName, value \"quasit\": beforeinput event, canceled":true,
"Command fontName, value \"quasit\": input event, canceled":true,
"Command fontName, value \"quasit\": beforeinput event, uncanceled":true,
"Command fontName, value \"quasit\": input event, uncanceled":true,
"Command fontName, value \"serif\": beforeinput event, canceled":true,
"Command fontName, value \"serif\": input event, canceled":true,
"Command fontName, value \"serif\": beforeinput event, uncanceled":true,
"Command fontName, value \"serif\": input event, uncanceled":true,
"Command fontName, value \"Helvetica\": beforeinput event, canceled":true,
"Command fontName, value \"Helvetica\": input event, canceled":true,
"Command fontName, value \"Helvetica\": beforeinput event, uncanceled":true,
"Command fontName, value \"Helvetica\": input event, uncanceled":true,
"Command fontSize, value \"\": beforeinput event, canceled":true,
"Command fontSize, value \"\": beforeinput event, uncanceled":true,
"Command fontSize, value \"\": input event, uncanceled":true,
"Command fontSize, value \"quasit\": beforeinput event, canceled":true,
"Command fontSize, value \"quasit\": beforeinput event, uncanceled":true,
"Command fontSize, value \"quasit\": input event, uncanceled":true,
"Command fontSize, value \"6\": beforeinput event, canceled":true,
"Command fontSize, value \"6\": input event, canceled":true,
"Command fontSize, value \"6\": beforeinput event, uncanceled":true,
"Command fontSize, value \"6\": input event, uncanceled":true,
"Command fontSize, value \"15px\": beforeinput event, canceled":true,
"Command fontSize, value \"15px\": input event, canceled":true,
"Command fontSize, value \"15px\": beforeinput event, uncanceled":true,
"Command fontSize, value \"15px\": input event, uncanceled":true,
"Command foreColor, value \"\": beforeinput event, canceled":true,
"Command foreColor, value \"\": beforeinput event, uncanceled":true,
"Command foreColor, value \"\": input event, uncanceled":true,
"Command foreColor, value \"quasit\": beforeinput event, canceled":true,
"Command foreColor, value \"quasit\": input event, canceled":true,
"Command foreColor, value \"quasit\": beforeinput event, uncanceled":true,
"Command foreColor, value \"quasit\": input event, uncanceled":true,
"Command foreColor, value \"green\": beforeinput event, canceled":true,
"Command foreColor, value \"green\": input event, canceled":true,
"Command foreColor, value \"green\": beforeinput event, uncanceled":true,
"Command foreColor, value \"green\": input event, uncanceled":true,
"Command hiliteColor, value \"\": beforeinput event, canceled":true,
"Command hiliteColor, value \"\": beforeinput event, uncanceled":true,
"Command hiliteColor, value \"\": input event, uncanceled":true,
"Command hiliteColor, value \"quasit\": beforeinput event, canceled":true,
"Command hiliteColor, value \"quasit\": input event, canceled":true,
"Command hiliteColor, value \"quasit\": beforeinput event, uncanceled":true,
"Command hiliteColor, value \"quasit\": input event, uncanceled":true,
"Command hiliteColor, value \"green\": beforeinput event, canceled":true,
"Command hiliteColor, value \"green\": input event, canceled":true,
"Command hiliteColor, value \"green\": beforeinput event, uncanceled":true,
"Command hiliteColor, value \"green\": input event, uncanceled":true,
"Command italic, value \"\": beforeinput event, canceled":true,
"Command italic, value \"\": input event, canceled":true,
"Command italic, value \"\": beforeinput event, uncanceled":true,
"Command italic, value \"\": input event, uncanceled":true,
"Command italic, value \"quasit\": beforeinput event, canceled":true,
"Command italic, value \"quasit\": input event, canceled":true,
"Command italic, value \"quasit\": beforeinput event, uncanceled":true,
"Command italic, value \"quasit\": input event, uncanceled":true,
"Command removeFormat, value \"\": beforeinput event, canceled":true,
"Command removeFormat, value \"\": input event, canceled":true,
"Command removeFormat, value \"\": beforeinput event, uncanceled":true,
"Command removeFormat, value \"\": input event, uncanceled":true,
"Command removeFormat, value \"quasit\": beforeinput event, canceled":true,
"Command removeFormat, value \"quasit\": input event, canceled":true,
"Command removeFormat, value \"quasit\": beforeinput event, uncanceled":true,
"Command removeFormat, value \"quasit\": input event, uncanceled":true,
"Command strikeThrough, value \"\": beforeinput event, canceled":true,
"Command strikeThrough, value \"\": input event, canceled":true,
"Command strikeThrough, value \"\": beforeinput event, uncanceled":true,
"Command strikeThrough, value \"\": input event, uncanceled":true,
"Command strikeThrough, value \"quasit\": beforeinput event, canceled":true,
"Command strikeThrough, value \"quasit\": input event, canceled":true,
"Command strikeThrough, value \"quasit\": beforeinput event, uncanceled":true,
"Command strikeThrough, value \"quasit\": input event, uncanceled":true,
"Command subscript, value \"\": beforeinput event, canceled":true,
"Command subscript, value \"\": input event, canceled":true,
"Command subscript, value \"\": beforeinput event, uncanceled":true,
"Command subscript, value \"\": input event, uncanceled":true,
"Command subscript, value \"quasit\": beforeinput event, canceled":true,
"Command subscript, value \"quasit\": input event, canceled":true,
"Command subscript, value \"quasit\": beforeinput event, uncanceled":true,
"Command subscript, value \"quasit\": input event, uncanceled":true,
"Command superscript, value \"\": beforeinput event, canceled":true,
"Command superscript, value \"\": input event, canceled":true,
"Command superscript, value \"\": beforeinput event, uncanceled":true,
"Command superscript, value \"\": input event, uncanceled":true,
"Command superscript, value \"quasit\": beforeinput event, canceled":true,
"Command superscript, value \"quasit\": input event, canceled":true,
"Command superscript, value \"quasit\": beforeinput event, uncanceled":true,
"Command superscript, value \"quasit\": input event, uncanceled":true,
"Command underline, value \"\": beforeinput event, canceled":true,
"Command underline, value \"\": input event, canceled":true,
"Command underline, value \"\": beforeinput event, uncanceled":true,
"Command underline, value \"\": input event, uncanceled":true,
"Command underline, value \"quasit\": beforeinput event, canceled":true,
"Command underline, value \"quasit\": input event, canceled":true,
"Command underline, value \"quasit\": beforeinput event, uncanceled":true,
"Command underline, value \"quasit\": input event, uncanceled":true,
"Command unlink, value \"\": beforeinput event, canceled":true,
"Command unlink, value \"\": beforeinput event, uncanceled":true,
"Command unlink, value \"\": input event, uncanceled":true,
"Command unlink, value \"quasit\": beforeinput event, canceled":true,
"Command unlink, value \"quasit\": beforeinput event, uncanceled":true,
"Command unlink, value \"quasit\": input event, uncanceled":true,
"Command delete, value \"\": beforeinput event, canceled":true,
"Command delete, value \"\": input event, canceled":true,
"Command delete, value \"\": beforeinput event, uncanceled":true,
"Command delete, value \"\": input event, uncanceled":true,
"Command delete, value \"quasit\": beforeinput event, canceled":true,
"Command delete, value \"quasit\": input event, canceled":true,
"Command delete, value \"quasit\": beforeinput event, uncanceled":true,
"Command delete, value \"quasit\": input event, uncanceled":true,
"Command formatBlock, value \"\": beforeinput event, canceled":true,
"Command formatBlock, value \"\": beforeinput event, uncanceled":true,
"Command formatBlock, value \"\": input event, uncanceled":true,
"Command formatBlock, value \"quasit\": beforeinput event, canceled":true,
"Command formatBlock, value \"quasit\": beforeinput event, uncanceled":true,
"Command formatBlock, value \"quasit\": input event, uncanceled":true,
"Command formatBlock, value \"p\": beforeinput event, canceled":true,
"Command formatBlock, value \"p\": input event, canceled":true,
"Command formatBlock, value \"p\": beforeinput event, uncanceled":true,
"Command formatBlock, value \"p\": input event, uncanceled":true,
"Command forwardDelete, value \"\": beforeinput event, canceled":true,
"Command forwardDelete, value \"\": beforeinput event, uncanceled":true,
"Command forwardDelete, value \"\": input event, uncanceled":true,
"Command forwardDelete, value \"quasit\": beforeinput event, canceled":true,
"Command forwardDelete, value \"quasit\": beforeinput event, uncanceled":true,
"Command forwardDelete, value \"quasit\": input event, uncanceled":true,
"Command indent, value \"\": beforeinput event, canceled":true,
"Command indent, value \"\": input event, canceled":true,
"Command indent, value \"\": beforeinput event, uncanceled":true,
"Command indent, value \"\": input event, uncanceled":true,
"Command indent, value \"quasit\": beforeinput event, canceled":true,
"Command indent, value \"quasit\": input event, canceled":true,
"Command indent, value \"quasit\": beforeinput event, uncanceled":true,
"Command indent, value \"quasit\": input event, uncanceled":true,
"Command insertHorizontalRule, value \"\": beforeinput event, canceled":true,
"Command insertHorizontalRule, value \"\": input event, canceled":true,
"Command insertHorizontalRule, value \"\": beforeinput event, uncanceled":true,
"Command insertHorizontalRule, value \"\": input event, uncanceled":true,
"Command insertHorizontalRule, value \"quasit\": beforeinput event, canceled":true,
"Command insertHorizontalRule, value \"quasit\": input event, canceled":true,
"Command insertHorizontalRule, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertHorizontalRule, value \"quasit\": input event, uncanceled":true,
"Command insertHorizontalRule, value \"id\": beforeinput event, canceled":true,
"Command insertHorizontalRule, value \"id\": input event, canceled":true,
"Command insertHorizontalRule, value \"id\": beforeinput event, uncanceled":true,
"Command insertHorizontalRule, value \"id\": input event, uncanceled":true,
"Command insertHTML, value \"\": execCommand() must not throw, canceled":true,
"Command insertHTML, value \"\": beforeinput event, canceled":true,
"Command insertHTML, value \"\": execCommand() must not throw, uncanceled":true,
"Command insertHTML, value \"\": beforeinput event, uncanceled":true,
"Command insertHTML, value \"\": input event, uncanceled":true,
"Command insertHTML, value \"quasit\": beforeinput event, canceled":true,
"Command insertHTML, value \"quasit\": input event, canceled":true,
"Command insertHTML, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertHTML, value \"quasit\": input event, uncanceled":true,
"Command insertHTML, value \"<b>hi</b>\": beforeinput event, canceled":true,
"Command insertHTML, value \"<b>hi</b>\": input event, canceled":true,
"Command insertHTML, value \"<b>hi</b>\": beforeinput event, uncanceled":true,
"Command insertHTML, value \"<b>hi</b>\": input event, uncanceled":true,
"Command insertImage, value \"\": execCommand() must not throw, canceled":true,
"Command insertImage, value \"\": beforeinput event, canceled":true,
"Command insertImage, value \"\": execCommand() must not throw, uncanceled":true,
"Command insertImage, value \"\": beforeinput event, uncanceled":true,
"Command insertImage, value \"\": input event, uncanceled":true,
"Command insertImage, value \"quasit\": beforeinput event, canceled":true,
"Command insertImage, value \"quasit\": input event, canceled":true,
"Command insertImage, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertImage, value \"quasit\": input event, uncanceled":true,
"Command insertImage, value \"http://example.com/some-image\": beforeinput event, canceled":true,
"Command insertImage, value \"http://example.com/some-image\": input event, canceled":true,
"Command insertImage, value \"http://example.com/some-image\": beforeinput event, uncanceled":true,
"Command insertImage, value \"http://example.com/some-image\": input event, uncanceled":true,
"Command insertLineBreak, value \"\": beforeinput event, canceled":true,
"Command insertLineBreak, value \"\": beforeinput event, uncanceled":true,
"Command insertLineBreak, value \"\": input event, uncanceled":true,
"Command insertLineBreak, value \"quasit\": beforeinput event, canceled":true,
"Command insertLineBreak, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertLineBreak, value \"quasit\": input event, uncanceled":true,
"Command insertOrderedList, value \"\": beforeinput event, canceled":true,
"Command insertOrderedList, value \"\": input event, canceled":true,
"Command insertOrderedList, value \"\": beforeinput event, uncanceled":true,
"Command insertOrderedList, value \"\": input event, uncanceled":true,
"Command insertOrderedList, value \"quasit\": beforeinput event, canceled":true,
"Command insertOrderedList, value \"quasit\": input event, canceled":true,
"Command insertOrderedList, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertOrderedList, value \"quasit\": input event, uncanceled":true,
"Command insertParagraph, value \"\": beforeinput event, canceled":true,
"Command insertParagraph, value \"\": input event, canceled":true,
"Command insertParagraph, value \"\": beforeinput event, uncanceled":true,
"Command insertParagraph, value \"\": input event, uncanceled":true,
"Command insertParagraph, value \"quasit\": beforeinput event, canceled":true,
"Command insertParagraph, value \"quasit\": input event, canceled":true,
"Command insertParagraph, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertParagraph, value \"quasit\": input event, uncanceled":true,
"Command insertText, value \"\": beforeinput event, canceled":true,
"Command insertText, value \"\": beforeinput event, uncanceled":true,
"Command insertText, value \"\": input event, uncanceled":true,
"Command insertText, value \"quasit\": beforeinput event, canceled":true,
"Command insertText, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertText, value \"quasit\": input event, uncanceled":true,
"Command insertText, value \"abc\": beforeinput event, canceled":true,
"Command insertText, value \"abc\": beforeinput event, uncanceled":true,
"Command insertText, value \"abc\": input event, uncanceled":true,
"Command insertUnorderedList, value \"\": beforeinput event, canceled":true,
"Command insertUnorderedList, value \"\": input event, canceled":true,
"Command insertUnorderedList, value \"\": beforeinput event, uncanceled":true,
"Command insertUnorderedList, value \"\": input event, uncanceled":true,
"Command insertUnorderedList, value \"quasit\": beforeinput event, canceled":true,
"Command insertUnorderedList, value \"quasit\": input event, canceled":true,
"Command insertUnorderedList, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertUnorderedList, value \"quasit\": input event, uncanceled":true,
"Command justifyCenter, value \"\": beforeinput event, canceled":true,
"Command justifyCenter, value \"\": input event, canceled":true,
"Command justifyCenter, value \"\": beforeinput event, uncanceled":true,
"Command justifyCenter, value \"\": input event, uncanceled":true,
"Command justifyCenter, value \"quasit\": beforeinput event, canceled":true,
"Command justifyCenter, value \"quasit\": input event, canceled":true,
"Command justifyCenter, value \"quasit\": beforeinput event, uncanceled":true,
"Command justifyCenter, value \"quasit\": input event, uncanceled":true,
"Command justifyFull, value \"\": beforeinput event, canceled":true,
"Command justifyFull, value \"\": input event, canceled":true,
"Command justifyFull, value \"\": beforeinput event, uncanceled":true,
"Command justifyFull, value \"\": input event, uncanceled":true,
"Command justifyFull, value \"quasit\": beforeinput event, canceled":true,
"Command justifyFull, value \"quasit\": input event, canceled":true,
"Command justifyFull, value \"quasit\": beforeinput event, uncanceled":true,
"Command justifyFull, value \"quasit\": input event, uncanceled":true,
"Command justifyLeft, value \"\": beforeinput event, canceled":true,
"Command justifyLeft, value \"\": input event, canceled":true,
"Command justifyLeft, value \"\": beforeinput event, uncanceled":true,
"Command justifyLeft, value \"\": input event, uncanceled":true,
"Command justifyLeft, value \"quasit\": beforeinput event, canceled":true,
"Command justifyLeft, value \"quasit\": input event, canceled":true,
"Command justifyLeft, value \"quasit\": beforeinput event, uncanceled":true,
"Command justifyLeft, value \"quasit\": input event, uncanceled":true,
"Command justifyRight, value \"\": beforeinput event, canceled":true,
"Command justifyRight, value \"\": input event, canceled":true,
"Command justifyRight, value \"\": beforeinput event, uncanceled":true,
"Command justifyRight, value \"\": input event, uncanceled":true,
"Command justifyRight, value \"quasit\": beforeinput event, canceled":true,
"Command justifyRight, value \"quasit\": input event, canceled":true,
"Command justifyRight, value \"quasit\": beforeinput event, uncanceled":true,
"Command justifyRight, value \"quasit\": input event, uncanceled":true,
"Command outdent, value \"\": beforeinput event, canceled":true,
"Command outdent, value \"\": beforeinput event, uncanceled":true,
"Command outdent, value \"\": input event, uncanceled":true,
"Command outdent, value \"quasit\": beforeinput event, canceled":true,
"Command outdent, value \"quasit\": beforeinput event, uncanceled":true,
"Command outdent, value \"quasit\": input event, uncanceled":true,
"Command redo, value \"\": beforeinput event, canceled":true,
"Command redo, value \"\": input event, canceled":true,
"Command redo, value \"\": beforeinput event, uncanceled":true,
"Command redo, value \"\": input event, uncanceled":true,
"Command redo, value \"quasit\": beforeinput event, canceled":true,
"Command redo, value \"quasit\": input event, canceled":true,
"Command redo, value \"quasit\": beforeinput event, uncanceled":true,
"Command redo, value \"quasit\": input event, uncanceled":true,
"Command undo, value \"\": beforeinput event, canceled":true,
"Command undo, value \"\": input event, canceled":true,
"Command undo, value \"\": beforeinput event, uncanceled":true,
"Command undo, value \"\": input event, uncanceled":true,
"Command undo, value \"quasit\": beforeinput event, canceled":true,
"Command undo, value \"quasit\": input event, canceled":true,
"Command undo, value \"quasit\": beforeinput event, uncanceled":true,
"Command undo, value \"quasit\": input event, uncanceled":true
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,22 @@
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/failures/editing/selecttest
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_addRange.html.json \
test_Document-open.html.json \
test_getSelection.html.json \
test_interfaces.html.json \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,3 @@
{
"Selection must be replaced with a new object after document.open()":true
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,7 @@
{
"getSelection() on HTML document with null defaultView must be null":true,
"getSelection() on XML document with null defaultView must be null":true,
"window.getSelection() instanceof Selection in an iframe immediately after appendChild":true,
"document.getSelection() instanceof Selection in an iframe immediately after appendChild":true,
"getSelection() on HTML document with null defaultView must be null inside an iframe onload":true
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"Selection interface: existence and properties of interface object":true,
"Selection interface: existence and properties of interface prototype object":true,
"Selection interface: existence and properties of interface prototype object's \"constructor\" property":true,
"Selection interface: calling collapse() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling extend() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling selectAllChildren() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling getRangeAt() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling addRange() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling removeRange() on getSelection() with too few arguments must throw TypeError":true
}

Просмотреть файл

@ -0,0 +1,20 @@
DEPTH = ../../../../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/failures/webapps/DOMCore/tests/submissions/Opera
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_getElementsByClassName-10.xml.json \
test_getElementsByClassName-11.xml.json \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,3 @@
{
"document.getElementsByClassName(): compound": true
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"document.getElementsByClassName(): \"tricky\" compound": true
}

Просмотреть файл

@ -0,0 +1,20 @@
DEPTH = ../../../../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/failures/webapps/WebStorage/tests/submissions/Infraware
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_event_constructor.html.json \
test_storage_local_security.html.json \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,3 @@
{
"storageeventinit test": true
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"storage local security test": true
}

Просмотреть файл

@ -0,0 +1,23 @@
DEPTH = ../../../../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/failures/webapps/WebStorage/tests/submissions/Ms2ger
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_event_constructor_js.html.json \
test_storage_local_in_js.html.json \
test_storage_local_removeitem_js.html.json \
test_storage_session_in_js.html.json \
test_storage_session_removeitem_js.html.json \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,3 @@
{
"StorageEvent constructor and nulls": true
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"Web Storage 1": true
}

Просмотреть файл

@ -0,0 +1,4 @@
{
"Web Storage 2": true,
"Web Storage 3": true
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"Web Storage 1": true
}

Просмотреть файл

@ -0,0 +1,4 @@
{
"Web Storage 2": true,
"Web Storage 3": true
}

Просмотреть файл

@ -1,2 +0,0 @@
{
}

Просмотреть файл

@ -55,8 +55,13 @@ def copy(thissrcdir, dest, directories):
dirtocreate = dest
subdirs, mochitests, supportfiles = parseManifestFile(dest, d)
sourcedir = "hg-%s/%s" % (dest, d)
destdir = "%s/%s" % (dest, d)
if d:
sourcedir = "hg-%s/%s" % (dest, d)
destdir = "%s/%s" % (dest, d)
else:
# Empty directory, i.e., the repository root
sourcedir = "hg-%s" % dest
destdir = dest
os.makedirs(destdir)
for mochitest in mochitests:
@ -65,7 +70,11 @@ def copy(thissrcdir, dest, directories):
shutil.copy("%s/%s" % (sourcedir, support), "%s/%s" % (destdir, support))
if len(subdirs):
importDirs(thissrcdir, dest, ["%s/%s" % (d, subdir) for subdir in subdirs])
if d:
importDirs(thissrcdir, dest, ["%s/%s" % (d, subdir) for subdir in subdirs])
else:
# Empty directory, i.e., the repository root
importDirs(thissrcdir, dest, subdirs)
def printMakefile(dest, directories):
"""Create a .mk file to be included into the main Makefile.in, which lists the
@ -116,7 +125,11 @@ def printMakefiles(thissrcdir, dest, directories):
"""
print "Creating Makefile.ins..."
for d in directories:
path = "%s/%s" % (dest, d)
if d:
path = "%s/%s" % (dest, d)
else:
# Empty directory, i.e., the repository root
path = dest
abspath = "%s/%s" % (thissrcdir, path)
print "Creating Makefile.in in %s..." % (path, )

Просмотреть файл

@ -9,10 +9,8 @@ var W3CTest = {
* names to either the boolean |true|, or the string "debug". The former
* means that this test is expected to fail in all builds, and the latter
* that it is only expected to fail in debug builds.
*
* This is filled in by the writeReporter.py script.
*/
"expectedFailures": ${expectations},
"expectedFailures": {},
/**
* List of test results, needed by TestRunner to update the UI.
@ -68,14 +66,11 @@ var W3CTest = {
/**
* Returns true if this test is expected to fail, and false otherwise.
*/
"_todo": function(url, test) {
if (!(url in this.expectedFailures)) {
return false;
}
if (this.expectedFailures[url] === "all") {
"_todo": function(test) {
if (this.expectedFailures === "all") {
return true;
}
var value = this.expectedFailures[url][test.name];
var value = this.expectedFailures[test.name];
return value === true || (value === "debug" && !!SpecialPowers.isDebugBuild);
},
@ -86,9 +81,9 @@ var W3CTest = {
"result": function(test) {
var url = this.getURL();
this.report({
"message": test.message || test.name,
"message": test.name + (test.message ? "; " + test.message : ""),
"result": test.status === test.PASS,
"todo": this._todo(url, test)
"todo": this._todo(test)
});
},
@ -99,7 +94,7 @@ var W3CTest = {
"finish": function(tests, status) {
var url = this.getURL();
this.report({
"message": "Finished test",
"message": "Finished test, status " + status.status,
"result": status.status === status.OK,
"todo":
url in this.expectedFailures &&
@ -112,9 +107,21 @@ var W3CTest = {
if (!W3CTest.runner) {
return;
}
// Get expected fails. If there aren't any, there will be a 404, which is
// fine. Anything else is unexpected.
var request = new XMLHttpRequest();
request.open("GET", "/tests/dom/imptests/failures/" + W3CTest.getURL() + ".json", false);
request.send();
if (request.status === 200) {
W3CTest.expectedFailures = JSON.parse(request.responseText);
} else if (request.status !== 404) {
is(request.status, 404, "Request status neither 200 nor 404");
}
add_result_callback(W3CTest.result.bind(W3CTest));
add_completion_callback(W3CTest.finish.bind(W3CTest));
setup({
"output": false
"output": false,
"timeout": 1000000,
});
})();

Просмотреть файл

@ -1,39 +0,0 @@
{
"webapps/DOMCore/tests/submissions/Opera/test_getElementsByClassName-10.xml": {
"document.getElementsByClassName(): compound": true
},
"webapps/DOMCore/tests/submissions/Opera/test_getElementsByClassName-11.xml": {
"document.getElementsByClassName(): \"tricky\" compound": true
},
"webapps/WebStorage/tests/submissions/Infraware/test_event_constructor.html": {
"storageeventinit test": true
},
"webapps/WebStorage/tests/submissions/Infraware/test_storage_local_security.html": {
"storage local security test": true
},
"webapps/WebStorage/tests/submissions/Ms2ger/test_event_constructor_js.html": {
"StorageEvent constructor and nulls": true
},
"webapps/WebStorage/tests/submissions/Ms2ger/test_storage_local_in_js.html": {
"Web Storage 1": true
},
"webapps/WebStorage/tests/submissions/Ms2ger/test_storage_local_removeitem_js.html": {
"Web Storage 2": true,
"Web Storage 3": true
},
"webapps/WebStorage/tests/submissions/Ms2ger/test_storage_session_in_js.html": {
"Web Storage 1": true
},
"webapps/WebStorage/tests/submissions/Ms2ger/test_storage_session_removeitem_js.html": {
"Web Storage 2": true,
"Web Storage 3": true
}
}

Просмотреть файл

@ -1,36 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import sys
import string
try:
import json
except ImportError:
import simplejson as json
def writeReporter(src):
src = src.replace("testharnessreport.js.in", "")
expectations = {}
fp = open(src + "failures.txt", "rb")
for line in fp:
gp = open(src + line.strip() + ".json")
expectations.update(json.load(gp))
gp.close()
fp.close()
fp = open(src + "testharnessreport.js.in", "rb")
template = fp.read()
fp.close()
fp = open("testharnessreport.js", "wb")
expjson = json.dumps(expectations,
indent = 2,
sort_keys = True,
separators = (',', ': '))
result = string.Template(template).substitute({ 'expectations': expjson })
fp.write(result)
fp.close()
if __name__ == "__main__":
writeReporter(sys.argv[1])

Просмотреть файл

@ -51,7 +51,7 @@
* http://www.w3.org/TR/DOM-Level-2-Style
*/
[builtinclass, scriptable, uuid(fc30df1b-9b5a-42f6-965b-cbcc67ac3c4c)]
[builtinclass, scriptable, uuid(81085b2d-eea9-4aca-ac93-0b1eea6587d3)]
interface nsIDOMCSS2Properties : nsISupports
{
attribute DOMString background;
@ -475,6 +475,9 @@ interface nsIDOMCSS2Properties : nsISupports
attribute DOMString textRendering;
// raises(DOMException) on setting
attribute DOMString vectorEffect;
// raises(DOMException) on setting
/* Non-DOM 2 extensions */
/* Mozilla extension CSS properties */

Просмотреть файл

@ -55,12 +55,13 @@ interface nsIEditActionListener;
interface nsIInlineSpellChecker;
interface nsITransferable;
[scriptable, uuid(7861fe14-9977-413f-a893-3e1000c40817)]
[scriptable, uuid(7ad59e28-f3d5-4e14-8ea3-794ad4a86de3)]
interface nsIEditor : nsISupports
{
%{C++
typedef short EDirection;
typedef short EStripWrappers;
%}
const short eNone = 0;
const short eNext = 1;
@ -70,6 +71,9 @@ interface nsIEditor : nsISupports
const short eToBeginningOfLine = 5;
const short eToEndOfLine = 6;
const short eStrip = 0;
const short eNoStrip = 1;
readonly attribute nsISelection selection;
/**
@ -146,8 +150,12 @@ interface nsIEditor : nsISupports
* DeleteSelection removes all nodes in the current selection.
* @param aDir if eNext, delete to the right (for example, the DEL key)
* if ePrevious, delete to the left (for example, the BACKSPACE key)
* @param stripWrappers If eStrip, strip any empty inline elements left
* behind after the deletion; if eNoStrip, don't. If in
* doubt, pass eStrip -- eNoStrip is only for if you're
* about to insert text or similar right after.
*/
void deleteSelection(in short action);
void deleteSelection(in short action, in short stripWrappers);
/* ------------ Document info and file methods -------------- */

Просмотреть файл

@ -7,6 +7,6 @@ load 430624-1.html
load 459613.html
load 475132-1.xhtml
load 633709.xhtml
asserts-if(!Android,6) load 636074-1.html # Bug 439258, charged to the wrong test due to bug 635550
load 636074-1.html
load 713427-1.html
load 713427-2.xhtml

Просмотреть файл

@ -616,9 +616,10 @@ nsEditor::GetSelectionController(nsISelectionController **aSel)
NS_IMETHODIMP
nsEditor::DeleteSelection(EDirection aAction)
nsEditor::DeleteSelection(EDirection aAction, EStripWrappers aStripWrappers)
{
return DeleteSelectionImpl(aAction);
MOZ_ASSERT(aStripWrappers == eStrip || aStripWrappers == eNoStrip);
return DeleteSelectionImpl(aAction, aStripWrappers);
}
@ -634,6 +635,23 @@ nsEditor::GetSelection(nsISelection **aSelection)
return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection); // does an addref
}
nsTypedSelection*
nsEditor::GetTypedSelection()
{
nsCOMPtr<nsISelection> sel;
nsresult res = GetSelection(getter_AddRefs(sel));
NS_ENSURE_SUCCESS(res, nsnull);
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(sel);
NS_ENSURE_TRUE(selPrivate, nsnull);
nsRefPtr<nsFrameSelection> frameSel;
res = selPrivate->GetFrameSelection(getter_AddRefs(frameSel));
NS_ENSURE_SUCCESS(res, nsnull);
return frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
}
NS_IMETHODIMP
nsEditor::DoTransaction(nsITransaction *aTxn)
{
@ -4313,8 +4331,11 @@ nsEditor::GetShouldTxnSetSelection()
NS_IMETHODIMP
nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
nsEditor::DeleteSelectionImpl(EDirection aAction,
EStripWrappers aStripWrappers)
{
MOZ_ASSERT(aStripWrappers == eStrip || aStripWrappers == eNoStrip);
nsCOMPtr<nsISelection>selection;
nsresult res = GetSelection(getter_AddRefs(selection));
NS_ENSURE_SUCCESS(res, res);
@ -4440,7 +4461,7 @@ nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSele
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
if (!selection->Collapsed()) {
result = DeleteSelection(nsIEditor::eNone);
result = DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
if (NS_FAILED(result)) {
return result;
}
@ -5099,7 +5120,7 @@ nsEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent)
nativeKeyEvent->IsMeta()) {
return NS_OK;
}
DeleteSelection(nsIEditor::ePrevious);
DeleteSelection(nsIEditor::ePrevious, nsIEditor::eStrip);
aKeyEvent->PreventDefault(); // consumed
return NS_OK;
case nsIDOMKeyEvent::DOM_VK_DELETE:
@ -5110,7 +5131,7 @@ nsEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent)
nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
return NS_OK;
}
DeleteSelection(nsIEditor::eNext);
DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
aKeyEvent->PreventDefault(); // consumed
return NS_OK;
}

Просмотреть файл

@ -50,6 +50,8 @@
#include "nsIAtom.h"
#include "nsIDOMDocument.h"
#include "nsISelection.h"
#include "nsRange.h"
#include "nsTypedSelection.h"
#include "nsIDOMCharacterData.h"
#include "nsIPrivateTextRange.h"
#include "nsITransactionManager.h"
@ -203,7 +205,8 @@ public:
nsIDOMCharacterData *aTextNode,
PRInt32 aOffset,
bool aSuppressIME = false);
NS_IMETHOD DeleteSelectionImpl(EDirection aAction);
NS_IMETHOD DeleteSelectionImpl(EDirection aAction,
EStripWrappers aStripWrappers);
NS_IMETHOD DeleteSelectionAndCreateNode(const nsAString& aTag,
nsIDOMNode ** aNewNode);
@ -620,6 +623,7 @@ public:
#if DEBUG_JOE
static void DumpNode(nsIDOMNode *aNode, PRInt32 indent=0);
#endif
nsTypedSelection* GetTypedSelection();
// Helpers to add a node to the selection.
// Used by table cell selection methods

Просмотреть файл

@ -282,7 +282,7 @@ nsCutOrDeleteCommand::DoCommand(const char *aCommandName,
nsCOMPtr<nsISelection> selection;
nsresult rv = editor->GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(rv) && selection && selection->Collapsed()) {
return editor->DeleteSelection(nsIEditor::eNext);
return editor->DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
}
return editor->Cut();
}
@ -376,7 +376,7 @@ nsCopyOrDeleteCommand::DoCommand(const char *aCommandName,
nsCOMPtr<nsISelection> selection;
nsresult rv = editor->GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(rv) && selection && selection->Collapsed()) {
return editor->DeleteSelection(nsIEditor::eNextWord);
return editor->DeleteSelection(nsIEditor::eNextWord, nsIEditor::eStrip);
}
return editor->Copy();
}
@ -619,7 +619,7 @@ nsDeleteCommand::DoCommand(const char *aCommandName, nsISupports *aCommandRefCon
else if (!nsCRT::strcmp("cmd_deleteToEndOfLine",aCommandName))
deleteDir = nsIEditor::eToEndOfLine;
return editor->DeleteSelection(deleteDir);
return editor->DeleteSelection(deleteDir, nsIEditor::eStrip);
}
NS_IMETHODIMP

Просмотреть файл

@ -122,7 +122,7 @@ nsresult TextEditorTest::InitDoc()
{
nsresult result = mEditor->SelectAll();
TEST_RESULT(result);
result = mEditor->DeleteSelection(nsIEditor::eNext);
result = mEditor->DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
TEST_RESULT(result);
return result;
}

Просмотреть файл

@ -245,6 +245,9 @@ nsHTMLEditor::DeleteRefToAnonymousNode(nsIDOMElement* aElement,
if (document)
docObserver->BeginUpdate(document, UPDATE_CONTENT_MODEL);
// XXX This is wrong (bug 439258). Once it's fixed, the NS_WARNING
// in nsCSSFrameConstructor::RestyleForRemove should be changed back
// to an assertion.
docObserver->ContentRemoved(content->GetCurrentDoc(),
aParentContent, content, -1,
content->GetPreviousSibling());

Просмотреть файл

@ -201,7 +201,7 @@ NS_IMETHODIMP nsHTMLEditor::LoadHTML(const nsAString & aInputString)
{
// Delete Selection, but only if it isn't collapsed, see bug #106269
if (!selection->Collapsed()) {
rv = DeleteSelection(eNone);
rv = DeleteSelection(eNone, eStrip);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -283,21 +283,20 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
nsAutoRules beginRulesSniffing(this, kOpHTMLPaste, nsIEditor::eNext);
// Get selection
nsCOMPtr<nsISelection>selection;
nsresult rv = GetSelection(getter_AddRefs(selection));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsTypedSelection> selection = GetTypedSelection();
NS_ENSURE_STATE(selection);
// create a dom document fragment that represents the structure to paste
nsCOMPtr<nsIDOMNode> fragmentAsNode, streamStartParent, streamEndParent;
PRInt32 streamStartOffset = 0, streamEndOffset = 0;
rv = CreateDOMFragmentFromPaste(aInputString, aContextStr, aInfoStr,
address_of(fragmentAsNode),
address_of(streamStartParent),
address_of(streamEndParent),
&streamStartOffset,
&streamEndOffset,
aTrustedInput);
nsresult rv = CreateDOMFragmentFromPaste(aInputString, aContextStr, aInfoStr,
address_of(fragmentAsNode),
address_of(streamStartParent),
address_of(streamEndParent),
&streamStartOffset,
&streamEndOffset,
aTrustedInput);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> targetNode, tempNode;
@ -346,7 +345,7 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
// Use an auto tracker so that our drop point is correctly
// positioned after the delete.
nsAutoTrackDOMPoint tracker(mRangeUpdater, &targetNode, &targetOffset);
rv = DeleteSelection(eNone);
rv = DeleteSelection(eNone, eStrip);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -400,7 +399,10 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
NS_ENSURE_SUCCESS(rv, rv);
// pasting does not inherit local inline styles
rv = RemoveAllInlineProperties();
nsCOMPtr<nsIDOMNode> tmpNode =
do_QueryInterface(selection->GetAnchorNode());
PRInt32 tmpOffset = selection->GetAnchorOffset();
rv = ClearStyle(address_of(tmpNode), &tmpOffset, nsnull, nsnull);
NS_ENSURE_SUCCESS(rv, rv);
}
else

Просмотреть файл

@ -109,6 +109,22 @@ static bool IsInlineNode(nsIDOMNode* node)
{
return !IsBlockNode(node);
}
static bool
IsStyleCachePreservingAction(nsEditor::OperationID action)
{
return action == nsEditor::kOpDeleteSelection ||
action == nsEditor::kOpInsertBreak ||
action == nsEditor::kOpMakeList ||
action == nsEditor::kOpIndent ||
action == nsEditor::kOpOutdent ||
action == nsEditor::kOpAlign ||
action == nsEditor::kOpMakeBasicBlock ||
action == nsEditor::kOpRemoveList ||
action == nsEditor::kOpMakeDefListItem ||
action == nsEditor::kOpInsertElement ||
action == nsEditor::kOpInsertQuotation;
}
class nsTableCellAndListItemFunctor : public nsBoolDomIterFunctor
{
@ -335,11 +351,10 @@ nsHTMLEditRules::BeforeEdit(nsEditor::OperationID action,
}
// remember current inline styles for deletion and normal insertion operations
if ((action == nsEditor::kOpInsertText) ||
(action == nsEditor::kOpInsertIMEText) ||
(action == nsEditor::kOpDeleteSelection) ||
(action == nsEditor::kOpInsertBreak))
{
if (action == nsEditor::kOpInsertText ||
action == nsEditor::kOpInsertIMEText ||
action == nsEditor::kOpDeleteSelection ||
IsStyleCachePreservingAction(action)) {
nsCOMPtr<nsIDOMNode> selNode = selStartNode;
if (aDirection == nsIEditor::eNext)
selNode = selEndNode;
@ -502,11 +517,10 @@ nsHTMLEditRules::AfterEditInner(nsEditor::OperationID action,
}
// check for any styles which were removed inappropriately
if ((action == nsEditor::kOpInsertText) ||
(action == nsEditor::kOpInsertIMEText) ||
(action == nsEditor::kOpDeleteSelection) ||
(action == nsEditor::kOpInsertBreak))
{
if (action == nsEditor::kOpInsertText ||
action == nsEditor::kOpInsertIMEText ||
action == nsEditor::kOpDeleteSelection ||
IsStyleCachePreservingAction(action)) {
mHTMLEditor->mTypeInState->UpdateSelState(selection);
res = ReapplyCachedStyles();
NS_ENSURE_SUCCESS(res, res);
@ -616,7 +630,8 @@ nsHTMLEditRules::WillDoAction(nsISelection *aSelection,
case nsEditor::kOpInsertBreak:
return WillInsertBreak(aSelection, aCancel, aHandled);
case nsEditor::kOpDeleteSelection:
return WillDeleteSelection(aSelection, info->collapsedAction, aCancel, aHandled);
return WillDeleteSelection(aSelection, info->collapsedAction,
info->stripWrappers, aCancel, aHandled);
case nsEditor::kOpMakeList:
return WillMakeList(aSelection, info->blockType, info->entireList, info->bulletType, aCancel, aHandled);
case nsEditor::kOpIndent:
@ -1256,21 +1271,22 @@ nsHTMLEditRules::WillInsert(nsISelection *aSelection, bool *aCancel)
}
}
// we need to get the doc
nsCOMPtr<nsIDOMDocument> doc = mHTMLEditor->GetDOMDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
// for every property that is set, insert a new inline style node
return CreateStyleForInsertText(aSelection, doc);
}
if (mDidDeleteSelection &&
(mTheAction == nsEditor::kOpInsertText ||
mTheAction == nsEditor::kOpInsertIMEText ||
mTheAction == nsEditor::kOpDeleteSelection)) {
res = ReapplyCachedStyles();
NS_ENSURE_SUCCESS(res, res);
}
// For most actions we want to clear the cached styles, but there are
// exceptions
if (!IsStyleCachePreservingAction(mTheAction)) {
res = ClearCachedStyles();
NS_ENSURE_SUCCESS(res, res);
}
#ifdef XXX_DEAD_CODE
nsresult
nsHTMLEditRules::DidInsert(nsISelection *aSelection, nsresult aResult)
{
return nsTextEditRules::DidInsert(aSelection, aResult);
}
#endif
return NS_OK;
}
nsresult
nsHTMLEditRules::WillInsertText(nsEditor::OperationID aAction,
@ -1303,7 +1319,7 @@ nsHTMLEditRules::WillInsertText(nsEditor::OperationID aAction,
// if the selection isn't collapsed, delete it.
if (!aSelection->Collapsed()) {
res = mHTMLEditor->DeleteSelection(nsIEditor::eNone);
res = mHTMLEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
NS_ENSURE_SUCCESS(res, res);
}
@ -1312,6 +1328,14 @@ nsHTMLEditRules::WillInsertText(nsEditor::OperationID aAction,
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = false;
// we need to get the doc
nsCOMPtr<nsIDOMDocument> doc = mHTMLEditor->GetDOMDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
// for every property that is set, insert a new inline style node
res = CreateStyleForInsertText(aSelection, doc);
NS_ENSURE_SUCCESS(res, res);
// get the (collapsed) selection location
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
@ -1322,10 +1346,6 @@ nsHTMLEditRules::WillInsertText(nsEditor::OperationID aAction,
!mHTMLEditor->CanContainTag(selNode, nsGkAtoms::textTagName)) {
return NS_ERROR_FAILURE;
}
// we need to get the doc
nsCOMPtr<nsIDOMDocument> doc = mHTMLEditor->GetDOMDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
if (aAction == nsEditor::kOpInsertIMEText) {
// Right now the nsWSRunObject code bails on empty strings, but IME needs
@ -1509,7 +1529,7 @@ nsHTMLEditRules::WillInsertBreak(nsISelection* aSelection,
// if the selection isn't collapsed, delete it.
nsresult res = NS_OK;
if (!aSelection->Collapsed()) {
res = mHTMLEditor->DeleteSelection(nsIEditor::eNone);
res = mHTMLEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
NS_ENSURE_SUCCESS(res, res);
}
@ -1814,11 +1834,14 @@ nsHTMLEditRules::SplitMailCites(nsISelection *aSelection, bool aPlaintext, bool
nsresult
nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
nsIEditor::EDirection aAction,
bool *aCancel,
bool *aHandled)
nsHTMLEditRules::WillDeleteSelection(nsISelection* aSelection,
nsIEditor::EDirection aAction,
nsIEditor::EStripWrappers aStripWrappers,
bool* aCancel,
bool* aHandled)
{
MOZ_ASSERT(aStripWrappers == nsIEditor::eStrip ||
aStripWrappers == nsIEditor::eNoStrip);
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
// initialize out param
@ -1977,7 +2000,8 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
{
res = mHTMLEditor->DeleteNode(visNode);
NS_ENSURE_SUCCESS(res, res);
return WillDeleteSelection(aSelection, aAction, aCancel, aHandled);
return WillDeleteSelection(aSelection, aAction, aStripWrappers,
aCancel, aHandled);
}
// special handling for backspace when positioned after <hr>
@ -2281,14 +2305,17 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
}
{
// track end location of where we are deleting
nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(endNode), &endOffset);
// track location of where we are deleting
nsAutoTrackDOMPoint startTracker(mHTMLEditor->mRangeUpdater,
address_of(startNode), &startOffset);
nsAutoTrackDOMPoint endTracker(mHTMLEditor->mRangeUpdater,
address_of(endNode), &endOffset);
// we are handling all ranged deletions directly now.
*aHandled = true;
if (endNode == startNode)
{
res = mHTMLEditor->DeleteSelectionImpl(aAction);
res = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers);
NS_ENSURE_SUCCESS(res, res);
}
else
@ -2328,7 +2355,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
// are endpoint block parents the same? use default deletion
if (leftParent == rightParent)
{
res = mHTMLEditor->DeleteSelectionImpl(aAction);
res = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers);
}
else
{
@ -2349,7 +2376,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
if (nsHTMLEditUtils::IsParagraph(leftParent))
{
// first delete the selection
res = mHTMLEditor->DeleteSelectionImpl(aAction);
res = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers);
NS_ENSURE_SUCCESS(res, res);
// then join para's, insert break
res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
@ -2362,7 +2389,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|| nsHTMLEditUtils::IsHeader(leftParent))
{
// first delete the selection
res = mHTMLEditor->DeleteSelectionImpl(aAction);
res = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers);
NS_ENSURE_SUCCESS(res, res);
// join blocks
res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
@ -2912,15 +2939,18 @@ nsHTMLEditRules::DidDeleteSelection(nsISelection *aSelection,
}
nsresult
nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
const nsAString *aListType,
nsHTMLEditRules::WillMakeList(nsISelection* aSelection,
const nsAString* aListType,
bool aEntireList,
const nsAString *aBulletType,
bool *aCancel,
bool *aHandled,
const nsAString *aItemType)
const nsAString* aBulletType,
bool* aCancel,
bool* aHandled,
const nsAString* aItemType)
{
if (!aSelection || !aListType || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
if (!aSelection || !aListType || !aCancel || !aHandled) {
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIAtom> listTypeAtom = do_GetAtom(*aListType);
nsresult res = WillInsert(aSelection, aCancel);
NS_ENSURE_SUCCESS(res, res);
@ -2932,160 +2962,148 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
// deduce what tag to use for list items
nsAutoString itemType;
if (aItemType)
if (aItemType) {
itemType = *aItemType;
else if (aListType->LowerCaseEqualsLiteral("dl"))
} else if (listTypeAtom == nsGkAtoms::dl) {
itemType.AssignLiteral("dd");
else
} else {
itemType.AssignLiteral("li");
}
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
*aHandled = true;
res = NormalizeSelection(aSelection);
NS_ENSURE_SUCCESS(res, res);
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
nsCOMArray<nsIDOMNode> arrayOfNodes;
res = GetListActionNodes(arrayOfNodes, aEntireList);
NS_ENSURE_SUCCESS(res, res);
PRInt32 listCount = arrayOfNodes.Count();
// check if all our nodes are <br>s, or empty inlines
bool bOnlyBreaks = true;
PRInt32 j;
for (j=0; j<listCount; j++)
{
for (PRInt32 j = 0; j < listCount; j++) {
nsIDOMNode* curNode = arrayOfNodes[j];
// if curNode is not a Break or empty inline, we're done
if ( (!nsTextEditUtils::IsBreak(curNode)) && (!IsEmptyInline(curNode)) )
{
if (!nsTextEditUtils::IsBreak(curNode) && !IsEmptyInline(curNode)) {
bOnlyBreaks = false;
break;
}
}
// if no nodes, we make empty list. Ditto if the user tried to make a list of some # of breaks.
if (!listCount || bOnlyBreaks)
{
// if no nodes, we make empty list. Ditto if the user tried to make a list
// of some # of breaks.
if (!listCount || bOnlyBreaks) {
nsCOMPtr<nsIDOMNode> parent, theList, theListItem;
PRInt32 offset;
// if only breaks, delete them
if (bOnlyBreaks)
{
for (j=0; j<(PRInt32)listCount; j++)
{
if (bOnlyBreaks) {
for (PRInt32 j = 0; j < (PRInt32)listCount; j++) {
res = mHTMLEditor->DeleteNode(arrayOfNodes[j]);
NS_ENSURE_SUCCESS(res, res);
}
}
// get selection location
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
res = mHTMLEditor->GetStartNodeAndOffset(aSelection,
getter_AddRefs(parent), &offset);
NS_ENSURE_SUCCESS(res, res);
// make sure we can put a list here
nsCOMPtr<nsIAtom> listTypeAtom = do_GetAtom(*aListType);
if (!mHTMLEditor->CanContainTag(parent, listTypeAtom)) {
*aCancel = true;
return NS_OK;
}
res = SplitAsNeeded(aListType, address_of(parent), &offset);
NS_ENSURE_SUCCESS(res, res);
res = mHTMLEditor->CreateNode(*aListType, parent, offset, getter_AddRefs(theList));
res = mHTMLEditor->CreateNode(*aListType, parent, offset,
getter_AddRefs(theList));
NS_ENSURE_SUCCESS(res, res);
res = mHTMLEditor->CreateNode(itemType, theList, 0, getter_AddRefs(theListItem));
res = mHTMLEditor->CreateNode(itemType, theList, 0,
getter_AddRefs(theListItem));
NS_ENSURE_SUCCESS(res, res);
// remember our new block for postprocessing
mNewBlock = theListItem;
// put selection in new list item
res = aSelection->Collapse(theListItem,0);
selectionResetter.Abort(); // to prevent selection reseter from overriding us.
res = aSelection->Collapse(theListItem, 0);
// to prevent selection resetter from overriding us
selectionResetter.Abort();
*aHandled = true;
return res;
}
// if there is only one node in the array, and it is a list, div, or blockquote,
// then look inside of it until we find inner list or content.
// if there is only one node in the array, and it is a list, div, or
// blockquote, then look inside of it until we find inner list or content.
res = LookInsideDivBQandList(arrayOfNodes);
NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_SUCCESS(res, res);
// Ok, now go through all the nodes and put then in the list,
// Ok, now go through all the nodes and put then in the list,
// or whatever is approriate. Wohoo!
listCount = arrayOfNodes.Count();
nsCOMPtr<nsIDOMNode> curParent;
nsCOMPtr<nsIDOMNode> curList;
nsCOMPtr<nsIDOMNode> prevListItem;
PRInt32 i;
for (i=0; i<listCount; i++)
{
for (PRInt32 i = 0; i < listCount; i++) {
// here's where we actually figure out what to do
nsCOMPtr<nsIDOMNode> newBlock;
nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
NS_ENSURE_SUCCESS(res, res);
// make sure we don't assemble content that is in different table cells into the same list.
// respect table cell boundaries when listifying.
if (curList)
{
// make sure we don't assemble content that is in different table cells
// into the same list. respect table cell boundaries when listifying.
if (curList) {
bool bInDifTblElems;
res = InDifferentTableElements(curList, curNode, &bInDifTblElems);
NS_ENSURE_SUCCESS(res, res);
if (bInDifTblElems)
if (bInDifTblElems) {
curList = nsnull;
}
}
// if curNode is a Break, delete it, and quit remembering prev list item
if (nsTextEditUtils::IsBreak(curNode))
{
if (nsTextEditUtils::IsBreak(curNode)) {
res = mHTMLEditor->DeleteNode(curNode);
NS_ENSURE_SUCCESS(res, res);
prevListItem = 0;
continue;
}
// if curNode is an empty inline container, delete it
else if (IsEmptyInline(curNode))
{
} else if (IsEmptyInline(curNode)) {
// if curNode is an empty inline container, delete it
res = mHTMLEditor->DeleteNode(curNode);
NS_ENSURE_SUCCESS(res, res);
continue;
}
if (nsHTMLEditUtils::IsList(curNode))
{
nsAutoString existingListStr;
res = mHTMLEditor->GetTagString(curNode, existingListStr);
ToLowerCase(existingListStr);
if (nsHTMLEditUtils::IsList(curNode)) {
// do we have a curList already?
if (curList && !nsEditorUtils::IsDescendantOf(curNode, curList))
{
// move all of our children into curList.
// cheezy way to do it: move whole list and then
// RemoveContainer() on the list.
// ConvertListType first: that routine
// handles converting the list item types, if needed
if (curList && !nsEditorUtils::IsDescendantOf(curNode, curList)) {
// move all of our children into curList. cheezy way to do it: move
// whole list and then RemoveContainer() on the list. ConvertListType
// first: that routine handles converting the list item types, if
// needed
res = mHTMLEditor->MoveNode(curNode, curList, -1);
NS_ENSURE_SUCCESS(res, res);
res = ConvertListType(curNode, address_of(newBlock), *aListType, itemType);
res = ConvertListType(curNode, address_of(newBlock),
*aListType, itemType);
NS_ENSURE_SUCCESS(res, res);
res = mHTMLEditor->RemoveBlockContainer(newBlock);
NS_ENSURE_SUCCESS(res, res);
}
else
{
} else {
// replace list with new list type
res = ConvertListType(curNode, address_of(newBlock), *aListType, itemType);
res = ConvertListType(curNode, address_of(newBlock),
*aListType, itemType);
NS_ENSURE_SUCCESS(res, res);
curList = newBlock;
}
@ -3093,55 +3111,45 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
continue;
}
if (nsHTMLEditUtils::IsListItem(curNode))
{
nsAutoString existingListStr;
res = mHTMLEditor->GetTagString(curParent, existingListStr);
ToLowerCase(existingListStr);
if ( existingListStr != *aListType )
{
// list item is in wrong type of list.
// if we don't have a curList, split the old list
// and make a new list of correct type.
if (!curList || nsEditorUtils::IsDescendantOf(curNode, curList))
{
res = mHTMLEditor->SplitNode(curParent, offset, getter_AddRefs(newBlock));
if (nsHTMLEditUtils::IsListItem(curNode)) {
if (mHTMLEditor->GetTag(curParent) != listTypeAtom) {
// list item is in wrong type of list. if we don't have a curList,
// split the old list and make a new list of correct type.
if (!curList || nsEditorUtils::IsDescendantOf(curNode, curList)) {
res = mHTMLEditor->SplitNode(curParent, offset,
getter_AddRefs(newBlock));
NS_ENSURE_SUCCESS(res, res);
nsCOMPtr<nsIDOMNode> p;
PRInt32 o;
res = nsEditor::GetNodeLocation(curParent, address_of(p), &o);
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = nsEditor::GetNodeLocation(curParent, address_of(parent),
&offset);
NS_ENSURE_SUCCESS(res, res);
res = mHTMLEditor->CreateNode(*aListType, p, o, getter_AddRefs(curList));
res = mHTMLEditor->CreateNode(*aListType, parent, offset,
getter_AddRefs(curList));
NS_ENSURE_SUCCESS(res, res);
}
// move list item to new list
res = mHTMLEditor->MoveNode(curNode, curList, -1);
NS_ENSURE_SUCCESS(res, res);
// convert list item type if needed
if (!mHTMLEditor->NodeIsTypeString(curNode,itemType))
{
res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), itemType);
if (!mHTMLEditor->NodeIsTypeString(curNode, itemType)) {
res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock),
itemType);
NS_ENSURE_SUCCESS(res, res);
}
}
else
{
} else {
// item is in right type of list. But we might still have to move it.
// and we might need to convert list item types.
if (!curList)
if (!curList) {
curList = curParent;
else
{
if (curParent != curList)
{
// move list item to new list
res = mHTMLEditor->MoveNode(curNode, curList, -1);
NS_ENSURE_SUCCESS(res, res);
}
} else if (curParent != curList) {
// move list item to new list
res = mHTMLEditor->MoveNode(curNode, curList, -1);
NS_ENSURE_SUCCESS(res, res);
}
if (!mHTMLEditor->NodeIsTypeString(curNode,itemType))
{
res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), itemType);
if (!mHTMLEditor->NodeIsTypeString(curNode, itemType)) {
res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock),
itemType);
NS_ENSURE_SUCCESS(res, res);
}
}
@ -3149,20 +3157,18 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
NS_NAMED_LITERAL_STRING(typestr, "type");
if (aBulletType && !aBulletType->IsEmpty()) {
res = mHTMLEditor->SetAttribute(curElement, typestr, *aBulletType);
}
else {
} else {
res = mHTMLEditor->RemoveAttribute(curElement, typestr);
}
NS_ENSURE_SUCCESS(res, res);
continue;
}
// if we hit a div clear our prevListItem, insert divs contents
// into our node array, and remove the div
if (nsHTMLEditUtils::IsDiv(curNode))
{
if (nsHTMLEditUtils::IsDiv(curNode)) {
prevListItem = nsnull;
PRInt32 j=i+1;
PRInt32 j = i + 1;
res = GetInnerContent(curNode, arrayOfNodes, &j);
NS_ENSURE_SUCCESS(res, res);
res = mHTMLEditor->RemoveContainer(curNode);
@ -3170,57 +3176,52 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
listCount = arrayOfNodes.Count();
continue;
}
// need to make a list to put things in if we haven't already,
if (!curList)
{
if (!curList) {
res = SplitAsNeeded(aListType, address_of(curParent), &offset);
NS_ENSURE_SUCCESS(res, res);
res = mHTMLEditor->CreateNode(*aListType, curParent, offset, getter_AddRefs(curList));
res = mHTMLEditor->CreateNode(*aListType, curParent, offset,
getter_AddRefs(curList));
NS_ENSURE_SUCCESS(res, res);
// remember our new block for postprocessing
mNewBlock = curList;
// curList is now the correct thing to put curNode in
prevListItem = 0;
}
// if curNode isn't a list item, we must wrap it in one
nsCOMPtr<nsIDOMNode> listItem;
if (!nsHTMLEditUtils::IsListItem(curNode))
{
if (IsInlineNode(curNode) && prevListItem)
{
if (!nsHTMLEditUtils::IsListItem(curNode)) {
if (IsInlineNode(curNode) && prevListItem) {
// this is a continuation of some inline nodes that belong together in
// the same list item. use prevListItem
res = mHTMLEditor->MoveNode(curNode, prevListItem, -1);
NS_ENSURE_SUCCESS(res, res);
}
else
{
} else {
// don't wrap li around a paragraph. instead replace paragraph with li
if (nsHTMLEditUtils::IsParagraph(curNode))
{
res = mHTMLEditor->ReplaceContainer(curNode, address_of(listItem), itemType);
}
else
{
res = mHTMLEditor->InsertContainerAbove(curNode, address_of(listItem), itemType);
if (nsHTMLEditUtils::IsParagraph(curNode)) {
res = mHTMLEditor->ReplaceContainer(curNode, address_of(listItem),
itemType);
} else {
res = mHTMLEditor->InsertContainerAbove(curNode,
address_of(listItem),
itemType);
}
NS_ENSURE_SUCCESS(res, res);
if (IsInlineNode(curNode))
if (IsInlineNode(curNode)) {
prevListItem = listItem;
else
} else {
prevListItem = nsnull;
}
}
}
else
{
} else {
listItem = curNode;
}
if (listItem) // if we made a new list item, deal with it
{
// tuck the listItem into the end of the active list
if (listItem) {
// if we made a new list item, deal with it: tuck the listItem into the
// end of the active list
res = mHTMLEditor->MoveNode(listItem, curList, -1);
NS_ENSURE_SUCCESS(res, res);
}
@ -4321,152 +4322,81 @@ nsHTMLEditRules::ConvertListType(nsIDOMNode *aList,
///////////////////////////////////////////////////////////////////////////
// CreateStyleForInsertText: take care of clearing and setting appropriate
// style nodes for text insertion.
//
//
nsresult
nsHTMLEditRules::CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocument *aDoc)
//
//
nsresult
nsHTMLEditRules::CreateStyleForInsertText(nsISelection *aSelection,
nsIDOMDocument *aDoc)
{
NS_ENSURE_TRUE(aSelection && aDoc, NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(mHTMLEditor->mTypeInState, NS_ERROR_NULL_POINTER);
bool weDidSometing = false;
MOZ_ASSERT(aSelection && aDoc && mHTMLEditor->mTypeInState);
bool weDidSomething = false;
nsCOMPtr<nsIDOMNode> node, tmp;
PRInt32 offset;
nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
NS_ENSURE_SUCCESS(res, res);
// if we deleted selection then also for cached styles
if (mDidDeleteSelection &&
((mTheAction == nsEditor::kOpInsertText ) ||
(mTheAction == nsEditor::kOpInsertIMEText) ||
(mTheAction == nsEditor::kOpInsertBreak) ||
(mTheAction == nsEditor::kOpDeleteSelection)))
{
res = ReapplyCachedStyles();
NS_ENSURE_SUCCESS(res, res);
}
// either way we clear the cached styles array
res = ClearCachedStyles();
nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection,
getter_AddRefs(node),
&offset);
NS_ENSURE_SUCCESS(res, res);
// next examine our present style and make sure default styles are either present or
// explicitly overridden. If neither, add the default style to the TypeInState
PRInt32 j, defcon = mHTMLEditor->mDefaultStyles.Length();
for (j=0; j<defcon; j++)
{
PropItem *propItem = mHTMLEditor->mDefaultStyles[j];
NS_ENSURE_TRUE(propItem, NS_ERROR_NULL_POINTER);
// next examine our present style and make sure default styles are either
// present or explicitly overridden. If neither, add the default style to
// the TypeInState
PRInt32 length = mHTMLEditor->mDefaultStyles.Length();
for (PRInt32 j = 0; j < length; j++) {
PropItem* propItem = mHTMLEditor->mDefaultStyles[j];
MOZ_ASSERT(propItem);
bool bFirst, bAny, bAll;
// GetInlineProperty also examine TypeInState. The only gotcha here is that a cleared
// property looks like an unset property. For now I'm assuming that's not a problem:
// that default styles will always be multivalue styles (like font face or size) where
// clearing the style means we want to go back to the default. If we ever wanted a
// "toggle" style like bold for a default, though, I'll have to add code to detect the
// difference between unset and explicitly cleared, else user would never be able to
// unbold, for instance.
// GetInlineProperty also examine TypeInState. The only gotcha here is
// that a cleared property looks like an unset property. For now I'm
// assuming that's not a problem: that default styles will always be
// multivalue styles (like font face or size) where clearing the style
// means we want to go back to the default. If we ever wanted a "toggle"
// style like bold for a default, though, I'll have to add code to detect
// the difference between unset and explicitly cleared, else user would
// never be able to unbold, for instance.
nsAutoString curValue;
res = mHTMLEditor->GetInlinePropertyBase(propItem->tag, &(propItem->attr), nsnull,
&bFirst, &bAny, &bAll, &curValue, false);
res = mHTMLEditor->GetInlinePropertyBase(propItem->tag, &propItem->attr,
nsnull, &bFirst, &bAny, &bAll,
&curValue, false);
NS_ENSURE_SUCCESS(res, res);
if (!bAny) // no style set for this prop/attr
{
mHTMLEditor->mTypeInState->SetProp(propItem->tag, propItem->attr, propItem->value);
if (!bAny) {
// no style set for this prop/attr
mHTMLEditor->mTypeInState->SetProp(propItem->tag, propItem->attr,
propItem->value);
}
}
nsCOMPtr<nsIDOMElement> rootElement;
res = aDoc->GetDocumentElement(getter_AddRefs(rootElement));
NS_ENSURE_SUCCESS(res, res);
// process clearing any styles first
nsAutoPtr<PropItem> item(mHTMLEditor->mTypeInState->TakeClearProperty());
while (item && node != rootElement)
{
nsCOMPtr<nsIDOMNode> leftNode, rightNode, secondSplitParent, newSelParent, savedBR;
res = mHTMLEditor->SplitStyleAbovePoint(address_of(node), &offset, item->tag, &item->attr, address_of(leftNode), address_of(rightNode));
while (item && node != rootElement) {
res = mHTMLEditor->ClearStyle(address_of(node), &offset,
item->tag, &item->attr);
NS_ENSURE_SUCCESS(res, res);
bool bIsEmptyNode;
if (leftNode)
{
mHTMLEditor->IsEmptyNode(leftNode, &bIsEmptyNode, false, true);
if (bIsEmptyNode)
{
// delete leftNode if it became empty
res = mEditor->DeleteNode(leftNode);
NS_ENSURE_SUCCESS(res, res);
}
}
if (rightNode)
{
secondSplitParent = mHTMLEditor->GetLeftmostChild(rightNode);
// don't try to split non-containers (br's, images, hr's, etc)
if (!secondSplitParent) secondSplitParent = rightNode;
if (!mHTMLEditor->IsContainer(secondSplitParent))
{
if (nsTextEditUtils::IsBreak(secondSplitParent))
savedBR = secondSplitParent;
secondSplitParent->GetParentNode(getter_AddRefs(tmp));
secondSplitParent = tmp;
}
offset = 0;
res = mHTMLEditor->SplitStyleAbovePoint(address_of(secondSplitParent), &offset, item->tag, &(item->attr), address_of(leftNode), address_of(rightNode));
NS_ENSURE_SUCCESS(res, res);
// should be impossible to not get a new leftnode here
NS_ENSURE_TRUE(leftNode, NS_ERROR_FAILURE);
newSelParent = mHTMLEditor->GetLeftmostChild(leftNode);
if (!newSelParent) newSelParent = leftNode;
// if rightNode starts with a br, suck it out of right node and into leftNode.
// This is so we you don't revert back to the previous style if you happen to click at the end of a line.
if (savedBR)
{
res = mEditor->MoveNode(savedBR, newSelParent, 0);
NS_ENSURE_SUCCESS(res, res);
}
mHTMLEditor->IsEmptyNode(rightNode, &bIsEmptyNode, false, true);
if (bIsEmptyNode)
{
// delete rightNode if it became empty
res = mEditor->DeleteNode(rightNode);
NS_ENSURE_SUCCESS(res, res);
}
// remove the style on this new hierarchy
PRInt32 newSelOffset = 0;
{
// track the point at the new hierarchy.
// This is so we can know where to put the selection after we call
// RemoveStyleInside(). RemoveStyleInside() could remove any and all of those nodes,
// so I have to use the range tracking system to find the right spot to put selection.
nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(newSelParent), &newSelOffset);
res = mHTMLEditor->RemoveStyleInside(leftNode, item->tag, &(item->attr));
NS_ENSURE_SUCCESS(res, res);
}
// reset our node offset values to the resulting new sel point
node = newSelParent;
offset = newSelOffset;
}
item = mHTMLEditor->mTypeInState->TakeClearProperty();
weDidSometing = true;
weDidSomething = true;
}
// then process setting any styles
PRInt32 relFontSize = mHTMLEditor->mTypeInState->TakeRelativeFontSize();
item = mHTMLEditor->mTypeInState->TakeSetProperty();
if (item || relFontSize) // we have at least one style to add; make a
{ // new text node to insert style nodes above.
if (mHTMLEditor->IsTextNode(node))
{
if (item || relFontSize) {
// we have at least one style to add; make a new text node to insert style
// nodes above.
if (mHTMLEditor->IsTextNode(node)) {
// if we are in a text node, split it
res = mHTMLEditor->SplitNodeDeep(node, node, offset, &offset);
NS_ENSURE_SUCCESS(res, res);
node->GetParentNode(getter_AddRefs(tmp));
node = tmp;
}
if (!mHTMLEditor->IsContainer(node))
{
if (!mHTMLEditor->IsContainer(node)) {
return NS_OK;
}
nsCOMPtr<nsIDOMNode> newNode;
@ -4479,32 +4409,30 @@ nsHTMLEditRules::CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocume
NS_ENSURE_SUCCESS(res, res);
node = newNode;
offset = 0;
weDidSometing = true;
weDidSomething = true;
if (relFontSize)
{
PRInt32 j, dir;
if (relFontSize) {
// dir indicated bigger versus smaller. 1 = bigger, -1 = smaller
if (relFontSize > 0) dir=1;
else dir = -1;
for (j=0; j<abs(relFontSize); j++)
{
res = mHTMLEditor->RelativeFontChangeOnTextNode(dir, nodeAsText, 0, -1);
PRInt32 dir = relFontSize > 0 ? 1 : -1;
for (PRInt32 j = 0; j < abs(relFontSize); j++) {
res = mHTMLEditor->RelativeFontChangeOnTextNode(dir, nodeAsText,
0, -1);
NS_ENSURE_SUCCESS(res, res);
}
}
while (item)
{
res = mHTMLEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr, &item->value);
while (item) {
res = mHTMLEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr,
&item->value);
NS_ENSURE_SUCCESS(res, res);
item = mHTMLEditor->mTypeInState->TakeSetProperty();
}
}
if (weDidSometing)
if (weDidSomething) {
return aSelection->Collapse(node, offset);
return res;
}
return NS_OK;
}
@ -5204,69 +5132,6 @@ nsHTMLEditRules::ExpandSelectionForDeletion(nsISelection *aSelection)
return res;
}
#ifdef XXX_DEAD_CODE
///////////////////////////////////////////////////////////////////////////
// AtStartOfBlock: is node/offset at the start of the editable material in this block?
//
bool
nsHTMLEditRules::AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock)
{
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
if (nodeAsText && aOffset) return false; // there are chars in front of us
nsCOMPtr<nsIDOMNode> priorNode;
nsresult res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(priorNode));
NS_ENSURE_SUCCESS(res, true);
NS_ENSURE_TRUE(priorNode, true);
nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(priorNode);
if (blockParent && (blockParent == aBlock)) return false;
return true;
}
///////////////////////////////////////////////////////////////////////////
// AtEndOfBlock: is node/offset at the end of the editable material in this block?
//
bool
nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock)
{
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
if (nodeAsText)
{
PRUint32 strLength;
nodeAsText->GetLength(&strLength);
if ((PRInt32)strLength > aOffset) return false; // there are chars in after us
}
nsCOMPtr<nsIDOMNode> nextNode;
nsresult res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nextNode));
NS_ENSURE_SUCCESS(res, true);
NS_ENSURE_TRUE(nextNode, true);
nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(nextNode);
if (blockParent && (blockParent == aBlock)) return false;
return true;
}
///////////////////////////////////////////////////////////////////////////
// CreateMozDiv: makes a div with type = _moz
//
nsresult
nsHTMLEditRules::CreateMozDiv(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outDiv)
{
NS_ENSURE_TRUE(inParent && outDiv, NS_ERROR_NULL_POINTER);
nsAutoString divType= "div";
*outDiv = nsnull;
nsresult res = mHTMLEditor->CreateNode(divType, inParent, inOffset, getter_AddRefs(*outDiv));
NS_ENSURE_SUCCESS(res, res);
// give it special moz attr
nsCOMPtr<nsIDOMElement> mozDivElem = do_QueryInterface(*outDiv);
res = mHTMLEditor->SetAttribute(mozDivElem, "type", "_moz");
NS_ENSURE_SUCCESS(res, res);
res = AddTrailerBR(*outDiv);
return res;
}
#endif
///////////////////////////////////////////////////////////////////////////
// NormalizeSelection: tweak non-collapsed selections to be more "natural".
@ -7407,10 +7272,6 @@ nsHTMLEditRules::ReapplyCachedStyles()
// and see if any have been removed. If so, add typeinstate
// for them, so that they will be reinserted when new
// content is added.
// When we apply cached styles to TypeInState, we always want
// to blow away prior TypeInState:
mHTMLEditor->mTypeInState->Reset();
// remember if we are in css mode
bool useCSS = mHTMLEditor->IsCSSEnabled();
@ -7444,8 +7305,7 @@ nsHTMLEditRules::ReapplyCachedStyles()
NS_ENSURE_SUCCESS(res, res);
}
// this style has disappeared through deletion. Add it onto our typeinstate:
if (!bAny)
{
if (!bAny || IsStyleCachePreservingAction(mTheAction)) {
mHTMLEditor->mTypeInState->SetProp(mCachedStyles[j].tag, mCachedStyles[j].attr, mCachedStyles[j].value);
}
}

Просмотреть файл

@ -140,9 +140,6 @@ protected:
// nsHTMLEditRules implementation methods
nsresult WillInsert(nsISelection *aSelection, bool *aCancel);
#ifdef XXX_DEAD_CODE
nsresult DidInsert(nsISelection *aSelection, nsresult aResult);
#endif
nsresult WillInsertText( nsEditor::OperationID aAction,
nsISelection *aSelection,
bool *aCancel,
@ -155,8 +152,10 @@ protected:
nsresult StandardBreakImpl(nsIDOMNode *aNode, PRInt32 aOffset, nsISelection *aSelection);
nsresult DidInsertBreak(nsISelection *aSelection, nsresult aResult);
nsresult SplitMailCites(nsISelection *aSelection, bool aPlaintext, bool *aHandled);
nsresult WillDeleteSelection(nsISelection *aSelection, nsIEditor::EDirection aAction,
bool *aCancel, bool *aHandled);
nsresult WillDeleteSelection(nsISelection* aSelection,
nsIEditor::EDirection aAction,
nsIEditor::EStripWrappers aStripWrappers,
bool* aCancel, bool* aHandled);
nsresult DidDeleteSelection(nsISelection *aSelection,
nsIEditor::EDirection aDir,
nsresult aResult);
@ -234,10 +233,6 @@ protected:
nsresult ExpandSelectionForDeletion(nsISelection *aSelection);
bool IsFirstNode(nsIDOMNode *aNode);
bool IsLastNode(nsIDOMNode *aNode);
#ifdef XXX_DEAD_CODE
bool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
bool AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
#endif
nsresult NormalizeSelection(nsISelection *inSelection);
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode,
PRInt32 aOffset, nsEditor::OperationID actionID,

Просмотреть файл

@ -1757,6 +1757,15 @@ nsHTMLEditor::InsertElementAtSelection(nsIDOMElement* aElement, bool aDeleteSele
{
if (aDeleteSelection)
{
if (!IsBlockNode(aElement)) {
// E.g., inserting an image. In this case we don't need to delete any
// inline wrappers before we do the insertion. Otherwise we let
// DeleteSelectionAndPrepareToCreateNode do the deletion for us, which
// calls DeleteSelection with aStripWrappers = eStrip.
res = DeleteSelection(nsIEditor::eNone, nsIEditor::eNoStrip);
NS_ENSURE_SUCCESS(res, res);
}
nsCOMPtr<nsIDOMNode> tempNode;
PRInt32 tempOffset;
nsresult result = DeleteSelectionAndPrepareToCreateNode(tempNode,tempOffset);
@ -3425,6 +3434,66 @@ nsHTMLEditor::GetEmbeddedObjects(nsISupportsArray** aNodeList)
}
NS_IMETHODIMP
nsHTMLEditor::DeleteSelectionImpl(EDirection aAction,
EStripWrappers aStripWrappers)
{
MOZ_ASSERT(aStripWrappers == eStrip || aStripWrappers == eNoStrip);
nsresult res = nsEditor::DeleteSelectionImpl(aAction, aStripWrappers);
NS_ENSURE_SUCCESS(res, res);
// If we weren't asked to strip any wrappers, we're done.
if (aStripWrappers == eNoStrip) {
return NS_OK;
}
nsRefPtr<nsTypedSelection> typedSel = GetTypedSelection();
// Just checking that the selection itself is collapsed doesn't seem to work
// right in the multi-range case
NS_ENSURE_STATE(typedSel);
NS_ENSURE_STATE(typedSel->GetAnchorFocusRange());
NS_ENSURE_STATE(typedSel->GetAnchorFocusRange()->Collapsed());
nsCOMPtr<nsIContent> content = do_QueryInterface(typedSel->GetAnchorNode());
NS_ENSURE_STATE(content);
// Don't strip wrappers if this is the only wrapper in the block. Then we'll
// add a <br> later, so it won't be an empty wrapper in the end.
nsCOMPtr<nsIContent> blockParent = content;
while (!IsBlockNode(blockParent)) {
blockParent = blockParent->GetParent();
}
bool emptyBlockParent;
res = IsEmptyNode(blockParent, &emptyBlockParent);
NS_ENSURE_SUCCESS(res, res);
if (emptyBlockParent) {
return NS_OK;
}
if (content && !IsBlockNode(content) && !content->Length() &&
content->IsEditable() && content != content->GetEditingHost()) {
while (content->GetParent() && !IsBlockNode(content->GetParent()) &&
content->GetParent()->Length() == 1 &&
content->GetParent()->IsEditable() &&
content->GetParent() != content->GetEditingHost()) {
content = content->GetParent();
}
res = DeleteNode(content);
NS_ENSURE_SUCCESS(res, res);
}
return NS_OK;
}
nsresult
nsHTMLEditor::DeleteNode(nsINode* aNode)
{
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
return DeleteNode(node);
}
NS_IMETHODIMP
nsHTMLEditor::DeleteNode(nsIDOMNode* aNode)
{

Просмотреть файл

@ -329,6 +329,9 @@ public:
virtual bool AreNodesSameType(nsIContent* aNode1, nsIContent* aNode2)
MOZ_OVERRIDE;
NS_IMETHOD DeleteSelectionImpl(EDirection aAction,
EStripWrappers aStripWrappers);
nsresult DeleteNode(nsINode* aNode);
NS_IMETHODIMP DeleteNode(nsIDOMNode * aNode);
NS_IMETHODIMP DeleteText(nsIDOMCharacterData *aTextNode,
PRUint32 aOffset,
@ -762,6 +765,9 @@ protected:
bool aDeleteSelection,
bool aTrustedInput);
nsresult ClearStyle(nsCOMPtr<nsIDOMNode>* aNode, PRInt32* aOffset,
nsIAtom* aProperty, const nsAString* aAttribute);
// Data members
protected:

Просмотреть файл

@ -145,7 +145,8 @@ nsHTMLEditorLog::RemoveInlineProperty(nsIAtom *aProperty, const nsAString &aAttr
}
NS_IMETHODIMP
nsHTMLEditorLog::DeleteSelection(nsIEditor::EDirection aAction)
nsHTMLEditorLog::DeleteSelection(nsIEditor::EDirection aAction,
nsIEditor::EStripWrappers aStripWrappers)
{
nsAutoHTMLEditorLogLock logLock(this);
@ -159,7 +160,7 @@ nsHTMLEditorLog::DeleteSelection(nsIEditor::EDirection aAction)
Flush();
}
return nsHTMLEditor::DeleteSelection(aAction);
return nsHTMLEditor::DeleteSelection(aAction, aStripWrappers);
}
NS_IMETHODIMP

Просмотреть файл

@ -73,7 +73,8 @@ public:
const nsAString & aValue);
NS_IMETHOD SetParagraphFormat(const nsAString& aParagraphFormat);
NS_IMETHOD RemoveInlineProperty(nsIAtom *aProperty, const nsAString& aAttribute);
NS_IMETHOD DeleteSelection(nsIEditor::EDirection aAction);
NS_IMETHOD DeleteSelection(nsIEditor::EDirection aAction,
nsIEditor::EStripWrappers aStripWrappers);
NS_IMETHOD InsertText(const nsAString& aStringToInsert);
NS_IMETHOD InsertLineBreak();
NS_IMETHOD Undo(PRUint32 aCount);

Просмотреть файл

@ -624,6 +624,85 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode,
return NS_OK;
}
nsresult
nsHTMLEditor::ClearStyle(nsCOMPtr<nsIDOMNode>* aNode, PRInt32* aOffset,
nsIAtom* aProperty, const nsAString* aAttribute)
{
nsCOMPtr<nsIDOMNode> leftNode, rightNode, tmp;
nsresult res = SplitStyleAbovePoint(aNode, aOffset, aProperty, aAttribute,
address_of(leftNode),
address_of(rightNode));
NS_ENSURE_SUCCESS(res, res);
if (leftNode) {
bool bIsEmptyNode;
IsEmptyNode(leftNode, &bIsEmptyNode, false, true);
if (bIsEmptyNode) {
// delete leftNode if it became empty
res = DeleteNode(leftNode);
NS_ENSURE_SUCCESS(res, res);
}
}
if (rightNode) {
nsCOMPtr<nsIDOMNode> secondSplitParent = GetLeftmostChild(rightNode);
// don't try to split non-containers (br's, images, hr's, etc)
if (!secondSplitParent) {
secondSplitParent = rightNode;
}
nsCOMPtr<nsIDOMNode> savedBR;
if (!IsContainer(secondSplitParent)) {
if (nsTextEditUtils::IsBreak(secondSplitParent)) {
savedBR = secondSplitParent;
}
secondSplitParent->GetParentNode(getter_AddRefs(tmp));
secondSplitParent = tmp;
}
*aOffset = 0;
res = SplitStyleAbovePoint(address_of(secondSplitParent),
aOffset, aProperty, aAttribute,
address_of(leftNode), address_of(rightNode));
NS_ENSURE_SUCCESS(res, res);
// should be impossible to not get a new leftnode here
NS_ENSURE_TRUE(leftNode, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNode> newSelParent = GetLeftmostChild(leftNode);
if (!newSelParent) {
newSelParent = leftNode;
}
// If rightNode starts with a br, suck it out of right node and into
// leftNode. This is so we you don't revert back to the previous style
// if you happen to click at the end of a line.
if (savedBR) {
res = MoveNode(savedBR, newSelParent, 0);
NS_ENSURE_SUCCESS(res, res);
}
bool bIsEmptyNode;
IsEmptyNode(rightNode, &bIsEmptyNode, false, true);
if (bIsEmptyNode) {
// delete rightNode if it became empty
res = DeleteNode(rightNode);
NS_ENSURE_SUCCESS(res, res);
}
// remove the style on this new hierarchy
PRInt32 newSelOffset = 0;
{
// Track the point at the new hierarchy. This is so we can know where
// to put the selection after we call RemoveStyleInside().
// RemoveStyleInside() could remove any and all of those nodes, so I
// have to use the range tracking system to find the right spot to put
// selection.
nsAutoTrackDOMPoint tracker(mRangeUpdater,
address_of(newSelParent), &newSelOffset);
res = RemoveStyleInside(leftNode, aProperty, aAttribute);
NS_ENSURE_SUCCESS(res, res);
}
// reset our node offset values to the resulting new sel point
*aNode = newSelParent;
*aOffset = newSelOffset;
}
return NS_OK;
}
bool nsHTMLEditor::NodeIsProperty(nsIDOMNode *aNode)
{
NS_ENSURE_TRUE(aNode, false);

Просмотреть файл

@ -749,7 +749,7 @@ nsHTMLEditor::DeleteTable2(nsIDOMElement *aTable, nsISelection *aSelection)
res = AppendNodeToSelectionAsRange(aTable);
NS_ENSURE_SUCCESS(res, res);
return DeleteSelection(nsIEditor::eNext);
return DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
}
NS_IMETHODIMP

Просмотреть файл

@ -968,8 +968,6 @@ const knownFailures = {
"D-Proposed-CHAR-7_SC-dM": true,
"D-Proposed-CHAR-7_SC-body": true,
"D-Proposed-CHAR-7_SC-div": true,
"D-Proposed-B-1_SW-dM": true,
"D-Proposed-B-1_SW-body": true,
"D-Proposed-B-1_SW-div": true,
"D-Proposed-B-1_SL-dM": true,
"D-Proposed-B-1_SL-body": true,

Просмотреть файл

@ -108,11 +108,11 @@ function runTests() {
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
node.focus();
is(checkBR(node), 0, "This node should not have any <br> element yet.");
is(checkBR(node), 0, node.textContent.trim() + ": This node should not have any <br> element yet.");
for (var j = 0; j < 3; j++) { // CARET_BEGIN|MIDDLE|END
split(node, j);
ok(checkBR(node) > 0, "Pressing [Return] should add (at least) one <br> element.");
is(getBlockCount(), count, "Pressing [Return] should not change the number of non-<br> elements.");
ok(checkBR(node) > 0, node.textContent.trim() + " " + j + ": Pressing [Return] should add (at least) one <br> element.");
is(getBlockCount(), count, node.textContent.trim() + " " + j + ": Pressing [Return] should not change the number of non-<br> elements.");
document.execCommand("Undo", false, null);
}
}

Просмотреть файл

@ -60,7 +60,7 @@ function runTests() {
select(document.querySelector("#test2 span"));
document.querySelector("#test2 [contenteditable]").focus();
synthesizeKey("VK_DELETE", {});
todo_is(document.querySelector("#test2 span"), null,
is(document.querySelector("#test2 span"), null,
"The <span> element should have been deleted.");
// done

Просмотреть файл

@ -109,7 +109,7 @@ nsresult nsPlaintextEditor::InsertTextAt(const nsAString &aStringToInsert,
// Use an auto tracker so that our drop point is correctly
// positioned after the delete.
nsAutoTrackDOMPoint tracker(mRangeUpdater, &targetNode, &targetOffset);
res = DeleteSelection(eNone);
res = DeleteSelection(eNone, eStrip);
NS_ENSURE_SUCCESS(res, res);
}

Просмотреть файл

@ -550,7 +550,7 @@ nsPlaintextEditor::InsertBR(nsCOMPtr<nsIDOMNode>* outBRNode)
NS_ENSURE_SUCCESS(res, res);
if (!selection->Collapsed()) {
res = DeleteSelection(nsIEditor::eNone);
res = DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
NS_ENSURE_SUCCESS(res, res);
}
@ -735,8 +735,12 @@ nsPlaintextEditor::ExtendSelectionForDelete(nsISelection *aSelection,
return result;
}
NS_IMETHODIMP nsPlaintextEditor::DeleteSelection(nsIEditor::EDirection aAction)
nsresult
nsPlaintextEditor::DeleteSelection(EDirection aAction,
EStripWrappers aStripWrappers)
{
MOZ_ASSERT(aStripWrappers == eStrip || aStripWrappers == eNoStrip);
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
// Protect the edit rules object from dying
@ -778,12 +782,13 @@ NS_IMETHODIMP nsPlaintextEditor::DeleteSelection(nsIEditor::EDirection aAction)
nsTextRulesInfo ruleInfo(kOpDeleteSelection);
ruleInfo.collapsedAction = aAction;
ruleInfo.stripWrappers = aStripWrappers;
bool cancel, handled;
result = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
NS_ENSURE_SUCCESS(result, result);
if (!cancel && !handled)
{
result = DeleteSelectionImpl(aAction);
result = DeleteSelectionImpl(aAction, aStripWrappers);
}
if (!cancel)
{
@ -1282,7 +1287,7 @@ NS_IMETHODIMP nsPlaintextEditor::Cut()
HandlingTrustedAction trusted(this);
if (FireClipboardEvent(NS_CUT))
return DeleteSelection(eNone);
return DeleteSelection(eNone, eStrip);
return NS_OK;
}

Просмотреть файл

@ -102,7 +102,8 @@ public:
NS_IMETHOD GetDocumentIsEmpty(bool *aDocumentIsEmpty);
NS_IMETHOD GetIsDocumentEditable(bool *aIsDocumentEditable);
NS_IMETHOD DeleteSelection(EDirection aAction);
NS_IMETHOD DeleteSelection(EDirection aAction,
EStripWrappers aStripWrappers);
NS_IMETHOD SetDocumentCharacterSet(const nsACString & characterSet);

Просмотреть файл

@ -410,7 +410,7 @@ nsTextEditRules::WillInsertBreak(nsISelection *aSelection,
NS_ENSURE_SUCCESS(res, res);
if (!bCollapsed)
{
res = mEditor->DeleteSelection(nsIEditor::eNone);
res = mEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
NS_ENSURE_SUCCESS(res, res);
}
@ -638,7 +638,7 @@ nsTextEditRules::WillInsertText(nsEditor::OperationID aAction,
NS_ENSURE_SUCCESS(res, res);
if (!bCollapsed)
{
res = mEditor->DeleteSelection(nsIEditor::eNone);
res = mEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
NS_ENSURE_SUCCESS(res, res);
}
@ -878,7 +878,7 @@ nsTextEditRules::WillDeleteSelection(nsISelection *aSelection,
NS_ENSURE_SUCCESS(res, res);
}
res = mEditor->DeleteSelectionImpl(aCollapsedAction);
res = mEditor->DeleteSelectionImpl(aCollapsedAction, nsIEditor::eStrip);
NS_ENSURE_SUCCESS(res, res);
*aHandled = true;

Просмотреть файл

@ -275,6 +275,7 @@ class nsTextRulesInfo : public nsRulesInfo
outputFormat(0),
maxLength(-1),
collapsedAction(nsIEditor::eNext),
stripWrappers(nsIEditor::eStrip),
bOrdered(false),
entireList(false),
bulletType(0),
@ -293,6 +294,7 @@ class nsTextRulesInfo : public nsRulesInfo
// kDeleteSelection
nsIEditor::EDirection collapsedAction;
nsIEditor::EStripWrappers stripWrappers;
// kMakeList
bool bOrdered;

Просмотреть файл

@ -47,25 +47,19 @@ using namespace mozilla;
///////////////////////////////////////////////////////////////////////////
// IsBody: true if node an html body node
//
// Would use NodeIsType and the corresponding atom, but
// the atom list isn't generationed in a plaintext-only
// configured build.
bool
nsTextEditUtils::IsBody(nsIDOMNode *node)
{
return nsEditor::NodeIsTypeString(node, NS_LITERAL_STRING("body"));
return nsEditor::NodeIsType(node, nsGkAtoms::body);
}
///////////////////////////////////////////////////////////////////////////
// IsBreak: true if node an html break node
//
// See previous comment regarding NodeisType
bool
nsTextEditUtils::IsBreak(nsIDOMNode *node)
{
return nsEditor::NodeIsTypeString(node, NS_LITERAL_STRING("br"));
return nsEditor::NodeIsType(node, nsGkAtoms::br);
}

Просмотреть файл

@ -1377,7 +1377,7 @@ nsTextServicesDocument::DeleteSelection()
// Now delete the actual content!
result = editor->DeleteSelection(nsIEditor::ePrevious);
result = editor->DeleteSelection(nsIEditor::ePrevious, nsIEditor::eStrip);
if (NS_FAILED(result))
{

Просмотреть файл

@ -832,7 +832,7 @@ mozInlineSpellChecker::ReplaceWord(nsIDOMNode *aNode, PRInt32 aOffset,
NS_ENSURE_SUCCESS(res, res);
selection->RemoveAllRanges();
selection->AddRange(range);
editor->DeleteSelection(nsIEditor::eNone);
editor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryReferent(mEditor));
textEditor->InsertText(newword);

Просмотреть файл

@ -11519,8 +11519,12 @@ nsCSSFrameConstructor::RestyleForRemove(Element* aContainer,
nsIContent* aOldChild,
nsIContent* aFollowingSibling)
{
NS_ASSERTION(!aOldChild->IsRootOfAnonymousSubtree(),
"anonymous nodes should not be in child lists");
if (aOldChild->IsRootOfAnonymousSubtree()) {
// This should be an assert, but this is called incorrectly in
// nsHTMLEditor::DeleteRefToAnonymousNode and the assertions were clogging
// up the logs. Make it an assert again when that's fixed.
NS_WARNING("anonymous nodes should not be in child lists (bug 439258)");
}
PRUint32 selectorFlags =
aContainer ? (aContainer->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
if (selectorFlags == 0)

Просмотреть файл

@ -876,6 +876,10 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_COLOR_INTERPOLATION_SRGB 1
#define NS_STYLE_COLOR_INTERPOLATION_LINEARRGB 2
// vector-effect
#define NS_STYLE_VECTOR_EFFECT_NONE 0
#define NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE 1
// 3d Transforms - Backface visibility
#define NS_STYLE_BACKFACE_VISIBILITY_VISIBLE 1
#define NS_STYLE_BACKFACE_VISIBILITY_HIDDEN 0

Просмотреть файл

@ -184,7 +184,7 @@ load 413582-1.xhtml
load 413582-2.html
load 413712-1.xhtml
asserts-if(Android,6) load 414061-1.html
asserts-if(!Android,6) load 414180-1.xul # Bug 439258
load 414180-1.xul
load 414719-1.html
load 415685-1.html
load 416264-1.html

Просмотреть файл

@ -0,0 +1,33 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css" >
rect {
stroke-width: 15px;
}
</style>
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0" stop-color="blue"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
<linearGradient id="grad2" x1="180" y1="250" x2="280" y2="300" gradientUnits="userSpaceOnUse" gradientTransform="scale(0.25,1)">
<stop offset="0" stop-color="blue"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
<pattern id="pattern" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" patternTransform="scale(1,0.5), skewX(45)">
<rect x="0" y="0" width="10" height="10" fill="red"/>
<rect x="10" y="0" width="10" height="10" fill="green"/>
<rect x="0" y="10" width="10" height="10" fill="blue"/>
<rect x="10" y="10" width="10" height="10" fill="yellow"/>
</pattern>
<rect id="rect" width="100" height="50" fill="none"/>
</defs>
<rect x="20" y="20" width="100" height="50" fill="none" stroke="url(#grad1)"/>
<rect x="20" y="100" width="100" height="50" fill="none" stroke="url(#grad2)" />
<use xlink:href="#rect" transform="translate(20, 180)" stroke="url(#pattern)"/>
<use xlink:href="#rect" x="20" y="260" stroke="green"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.3 KiB

Просмотреть файл

@ -0,0 +1,36 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css" >
rect {
stroke-width: 15px;
vector-effect: non-scaling-stroke;
}
</style>
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0" stop-color="blue"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
<linearGradient id="grad2" x1="100" y1="150" x2="200" y2="200" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="blue"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
<pattern id="pattern" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" patternTransform="scale(4,0.5), skewX(45)">
<rect x="0" y="0" width="10" height="10" fill="red"/>
<rect x="10" y="0" width="10" height="10" fill="green"/>
<rect x="0" y="10" width="10" height="10" fill="blue"/>
<rect x="10" y="10" width="10" height="10" fill="yellow"/>
</pattern>
<rect id="rect" width="400" height="50" fill="none"/>
</defs>
<g transform="translate(20,20)">
<rect width="400" height="50" fill="none" stroke="url(#grad1)" transform="scale(0.25,1)"/>
</g>
<rect width="400" height="50" fill="none" stroke="url(#grad2)" transform="translate(20,100) scale(0.25,1)"/>
<use xlink:href="#rect" transform="translate(20, 180) scale(0.25,1)" stroke="url(#pattern)"/>
<use xlink:href="#rect" x="40" y="80" transform="translate(10, 180) scale(0.25,1)" stroke="green"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Просмотреть файл

@ -0,0 +1,33 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden">
<style type="text/css" >
rect {
stroke-width: 30px;
}
</style>
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0" stop-color="blue"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
<linearGradient id="grad2" x1="360" y1="500" x2="560" y2="600" gradientUnits="userSpaceOnUse" gradientTransform="scale(0.25,1)">
<stop offset="0" stop-color="blue"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
<pattern id="pattern" x="0" y="0" width="40" height="40" patternUnits="userSpaceOnUse" patternTransform="scale(1,0.5), skewX(45)">
<rect x="0" y="0" width="20" height="20" fill="red"/>
<rect x="20" y="0" width="20" height="20" fill="green"/>
<rect x="0" y="20" width="20" height="20" fill="blue"/>
<rect x="20" y="20" width="20" height="20" fill="yellow"/>
</pattern>
<rect id="rect" width="200" height="100" fill="none"/>
</defs>
<rect x="40" y="40" width="200" height="100" fill="none" stroke="url(#grad1)"/>
<rect x="40" y="200" width="200" height="100" fill="none" stroke="url(#grad2)" />
<use xlink:href="#rect" transform="translate(40, 360)" stroke="url(#pattern)"/>
<use xlink:href="#rect" x="40" y="520" stroke="green"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.3 KiB

Просмотреть файл

@ -0,0 +1,36 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" reftest-zoom="2" overflow="hidden">
<style type="text/css" >
rect {
stroke-width: 15px;
vector-effect: non-scaling-stroke;
}
</style>
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0" stop-color="blue"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
<linearGradient id="grad2" x1="100" y1="150" x2="200" y2="200" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="blue"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
<pattern id="pattern" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" patternTransform="scale(4,0.5), skewX(45)">
<rect x="0" y="0" width="10" height="10" fill="red"/>
<rect x="10" y="0" width="10" height="10" fill="green"/>
<rect x="0" y="10" width="10" height="10" fill="blue"/>
<rect x="10" y="10" width="10" height="10" fill="yellow"/>
</pattern>
<rect id="rect" width="400" height="50" fill="none"/>
</defs>
<g transform="translate(20,20)">
<rect width="400" height="50" fill="none" stroke="url(#grad1)" transform="scale(0.25,1)"/>
</g>
<rect width="400" height="50" fill="none" stroke="url(#grad2)" transform="translate(20,100) scale(0.25,1)"/>
<use xlink:href="#rect" transform="translate(20, 180) scale(0.25,1)" stroke="url(#pattern)"/>
<use xlink:href="#rect" x="40" y="80" transform="translate(10, 180) scale(0.25,1)" stroke="green"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше