| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>Testing Widows and Orphans</title> |
| <style> |
| body.hide-containers .container { |
| display: none; |
| } |
| |
| .container { |
| width: 600px; |
| height: 200px; |
| -webkit-columns: 3; |
| -webkit-column-fill: auto; |
| columns: 3; |
| column-fill: auto; |
| line-height: 20px; /* 10 lines per page */ |
| font-size: 16px; |
| margin: 0 0 20px 0; |
| padding: 0; |
| overflow: hidden; |
| } |
| |
| .block { |
| margin: 0 0 15px 0; |
| padding: 0; |
| } |
| |
| .top { |
| color: red; |
| } |
| |
| .bottom { |
| color: green; |
| } |
| </style> |
| <script> |
| var results; |
| |
| function createTestContainer(id, description, blocks) |
| { |
| var label = document.createElement("h3"); |
| label.textContent = id + " - " + description; |
| document.body.appendChild(label); |
| var element = document.createElement("div"); |
| element.className = "container"; |
| element.id = id; |
| |
| for (var i = 1; i <= blocks.length; i++) { |
| var block = document.createElement("div"); |
| block.className = "block"; |
| var numLines = blocks[i-1]; |
| for (var j = 1; j <= numLines; j++) { |
| var line = document.createElement("span"); |
| line.id = id + "-block-" + i + "-line-" + j; |
| line.textContent = "Block " + i + " Line " + j; |
| block.appendChild(line); |
| block.appendChild(document.createElement("br")); |
| } |
| element.appendChild(block); |
| } |
| document.body.appendChild(element); |
| return element; |
| } |
| |
| function markTopLine(containerId, blockNumber, lineNumber) |
| { |
| var element = document.getElementById(containerId + "-block-" + blockNumber + "-line-" + lineNumber); |
| element.className = "top"; |
| } |
| |
| function markBottomLine(containerId, blockNumber, lineNumber) |
| { |
| var element = document.getElementById(containerId + "-block-" + blockNumber + "-line-" + lineNumber); |
| element.className = "bottom"; |
| } |
| |
| function logPass(msg) { |
| log("PASS: " + msg); |
| } |
| |
| function logFail(msg) { |
| log("FAIL: " + msg); |
| } |
| |
| function log(msg) { |
| if (!results) |
| results = document.createElement("div"); |
| |
| var output = document.createElement("p"); |
| output.textContent = msg; |
| results.appendChild(output); |
| } |
| |
| function testIsFirstInColumn(containerId, blockNumber, lineNumber) |
| { |
| // Get the upper bounds of the container and line. |
| var topOfContainer = document.getElementById(containerId).getBoundingClientRect().top; |
| var topOfLine = document.getElementById(containerId + "-block-" + blockNumber + "-line-" + lineNumber).getBoundingClientRect().top; |
| |
| if (Math.abs(topOfContainer - topOfLine) < 5) // Give 5 pixels to account for subpixel layout. |
| logPass(containerId + " Block " + blockNumber + " Line " + lineNumber + " is correct."); |
| else |
| logFail(containerId + " Block " + blockNumber + " Line " + lineNumber + " wasn't at the top of the column."); |
| } |
| |
| function runTest() |
| { |
| var container; |
| |
| createTestContainer("test1", "Normal breaking", [5, 6, 5, 5]); |
| |
| markTopLine("test1", 1, 1); |
| markBottomLine("test1", 2, 4); |
| markTopLine("test1", 2, 5); |
| markBottomLine("test1", 4, 1); |
| markTopLine("test1", 4, 2); |
| |
| testIsFirstInColumn("test1", 1, 1); |
| testIsFirstInColumn("test1", 2, 5); |
| testIsFirstInColumn("test1", 4, 2); |
| |
| container = createTestContainer("test2", "Basic Orphan", [8, 6]); |
| container.style.orphans = 2; |
| |
| markTopLine("test2", 1, 1); |
| markBottomLine("test2", 1, 8); // Orphan break happens here. |
| markTopLine("test2", 2, 1); |
| |
| testIsFirstInColumn("test2", 1, 1); |
| testIsFirstInColumn("test2", 2, 1); |
| |
| container = createTestContainer("test3", "Basic Widow", [4, 6, 3]); |
| container.style.widows = 2; |
| |
| markTopLine("test3", 1, 1); |
| markBottomLine("test3", 2, 4); // Widow break happens here. |
| markTopLine("test3", 2, 5); |
| |
| testIsFirstInColumn("test3", 1, 1); |
| testIsFirstInColumn("test3", 2, 5); |
| |
| container = createTestContainer("test4", "Orphans causing Widows", [8, 6, 4, 4]); |
| container.style.orphans = 2; |
| container.style.widows = 2; |
| |
| markTopLine("test4", 1, 1); |
| markBottomLine("test4", 1, 8); // Orphan break happens here. |
| markTopLine("test4", 2, 1); |
| markBottomLine("test4", 3, 2); // And that creates a widow forcing a break here. |
| markTopLine("test4", 3, 3); |
| |
| testIsFirstInColumn("test4", 1, 1); |
| testIsFirstInColumn("test4", 2, 1); |
| testIsFirstInColumn("test4", 3, 3); |
| |
| container = createTestContainer("test5", "Widows blocked by Orphan rule", [7, 3, 4]); |
| container.style.orphans = 2; |
| container.style.widows = 2; |
| |
| markTopLine("test5", 1, 1); |
| markBottomLine("test5", 2, 2); // This line should not move - protected by orphaning. |
| markTopLine("test5", 2, 3); // This line won't be un-widowed - blocked by orphaning. |
| |
| testIsFirstInColumn("test5", 1, 1); |
| testIsFirstInColumn("test5", 2, 3); |
| |
| container = createTestContainer("test6", "Ridiculous values", [7, 7, 7, 7]); |
| container.style.orphans = 100; |
| container.style.widows = 100; |
| |
| markTopLine("test6", 1, 1); |
| markBottomLine("test6", 1, 7); // Orphan break happens here. |
| markTopLine("test6", 2, 1); // Adopted. |
| markBottomLine("test6", 2, 7); // Orphan break. |
| markTopLine("test6", 3, 1); // Adopted. |
| |
| testIsFirstInColumn("test6", 1, 1); |
| testIsFirstInColumn("test6", 2, 1); |
| testIsFirstInColumn("test6", 3, 1); |
| |
| if (results) |
| document.body.appendChild(results); |
| |
| if (window.testRunner) { |
| // Hide all the containers and leave just the test results for text output. |
| document.body.className = "hide-containers"; |
| testRunner.notifyDone(); |
| } |
| } |
| |
| if (window.testRunner) { |
| testRunner.dumpAsText(); |
| testRunner.waitUntilDone(); |
| } |
| |
| window.addEventListener("load", runTest, false); |
| </script> |
| </head> |
| <body> |
| <p> |
| Testing widows and orphans. Any green lines |
| should be at the bottom of pages/columns, and any red lines |
| should be at the top of pages/columns. |
| </p> |
| </body> |
| </html> |