summaryrefslogtreecommitdiff
path: root/misc/openlayers/tests/Handler/Click.html
diff options
context:
space:
mode:
Diffstat (limited to 'misc/openlayers/tests/Handler/Click.html')
-rw-r--r--misc/openlayers/tests/Handler/Click.html735
1 files changed, 735 insertions, 0 deletions
diff --git a/misc/openlayers/tests/Handler/Click.html b/misc/openlayers/tests/Handler/Click.html
new file mode 100644
index 0000000..be508ca
--- /dev/null
+++ b/misc/openlayers/tests/Handler/Click.html
@@ -0,0 +1,735 @@
+<html>
+<head>
+ <script src="../OLLoader.js"></script>
+ <script type="text/javascript">
+
+ function px(x, y) {
+ return new OpenLayers.Pixel(x, y);
+ }
+
+ function test_Handler_Click_constructor(t) {
+ t.plan(3);
+ var control = new OpenLayers.Control();
+ control.id = Math.random();
+ var callbacks = {foo: "bar"};
+ var options = {bar: "foo"};
+
+ var oldInit = OpenLayers.Handler.prototype.initialize;
+
+ OpenLayers.Handler.prototype.initialize = function(con, call, opt) {
+ t.eq(con.id, control.id,
+ "constructor calls parent with the correct control");
+ t.eq(call, callbacks,
+ "constructor calls parent with the correct callbacks");
+ t.eq(opt, options,
+ "constructor calls parent with the correct options");
+ }
+ var handler = new OpenLayers.Handler.Click(control, callbacks, options);
+
+ OpenLayers.Handler.prototype.initialize = oldInit;
+ }
+
+ function test_Handler_Click_activate(t) {
+ t.plan(2);
+ var control = {
+ map: new OpenLayers.Map('map')
+ };
+ var handler = new OpenLayers.Handler.Click(control);
+ handler.active = true;
+ var activated = handler.activate();
+ t.ok(!activated,
+ "activate returns false if the handler was already active");
+ handler.active = false;
+ handler.dragging = true;
+ activated = handler.activate();
+ t.ok(activated,
+ "activate returns true if the handler was not already active");
+
+ }
+
+ function test_Handler_Click_events(t) {
+ t.plan(80);
+
+ var map = new OpenLayers.Map('map');
+ var control = {
+ map: map
+ };
+ map.events.registerPriority = function(type, obj, func) {
+ var f = OpenLayers.Function.bind(func, obj)
+ var r = f({xy:null});
+ if(typeof r == "string") {
+ // this is one of the mock handler methods
+ t.eq(OpenLayers.Util.indexOf(nonevents, type), -1,
+ "registered method is not one of the events " +
+ "that should not be handled");
+ t.ok(OpenLayers.Util.indexOf(events, type) > -1,
+ "activate calls registerPriority with browser event: " + type);
+ t.eq(typeof func, "function",
+ "activate calls registerPriority with a function");
+ t.eq(func(), type,
+ "activate calls registerPriority with the correct method");
+ t.eq(obj["CLASS_NAME"], "OpenLayers.Handler.Click",
+ "activate calls registerPriority with the handler");
+ }
+ }
+ function setMethod(key) {
+ handler[key] = function() {return key};
+ }
+
+ // list below events that should be handled (events) and those
+ // that should not be handled (nonevents) by the handler
+ var events = ["click", "dblclick", "mousedown", "mouseup", "rightclick", "touchstart", "touchmove", "touchend"];
+ var nonevents = ["mousemove", "resize", "focus", "blur"];
+ var handler = new OpenLayers.Handler.Click(control);
+ // set browser event like properties on the handler
+ for(var i=0; i<events.length; ++i) {
+ setMethod(events[i]);
+ }
+ handler.activate();
+
+ // different listeners registered for pixelTolerance option
+ var events = ["click", "dblclick", "mousedown", "mouseup", "rightclick", "touchstart", "touchmove", "touchend"];
+ var nonevents = ["mousemove", "resize", "focus", "blur"];
+ var handler = new OpenLayers.Handler.Click(control, {}, {
+ pixelTolerance: 2
+ });
+ for(var i=0; i<events.length; ++i) {
+ setMethod(events[i]);
+ }
+ handler.activate();
+
+ }
+
+ var callbackMap;
+ function callbackSetup(log, options) {
+ callbackMap = new OpenLayers.Map({
+ div: "map",
+ controls: [], // no controls here because these tests use a custom setTimeout and we only want setTimeout calls from a single handler
+ layers: [new OpenLayers.Layer(null, {isBaseLayer: true})],
+ center: new OpenLayers.LonLat(0, 0),
+ zoom: 1
+ });
+ var control = new OpenLayers.Control();
+ callbackMap.addControl(control);
+
+ var callbacks = {
+ "click": function(evt) {
+ log.push({callback: "click", evt: evt});
+ },
+ "dblclick": function(evt) {
+ log.push({callback: "dblclick", evt: evt});
+ }
+ };
+ var handler = new OpenLayers.Handler.Click(control, callbacks, options);
+ handler.activate();
+
+
+ var timers = {};
+ window._setTimeout = window.setTimeout;
+ window.setTimeout = function(func, delay) {
+ log.push({method: "setTimeout", func: func, delay: delay});
+ var key = (new Date).getTime() + "-" + Math.random();
+ timers[key] = true;
+ // execute function that is supposed to be delayed
+ func();
+ return key;
+ }
+ window._clearTimeout = window.clearTimeout;
+ window.clearTimeout = function(key) {
+ log.push({
+ method: "clearTimeout",
+ keyExists: (key in timers)
+ });
+ delete timers[key];
+ }
+ return handler;
+ }
+
+ function callbackTeardown() {
+ window.setTimeout = window._setTimeout;
+ window.clearTimeout = window._clearTimeout;
+ callbackMap.destroy();
+ callbackMap = null;
+ }
+
+ function test_callbacks_click_default(t) {
+ t.plan(6);
+
+ var log = [];
+ var handler = callbackSetup(log);
+
+ // set up for single click - three tests here
+ var testEvt = {id: Math.random()};
+ handler.map.events.triggerEvent("click", testEvt);
+ t.eq(log.length, 2, "(click w/ single true) two items logged");
+
+ // first item logged is setTimeout call
+ t.eq(log[0].method, "setTimeout", "setTimeout called");
+ t.eq(typeof log[0].func, "function", "setTimeout called with a function");
+ t.eq(log[0].delay, handler.delay, "setTimeout called with proper delay");
+
+ // second item logged is from click callback
+ t.eq(log[1].callback, "click", "click callback called");
+ t.eq(log[1].evt.id, testEvt.id, "got correct event");
+
+ callbackTeardown();
+ }
+
+ function test_callbacks_dblclick_default(t) {
+ t.plan(1);
+
+ var log = [];
+ var handler = callbackSetup(log);
+ var testEvt = {id: Math.random()};
+ handler.map.events.triggerEvent("dblclick", testEvt);
+
+ t.eq(log.length, 0, "nothing happens by default with dblclick (double is false)");
+
+ callbackTeardown();
+
+ }
+
+ function test_callbacks_dblclick_double(t) {
+ t.plan(3);
+
+ var log = [];
+ var handler = callbackSetup(log, {"double": true});
+ var testEvt = {id: Math.random()};
+ handler.map.events.triggerEvent("dblclick", testEvt);
+
+ t.eq(log.length, 1, "one item logged");
+ t.eq(log[0].callback, "dblclick", "dblclick callback called")
+ t.eq(log[0].evt.id, testEvt.id, "dblclick callback called with event");
+
+ callbackTeardown();
+
+ }
+
+ function test_callbacks_dblclick_sequence(t) {
+ t.plan(8);
+
+ var log = [];
+ var handler = callbackSetup(log, {"double": true});
+ var testEvt = {id: Math.random()};
+
+ // first click - set timer for next
+ handler.map.events.triggerEvent("click", testEvt);
+ t.ok(handler.timerId != null, "timer is set");
+ log.pop(); // because the test setTimeout is synchronous we get the click callback immediately
+ t.eq(log.length, 1, "one item logged (after pop due to synchronous setTimeout call in our tests");
+ t.eq(log[0].method, "setTimeout", "setTimeout called first");
+
+ // second click - timer cleared
+ handler.map.events.triggerEvent("click", testEvt);
+ t.ok(handler.timerId == null, "timer is cleared");
+ t.eq(log.length, 2, "two items logged after second click");
+ t.eq(log[1].method, "clearTimeout", "clearTimeout called second");
+
+ // dblclick event - callback called
+ handler.map.events.triggerEvent("dblclick", testEvt);
+ t.eq(log.length, 3, "three items logged");
+ t.eq(log[2].callback, "dblclick", "dblclick callback called third");
+
+ callbackTeardown();
+
+ }
+
+ function test_callbacks_within_pixelTolerance(t) {
+ t.plan(1);
+
+ var log = [];
+ var handler = callbackSetup(log, {"double": true, pixelTolerance: 2});
+
+ var down = {
+ xy: px(0, 0)
+ };
+ var up = {
+ xy: px(0, 1)
+ };
+
+ handler.map.events.triggerEvent("mousedown", down);
+ handler.map.events.triggerEvent("mouseup", up);
+ handler.map.events.triggerEvent("click", up);
+
+ t.eq(log[log.length-1].callback, "click", "click callback called");
+
+ callbackTeardown();
+
+ }
+
+ function test_callbacks_outside_pixelTolerance(t) {
+ t.plan(2);
+
+ var log = [];
+ var handler = callbackSetup(log, {pixelTolerance: 2});
+
+ var down = {
+ xy: px(0, 0)
+ };
+ var up = {
+ xy: px(2, 3)
+ };
+
+ handler.map.events.triggerEvent("mousedown", down);
+ t.ok(handler.down && handler.down.xy.equals(down.xy), "down position set");
+
+ handler.map.events.triggerEvent("mouseup", up);
+ handler.map.events.triggerEvent("click", up);
+ t.eq(log.length, 0, "nothing logged - event outside tolerance");
+
+ callbackTeardown();
+
+ }
+
+ function test_callbacks_within_dblclickTolerance(t) {
+ t.plan(6);
+
+ var log = [];
+ var handler = callbackSetup(log, {single: false, "double": true, dblclickTolerance: 8});
+
+ var first = {
+ xy: px(0, 0)
+ };
+ var second = {
+ xy: px(0, 5)
+ };
+
+ handler.map.events.triggerEvent("mousedown", first);
+ handler.map.events.triggerEvent("mouseup", first);
+ handler.map.events.triggerEvent("click", first);
+ t.eq(log.length, 1, "one item logged");
+ t.eq(log[0] && log[0].method, "setTimeout", "setTimeout called");
+
+ handler.map.events.triggerEvent("mousedown", second);
+ handler.map.events.triggerEvent("mouseup", second);
+ handler.map.events.triggerEvent("click", second);
+ t.eq(log.length, 2, "two events logged");
+ t.eq(log[1] && log[1].method, "clearTimeout", "clearTimeout called");
+
+ handler.map.events.triggerEvent("dblclick", second);
+ t.eq(log.length, 3, "three items logged");
+ t.eq(log[2] && log[2].callback, "dblclick", "dblclick callback called");
+
+ callbackTeardown();
+ }
+
+ function test_callbacks_outside_dblclickTolerance(t) {
+ t.plan(5);
+
+ var log = [];
+ // default dblclickTolerance is 13
+ var handler = callbackSetup(log, {single: false, "double": true});
+
+ var first = {
+ xy: px(0, 0)
+ };
+ var second = {
+ xy: px(13.5, 0)
+ };
+
+ handler.map.events.triggerEvent("mousedown", first);
+ handler.map.events.triggerEvent("mouseup", first);
+ handler.map.events.triggerEvent("click", first);
+ t.eq(log.length, 1, "one item logged");
+ t.eq(log[0] && log[0].method, "setTimeout", "setTimeout called");
+
+ handler.map.events.triggerEvent("mousedown", second);
+ handler.map.events.triggerEvent("mouseup", second);
+ handler.map.events.triggerEvent("click", second);
+ t.eq(log.length, 2, "two items logged");
+ t.eq(log[1] && log[1].method, "clearTimeout", "clearTimeout called");
+
+ handler.map.events.triggerEvent("dblclick", second);
+ t.eq(log.length, 2, "still two items logged - dblclick callback is not called");
+
+ callbackTeardown();
+ }
+
+ function test_callbacks_multitouch_single(t) {
+
+ t.plan(2);
+
+ var log = [];
+
+ var callbacks = {
+ click: function(evt) {
+ log.push({callback: "click", type: evt.type});
+ },
+ dblclick: function(evt) {
+ log.push({callback: "dblclick", type: evt.type});
+ }
+ };
+
+ var map = new OpenLayers.Map("map");
+ var layer = new OpenLayers.Layer(null, {isBaseLayer: true});
+ map.addLayer(layer);
+ map.setCenter(new OpenLayers.LonLat(0, 0), 1);
+ var control = new OpenLayers.Control();
+ map.addControl(control);
+ var handler = new OpenLayers.Handler.Click(
+ control, callbacks,
+ {"double": true, single: true, pixelTolerance: 2}
+ );
+
+ // we override here so we don't have to wait for the timeout
+ handler.queuePotentialClick = function(evt) {
+ log.push({potential: true, evt: evt});
+ OpenLayers.Handler.Click.prototype.queuePotentialClick.call(this, evt);
+ }
+
+ handler.activate();
+
+ function handle(o) {
+ var touches = [];
+ if (("x0" in o) && ("y0" in o)) {
+ touches.push({
+ clientX: o.x0, clientY: o.y0
+ });
+ }
+ if (("x1" in o) && ("y1" in o)) {
+ touches.push({
+ clientX: o.x1, clientY: o.y1
+ });
+ }
+ handler.map.events.handleBrowserEvent({
+ type: o.type, touches: touches
+ });
+ }
+
+ // a typical multitouch sequence goes like this:
+ // touchstart, touchstart, touchend, touchend
+ handle({type: "touchstart", x0: 10, y0: 10});
+ handle({type: "touchstart", x0: 10, y0: 10, x1: 30, y1: 15});
+ handle({type: "touchend"});
+ handle({type: "touchend"});
+
+ t.eq(log.length, 1, "one item logged");
+ t.eq(log[0] && log[0].potential, true, "click in queue - no dblclick called");
+
+ map.destroy();
+ }
+
+ function test_Handler_Click_deactivate(t) {
+ t.plan(6);
+ var control = {
+ map: new OpenLayers.Map('map')
+ };
+ var handler = new OpenLayers.Handler.Click(control);
+ handler.active = false;
+ var deactivated = handler.deactivate();
+ t.ok(!deactivated,
+ "deactivate returns false if the handler was not already active");
+ handler.active = true;
+ handler.down = true;
+ handler.timerId = true;
+ handler.touch = true;
+ handler.last = true;
+ deactivated = handler.deactivate();
+ t.ok(deactivated,
+ "deactivate returns true if the handler was active already");
+ t.eq(handler.down, null,
+ "deactivate sets down to null");
+ t.eq(handler.timerId, null,
+ "deactivate sets timerId to null");
+ t.eq(handler.touch, false,
+ "deactivate sets touch to false");
+ t.eq(handler.last, null,
+ "deactivate sets last to null");
+
+ }
+
+ function test_Handler_Click_mouseup(t) {
+ t.plan(11);
+
+ var map = new OpenLayers.Map("map");
+ var control = new OpenLayers.Control();
+ map.addControl(control);
+ var handler = new OpenLayers.Handler.Click(control);
+
+ var testEvent = {id: Math.random()};
+ var propagate = true;
+ var log, got, modMatch, rightClick;
+
+ // override methods to log what is called
+ var temp = OpenLayers.Event.isRightClick;
+ OpenLayers.Event.isRightClick = function(e) {
+ log.push({method: "isRightClick", evt: e});
+ return rightClick;
+ };
+ handler.checkModifiers = function(e) {
+ log.push({method: "checkModifiers", evt: e});
+ return modMatch;
+ };
+ handler.rightclick = function(e) {
+ log.push({method: "rightclick", evt: e});
+ return propagate;
+ };
+
+
+ // simulate an event with non-matching modifiers
+ log = [];
+ modMatch = false;
+ rightClick = false;
+ got = handler.mouseup(testEvent);
+ t.eq(log.length, 1, "one item logged");
+ t.eq(log[0] && log[0].method, "checkModifiers", "a) checkModifiers called first");
+ t.eq(log[0] && log[0].evt, testEvent, "a) first method called with correct event");
+
+
+ // modifiers, handlerightclicks, and isrightclick
+ log = [];
+ rightClick = true;
+ modMatch = true;
+ handler.control.handleRightClicks = true;
+ got = handler.mouseup(testEvent);
+ t.eq(log.length, 3, "three items logged");
+ t.eq(log[0] && log[0].method, "checkModifiers", "b) checkModifiers called first");
+ t.eq(log[0] && log[0].evt, testEvent, "b) first method called with correct event");
+ t.eq(log[1] && log[1].method, "isRightClick", "b) isRightClick called second");
+ t.eq(log[1] && log[1].evt, testEvent, "b) second method called with correct event");
+ t.eq(log[2] && log[2].method, "rightclick", "b) rightclick called third");
+ t.eq(log[2] && log[2].evt, testEvent, "b) third method called with correct event");
+ t.eq(got, propagate, "b) return from handler's rightclick returned from mouseup");
+
+ OpenLayers.Event.isRightClick = temp;
+ map.destroy();
+ }
+
+ function test_touch_click(t) {
+ t.plan(5);
+
+ // set up
+
+ var log;
+
+ var map = new OpenLayers.Map('map');
+ var control = {map: map};
+
+ var callbacks = {
+ 'click': function(e) {
+ log = {x: e.xy.x, y: e.xy.y,
+ lastTouches: e.lastTouches};
+ }
+ };
+
+ var handler = new OpenLayers.Handler.Click(
+ control, callbacks,
+ {'single': true, pixelTolerance: null});
+
+ // test
+
+ // the common case: a touchstart followed by a touchend
+ log = null;
+ handler.touchstart({xy: px(1, 1), touches: ["foo"]});
+ handler.touchend({touches: ["foo"]});
+
+ t.delay_call(1, function() {
+ t.ok(log != null, "click callback called");
+ if(log != null) {
+ t.eq(log.x, 1, "evt.xy.x as expected");
+ t.eq(log.y, 1, "evt.xy.y as expected");
+ t.ok(log.lastTouches, "evt.lastTouches as expected");
+ }
+
+ // now emulate a touch where touchstart doesn't propagate
+ // to the click handler, i.e. the click handler gets a
+ // touchend only
+ log = null;
+ handler.touchend({touches: ["foo"]});
+
+ t.delay_call(1, function() {
+ t.ok(log == null, "click callback not called");
+
+ // tear down
+ map.destroy();
+ });
+ });
+ }
+
+ function test_touch_within_dblclickTolerance(t) {
+ t.plan(4);
+
+ var log;
+
+ var callbacks = {
+ click: function(evt) {
+ log.push({callback: "click", type: evt.type});
+ },
+ dblclick: function(evt) {
+ log.push({callback: "dblclick", type: evt.type});
+ }
+ };
+
+ var map = new OpenLayers.Map("map");
+ var layer = new OpenLayers.Layer(null, {isBaseLayer: true});
+ map.addLayer(layer);
+ map.setCenter(new OpenLayers.LonLat(0, 0), 1);
+ var control = new OpenLayers.Control();
+ map.addControl(control);
+ var handler = new OpenLayers.Handler.Click(
+ control, callbacks,
+ {"double": true, single: true, pixelTolerance: 2}
+ );
+ handler.activate();
+
+ function handle(type, x, y) {
+ map.events.handleBrowserEvent({
+ type: type,
+ touches: [
+ {clientX: x, clientY: y}
+ ]
+ });
+ }
+
+ // test
+ log = [];
+ // sequence of two clicks on a touch device
+ // click 1
+ handle("touchstart", 10, 10);
+ handle("touchend", 11, 10);
+ handle("mousemove", 11, 10);
+ handle("mousedown", 10, 10);
+ handle("mouseup", 11, 10);
+ handle("click", 11, 10);
+ // click 2
+ handle("touchstart", 12, 10);
+ handle("touchend", 12, 10);
+ handle("mousedown", 12, 10);
+ handle("mouseup", 12, 10);
+ handle("click", 12, 10);
+
+ t.eq(log.length, 1, "one callback called");
+ t.eq(log[0] && log[0].callback, "dblclick", "click callback called");
+ t.eq(log[0] && log[0].type, "touchend", "click callback called with touchend event");
+ t.ok(!handler.timerId, "handler doesn't have a timerId waiting for click")
+
+ // tear down
+ map.destroy();
+ }
+
+ function test_touch_outside_dblclickTolerance(t) {
+ t.plan(2);
+
+ var log;
+
+ var callbacks = {
+ click: function(evt) {
+ log.push({callback: "click", type: evt.type});
+ },
+ dblclick: function(evt) {
+ log.push({callback: "dblclick", type: evt.type});
+ }
+ };
+
+ var map = new OpenLayers.Map("map");
+ var layer = new OpenLayers.Layer(null, {isBaseLayer: true});
+ map.addLayer(layer);
+ map.setCenter(new OpenLayers.LonLat(0, 0), 1);
+ var control = new OpenLayers.Control();
+ map.addControl(control);
+ var handler = new OpenLayers.Handler.Click(
+ control, callbacks,
+ {"double": true, single: true, pixelTolerance: 2, dblclickTolerance: 8}
+ );
+ handler.activate();
+
+ function handle(type, x, y) {
+ var touches = [];
+ if (x !== undefined && y !== undefined) {
+ touches.push({
+ clientX: x, clientY: y
+ });
+ }
+ map.events.handleBrowserEvent({
+ type: type, touches: touches
+ });
+ }
+
+ // test
+ log = [];
+ // sequence of two clicks on a touch device
+ // click 1
+ handle("touchstart", 10, 10);
+ handle("touchend");
+ handle("mousemove", 11, 10);
+ handle("mousedown", 10, 10);
+ handle("mouseup", 11, 10);
+ handle("click", 11, 10);
+ // click 2
+ handle("touchstart", 20, 10);
+ handle("touchend");
+ handle("mousedown", 20, 10);
+ handle("mouseup", 20, 10);
+ handle("click", 20, 10);
+
+ t.eq(log.length, 0, "no callbacks called");
+ t.ok(!handler.timerId, "handler doesn't have a timerId waiting for click")
+
+ // tear down
+ map.destroy();
+ }
+
+ function test_touchstart(t) {
+ // a test to verify that the touchstart function does
+ // unregister the mouse listeners when it's called the
+ // first time
+
+ t.plan(7);
+
+ // set up
+
+ var map = new OpenLayers.Map("map", {
+ controls: []
+ });
+ var control = new OpenLayers.Control({});
+ var handler = new OpenLayers.Handler.Click(control, {});
+ control.handler = handler;
+ map.addControl(control);
+ handler.activate();
+
+ function allRegistered() {
+ var eventTypes = ['mousedown', 'mouseup', 'click', 'dblclick'],
+ eventType,
+ listeners,
+ listener,
+ flag;
+ for(var i=0, ilen=eventTypes.length; i<ilen; i++) {
+ flag = false;
+ eventType = eventTypes[i];
+ listeners = map.events.listeners[eventType];
+ for(var j=0, jlen=listeners.length; j<jlen; j++) {
+ listener = listeners[j];
+ if(listener.func === handler[eventType] && listener.obj === handler) {
+ flag = true;
+ break;
+ }
+ }
+ if(!flag) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // test
+
+ t.ok(allRegistered(), 'mouse listeners are registered');
+ handler.touchstart({xy: new OpenLayers.Pixel(0, 0)});
+ t.eq(map.events.listeners.mousedown.length, 0,"mousedown is not registered");
+ t.eq(map.events.listeners.mouseup.length, 0,"mouseup is not registered");
+ t.eq(map.events.listeners.click.length, 0,"click is not registered");
+ t.eq(map.events.listeners.dblclick.length, 0,"dblclick is not registered");
+
+ t.ok(handler.touch, 'handler.touch is set');
+
+ handler.deactivate();
+ t.ok(!handler.touch, 'handler.touch is not set');
+
+ map.destroy();
+ }
+ </script>
+</head>
+<body>
+ <div id="map" style="width: 300px; height: 150px;"/>
+</body>
+</html>