// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide('goog.editor.plugins.RemoveFormattingTest');
goog.setTestOnly('goog.editor.plugins.RemoveFormattingTest');
goog.require('goog.dom');
goog.require('goog.dom.Range');
goog.require('goog.dom.TagName');
goog.require('goog.editor.BrowserFeature');
goog.require('goog.editor.plugins.RemoveFormatting');
goog.require('goog.string');
goog.require('goog.testing.ExpectedFailures');
goog.require('goog.testing.dom');
goog.require('goog.testing.editor.FieldMock');
goog.require('goog.testing.editor.TestHelper');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
goog.require('goog.userAgent.product');
var SAVED_HTML;
var FIELDMOCK;
var FORMATTER;
var testHelper;
var WEBKIT_BEFORE_CHROME_8;
var WEBKIT_AFTER_CHROME_16;
var WEBKIT_AFTER_CHROME_21;
var insertImageBoldGarbage = '';
var insertImageFontGarbage = '';
var controlHtml;
var controlCleanHtml;
var expectedFailures;
function setUpPage() {
WEBKIT_BEFORE_CHROME_8 =
goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('534.10');
WEBKIT_AFTER_CHROME_16 =
goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('535.7');
WEBKIT_AFTER_CHROME_21 =
goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('537.1');
// On Chrome 16, execCommand('insertImage') inserts a garbage BR
// after the image that we insert. We use this command to paste HTML
// in-place, because it has better paragraph-preserving semantics.
//
// TODO(nicksantos): Figure out if there are better chrome APIs that we
// should be using, or if insertImage should just be fixed.
if (WEBKIT_AFTER_CHROME_21) {
insertImageBoldGarbage = '
';
insertImageFontGarbage = '
';
} else if (WEBKIT_AFTER_CHROME_16) {
insertImageBoldGarbage = '
';
insertImageFontGarbage = '
';
} else if (goog.userAgent.EDGE) {
if (goog.userAgent.product.isVersion(14)) {
insertImageFontGarbage = '';
} else {
insertImageFontGarbage =
'';
}
}
// Extra html to add to test html to make sure removeformatting is actually
// getting called when you're testing if it leaves certain styles alone
// (instead of not even running at all due to some other bug). However, adding
// this extra text into the node to be selected screws up IE.
// (e.g.
t -->
t )
// TODO(user): Remove this special casing once http://b/3131117 is
// fixed.
controlHtml = goog.userAgent.IE ? '' : 'control';
controlCleanHtml = goog.userAgent.IE ? '' : 'control';
if (goog.userAgent.EDGE) {
controlCleanHtml = 'control';
}
expectedFailures = new goog.testing.ExpectedFailures();
}
function setUp() {
testHelper =
new goog.testing.editor.TestHelper(document.getElementById('html'));
testHelper.setUpEditableElement();
FIELDMOCK = new goog.testing.editor.FieldMock();
FIELDMOCK.getElement();
FIELDMOCK.$anyTimes();
FIELDMOCK.$returns(document.getElementById('html'));
FORMATTER = new goog.editor.plugins.RemoveFormatting();
FORMATTER.fieldObject = FIELDMOCK;
FIELDMOCK.$replay();
}
function tearDown() {
expectedFailures.handleTearDown();
testHelper.tearDownEditableElement();
}
function setUpTableTests() {
var div = document.getElementById('html');
div.innerHTML = '
head1 | ' +
'head2 |
one | ' +
'two |
three | ' +
'four |
' +
' five |
' +
'seven | ' +
'eight foo |
';
}
function testTableTagsAreNotRemoved() {
setUpTableTests();
var span;
// TD
span = document.getElementById('emptyTd');
goog.dom.Range.createFromNodeContents(span).select();
FORMATTER.removeFormatting_();
var elem = document.getElementById('outerTd');
assertTrue('TD should not be removed', !!elem);
if (!goog.userAgent.WEBKIT && !goog.userAgent.EDGE) {
// webkit seems to have an Apple-style-span
assertEquals(
'TD should be clean', 'four', goog.string.trim(elem.innerHTML));
}
// TR
span = document.getElementById('outerTr');
goog.dom.Range.createFromNodeContents(span).select();
FORMATTER.removeFormatting_();
elem = document.getElementById('outerTr');
assertTrue('TR should not be removed', !!elem);
// TH
span = document.getElementById('emptyTh');
goog.dom.Range.createFromNodeContents(span).select();
FORMATTER.removeFormatting_();
elem = document.getElementById('outerTh');
assertTrue('TH should not be removed', !!elem);
if (!goog.userAgent.WEBKIT && !goog.userAgent.EDGE) {
// webkit seems to have an Apple-style-span
assertEquals('TH should be clean', 'head2', elem.innerHTML);
}
}
/**
* We select two cells from the table and then make sure that there is no
* data loss and basic formatting is removed from each cell.
*/
function testTableDataIsNotRemoved() {
setUpTableTests();
if (goog.userAgent.IE) {
// IE returns an "unspecified error" which seems to be beyond
// ExpectedFailures' ability to catch.
return;
}
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT || goog.userAgent.EDGE,
'The content moves out of the table in WebKit and Edge.');
if (goog.userAgent.IE) {
// Not used since we bail out early for IE, but this is there so that
// developers can easily reproduce IE error.
goog.dom.Range.createFromNodeContents(document.getElementById('outerTr2'))
.select();
} else {
var selection = window.getSelection();
if (selection.rangeCount > 0) selection.removeAllRanges();
var range = document.createRange();
range.selectNode(document.getElementById('cell1'));
selection.addRange(range);
range = document.createRange();
range.selectNode(document.getElementById('cell2'));
selection.addRange(range);
}
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
span = document.getElementById('outerTr2');
assertEquals(
'Table data should not be removed',
'seven | eight foo | ',
span.innerHTML);
});
}
function testLinksAreNotRemoved() {
expectedFailures.expectFailureFor(
WEBKIT_BEFORE_CHROME_8,
'WebKit\'s removeFormatting command removes links.');
var anchor;
var div = document.getElementById('html');
div.innerHTML = 'FooPre' +
'Outside SpanInside Span' +
'';
anchor = document.getElementById('link');
goog.dom.Range.createFromNodeContents(anchor).select();
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
assertHTMLEquals(
'link should not be removed',
'FooPreOutside SpanInside Span',
div.innerHTML);
});
}
/**
* A short formatting removal function for use with the RemoveFormatting
* plugin. Does enough that we can tell this function was run over the
* document.
* @param {string} text The HTML in from the document.
* @return {string} The "cleaned" HTML out.
*/
function replacementFormattingFunc(text) {
// Really basic so that we can just see this is executing.
return text.replace(/Foo/gi, 'Bar').replace(/<[\/]*span[^>]*>/gi, '');
}
function testAlternateRemoveFormattingFunction() {
var div = document.getElementById('html');
div.innerHTML = 'StartFooBar
Baz';
FORMATTER.setRemoveFormattingFunc(replacementFormattingFunc);
var area = document.getElementById('remFormat');
goog.dom.Range.createFromNodeContents(area).select();
FORMATTER.removeFormatting_();
// Webkit will change all tags to non-formatted ones anyway.
// Make sure 'Foo' was changed to 'Bar'
if (WEBKIT_BEFORE_CHROME_8) {
assertHTMLEquals(
'regular cleaner should not have run', 'StartBar
Bar
Baz',
div.innerHTML);
} else {
assertHTMLEquals(
'regular cleaner should not have run', 'StartBarBar
Baz',
div.innerHTML);
}
}
function testGetValueForNode() {
// Override getValueForNode to keep bold tags.
var oldGetValue =
goog.editor.plugins.RemoveFormatting.prototype.getValueForNode;
goog.editor.plugins.RemoveFormatting.prototype.getValueForNode = function(
node) {
if (node.nodeName == goog.dom.TagName.B) {
return '' + this.removeFormattingWorker_(node.innerHTML) + '';
}
return null;
};
var html = FORMATTER.removeFormattingWorker_('foobar
');
assertHTMLEquals('B tags should remain', 'foobar', html);
// Override getValueForNode to throw out bold tags, and their contents.
goog.editor.plugins.RemoveFormatting.prototype.getValueForNode = function(
node) {
if (node.nodeName == goog.dom.TagName.B) {
return '';
}
return null;
};
html = FORMATTER.removeFormattingWorker_('foobar
');
assertHTMLEquals('B tag and its contents should be removed', 'foo', html);
FIELDMOCK.$verify();
goog.editor.plugins.RemoveFormatting.prototype.getValueForNode = oldGetValue;
}
function testRemoveFormattingAddsNoNbsps() {
var div = document.getElementById('html');
div.innerHTML = '"Twin Cinema"';
var span = document.getElementById('toStrip');
goog.dom.Range.createFromNodeContents(span).select();
FORMATTER.removeFormatting_();
assertEquals(
'Text should be the same, with no non-breaking spaces', '"Twin Cinema"',
div.innerHTML);
FIELDMOCK.$verify();
}
/**
* @bug 992795
*/
function testRemoveFormattingNestedDivs() {
var html =
FORMATTER.removeFormattingWorker_('1
');
goog.testing.dom.assertHtmlMatches('1
2', html);
}
function testTheJavascriptReplaceMetacharacters() {
var div = document.getElementById('html');
div.innerHTML = '123 $< $> $" $& $$ $` $\' 456';
var expected = '123 $< $> $" $& $$ $` $\' 456' +
(goog.userAgent.product.SAFARI ? '
' : '');
// No idea why these
appear, but they're fairly insignificant anyways.
goog.dom.Range.createFromNodeContents(div).select();
FORMATTER.removeFormatting_();
assertHTMLEquals(
'String.prototype.replace metacharacters should not trigger', expected,
div.innerHTML);
}
/**
* Test that when we perform remove formatting on an entire table,
* that the visual look is similar to as if there was a table there.
*/
function testRemoveFormattingForTableFormatting() {
// We preserve the table formatting as much as possible.
// Spaces separate TD's,
's separate TR's.
//
's separate the start and end of a table.
var html = 'cell00 | cell01 |
' +
'cell10 | cell11 |
';
html = FORMATTER.removeFormattingWorker_(html);
assertHTMLEquals('
cell00 cell01
cell10 cell11
', html);
}
/**
* @bug 1319715
*/
function testRemoveFormattingDoesNotShrinkSelection() {
var div = document.getElementById('html');
div.innerHTML = 'l
afoo bar
';
var div2 = div.lastChild;
goog.dom.Range.createFromNodes(div2.firstChild, 0, div2.lastChild, 7)
.select();
FORMATTER.removeFormatting_();
var range = goog.dom.Range.createFromWindow();
assertEquals('Correct text should be selected', 'afoo bar', range.getText());
// We have to trim out the leading BR in IE due to execCommand issues,
// so it isn't sent off to the removeFormattingWorker.
// Workaround for broken removeFormat in old webkit added an extra
//
to the end of the html.
var html = 'l
afoo bar' +
(goog.editor.BrowserFeature.ADDS_NBSPS_IN_REMOVE_FORMAT ? '
' : '');
if (goog.userAgent.EDGE) { // TODO(user): I have no idea where this comes from
html = html.replace(' class="GECKO WEBKIT"', '');
}
goog.testing.dom.assertHtmlContentsMatch(html, div);
FIELDMOCK.$verify();
}
/**
* @bug 1447374
*/
function testInsideListRemoveFormat() {
var div = document.getElementById('html');
div.innerHTML = '';
var twoLi = div.firstChild.childNodes[1];
goog.dom.Range.createFromNodeContents(twoLi).select();
expectedFailures.expectFailureFor(
goog.userAgent.IE,
'IE adds the "two" to the "three" li, and leaves empty B tags.');
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT || goog.userAgent.EDGE,
'WebKit and Edge leave the "two" orphaned outside of an li but ' +
'inside the ul (invalid HTML).');
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
// Test that we split the list.
assertHTMLEquals(
'
two', div.innerHTML);
FIELDMOCK.$verify();
});
}
function testFullListRemoveFormat() {
var div = document.getElementById('html');
div.innerHTML = 'after';
goog.dom.Range.createFromNodeContents(div.firstChild).select();
// Note: This may just be a createFromNodeContents issue, as
// I can't ever make this happen with real user selection.
expectedFailures.expectFailureFor(
goog.userAgent.IE,
'IE combines everything into a single LI and leaves the UL.');
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
// Test that we completely remove the list.
assertHTMLEquals('
one
two
threeafter', div.innerHTML);
FIELDMOCK.$verify();
});
}
/**
* @bug 1440935
*/
function testPartialListRemoveFormat() {
var div = document.getElementById('html');
div.innerHTML = 'after';
// Select "two three after".
goog.dom.Range
.createFromNodes(div.firstChild.childNodes[1], 0, div.lastChild, 5)
.select();
expectedFailures.expectFailureFor(
goog.userAgent.IE, 'IE leaves behind an empty LI.');
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT, 'WebKit completely loses the "one".');
if (goog.userAgent.EDGE) {
// Edge leaves "two" and "threeafter" orphaned outside of an li but inside
// the ul (invalid HTML).
// Skip this test instead of using expectedFailures because this failure
// mode wrecks the DOM and causes later tests to fail as well.
return;
}
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
// Test that we leave the list start alone.
assertHTMLEquals(
'
two
threeafter', div.innerHTML);
FIELDMOCK.$verify();
});
}
function testBasicRemoveFormatting() {
// IE will clobber the editable div.
// Note: I can't repro this using normal user selections.
if (goog.userAgent.IE) {
return;
}
var div = document.getElementById('html');
div.innerHTML = 'bolditalic';
goog.dom.Range.createFromNodeContents(div).select();
expectedFailures.expectFailureFor(
goog.editor.BrowserFeature.ADDS_NBSPS_IN_REMOVE_FORMAT,
'The workaround for the nbsp bug adds an extra br at the end.');
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
assertHTMLEquals('bolditalic' + insertImageBoldGarbage, div.innerHTML);
FIELDMOCK.$verify();
});
}
/**
* @bug 1480260
*/
function testPartialBasicRemoveFormatting() {
var div = document.getElementById('html');
div.innerHTML = 'bolditalic';
goog.dom.Range
.createFromNodes(
div.firstChild.firstChild, 2, div.firstChild.lastChild.firstChild, 3)
.select();
expectedFailures.expectFailureFor(
WEBKIT_BEFORE_CHROME_8,
'WebKit just gets this all wrong. Everything stays bold and ' +
'"lditalic" gets italicised.');
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
assertHTMLEquals('bolditalic', div.innerHTML);
FIELDMOCK.$verify();
});
}
/**
* @bug 3075557
*/
function testRemoveFormattingLinkedImageBorderZero() {
var testHtml = '' +
'
';
var div = document.getElementById('html');
div.innerHTML = testHtml + controlHtml;
goog.dom.Range.createFromNodeContents(div).select();
FORMATTER.removeFormatting_();
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT, 'WebKit removes the image entirely, see ' +
'https://bugs.webkit.org/show_bug.cgi?id=13125 .');
expectedFailures.run(function() {
assertHTMLEquals(
'Image\'s border=0 should not be removed during remove formatting',
testHtml + controlCleanHtml, div.innerHTML);
FIELDMOCK.$verify();
});
}
/**
* @bug 3075557
*/
function testRemoveFormattingLinkedImageBorderNonzero() {
var testHtml = '' +
'
';
var div = document.getElementById('html');
div.innerHTML = testHtml + controlHtml;
goog.dom.Range.createFromNodeContents(div).select();
FORMATTER.removeFormatting_();
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT, 'WebKit removes the image entirely, see ' +
'https://bugs.webkit.org/show_bug.cgi?id=13125 .');
expectedFailures.run(function() {
assertHTMLEquals(
'Image\'s border should be removed during remove formatting' +
' if non-zero',
testHtml.replace(' border="1"', '') + controlCleanHtml, div.innerHTML);
FIELDMOCK.$verify();
});
}
/**
* @bug 3075557
*/
function testRemoveFormattingUnlinkedImage() {
var testHtml = '
';
var div = document.getElementById('html');
div.innerHTML = testHtml + controlHtml;
goog.dom.Range.createFromNodeContents(div).select();
FORMATTER.removeFormatting_();
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT, 'WebKit removes the image entirely, see ' +
'https://bugs.webkit.org/show_bug.cgi?id=13125 .');
expectedFailures.run(function() {
assertHTMLEquals(
'Image\'s border=0 should not be removed during remove formatting' +
' even if not wrapped by a link',
testHtml + controlCleanHtml, div.innerHTML);
FIELDMOCK.$verify();
});
}
/**
* @bug 3075557
*/
function testRemoveFormattingLinkedImageDeep() {
var testHtml = 'hello' +
'
' +
'world';
var div = document.getElementById('html');
div.innerHTML = testHtml + controlHtml;
goog.dom.Range.createFromNodeContents(div).select();
FORMATTER.removeFormatting_();
expectedFailures.expectFailureFor(
WEBKIT_BEFORE_CHROME_8, 'WebKit removes the image entirely, see ' +
'https://bugs.webkit.org/show_bug.cgi?id=13125 .');
expectedFailures.run(function() {
assertHTMLEquals(
'Image\'s border=0 should not be removed during remove formatting' +
' even if deep inside anchor tag',
testHtml.replace(/<\/?b>/g, '') + controlCleanHtml +
insertImageBoldGarbage,
div.innerHTML);
FIELDMOCK.$verify();
});
}
function testFullTableRemoveFormatting() {
// Something goes horrible wrong in case 1 below. It was crashing all
// WebKit browsers, and now seems to be giving errors as it is trying
// to perform remove formatting on the little expected failures window
// instead of the dom we select. WTF. Since I'm gutting this code,
// I'm not going to look into this anymore right now. For what its worth,
// I can't repro any issues in standalone TrogEdit.
if (goog.userAgent.WEBKIT) {
return;
}
var div = document.getElementById('html');
// WebKit has an extra BR in case 2.
expectedFailures.expectFailureFor(
goog.userAgent.IE,
'IE clobbers the editable node in case 2 (can\'t repro with real ' +
'user selections). IE doesn\'t remove the table in case 1.');
expectedFailures.run(function() {
// When a full table is selected, we remove it completely.
div.innerHTML = 'foobaz1';
goog.dom.Range.createFromNodeContents(div.childNodes[1]).select();
FORMATTER.removeFormatting_();
assertHTMLEquals('foo
bar
baz1', div.innerHTML);
FIELDMOCK.$verify();
// Remove the full table when it is selected with additional
// contents too.
div.innerHTML = 'foobaz2';
goog.dom.Range.createFromNodes(div.firstChild, 0, div.lastChild, 1)
.select();
FORMATTER.removeFormatting_();
assertHTMLEquals('foo
bar
baz2', div.innerHTML);
FIELDMOCK.$verify();
// We should still remove the table, even if the selection is inside the
// table and it is fully selected.
div.innerHTML = 'foobaz3';
goog.dom.Range.createFromNodeContents(goog.dom.getElement('td').firstChild)
.select();
FORMATTER.removeFormatting_();
assertHTMLEquals('foo
bar
baz3', div.innerHTML);
FIELDMOCK.$verify();
});
}
function testInsideTableRemoveFormatting() {
var div = document.getElementById('html');
div.innerHTML =
'';
goog.dom.Range.createFromNodeContents(goog.dom.getElement('b')).select();
// Webkit adds some apple style span crap during execCommand("removeFormat")
// Our workaround for the nbsp bug removes these, but causes worse problems.
// See bugs.webkit.org/show_bug.cgi?id=29164 for more details.
expectedFailures.expectFailureFor(
WEBKIT_BEFORE_CHROME_8 &&
!goog.editor.BrowserFeature.ADDS_NBSPS_IN_REMOVE_FORMAT,
'Extra apple-style-spans');
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
// Only remove styling from inside tables.
assertHTMLEquals(
'foo' + insertImageBoldGarbage +
' |
ba |
',
div.innerHTML);
FIELDMOCK.$verify();
});
}
function testPartialTableRemoveFormatting() {
if (goog.userAgent.IE) {
// IE returns an "unspecified error" which seems to be beyond
// ExpectedFailures' ability to catch.
return;
}
var div = document.getElementById('html');
div.innerHTML = 'bar' +
'baz
';
// Select from the "oo" inside the b tag to the end of "baz".
goog.dom.Range
.createFromNodes(
goog.dom.getElement('b').firstChild, 1,
goog.dom.getElement('baz').firstChild, 3)
.select();
// All browsers currently clobber the table cells that are selected.
expectedFailures.expectFailureFor(goog.userAgent.WEBKIT);
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
// Only remove styling from inside tables.
assertHTMLEquals(
'barbaz',
div.innerHTML);
FIELDMOCK.$verify();
});
}
// Runs tests knowing some browsers will fail, because the new
// table functionality hasn't been implemented in them yet.
function runExpectingFailuresForUnimplementedBrowsers(func) {
if (goog.userAgent.IE) {
// IE returns an "unspecified error" which seems to be beyond
// ExpectedFailures' ability to catch.
return;
}
expectedFailures.expectFailureFor(
goog.userAgent.IE, 'Proper behavior not yet implemented for IE.');
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT, 'Proper behavior not yet implemented for WebKit.');
expectedFailures.run(func);
}
function testTwoTablesSelectedFullyRemoveFormatting() {
runExpectingFailuresForUnimplementedBrowsers(function() {
var div = document.getElementById('html');
// When two tables are fully selected, we remove them completely.
div.innerHTML = '' +
'';
goog.dom.Range.createFromNodes(div.firstChild, 0, div.lastChild, 1)
.select();
FORMATTER.removeFormatting_();
assertHTMLEquals('
foo
bar
', div.innerHTML);
FIELDMOCK.$verify();
});
}
function testTwoTablesSelectedFullyInsideRemoveFormatting() {
if (goog.userAgent.WEBKIT) {
// Something goes very wrong here, but it did before
// Julie started writing v2. Will address when converting
// safari to v2.
return;
}
runExpectingFailuresForUnimplementedBrowsers(function() {
var div = document.getElementById('html');
// When two tables are selected from inside but fully,
// also remove them completely.
div.innerHTML = '' +
'';
goog.dom.Range
.createFromNodes(
goog.dom.getElement('td1').firstChild, 0,
goog.dom.getElement('td2').firstChild, 3)
.select();
FORMATTER.removeFormatting_();
assertHTMLEquals('
foo
bar
', div.innerHTML);
FIELDMOCK.$verify();
});
}
function testTwoTablesSelectedFullyAndPartiallyRemoveFormatting() {
runExpectingFailuresForUnimplementedBrowsers(function() {
var div = document.getElementById('html');
// Two tables selected, one fully, one partially. Remove
// only the fully selected one and remove styles only from
// partially selected one.
div.innerHTML = '' +
'';
goog.dom.Range
.createFromNodes(
goog.dom.getElement('td1').firstChild, 0,
goog.dom.getElement('td2').firstChild.firstChild, 2)
.select();
FORMATTER.removeFormatting_();
var expectedHtml = '
foo
' +
'';
if (goog.userAgent.EDGE) {
// TODO(user): Edge inserts an extra empty tag but is otherwise correct
expectedHtml = expectedHtml.replace('', '');
}
assertHTMLEquals(expectedHtml, div.innerHTML);
FIELDMOCK.$verify();
});
}
function testTwoTablesSelectedPartiallyRemoveFormatting() {
runExpectingFailuresForUnimplementedBrowsers(function() {
var div = document.getElementById('html');
// Two tables selected, both partially. Don't remove tables,
// but remove styles.
div.innerHTML = '' +
'';
goog.dom.Range
.createFromNodes(
goog.dom.getElement('td1').firstChild, 1,
goog.dom.getElement('td2').childNodes[1], 1)
.select();
FORMATTER.removeFormatting_();
assertHTMLEquals(
'' +
'',
div.innerHTML);
FIELDMOCK.$verify();
});
}
/**
* Test a random snippet from Google News (Google News has complicated
* dom structure, including tables, links, images, etc).
*/
function testRandomGoogleNewsSnippetRemoveFormatting() {
if (goog.userAgent.IE) {
// IE returns an "unspecified error" which seems to be beyond
// ExpectedFailures' ability to catch.
return;
}
var div = document.getElementById('html');
div.innerHTML =
'
Britney\'s son ' +
'released from hospital
NME.com - 53 minutes ago' +
'
Britney Spears� youngest son Jayden James ' +
'has been released from hospital, having been admitted on Sunday after' +
' suffering a severe reaction to something he ingested.
Britney ' +
'and Jamie Lynn Spears: Alligator Alley! The Gossip Girls
Allergy incident could spell trouble for Britney Spears ' +
'Food Consumer' +
'
People Magazine&nb' +
'sp;- E! Online - Just Jared - eF' +
'luxMedia
' +
'all 950 news articles �';
// Select it all.
goog.dom.Range.createFromNodeContents(div).select();
expectedFailures.expectFailureFor(
WEBKIT_BEFORE_CHROME_8,
'WebKit barfs apple-style-spans all over the place, and removes links.');
expectedFailures.run(function() {
FORMATTER.removeFormatting_();
// Leave links and images alone, remove all other formatting.
assertHTMLEquals(
'
![](http://n' +
'ews.google.com/news?imgefp=4LFiNNP62TgJ&imgurl=media3.washingto' +
'npost.com/wp-dyn/content/photo/2008/11/11/PH2008111101091.jpg)
' +
'Washington Post
Britney\'s son released from hospital
NME.com - 5' +
'3 minutes ago
Britney Spears� youngest son Jayden James has been' +
' released from hospital, having been admitted on Sunday after suffe' +
'ring a severe reaction to something he ingested.
Britney and Jamie Lynn Spears: ' +
'Alligator Alley! The Gossip Girls
Allergy incident c' +
'ould spell trouble for Britney Spears Food Consumer
People M' +
'agazine - E! Online - Just Jared - eFluxMedia
<' +
'a href="http://news.google.com/news?ncl=1268233361&hl=en">all 9' +
'50 news articles �' + insertImageFontGarbage,
div.innerHTML);
FIELDMOCK.$verify();
});
}
function testRangeDelimitedByRanges() {
var abcde = goog.dom.getElement('abcde').firstChild;
var start = goog.dom.Range.createFromNodes(abcde, 1, abcde, 2);
var end = goog.dom.Range.createFromNodes(abcde, 3, abcde, 4);
goog.testing.dom.assertRangeEquals(
abcde, 1, abcde, 4,
goog.editor.plugins.RemoveFormatting.createRangeDelimitedByRanges_(
start, end));
}
function testGetTableAncestor() {
var div = document.getElementById('html');
div.innerHTML = 'foobar';
assertTrue(
'Full table is in table',
!!FORMATTER.getTableAncestor_(div.childNodes[1]));
assertFalse(
'Outside of table', !!FORMATTER.getTableAncestor_(div.firstChild));
assertTrue(
'Table cell is in table',
!!FORMATTER.getTableAncestor_(
div.childNodes[1].firstChild.firstChild.firstChild));
goog.dom.setTextContent(div, 'foo');
assertNull(
'No table inside field.', FORMATTER.getTableAncestor_(div.childNodes[0]));
}
/**
* @bug 1272905
*/
function testHardReturnsInHeadersPreserved() {
var div = document.getElementById('html');
div.innerHTML = 'abcd
efgh
ijkl
';
// Select efgh.
goog.dom.Range.createFromNodeContents(div.childNodes[1]).select();
FORMATTER.removeFormatting_();
expectedFailures.expectFailureFor(
goog.userAgent.IE, 'Proper behavior not yet implemented for IE.');
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT, 'Proper behavior not yet implemented for WebKit.');
expectedFailures.run(function() {
assertHTMLEquals('abcd
efghijkl
', div.innerHTML);
});
// Select ijkl.
goog.dom.Range.createFromNodeContents(div.lastChild).select();
FORMATTER.removeFormatting_();
expectedFailures.expectFailureFor(
goog.userAgent.IE, 'Proper behavior not yet implemented for IE.');
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT, 'Proper behavior not yet implemented for WebKit.');
expectedFailures.run(function() {
assertHTMLEquals('abcd
efgh
ijkl', div.innerHTML);
});
// Select abcd.
goog.dom.Range.createFromNodeContents(div.firstChild).select();
FORMATTER.removeFormatting_();
expectedFailures.expectFailureFor(
goog.userAgent.IE, 'Proper behavior not yet implemented for IE.');
expectedFailures.expectFailureFor(
goog.userAgent.WEBKIT, 'Proper behavior not yet implemented for WebKit.');
expectedFailures.run(function() {
assertHTMLEquals('
abcd
efgh
ijkl', div.innerHTML);
});
}
function testKeyboardShortcut_space() {
FIELDMOCK.$reset();
FIELDMOCK.execCommand(
goog.editor.plugins.RemoveFormatting.REMOVE_FORMATTING_COMMAND);
FIELDMOCK.$replay();
var e = {};
var key = ' ';
var result = FORMATTER.handleKeyboardShortcut(e, key, true);
assertTrue(result);
FIELDMOCK.$verify();
}
function testKeyboardShortcut_other() {
FIELDMOCK.$reset();
FIELDMOCK.$replay();
var e = {};
var key = 'x';
var result = FORMATTER.handleKeyboardShortcut(e, key, true);
assertFalse(result);
FIELDMOCK.$verify();
}
function testCustomKeyboardShortcut_custom() {
FIELDMOCK.$reset();
FIELDMOCK.execCommand(
goog.editor.plugins.RemoveFormatting.REMOVE_FORMATTING_COMMAND);
FIELDMOCK.$replay();
var e = {};
var key = '\\';
FORMATTER.setKeyboardShortcutKey(key);
var result = FORMATTER.handleKeyboardShortcut(e, key, true);
assertTrue(result);
FIELDMOCK.$verify();
}
function testCustomKeyboardShortcut_default() {
FIELDMOCK.$reset();
FIELDMOCK.$replay();
var e = {};
var key = ' ';
FORMATTER.setKeyboardShortcutKey('\\');
var result = FORMATTER.handleKeyboardShortcut(e, key, true);
assertFalse(result);
FIELDMOCK.$verify();
}
function testKeyboardShortcut_withBothModifierKeys() {
FIELDMOCK.$reset();
FIELDMOCK.$replay();
var e = {};
e.metaKey = true;
e.ctrlKey = true;
var key = ' ';
var result = FORMATTER.handleKeyboardShortcut(e, key, true);
assertFalse(result);
FIELDMOCK.$verify();
}
function testKeyboardShortcut_withMetaKeyAndShiftKey() {
FIELDMOCK.$reset();
FIELDMOCK.$replay();
var e = {};
e.metaKey = true;
e.shiftKey = true;
var key = ' ';
var result = FORMATTER.handleKeyboardShortcut(e, key, true);
assertFalse(result);
FIELDMOCK.$verify();
}
function testKeyboardShortcut_withCtrlKeyAndShiftKey() {
FIELDMOCK.$reset();
FIELDMOCK.$replay();
var e = {};
e.ctrlKey = true;
e.shiftKey = true;
var key = ' ';
var result = FORMATTER.handleKeyboardShortcut(e, key, true);
assertFalse(result);
FIELDMOCK.$verify();
}