This works:
OpenLayers.Handler.PolygonHolePuncherHandler = (function PolygonHolePuncherHandler_module( OpenLayers, undefined )
{
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=//
/**
* Example:
var drawControl = new OpenLayers.Control.DrawFeature(
olVectorLayer,
OpenLayers.Handler.PolygonHolePuncherHandler,
{
'handlerOptions':
{
'events':
{
'beforepunchinghole':function( evt )
{return( document.getElementById( 'is_punching' ).checked );}
},
'holeModifier':'altKey'
}
}
);
olMap.addControl( drawControl );
drawControl.activate();
*/
var PolygonHolePuncherHandler = OpenLayers.Class( OpenLayers.Handler.Polygon,
{
/**
* Constructor: OpenLayers.Handler.PolygonHolePuncherHandler
* Create a Polygon Handler.
*
* Parameters:
* control - {<OpenLayers.Control>} The control that owns this handler
* eventListeners - {Object} An object with a properties whose values are
* functions. Events described below.
* options - {Object} An optional object with properties to be set on the
* handler
*
* Named events:
* beforepunchinghole - Called to determine whether hole punching should be performed.
* The callback will receive (a copy of) the polygon geometry.
*/
'CLASS_NAME':'OpenLayers.Handler.PolygonHolePuncherHandler',
'addPoint':function PolygonHolePuncherHandler_addPoint( olPixel )
{
var before_punching_hole = this.events.triggerEvent( 'beforepunchinghole' );
// If the event handler returns "truthy" or has nothing to say.
if( !!before_punching_hole || before_punching_hole === undefined )
{
if( !!before_punching_hole )
{
this.evt = OpenLayers.Util.extend({}, this.evt );
this.evt[ this.holeModifier ] = is_punching;
}
// else 'before_punching_hole' is undefined, assume nothing.
}
// else 'before_punching_hole' is false, do not override.
// Forward the call to the parent, OpenLayers.Handler.Polygon.
return( OpenLayers.Handler.Polygon.prototype.addPoint.apply( this, arguments ));
},
'destroy':function PolygonHolePuncherHandler_destroy()
{
if( !!this.events )
{
if( !!this.eventListeners )
{this.events.un( this.eventListeners );}
this.events.destroy();
this.events = null;
}
this.eventListeners = null;
this.options = null;
return( OpenLayers.Handler.Polygon.prototype['destroy'].apply( this, arguments ));
},
'initialize':function PolygonHolePuncherHandler_initialize( olControl, callbacks, options )
{
// backup original options
this.options = OpenLayers.Util.extend({}, options );
// now override default options
OpenLayers.Util.extend( this, options );
this.events = new OpenLayers.Events( this );
// register event listeners
if( this.eventListeners instanceof Object )
{this.events.on( this.eventListeners );}
return( OpenLayers.Handler.Polygon.prototype['initialize'].apply( this, arguments ));
},
});
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=//
return( PolygonHolePuncherHandler );
})( OpenLayers );
The "magic" is that this handler intercepts the 'addPoint' calls, gives the developer the opportunity to override drawing a hole (does not disable drawing holes), conditionally overrides the event's 'holeModifier' property ('altKey', 'ctrlKey', or 'shiftKey') by replacing it, then forwards the calls to the default Polygon handler. So, in the 'beforepunchinghole' handler, check the state of a checkbox (or some other form of toggle) to indicate whether a hole is being drawn.
The 'destroy' and 'initialize' overrides are used to manage the 'events' property configured with the 'eventListeners' option.
More work needs to be done to find an inexpensive way of checking whether the point intersects a feature. If it's not intersecting one, don't trigger the 'beforepunchinghole' event.