From 3d2fb54ea3029bfc9b43cb1ce769db43d784e7c7 Mon Sep 17 00:00:00 2001 From: thatcher Date: Fri, 8 Mar 2013 20:27:08 -0500 Subject: [PATCH] initial attempt at cleaning up events in terms of where they are raised, how they affect default behavior, and how the affect other handlers. I need to do another pass because its clear that we want to be able to independently prevent default and stop propagation just like normal javascript events --- src/drawer.js | 102 +++++++++++++---------------- src/eventhandler.js | 12 ++-- src/viewer.js | 155 +++++++++++++++++++++++++++----------------- src/viewport.js | 97 +++++++++++++++------------ 4 files changed, 201 insertions(+), 165 deletions(-) diff --git a/src/drawer.js b/src/drawer.js index 2fe5c4ba..41f04a1e 100644 --- a/src/drawer.js +++ b/src/drawer.js @@ -133,25 +133,31 @@ $.Drawer.prototype = { * @param {OpenSeadragon.OverlayPlacement} placement - The position of the * viewport which the location coordinates will be treated as relative * to. + * @return {OpenSeadragon.Drawer} Chainable. */ addOverlay: function( element, location, placement ) { + var stop; element = $.getElement( element ); - if ( getOverlayIndex( this.overlays, element ) >= 0 ) { - // they're trying to add a duplicate overlay - return; - } - - this.overlays.push( new $.Overlay( element, location, placement ) ); - this.updateAgain = true; if( this.viewer ){ - this.viewer.raiseEvent( 'add-overlay', { + stop = this.viewer.raiseEvent( 'addoverlay', { viewer: this.viewer, element: element, location: location, placement: placement }); + if( false === stop ){ + return this; + } } + + if ( getOverlayIndex( this.overlays, element ) >= 0 ) { + // they're trying to add a duplicate overlay + return this; + } + + this.overlays.push( new $.Overlay( element, location, placement ) ); + this.updateAgain = true; return this; }, @@ -167,22 +173,27 @@ $.Drawer.prototype = { * @return {OpenSeadragon.Drawer} Chainable. */ updateOverlay: function( element, location, placement ) { - var i; + var i, + stop; element = $.getElement( element ); i = getOverlayIndex( this.overlays, element ); - if ( i >= 0 ) { - this.overlays[ i ].update( location, placement ); - this.updateAgain = true; - } if( this.viewer ){ - this.viewer.raiseEvent( 'update-overlay', { + stop = this.viewer.raiseEvent( 'updateoverlay', { viewer: this.viewer, element: element, location: location, placement: placement }); + if( false === stop ){ + return this; + } + } + + if ( i >= 0 ) { + this.overlays[ i ].update( location, placement ); + this.updateAgain = true; } return this; }, @@ -201,17 +212,21 @@ $.Drawer.prototype = { element = $.getElement( element ); i = getOverlayIndex( this.overlays, element ); + if( this.viewer ){ + stop = this.viewer.raiseEvent( 'removeoverlay', { + viewer: this.viewer, + element: element + }); + if( false === stop ){ + return this; + } + } + if ( i >= 0 ) { this.overlays[ i ].destroy(); this.overlays.splice( i, 1 ); this.updateAgain = true; } - if( this.viewer ){ - this.viewer.raiseEvent( 'remove-overlay', { - viewer: this.viewer, - element: element - }); - } return this; }, @@ -222,15 +237,19 @@ $.Drawer.prototype = { * @return {OpenSeadragon.Drawer} Chainable. */ clearOverlays: function() { - while ( this.overlays.length > 0 ) { - this.overlays.pop().destroy(); - this.updateAgain = true; - } + var stop; if( this.viewer ){ - this.viewer.raiseEvent( 'clear-overlay', { + stop = this.viewer.raiseEvent( 'clearoverlay', { viewer: this.viewer, element: element }); + if( false === stop ){ + return this; + } + } + while ( this.overlays.length > 0 ) { + this.overlays.pop().destroy(); + this.updateAgain = true; } return this; }, @@ -412,12 +431,6 @@ function updateViewport( drawer ) { drawer.updateAgain = false; - if( drawer.viewer ){ - drawer.viewer.raiseEvent( 'update-viewport', { - viewer: drawer.viewer - }); - } - var tile, level, best = null, @@ -571,20 +584,6 @@ function updateLevel( drawer, haveDrawn, level, levelOpacity, levelVisibility, v viewportCenter = drawer.viewport.pixelFromPoint( drawer.viewport.getCenter() ); - if( drawer.viewer ){ - drawer.viewer.raiseEvent( 'update-level', { - viewer: drawer.viewer, - havedrawn: haveDrawn, - level: level, - opacity: levelOpacity, - visibility: levelVisibility, - topleft: viewportTopLeft, - bottomright: viewportBottomRight, - currenttime: currentTime, - best: best - }); - } - //OK, a new drawing so do your calculations tileTL = drawer.source.getTileAtPoint( level, viewportTL ); tileBR = drawer.source.getTileAtPoint( level, viewportBR ); @@ -636,13 +635,6 @@ function updateTile( drawer, drawLevel, haveDrawn, x, y, level, levelOpacity, le drawTile = drawLevel, newbest; - if( drawer.viewer ){ - drawer.viewer.raiseEvent( 'update-tile', { - viewer: drawer.viewer, - tile: tile - }); - } - setCoverage( drawer.coverage, level, x, y, false ); if ( !tile.exists ) { @@ -1140,12 +1132,6 @@ function drawTiles( drawer, lastDrawn ){ } } - if( drawer.viewer ){ - drawer.viewer.raiseEvent( 'tile-drawn', { - viewer: drawer.viewer, - tile: tile - }); - } } } diff --git a/src/eventhandler.js b/src/eventhandler.js index 2635e86a..b4f9f677 100644 --- a/src/eventhandler.js +++ b/src/eventhandler.js @@ -81,10 +81,14 @@ $.EventHandler.prototype = { Array.apply( null, events ); return function( source, args ) { var i, - length = events.length; + length = events.length, + stop; for ( i = 0; i < length; i++ ) { - if( events[ i ] ){ - events[ i ]( source, args ); + if( $.isFunction( events[ i ] ) { + stop = events[ i ].apply( source, args ); + if( stop === false ){ + return stop; + } } } }; @@ -106,7 +110,7 @@ $.EventHandler.prototype = { eventArgs = {}; } - handler( this, eventArgs ); + return handler( this, eventArgs ); } } }; diff --git a/src/viewer.js b/src/viewer.js index 16cd3210..33f30579 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -342,6 +342,11 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, overlay, i; + if( false === this.raiseEvent( 'open', { source: source } ) ){ + //cancel open + return this; + } + if ( this.source ) { this.close( ); } @@ -506,8 +511,6 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, this.navigator.open( source ); } - this.raiseEvent( 'open', { source: source, viewer: this } ); - return this; }, @@ -517,6 +520,10 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, * @return {OpenSeadragon.Viewer} Chainable. */ close: function ( ) { + if( false === this.raiseEvent( 'close' ) ){ + //cancel close + return this; + } if( this.drawer ){ this.drawer.clearOverlays(); @@ -531,8 +538,6 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, VIEWERS[ this.hash ] = null; delete VIEWERS[ this.hash ]; - - this.raiseEvent( 'close', { viewer: this } ); return this; }, @@ -553,8 +558,11 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, * @return {OpenSeadragon.Viewer} Chainable. */ setMouseNavEnabled: function( enabled ){ + if( false === this.raiseEvent( enabled ? 'activate' : 'deactivate' ) ){ + //cancel activation/deactivation of mouse/touch/keyboard interactive + return this; + } this.innerTracker.setTracking( enabled ); - this.raiseEvent( 'mouse-enabled', { enabled: enabled, viewer: this } ); return this; }, @@ -580,12 +588,15 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, * @return {OpenSeadragon.Viewer} Chainable. */ setControlsEnabled: function( enabled ) { + if( false === this.raiseEvent( enabled ? 'showcontrols' : 'hidecontrols' ) ){ + //cancel show/hide of controls + return this; + } if( enabled ){ abortControlsAutoHide( this ); } else { beginControlsAutoHide( this ); } - this.raiseEvent( 'controls-enabled', { enabled: enabled, viewer: this } ); return this; }, @@ -622,6 +633,11 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, nodes, i; + if( false === this.raiseEvent( fullPage ? 'maximize' : 'minimize' ) ){ + //cancel maximize/minimize + return this; + } + //dont bother modifying the DOM if we are already in full page mode. if ( fullPage == this.isFullPage() ) { return; @@ -747,7 +763,6 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, $.delegate( this, onContainerExit )(); } - this.raiseEvent( 'fullpage', { fullpage: fullPage, viewer: this } ); if ( this.viewport ) { oldBounds = this.viewport.getBounds(); @@ -806,8 +821,11 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, * @return {OpenSeadragon.Viewer} Chainable. */ setVisible: function( visible ){ + if( false === this.raiseEvent( visible ? 'show' : 'hide' ) ){ + //cancel show/hide + return this; + } this.container.style.visibility = visible ? "" : "hidden"; - this.raiseEvent( 'visible', { visible: visible, viewer: this } ); return this; }, @@ -1026,9 +1044,11 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, * @return {OpenSeadragon.Viewer} Chainable. */ goToPage: function( page ){ - //page is a 1 based index so normalize now - //page = page; - this.raiseEvent( 'page', { page: page, viewer: this } ); + + if( false === this.raiseEvent( 'page', { page: page }) ){ + //cancel page change + return this; + } if( this.tileSources.length > page ){ @@ -1171,8 +1191,15 @@ function onBlur(){ function onCanvasClick( tracker, position, quick, shift, event ) { var zoomPreClick, - factor; - if ( this.viewport && quick ) { // ignore clicks where mouse moved + factor, + stop = this.raiseEvent( 'click', { + tracker: tracker, + position: position, + quick: quick, + shift: shift, + originalEvent: event + }); + if ( this.viewport && quick && stop !== false ) { // ignore clicks where mouse moved zoomPerClick = this.zoomPerClick; factor = shift ? 1.0 / zoomPerClick : zoomPerClick; this.viewport.zoomBy( @@ -1181,17 +1208,17 @@ function onCanvasClick( tracker, position, quick, shift, event ) { ); this.viewport.applyConstraints(); } - this.raiseEvent( 'click', { - tracker: tracker, - position: position, - quick: quick, - shift: shift, - originalEvent: event - }); } function onCanvasDrag( tracker, position, delta, shift, event ) { - if ( this.viewport ) { + var stop = this.raiseEvent( 'drag', { + tracker: tracker, + position: position, + delta: delta, + shift: shift, + originalEvent: event + }); + if ( this.viewport && stop !== false ) { if( !this.panHorizontal ){ delta.x = 0; } @@ -1207,91 +1234,91 @@ function onCanvasDrag( tracker, position, delta, shift, event ) { this.viewport.applyConstraints(); } } - this.raiseEvent( 'drag', { - tracker: tracker, - position: position, - delta: delta, - shift: shift, - originalEvent: event - }); } function onCanvasRelease( tracker, position, insideElementPress, insideElementRelease, event ) { - if ( insideElementPress && this.viewport ) { - this.viewport.applyConstraints(); - } - this.raiseEvent( 'release', { + var stop = this.raiseEvent( 'release', { tracker: tracker, position: position, insideElementPress: insideElementPress, insideElementRelease: insideElementRelease, originalEvent: event }); + if ( insideElementPress && this.viewport && stop !== false ) { + this.viewport.applyConstraints(); + } } function onCanvasScroll( tracker, position, scroll, shift, event ) { - var factor; - if ( this.viewport ) { + var factor, + stop = this.raiseEvent( 'scroll', { + tracker: tracker, + position: position, + scroll: scroll, + shift: shift, + originalEvent: event + }); + + if ( this.viewport && stop !== false ) { factor = Math.pow( this.zoomPerScroll, scroll ); this.viewport.zoomBy( factor, this.viewport.pointFromPixel( position, true ) ); this.viewport.applyConstraints(); + //cancels event + event.stopPropagation(); + event.preventDefault(); + return false; } - this.raiseEvent( 'scroll', { - tracker: tracker, - position: position, - scroll: scroll, - shift: shift, - originalEvent: event - }); - //cancels event - return false; } function onContainerExit( tracker, position, buttonDownElement, buttonDownAny, event ) { - if ( !buttonDownElement ) { - THIS[ this.hash ].mouseInside = false; - if ( !THIS[ this.hash ].animating ) { - beginControlsAutoHide( this ); - } - } - this.raiseEvent( 'exit', { + var stop = this.raiseEvent( 'exit', { tracker: tracker, position: position, buttonDownElement: buttonDownElement, buttonDownAny: buttonDownAny, originalEvent: event }); -} - -function onContainerRelease( tracker, position, insideElementPress, insideElementRelease, event ) { - if ( !insideElementRelease ) { + if ( !buttonDownElement ) { THIS[ this.hash ].mouseInside = false; - if ( !THIS[ this.hash ].animating ) { + if ( !THIS[ this.hash ].animating && stop !== false ) { beginControlsAutoHide( this ); } } - this.raiseEvent( 'release', { +} + +function onContainerRelease( tracker, position, insideElementPress, insideElementRelease, event ) { + var stop = this.raiseEvent( 'release', { tracker: tracker, position: position, insideElementPress: insideElementPress, insideElementRelease: insideElementRelease, originalEvent: event }); + + if ( !insideElementRelease ) { + THIS[ this.hash ].mouseInside = false; + if ( !THIS[ this.hash ].animating && stop !== false ) { + beginControlsAutoHide( this ); + } + } } function onContainerEnter( tracker, position, buttonDownElement, buttonDownAny, event ) { + var stop; THIS[ this.hash ].mouseInside = true; - abortControlsAutoHide( this ); - this.raiseEvent( 'enter', { + stop = this.raiseEvent( 'enter', { tracker: tracker, position: position, buttonDownElement: buttonDownElement, buttonDownAny: buttonDownAny, originalEvent: event }); + if( stop !== false ){ + abortControlsAutoHide( this ); + } } @@ -1337,16 +1364,20 @@ function updateOnce( viewer ) { } if ( !THIS[ viewer.hash ].animating && animated ) { - viewer.raiseEvent( "animationstart" ); + if( false === viewer.raiseEvent( "animationstart" ) ){ + return; + } abortControlsAutoHide( viewer ); } if ( animated ) { + if( false === viewer.raiseEvent( "animation" ) ){ + return; + } viewer.drawer.update(); if( viewer.navigator ){ viewer.navigator.update( viewer.viewport ); } - viewer.raiseEvent( "animation" ); } else if ( THIS[ viewer.hash ].forceRedraw || viewer.drawer.needsUpdate() ) { viewer.drawer.update(); if( viewer.navigator ){ @@ -1356,7 +1387,9 @@ function updateOnce( viewer ) { } if ( THIS[ viewer.hash ].animating && !animated ) { - viewer.raiseEvent( "animationfinish" ); + if( false === viewer.raiseEvent( "animationfinish" ) ){ + return; + } if ( !THIS[ viewer.hash ].mouseInside ) { beginControlsAutoHide( viewer ); diff --git a/src/viewport.js b/src/viewport.js index d5800cf1..f92db393 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -77,6 +77,13 @@ $.Viewport.prototype = { * @return {OpenSeadragon.Viewport} Chainable. */ resetContentSize: function( contentSize ){ + if( this.viewer ){ + if( false === this.viewer.raiseEvent( 'reset', { contentSize: contentSize } ) ){ + //cancel event + return this; + } + } + this.contentSize = contentSize; this.contentAspectX = this.contentSize.x / this.contentSize.y; this.contentAspectY = this.contentSize.y / this.contentSize.x; @@ -84,13 +91,6 @@ $.Viewport.prototype = { this.fitHeightBounds = new $.Rect( 0, 0, this.contentAspectY, this.contentAspectY); this.homeBounds = new $.Rect( 0, 0, 1, this.contentAspectY ); - - if( this.viewer ){ - this.viewer.raiseEvent( 'reset-size', { - contentSize: contentSize, - viewer: this.viewer - }); - } return this; }, @@ -133,10 +133,10 @@ $.Viewport.prototype = { */ goHome: function( immediately ) { if( this.viewer ){ - this.viewer.raiseEvent( 'home', { - immediately: immediately, - viewer: this.viewer - }); + if( false === this.viewer.raiseEvent( 'home', { immediately: immediately } ) ){ + //cancel event + return this; + } } return this.fitBounds( this.getHomeBounds(), immediately ); }, @@ -280,6 +280,13 @@ $.Viewport.prototype = { dy = 0, dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0; + if( this.viewer ){ + if( false === this.viewer.raiseEvent( 'constrain', { immediately: immediately } ) ){ + //cancel event + return this; + } + } + if ( actualZoom != constrainedZoom ) { this.zoomTo( constrainedZoom, this.zoomPoint, immediately ); } @@ -332,13 +339,6 @@ $.Viewport.prototype = { this.fitBounds( bounds, immediately ); } - if( this.viewer ){ - this.viewer.raiseEvent( 'constrain', { - immediately: immediately, - viewer: this.viewer - }); - } - return this; }, @@ -475,6 +475,18 @@ $.Viewport.prototype = { * @return {OpenSeadragon.Viewport} Chainable. */ panTo: function( center, immediately ) { + var stop; + if( this.viewer ){ + stop = this.viewer.raiseEvent( 'pan', { + center: center, + immediately: immediately + }); + if( stop === false ){ + //cancel event + return this; + } + } + if ( immediately ) { this.centerSpringX.resetTo( center.x ); this.centerSpringY.resetTo( center.y ); @@ -483,13 +495,6 @@ $.Viewport.prototype = { this.centerSpringY.springTo( center.y ); } - if( this.viewer ){ - this.viewer.raiseEvent( 'pan', { - center: center, - immediately: immediately, - viewer: this.viewer - }); - } return this; }, @@ -507,6 +512,18 @@ $.Viewport.prototype = { * @return {OpenSeadragon.Viewport} Chainable. */ zoomTo: function( zoom, refPoint, immediately ) { + var stop; + if( this.viewer ){ + stop = this.viewer.raiseEvent( 'zoom', { + zoom: zoom, + refPoint: refPoint, + immediately: immediately + }); + if( stop === false ){ + //cancel event; + return this; + } + } this.zoomPoint = refPoint instanceof $.Point ? refPoint : @@ -518,14 +535,6 @@ $.Viewport.prototype = { this.zoomSpring.springTo( zoom ); } - if( this.viewer ){ - this.viewer.raiseEvent( 'zoom', { - zoom: zoom, - refPoint: refPoint, - immediately: immediately, - viewer: this.viewer - }); - } return this; }, @@ -537,7 +546,19 @@ $.Viewport.prototype = { resize: function( newContainerSize, maintain ) { var oldBounds = this.getBounds(), newBounds = oldBounds, - widthDeltaFactor = newContainerSize.x / this.containerSize.x; + widthDeltaFactor = newContainerSize.x / this.containerSize.x, + stop; + + if( this.viewer ){ + stop = this.viewer.raiseEvent( 'resize', { + newContainerSize: newContainerSize, + maintain: maintain + }); + if( stop === false ){ + //cancel event + return this; + } + } this.containerSize = new $.Point( newContainerSize.x, @@ -549,14 +570,6 @@ $.Viewport.prototype = { newBounds.height = newBounds.width / this.getAspectRatio(); } - if( this.viewer ){ - this.viewer.raiseEvent( 'resize', { - newContainerSize: newContainerSize, - maintain: maintain, - viewer: this.viewer - }); - } - return this.fitBounds( newBounds, true ); },