diff --git a/src/test/javascript/lib/env.utils.js b/src/test/javascript/lib/env.utils.js index f8735f4..aea41d1 100755 --- a/src/test/javascript/lib/env.utils.js +++ b/src/test/javascript/lib/env.utils.js @@ -54,9 +54,9 @@ /** * Envjs specific hacks * 1) Fix Envjs relative path system to work with Windows path systems - * 2) Fix window.setTimeout() using Rhino specific functions - * 3) Fix CSS2Properties support for parsing style attributes: get from raw node context. - * 4) Fix CSS2Properties support for setting values: all properties have the same objmaps, wtf? + * 2) Fix CSS2Properties support for parsing style attributes: get from raw node context. + * 3) Fix CSS2Properties support for setting values: all properties have the same objmaps, wtf? + * 4) Fix focus() which sets document.activeElement correctly for jQuery:focus */ (function() { @@ -68,13 +68,6 @@ return oldEnvjsUriFn(path, "file:///" + ("" + Envjs.getcwd()).replace(/\\/g, '/') + "/"); }; - window.setTimeout = function(closure, timeout) { - spawn(function() { - java.lang.Thread.sleep(timeout); - closure(); - }); - }; - (function(Element) { var style = "style"; @@ -97,6 +90,25 @@ }); })(HTMLElement.prototype); + + (function(Input, Textarea, document) { + var activeElement; + function fixFocusForPrototype(element) { + var originalFocus = element.prototype.focus; + element.prototype.focus = function(element) { + activeElement = this; + originalFocus.apply(this, arguments); + } + } + + fixFocusForPrototype(Input); + fixFocusForPrototype(Textarea); + + document.__defineGetter__("activeElement", function() { + return activeElement; + }); + + })(HTMLInputElement, HTMLTextAreaElement, document); (function(css) { @@ -111,3 +123,58 @@ } })(CSS2Properties); })(); + +/** + * Envjs timeout fixes which use native Java code to re-implement setTimeout and setInterval + * also sets clearTimeout & clearInterval on same level. + */ +(function() { + var threadTimeoutPool = {}; + + window.setTimeout = function(closure, timeout) { + var thread = spawn(function() { + try { + java.lang.Thread.sleep(timeout); + closure(); + } catch(e) { + // ignore InterruptedExceptions, is probably due to clearTimeout + if (!(e.javaException instanceof java.lang.InterruptedException)) { + throw(e); + } + } + }); + + threadTimeoutPool[thread.getId()] = thread; + return thread.getId(); + }; + + window.setInterval = function(closure, timeout) { + var thread = spawn(function() { + try { + while(true) { + java.lang.Thread.sleep(timeout); + closure(); + } + } catch(e) { + // ignore InterruptedExceptions, is probably due to clearTimeout + if (!(e.javaException instanceof java.lang.InterruptedException)) { + throw(e); + } + } + }); + + threadTimeoutPool[thread.getId()] = thread; + return thread.getId(); + }; + + window.clearTimeout = function(threadId) { + if (threadId) { + if(threadTimeoutPool[threadId]) { + threadTimeoutPool[threadId].interrupt(); + delete threadTimeoutPool[threadId]; + } + } + }; + + window.clearInterval = window.clearTimeout; +})(); diff --git a/src/test/javascript/specs/envUtilsSpec.js b/src/test/javascript/specs/envUtilsSpec.js index 13ddb6e..2fc2c2d 100755 --- a/src/test/javascript/specs/envUtilsSpec.js +++ b/src/test/javascript/specs/envUtilsSpec.js @@ -1,6 +1,44 @@ describe("envjs fixes", function() { + describe("Envjs event handling fixes", function() { + beforeEach(function() { + loadFixtures("formevents.html"); + }); + + describe("focussing events", function() { + it("should set activeElement when focussing an input element", function() { + $("#input").focus(); + expect(document.activeElement.id).toBe("input"); + expect($(":focus")).toBe("#input"); + }); + + it("should set activeElement when focussing a textarea element", function() { + $("#area").focus(); + expect(document.activeElement.id).toBe("area"); + expect($(":focus")).toBe("#area"); + }); + }); + + describe("form submit events", function() { + it("should be able to catch a formsubmit event", function() { + var submitted = false; + $("#form").submit(function() { + submitted = true; + }); + + $("#form").submit(); + waitsFor(function() { + return submitted === true; + }); + + runs(function() { + expect(submitted).toBeTruthy(); + }); + }); + }); + }); + describe("CSS2 style property support for parsing style attributes", function() { beforeEach(function() { loadFixtures("styleAttributes.html"); @@ -52,20 +90,111 @@ describe("envjs fixes", function() { }); - describe("window setTimeout", function() { + describe("timer based events", function() { - it("should wait one second before executing", function() { - var done = false; - window.setTimeout(function() { - done = true; - }, 1000); - - waitsFor(function() { - return done === true; + describe("setTimeout", function() { + it("should wait one second before executing", function() { + var done = false; + window.setTimeout(function() { + done = true; + }, 50); + + waitsFor(function() { + return done === true; + }); + + runs(function() { + expect(done).toBeTruthy(); + }); }); + + it("should return a unique timerID when the timeout has been set which can be cancelled", function() { + var done = false; + var timerID = window.setTimeout(function() { + done = true; + }, 10); + var timerID2 = window.setTimeout(function() { }, 10); + + window.clearTimeout(timerID); + waits(50); + + runs(function() { + expect(typeof(timerID)).toEqual("number"); + expect(timerID).not.toEqual(timerID2); + expect(done).toBeFalsy(); + }); + }); + + it("should be able to use clearInterval for timeouts", function() { + var done = false; + var timerID = window.setTimeout(function() { + done = true; + }, 10); + + window.clearInterval(timerID); + waits(50); + + runs(function() { + expect(done).toBeFalsy(); + }); + }); + }); - runs(function() { - expect(done).toBeTruthy(); + describe("setInterval", function() { + it("should call the callback method x times until the interval has been stopped", function() { + var count = 0, storedCount; + var intervalId = window.setInterval(function() { + count++; + }, 20); + + waitsFor(function() { + return count > 3; + }); + + runs(function() { + storedCount = count; + window.clearInterval(intervalId); + }); + waits(100); + + runs(function() { + expect(storedCount).toEqual(count); + }); + }); + + it("should be able to use setTimeout and setInterval which create unique return IDs", function() { + var id1 = window.setTimeout(function() {}, 10); + var id2 = window.setInterval(function() {}, 10); + + waits(50); + this.after(function() { + window.clearInterval(id2); + }); + + runs(function() { + expect(id1 < id2).toBeTruthy(); + }); + }); + + it("should be able to use clearTimeout for intervals", function() { + var count = 0, storedCount; + var intervalId = window.setInterval(function() { + count++; + }, 10); + + waitsFor(function() { + return count > 1; + }); + + runs(function() { + storedCount = count; + window.clearTimeout(intervalId); + }); + waits(100); + + runs(function() { + expect(storedCount).toEqual(count); + }); }); });