From 2bc61933b2e10fc0e59988bb6dee84119685d726 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Thu, 21 Mar 2013 10:26:03 -0700 Subject: [PATCH 1/5] First attempt --- Gruntfile.js | 9 ++++++++- package.json | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 33e45459..9dbc730a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -9,6 +9,7 @@ module.exports = function(grunt) { grunt.loadNpmTasks("grunt-contrib-connect"); grunt.loadNpmTasks("grunt-contrib-watch"); grunt.loadNpmTasks("grunt-contrib-clean"); + grunt.loadNpmTasks("grunt-git-describe"); // ---------- var distribution = "build/openseadragon/openseadragon.js", @@ -65,6 +66,7 @@ module.exports = function(grunt) { options: { banner: "//! <%= pkg.name %> <%= pkg.version %>\n" + "//! Built on <%= grunt.template.today('yyyy-mm-dd') %>\n" + + "//! <%= grunt.config.get('describeResult') %>\n" + "//! http://openseadragon.github.com\n\n", process: true }, @@ -130,6 +132,11 @@ module.exports = function(grunt) { }, beforeconcat: sources, afterconcat: [ distribution ] + }, + "git-describe": { + options: { + prop: "describeResult" + } } }); @@ -159,7 +166,7 @@ module.exports = function(grunt) { // Build task. // Cleans out the build folder and builds the code and images into it, checking lint. grunt.registerTask("build", [ - "clean:build", "jshint:beforeconcat", "concat", "jshint:afterconcat", "uglify", "copy:build" + "clean:build", "jshint:beforeconcat", "git-describe", "concat", "jshint:afterconcat", "uglify", "copy:build" ]); // ---------- diff --git a/package.json b/package.json index 71698851..49bcd9af 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "grunt-contrib-qunit": "~0.1.1", "grunt-contrib-connect": "~0.1.2", "grunt-contrib-watch": "~0.2.0", - "grunt-contrib-clean": "~0.4.0" + "grunt-contrib-clean": "~0.4.0", + "grunt-git-describe": "~2.0.0" }, "scripts": { "test": "grunt test" From b1758040a0aa569a292abeba0fa35b78706969d9 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Thu, 21 Mar 2013 13:44:22 -0700 Subject: [PATCH 2/5] Added "home" and "click" tests --- test/basic.js | 48 +++++- test/lib/jquery.simulate.js | 324 ++++++++++++++++++++++++++++++++++++ test/test.html | 2 + test/util.js | 32 ++++ 4 files changed, 402 insertions(+), 4 deletions(-) create mode 100644 test/lib/jquery.simulate.js create mode 100644 test/util.js diff --git a/test/basic.js b/test/basic.js index 5e99f6b7..ca4556c8 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,5 +1,8 @@ (function() { + // TODO: Tighten up springs and use "immediate" where possible, so tests run faster + // TODO: Test drag + var viewer = null; // ---------- @@ -17,7 +20,7 @@ var openHandler = function(eventSender, eventData) { viewer.removeHandler('open', openHandler); ok(true, 'Open event was sent'); - ok(eventSender === viewer, 'Sender of open event was viewer'); + equal(eventSender, viewer, 'Sender of open event was viewer'); ok(eventData, 'Handler also received event data'); ok(viewer.viewport, 'Viewport exists'); start(); @@ -30,11 +33,11 @@ // ---------- asyncTest('Zoom', function() { var viewport = viewer.viewport; - ok(viewport.getZoom() === 1, 'We start out unzoomed'); + equal(viewport.getZoom(), 1, 'We start out unzoomed'); var zoomHandler = function() { viewer.removeHandler('animationfinish', zoomHandler); - ok(viewport.getZoom() === 2, 'Zoomed correctly'); + equal(viewport.getZoom(), 2, 'Zoomed correctly'); start(); }; @@ -59,6 +62,44 @@ viewport.panTo(new OpenSeadragon.Point(0.1, 0.1)); }); + // ---------- + asyncTest('Home', function() { + var viewport = viewer.viewport; + var center = viewport.getCenter(); + ok(center.x !== 0.5 && center.y !== 0.5, 'We start out panned'); + notEqual(viewport.getZoom(), 1, 'We start out zoomed'); + + var homeHandler = function() { + viewer.removeHandler('animationfinish', homeHandler); + center = viewport.getCenter(); + ok(center.x === 0.5 && center.y === 0.5, 'We end up unpanned'); + equal(viewport.getZoom(), 1, 'We end up unzoomed'); + start(); + }; + + viewer.addHandler('animationfinish', homeHandler); + viewport.goHome(true); + }); + + // ---------- + asyncTest('Click', function() { + var viewport = viewer.viewport; + center = viewport.getCenter(); + ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned'); + equal(viewport.getZoom(), 1, 'We start out unzoomed'); + + var clickHandler = function() { + viewer.removeHandler('animationfinish', clickHandler); + center = viewport.getCenter(); + ok(center.x > 0.37 && center.x < 0.38 && center.y > 0.37 && center.y < 0.38, 'Panned correctly'); + equal(viewport.getZoom(), 2, 'Zoomed correctly'); + start(); + }; + + viewer.addHandler('animationfinish', clickHandler); + Util.simulateViewerClick(viewer, 0.25, 0.25); + }); + // ---------- asyncTest('Close', function() { var closeHandler = function() { @@ -68,7 +109,6 @@ }; viewer.addHandler('close', closeHandler); - viewer.close(); }); diff --git a/test/lib/jquery.simulate.js b/test/lib/jquery.simulate.js new file mode 100644 index 00000000..6e2f3ba8 --- /dev/null +++ b/test/lib/jquery.simulate.js @@ -0,0 +1,324 @@ + /*! + * jQuery Simulate v0.0.1 - simulate browser mouse and keyboard events + * https://github.com/jquery/jquery-simulate + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * Date: Sun Dec 9 12:15:33 2012 -0500 + */ + +;(function( $, undefined ) { + +var rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/; + +$.fn.simulate = function( type, options ) { + return this.each(function() { + new $.simulate( this, type, options ); + }); +}; + +$.simulate = function( elem, type, options ) { + var method = $.camelCase( "simulate-" + type ); + + this.target = elem; + this.options = options; + + if ( this[ method ] ) { + this[ method ](); + } else { + this.simulateEvent( elem, type, options ); + } +}; + +$.extend( $.simulate, { + + keyCode: { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 + }, + + buttonCode: { + LEFT: 0, + MIDDLE: 1, + RIGHT: 2 + } +}); + +$.extend( $.simulate.prototype, { + + simulateEvent: function( elem, type, options ) { + var event = this.createEvent( type, options ); + this.dispatchEvent( elem, type, event, options ); + }, + + createEvent: function( type, options ) { + if ( rkeyEvent.test( type ) ) { + return this.keyEvent( type, options ); + } + + if ( rmouseEvent.test( type ) ) { + return this.mouseEvent( type, options ); + } + }, + + mouseEvent: function( type, options ) { + var event, eventDoc, doc, body; + options = $.extend({ + bubbles: true, + cancelable: (type !== "mousemove"), + view: window, + detail: 0, + screenX: 0, + screenY: 0, + clientX: 1, + clientY: 1, + ctrlKey: false, + altKey: false, + shiftKey: false, + metaKey: false, + button: 0, + relatedTarget: undefined + }, options ); + + if ( document.createEvent ) { + event = document.createEvent( "MouseEvents" ); + event.initMouseEvent( type, options.bubbles, options.cancelable, + options.view, options.detail, + options.screenX, options.screenY, options.clientX, options.clientY, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, + options.button, options.relatedTarget || document.body.parentNode ); + + // IE 9+ creates events with pageX and pageY set to 0. + // Trying to modify the properties throws an error, + // so we define getters to return the correct values. + if ( event.pageX === 0 && event.pageY === 0 && Object.defineProperty ) { + eventDoc = event.relatedTarget.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + Object.defineProperty( event, "pageX", { + get: function() { + return options.clientX + + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - + ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + } + }); + Object.defineProperty( event, "pageY", { + get: function() { + return options.clientY + + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - + ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + }); + } + } else if ( document.createEventObject ) { + event = document.createEventObject(); + $.extend( event, options ); + // standards event.button uses constants defined here: http://msdn.microsoft.com/en-us/library/ie/ff974877(v=vs.85).aspx + // old IE event.button uses constants defined here: http://msdn.microsoft.com/en-us/library/ie/ms533544(v=vs.85).aspx + // so we actually need to map the standard back to oldIE + event.button = { + 0: 1, + 1: 4, + 2: 2 + }[ event.button ] || event.button; + } + + return event; + }, + + keyEvent: function( type, options ) { + var event; + options = $.extend({ + bubbles: true, + cancelable: true, + view: window, + ctrlKey: false, + altKey: false, + shiftKey: false, + metaKey: false, + keyCode: 0, + charCode: undefined + }, options ); + + if ( document.createEvent ) { + try { + event = document.createEvent( "KeyEvents" ); + event.initKeyEvent( type, options.bubbles, options.cancelable, options.view, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, + options.keyCode, options.charCode ); + // initKeyEvent throws an exception in WebKit + // see: http://stackoverflow.com/questions/6406784/initkeyevent-keypress-only-works-in-firefox-need-a-cross-browser-solution + // and also https://bugs.webkit.org/show_bug.cgi?id=13368 + // fall back to a generic event until we decide to implement initKeyboardEvent + } catch( err ) { + event = document.createEvent( "Events" ); + event.initEvent( type, options.bubbles, options.cancelable ); + $.extend( event, { + view: options.view, + ctrlKey: options.ctrlKey, + altKey: options.altKey, + shiftKey: options.shiftKey, + metaKey: options.metaKey, + keyCode: options.keyCode, + charCode: options.charCode + }); + } + } else if ( document.createEventObject ) { + event = document.createEventObject(); + $.extend( event, options ); + } + + if ( !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ) || (({}).toString.call( window.opera ) === "[object Opera]") ) { + event.keyCode = (options.charCode > 0) ? options.charCode : options.keyCode; + event.charCode = undefined; + } + + return event; + }, + + dispatchEvent: function( elem, type, event ) { + if ( elem.dispatchEvent ) { + elem.dispatchEvent( event ); + } else if ( elem.fireEvent ) { + elem.fireEvent( "on" + type, event ); + } + }, + + simulateFocus: function() { + var focusinEvent, + triggered = false, + element = $( this.target ); + + function trigger() { + triggered = true; + } + + element.bind( "focus", trigger ); + element[ 0 ].focus(); + + if ( !triggered ) { + focusinEvent = $.Event( "focusin" ); + focusinEvent.preventDefault(); + element.trigger( focusinEvent ); + element.triggerHandler( "focus" ); + } + element.unbind( "focus", trigger ); + }, + + simulateBlur: function() { + var focusoutEvent, + triggered = false, + element = $( this.target ); + + function trigger() { + triggered = true; + } + + element.bind( "blur", trigger ); + element[ 0 ].blur(); + + // blur events are async in IE + setTimeout(function() { + // IE won't let the blur occur if the window is inactive + if ( element[ 0 ].ownerDocument.activeElement === element[ 0 ] ) { + element[ 0 ].ownerDocument.body.focus(); + } + + // Firefox won't trigger events if the window is inactive + // IE doesn't trigger events if we had to manually focus the body + if ( !triggered ) { + focusoutEvent = $.Event( "focusout" ); + focusoutEvent.preventDefault(); + element.trigger( focusoutEvent ); + element.triggerHandler( "blur" ); + } + element.unbind( "blur", trigger ); + }, 1 ); + } +}); + + + +/** complex events **/ + +function findCenter( elem ) { + var offset, + document = $( elem.ownerDocument ); + elem = $( elem ); + offset = elem.offset(); + + return { + x: offset.left + elem.outerWidth() / 2 - document.scrollLeft(), + y: offset.top + elem.outerHeight() / 2 - document.scrollTop() + }; +} + +function findCorner( elem ) { + var offset, + document = $( elem.ownerDocument ); + elem = $( elem ); + offset = elem.offset(); + + return { + x: offset.left - document.scrollLeft(), + y: offset.top - document.scrollTop() + }; +} + +$.extend( $.simulate.prototype, { + simulateDrag: function() { + var i = 0, + target = this.target, + options = this.options, + center = options.handle === "corner" ? findCorner( target ) : findCenter( target ), + x = Math.floor( center.x ), + y = Math.floor( center.y ), + coord = { clientX: x, clientY: y }, + dx = options.dx || ( options.x !== undefined ? options.x - x : 0 ), + dy = options.dy || ( options.y !== undefined ? options.y - y : 0 ), + moves = options.moves || 3; + + this.simulateEvent( target, "mousedown", coord ); + + for ( ; i < moves ; i++ ) { + x += dx / moves; + y += dy / moves; + + coord = { + clientX: Math.round( x ), + clientY: Math.round( y ) + }; + + this.simulateEvent( document, "mousemove", coord ); + } + + this.simulateEvent( target, "mouseup", coord ); + this.simulateEvent( target, "click", coord ); + } +}); + +})( jQuery ); diff --git a/test/test.html b/test/test.html index a88ca967..37a9afe4 100644 --- a/test/test.html +++ b/test/test.html @@ -12,7 +12,9 @@
+ + \ No newline at end of file diff --git a/test/util.js b/test/util.js new file mode 100644 index 00000000..a426bd52 --- /dev/null +++ b/test/util.js @@ -0,0 +1,32 @@ +(function() { + + // ---------- + window.Util = { + // ---------- + simulateViewerClick: function(viewer, widthFactor, heightFactor) { + if (widthFactor === undefined) { + widthFactor = 0.5; + } + + if (heightFactor === undefined) { + heightFactor = 0.5; + } + + widthFactor = Math.min(1, Math.max(0, widthFactor)); + heightFactor = Math.min(1, Math.max(0, heightFactor)); + + var $canvas = $(viewer.element).find('.openseadragon-canvas').not('.navigator .openseadragon-canvas'); + var offset = $canvas.offset(); + var event = { + clientX: offset.left + Math.floor($canvas.width() * widthFactor), + clientY: offset.top + Math.floor($canvas.height() * heightFactor) + }; + + $canvas + .simulate('mouseover', event) + .simulate('mousedown', event) + .simulate('mouseup', event); + } + }; + +})(); From f0c4f5a875f902935b1cb8f2e73a2ce57a4ea738 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 22 Mar 2013 09:40:37 -0700 Subject: [PATCH 3/5] Fixed git-describe grunt task --- Gruntfile.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 9dbc730a..b400e2e3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -66,7 +66,7 @@ module.exports = function(grunt) { options: { banner: "//! <%= pkg.name %> <%= pkg.version %>\n" + "//! Built on <%= grunt.template.today('yyyy-mm-dd') %>\n" - + "//! <%= grunt.config.get('describeResult') %>\n" + + "//! Git commit: <%= gitInfo %>\n" + "//! http://openseadragon.github.com\n\n", process: true }, @@ -135,7 +135,10 @@ module.exports = function(grunt) { }, "git-describe": { options: { - prop: "describeResult" + prop: "gitInfo" + }, + build: { + // Nothing here; we just need it in order to trigger this task } } }); From 57f4cf15494c4158c94092461f343f82549dd71e Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 22 Mar 2013 09:42:51 -0700 Subject: [PATCH 4/5] A little git-describe cleanup --- Gruntfile.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index b400e2e3..6a94d6a3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -134,11 +134,10 @@ module.exports = function(grunt) { afterconcat: [ distribution ] }, "git-describe": { - options: { - prop: "gitInfo" - }, build: { - // Nothing here; we just need it in order to trigger this task + options: { + prop: "gitInfo" + } } } }); From 557927e4c0cbb84a25e5dea9454e500d18d749a1 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 22 Mar 2013 09:51:37 -0700 Subject: [PATCH 5/5] Removed "We've upgraded Grunt" message; it's been a month --- README.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/README.md b/README.md index aaac7786..ae259f02 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,6 @@ This project is a fork of the OpenSeadragon project at http://openseadragon.code http://openseadragon.github.com/ -## We've upgraded to Grunt 0.4.0! Please follow these directions if you've built OpenSeadragon prior to Feb 22, 2013: - -If you're new here, you can skip down to the "First Time Setup" section. - -1. If you had already installed Grunt globally, you now need to uninstall it: `npm uninstall -g grunt` -1. Delete the `build` and `node_modules` folders in your openseadragon directory -1. On the command line, go in to the openseadragon folder -1. Run `npm install -g grunt-cli` (this will install the Grunt command line runner) -1. Run `npm install` - -For more information on the upgrade, see http://gruntjs.com/upgrading-from-0.3-to-0.4 - ## First Time Setup All command-line operations are scripted using [Grunt](http://gruntjs.com/) which is based on [Node.js](http://nodejs.org/). To get set up: