', '[foo
bar]'],
+ ['
', '[foo
bar]'],
+ ['', '[foo
bar]'],
+ ['
', '[foo
bar]'],
+ ['
', '[foo
bar]'],
+ ['', '[foo
bar]'],
+
+ ['p', '
[foobar]
'],
+
+ '[foo] bar ',
+
+ ['', '
[foo] bar '],
+ ['', '
foo [bar] '],
+ ['', '
[foo bar] '],
+ ['', '[foo] bar '],
+ ['', 'foo [bar] '],
+ ['', '[foo bar] '],
+ ['', '[foo] bar '],
+ ['', 'foo [bar] '],
+ ['', '[foo bar] '],
+ ['', '[foo] bar '],
+ ['', 'foo [bar] '],
+ ['', '[foo bar] '],
+
+ ['', ' [foo] bar
'],
+ ['', ' foo [bar]
'],
+ ['', ' [foo bar]
'],
+ ['', '[foo] bar
'],
+ ['', 'foo [bar]
'],
+ ['', '[foo bar]
'],
+ ['', '[foo] bar
'],
+ ['', 'foo [bar]
'],
+ ['', '[foo bar]
'],
+
+ ['', '
[foo] bar '],
+ ['', '
foo [bar] '],
+ ['', '
[foo bar] '],
+ ['', '[foo] bar '],
+ ['', 'foo [bar] '],
+ ['', '[foo bar] '],
+ ['', '[foo] bar '],
+ ['', 'foo [bar] '],
+ ['', '[foo bar] '],
+
+ [' ', '
[foo] bar '],
+ ['', '
foo [bar] '],
+ ['', '
[foo bar] '],
+ ['', '[foo] bar '],
+ ['', 'foo [bar] '],
+ ['', '[foo bar] '],
+ ['', '[foo] bar '],
+ ['', 'foo [bar] '],
+ ['', '[foo bar] '],
+
+ ['', ' [foo
bar]'],
+ ['', '[foo bar]
'],
+ ['', '
'],
+ ['', '
[foo] '],
+ ['', '
[foo] '],
+
+ '
',
+ '
',
+ '
[foo
bar] ',
+ '
[foo bar] ',
+ '
[foo
bar]',
+
+ // https://bugs.webkit.org/show_bug.cgi?id=47054
+ ['
', '
[foo]
'],
+ // https://bugs.webkit.org/show_bug.cgi?id=47574
+ ['
', '{ foo
ba]r'],
+ ['
', '
[foobar]
'],
+ // From https://bugs.webkit.org/show_bug.cgi?id=47300
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14009
+ ['!', '{
foo
bar
}'],
+ ],
+ //@}
+ forwarddelete: [
+ //@{
+ // Collapsed selection
+ 'foo[]',
+ 'foo[] ',
+ 'foo[]
',
+ 'foo[]bar',
+ 'foo {}bar ',
+ 'foo[ ]bar ',
+ 'foo[]bar baz',
+ 'foo[]baz',
+ 'fo[]öbar',
+ 'fo[]öbar',
+ 'fo[]ö̧bar',
+ '[]öbar',
+ '[]öbar',
+ '[]ö̧bar',
+
+ '[]שָׁלוֹם',
+ 'שָׁל[]וֹם',
+
+ 'foo[]
bar
',
+ 'foo[]
bar',
+ 'foo[]bar
',
+ 'foo[]
bar
',
+ 'foo[]
bar',
+ 'foo[]bar
',
+
+ '{}
foo',
+ '{}
foo',
+ 'foo{} ',
+ 'foo{}
',
+ 'foo{}
',
+ 'foo{}
',
+ 'foo{}
',
+ 'foo{}
',
+ 'foo{}
',
+ '
foo',
+ '
foo',
+ '
foo',
+
+ '
bar
',
+ '
foo[]
',
+ '
',
+ '
bar',
+ 'foo[]
',
+
+ '
foo[]
bar
',
+ '
foo[] bar',
+
+ 'foo[]
bar',
+ '
foo[] bar',
+ 'foo[]
bar',
+ '
foo[]
bar',
+ '
foo[]
bar
',
+ '
foo[]
bar
',
+ '
foo[]
bar',
+ 'foo[] bar',
+
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+
+ 'foo [] ',
+ '[] foo',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo [] bar',
+ 'foo [] bar',
+ 'foo[] bar',
+ 'foo [] bar',
+ 'foo [] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+
+ '
foo [] ',
+ '
[] foo ',
+ '
foo[] bar ',
+ '
foo[] bar ',
+ '
foo[] bar ',
+
+ '
foo []
',
+ '
[] foo
',
+ '
foo[] bar
',
+ '
foo[] bar
',
+ '
foo[] bar
',
+
+ '
foo []
',
+ '
[] foo
',
+ '
foo[] bar
',
+ '
foo[] bar
',
+ '
foo[] bar
',
+
+ '
foo []
',
+ '
[] foo
',
+ '
foo[] bar
',
+ '
foo[] bar
',
+ '
foo[] bar
',
+
+ '
foo []
',
+ '
[] foo
',
+ '
foo[] bar
',
+ '
foo[] bar
',
+ '
foo[] bar
',
+
+ // Tables with collapsed selection
+ 'foo[]
baz',
+ 'foo
baz',
+ '
foo[]
baz',
+ '
',
+ '
',
+
+ 'foo[]
baz',
+ 'foo
baz',
+ '
foo[]
baz',
+ '
foo
baz',
+ '
',
+ '
',
+
+ 'foo
baz',
+ 'foo[]
baz',
+ '
',
+ '
',
+
+ // Lists with collapsed selection
+ 'foo[]
bar baz ',
+ 'foo[]
bar baz ',
+ '
foo[] bar ',
+ '
foo[] bar ',
+ '
foo[] bar baz ',
+
+ '
foo[]
bar ',
+ '
foo[] bar
',
+ '
foo[]
bar
',
+
+ '
foo[] ',
+ 'foo[]
bar ',
+ 'foo[]
',
+
+ 'foo[]
bar baz ',
+ 'foo[]
bar ',
+ '
foo[] bar ',
+ '
foo[]bar baz ',
+ '
foo bar[]baz ',
+
+ '
foo[] bar',
+ '
foo[] bar',
+ '
{} bar',
+ '
foo {} bar',
+
+ '
foo[] bar',
+ '
foo[] bar',
+ '
{} bar',
+ '
foo {} bar',
+
+ '
foo[] ',
+ '
foo[] ',
+ '
{} ',
+ '
foo {} ',
+
+ '
foo[] ',
+ '
foo[] ',
+ '
{} ',
+ '
foo {} ',
+
+ // Indented stuff with collapsed selection
+ 'foo[]
bar ',
+ 'foo[]
bar ',
+ 'foo[]
bar
',
+ 'foo[]
bar ',
+
+ 'foo[]
bar
baz
',
+ 'foo[]
',
+ 'foo[]
bar
baz
',
+
+ 'foo[]
bar
baz
',
+ 'foo[]
bar
baz
',
+ 'foo[]
bar
baz
',
+
+ 'foo[]
bar extra',
+ 'foo[]
barbaz quz extra',
+ 'foo
bar[] baz quz extra',
+
+ // Invisible stuff with collapsed selection
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[] bar',
+ 'foo[]bar ',
+ 'foo[]
',
+ 'foo[]
',
+ 'foo[]
',
+ 'foo[]
',
+ 'foo[]
',
+ '
bar',
+ '
bar',
+ '
bar',
+ '
bar',
+ '
bar',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+
+ // Styled stuff with collapsed selection
+ '
foo[]
bar',
+ '
foo[]
bar',
+ '
foo[]
bar',
+ '
foo[]
bar',
+ '
foo[]
bar ',
+ '
foo[]
bar ',
+ '
foo[]bar',
+ '
foo[]bar',
+ 'foo[]
bar',
+
+ 'foo[]
bar',
+ '
foo[]
bar',
+ '
foo[]
bar',
+ '
foo[]bar',
+ '
foo[]bar',
+ 'foo[]
bar',
+
+ 'foo[]
bar',
+ '
foo[]
bar',
+ '
foo[]
bar',
+ '
foo[]
bar',
+ '
foo[]
bar ',
+ '
foo[]
bar ',
+
+ '
foo[]
bar',
+ 'foo[]bar',
+ '
bar',
+ 'bar',
+ '
foo[]
bar',
+
+ // Uncollapsed selection (should be same as delete command)
+ 'foo[bar]baz',
+ '
foo[bar] baz',
+ '
foo{bar} baz',
+ '
foo{bar }baz',
+ '
[foobar] baz',
+ '
{foobar} baz',
+ '
foo[bar baz]',
+ '
foo{bar baz}',
+ '
foo[bar baz] quz',
+
+ 'foo[bar] baz',
+ 'foo{bar} baz',
+ 'foo{bar }baz',
+ 'foo[bar] baz',
+ 'foo{bar} baz',
+ 'foo{bar }baz',
+ 'foo[bar baz]quz ',
+ '
foo
[bar]
baz
',
+ '
foo
{bar}
baz
',
+ '
foo
{bar
}
baz
',
+ '
foo
{
bar}
baz
',
+ '
foo
{
bar
}
baz
',
+
+ '
foo[bar
baz]quz',
+ '
foo[bar
baz]quz
',
+ '
foo[bar
baz]quz ',
+ '
foo[bar
baz]quz',
+ '
foo[bar baz]quz ',
+
+ '
foo[bar
baz]quz',
+ '
baz]quz',
+ '
foo[bar
baz]quz
qoz
foo[bar
baz]quz',
+ '
foo[bar
baz]quz ',
+
+ '
',
+
+ 'foo[
]bar',
+ '
foo[
]bar
',
+ '
foo[
]bar baz
',
+ 'foo[
]bar
',
+ 'foo{
}bar
',
+ 'foo[
]bar baz
',
+ 'foo[
]bar
baz',
+ 'foo{
bar
}baz',
+ 'foo
{bar
}baz',
+ 'foo{
bar}
baz',
+ '
foo[
]bar',
+ '
foo{
}bar',
+ '
foo[
]bar
baz',
+ '
foo[
]bar
baz
',
+ 'foo[
',
+ '
]bar',
+ 'foo[
',
+ 'foo[
',
+ '
]baz',
+ '
]baz',
+
+ '
foo {
]bar',
+ '
foo {
]bar',
+ 'foo
{
]bar
',
+ 'foo
{
]bar
',
+ '
foo {
}bar
',
+ '
foo {
}bar
',
+
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '{
}',
+ '
',
+ '
fo[o
baz',
+ '
foo
b]az',
+ '
fo[o
b]az',
+
+ '
foo
ba[r b]az quz',
+ '
foo
bar [baz] quz',
+ '
fo[o
b]ar baz quz',
+ '
foo
bar ba[z q]uz',
+ '
fo[o
bar b]az quz',
+ '
fo[o
bar baz q]uz',
+
+ '
fo[o b]ar ',
+ '
fo[o ',
+
+ 'foo[
]bar ',
+ '
foo[ ]bar ',
+ 'foo[
]bar baz ',
+ 'foo[
]bar ',
+ '
foo[ ]bar ',
+ '
foo[]bar baz ',
+ '
foo bar[]baz ',
+
+ // https://bugs.webkit.org/show_bug.cgi?id=35281
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=13976
+ '
foo {}
bar ',
+ '
foo {}
bar ',
+ '
foo
{}
bar ',
+ '
foo {}
bar ',
+ '
foo {}
bar ',
+ '
foo {}
bar ',
+ '
foo {}
bar ',
+ '
foo {}bar ',
+ '
foo {} bar ',
+ '
foo[ bar]
baz ',
+ '
foo[ bar]
baz ',
+ '
foo[
bar]
baz ',
+ '
fo[]o bar ',
+ '
foo [bar
]baz ',
+ '
foo [bar
]baz ',
+ '
foo [bar
]baz
',
+ '
foo []bar ',
+ '
foo[ bar baz]
quz ',
+ '
{}
',
+ '
{}
',
+ '
foo[ bar] baz quz ',
+ '
foo {}
',
+ '
foo {}
',
+ '
{}
bar ',
+ '
{}
bar ',
+
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=13831
+ '
[foo] ',
+ '
[foo] ',
+ '
[foo] ',
+ '
{foo} ',
+ '
{foo }',
+ '
[]f ',
+ '[foo] ',
+ '
[foo]
',
+ ],
+ //@}
+ hilitecolor: [
+ //@{
+ 'foo[]bar',
+ '
[foo
bar]
',
+ '
[foo bar] ',
+ '
[foo
bar
baz]
',
+ '
[foo
bar]',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo {}bar ',
+ 'foo[ ]bar ',
+ 'foo[bar]baz',
+ 'foo[barbaz]qoz quz',
+ 'foo[barbaz]qoz quz',
+ '{
foo
}',
+
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '{
}',
+
+ '
foo[bar]baz
',
+ '
foo[bar]baz
',
+ '
foo[bar]baz
',
+ '{
foo
bar
}',
+ '
foo[bar] baz ',
+ '
foo[bar] baz ',
+ '
foo[bar] baz ',
+ '
foo[bar] baz ',
+ '
foob[ar] baz ',
+ '
foob[ar] baz
',
+ '
',
+ '
b[ar] ',
+
+ // Tests for queryCommandIndeterm() and queryCommandState()
+ 'fo[o
b]ar baz',
+ 'foo
ba[r b]az',
+ 'fo[o
bar b]az',
+ 'foo[
b]ar baz',
+ 'foo
ba[r ]baz',
+ 'foo[
bar ]baz',
+ 'foo
[bar] baz',
+ 'foo{
bar }baz',
+ '
fo[o b]ar ',
+ '
fo[o b]ar ',
+ '
fo[ob]ar ',
+
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=13829
+ '!
[foo] ',
+ '!
[foo] ',
+ '!
foo[bar]baz ',
+ '!
foo[bar]baz ',
+ '![foo
bar baz]',
+ '![foo
bar baz]',
+ ],
+ //@}
+ indent: [
+ //@{
+ // All these have a trailing unselected paragraph, because otherwise
+ // Gecko is unhappy: it throws exceptions in non-CSS mode, and in CSS
+ // mode it adds the indentation invisibly to the wrapper div in many
+ // cases.
+ 'foo[]bar
extra',
+ 'foo {}bar
extra',
+ 'foo[ ]bar
extra',
+ 'foo[bar]baz
extra',
+ '
פו[בר]בז
נוםף',
+ '
פו[ברבז
Foobar]baz
Extra',
+ '
Foo[barbaz
פובר]בז
Extra',
+ '
Extra',
+ 'foo]bar[baz
extra',
+ '{
foo
}
extra',
+ 'foo[barbaz]qoz quz
extra',
+ '[]foo
extra',
+ 'foo[]
extra',
+ '
[]foo
extra',
+ '
foo[]
extra',
+ '
{} foo
extra',
+ '
foo {}
extra',
+ '{} foo bar
extra',
+ 'foo {} bar
extra',
+ '
foo
{}
bar
',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}
extra',
+
+ '
foo[bar]
baz
extra',
+ '
[foobar
ba]z
extra',
+ 'foo[bar] baz
extra',
+ 'foo[bar] baz
extra',
+ 'foobar [ba]z
extra',
+ 'foobar [ba]z
extra',
+ 'foo[bar ba]z
extra',
+ '
extra',
+
+ // These mimic existing indentation in various browsers, to see how
+ // they cope with indenting twice. This is spec, Gecko non-CSS, and
+ // Opera:
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
[foo]
bar
extra',
+ '
[foo
b]ar
extra',
+ '
foo
bar
[baz]
extra',
+ '
foo
[bar
baz]
extra',
+ '
[foo
bar
baz]
extra',
+ '
foo
[bar]
baz
extra',
+
+ '
foo[bar] baz extra',
+ '
foo[bar b]az extra',
+ '
foo[bar] baz
extra',
+ '
foo[bar b]az
extra',
+ '[foo]
bar extra',
+ '[foo
b]ar extra',
+ 'foo
bar [baz]
extra',
+ '[foo
bar baz]
extra',
+ '
foo [bar]
baz extra',
+
+ // IE:
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
[foo]
bar
extra',
+ '
[foo
b]ar
extra',
+ '
foo
bar
[baz]
extra',
+ '
foo
[bar
baz]
extra',
+ '
[foo
bar
baz]
extra',
+ '
foo
[bar]
baz
extra',
+
+ // Firefox CSS mode:
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
[foo]
bar
extra',
+ '
[foo
b]ar
extra',
+ '
foo
bar
[baz]
extra',
+ '
foo
[bar
baz]
extra',
+ '
[foo
bar
baz]
extra',
+ '
foo
[bar]
baz
extra',
+
+ // WebKit:
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
[foo]
bar
extra',
+ '
[foo
b]ar
extra',
+ '
foo
bar
[baz]
extra',
+ '
foo
[bar
baz]
extra',
+ '
[foo
bar
baz]
extra',
+ '
foo
[bar]
baz
extra',
+
+ // MDC says "In Firefox, if the selection spans multiple lines at
+ // different levels of indentation, only the least indented lines in
+ // the selection will be indented." Let's test that.
+ '
f[oob]ar extra',
+
+ // Lists!
+ '
foo [bar] baz ',
+ '
foo bar baz ',
+ '
foo [bar]',
+ '
[foo] bar baz ',
+ '
foo [bar] baz ',
+ '
[foo]
barbaz ',
+ '
foo[bar] baz quz ',
+ '
foobar [baz] quz ',
+ '
foo [bar] baz quz ',
+ '
foo bar baz quz ',
+ '
foo bar [baz] quz ',
+ '
foo bar baz quz ',
+ '
foob[a]r baz ',
+ '
foo b[a]r baz ',
+ '
foo{bar } baz ',
+ '
foo {bar }baz ',
+ '
[foo]bar baz ',
+ '
[foo] bar baz ',
+ '
foo [bar]baz quz ',
+ '
foo [bar] baz quz ',
+ '
foobar baz [quz] ',
+ '
foo bar baz [quz] ',
+
+ // Lists with id's:
+ // http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2009-July/020721.html
+ '
foo [bar] baz ',
+ '
foo [bar] baz ',
+ '
foo [bar] baz ',
+ '
[bar] baz ',
+ '
foo [bar] ',
+
+ // Try indenting multiple items at once.
+ '
foo b[ar baz] ',
+ '
[foobar] baz ',
+ '
[foo bar] baz ',
+ '
foob[ar b]az ',
+ '
foo b[ar b]az ',
+ '
[foobar baz] extra',
+ '
[foo bar baz] extra',
+
+ // We probably can't actually get this DOM . . .
+ '
[foo]bar baz ',
+ '
foo[bar] baz ',
+ '
foobar [baz] ',
+ '
[foobar] baz ',
+
+ 'foo[baz]
extra',
+ '[foo]baz
extra',
+ '
foo{}
extra',
+ '
{}bar
extra',
+
+ // Whitespace nodes
+ '
foo
[bar]',
+ '
[foo]
bar
',
+ '
foo
[bar]
baz
',
+ '
foo bar [baz] ',
+ '
foo bar [baz] ',
+ '
foo bar [baz] ',
+ '
foobar [baz] ',
+ '
foobar [baz] ',
+ '
foobar [baz] ',
+ '
foo [bar] baz ',
+ '
foo [bar] baz ',
+ '
foo [bar] baz ',
+ '
foo [bar] baz ',
+ '
foo [bar] baz ',
+ '
foo [bar] baz ',
+
+ // https://bugs.webkit.org/show_bug.cgi?id=32003
+ '
',
+ ],
+ //@}
+ inserthorizontalrule: [
+ //@{
+ 'foo[]bar',
+ '
foo {}
bar ',
+ '
foo[ ]bar ',
+ '
foo[bar
baz]quz',
+ '
foo {}bar
',
+ '
foo[ ]bar
',
+ '
foo {bar }baz
',
+ '
foo[]bar ',
+ '
foo[]bar ',
+ ["abc", 'foo[bar]baz'],
+ 'foo[bar]baz',
+
+ 'foo
[bar] baz',
+ 'foo
{bar} baz',
+ 'foo{
bar }baz',
+ '
foo
[bar]
baz',
+ '
foo
{bar}
baz',
+ '
foo{
bar
}
baz',
+
+ '
foo[bar]baz
',
+ '
foo[bar]baz
',
+ '
foo[bar]baz ',
+ '
foob[a]r baz
',
+
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
',
+ '
foo[bar]baz ',
+ '
foo[bar]baz
',
+ '
foo[bar]baz ',
+ '
foo[bar]baz',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz
',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz quz',
+ '
foo[bar]baz ',
+ '
',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz
',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]bazquz ',
+ '
foobar[baz]quz ',
+ '
foobar[baz]quz qoz qiz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
',
+ '
',
+ '
foo[bar]baz ',
+ '
',
+ '
foo[bar]baz ',
+
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+ '
foo[bar]baz ',
+
+ '
foo[bar]baz ',
+
+ '
',
+ 'fo[o
bar b]az',
+ ],
+ //@}
+ inserthtml: [
+ //@{
+ 'foo[]bar',
+ 'foo[bar]baz',
+ 'foo
[bar] baz',
+ 'foo
{bar} baz',
+ 'foo{
bar }baz',
+ '[foo
bar] baz',
+ '{foo
bar} baz',
+ 'foo
[bar baz]',
+ 'foo
{bar baz}',
+ 'foo
[bar baz] quz',
+
+ ['', 'foo[bar]baz'],
+ ['\0', 'foo[bar]baz'],
+ ['\x07', 'foo[bar]baz'],
+ // The following line makes Firefox 7.0a2 go into an infinite loop on
+ // my machine.
+ //['\ud800', 'foo[bar]baz'],
+
+ ['
', 'foo[bar]baz'],
+ ['abc', 'foo[bar]baz'],
+ [' abc', '
foo[bar]baz'],
+ ['
abc', 'foo[bar]baz'],
+ ['
abc', '
{foo }bar '],
+ ['abc', '
foo {bar }baz '],
+ ['abc', '
[foo] bar '],
+
+ ['abc', 'f[o]o '],
+ ['abc ', 'f[o]o '],
+ ['abc', 'bar'],
+ ['abc ', 'bar'],
+
+ ['abc ', 'f[o]o '],
+ ['abc ', 'f[o]o '],
+ [' ', 'f[o]o'],
+ ['
', 'f[o]o '],
+ ['abc ', 'f[o]o '],
+ ['abc ', ''],
+ ['abc ', 'f[o]o'],
+
+ ['abc ', 'f[o]o bar '],
+ ['abc ', 'foo b[a]r '],
+ ['abc ', 'f[o]o bar '],
+ ['abc ', 'foo b[a]r '],
+ ['abc ', 'f[o]o'],
+ ['abc ', 'f[o]o '],
+ ['abc ', 'f[o]o'],
+ ['abc ', 'f[o]o '],
+
+ [' abc ', '
f[o]o '],
+ ['
abc ', '
f[o]o '],
+ ['
abc ', '
'],
+ ['
abc ', '
f[o]o '],
+ ['
abc ', '
f[o]o '],
+ ['
abc ', '
'],
+ ['
abc ', '
f[o]o '],
+ ['
abc ', '
f[o]o '],
+ ['
abc ', '
'],
+ ['
', '
f[o]o '],
+ ['
', '
f[o]o '],
+ ['
', '
'],
+ ['
abc ', 'f[o]o'],
+
+ ['
abc ', '
f[o]o '],
+ ['
abc ', 'f[o]o'],
+
+ ['
abc', 'foo[]bar '],
+ ['
abc', 'foo[]bar '],
+ ['
abc', 'foo[]bar '],
+ [' ', '
[foo]
'],
+ ['
', '
[foo]
'],
+ ['', '
[foo]
'],
+
+ ['abc', '
{}
'],
+ ['', '
{}
'],
+ ['abc', '
{}
'],
+ ['', '
{}
'],
+ ['abc', '
{}
'],
+ ['', '
{}
'],
+
+ ['abc', '
{}
'],
+ ['', '
{}
'],
+ ['abc', '
{}
'],
+ ['', '
{}
'],
+ ['abc', '
{}
'],
+ ['', '
{}
'],
+ ],
+ //@}
+ insertimage: [
+ //@{
+ 'foo[]bar',
+ '
foo {}
bar ',
+ '
foo[ ]bar ',
+ ["", 'foo[bar]baz'],
+ 'foo[bar]baz',
+ 'foo
[bar] baz',
+ 'foo
{bar} baz',
+ 'foo{
bar }baz',
+ '[foo
bar] baz',
+ '{foo
bar} baz',
+ 'foo
[bar baz]',
+ 'foo
{bar baz}',
+ 'foo
[bar baz] quz',
+
+ 'foo
[bar] baz',
+ 'foo
{bar} baz',
+ 'foo{
bar }baz',
+ 'foo
[bar] baz',
+ 'foo
{bar} baz',
+ 'foo{
bar }baz',
+ '
foo[bar baz]quz ',
+ '
foo
[bar]
baz
',
+ '
foo
{bar}
baz
',
+ '
foo
{
bar
}
baz
',
+
+ '
foo[bar
baz]quz',
+ '
foo[bar
baz]quz
',
+ '
foo[bar
baz]quz ',
+ '
foo[bar
baz]quz',
+ '
foo[bar baz]quz ',
+
+ '
foo[bar
baz]quz',
+ '
baz]quz',
+ '
foo[bar
baz]quz
qoz
foo[bar
baz]quz',
+ '
foo[bar
baz]quz ',
+
+ '
',
+
+ 'foo[
]bar',
+ '
foo[
]bar
',
+ '
foo[
]bar baz
',
+ 'foo[
]bar
',
+ 'foo[
]bar baz
',
+ 'foo[
]bar
baz',
+ '
foo[
]bar',
+ '
foo[
]bar
baz',
+ '
foo[
]bar
baz
',
+ 'foo[
',
+ '
]bar',
+ 'foo[
',
+ 'foo[
',
+ '
]baz',
+ '
]baz',
+ ],
+ //@}
+ insertlinebreak: [
+ //@{ Same as insertparagraph (set below)
+ ],
+ //@}
+ insertorderedlist: [
+ //@{
+ 'foo[]bar',
+ 'foo[bar]baz',
+ 'foo
[bar]',
+ 'f[oo
b]ar
baz',
+ '
[foo] bar
',
+ '[foo
bar] baz',
+ 'foo
[bar baz]',
+ '[foo
baz',
+ 'foo
baz]',
+ 'foo
baz] quz',
+ 'foo
[bar quz',
+
+ '
',
+ '
',
+ '{
}',
+
+ '
foo
[bar]
baz',
+ '
foo
[bar] baz',
+ '
foo [bar] baz quz ',
+ '
foo bar [baz] quz ',
+
+ '
[foo
bar]
baz',
+ '
[foo
bar] baz',
+ '
[foo bar] baz quz ',
+ '
foo [bar baz] quz ',
+
+ '
[foo
bar]
baz
',
+
+
+ // Various
stuff
+ 'foo [bar] baz ',
+ 'foo [bar]',
+ '[foo]bar ',
+ 'foo [bar]baz ',
+ '[foo] ',
+ '[foo] bar baz ',
+ 'foo [bar] baz ',
+ '[foo]
barbaz ',
+ 'foo[bar] baz quz ',
+ 'foobar [baz] quz ',
+ 'foo [bar] baz quz ',
+ 'foo bar [baz] quz ',
+ '[foo]bar baz ',
+ '[foo] bar baz ',
+ 'foo [bar]baz quz ',
+ 'foo [bar] baz quz ',
+ 'foobar baz [quz] ',
+ 'foo bar baz [quz] ',
+
+ // Multiple items at once.
+ 'foo [bar baz] ',
+ '[foobar] baz ',
+ 'foob[ar b]az ',
+ '[foobar baz] extra',
+
+ // We probably can't actually get this DOM . . .
+ '
[foo]bar baz ',
+ 'foo[bar] baz ',
+ 'foobar [baz] ',
+ '[foobar] baz ',
+
+
+ // Same stuff but with
+ '',
+ '[bar]',
+ '[foo]',
+ '[bar]',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+
+ // Multiple items at once.
+ '',
+ '',
+ '',
+ 'extra',
+
+ // We probably can't actually get this DOM . . .
+ '
',
+ '',
+ '',
+ '',
+
+
+ // Mix of and
+ 'foobar quz',
+ 'foobar quz]',
+ 'foobaz quz',
+ '[foobaz quz',
+
+ // Interaction with indentation
+ '[foo]bar baz',
+ 'foo[bar] baz',
+ '[foobar] baz',
+ 'foo [bar] baz',
+ '[foo]bar baz',
+ 'foo[bar] baz ',
+ '[foobar] baz ',
+ 'foo [bar] baz ',
+
+ '[foo]
bar
baz',
+ '
foo
[bar]
baz',
+ '
[foo
bar]
baz',
+ '
foo [bar]
baz',
+
+ // Attributes
+ '
',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+
+ // Whitespace nodes
+ 'foo [bar]',
+ '
[foo]
bar ',
+ 'foo [bar]
baz ',
+
+ // This caused an infinite loop at one point due to a bug in "fix
+ // disallowed ancestors". Disabled because I'm not sure how we want it
+ // to behave:
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14578
+ '!foo[] ',
+ ],
+ //@}
+ insertparagraph: [
+ //@{
+ 'foo[bar]baz',
+ 'fo[o',
+ '',
+ '',
+ 'b]ar',
+ '',
+ '{}',
+ '',
+ '[foo] bar ',
+ 'f[o]o bar ',
+
+ '[]foo',
+ 'foo[]',
+ 'foo[] ',
+ 'foo[] ',
+ 'foo[]bar',
+ ' []foo ',
+ 'foo[] ',
+ 'foo[] ',
+ 'foo[]bar ',
+ '[]foo
',
+ 'foo[]
',
+ 'foo[]
',
+ 'foo[]bar
',
+ '[]foo bar ',
+ 'foo[] bar ',
+ 'foo[] bar ',
+ 'foo[]bar baz ',
+ 'foo []bar ',
+ 'foo bar[] ',
+ 'foo bar[] ',
+ 'foo bar[]baz ',
+ '[]foo ',
+ 'foo[] ',
+ 'foo[] ',
+ 'foo[]bar ',
+ '[]foo ',
+ 'foo[] ',
+ 'foo[] ',
+ 'foo[]bar ',
+ '[]foo
',
+ 'foo[]
',
+ 'foo[]
',
+ 'foo[]bar
',
+ '[]foo ',
+ 'foo[] ',
+ 'foo[] ',
+ 'foo[]bar ',
+
+ 'foo[] ',
+ 'foo {} ',
+ 'foo
[] ',
+ 'foo[]
',
+ 'foo
[]
',
+
+ 'foo[]bar ',
+ 'baz',
+ 'foo[]bar
baz',
+ 'foo[]bar ',
+
+ '{} ',
+ 'foo{} ',
+ '{} foo',
+ 'foo {} ',
+ '{} bar ',
+ 'foo ',
+
+ '{} ',
+ 'foo {} ',
+ '{} bar ',
+ 'foo bar{} baz ',
+ 'foo barbaz {} ',
+
+ 'foo[bar baz]quz
',
+ 'foo[bar
baz]quz ',
+ 'foo
{} ',
+ '{}foo
',
+ 'foo
{}bar ',
+ 'foo {}bar
',
+ 'foo {}bar ',
+ 'foo
[bar] baz
',
+ 'foo
{bar }baz
',
+
+ '',
+ '',
+
+ '[]foo ',
+ 'foo[] ',
+ 'foo[] ',
+ 'foo[]bar ',
+ '[]foo
',
+ 'foo[]
',
+ 'foo[]bar
',
+ 'foo[]
bar
',
+ 'foo[]bar
baz
',
+
+ 'foo[]bar ',
+ 'foo[]bar baz',
+ 'foo[]bar ',
+ 'foo[]bar baz',
+ 'foo[] bar',
+ 'foo[]bar ',
+ 'foo[] bar ',
+ 'foo[]bar ',
+ 'foo[]bar baz ',
+
+ 'foo[]bar
',
+ '[]foo
',
+ 'foo[]bar
',
+ 'foo[]bar
',
+
+ 'foo[]bar ',
+ 'foo[]bar baz',
+ 'foo[] bar',
+ 'foo[]bar ',
+
+ 'foo[]',
+ '
[]bar',
+
+ '
foo[bar] baz',
+ '
foo{bar} baz',
+ '
foo{bar }baz',
+ '
[foobar] baz',
+ '
{foobar} baz',
+ '
foo[bar baz]',
+ '
foo{bar baz}',
+ '
foo[bar baz] quz',
+
+ // https://bugs.webkit.org/show_bug.cgi?id=5036
+ '
',
+ '',
+ '',
+ '',
+
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=13841
+ // https://bugs.webkit.org/show_bug.cgi?id=23507
+ 'foo[]
',
+ 'foo[]
',
+ 'foo[]
',
+ 'foo[]
',
+ '',
+ 'foo[]',
+ '
foo[]',
+ '
foo[]',
+ '
foo[]',
+ '
foo[]',
+ '
',
+ '
foo[]
',
+
+ '
[]foo
',
+ '
[]foo
',
+ '
[]foo
',
+ '
[]foo
',
+ '
',
+ '
[]foo',
+ '
[]foo',
+ '
[]foo',
+ '
[]foo',
+ '
[]foo',
+ '
',
+ '
[]foo
',
+
+ '
foo[]bar
',
+ '
foo[]bar
',
+ '
foo[]bar
',
+ '
foo[]bar
',
+ '
',
+ '
foo[]bar',
+ '
foo[]bar',
+ '
foo[]bar',
+ '
foo[]bar',
+ '
foo[]bar',
+ '
',
+ '
foo[]bar
',
+
+ '
foo[]
',
+ '
',
+ '
',
+ '
[]foo
',
+ '
',
+ '
',
+ '
foo[]bar
',
+ '
',
+ '
',
+ ],
+ //@}
+ inserttext: [
+ //@{
+ 'foo[bar]baz',
+ ['', 'foo[bar]baz'],
+
+ ['\t', 'foo[]bar'],
+ ['&', 'foo[]bar'],
+ ['\n', 'foo[]bar'],
+ ['abc\ndef', 'foo[]bar'],
+ ['\x07', 'foo[]bar'],
+
+ ['
hi ', 'foo[]bar'],
+ ['<', 'foo[]bar'],
+ ['&', 'foo[]bar'],
+
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14254
+ ['!\r', 'foo[]bar'],
+ ['!\r\n', 'foo[]bar'],
+ ['!\0', 'foo[]bar'],
+ ['!\ud800', 'foo[]bar'],
+
+ // Whitespace tests! The following two bugs are relevant to some of
+ // these:
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14119
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=681626
+ [' ', 'foo[]bar'],
+ [' ', 'foo []bar'],
+ [' ', 'foo[] bar'],
+ [' ', 'foo []bar'],
+ [' ', 'foo [] bar'],
+ [' ', 'foo[] bar'],
+ [' ', 'foo []bar'],
+ [' ', 'foo [] bar'],
+ [' ', 'foo[] bar'],
+ [' ', 'foo []bar'],
+ [' ', 'foo [] bar'],
+ [' ', 'foo[] bar'],
+ [' ', 'foo [] bar'],
+ [' ', 'foo []bar'],
+ [' ', 'foo [] bar'],
+
+ [' ', '[]foo'],
+ [' ', '{}foo'],
+ [' ', 'foo[]'],
+ [' ', 'foo{}'],
+ [' ', 'foo []'],
+ [' ', 'foo {}'],
+ [' ', 'foo []'],
+ [' ', 'foo {}'],
+ [' ', '
foo[] bar'],
+ [' ', 'foo[]
bar '],
+
+ [' ', 'foo[] '],
+ [' ', ' foo [] '],
+ [' ', 'foo[]
'],
+ [' ', 'foo[]
'],
+ [' ', ' []foo'],
+ [' ', ' [] foo '],
+ [' ', '
[]foo'],
+ [' ', '
[]foo'],
+
+ [' ', '{}
'],
+ [' ', '
{} '],
+
+ [' ', '
foo[]
bar'],
+ [' ', '
foo []
bar'],
+ [' ', '
foo[]
bar'],
+
+ // Some of the same tests as above, repeated with various values of
+ // white-space.
+ [' ', '
foo[]bar '],
+ [' ', '
foo []bar '],
+ [' ', '
foo[] bar '],
+ [' ', '
foo []bar '],
+ [' ', '
[]foo '],
+ [' ', '
foo[] '],
+ [' ', '
foo [] '],
+ [' ', '
foo [] '],
+
+ [' ', '
foo[]bar
'],
+ [' ', '
foo []bar
'],
+ [' ', '
foo[] bar
'],
+ [' ', '
foo []bar
'],
+ [' ', '
[]foo
'],
+ [' ', '
foo[]
'],
+ [' ', '
foo []
'],
+ [' ', '
foo []
'],
+
+ [' ', '
foo[]bar
'],
+ [' ', '
foo []bar
'],
+ [' ', '
foo[] bar
'],
+ [' ', '
foo []bar
'],
+ [' ', '
[]foo
'],
+ [' ', '
foo[]
'],
+ [' ', '
foo []
'],
+ [' ', '
foo []
'],
+
+ [' ', '
foo[]bar
'],
+ [' ', '
foo []bar
'],
+ [' ', '
foo[] bar
'],
+ [' ', '
foo []bar
'],
+ [' ', '
[]foo
'],
+ [' ', '
foo[]
'],
+ [' ', '
foo []
'],
+ [' ', '
foo []
'],
+
+ [' ', '
foo[]bar
'],
+ [' ', '
foo []bar
'],
+ [' ', '
foo[] bar
'],
+ [' ', '
foo []bar
'],
+ [' ', '
[]foo
'],
+ [' ', '
foo[]
'],
+ [' ', '
foo []
'],
+ [' ', '
foo []
'],
+
+ // End whitespace tests
+
+ // Autolinking tests
+ [' ', 'http://a[]'],
+ [' ', 'ftp://a[]'],
+ [' ', 'quasit://a[]'],
+ [' ', '.x-++-.://a[]'],
+ [' ', '(http://a)[]'],
+ [' ', '<http://a>[]'],
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14744
+ ['! ', '[http://a][]'],
+ ['! ', '{http://a}[]'],
+ [' ', 'http://a![]'],
+ [' ', '!"#$%&\'()*+,-./:;<=>?\^_`|~http://a!"#$%&\'()*+,-./:;<=>?\^_`|~[]'],
+ [' ', 'http://a!"\'(),-.:;<>`[]'],
+ [' ', 'http://a#$%&*+/=?\^_|~[]'],
+ [' ', 'mailto:a[]'],
+ [' ', 'a@b[]'],
+ [' ', 'a@[]'],
+ [' ', '@b[]'],
+ [' ', '#@x[]'],
+ [' ', 'a@.[]'],
+ [' ', '!"#$%&\'()*+,-./:;<=>?\^_`|~a@b!"#$%&\'()*+,-./:;<=>?\^_`|~[]'],
+ [' ', '
a@b {}'],
+ [' ', '
a @ b {}'],
+ [' ', 'a@b
[]c '],
+ [' ', '
a@b
[]c
'],
+ ['a', 'http://a[]'],
+ ['\t', 'http://a[]'],
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14254
+ ['!\r', 'http://a[]'],
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14745
+ ['!\n', 'http://a[]'],
+ ['\f', 'http://a[]'],
+ ['\u00A0', 'http://a[]'],
+
+ [' ', 'foo[]'],
+
+ 'foo[]bar',
+ 'foo []',
+ 'foo\xa0[]',
+ '
foo[]',
+ '
foo
{}',
+ '
[]foo',
+ '
{}foo',
+ '{}
foo',
+ '
foo
{}
bar
',
+ '
foo[] bar',
+ '
foo []bar',
+ 'foo
{} bar',
+ '
foo[] bar',
+ '
foo []bar',
+ '
foo[] bar',
+ '
foo []bar',
+ '
fo[o
b]ar',
+ '
fo[o
bar
b]az',
+ '{} ',
+ '
{} ',
+ '
{} ',
+ '
foo[bar] baz',
+ '
foo{bar} baz',
+ '
foo{bar }baz',
+ '
[foobar] baz',
+ '
{foobar} baz',
+ '
foo[bar baz]',
+ '
foo{bar baz}',
+ '
foo[bar baz] quz',
+
+
+ // These are like the corresponding tests in the multitest section, but
+ // because the selection isn't collapsed, we don't need to do
+ // multitests to set overrides.
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+
+ // Now repeat but with different selections.
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+ '[foobar] baz',
+
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+
+ // https://bugs.webkit.org/show_bug.cgi?id=19702
+ '
[foo] ',
+ ],
+ //@}
+ insertunorderedlist: [
+ //@{
+ 'foo[]bar',
+ 'foo[bar]baz',
+ 'foo
[bar]',
+ 'f[oo
b]ar
baz',
+ '
[foo] bar
',
+ '[foo
bar] baz',
+ 'foo
[bar baz]',
+ '[foo
baz',
+ 'foo
baz]',
+ 'foo
baz] quz',
+ 'foo
[bar quz',
+
+ '
',
+ '
',
+ '{
}',
+
+ '
foo
[bar]
baz',
+ '
foo
[bar] baz',
+ '
foo [bar] baz quz ',
+ '
foo bar [baz] quz ',
+
+ '
[foo
bar]
baz',
+ '
[foo
bar] baz',
+ '
[foo bar] baz quz ',
+ '
foo [bar baz] quz ',
+
+ '
[foo
bar]
baz
',
+
+
+ // Various
stuff
+ 'foo [bar] baz ',
+ 'foo [bar]',
+ '[foo]bar ',
+ 'foo [bar]baz ',
+ '[foo] ',
+ '[foo] bar baz ',
+ 'foo [bar] baz ',
+ '[foo]
barbaz ',
+ 'foo[bar] baz quz ',
+ 'foobar [baz] quz ',
+ 'foo [bar] baz quz ',
+ 'foo bar [baz] quz ',
+ '[foo]bar baz ',
+ '[foo] bar baz ',
+ 'foo [bar]baz quz ',
+ 'foo [bar] baz quz ',
+ 'foobar baz [quz] ',
+ 'foo bar baz [quz] ',
+
+ // Multiple items at once.
+ 'foo [bar baz] ',
+ '[foobar] baz ',
+ 'foob[ar b]az ',
+ '[foobar baz] extra',
+
+ // We probably can't actually get this DOM . . .
+ '
[foo]bar baz ',
+ 'foo[bar] baz ',
+ 'foobar [baz] ',
+ '[foobar] baz ',
+
+
+ // Same stuff but with
+ '',
+ '[bar]',
+ '[foo]',
+ '[bar]',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+
+ // Multiple items at once.
+ '',
+ '',
+ '',
+ 'extra',
+
+ // We probably can't actually get this DOM . . .
+ '
',
+ '',
+ '',
+ '',
+
+
+ // Mix of and
+ 'foobar quz',
+ 'foobar quz]',
+ 'foobaz quz',
+ '[foobaz quz',
+
+ // Interaction with indentation
+ '[foo]bar baz',
+ 'foo[bar] baz',
+ '[foobar] baz',
+ 'foo [bar] baz',
+ '[foo]bar baz',
+ 'foo[bar] baz ',
+ '[foobar] baz ',
+ 'foo [bar] baz ',
+
+ '[foo]
bar
baz',
+ '
foo
[bar]
baz',
+ '
[foo
bar]
baz',
+ '
foo [bar]
baz',
+
+ // Attributes
+ '
',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+
+ // Whitespace nodes
+ ' [bar]',
+ '
[foo]
',
+ ' [bar]
',
+
+ // https://bugs.webkit.org/show_bug.cgi?id=24167
+ '{1
2
}',
+ ],
+ //@}
+ italic: [
+ //@{
+ 'foo[]bar',
+ '[foo
bar]
',
+ '[foo bar] ',
+ '[foo
bar
baz]
',
+ '[foo
bar]',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo {}bar ',
+ 'foo[ ]bar ',
+ 'foo[bar]baz',
+ 'foo[barbaz]qoz quz',
+ 'foo[barbaz]qoz quz',
+ '{
foo
}',
+
+ '',
+ '',
+ '',
+ '',
+ '',
+ '{}',
+
+ 'foo[bar] baz',
+ 'foo [bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+
+ 'foo{bar }baz',
+ 'foo{bar }baz',
+ 'foo{bar }baz',
+ 'foo{bar }baz',
+ 'foo{bar }baz',
+ 'foo{bar }baz',
+
+ 'foob[a]r baz',
+ 'foob[a]r baz',
+ 'foob[a]r baz',
+ 'foob[a]r baz',
+ 'foob[a]r baz',
+ 'foob[a]r baz',
+
+ 'fo[obar b]az',
+ 'fo[obar b]az',
+ 'fo[obar b]az',
+ 'fo[obar b]az',
+ 'fo[obar b]az',
+ 'fo[obar b]az',
+
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+ 'foo[bar baz]',
+
+ '[foobar ]baz',
+ '[foobar ]baz',
+ '[foobar ]baz',
+ '[foobar ]baz',
+ '[foobar ]baz',
+ '[foobar ]baz',
+
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+
+ '{ foo
bar
}baz
',
+ 'foo[bar }
baz
',
+ 'foo [bar baz] qoz quz sic',
+ 'foo bar baz [qoz quz] sic',
+ 'foo [bar baz] qoz quz sic',
+ 'foo bar baz [qoz quz] sic',
+
+ // Tests for queryCommandIndeterm() and queryCommandState()
+ 'fo[ob]ar baz',
+ 'fooba[r b]az',
+ 'fo[obar b]az',
+ 'foo[b]ar baz',
+ 'fooba[r ]baz',
+ 'foo[bar ]baz',
+ 'foo[bar] baz',
+ 'foo{bar }baz',
+ 'fo[ob]ar baz',
+ 'fo[ob]ar baz',
+ 'fo[o b]ar ',
+ 'fo[o b]ar ',
+ 'fo[o b]ar ',
+ ],
+ //@}
+ justifycenter: [
+ //@{
+ 'foo[]barextra',
+ 'foo {}bar
extra',
+ 'foo[ ]bar
extra',
+ 'foo[bar]baz
extra',
+ 'foo[barbaz]qoz quz
extra',
+ '
foo[]bar
extra',
+ '
foo[bar]baz
extra',
+ '
foo[bar]baz extra',
+ '
foo[bar]baz extra',
+ '
foo[bar]baz extra',
+ '
[foo]
bar
extra',
+ '
[foo
bar]
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
foo [bar]extra',
+ '[foo]
bar extra',
+ '
foo [bar]baz extra',
+ '
foo
[bar]extra',
+ '[foo]
bar
extra',
+ '
foo
[bar]baz
extra',
+ '
[bar]
extra',
+ '
[foo]
extra',
+ '
[bar]
extra',
+ '
foo
[bar]extra',
+ '[foo]
bar
extra',
+ '
foo
[bar]baz
extra',
+ '
[bar]
extra',
+ '
[foo]
extra',
+ '
[bar]
extra',
+ '
foo
[bar]
extra',
+ '
[foo]
bar
extra',
+ '
foo
[bar]
baz
extra',
+
+ '
[foo bar]extra',
+ '
fo[o b]arextra',
+ '
[foo
bar]extra',
+ '
fo[o
b]arextra',
+ '
[foo
bar]extra',
+ '
fo[o
b]arextra',
+ '[foo]
extra',
+ 'f[o]o
extra',
+
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '[foo]
extra',
+
+ '
',
+ '',
+ '',
+ '',
+ '{
foo
}
',
+ '{
foo
}
',
+ '',
+ '',
+
+ '[foo]
extra',
+ '
[foo]
extra',
+ '
[foo]
extra',
+ '
[foo]
extra',
+
+ // Whitespace nodes
+ '
[bar]',
+ '
[bar]',
+ '
foo
[bar]',
+ '
[foo]
',
+ '[foo]
',
+ '[foo]
bar
',
+ ' [bar]
',
+ ' [bar]
',
+ 'foo
[bar]
baz
',
+ ],
+ //@}
+ justifyfull: [
+ //@{
+ 'foo[]barextra',
+ 'foo {}bar
extra',
+ 'foo[ ]bar
extra',
+ 'foo[bar]baz
extra',
+ 'foo[barbaz]qoz quz
extra',
+ '
foo[]bar
extra',
+ '
foo[bar]baz
extra',
+ '
foo[bar]baz extra',
+ '
foo[bar]baz extra',
+ '
foo[bar]baz extra',
+ '
[foo]
bar
extra',
+ '
[foo
bar]
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
foo
[bar]extra',
+ '[foo]
bar
extra',
+ '
foo
[bar]baz
extra',
+ '
[bar]
extra',
+ '
[foo]
extra',
+ '
[bar]
extra',
+ '
foo
[bar]extra',
+ '[foo]
bar
extra',
+ '
foo
[bar]baz
extra',
+ '
[bar]
extra',
+ '
[foo]
extra',
+ '
[bar]
extra',
+ '
foo
[bar]
extra',
+ '
[foo]
bar
extra',
+ '
foo
[bar]
baz
extra',
+
+ '
[foo
bar]extra',
+ '
fo[o
b]arextra',
+ '
[foo
bar]extra',
+ '
fo[o
b]arextra',
+ '[foo]
extra',
+ 'f[o]o
extra',
+
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '[foo]
extra',
+
+ '
[foo]
extra',
+ '
[foo]
extra',
+ '
[foo]
extra',
+ '
[foo]
extra',
+
+ // Whitespace nodes
+ '
[bar]',
+ '
[bar]',
+ '
[foo]
',
+ '[foo]
',
+ ' [bar]
',
+ ' [bar]
',
+ ],
+ //@}
+ justifyleft: [
+ //@{
+ 'foo[]barextra',
+ 'foo {}bar
extra',
+ 'foo[ ]bar
extra',
+ 'foo[bar]baz
extra',
+ 'foo[barbaz]qoz quz
extra',
+ '
foo[]bar
extra',
+ '
foo[bar]baz
extra',
+ '
foo[bar]baz extra',
+ '
foo[bar]baz extra',
+ '
foo[bar]baz extra',
+ '
[foo]
bar
extra',
+ '
[foo
bar]
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
foo
[bar]extra',
+ '[foo]
bar
extra',
+ '
foo
[bar]baz
extra',
+ '
[bar]
extra',
+ '
[foo]
extra',
+ '
[bar]
extra',
+ '
foo
[bar]extra',
+ '[foo]
bar
extra',
+ '
foo
[bar]baz
extra',
+ '
[bar]
extra',
+ '
[foo]
extra',
+ '
[bar]
extra',
+ '
foo
[bar]
extra',
+ '
[foo]
bar
extra',
+ '
foo
[bar]
baz
extra',
+
+ '
[foo
bar]extra',
+ '
fo[o
b]arextra',
+ '
[foo
bar]extra',
+ '
fo[o
b]arextra',
+ '[foo]
extra',
+ 'f[o]o
extra',
+
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '[foo]
extra',
+
+ '
[foo]
extra',
+ '
[foo]
extra',
+ '
[foo]
extra',
+ '
[foo]
extra',
+
+ // Whitespace nodes
+ '
[bar]',
+ '
[bar]',
+ '
[foo]
',
+ '[foo]
',
+ ' [bar]
',
+ ' [bar]
',
+ ],
+ //@}
+ justifyright: [
+ //@{
+ 'foo[]barextra',
+ 'foo {}bar
extra',
+ 'foo[ ]bar
extra',
+ 'foo[bar]baz
extra',
+ 'foo[barbaz]qoz quz
extra',
+ '
foo[]bar
extra',
+ '
foo[bar]baz
extra',
+ '
foo[bar]baz extra',
+ '
foo[bar]baz extra',
+ '
foo[bar]baz extra',
+ '
[foo]
bar
extra',
+ '
[foo
bar]
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+ '{
}extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '
extra',
+ '
extra',
+
+ '
foo
[bar]extra',
+ '[foo]
bar
extra',
+ '
foo
[bar]baz
extra',
+ '
[bar]
extra',
+ '
[foo]
extra',
+ '
[bar]
extra',
+ '
foo
[bar]extra',
+ '[foo]
bar
extra',
+ '
foo
[bar]baz
extra',
+ '
[bar]
extra',
+ '
[foo]
extra',
+ '
[bar]
extra',
+ '
foo
[bar]
extra',
+ '
[foo]
bar
extra',
+ '
foo
[bar]
baz
extra',
+
+ '
[foo
bar]extra',
+ '
fo[o
b]arextra',
+ '
[foo
bar]extra',
+ '
fo[o
b]arextra',
+ '[foo]
extra',
+ 'f[o]o
extra',
+
+ '
extra',
+
+ '
extra',
+ '
extra',
+ '[foo]
extra',
+
+ '
[foo]
extra',
+ '
[foo]
extra',
+ '
[foo]
extra',
+ '
[foo]
extra',
+
+ // Whitespace nodes
+ '
[bar]',
+ '
[bar]',
+ '
[foo]
',
+ '[foo]
',
+ ' [bar]
',
+ ' [bar]
',
+ ],
+ //@}
+ outdent: [
+ //@{
+ // These mimic existing indentation in various browsers, to see how
+ // they cope with outdenting various things. This is spec, Gecko
+ // non-CSS, and Opera:
+ 'foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+
+ // IE:
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+
+ // Firefox CSS mode:
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+
+ // WebKit:
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+ '
foo[bar]
baz
extra',
+ '
foo[bar
b]az
extra',
+
+ // Now let's try nesting lots of stuff and see what happens.
+ '
foo[bar]baz ',
+ 'foo[bar]baz ',
+ 'foo[bar]baz ',
+ 'foo[bar]baz
',
+ 'foo[bar]baz
',
+ 'foo[bar]baz ',
+ 'foo[bar]baz ',
+
+ 'foo[bar]
baz
',
+ 'foo[bar]
baz
',
+ 'foo[bar]
baz
',
+ ' ',
+ ' ',
+ 'foo[bar]
baz
',
+ 'foo[bar]
baz
',
+
+ 'foo[bar]
baz
',
+ 'foo[bar]
baz
',
+ 'foo[bar]
baz
',
+ 'foo[bar]
baz
',
+ 'foo[bar]
baz
',
+
+ // Lists!
+ 'foo [bar] baz ',
+ 'foo bar baz ',
+ 'foo [bar]',
+ '[foo] bar baz ',
+ 'foo [bar] baz ',
+ '[foo]
barbaz ',
+ 'foo[bar] baz quz ',
+ 'foobar [baz] quz ',
+ 'foo [bar] baz quz ',
+ 'foo bar baz quz ',
+ 'foo bar [baz] quz ',
+ 'foo bar baz quz ',
+ 'foob[a]r baz ',
+ 'foo b[a]r baz ',
+ 'foo{bar } baz ',
+ 'foo {bar }baz ',
+ '[foo]bar baz ',
+ '[foo] bar baz ',
+ 'foo [bar]baz quz ',
+ 'foo [bar] baz quz ',
+ 'foobar baz [quz] ',
+ 'foo bar baz [quz] ',
+
+ // Try outdenting multiple items at once.
+ 'foo b[ar baz] ',
+ '[foobar] baz ',
+ '[foo bar] baz ',
+ 'foob[ar b]az ',
+ 'foo b[ar b]az ',
+ '[foobar baz] extra',
+ '
[foo bar baz] extra',
+
+ // We probably can't actually get this DOM . . .
+ '
[foo]bar baz ',
+ 'foo[bar] baz ',
+ 'foobar [baz] ',
+ '[foobar] baz ',
+
+ // Attribute handling on lists
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo [bar] ',
+ '',
+ 'foo [bar] baz ',
+ 'foo [bar] baz ',
+ 'foo [bar] baz ',
+ 'foo [bar] baz ',
+ 'foo [bar baz] quz ',
+ 'foo [bar baz] quz ',
+ 'foo [bar baz] quz ',
+ 'foo [bar baz] quz ',
+
+ // List inside indentation element
+ '[foo] extra',
+ '
foo[bar] baz extra',
+ '
foo [bar] baz extra',
+
+ '
[foo] ',
+ '[foo] ',
+ 'foo baz ',
+
+ // Whitespace nodes
+ ' [foo]
',
+ '[foo]
',
+ ' [foo]
',
+ ' [foo] ',
+ '[foo] ',
+ ' [foo] ',
+ '',
+ '',
+ '',
+ ' [foo]
bar
baz
',
+ ' foo
[bar]
baz
',
+ ' foo
bar
[baz]
',
+ ' [foo] bar baz ',
+ ' foo [bar] baz ',
+ ' foo bar [baz] ',
+ '',
+ '',
+ '',
+
+ // https://bugs.webkit.org/show_bug.cgi?id=24249
+ '[]a ',
+ // https://bugs.webkit.org/show_bug.cgi?id=43447
+ 'foo [bar] ',
+ ],
+ //@}
+ removeformat: [
+ //@{
+ 'foo[]bar',
+ 'foo {}bar ',
+ 'foo[ ]bar ',
+ '[foobar baz]',
+ 'foo[bar baz]',
+ 'foo[bar ]baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+
+ // HTML has lots of inline elements, doesn't it?
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar
baz]',
+ 'foob[a]r
baz',
+ '[foobarbaz]',
+ 'foob[a]rbaz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+
+ // Empty and replaced elements
+ '[foo bar]',
+ '[foo bar]',
+ '[foobar]',
+ '[foo bar]',
+ '[foo bar]',
+ '[foo bar]',
+ '[foo bar]',
+ '[foo bar]',
+
+ // Unrecognized elements
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+
+ // Random stuff
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ '[foobar baz]',
+ 'foob[a]r baz',
+ 'foo[bar]baz
',
+ 'foo[bar]baz
',
+ 'foo[bar]baz
',
+ 'foo[bar]baz
',
+ 'foo[bar]baz
',
+ '{foobarbaz
}',
+ 'foo[bar]baz
',
+ '{foobarbaz
}',
+
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=649138
+ // Chrome 15 dev fails this for some unclear reason.
+ '',
+ ],
+ //@}
+ strikethrough: [
+ //@{
+ 'foo[]bar',
+ '[foo
bar]
',
+ '[foo bar] ',
+ '[foo
bar
baz]
',
+ '[foo
bar]',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo {}bar ',
+ 'foo[ ]bar ',
+ 'foo[bar]baz',
+ 'foo[barbaz]qoz quz',
+ 'foo[barbaz]qoz quz',
+ '{
foo
}',
+
+ '',
+ '',
+ '',
+ '',
+ '',
+ '{}',
+
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar]baz ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]baz
',
+
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar]baz ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]baz
',
+
+ 'foo[bar] baz',
+ 'foo[bar]baz ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+
+ 'foo[bar] baz',
+ 'foo[bar]baz ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+
+ 'foo[bar]baz',
+ 'foo[bar]baz',
+ 'foo[bar]ba z',
+ 'foo[bar]ba z',
+ 'foo[bar]ba z',
+ 'foo[bar]ba z',
+
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+
+ 'foo[bar]baz
',
+ 'foo[bar]baz
',
+
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+
+ // Tests for queryCommandIndeterm() and queryCommandState()
+ 'fo[ob]ar baz',
+ 'fooba[r b]az',
+ 'fo[obar b]az',
+ 'foo[b]ar baz',
+ 'fooba[r ]baz',
+ 'foo[bar ]baz',
+ 'foo[bar] baz',
+ 'foo{bar }baz',
+ 'fo[ob]ar baz',
+ 'fo[o b]ar ',
+ 'fo[o b]ar',
+ ],
+ //@}
+ subscript: [
+ //@{
+ 'foo[]bar',
+ '[foo
bar]
',
+ '[foo bar] ',
+ '[foo
bar
baz]
',
+ '[foo
bar]',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo {}bar ',
+ 'foo[ ]bar ',
+ 'foo[bar]baz',
+ 'foo[barbaz]qoz quz',
+ 'foo[barbaz]qoz quz',
+ '{
foo
}',
+
+ '',
+ '',
+ '',
+ '',
+ '',
+ '{}',
+
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foob[a] r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foob[a] r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foob[a] r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foob[a] r baz',
+
+ // Tests for queryCommandIndeterm() and queryCommandState()
+ 'fo[ob]ar baz',
+ 'fooba[r b]az',
+ 'fo[obar b]az',
+ 'foo[b]ar baz',
+ 'fooba[r ]baz',
+ 'foo[bar ]baz',
+ 'foo[bar] baz',
+ 'foo{bar }baz',
+ 'fo[o b]ar ',
+ 'fo[o b]ar ',
+ 'foo[bar] baz',
+ 'fo[o b]ar ',
+ ],
+ //@}
+ superscript: [
+ //@{
+ 'foo[]bar',
+ '[foo
bar]
',
+ '[foo bar] ',
+ '[foo
bar
baz]
',
+ '[foo
bar]',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo {}bar ',
+ 'foo[ ]bar ',
+ 'foo[bar]baz',
+ 'foo[barbaz]qoz quz',
+ 'foo[barbaz]qoz quz',
+ '{
foo
}',
+
+ '',
+ '',
+ '',
+ '',
+ '',
+ '{}',
+
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foob[a] r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foob[a] r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foob[a] r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foob[a] r baz',
+
+ // Tests for queryCommandIndeterm() and queryCommandState()
+ 'fo[ob]ar baz',
+ 'fooba[r b]az',
+ 'fo[obar b]az',
+ 'foo[b]ar baz',
+ 'fooba[r ]baz',
+ 'foo[bar ]baz',
+ 'foo[bar] baz',
+ 'foo{bar }baz',
+ 'fo[o b]ar ',
+ 'fo[o b]ar ',
+ 'foo[bar] baz',
+ 'fo[o b]ar ',
+
+ // https://bugs.webkit.org/show_bug.cgi?id=28472
+ 'foo[bar] ',
+ ],
+ //@}
+ underline: [
+ //@{
+ 'foo[]bar',
+ '[foo
bar]
',
+ '[foo bar] ',
+ '[foo
bar
baz]
',
+ '[foo
bar]',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo {}bar ',
+ 'foo[ ]bar ',
+ 'foo[bar]baz',
+ 'foo[barbaz]qoz quz',
+ 'foo[barbaz]qoz quz',
+ '{
foo
}',
+
+ '',
+ '',
+ '',
+ '',
+ '',
+ '{}',
+
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar]baz ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]baz
',
+
+ 'foo[bar] baz',
+ 'foo[bar] baz',
+ 'foo[bar]baz ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]baz
',
+
+ 'foo[bar] baz',
+ 'foo[bar]baz ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+
+ 'foo[bar] baz',
+ 'foo[bar]baz ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+ 'foo[bar]ba z ',
+
+ 'foo[bar]baz',
+ 'foo[bar]baz',
+ 'foo[bar]ba z',
+ 'foo[bar]ba z',
+ 'foo[bar]ba z',
+ 'foo[bar]ba z',
+
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+
+ 'foo[bar]baz
',
+ 'foo[bar]baz
',
+
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+ 'foo[bar] baz',
+ 'foob[a]r baz',
+
+ // Tests for queryCommandIndeterm() and queryCommandState()
+ 'fo[ob]ar baz',
+ 'fooba[r b]az',
+ 'fo[obar b]az',
+ 'foo[b]ar baz',
+ 'fooba[r ]baz',
+ 'foo[bar ]baz',
+ 'foo[bar] baz',
+ 'foo{bar }baz',
+ 'fo[ob]ar baz',
+ 'fo[o b]ar ',
+ 'fo[o b]ar ',
+ ],
+ //@}
+ unlink: [
+ //@{
+ 'foo[]bar',
+ '[foo
bar]
',
+ '[foo bar] ',
+ '[foo
bar
baz]
',
+ 'foo[]bar ',
+ 'foo[]bar ',
+ 'foo {}bar ',
+ 'foo[ ]bar ',
+ 'foo[bar]baz',
+ 'foo[barbaz]qoz quz',
+ 'foo[barbaz]qoz quz',
+ '{
foo
}',
+
+ 'foo[bar]baz ',
+ 'foo[barbaz }',
+ '{foobar]baz ',
+ '{foobarbaz }',
+ '[foobarbaz] ',
+
+ 'foob[]ar baz',
+ 'foo[bar] baz',
+ 'foo[bar ]baz',
+ 'foo[bar baz]',
+ '[foobar] baz',
+ '[foobar baz]',
+
+ 'foobar[]baz ',
+ 'foo[bar]baz ',
+ '[foobarbaz] ',
+ 'foo[bar] baz',
+ 'foo[bar ]baz',
+ '[foobar baz]',
+
+ 'foobar[]baz ',
+ 'foo[bar]baz ',
+ '[foobarbaz] ',
+ 'foo[bar] baz',
+ 'foo[bar ]baz',
+ '[foobar baz]',
+ ],
+ //@}
+ copy: ['!foo[bar]baz'],
+ cut: ['!foo[bar]baz'],
+ defaultparagraphseparator: [
+ //@{
+ ['', 'foo[bar]baz'],
+ ['div', 'foo[bar]baz'],
+ ['p', 'foo[bar]baz'],
+ ['DIV', 'foo[bar]baz'],
+ ['P', 'foo[bar]baz'],
+ [' div ', 'foo[bar]baz'],
+ [' p ', 'foo[bar]baz'],
+ ['', 'foo[bar]baz'],
+ ['
', 'foo[bar]baz'],
+ ['li', 'foo[bar]baz'],
+ ['blockquote', 'foo[bar]baz'],
+ ],
+ //@}
+ paste: ['!foo[bar]baz'],
+ selectall: ['foo[bar]baz'],
+ stylewithcss: [
+ //@{
+ ['true', 'foo[bar]baz'],
+ ['TRUE', 'foo[bar]baz'],
+ ['TrUe', 'foo[bar]baz'],
+ ['true ', 'foo[bar]baz'],
+ [' true', 'foo[bar]baz'],
+ ['truer', 'foo[bar]baz'],
+ [' true ', 'foo[bar]baz'],
+ [' TrUe', 'foo[bar]baz'],
+ ['', 'foo[bar]baz'],
+ [' ', 'foo[bar]baz'],
+ ['false', 'foo[bar]baz'],
+ ['FALSE', 'foo[bar]baz'],
+ ['FaLsE', 'foo[bar]baz'],
+ [' false', 'foo[bar]baz'],
+ ['false ', 'foo[bar]baz'],
+ ['falser', 'foo[bar]baz'],
+ ['falsé', 'foo[bar]baz'],
+ ],
+ //@}
+ usecss: [
+ //@{
+ ['true', 'foo[bar]baz'],
+ ['TRUE', 'foo[bar]baz'],
+ ['TrUe', 'foo[bar]baz'],
+ ['true ', 'foo[bar]baz'],
+ [' true', 'foo[bar]baz'],
+ ['truer', 'foo[bar]baz'],
+ [' true ', 'foo[bar]baz'],
+ [' TrUe', 'foo[bar]baz'],
+ ['', 'foo[bar]baz'],
+ [' ', 'foo[bar]baz'],
+ ['false', 'foo[bar]baz'],
+ ['FALSE', 'foo[bar]baz'],
+ ['FaLsE', 'foo[bar]baz'],
+ [' false', 'foo[bar]baz'],
+ ['false ', 'foo[bar]baz'],
+ ['falser', 'foo[bar]baz'],
+ ['falsé', 'foo[bar]baz'],
+ ],
+ //@}
+ quasit: ['foo[bar]baz'],
+ multitest: [
+ //@{
+ // Insertion-affecting state. Test that insertText works right, and
+ // test that various block commands preserve (or don't preserve) the
+ // state.
+ ['foo[]bar', 'bold', 'inserttext'],
+ ['foo[]bar', 'bold', 'delete'],
+ ['foo[]bar', 'bold', 'delete', 'inserttext'],
+ ['foo[]bar', 'bold', 'formatblock'],
+ ['foo[]bar', 'bold', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'bold', 'forwarddelete'],
+ ['foo[]bar', 'bold', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'bold', 'indent'],
+ ['foo[]bar', 'bold', 'indent', 'inserttext'],
+ ['foo[]bar', 'bold', 'inserthorizontalrule'],
+ ['foo[]bar', 'bold', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'bold', 'inserthtml'],
+ ['foo[]bar', 'bold', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'bold', 'insertimage'],
+ ['foo[]bar', 'bold', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'bold', 'insertlinebreak'],
+ ['foo[]bar', 'bold', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'bold', 'insertorderedlist'],
+ ['foo[]bar', 'bold', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'bold', 'insertparagraph'],
+ ['foo[]bar', 'bold', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'bold', 'insertunorderedlist'],
+ ['foo[]bar', 'bold', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'bold', 'justifycenter'],
+ ['foo[]bar', 'bold', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'bold', 'justifyfull'],
+ ['foo[]bar', 'bold', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'bold', 'justifyleft'],
+ ['foo[]bar', 'bold', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'bold', 'justifyright'],
+ ['foo[]bar', 'bold', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'bold', 'outdent'],
+ ['foo[]bar', 'bold', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'italic', 'inserttext'],
+ ['foo[]bar', 'italic', 'delete'],
+ ['foo[]bar', 'italic', 'delete', 'inserttext'],
+ ['foo[]bar', 'italic', 'formatblock'],
+ ['foo[]bar', 'italic', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'italic', 'forwarddelete'],
+ ['foo[]bar', 'italic', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'italic', 'indent'],
+ ['foo[]bar', 'italic', 'indent', 'inserttext'],
+ ['foo[]bar', 'italic', 'inserthorizontalrule'],
+ ['foo[]bar', 'italic', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'italic', 'inserthtml'],
+ ['foo[]bar', 'italic', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'italic', 'insertimage'],
+ ['foo[]bar', 'italic', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'italic', 'insertlinebreak'],
+ ['foo[]bar', 'italic', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'italic', 'insertorderedlist'],
+ ['foo[]bar', 'italic', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'italic', 'insertparagraph'],
+ ['foo[]bar', 'italic', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'italic', 'insertunorderedlist'],
+ ['foo[]bar', 'italic', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'italic', 'justifycenter'],
+ ['foo[]bar', 'italic', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'italic', 'justifyfull'],
+ ['foo[]bar', 'italic', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'italic', 'justifyleft'],
+ ['foo[]bar', 'italic', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'italic', 'justifyright'],
+ ['foo[]bar', 'italic', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'italic', 'outdent'],
+ ['foo[]bar', 'italic', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'strikethrough', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'delete'],
+ ['foo[]bar', 'strikethrough', 'delete', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'formatblock'],
+ ['foo[]bar', 'strikethrough', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'forwarddelete'],
+ ['foo[]bar', 'strikethrough', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'indent'],
+ ['foo[]bar', 'strikethrough', 'indent', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'inserthorizontalrule'],
+ ['foo[]bar', 'strikethrough', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'inserthtml'],
+ ['foo[]bar', 'strikethrough', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'insertimage'],
+ ['foo[]bar', 'strikethrough', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'insertlinebreak'],
+ ['foo[]bar', 'strikethrough', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'insertorderedlist'],
+ ['foo[]bar', 'strikethrough', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'insertparagraph'],
+ ['foo[]bar', 'strikethrough', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'insertunorderedlist'],
+ ['foo[]bar', 'strikethrough', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'justifycenter'],
+ ['foo[]bar', 'strikethrough', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'justifyfull'],
+ ['foo[]bar', 'strikethrough', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'justifyleft'],
+ ['foo[]bar', 'strikethrough', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'justifyright'],
+ ['foo[]bar', 'strikethrough', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'strikethrough', 'outdent'],
+ ['foo[]bar', 'strikethrough', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'subscript', 'inserttext'],
+ ['foo[]bar', 'subscript', 'delete'],
+ ['foo[]bar', 'subscript', 'delete', 'inserttext'],
+ ['foo[]bar', 'subscript', 'formatblock'],
+ ['foo[]bar', 'subscript', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'subscript', 'forwarddelete'],
+ ['foo[]bar', 'subscript', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'subscript', 'indent'],
+ ['foo[]bar', 'subscript', 'indent', 'inserttext'],
+ ['foo[]bar', 'subscript', 'inserthorizontalrule'],
+ ['foo[]bar', 'subscript', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'subscript', 'inserthtml'],
+ ['foo[]bar', 'subscript', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'subscript', 'insertimage'],
+ ['foo[]bar', 'subscript', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'subscript', 'insertlinebreak'],
+ ['foo[]bar', 'subscript', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'subscript', 'insertorderedlist'],
+ ['foo[]bar', 'subscript', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'subscript', 'insertparagraph'],
+ ['foo[]bar', 'subscript', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'subscript', 'insertunorderedlist'],
+ ['foo[]bar', 'subscript', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'subscript', 'justifycenter'],
+ ['foo[]bar', 'subscript', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'subscript', 'justifyfull'],
+ ['foo[]bar', 'subscript', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'subscript', 'justifyleft'],
+ ['foo[]bar', 'subscript', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'subscript', 'justifyright'],
+ ['foo[]bar', 'subscript', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'subscript', 'outdent'],
+ ['foo[]bar', 'subscript', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'superscript', 'inserttext'],
+ ['foo[]bar', 'superscript', 'delete'],
+ ['foo[]bar', 'superscript', 'delete', 'inserttext'],
+ ['foo[]bar', 'superscript', 'formatblock'],
+ ['foo[]bar', 'superscript', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'superscript', 'forwarddelete'],
+ ['foo[]bar', 'superscript', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'superscript', 'indent'],
+ ['foo[]bar', 'superscript', 'indent', 'inserttext'],
+ ['foo[]bar', 'superscript', 'inserthorizontalrule'],
+ ['foo[]bar', 'superscript', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'superscript', 'inserthtml'],
+ ['foo[]bar', 'superscript', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'superscript', 'insertimage'],
+ ['foo[]bar', 'superscript', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'superscript', 'insertlinebreak'],
+ ['foo[]bar', 'superscript', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'superscript', 'insertorderedlist'],
+ ['foo[]bar', 'superscript', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'superscript', 'insertparagraph'],
+ ['foo[]bar', 'superscript', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'superscript', 'insertunorderedlist'],
+ ['foo[]bar', 'superscript', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'superscript', 'justifycenter'],
+ ['foo[]bar', 'superscript', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'superscript', 'justifyfull'],
+ ['foo[]bar', 'superscript', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'superscript', 'justifyleft'],
+ ['foo[]bar', 'superscript', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'superscript', 'justifyright'],
+ ['foo[]bar', 'superscript', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'superscript', 'outdent'],
+ ['foo[]bar', 'superscript', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'underline', 'inserttext'],
+ ['foo[]bar', 'underline', 'delete'],
+ ['foo[]bar', 'underline', 'delete', 'inserttext'],
+ ['foo[]bar', 'underline', 'formatblock'],
+ ['foo[]bar', 'underline', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'underline', 'forwarddelete'],
+ ['foo[]bar', 'underline', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'underline', 'indent'],
+ ['foo[]bar', 'underline', 'indent', 'inserttext'],
+ ['foo[]bar', 'underline', 'inserthorizontalrule'],
+ ['foo[]bar', 'underline', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'underline', 'inserthtml'],
+ ['foo[]bar', 'underline', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'underline', 'insertimage'],
+ ['foo[]bar', 'underline', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'underline', 'insertlinebreak'],
+ ['foo[]bar', 'underline', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'underline', 'insertorderedlist'],
+ ['foo[]bar', 'underline', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'underline', 'insertparagraph'],
+ ['foo[]bar', 'underline', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'underline', 'insertunorderedlist'],
+ ['foo[]bar', 'underline', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'underline', 'justifycenter'],
+ ['foo[]bar', 'underline', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'underline', 'justifyfull'],
+ ['foo[]bar', 'underline', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'underline', 'justifyleft'],
+ ['foo[]bar', 'underline', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'underline', 'justifyright'],
+ ['foo[]bar', 'underline', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'underline', 'outdent'],
+ ['foo[]bar', 'underline', 'outdent', 'inserttext'],
+
+ // Insertion-affecting value. Test that insertText works right, and
+ // test that various block commands preserve (or don't preserve) the
+ // value.
+ ['foo[]bar', 'backcolor', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'delete'],
+ ['foo[]bar', 'backcolor', 'delete', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'formatblock'],
+ ['foo[]bar', 'backcolor', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'forwarddelete'],
+ ['foo[]bar', 'backcolor', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'indent'],
+ ['foo[]bar', 'backcolor', 'indent', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'inserthorizontalrule'],
+ ['foo[]bar', 'backcolor', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'inserthtml'],
+ ['foo[]bar', 'backcolor', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'insertimage'],
+ ['foo[]bar', 'backcolor', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'insertlinebreak'],
+ ['foo[]bar', 'backcolor', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'insertorderedlist'],
+ ['foo[]bar', 'backcolor', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'insertparagraph'],
+ ['foo[]bar', 'backcolor', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'insertunorderedlist'],
+ ['foo[]bar', 'backcolor', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'justifycenter'],
+ ['foo[]bar', 'backcolor', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'justifyfull'],
+ ['foo[]bar', 'backcolor', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'justifyleft'],
+ ['foo[]bar', 'backcolor', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'justifyright'],
+ ['foo[]bar', 'backcolor', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'backcolor', 'outdent'],
+ ['foo[]bar', 'backcolor', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'createlink', 'inserttext'],
+ ['foo[]bar', 'createlink', 'delete'],
+ ['foo[]bar', 'createlink', 'delete', 'inserttext'],
+ ['foo[]bar', 'createlink', 'formatblock'],
+ ['foo[]bar', 'createlink', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'createlink', 'forwarddelete'],
+ ['foo[]bar', 'createlink', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'createlink', 'indent'],
+ ['foo[]bar', 'createlink', 'indent', 'inserttext'],
+ ['foo[]bar', 'createlink', 'inserthorizontalrule'],
+ ['foo[]bar', 'createlink', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'createlink', 'inserthtml'],
+ ['foo[]bar', 'createlink', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'createlink', 'insertimage'],
+ ['foo[]bar', 'createlink', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'createlink', 'insertlinebreak'],
+ ['foo[]bar', 'createlink', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'createlink', 'insertorderedlist'],
+ ['foo[]bar', 'createlink', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'createlink', 'insertparagraph'],
+ ['foo[]bar', 'createlink', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'createlink', 'insertunorderedlist'],
+ ['foo[]bar', 'createlink', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'createlink', 'justifycenter'],
+ ['foo[]bar', 'createlink', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'createlink', 'justifyfull'],
+ ['foo[]bar', 'createlink', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'createlink', 'justifyleft'],
+ ['foo[]bar', 'createlink', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'createlink', 'justifyright'],
+ ['foo[]bar', 'createlink', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'createlink', 'outdent'],
+ ['foo[]bar', 'createlink', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'fontname', 'inserttext'],
+ ['foo[]bar', 'fontname', 'delete'],
+ ['foo[]bar', 'fontname', 'delete', 'inserttext'],
+ ['foo[]bar', 'fontname', 'formatblock'],
+ ['foo[]bar', 'fontname', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'fontname', 'forwarddelete'],
+ ['foo[]bar', 'fontname', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'fontname', 'indent'],
+ ['foo[]bar', 'fontname', 'indent', 'inserttext'],
+ ['foo[]bar', 'fontname', 'inserthorizontalrule'],
+ ['foo[]bar', 'fontname', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'fontname', 'inserthtml'],
+ ['foo[]bar', 'fontname', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'fontname', 'insertimage'],
+ ['foo[]bar', 'fontname', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'fontname', 'insertlinebreak'],
+ ['foo[]bar', 'fontname', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'fontname', 'insertorderedlist'],
+ ['foo[]bar', 'fontname', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'fontname', 'insertparagraph'],
+ ['foo[]bar', 'fontname', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'fontname', 'insertunorderedlist'],
+ ['foo[]bar', 'fontname', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'fontname', 'justifycenter'],
+ ['foo[]bar', 'fontname', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'fontname', 'justifyfull'],
+ ['foo[]bar', 'fontname', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'fontname', 'justifyleft'],
+ ['foo[]bar', 'fontname', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'fontname', 'justifyright'],
+ ['foo[]bar', 'fontname', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'fontname', 'outdent'],
+ ['foo[]bar', 'fontname', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'fontsize', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'delete'],
+ ['foo[]bar', 'fontsize', 'delete', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'formatblock'],
+ ['foo[]bar', 'fontsize', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'forwarddelete'],
+ ['foo[]bar', 'fontsize', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'indent'],
+ ['foo[]bar', 'fontsize', 'indent', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'inserthorizontalrule'],
+ ['foo[]bar', 'fontsize', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'inserthtml'],
+ ['foo[]bar', 'fontsize', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'insertimage'],
+ ['foo[]bar', 'fontsize', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'insertlinebreak'],
+ ['foo[]bar', 'fontsize', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'insertorderedlist'],
+ ['foo[]bar', 'fontsize', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'insertparagraph'],
+ ['foo[]bar', 'fontsize', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'insertunorderedlist'],
+ ['foo[]bar', 'fontsize', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'justifycenter'],
+ ['foo[]bar', 'fontsize', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'justifyfull'],
+ ['foo[]bar', 'fontsize', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'justifyleft'],
+ ['foo[]bar', 'fontsize', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'justifyright'],
+ ['foo[]bar', 'fontsize', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'fontsize', 'outdent'],
+ ['foo[]bar', 'fontsize', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'forecolor', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'delete'],
+ ['foo[]bar', 'forecolor', 'delete', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'formatblock'],
+ ['foo[]bar', 'forecolor', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'forwarddelete'],
+ ['foo[]bar', 'forecolor', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'indent'],
+ ['foo[]bar', 'forecolor', 'indent', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'inserthorizontalrule'],
+ ['foo[]bar', 'forecolor', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'inserthtml'],
+ ['foo[]bar', 'forecolor', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'insertimage'],
+ ['foo[]bar', 'forecolor', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'insertlinebreak'],
+ ['foo[]bar', 'forecolor', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'insertorderedlist'],
+ ['foo[]bar', 'forecolor', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'insertparagraph'],
+ ['foo[]bar', 'forecolor', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'insertunorderedlist'],
+ ['foo[]bar', 'forecolor', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'justifycenter'],
+ ['foo[]bar', 'forecolor', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'justifyfull'],
+ ['foo[]bar', 'forecolor', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'justifyleft'],
+ ['foo[]bar', 'forecolor', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'justifyright'],
+ ['foo[]bar', 'forecolor', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'forecolor', 'outdent'],
+ ['foo[]bar', 'forecolor', 'outdent', 'inserttext'],
+
+ ['foo[]bar', 'hilitecolor', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'delete'],
+ ['foo[]bar', 'hilitecolor', 'delete', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'formatblock'],
+ ['foo[]bar', 'hilitecolor', 'formatblock', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'forwarddelete'],
+ ['foo[]bar', 'hilitecolor', 'forwarddelete', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'indent'],
+ ['foo[]bar', 'hilitecolor', 'indent', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'inserthorizontalrule'],
+ ['foo[]bar', 'hilitecolor', 'inserthorizontalrule', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'inserthtml'],
+ ['foo[]bar', 'hilitecolor', 'inserthtml', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'insertimage'],
+ ['foo[]bar', 'hilitecolor', 'insertimage', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'insertlinebreak'],
+ ['foo[]bar', 'hilitecolor', 'insertlinebreak', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'insertorderedlist'],
+ ['foo[]bar', 'hilitecolor', 'insertorderedlist', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'insertparagraph'],
+ ['foo[]bar', 'hilitecolor', 'insertparagraph', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'insertunorderedlist'],
+ ['foo[]bar', 'hilitecolor', 'insertunorderedlist', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'justifycenter'],
+ ['foo[]bar', 'hilitecolor', 'justifycenter', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'justifyfull'],
+ ['foo[]bar', 'hilitecolor', 'justifyfull', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'justifyleft'],
+ ['foo[]bar', 'hilitecolor', 'justifyleft', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'justifyright'],
+ ['foo[]bar', 'hilitecolor', 'justifyright', 'inserttext'],
+ ['foo[]bar', 'hilitecolor', 'outdent'],
+ ['foo[]bar', 'hilitecolor', 'outdent', 'inserttext'],
+
+ // Test things that interfere with each other
+ ['foo[]bar', 'superscript', 'subscript', 'inserttext'],
+ ['foo[]bar', 'subscript', 'superscript', 'inserttext'],
+
+ ['foo[]bar', 'createlink', ['forecolor', '#0000FF'], 'inserttext'],
+ ['foo[]bar', ['forecolor', '#0000FF'], 'createlink', 'inserttext'],
+ ['foo[]bar', 'createlink', ['forecolor', 'blue'], 'inserttext'],
+ ['foo[]bar', ['forecolor', 'blue'], 'createlink', 'inserttext'],
+ ['foo[]bar', 'createlink', ['forecolor', 'brown'], 'inserttext'],
+ ['foo[]bar', ['forecolor', 'brown'], 'createlink', 'inserttext'],
+ ['foo[]bar', 'createlink', ['forecolor', 'black'], 'inserttext'],
+ ['foo[]bar', ['forecolor', 'black'], 'createlink', 'inserttext'],
+ ['foo[]bar', 'createlink', 'underline', 'inserttext'],
+ ['foo[]bar', 'underline', 'createlink', 'inserttext'],
+ ['foo[]bar', 'createlink', 'underline', 'underline', 'inserttext'],
+ ['foo[]bar', 'underline', 'underline', 'createlink', 'inserttext'],
+
+ ['foo[]bar', 'subscript', ['fontsize', '2'], 'inserttext'],
+ ['foo[]bar', ['fontsize', '2'], 'subscript', 'inserttext'],
+ ['foo[]bar', 'subscript', ['fontsize', '3'], 'inserttext'],
+ ['foo[]bar', ['fontsize', '3'], 'subscript', 'inserttext'],
+
+ ['foo[]bar', ['hilitecolor', 'aqua'], ['backcolor', 'tan'], 'inserttext'],
+ ['foo[]bar', ['backcolor', 'tan'], ['hilitecolor', 'aqua'], 'inserttext'],
+
+
+ // The following are all just inserttext tests that we took from there,
+ // but we first backspace the selected text instead of letting
+ // inserttext handle it. This tests that deletion correctly sets
+ // overrides.
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+ ['foo[bar] baz', 'delete', 'inserttext'],
+
+ // Now repeat but with different selections.
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+ ['[foobar] baz', 'delete', 'inserttext'],
+
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+ ['foo[bar baz]', 'delete', 'inserttext'],
+
+ // https://bugs.webkit.org/show_bug.cgi?id=19702
+ ['
[foo] ', 'delete', 'inserttext'],
+ ],
+ //@}
+};
+tests.backcolor = tests.hilitecolor;
+tests.insertlinebreak = tests.insertparagraph;
+
+// Tests that start with "!" are believed to have bogus results and should be
+// skipped until the relevant bugs are fixed.
+var badTests = {};
+(function(){
+ for (var command in tests) {
+ badTests[command] = [];
+ for (var i = 0; i < tests[command].length; i++) {
+ var test = tests[command][i];
+ if (typeof test == "string" && test[0] == "!") {
+ test = test.slice(1);
+ tests[command][i] = test;
+ badTests[command].push(test);
+ }
+ if (typeof test == "object" && test[0][0] == "!") {
+ test = [test[0].slice(1)].concat(test.slice(1));
+ tests[command][i] = test;
+ badTests[command].push(test);
+ }
+ }
+ }
+})();
+
+var defaultValues = {
+//@{
+ backcolor: "#00FFFF",
+ createlink: "http://www.google.com/",
+ fontname: "sans-serif",
+ fontsize: "4",
+ forecolor: "#0000FF",
+ formatblock: "
",
+ hilitecolor: "#00FFFF",
+ inserthorizontalrule: "",
+ inserthtml: "ab
c d",
+ insertimage: "/img/lion.svg",
+ inserttext: "a",
+ defaultparagraphseparator: "p",
+ stylewithcss: "true",
+ usecss: "true",
+};
+//@}
+
+var notes = {
+//@{
+ fontname: 'Note that the body\'s font-family is "serif".',
+};
+//@}
+
+var doubleTestingCommands = [
+//@{
+ "backcolor",
+ "bold",
+ "fontname",
+ "fontsize",
+ "forecolor",
+ "italic",
+ "justifycenter",
+ "justifyfull",
+ "justifyleft",
+ "justifyright",
+ "strikethrough",
+ "stylewithcss",
+ "subscript",
+ "superscript",
+ "underline",
+ "usecss",
+];
+//@}
+
+function prettyPrint(value) {
+//@{
+ // Partly stolen from testharness.js
+ if (typeof value != "string") {
+ return String(value);
+ }
+
+ value = value.replace(/\\/g, "\\\\")
+ .replace(/"/g, '\\"');
+
+ for (var i = 0; i < 32; i++) {
+ var replace = "\\";
+ switch (i) {
+ case 0: replace += "0"; break;
+ case 1: replace += "x01"; break;
+ case 2: replace += "x02"; break;
+ case 3: replace += "x03"; break;
+ case 4: replace += "x04"; break;
+ case 5: replace += "x05"; break;
+ case 6: replace += "x06"; break;
+ case 7: replace += "x07"; break;
+ case 8: replace += "b"; break;
+ case 9: replace += "t"; break;
+ case 10: replace += "n"; break;
+ case 11: replace += "v"; break;
+ case 12: replace += "f"; break;
+ case 13: replace += "r"; break;
+ case 14: replace += "x0e"; break;
+ case 15: replace += "x0f"; break;
+ case 16: replace += "x10"; break;
+ case 17: replace += "x11"; break;
+ case 18: replace += "x12"; break;
+ case 19: replace += "x13"; break;
+ case 20: replace += "x14"; break;
+ case 21: replace += "x15"; break;
+ case 22: replace += "x16"; break;
+ case 23: replace += "x17"; break;
+ case 24: replace += "x18"; break;
+ case 25: replace += "x19"; break;
+ case 26: replace += "x1a"; break;
+ case 27: replace += "x1b"; break;
+ case 28: replace += "x1c"; break;
+ case 29: replace += "x1d"; break;
+ case 30: replace += "x1e"; break;
+ case 31: replace += "x1f"; break;
+ }
+ value = value.replace(new RegExp(String.fromCharCode(i), "g"), replace);
+ }
+ return '"' + value + '"';
+}
+//@}
+
+function doSetup(selector, idx) {
+//@{
+ var table = document.querySelectorAll(selector)[idx];
+
+ var tr = document.createElement("tr");
+ table.firstChild.appendChild(tr);
+ tr.className = (tr.className + " active").trim();
+
+ return tr;
+}
+//@}
+
+function queryOutputHelper(beforeIndeterm, beforeState, beforeValue,
+ afterIndeterm, afterState, afterValue,
+ command, value) {
+//@{
+ var frag = document.createDocumentFragment();
+ var beforeDiv = document.createElement("div");
+ var afterDiv = document.createElement("div");
+ frag.appendChild(beforeDiv);
+ frag.appendChild(afterDiv);
+ beforeDiv.className = afterDiv.className = "extra-results";
+ beforeDiv.textContent = "Before: ";
+ afterDiv.textContent = "After: ";
+
+ beforeDiv.appendChild(document.createElement("span"));
+ afterDiv.appendChild(document.createElement("span"));
+ if ("indeterm" in commands[command]) {
+ // We only know it has to be either true or false.
+ if (beforeIndeterm !== true && beforeIndeterm !== false) {
+ beforeDiv.lastChild.className = "bad-result";
+ }
+ } else {
+ // It always has to be false.
+ beforeDiv.lastChild.className = beforeIndeterm === false
+ ? "good-result"
+ : "bad-result";
+ }
+ // After running the command, indeterminate must always be false, except if
+ // it's an exception, or if it's insert*list and the state was true to
+ // begin with. And we can't help strikethrough/underline.
+ if ((/^insert(un)?orderedlist$/.test(command) && beforeState)
+ || command == "strikethrough"
+ || command == "underline") {
+ if (afterIndeterm !== true && afterIndeterm !== false) {
+ afterDiv.lastChild.className = "bad-result";
+ }
+ } else {
+ afterDiv.lastChild.className =
+ afterIndeterm === false
+ ? "good-result"
+ : "bad-result";
+ }
+ beforeDiv.lastChild.textContent = "indeterm " + prettyPrint(beforeIndeterm);
+ afterDiv.lastChild.textContent = "indeterm " + prettyPrint(afterIndeterm);
+
+ beforeDiv.appendChild(document.createTextNode(", "));
+ afterDiv.appendChild(document.createTextNode(", "));
+
+ beforeDiv.appendChild(document.createElement("span"));
+ afterDiv.appendChild(document.createElement("span"));
+ if (/^insert(un)?orderedlist$/.test(command)) {
+ // If the before state is true, the after state could be either true or
+ // false. But if the before state is false, the after state has to be
+ // true.
+ if (beforeState !== true && beforeState !== false) {
+ beforeDiv.lastChild.className = "bad-result";
+ }
+ if (!beforeState) {
+ afterDiv.lastChild.className = afterState === true
+ ? "good-result"
+ : "bad-result";
+ } else if (afterState !== true && afterState !== false) {
+ afterDiv.lastChild.className = "bad-result";
+ }
+ } else if (/^justify(center|full|left|right)$/.test(command)) {
+ // We don't know about the before state, but the after state is always
+ // supposed to be true.
+ if (beforeState !== true && beforeState !== false) {
+ beforeDiv.lastChild.className = "bad-result";
+ }
+ afterDiv.lastChild.className = afterState === true
+ ? "good-result"
+ : "bad-result";
+ } else if (command == "strikethrough" || command == "underline") {
+ // The only thing we can say is the before/after states need to be
+ // either true or false.
+ if (beforeState !== true && beforeState !== false) {
+ beforeDiv.lastChild.className = "bad-result";
+ }
+ if (afterState !== true && afterState !== false) {
+ afterDiv.lastChild.className = "bad-result";
+ }
+ } else {
+ // The general rule is it must flip the state, unless there's no state
+ // defined, in which case it should always be false.
+ beforeDiv.lastChild.className =
+ afterDiv.lastChild.className =
+ ("state" in commands[command] && typeof beforeState == "boolean" && typeof afterState == "boolean" && beforeState === !afterState)
+ || (!("state" in commands[command]) && beforeState === false && afterState === false)
+ ? "good-result"
+ : "bad-result";
+ }
+ beforeDiv.lastChild.textContent = "state " + prettyPrint(beforeState);
+ afterDiv.lastChild.textContent = "state " + prettyPrint(afterState);
+
+ beforeDiv.appendChild(document.createTextNode(", "));
+ afterDiv.appendChild(document.createTextNode(", "));
+
+ beforeDiv.appendChild(document.createElement("span"));
+ afterDiv.appendChild(document.createElement("span"));
+
+ // Direct equality comparison doesn't make sense in a bunch of cases.
+ if (command == "backcolor" || command == "forecolor" || command == "hilitecolor") {
+ if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) {
+ value = "#" + value;
+ }
+ } else if (command == "fontsize") {
+ value = normalizeFontSize(value);
+ if (value !== null) {
+ value = String(cssSizeToLegacy(value));
+ }
+ } else if (command == "formatblock") {
+ value = value.replace(/^<(.*)>$/, "$1").toLowerCase();
+ } else if (command == "defaultparagraphseparator") {
+ value = value.toLowerCase();
+ if (value != "p" && value != "div") {
+ value = "";
+ }
+ }
+
+ if (((command == "backcolor" || command == "forecolor" || command == "hilitecolor") && value.toLowerCase() == "currentcolor")
+ || (command == "fontsize" && value === null)
+ || (command == "formatblock" && formattableBlockNames.indexOf(value.replace(/^<(.*)>$/, "$1").trim()) == -1)
+ || (command == "defaultparagraphseparator" && value == "")) {
+ afterDiv.lastChild.className = beforeValue === afterValue
+ ? "good-result"
+ : "bad-result";
+ } else if (/^justify(center|full|left|right)$/.test(command)) {
+ // We know there are only four correct values beforehand, and afterward
+ // the value has to be the one we set.
+ if (!/^(center|justify|left|right)$/.test(beforeValue)) {
+ beforeDiv.lastChild.className = "bad-result";
+ }
+ var expectedValue = command == "justifyfull"
+ ? "justify"
+ : command.replace("justify", "");
+ afterDiv.lastChild.className = afterValue === expectedValue
+ ? "good-result"
+ : "bad-result";
+ } else if (!("value" in commands[command])) {
+ // If it's not defined we want "".
+ beforeDiv.lastChild.className = beforeValue === ""
+ ? "good-result"
+ : "bad-result";
+ afterDiv.lastChild.className = afterValue === ""
+ ? "good-result"
+ : "bad-result";
+ } else {
+ // And in all other cases, the value afterwards has to be the one we
+ // set.
+ afterDiv.lastChild.className =
+ areEquivalentValues(command, afterValue, value)
+ ? "good-result"
+ : "bad-result";
+ }
+ beforeDiv.lastChild.textContent = "value " + prettyPrint(beforeValue);
+ afterDiv.lastChild.textContent = "value " + prettyPrint(afterValue);
+
+ return frag;
+}
+//@}
+
+function normalizeTest(command, test, styleWithCss) {
+//@{
+ // Our standard format for test processing is:
+ // [input HTML, [command1, value1], [command2, value2], ...]
+ // But this is verbose, so we actually use three different formats in the
+ // tests and multiTests arrays:
+ //
+ // 1) Plain string giving the input HTML. The command is implicit from the
+ // key of the tests array. If the command takes values, the value is given
+ // by defaultValues, otherwise it's "". Has to be converted to
+ // [input HTML, [command, value].
+ //
+ // 2) Two-element array [value, input HTML]. Has to be converted to
+ // [input HTML, [command, value]].
+ //
+ // 3) An element of multiTests. This just has to have values filled in.
+ //
+ // Optionally, a styleWithCss argument can be passed, either true or false.
+ // If it is, we'll prepend a styleWithCss invocation.
+ if (command == "multitest") {
+ if (typeof test == "string") {
+ test = JSON.parse(test);
+ }
+ for (var i = 1; i < test.length; i++) {
+ if (typeof test[i] == "string"
+ && test[i] in defaultValues) {
+ test[i] = [test[i], defaultValues[test[i]]];
+ } else if (typeof test[i] == "string") {
+ test[i] = [test[i], ""];
+ }
+ }
+ return test;
+ }
+
+ if (typeof test == "string") {
+ if (command in defaultValues) {
+ test = [test, [command, defaultValues[command]]];
+ } else {
+ test = [test, [command, ""]];
+ }
+ } else if (test.length == 2) {
+ test = [test[1], [command, String(test[0])]];
+ }
+
+ if (styleWithCss !== undefined) {
+ test.splice(1, 0, ["stylewithcss", String(styleWithCss)]);
+ }
+
+ return test;
+}
+//@}
+
+function doInputCell(tr, test, command) {
+//@{
+ var testHtml = test[0];
+
+ var msg = null;
+ if (command in defaultValues) {
+ // Single command with a value, possibly with a styleWithCss stuck
+ // before. We don't need to specify the command itself, since this
+ // presumably isn't in multiTests, so the command is already given by
+ // the section header.
+ msg = 'value: ' + prettyPrint(test[test.length - 1][1]);
+ } else if (command == "multitest") {
+ // Uses a different input format
+ msg = JSON.stringify(test);
+ }
+ var inputCell = document.createElement("td");
+ inputCell.innerHTML = "
";
+ inputCell.firstChild.innerHTML = testHtml;
+ inputCell.lastChild.textContent = inputCell.firstChild.innerHTML;
+ if (msg !== null) {
+ inputCell.lastChild.textContent += " (" + msg + ")";
+ }
+
+ tr.appendChild(inputCell);
+}
+//@}
+
+function doSpecCell(tr, test, command) {
+//@{
+ var specCell = document.createElement("td");
+ tr.appendChild(specCell);
+ try {
+ var points = setupCell(specCell, test[0]);
+ var range = document.createRange();
+ range.setStart(points[0], points[1]);
+ range.setEnd(points[2], points[3]);
+ // The points might be backwards
+ if (range.collapsed) {
+ range.setEnd(points[0], points[1]);
+ }
+ specCell.firstChild.contentEditable = "true";
+ specCell.firstChild.spellcheck = false;
+
+ if (command != "multitest") {
+ try { var beforeIndeterm = myQueryCommandIndeterm(command, range) }
+ catch(e) { beforeIndeterm = "Exception" }
+ try { var beforeState = myQueryCommandState(command, range) }
+ catch(e) { beforeState = "Exception" }
+ try { var beforeValue = myQueryCommandValue(command, range) }
+ catch(e) { beforeValue = "Exception" }
+ }
+
+ for (var i = 1; i < test.length; i++) {
+ myExecCommand(test[i][0], false, test[i][1], range);
+ }
+
+ if (command != "multitest") {
+ try { var afterIndeterm = myQueryCommandIndeterm(command, range) }
+ catch(e) { afterIndeterm = "Exception" }
+ try { var afterState = myQueryCommandState(command, range) }
+ catch(e) { afterState = "Exception" }
+ try { var afterValue = myQueryCommandValue(command, range) }
+ catch(e) { afterValue = "Exception" }
+ }
+
+ specCell.firstChild.contentEditable = "inherit";
+ specCell.firstChild.removeAttribute("spellcheck");
+ var compareDiv1 = specCell.firstChild.cloneNode(true);
+
+ // Now do various sanity checks, and throw if they're violated. First
+ // just count children:
+ if (specCell.childNodes.length != 2) {
+ throw "The cell didn't have two children. Did something spill outside the test div?";
+ }
+
+ // Now verify that the DOM serializes.
+ compareDiv1.normalize();
+ var compareDiv2 = compareDiv1.cloneNode(false);
+ compareDiv2.innerHTML = compareDiv1.innerHTML;
+ // Oddly, IE9 sometimes produces two nodes that return true for
+ // isEqualNode but have different innerHTML (omitting closing tags vs.
+ // not).
+ if (!compareDiv1.isEqualNode(compareDiv2)
+ && compareDiv1.innerHTML != compareDiv2.innerHTML) {
+ throw "DOM does not round-trip through serialization! "
+ + compareDiv1.innerHTML + " vs. " + compareDiv2.innerHTML;
+ }
+ if (!compareDiv1.isEqualNode(compareDiv2)) {
+ throw "DOM does not round-trip through serialization (although innerHTML is the same)! "
+ + compareDiv1.innerHTML;
+ }
+
+ // Check for attributes
+ if (specCell.firstChild.attributes.length) {
+ throw "Wrapper div has attributes! " +
+ specCell.innerHTML.replace(/
<\/div>$/, "");
+ }
+
+ // Final sanity check: make sure everything isAllowedChild() of its
+ // parent.
+ getDescendants(specCell.firstChild).forEach(function(descendant) {
+ if (!isAllowedChild(descendant, descendant.parentNode)) {
+ throw "Something here is not an allowed child of its parent: " + descendant;
+ }
+ });
+
+ addBrackets(range);
+
+ specCell.lastChild.textContent = specCell.firstChild.innerHTML;
+ if (command != "multitest") {
+ specCell.lastChild.appendChild(queryOutputHelper(
+ beforeIndeterm, beforeState, beforeValue,
+ afterIndeterm, afterState, afterValue,
+ command, test[test.length - 1][1]));
+ if (specCell.querySelector(".bad-result")) {
+ specCell.parentNode.className = "alert";
+ }
+ }
+ } catch (e) {
+ specCell.firstChild.contentEditable = "inherit";
+ specCell.firstChild.removeAttribute("spellcheck");
+ specCell.lastChild.textContent = "Exception: " + formatException(e);
+
+ specCell.parentNode.className = "alert";
+ specCell.lastChild.className = "alert";
+
+ // Don't bother comparing to localStorage, this is always wrong no
+ // matter what.
+ return;
+ }
+
+ if (command != "multitest") {
+ // Old storage format
+ var key = "execcommand-" + command
+ + "-" + (test.length == 2 || test[1][1] == "false" ? "0" : "1")
+ + "-" + tr.firstChild.lastChild.textContent;
+ } else {
+ var key = "execcommand-" + JSON.stringify(test);
+ }
+
+ // Use getItem() instead of direct property access to work around Firefox
+ // bug: https://bugzilla.mozilla.org/show_bug.cgi?id=532062
+ var oldValue = localStorage.getItem(key);
+ var newValue = specCell.lastChild.firstChild.textContent;
+
+ // Ignore differences between {} and [].
+ if (oldValue === null
+ || oldValue.replace("{}", "[]") !== newValue.replace("{}", "[]")) {
+ specCell.parentNode.className = "alert";
+ var alertDiv = document.createElement("div");
+ specCell.lastChild.appendChild(alertDiv);
+ alertDiv.className = "alert";
+ if (oldValue === null) {
+ alertDiv.textContent = "Newly added test result";
+ } else if (oldValue.replace(/[\[\]{}]/g, "") == newValue.replace(/[\[\]{}]/g, "")) {
+ alertDiv.textContent = "Last run produced a different selection: " + oldValue;
+ } else {
+ alertDiv.textContent = "Last run produced different markup: " + oldValue;
+ }
+
+ var button = document.createElement("button");
+ alertDiv.appendChild(button);
+ button.textContent = "Store new result";
+ button.className = "store-new-result";
+ button.onclick = (function(key, val, alertDiv) { return function() {
+ localStorage[key] = val;
+ // Make it easier to do mass updates, and also to jump to the next
+ // new result
+ var buttons = document.getElementsByClassName("store-new-result");
+ for (var i = 0; i < buttons.length; i++) {
+ if (isDescendant(buttons[i], alertDiv)
+ && i + 1 < buttons.length) {
+ buttons[i + 1].focus();
+ break;
+ }
+ }
+ var td = alertDiv;
+ while (td.tagName != "TD") {
+ td = td.parentNode;
+ }
+ alertDiv.parentNode.removeChild(alertDiv);
+ if (!td.querySelector(".alert")) {
+ td.parentNode.className = (" " + td.parentNode.className + " ")
+ .replace(/ alert /g, "")
+ .replace(/^ | $/g, "");
+ }
+ } })(key, newValue, alertDiv);
+ }
+}
+//@}
+
+function browserCellException(e, testDiv, browserCell) {
+//@{
+ if (testDiv) {
+ testDiv.contenteditable = "inherit";
+ testDiv.removeAttribute("spellcheck");
+ }
+ browserCell.lastChild.className = "alert";
+ browserCell.lastChild.textContent = "Exception: " + formatException(e);
+ if (testDiv && testDiv.parentNode != browserCell) {
+ browserCell.insertBefore(testDiv, browserCell.firstChild);
+ }
+}
+//@}
+
+function formatException(e) {
+//@{
+ if (typeof e == "object" && "stack" in e) {
+ return e + " (stack: " + e.stack + ")";
+ }
+ return String(e);
+}
+//@}
+
+function doSameCell(tr) {
+//@{
+ tr.className = (" " + tr.className + " ").replace(" active ", "").trim();
+ if (tr.className == "") {
+ tr.removeAttribute("class");
+ }
+
+ var sameCell = document.createElement("td");
+ if (!document.querySelector("#browser-checkbox").checked) {
+ sameCell.className = "maybe";
+ sameCell.textContent = "?";
+ } else {
+ var exception = false;
+ try {
+ // Ad hoc normalization to avoid basically spurious mismatches. For
+ // now this includes ignoring where the selection goes.
+ var normalizedSpecCell = tr.childNodes[1].lastChild.firstChild.textContent
+ .replace(/[[\]{}]/g, "")
+ .replace(/ style="margin: 0 0 0 40px; border: none; padding: 0px;"/g, '')
+ .replace(/ style="margin-right: 0px;" dir="ltr"/g, '')
+ .replace(/ style="margin-left: 0px;" dir="rtl"/g, '')
+ .replace(/ style="margin-(left|right): 40px;"/g, '')
+ .replace(/: /g, ":")
+ .replace(/;? ?"/g, '"')
+ .replace(/<(\/?)strong/g, '<$1b')
+ .replace(/<(\/?)strike/g, '<$1s')
+ .replace(/<(\/?)em/g, '<$1i')
+ .replace(/#[0-9a-fA-F]{6}/g, function(match) { return match.toUpperCase(); });
+ var normalizedBrowserCell = tr.childNodes[2].lastChild.firstChild.textContent
+ .replace(/[[\]{}]/g, "")
+ .replace(/ style="margin: 0 0 0 40px; border: none; padding: 0px;"/g, '')
+ .replace(/ style="margin-right: 0px;" dir="ltr"/g, '')
+ .replace(/ style="margin-left: 0px;" dir="rtl"/g, '')
+ .replace(/ style="margin-(left|right): 40px;"/g, '')
+ .replace(/: /g, ":")
+ .replace(/;? ?"/g, '"')
+ .replace(/<(\/?)strong/g, '<$1b')
+ .replace(/<(\/?)strike/g, '<$1s')
+ .replace(/<(\/?)em/g, '<$1i')
+ .replace(/#[0-9a-fA-F]{6}/g, function(match) { return match.toUpperCase(); })
+ .replace(/ size="2" width="100%"/g, '');
+ if (navigator.userAgent.indexOf("MSIE") != -1) {
+ // IE produces
instead of , so let's
+ // translate all s to s.
+ normalizedSpecCell = normalizedSpecCell
+ .replace(/<(\/?)span/g, '<$1font');
+ normalizedBrowserCell = normalizedBrowserCell
+ .replace(/<(\/?)span/g, '<$1font');
+ }
+ } catch (e) {
+ exception = true;
+ }
+ if (!exception && normalizedSpecCell == normalizedBrowserCell) {
+ sameCell.className = "yes";
+ sameCell.textContent = "\u2713";
+ } else {
+ sameCell.className = "no";
+ sameCell.textContent = "\u2717";
+ }
+ }
+ tr.appendChild(sameCell);
+
+ for (var i = 0; i <= 2; i++) {
+ // Insert so IE doesn't stretch the screen. This is considerably
+ // more complicated than it has to be, thanks to Firefox's lack of
+ // support for outerHTML.
+ var div = tr.childNodes[i].lastChild;
+ if (div.firstChild) {
+ var text = div.firstChild.textContent;
+ div.removeChild(div.firstChild);
+ div.insertBefore(document.createElement("div"), div.firstChild);
+ div.firstChild.innerHTML = text
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/</g, "<");
+ while (div.firstChild.hasChildNodes()) {
+ div.insertBefore(div.firstChild.lastChild, div.firstChild.nextSibling);
+ }
+ div.removeChild(div.firstChild);
+ }
+
+ // Add position: absolute span to not affect vertical layout
+ getDescendants(tr.childNodes[i].firstChild)
+ .filter(function(node) {
+ return node.nodeType == Node.TEXT_NODE
+ && /^(\{\}?|\})$/.test(node.data);
+ }).forEach(function(node) {
+ var span = document.createElement("span");
+ span.style.position = "absolute";
+ span.textContent = node.data;
+ node.parentNode.insertBefore(span, node);
+ node.parentNode.removeChild(node);
+ });
+ }
+}
+//@}
+
+function doTearDown(command) {
+//@{
+ getSelection().removeAllRanges();
+}
+//@}
+
+function setupCell(cell, html) {
+//@{
+ cell.innerHTML = "
";
+
+ return setupDiv(cell.firstChild, html);
+}
+//@}
+
+function setupDiv(node, html) {
+//@{
+ // A variety of checks to avoid simple errors. Not foolproof, of course.
+ var re = /\{|\[|data-start/g;
+ var markers = [];
+ var marker;
+ while (marker = re.exec(html)) {
+ markers.push(marker);
+ }
+ if (markers.length != 1) {
+ throw "Need exactly one start marker ([ or { or data-start), found " + markers.length;
+ }
+
+ var re = /\}|\]|data-end/g;
+ var markers = [];
+ var marker;
+ while (marker = re.exec(html)) {
+ markers.push(marker);
+ }
+ if (markers.length != 1) {
+ throw "Need exactly one end marker (] or } or data-end), found " + markers.length;
+ }
+
+ node.innerHTML = html;
+
+ var startNode, startOffset, endNode, endOffset;
+
+ // For braces that don't lie inside text nodes, we can't just set
+ // innerHTML, because that might disturb the DOM. For instance, if the
+ // brace is right before a , it could get moved outside the table
+ // entirely, which messes everything up pretty badly. So we instead
+ // allow using data attributes: data-start and data-end on the start and
+ // end nodes, with a numeric value indicating the offset. This format
+ // doesn't allow the parent div to be a start or end node, but in that case
+ // you can always use the curly braces.
+ if (node.querySelector("[data-start]")) {
+ startNode = node.querySelector("[data-start]");
+ startOffset = startNode.getAttribute("data-start");
+ startNode.removeAttribute("data-start");
+ }
+ if (node.querySelector("[data-end]")) {
+ endNode = node.querySelector("[data-end]");
+ endOffset = endNode.getAttribute("data-end");
+ endNode.removeAttribute("data-end");
+ }
+
+ var cur = node;
+ while (true) {
+ if (!cur || (cur != node && !(cur.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_CONTAINS))) {
+ break;
+ }
+
+ if (cur.nodeType != Node.TEXT_NODE) {
+ cur = nextNode(cur);
+ continue;
+ }
+
+ var data = cur.data.replace(/\]/g, "");
+ var startIdx = data.indexOf("[");
+
+ data = cur.data.replace(/\[/g, "");
+ var endIdx = data.indexOf("]");
+
+ cur.data = cur.data.replace(/[\[\]]/g, "");
+
+ if (startIdx != -1) {
+ startNode = cur;
+ startOffset = startIdx;
+ }
+
+ if (endIdx != -1) {
+ endNode = cur;
+ endOffset = endIdx;
+ }
+
+ // These are only legal as the first or last
+ data = cur.data.replace(/\}/g, "");
+ var elStartIdx = data.indexOf("{");
+
+ data = cur.data.replace(/\{/g, "");
+ var elEndIdx = data.indexOf("}");
+
+ if (elStartIdx == 0) {
+ startNode = cur.parentNode;
+ startOffset = getNodeIndex(cur);
+ } else if (elStartIdx != -1) {
+ startNode = cur.parentNode;
+ startOffset = getNodeIndex(cur) + 1;
+ }
+ if (elEndIdx == 0) {
+ endNode = cur.parentNode;
+ endOffset = getNodeIndex(cur);
+ } else if (elEndIdx != -1) {
+ endNode = cur.parentNode;
+ endOffset = getNodeIndex(cur) + 1;
+ }
+
+ cur.data = cur.data.replace(/[{}]/g, "");
+ if (!cur.data.length) {
+ if (cur == startNode || cur == endNode) {
+ throw "You put a square bracket where there was no text node . . .";
+ }
+ var oldCur = cur;
+ cur = nextNode(cur);
+ oldCur.parentNode.removeChild(oldCur);
+ } else {
+ cur = nextNode(cur);
+ }
+ }
+
+ return [startNode, startOffset, endNode, endOffset];
+}
+//@}
+
+function setSelection(startNode, startOffset, endNode, endOffset) {
+//@{
+ if (navigator.userAgent.indexOf("Opera") != -1) {
+ // Yes, browser sniffing is evil, but I can't be bothered to debug
+ // Opera.
+ var range = document.createRange();
+ range.setStart(startNode, startOffset);
+ range.setEnd(endNode, endOffset);
+ if (range.collapsed) {
+ range.setEnd(startNode, startOffset);
+ }
+ getSelection().removeAllRanges();
+ getSelection().addRange(range);
+ } else if ("extend" in getSelection()) {
+ // WebKit behaves unreasonably for collapse(), so do that manually.
+ /*
+ var range = document.createRange();
+ range.setStart(startNode, startOffset);
+ getSelection().removeAllRanges();
+ getSelection().addRange(range);
+ */
+ getSelection().collapse(startNode, startOffset);
+ getSelection().extend(endNode, endOffset);
+ } else {
+ // IE9. Selections have no direction, so we just make the selection
+ // always forwards.
+ var range;
+ if (getSelection().rangeCount) {
+ range = getSelection().getRangeAt(0);
+ } else {
+ range = document.createRange();
+ }
+ range.setStart(startNode, startOffset);
+ range.setEnd(endNode, endOffset);
+ if (range.collapsed) {
+ // Phooey, we got them backwards.
+ range.setEnd(startNode, startOffset);
+ }
+ if (!getSelection().rangeCount) {
+ getSelection().addRange(range);
+ }
+ }
+}
+//@}
+
+/**
+ * Add brackets at the start and end points of the given range, so that they're
+ * visible.
+ */
+function addBrackets(range) {
+//@{
+ // Handle the collapsed case specially, to avoid confusingly getting the
+ // markers backwards in some cases
+ if (range.startContainer.nodeType == Node.TEXT_NODE
+ || range.startContainer.nodeType == Node.COMMENT_NODE) {
+ if (range.collapsed) {
+ range.startContainer.insertData(range.startOffset, "[]");
+ } else {
+ range.startContainer.insertData(range.startOffset, "[");
+ }
+ } else {
+ var marker = range.collapsed ? "{}" : "{";
+ if (range.startOffset != range.startContainer.childNodes.length
+ && range.startContainer.childNodes[range.startOffset].nodeType == Node.TEXT_NODE) {
+ range.startContainer.childNodes[range.startOffset].insertData(0, marker);
+ } else if (range.startOffset != 0
+ && range.startContainer.childNodes[range.startOffset - 1].nodeType == Node.TEXT_NODE) {
+ range.startContainer.childNodes[range.startOffset - 1].appendData(marker);
+ } else {
+ // Seems to serialize as I'd want even for tables . . . IE doesn't
+ // allow undefined to be passed as the second argument (it throws
+ // an exception), so we have to explicitly check the number of
+ // children and pass null.
+ range.startContainer.insertBefore(document.createTextNode(marker),
+ range.startContainer.childNodes.length == range.startOffset
+ ? null
+ : range.startContainer.childNodes[range.startOffset]);
+ }
+ }
+ if (range.collapsed) {
+ return;
+ }
+ if (range.endContainer.nodeType == Node.TEXT_NODE
+ || range.endContainer.nodeType == Node.COMMENT_NODE) {
+ range.endContainer.insertData(range.endOffset, "]");
+ } else {
+ if (range.endOffset != range.endContainer.childNodes.length
+ && range.endContainer.childNodes[range.endOffset].nodeType == Node.TEXT_NODE) {
+ range.endContainer.childNodes[range.endOffset].insertData(0, "}");
+ } else if (range.endOffset != 0
+ && range.endContainer.childNodes[range.endOffset - 1].nodeType == Node.TEXT_NODE) {
+ range.endContainer.childNodes[range.endOffset - 1].appendData("}");
+ } else {
+ range.endContainer.insertBefore(document.createTextNode("}"),
+ range.endContainer.childNodes.length == range.endOffset
+ ? null
+ : range.endContainer.childNodes[range.endOffset]);
+ }
+ }
+}
+//@}
+
+function normalizeSerializedStyle(wrapper) {
+//@{
+ // Inline CSS attribute serialization has terrible interop, so we fix
+ // things up a bit to avoid spurious mismatches. This needs to be removed
+ // once CSSOM defines this stuff properly, but for now there's just no
+ // standard for any of it. This only normalizes descendants of wrapper,
+ // not wrapper itself.
+ [].forEach.call(wrapper.querySelectorAll("[style]"), function(node) {
+ if (node.style.color != "") {
+ var newColor = normalizeColor(node.style.color);
+ node.style.color = "";
+ node.style.color = newColor;
+ }
+ if (node.style.backgroundColor != "") {
+ var newBackgroundColor = normalizeColor(node.style.backgroundColor);
+ node.style.backgroundColor = "";
+ node.style.backgroundColor = newBackgroundColor;
+ }
+ node.setAttribute("style", node.getAttribute("style")
+ // Random spacing differences
+ .replace(/; ?$/, "")
+ .replace(/: /g, ":")
+ // Gecko likes "transparent"
+ .replace(/transparent/g, "rgba(0, 0, 0, 0)")
+ // WebKit likes to look overly precise
+ .replace(/, 0.496094\)/g, ", 0.5)")
+ // Gecko converts anything with full alpha to "transparent" which
+ // then becomes "rgba(0, 0, 0, 0)", so we have to make other
+ // browsers match
+ .replace(/rgba\([0-9]+, [0-9]+, [0-9]+, 0\)/g, "rgba(0, 0, 0, 0)")
+ );
+ });
+}
+//@}
+
+/**
+ * Input is the same format as output of generateTest in gentest.html.
+ */
+function runConformanceTest(browserTest) {
+//@{
+ document.getElementById("test-container").innerHTML = "
test";
+ var testName = JSON.stringify(browserTest[1]) + " " + format_value(browserTest[0]);
+ var testDiv = document.querySelector("div[contenteditable]");
+ var originalRootElement, newRootElement;
+ var exception = null;
+ var expectedExecCommandReturnValues = browserTest[3];
+ var expectedQueryResults = browserTest[4];
+ var actualQueryResults = {};
+ var actualQueryExceptions = {};
+
+ try {
+ var points = setupDiv(testDiv, browserTest[0]);
+
+ var range = document.createRange();
+ range.setStart(points[0], points[1]);
+ range.setEnd(points[2], points[3]);
+ // The points might be backwards
+ if (range.collapsed) {
+ range.setEnd(points[0], points[1]);
+ }
+ getSelection().removeAllRanges();
+ getSelection().addRange(range);
+
+ var originalRootElement = document.documentElement.cloneNode(true);
+ originalRootElement.querySelector("[contenteditable]").parentNode
+ .removeChild(originalRootElement.querySelector("[contenteditable]"));
+ originalRootElement.querySelector("#log").parentNode
+ .removeChild(originalRootElement.querySelector("#log"));
+
+ for (var command in expectedQueryResults) {
+ var results = [];
+ var exceptions = {};
+ try { results[0] = document.queryCommandIndeterm(command) }
+ catch(e) { exceptions[0] = e }
+ try { results[1] = document.queryCommandState(command) }
+ catch(e) { exceptions[1] = e }
+ try { results[2] = document.queryCommandValue(command) }
+ catch(e) { exceptions[2] = e }
+ actualQueryResults[command] = results;
+ actualQueryExceptions[command] = exceptions;
+ }
+ } catch(e) {
+ exception = e;
+ }
+
+ for (var i = 0; i < browserTest[1].length; i++) {
+ test(function() {
+ assert_equals(exception, null, "Setup must not throw an exception");
+
+ assert_equals(document.execCommand(browserTest[1][i][0], false, browserTest[1][i][1]),
+ expectedExecCommandReturnValues[i]);
+ }, testName + ": execCommand(" + format_value(browserTest[1][i][0]) + ", false, " + format_value(browserTest[1][i][1]) + ") return value");
+ }
+
+ if (exception === null) {
+ try {
+ for (var command in expectedQueryResults) {
+ var results = actualQueryResults[command];
+ var exceptions = actualQueryExceptions[command];
+ try { results[3] = document.queryCommandIndeterm(command) }
+ catch(e) { exceptions[3] = e }
+ try { results[4] = document.queryCommandState(command) }
+ catch(e) { exceptions[4] = e }
+ try { results[5] = document.queryCommandValue(command) }
+ catch(e) { exceptions[5] = e }
+ }
+
+ var newRootElement = document.documentElement.cloneNode(true);
+ newRootElement.querySelector("[contenteditable]").parentNode
+ .removeChild(newRootElement.querySelector("[contenteditable]"));
+ newRootElement.querySelector("#log").parentNode
+ .removeChild(newRootElement.querySelector("#log"));
+
+ normalizeSerializedStyle(testDiv);
+ } catch(e) {
+ exception = e;
+ }
+ }
+
+ test(function() {
+ assert_equals(exception, null, "Setup must not throw an exception");
+
+ // Now test for modifications to non-editable content. First just
+ // count children:
+ assert_equals(testDiv.parentNode.childNodes.length, 2,
+ "The parent div must have two children. Did something spill outside the test div?");
+
+ // Check for attributes
+ assert_equals(testDiv.attributes.length, 1,
+ 'Wrapper div must have only one attribute (
), but has more (' +
+ formatStartTag(testDiv) + ")");
+
+ assert_equals(document.body.attributes.length, 0,
+ "Body element must have no attributes (), but has more (" +
+ formatStartTag(document.body) + ")");
+
+ // Check that in general, nothing outside the test div was modified.
+ // TODO: Less verbose error reporting, the way some of the range tests
+ // do?
+ assert_equals(newRootElement.innerHTML, originalRootElement.innerHTML,
+ "Everything outside the editable div must be unchanged, but some change did occur");
+ }, testName + " checks for modifications to non-editable content");
+
+ test(function() {
+ assert_equals(exception, null, "Setup must not throw an exception");
+
+ assert_equals(testDiv.innerHTML,
+ browserTest[2].replace(/[\[\]{}]/g, ""),
+ "Unexpected innerHTML (after normalizing inline style)");
+ }, testName + " compare innerHTML");
+
+ for (var command in expectedQueryResults) {
+ var descriptions = [
+ 'queryCommandIndeterm("' + command + '") before',
+ 'queryCommandState("' + command + '") before',
+ 'queryCommandValue("' + command + '") before',
+ 'queryCommandIndeterm("' + command + '") after',
+ 'queryCommandState("' + command + '") after',
+ 'queryCommandValue("' + command + '") after',
+ ];
+ for (var i = 0; i < 6; i++) {
+ test(function() {
+ assert_equals(exception, null, "Setup must not throw an exception");
+
+ if (expectedQueryResults[command][i] === null) {
+ // Some ad hoc tests to verify that we have a real
+ // DOMException. FIXME: This should be made more rigorous,
+ // with clear steps specified for checking that something
+ // is really a DOMException.
+ assert_true(i in actualQueryExceptions[command],
+ "An exception must be thrown in this case");
+ var e = actualQueryExceptions[command][i];
+ assert_equals(typeof e, "object",
+ "typeof thrown object");
+ assert_idl_attribute(e, "code",
+ "Thrown object must be a DOMException");
+ assert_idl_attribute(e, "INVALID_ACCESS_ERR",
+ "Thrown object must be a DOMException");
+ assert_equals(e.code, e.INVALID_ACCESS_ERR,
+ "Thrown object must be an INVALID_ACCESS_ERR, so its .code and .INVALID_ACCESS_ERR attributes must be equal");
+ } else if ((i == 2 || i == 5)
+ && (command == "backcolor" || command == "forecolor" || command == "hilitecolor")
+ && typeof actualQueryResults[command][i] == "string") {
+ assert_false(i in actualQueryExceptions[command],
+ "An exception must not be thrown in this case");
+ // We don't return the format that the color should be in:
+ // that's up to CSSOM. Thus we normalize before comparing.
+ assert_equals(normalizeColor(actualQueryResults[command][i]),
+ expectedQueryResults[command][i],
+ "Wrong result returned (after color normalization)");
+ } else {
+ assert_false(i in actualQueryExceptions[command],
+ "An exception must not be thrown in this case");
+ assert_equals(actualQueryResults[command][i],
+ expectedQueryResults[command][i],
+ "Wrong result returned");
+ }
+ }, testName + " " + descriptions[i]);
+ }
+ }
+
+ // Silly Firefox
+ document.body.removeAttribute("bgcolor");
+}
+//@}
+
+/**
+ * Return a string like ''.
+ */
+function formatStartTag(el) {
+//@{
+ var ret = "<" + el.tagName.toLowerCase();
+ for (var i = 0; i < el.attributes.length; i++) {
+ ret += " " + el.attributes[i].name + '="';
+ ret += el.attributes[i].value.replace(/\&/g, "&")
+ .replace(/"/g, """);
+ ret += '"';
+ }
+ return ret + ">";
+}
+//@}
+
+// vim: foldmarker=@{,@} foldmethod=marker