accessible/tests/mochitest/events/test_focus_autocomplete.xul

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 <?xml version="1.0"?>
michael@0 2 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
michael@0 3 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
michael@0 4 type="text/css"?>
michael@0 5
michael@0 6 <!-- Firefox searchbar -->
michael@0 7 <?xml-stylesheet href="chrome://browser/content/browser.css"
michael@0 8 type="text/css"?>
michael@0 9 <!-- SeaMonkey searchbar -->
michael@0 10 <?xml-stylesheet href="chrome://navigator/content/navigator.css"
michael@0 11 type="text/css"?>
michael@0 12
michael@0 13 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
michael@0 14 title="Accessible focus event testing">
michael@0 15
michael@0 16 <script type="application/javascript"
michael@0 17 src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
michael@0 18 <script type="application/javascript"
michael@0 19 src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
michael@0 20
michael@0 21 <script type="application/javascript"
michael@0 22 src="../common.js" />
michael@0 23 <script type="application/javascript"
michael@0 24 src="../role.js" />
michael@0 25 <script type="application/javascript"
michael@0 26 src="../states.js" />
michael@0 27 <script type="application/javascript"
michael@0 28 src="../events.js" />
michael@0 29
michael@0 30 <script type="application/javascript"
michael@0 31 src="../autocomplete.js" />
michael@0 32
michael@0 33 <script type="application/javascript">
michael@0 34 <![CDATA[
michael@0 35 ////////////////////////////////////////////////////////////////////////////
michael@0 36 // Hacky stuffs
michael@0 37
michael@0 38 // This is the hack needed for searchbar work outside of browser.
michael@0 39 function getBrowser()
michael@0 40 {
michael@0 41 return {
michael@0 42 mCurrentBrowser: { engines: new Array() }
michael@0 43 };
michael@0 44 }
michael@0 45
michael@0 46 ////////////////////////////////////////////////////////////////////////////
michael@0 47 // Invokers
michael@0 48
michael@0 49 function loadFormAutoComplete(aIFrameID)
michael@0 50 {
michael@0 51 this.iframeNode = getNode(aIFrameID);
michael@0 52 this.iframe = getAccessible(aIFrameID);
michael@0 53
michael@0 54 this.eventSeq = [
michael@0 55 new invokerChecker(EVENT_REORDER, this.iframe)
michael@0 56 ];
michael@0 57
michael@0 58 this.invoke = function loadFormAutoComplete_invoke()
michael@0 59 {
michael@0 60 var url = "data:text/html,<html><body><form id='form'>" +
michael@0 61 "<input id='input' name='a11ytest-formautocomplete'>" +
michael@0 62 "</form></body></html>";
michael@0 63 this.iframeNode.setAttribute("src", url);
michael@0 64 }
michael@0 65
michael@0 66 this.getID = function loadFormAutoComplete_getID()
michael@0 67 {
michael@0 68 return "load form autocomplete page";
michael@0 69 }
michael@0 70 }
michael@0 71
michael@0 72 function initFormAutoCompleteBy(aIFrameID, aAutoCompleteValue)
michael@0 73 {
michael@0 74 this.iframe = getAccessible(aIFrameID);
michael@0 75
michael@0 76 this.eventSeq = [
michael@0 77 new invokerChecker(EVENT_REORDER, this.iframe)
michael@0 78 ];
michael@0 79
michael@0 80 this.invoke = function initFormAutoCompleteBy_invoke()
michael@0 81 {
michael@0 82 var iframeDOMDoc = getIFrameDOMDoc(aIFrameID);
michael@0 83
michael@0 84 var inputNode = iframeDOMDoc.getElementById("input");
michael@0 85 inputNode.value = aAutoCompleteValue;
michael@0 86 var formNode = iframeDOMDoc.getElementById("form");
michael@0 87 formNode.submit();
michael@0 88 }
michael@0 89
michael@0 90 this.getID = function initFormAutoCompleteBy_getID()
michael@0 91 {
michael@0 92 return "init form autocomplete by '" + aAutoCompleteValue + "'";
michael@0 93 }
michael@0 94 }
michael@0 95
michael@0 96 function loadHTML5ListAutoComplete(aIFrameID)
michael@0 97 {
michael@0 98 this.iframeNode = getNode(aIFrameID);
michael@0 99 this.iframe = getAccessible(aIFrameID);
michael@0 100
michael@0 101 this.eventSeq = [
michael@0 102 new invokerChecker(EVENT_REORDER, this.iframe)
michael@0 103 ];
michael@0 104
michael@0 105 this.invoke = function loadHTML5ListAutoComplete_invoke()
michael@0 106 {
michael@0 107 var url = "data:text/html,<html><body>" +
michael@0 108 "<datalist id='cities'><option>hello</option><option>hi</option></datalist>" +
michael@0 109 "<input id='input' list='cities'>" +
michael@0 110 "</body></html>";
michael@0 111 this.iframeNode.setAttribute("src", url);
michael@0 112 }
michael@0 113
michael@0 114 this.getID = function loadHTML5ListAutoComplete_getID()
michael@0 115 {
michael@0 116 return "load HTML5 list autocomplete page";
michael@0 117 }
michael@0 118 }
michael@0 119
michael@0 120 function removeChar(aID, aCheckerOrEventSeq)
michael@0 121 {
michael@0 122 this.__proto__ = new synthAction(aID, aCheckerOrEventSeq);
michael@0 123
michael@0 124 this.invoke = function removeChar_invoke()
michael@0 125 {
michael@0 126 synthesizeKey("VK_LEFT", { shiftKey: true });
michael@0 127 synthesizeKey("VK_DELETE", {});
michael@0 128 }
michael@0 129
michael@0 130 this.getID = function removeChar_getID()
michael@0 131 {
michael@0 132 return "remove char on " + prettyName(aID);
michael@0 133 }
michael@0 134 }
michael@0 135
michael@0 136 function replaceOnChar(aID, aChar, aCheckerOrEventSeq)
michael@0 137 {
michael@0 138 this.__proto__ = new synthAction(aID, aCheckerOrEventSeq);
michael@0 139
michael@0 140 this.invoke = function replaceOnChar_invoke()
michael@0 141 {
michael@0 142 this.DOMNode.select();
michael@0 143 synthesizeKey(aChar, {});
michael@0 144 }
michael@0 145
michael@0 146 this.getID = function replaceOnChar_getID()
michael@0 147 {
michael@0 148 return "replace on char '" + aChar + "' for" + prettyName(aID);
michael@0 149 }
michael@0 150 }
michael@0 151
michael@0 152 function focusOnMouseOver(aIDFunc, aIDFuncArg)
michael@0 153 {
michael@0 154 this.eventSeq = [ new focusChecker(aIDFunc, aIDFuncArg) ];
michael@0 155
michael@0 156 this.invoke = function focusOnMouseOver_invoke()
michael@0 157 {
michael@0 158 this.id = aIDFunc.call(null, aIDFuncArg);
michael@0 159 this.node = getNode(this.id);
michael@0 160 this.window = this.node.ownerDocument.defaultView;
michael@0 161
michael@0 162 if (this.node.localName == "tree") {
michael@0 163 var tree = getAccessible(this.node);
michael@0 164 var accessible = getAccessible(this.id);
michael@0 165 if (tree != accessible) {
michael@0 166 var itemX = {}, itemY = {}, treeX = {}, treeY = {};
michael@0 167 accessible.getBounds(itemX, itemY, {}, {});
michael@0 168 tree.getBounds(treeX, treeY, {}, {});
michael@0 169 this.x = itemX.value - treeX.value;
michael@0 170 this.y = itemY.value - treeY.value;
michael@0 171 }
michael@0 172 }
michael@0 173
michael@0 174 // Generate mouse move events in timeouts until autocomplete popup list
michael@0 175 // doesn't have it, the reason is do that because autocomplete popup
michael@0 176 // ignores mousemove events firing in too short range.
michael@0 177 synthesizeMouse(this.node, this.x, this.y, { type: "mousemove" });
michael@0 178 this.doMouseMoveFlood(this);
michael@0 179 }
michael@0 180
michael@0 181 this.finalCheck = function focusOnMouseOver_getID()
michael@0 182 {
michael@0 183 this.isFlooding = false;
michael@0 184 }
michael@0 185
michael@0 186 this.getID = function focusOnMouseOver_getID()
michael@0 187 {
michael@0 188 return "mouse over on " + prettyName(aIDFunc.call(null, aIDFuncArg));
michael@0 189 }
michael@0 190
michael@0 191 this.doMouseMoveFlood = function focusOnMouseOver_doMouseMoveFlood(aThis)
michael@0 192 {
michael@0 193 synthesizeMouse(aThis.node, aThis.x + 1, aThis.y + 1,
michael@0 194 { type: "mousemove" }, aThis.window);
michael@0 195
michael@0 196 if (aThis.isFlooding)
michael@0 197 aThis.window.setTimeout(aThis.doMouseMoveFlood, 0, aThis);
michael@0 198 }
michael@0 199
michael@0 200 this.id = null;
michael@0 201 this.node = null;
michael@0 202 this.window = null;
michael@0 203
michael@0 204 this.isFlooding = true;
michael@0 205 this.x = 1;
michael@0 206 this.y = 1;
michael@0 207 }
michael@0 208
michael@0 209 function selectByClick(aIDFunc, aIDFuncArg,
michael@0 210 aFocusTargetFunc, aFocusTargetFuncArg)
michael@0 211 {
michael@0 212 this.eventSeq = [ new focusChecker(aFocusTargetFunc, aFocusTargetFuncArg) ];
michael@0 213
michael@0 214 this.invoke = function selectByClick_invoke()
michael@0 215 {
michael@0 216 var id = aIDFunc.call(null, aIDFuncArg);
michael@0 217 var node = getNode(id);
michael@0 218 var targetWindow = node.ownerDocument.defaultView;
michael@0 219
michael@0 220 var x = 0, y = 0;
michael@0 221 if (node.localName == "tree") {
michael@0 222 var tree = getAccessible(node);
michael@0 223 var accessible = getAccessible(id);
michael@0 224 if (tree != accessible) {
michael@0 225 var itemX = {}, itemY = {}, treeX = {}, treeY = {};
michael@0 226 accessible.getBounds(itemX, itemY, {}, {});
michael@0 227 tree.getBounds(treeX, treeY, {}, {});
michael@0 228 x = itemX.value - treeX.value;
michael@0 229 y = itemY.value - treeY.value;
michael@0 230 }
michael@0 231 }
michael@0 232
michael@0 233 synthesizeMouseAtCenter(node, {}, targetWindow);
michael@0 234 }
michael@0 235
michael@0 236 this.getID = function selectByClick_getID()
michael@0 237 {
michael@0 238 return "select by click " + prettyName(aIDFunc.call(null, aIDFuncArg));
michael@0 239 }
michael@0 240 }
michael@0 241
michael@0 242 ////////////////////////////////////////////////////////////////////////////
michael@0 243 // Target getters
michael@0 244
michael@0 245 function getItem(aItemObj)
michael@0 246 {
michael@0 247 var autocomplete = aItemObj.autocomplete;
michael@0 248 var autocompleteNode = aItemObj.autocompleteNode;
michael@0 249
michael@0 250 // XUL searchbar
michael@0 251 if (autocompleteNode.localName == "searchbar") {
michael@0 252 var popupNode = autocompleteNode._popup;
michael@0 253 if (popupNode) {
michael@0 254 var list = getAccessible(popupNode);
michael@0 255 return list.getChildAt(aItemObj.index);
michael@0 256 }
michael@0 257 }
michael@0 258
michael@0 259 // XUL autocomplete
michael@0 260 var popupNode = autocompleteNode.popup;
michael@0 261 if (!popupNode) {
michael@0 262 // HTML form autocomplete
michael@0 263 var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
michael@0 264 getService(Components.interfaces.nsIAutoCompleteController);
michael@0 265 popupNode = controller.input.popup.QueryInterface(nsIDOMNode);
michael@0 266 }
michael@0 267
michael@0 268 if (popupNode) {
michael@0 269 if ("richlistbox" in popupNode) {
michael@0 270 var list = getAccessible(popupNode.richlistbox);
michael@0 271 return list.getChildAt(aItemObj.index);
michael@0 272 }
michael@0 273
michael@0 274 var list = getAccessible(popupNode.tree);
michael@0 275 return list.getChildAt(aItemObj.index + 1);
michael@0 276 }
michael@0 277 }
michael@0 278
michael@0 279 function getTextEntry(aID)
michael@0 280 {
michael@0 281 // For form autocompletes the autocomplete widget and text entry widget
michael@0 282 // is the same widget, for XUL autocompletes the text entry is a first
michael@0 283 // child.
michael@0 284 var localName = getNode(aID).localName;
michael@0 285
michael@0 286 // XUL autocomplete
michael@0 287 if (localName == "textbox")
michael@0 288 return getAccessible(aID).firstChild;
michael@0 289
michael@0 290 // HTML form autocomplete
michael@0 291 if (localName == "input")
michael@0 292 return getAccessible(aID);
michael@0 293
michael@0 294 // XUL searchbar
michael@0 295 if (localName == "searchbar")
michael@0 296 return getAccessible(getNode(aID).textbox.inputField);
michael@0 297
michael@0 298 return null;
michael@0 299 }
michael@0 300
michael@0 301 function itemObj(aID, aIdx)
michael@0 302 {
michael@0 303 this.autocompleteNode = getNode(aID);
michael@0 304
michael@0 305 this.autocomplete = this.autocompleteNode.localName == "searchbar" ?
michael@0 306 getAccessible(this.autocompleteNode.textbox) :
michael@0 307 getAccessible(this.autocompleteNode);
michael@0 308
michael@0 309 this.index = aIdx;
michael@0 310 }
michael@0 311
michael@0 312 function getIFrameDOMDoc(aIFrameID)
michael@0 313 {
michael@0 314 return getNode(aIFrameID).contentDocument;
michael@0 315 }
michael@0 316
michael@0 317 ////////////////////////////////////////////////////////////////////////////
michael@0 318 // Test helpers
michael@0 319
michael@0 320 function queueAutoCompleteTests(aID)
michael@0 321 {
michael@0 322 // focus autocomplete text entry
michael@0 323 gQueue.push(new synthFocus(aID, new focusChecker(getTextEntry, aID)));
michael@0 324
michael@0 325 // open autocomplete popup
michael@0 326 gQueue.push(new synthDownKey(aID, new nofocusChecker()));
michael@0 327
michael@0 328 // select second option ('hi' option), focus on it
michael@0 329 gQueue.push(new synthUpKey(aID,
michael@0 330 new focusChecker(getItem, new itemObj(aID, 1))));
michael@0 331
michael@0 332 // choose selected option, focus on text entry
michael@0 333 gQueue.push(new synthEnterKey(aID, new focusChecker(getTextEntry, aID)));
michael@0 334
michael@0 335 // remove char, autocomplete popup appears
michael@0 336 gQueue.push(new removeChar(aID, new nofocusChecker()));
michael@0 337
michael@0 338 // select first option ('hello' option), focus on it
michael@0 339 gQueue.push(new synthDownKey(aID,
michael@0 340 new focusChecker(getItem, new itemObj(aID, 0))));
michael@0 341
michael@0 342 // mouse move on second option ('hi' option), focus on it
michael@0 343 gQueue.push(new focusOnMouseOver(getItem, new itemObj(aID, 1)));
michael@0 344
michael@0 345 // autocomplete popup updated (no selected item), focus on textentry
michael@0 346 gQueue.push(new synthKey(aID, "e", null, new focusChecker(getTextEntry, aID)));
michael@0 347
michael@0 348 // select first option ('hello' option), focus on it
michael@0 349 gQueue.push(new synthDownKey(aID,
michael@0 350 new focusChecker(getItem, new itemObj(aID, 0))));
michael@0 351
michael@0 352 // popup gets hidden, focus on textentry
michael@0 353 gQueue.push(new synthRightKey(aID, new focusChecker(getTextEntry, aID)));
michael@0 354
michael@0 355 // popup gets open, no focus
michael@0 356 gQueue.push(new synthOpenComboboxKey(aID, new nofocusChecker()));
michael@0 357
michael@0 358 // select first option again ('hello' option), focus on it
michael@0 359 gQueue.push(new synthDownKey(aID,
michael@0 360 new focusChecker(getItem, new itemObj(aID, 0))));
michael@0 361
michael@0 362 // no option is selected, focus on text entry
michael@0 363 gQueue.push(new synthUpKey(aID, new focusChecker(getTextEntry, aID)));
michael@0 364
michael@0 365 // close popup, no focus
michael@0 366 gQueue.push(new synthEscapeKey(aID, new nofocusChecker()));
michael@0 367
michael@0 368 // autocomplete popup appears (no selected item), focus stays on textentry
michael@0 369 gQueue.push(new replaceOnChar(aID, "h", new nofocusChecker()));
michael@0 370
michael@0 371 // mouse move on first option ('hello' option), focus on it
michael@0 372 gQueue.push(new focusOnMouseOver(getItem, new itemObj(aID, 0)));
michael@0 373
michael@0 374 // click first option ('hello' option), popup closes, focus on text entry
michael@0 375 gQueue.push(new selectByClick(getItem, new itemObj(aID, 0), getTextEntry, aID));
michael@0 376 }
michael@0 377
michael@0 378 ////////////////////////////////////////////////////////////////////////////
michael@0 379 // Tests
michael@0 380
michael@0 381 //gA11yEventDumpID = "eventdump"; // debug stuff
michael@0 382 //gA11yEventDumpToConsole = true; // debug stuff
michael@0 383
michael@0 384 var gInitQueue = null;
michael@0 385 function initTests()
michael@0 386 {
michael@0 387 if (SEAMONKEY || MAC) {
michael@0 388 todo(false, "Skipping this test on SeaMonkey ftb. (Bug 718237), and on Mac (bug 746177)");
michael@0 389 shutdownAutoComplete();
michael@0 390 SimpleTest.finish();
michael@0 391 return;
michael@0 392 }
michael@0 393
michael@0 394 gInitQueue = new eventQueue();
michael@0 395 gInitQueue.push(new loadFormAutoComplete("iframe"));
michael@0 396 gInitQueue.push(new initFormAutoCompleteBy("iframe", "hello"));
michael@0 397 gInitQueue.push(new initFormAutoCompleteBy("iframe", "hi"));
michael@0 398 gInitQueue.push(new loadHTML5ListAutoComplete("iframe2"));
michael@0 399 gInitQueue.onFinish = function initQueue_onFinish()
michael@0 400 {
michael@0 401 SimpleTest.executeSoon(doTests);
michael@0 402 return DO_NOT_FINISH_TEST;
michael@0 403 }
michael@0 404 gInitQueue.invoke();
michael@0 405 }
michael@0 406
michael@0 407 var gQueue = null;
michael@0 408 function doTests()
michael@0 409 {
michael@0 410 // Test focus events.
michael@0 411 gQueue = new eventQueue();
michael@0 412
michael@0 413 ////////////////////////////////////////////////////////////////////////////
michael@0 414 // tree popup autocomplete tests
michael@0 415 queueAutoCompleteTests("autocomplete");
michael@0 416
michael@0 417 ////////////////////////////////////////////////////////////////////////////
michael@0 418 // richlistbox popup autocomplete tests
michael@0 419 queueAutoCompleteTests("richautocomplete");
michael@0 420
michael@0 421 ////////////////////////////////////////////////////////////////////////////
michael@0 422 // HTML form autocomplete tests
michael@0 423 queueAutoCompleteTests(getIFrameDOMDoc("iframe").getElementById("input"));
michael@0 424
michael@0 425 ////////////////////////////////////////////////////////////////////////////
michael@0 426 // HTML5 list autocomplete tests
michael@0 427 queueAutoCompleteTests(getIFrameDOMDoc("iframe2").getElementById("input"));
michael@0 428
michael@0 429 ////////////////////////////////////////////////////////////////////////////
michael@0 430 // searchbar tests
michael@0 431
michael@0 432 // focus searchbar, focus on text entry
michael@0 433 gQueue.push(new synthFocus("searchbar",
michael@0 434 new focusChecker(getTextEntry, "searchbar")));
michael@0 435 // open search engine popup, no focus
michael@0 436 gQueue.push(new synthOpenComboboxKey("searchbar", new nofocusChecker()));
michael@0 437 // select first item, focus on it
michael@0 438 gQueue.push(new synthDownKey("searchbar",
michael@0 439 new focusChecker(getItem, new itemObj("searchbar", 0))));
michael@0 440 // mouse over on second item, focus on it
michael@0 441 gQueue.push(new focusOnMouseOver(getItem, new itemObj("searchbar", 1)));
michael@0 442 // press enter key, focus on text entry
michael@0 443 gQueue.push(new synthEnterKey("searchbar",
michael@0 444 new focusChecker(getTextEntry, "searchbar")));
michael@0 445 // click on search button, open popup, focus goes to document
michael@0 446 var searchBtn = getAccessible(getNode("searchbar").searchButton);
michael@0 447 gQueue.push(new synthClick(searchBtn, new focusChecker(document)));
michael@0 448 // select first item, focus on it
michael@0 449 gQueue.push(new synthDownKey("searchbar",
michael@0 450 new focusChecker(getItem, new itemObj("searchbar", 0))));
michael@0 451 // close popup, focus goes on document
michael@0 452 gQueue.push(new synthEscapeKey("searchbar", new focusChecker(document)));
michael@0 453
michael@0 454 gQueue.onFinish = function()
michael@0 455 {
michael@0 456 // unregister 'test-a11y-search' autocomplete search
michael@0 457 shutdownAutoComplete();
michael@0 458 }
michael@0 459 gQueue.invoke(); // Will call SimpleTest.finish();
michael@0 460 }
michael@0 461
michael@0 462 SimpleTest.waitForExplicitFinish();
michael@0 463
michael@0 464 // Register 'test-a11y-search' autocomplete search.
michael@0 465 // XPFE AutoComplete needs to register early.
michael@0 466 initAutoComplete([ "hello", "hi" ],
michael@0 467 [ "Beep beep'm beep beep yeah", "Baby you can drive my car" ]);
michael@0 468
michael@0 469 addA11yLoadEvent(initTests);
michael@0 470 ]]>
michael@0 471 </script>
michael@0 472
michael@0 473 <hbox flex="1" style="overflow: auto;">
michael@0 474 <body xmlns="http://www.w3.org/1999/xhtml">
michael@0 475 <a target="_blank"
michael@0 476 href="https://bugzilla.mozilla.org/show_bug.cgi?id=383759"
michael@0 477 title="Focus event inconsistent for search box autocomplete">
michael@0 478 Mozilla Bug 383759
michael@0 479 </a>
michael@0 480 <a target="_blank"
michael@0 481 href="https://bugzilla.mozilla.org/show_bug.cgi?id=673958"
michael@0 482 title="Rework accessible focus handling">
michael@0 483 Mozilla Bug 673958
michael@0 484 </a>
michael@0 485 <a target="_blank"
michael@0 486 href="https://bugzilla.mozilla.org/show_bug.cgi?id=559766"
michael@0 487 title="Add accessibility support for @list on HTML input and for HTML datalist">
michael@0 488 Mozilla Bug 559766
michael@0 489 </a>
michael@0 490 <p id="display"></p>
michael@0 491 <div id="content" style="display: none"></div>
michael@0 492 <pre id="test">
michael@0 493 </pre>
michael@0 494 </body>
michael@0 495
michael@0 496 <vbox flex="1">
michael@0 497 <textbox id="autocomplete" type="autocomplete"
michael@0 498 autocompletesearch="test-a11y-search"/>
michael@0 499
michael@0 500 <textbox id="richautocomplete" type="autocomplete"
michael@0 501 autocompletesearch="test-a11y-search"
michael@0 502 autocompletepopup="richpopup"/>
michael@0 503 <panel id="richpopup" type="autocomplete-richlistbox" noautofocus="true"/>
michael@0 504
michael@0 505 <iframe id="iframe"/>
michael@0 506
michael@0 507 <iframe id="iframe2"/>
michael@0 508
michael@0 509 <searchbar id="searchbar"/>
michael@0 510
michael@0 511 <vbox id="eventdump"/>
michael@0 512 </vbox>
michael@0 513 </hbox>
michael@0 514 </window>

mercurial