| <!DOCTYPE html> |
| <html> |
| <!-- |
| Copyright 2009 Google Inc. All Rights Reserved. |
| |
| Use of this source code is governed by an Apache 2.0 License. |
| See the COPYING file for details. |
| --> |
| |
| <!-- |
| Unit tests for domwalker.js. |
| --> |
| <head> |
| <title>bidichecker - Javascript Unit Tests</title> |
| <script type="text/javascript" src="../third_party/closure-library/closure/goog/base.js"> |
| </script> |
| |
| <!-- Include the generated deps.js which enables goog.require of |
| the modules under test. |
| --> |
| <script type="text/javascript" src="deps.js"></script> |
| <script type="text/javascript" src="testutils.js"></script> |
| |
| <script type="text/javascript"> |
| // This in turn pulls in the rest of the files. |
| goog.require('bidichecker.DomWalker'); |
| goog.require('bidichecker.DomWalker.EventTypes'); |
| |
| goog.require('goog.events.EventHandler'); |
| goog.require('goog.testing.jsunit'); |
| </script> |
| |
| </head> |
| <body> |
| <script type="text/javascript"> |
| |
| // Aliases for convenience in unit testing. |
| var START_TAG = bidichecker.DomWalker.EventTypes.START_TAG; |
| var END_TAG = bidichecker.DomWalker.EventTypes.END_TAG; |
| var TEXT_NODE = bidichecker.DomWalker.EventTypes.TEXT_NODE; |
| var END_OF_DOM = bidichecker.DomWalker.EventTypes.END_OF_DOM; |
| |
| |
| /** |
| * Walks the DOM using a {@code bidichecker.DomWalker}, collecting all DOM |
| * events dispatched along the way. |
| * @param {!bidichecker.DomWalker} domWalker The DOM walker. |
| * @return {Array.<!Object>} The sequence of states encountered while walking |
| * the DOM, each of which is represented by an object with fields indicating |
| * the state variables: 'type' is the event type string, 'inRtl' is the |
| * directionality (boolean), 'block' is the current lowest-level enclosing |
| * block, 'text' (if applicable) is the string contents of a text node, |
| * 'element' (if applicable) is the DOM element for a start or end tag, |
| * and 'inDeclaredDir' (if applicable) is the declared-directionality status |
| * (boolean). |
| */ |
| function walkTheDom(domWalker) { |
| var states = []; |
| |
| // Listen to all types of DOM events and collect the state of the traversal in |
| // {@code states}. |
| var handler = function(event) { |
| var state = { |
| type: event.type, |
| inRtl: domWalker.inRtl(), |
| block: domWalker.getCurrentBlock() |
| }; |
| if (event.type == TEXT_NODE) { |
| state.text = domWalker.getNode().data; |
| } else if (event.type == START_TAG || event.type == END_TAG) { |
| state.element = domWalker.getNode(); |
| } |
| if (domWalker.inDeclaredDir() != undefined) { |
| state.inDeclaredDir = domWalker.inDeclaredDir(); |
| } |
| states.push(state); |
| }; |
| |
| var eventHandler = new goog.events.EventHandler(); |
| eventHandler.listen(domWalker, |
| [START_TAG, END_TAG, TEXT_NODE, END_OF_DOM], |
| handler); |
| domWalker.go(); |
| eventHandler.removeAll(); |
| |
| return states; |
| } |
| |
| |
| /** |
| * Asserts the equality of two sequences of DOM states, as returned by |
| * {@code walkTheDom()}. |
| * @param {Array.<!Object>} expected The expected sequence of DOM states. |
| * @param {Array.<!Object>} actual The actual sequence of DOM states. |
| */ |
| function assertStatesEqual(expected, actual) { |
| // Check the lengths of the arguments. |
| assertEquals('Expected ' + expected.length + ' elements: [' + expected + |
| '], ' + 'got ' + actual.length + ' elements: [' + actual + ']', |
| expected.length, actual.length); |
| |
| // Compare individual entries by hash equality, which is a shallow equality |
| // check on the keys and values. |
| for (var i = 0; i < expected.length; ++i) { |
| // Warning: borrowing private _displayStringForValue() function from |
| // closure/testing/asserts.js. |
| assertHashEquals('Failed assertion in DOM state #' + i + ': Expected ' + |
| _displayStringForValue(expected[i]) + ', got ' + |
| _displayStringForValue(actual[i]), |
| expected[i], actual[i]); |
| } |
| } |
| |
| |
| function testDomWalker_EmptyDiv() { |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| assertEquals(testDiv, domWalker.getRootBlock()); |
| assertArrayEquals([], domWalker.getFrames()); |
| |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_TextNode() { |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}, 'test'); |
| goog.dom.appendChild(document.body, testDiv); |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: TEXT_NODE, text: 'test', |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_TwoOppositeDirParagraphs() { |
| // Two paragraphs with opposite directionality tags. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<p dir=\'rtl\'>Shalom!</p><p>Okay?</p>'; |
| var rtlPara = testDiv.firstChild; // <p dir='rtl'>... |
| var ltrPara = testDiv.childNodes[1]; // <p>Okay?</p> |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: START_TAG, element: rtlPara, |
| inRtl: true, inDeclaredDir: true, block: rtlPara}, |
| |
| {type: TEXT_NODE, text: 'Shalom!', |
| inRtl: true, inDeclaredDir: true, block: rtlPara}, |
| |
| {type: END_TAG, element: rtlPara, |
| inRtl: true, inDeclaredDir: true, block: rtlPara}, |
| |
| {type: START_TAG, element: ltrPara, |
| inRtl: false, inDeclaredDir: false, block: ltrPara}, |
| |
| {type: TEXT_NODE, text: 'Okay?', |
| inRtl: false, inDeclaredDir: false, block: ltrPara}, |
| |
| {type: END_TAG, element: ltrPara, |
| inRtl: false, inDeclaredDir: false, block: ltrPara}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_DeclaredSameDirParagraphs() { |
| // Paragraphs have explicit directionality declaration, though they're the |
| // same as the root element's. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<p dir=\'ltr\'>Shalom!</p><p dir=\'ltr\'>Okay?</p>'; |
| var para1 = testDiv.firstChild; // <p dir='ltr'>Shalom!</p> |
| var para2 = testDiv.childNodes[1]; // <p dir='ltr'>Okay?</p> |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: START_TAG, element: para1, |
| inRtl: false, inDeclaredDir: true, block: para1}, |
| |
| {type: TEXT_NODE, text: 'Shalom!', |
| inRtl: false, inDeclaredDir: true, block: para1}, |
| |
| {type: END_TAG, element: para1, |
| inRtl: false, inDeclaredDir: true, block: para1}, |
| |
| {type: START_TAG, element: para2, |
| inRtl: false, inDeclaredDir: true, block: para2}, |
| |
| {type: TEXT_NODE, text: 'Okay?', |
| inRtl: false, inDeclaredDir: true, block: para2}, |
| |
| {type: END_TAG, element: para2, |
| inRtl: false, inDeclaredDir: true, block: para2}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_DeclaredSameDirInBlock() { |
| // Text elements with the same directionality within the same block, |
| // but the second has declared directionality. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<p>Shalom! <span dir=\'ltr\'>BACK</span> Okay? </p>'; |
| var para = testDiv.firstChild; // <p>Shalom!... |
| var span = para.childNodes[1]; // <p dir='ltr'>BACK</p> |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: START_TAG, element: para, |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: TEXT_NODE, text: 'Shalom! ', |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: START_TAG, element: span, |
| inRtl: false, inDeclaredDir: true, block: para}, |
| |
| {type: TEXT_NODE, text: 'BACK', |
| inRtl: false, inDeclaredDir: true, block: para}, |
| |
| {type: END_TAG, element: span, |
| inRtl: false, inDeclaredDir: true, block: para}, |
| |
| {type: TEXT_NODE, text: ' Okay? ', |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: END_TAG, element: para, |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_EmbeddedBlockCancelsDeclaredStatus() { |
| // If a block with declared directionality contains another block inside it, |
| // we don't consider the outer block's contents to be "declared". |
| // Note: This DOM must be built with createDom(), since the HTML parser |
| // inserts unwanted paragraph breaks due to the nested paragraphs. |
| // The HTML would look like: |
| // <div id='test'><p dir='ltr'>Shalom<p dir='ltr'>BACK</p>Okay</p></div> |
| var para1 = goog.dom.createDom('p', {'dir': 'ltr'}, 'BACK'); |
| var para2 = goog.dom.createDom('p', {'dir': 'ltr'}, 'Shalom', para1, 'Okay'); |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}, para2); |
| goog.dom.appendChild(document.body, testDiv); |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: START_TAG, element: para2, |
| inRtl: false, inDeclaredDir: false, block: para2}, |
| |
| {type: TEXT_NODE, text: 'Shalom', |
| inRtl: false, inDeclaredDir: false, block: para2}, |
| |
| // "inDeclaredDir" is set only for the innermost paragraph. |
| {type: START_TAG, element: para1, |
| inRtl: false, inDeclaredDir: true, block: para1}, |
| |
| {type: TEXT_NODE, text: 'BACK', |
| inRtl: false, inDeclaredDir: true, block: para1}, |
| |
| {type: END_TAG, element: para1, |
| inRtl: false, inDeclaredDir: true, block: para1}, |
| |
| {type: TEXT_NODE, text: 'Okay', |
| inRtl: false, inDeclaredDir: false, block: para2}, |
| |
| {type: END_TAG, element: para2, |
| inRtl: false, inDeclaredDir: false, block: para2}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_EmbeddedBlockCancelsDeclaredStatusViaCss() { |
| // As above, but with the paragraph directionality declared via CSS, which |
| // causes a change in the computed directionality. |
| goog.style.installStyles('.domwalker-test-ltr { direction: ltr }'); |
| |
| // Note: This DOM must be built with createDom(), since the HTML parser |
| // inserts unwanted paragraph breaks due to the nested paragraphs. |
| // The HTML would look like: |
| // <div dir='rtl' id='test'><p class='domwalker-test-ltr'>Shalom |
| // <p dir='ltr'>BACK</p>Okay</p></div> |
| var para1 = goog.dom.createDom('p', {'dir': 'ltr'}, 'BACK'); |
| var para2 = goog.dom.createDom('p', {'class': 'domwalker-test-ltr'}, |
| 'Shalom', para1, 'Okay'); |
| var testDiv = goog.dom.createDom('div', {'dir': 'rtl', 'id': 'test'}, para2); |
| goog.dom.appendChild(document.body, testDiv); |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: true, inDeclaredDir: false, block: testDiv}, |
| |
| {type: START_TAG, element: para2, |
| inRtl: false, inDeclaredDir: false, block: para2}, |
| |
| {type: TEXT_NODE, text: 'Shalom', |
| inRtl: false, inDeclaredDir: false, block: para2}, |
| |
| // "inDeclaredDir" is set only for the innermost paragraph. |
| {type: START_TAG, element: para1, |
| inRtl: false, inDeclaredDir: true, block: para1}, |
| |
| {type: TEXT_NODE, text: 'BACK', |
| inRtl: false, inDeclaredDir: true, block: para1}, |
| |
| {type: END_TAG, element: para1, |
| inRtl: false, inDeclaredDir: true, block: para1}, |
| |
| {type: TEXT_NODE, text: 'Okay', |
| inRtl: false, inDeclaredDir: false, block: para2}, |
| |
| {type: END_TAG, element: para2, |
| inRtl: false, inDeclaredDir: false, block: para2}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: true, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: true, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_BlockChangesAfterExitingEmbeddedBlock() { |
| var testDiv = goog.dom.createDom('div', {'id': 'test', 'dir': 'rtl'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<div><div dir=\'ltr\'>Shalom</div>Okay</div>'; |
| var parentDiv = testDiv.firstChild; // <div>... |
| var ltrDiv = parentDiv.firstChild; // <div dir='ltr'>... |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: true, inDeclaredDir: false, block: testDiv}, |
| |
| {type: START_TAG, element: parentDiv, |
| inRtl: true, inDeclaredDir: false, block: parentDiv}, |
| |
| {type: START_TAG, element: ltrDiv, |
| inRtl: false, inDeclaredDir: true, block: ltrDiv}, |
| |
| {type: TEXT_NODE, text: 'Shalom', |
| inRtl: false, inDeclaredDir: true, block: ltrDiv}, |
| |
| {type: END_TAG, element: ltrDiv, |
| inRtl: false, inDeclaredDir: true, block: ltrDiv}, |
| |
| {type: TEXT_NODE, text: 'Okay', |
| inRtl: true, inDeclaredDir: false, block: parentDiv}, |
| |
| {type: END_TAG, element: parentDiv, |
| inRtl: true, inDeclaredDir: false, block: parentDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: true, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: true, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_DisplayNoneIsIgnored() { |
| // All the contents have display:none set. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<p dir=\'rtl\' style=\'display: none\'>Shalom!</p>' + |
| '<p style=\'display: none\'>Okay?</p>'; |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_VisibilityHiddenIsIgnored() { |
| // All the contents have visibility:hidden set; they should be ignored. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = |
| '<p dir=\'rtl\' style=\'visibility: hidden\'>Shalom!<\/p>'; |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_VisibilityCollapseIsIgnored() { |
| // All the contents have visibility:collapse set; they should be ignored. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = |
| '<p dir=\'rtl\' style=\'visibility: collapse\'>Shalom!<\/p>'; |
| var para = testDiv.firstChild; |
| |
| // Some browsers (in particular, IE7) do not support visiblity:collapse; skip |
| // the test in that case. |
| if (!para.style.visibility) { |
| return; |
| } |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_ScriptAndStyleAreIgnored() { |
| // <style> shouldn't really appear in the body, but sometimes it does. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<\script dir=\'rtl\'>if (true) x=7;</\script>' + |
| '<style>A b c d e f g</style>'; |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_TextareaContentsAreIgnored() { |
| // Text nodes inside a <textarea> are not inline with the surrounding text. |
| // We ignore them completely, instead processing the textarea value property |
| // (which contains the up-to-date text) in the undeclared field detector. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<textarea>A b c d e f g<\/textarea>'; |
| var textarea = testDiv.firstChild; |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: START_TAG, element: textarea, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: textarea, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_NoscriptIsIgnored() { |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<noscript><p>In a noscript tag.</p></noscript>'; |
| |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_CanWalkAnIframe() { |
| // Create an iframe in the document. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<iframe id=\'iframe\'></iframe>'; |
| // For iframes to work, the div must belong to a document. |
| goog.dom.appendChild(document.body, testDiv); |
| |
| // Fill the iframe with two "hello world" div's. |
| var iframe = testDiv.firstChild; |
| var iframeDoc = |
| goog.dom.getFrameContentDocument(/** @type {Element} */ (iframe)); |
| iframeDoc.open(); |
| iframeDoc.write('<div id=line1>hello world<\/div>' + |
| '<div id=line2>hello world<\/div>'); |
| iframeDoc.close(); |
| var iframeRoot = iframeDoc.body; |
| |
| // Walk the DOM; this should also collect the iframes. |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| var states = walkTheDom(domWalker); |
| var expected = [{type: START_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: START_TAG, element: iframe, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: iframe, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_TAG, element: testDiv, |
| inRtl: false, inDeclaredDir: false, block: testDiv}, |
| |
| {type: END_OF_DOM, inRtl: false, block: testDiv} |
| ]; |
| assertStatesEqual(expected, states); |
| assertArrayEquals([iframe], domWalker.getFrames()); |
| |
| // Access the elements for the div's inside the iframe. |
| var iframeHelper = new goog.dom.DomHelper(iframeDoc); |
| var line1 = iframeHelper.getElement('line1'); |
| var line2 = iframeHelper.getElement('line2'); |
| |
| // Now walk the DOM for the iframe, with a new DomWalker. |
| var iframeDomWalker = new bidichecker.DomWalker(iframeRoot); |
| states = walkTheDom(iframeDomWalker); |
| expected = [{type: START_TAG, element: iframeRoot, |
| inRtl: false, inDeclaredDir: false, block: iframeRoot}, |
| |
| {type: START_TAG, element: line1, |
| inRtl: false, inDeclaredDir: false, block: line1}, |
| |
| {type: TEXT_NODE, text: 'hello world', |
| inRtl: false, inDeclaredDir: false, block: line1}, |
| |
| {type: END_TAG, element: line1, |
| inRtl: false, inDeclaredDir: false, block: line1}, |
| |
| {type: START_TAG, element: line2, |
| inRtl: false, inDeclaredDir: false, block: line2}, |
| |
| {type: TEXT_NODE, text: 'hello world', |
| inRtl: false, inDeclaredDir: false, block: line2}, |
| |
| {type: END_TAG, element: line2, |
| inRtl: false, inDeclaredDir: false, block: line2}, |
| |
| {type: END_TAG, element: iframeRoot, |
| inRtl: false, inDeclaredDir: false, block: iframeRoot}, |
| |
| {type: END_OF_DOM, inRtl: false, block: iframeRoot} |
| ]; |
| assertStatesEqual(expected, states); |
| assertArrayEquals([], iframeDomWalker.getFrames()); // No nested iframes. |
| } |
| |
| |
| function testDomWalker_CanWalkMultipleIframes() { |
| // This time, there's more than iframe on the page, and there are nested |
| // iframes too. |
| |
| // Create two iframes in the document. |
| var testDiv = goog.dom.createDom('div', {'id': 'test'}); |
| goog.dom.appendChild(document.body, testDiv); |
| testDiv.innerHTML = '<iframe id=\'iframe1\'><\/iframe>' + |
| '<iframe id=\'iframe2\'><\/iframe>'; |
| goog.dom.appendChild(document.body, testDiv); |
| |
| // Fill the first iframe with content. |
| var iframe1 = testDiv.firstChild; |
| var iframe1Doc = |
| goog.dom.getFrameContentDocument(/** @type {Element} */ (iframe1)); |
| iframe1Doc.open(); |
| iframe1Doc.write('<p>hello world<\/p>'); |
| iframe1Doc.close(); |
| var iframe1Root = iframe1Doc.body; |
| |
| // Fill the second iframe with a nested iframe. |
| var iframe2 = testDiv.childNodes[1]; |
| var iframe2Doc = goog.dom.getFrameContentDocument(iframe2); |
| iframe2Doc.open(); |
| iframe2Doc.write('<iframe id=\'iframe_nested\'><\/iframe>'); |
| iframe2Doc.close(); |
| var iframe2Root = iframe2Doc.body; |
| |
| // Fill the nested iframe with content. |
| var iframe3 = iframe2Root.firstChild; |
| var iframe3Doc = |
| goog.dom.getFrameContentDocument(/** @type {Element} */ (iframe3)); |
| iframe3Doc.open(); |
| iframe3Doc.write('<p id=\'para\'>In a nested iframe!<\/p>'); |
| iframe3Doc.close(); |
| var iframe3Root = iframe3Doc.body; |
| |
| // Walk the DOM; this should also collect the iframes. |
| var domWalker = new bidichecker.DomWalker(testDiv); |
| walkTheDom(domWalker); |
| |
| // No need to bother testing the state machine here. Just make sure we've |
| // seen both top-level iframes. |
| var expectedFrames = [iframe1, iframe2]; |
| assertArrayEquals(expectedFrames, domWalker.getFrames()); |
| |
| |
| // Now walk the DOM for the first iframe, with a new DomWalker. No new iframes |
| // there. |
| var iframe1DomWalker = new bidichecker.DomWalker(iframe1Root); |
| walkTheDom(iframe1DomWalker); |
| assertArrayEquals([], iframe1DomWalker.getFrames()); |
| |
| // Now walk the DOM for the second iframe, revealing a third, nested, iframe. |
| // there. |
| var iframe2DomWalker = new bidichecker.DomWalker(iframe2Root); |
| walkTheDom(iframe2DomWalker); |
| assertArrayEquals([iframe3], iframe2DomWalker.getFrames()); |
| |
| // Finally, walk the DOM for the third iframe, with a new DomWalker. No new |
| // iframes there. |
| var iframe3DomWalker = new bidichecker.DomWalker(iframe3Root); |
| var states = walkTheDom(iframe3DomWalker); |
| assertArrayEquals([], iframe3DomWalker.getFrames()); |
| |
| // This time, we'll also check the DOM in the nested iframe. |
| var iframeHelper = new goog.dom.DomHelper(iframe3Doc); |
| var para = iframeHelper.getElement('para'); |
| var expected = [{type: START_TAG, element: iframe3Root, |
| inRtl: false, inDeclaredDir: false, block: iframe3Root}, |
| |
| {type: START_TAG, element: para, |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: TEXT_NODE, text: 'In a nested iframe!', |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: END_TAG, element: para, |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: END_TAG, element: iframe3Root, |
| inRtl: false, inDeclaredDir: false, block: iframe3Root}, |
| |
| {type: END_OF_DOM, inRtl: false, block: iframe3Root} |
| ]; |
| assertStatesEqual(expected, states); |
| } |
| |
| |
| function testDomWalker_CanWalkAFrameSet() { |
| // There doesn't seem to be a way to create a frameset using Javascript under |
| // IE; disable this test. |
| if (goog.userAgent.IE) { |
| return; |
| } |
| |
| var frameset = goog.dom.createDom('frameset', {'rows': '*,*', 'id': 'test' }, |
| goog.dom.createDom('frame'), goog.dom.createDom('frame')); |
| document.documentElement.appendChild(frameset); |
| |
| // Add a paragraph of text to the first frame. |
| var frame1 = frameset.firstChild; |
| var frame2 = frameset.childNodes[1]; |
| var frame1Doc = |
| goog.dom.getFrameContentDocument(/** @type {Element} */ (frame1)); |
| var frame1Root = frame1Doc.body; |
| frame1Root.appendChild(goog.dom.createDom('p', null, 'testing')); |
| |
| // Walk the top-level DOM for the frameset. |
| var domWalker = new bidichecker.DomWalker(frameset); |
| var states = walkTheDom(domWalker); |
| |
| var expected = [{type: START_TAG, element: frameset, |
| inRtl: false, inDeclaredDir: false, block: frameset}, |
| |
| {type: START_TAG, element: frame1, |
| inRtl: false, inDeclaredDir: false, block: frameset}, |
| |
| {type: END_TAG, element: frame1, |
| inRtl: false, inDeclaredDir: false, block: frameset}, |
| |
| {type: START_TAG, element: frame2, |
| inRtl: false, inDeclaredDir: false, block: frameset}, |
| |
| {type: END_TAG, element: frame2, |
| inRtl: false, inDeclaredDir: false, block: frameset}, |
| |
| {type: END_TAG, element: frameset, |
| inRtl: false, inDeclaredDir: false, block: frameset}, |
| |
| {type: END_OF_DOM, inRtl: false, block: frameset} |
| ]; |
| assertStatesEqual(expected, states); |
| |
| assertArrayEquals([frame1, frame2], domWalker.getFrames()); |
| |
| // Now walk the DOM for the first frame, with a new DomWalker. |
| var frame1DomWalker = new bidichecker.DomWalker(frame1Root); |
| states = walkTheDom(frame1DomWalker); |
| |
| var para = frame1Root.firstChild; |
| expected = [{type: START_TAG, element: frame1Root, |
| inRtl: false, inDeclaredDir: false, block: frame1Root}, |
| |
| {type: START_TAG, element: para, |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: TEXT_NODE, text: 'testing', |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: END_TAG, element: para, |
| inRtl: false, inDeclaredDir: false, block: para}, |
| |
| {type: END_TAG, element: frame1Root, |
| inRtl: false, inDeclaredDir: false, block: frame1Root}, |
| |
| {type: END_OF_DOM, inRtl: false, block: frame1Root} |
| ]; |
| assertStatesEqual(expected, states); |
| |
| assertArrayEquals([], frame1DomWalker.getFrames()); |
| } |
| |
| </script> |
| |
| </body> |
| </html> |