Skip to content
This repository has been archived by the owner on Aug 31, 2022. It is now read-only.

Commit

Permalink
Merge pull request #37 from filamentgroup/namespaced-events
Browse files Browse the repository at this point in the history
Namespaced events: Merging per discussion in chat room.
  • Loading branch information
zachleat committed Aug 28, 2014
2 parents 6ae6771 + 5aef2d0 commit 0d7d210
Show file tree
Hide file tree
Showing 5 changed files with 408 additions and 61 deletions.
54 changes: 36 additions & 18 deletions src/events/bind.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ define([ "shoestring", "dom/closest" ], function(){

var evts = evt.split( " " ),
docEl = document.documentElement,
addToEventCache = function( el, evt, callback ) {
addToEventCache = function( el, evt, eventInfo ) {
if ( !el.shoestringData ) {
el.shoestringData = {};
}
Expand All @@ -30,19 +30,25 @@ define([ "shoestring", "dom/closest" ], function(){
el.shoestringData.events[ evt ] = [];
}
var obj = {};
if( callback.customCallfunc ) {
if( eventInfo.customCallfunc ) {
obj.isCustomEvent = true;
}
obj.callback = callback.customCallfunc || callback.callfunc;
obj.originalCallback = callback.originalCallback;
obj.callback = eventInfo.customCallfunc || eventInfo.callfunc;
obj.originalCallback = eventInfo.originalCallback;
obj.namespace = eventInfo.namespace;

el.shoestringData.events[ evt ].push( obj );
};

function encasedCallback( e ){
function encasedCallback( e, namespace ){
var result;

if( e._namespace && e._namespace !== namespace ) {
return;
}

e.data = data;
e.namespace = e._namespace;

var returnTrue = function(){
return true;
Expand Down Expand Up @@ -85,19 +91,22 @@ define([ "shoestring", "dom/closest" ], function(){
}

// This is exclusively for custom events on browsers without addEventListener (IE8)
function propChange( originalEvent, boundElement ) {
var triggeredElement = document.documentElement[ originalEvent.propertyName ].el;
function propChange( originalEvent, boundElement, namespace ) {
var lastEventInfo = document.documentElement[ originalEvent.propertyName ],
triggeredElement = lastEventInfo.el;

if( triggeredElement !== undefined && shoestring( triggeredElement ).closest( boundElement ).length ) {
encasedCallback.call( triggeredElement, originalEvent );
originalEvent._namespace = lastEventInfo._namespace;
originalEvent._args = lastEventInfo._args;
encasedCallback.call( triggeredElement, originalEvent, namespace );
}
}

// In IE8 the events trigger in a reverse order. This code unbinds and
// rebinds all callbacks on an element in the correct order.
function reorderEvents( eventName ) {
if( !this.attachEvent ) {
// do onthing
// do nothing
return;
} else if( this.shoestringData && this.shoestringData.events ) {
var otherEvents = this.shoestringData.events[ eventName ];
Expand All @@ -117,35 +126,44 @@ define([ "shoestring", "dom/closest" ], function(){
var domEventCallback, customEventCallback, oEl = this;

for( var i = 0, il = evts.length; i < il; i++ ){
var evt = evts[ i ];
domEventCallback = null;
var split = evts[ i ].split( "." ),
evt = split[ 0 ],
namespace = split.length > 0 ? split[ 1 ] : null;

domEventCallback = function( originalEvent ) {
if( oEl.ssEventTrigger ) {
originalEvent._namespace = oEl.ssEventTrigger._namespace;
originalEvent._args = oEl.ssEventTrigger._args;

oEl.ssEventTrigger = null;
}
return encasedCallback.call( oEl, originalEvent, namespace );
};
customEventCallback = null;

if( "addEventListener" in this ){
this.addEventListener( evt, encasedCallback, false );
this.addEventListener( evt, domEventCallback, false );
} else if( this.attachEvent ){
if( this[ "on" + evt ] !== undefined ) {
domEventCallback = function( originalEvent ) {
return encasedCallback.call( oEl, originalEvent );
};
this.attachEvent( "on" + evt, domEventCallback );
} else {
customEventCallback = (function() {
var eventName = evt;
return function( e ) {
if( e.propertyName === eventName ) {
propChange.call( this, e, oEl );
propChange.call( this, e, oEl, namespace );
}
};
})();
docEl.attachEvent( "onpropertychange", customEventCallback );
}
}

addToEventCache( this, evts[ i ], {
addToEventCache( this, evt, {
callfunc: domEventCallback || encasedCallback,
customCallfunc: customEventCallback,
originalCallback: originalCallback
originalCallback: originalCallback,
namespace: namespace
});

reorderEvents.call( oEl, evt );
Expand Down
19 changes: 15 additions & 4 deletions src/events/trigger.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,30 @@ define([ "shoestring" ], function(){
var evts = evt.split( " " );

return this.each(function(){
var split, evt, namespace;
for( var i = 0, il = evts.length; i < il; i++ ){
split = evts[ i ].split( "." ),
evt = split[ 0 ],
namespace = split.length > 0 ? split[ 1 ] : null;

if( document.createEvent ){
var event = document.createEvent( "Event" );
event.initEvent( evts[ i ], true, true );
event.initEvent( evt, true, true );
event._args = args;
event._namespace = namespace;

this.dispatchEvent( event );
} else if ( document.createEventObject ) {
if( ( "" + this[ evts[ i ] ] ).indexOf( "function" ) > -1 ) {
this[ evts[ i ] ]();
if( ( "" + this[ evt ] ).indexOf( "function" ) > -1 ) {
this.ssEventTrigger = {
_namespace: namespace,
_args: args
};
this[ evt ]();
} else {
document.documentElement[ evts[ i ] ] = {
document.documentElement[ evt ] = {
"el": this,
_namespace: namespace,
_args: args
};
}
Expand Down
78 changes: 49 additions & 29 deletions src/events/unbind.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,61 @@
define([ "shoestring" ], function(){
//>>excludeEnd("exclude");

shoestring.fn.unbind = function( evt, callback ){
var evts = evt.split( " " ),
docEl = document.documentElement;
function unbind( evt, namespace, callback ) {
var bound = this.shoestringData.events[ evt ];
if( !bound.length ) {
return;
}

for( var j = 0, jl = bound.length; j < jl; j++ ) {
if( !namespace || namespace === bound[ j ].namespace ) {
if( "removeEventListener" in window ){
if( callback === undefined ) {
this.removeEventListener( evt, bound[ j ].callback, false );
} else if( callback === bound[ j ].originalCallback ) {
this.removeEventListener( evt, bound[ j ].callback, false );
}
} else if( this.detachEvent ){
if( callback === undefined ) {
this.detachEvent( "on" + evt, bound[ j ].callback );
// custom event
document.documentElement.detachEvent( "onpropertychange", bound[ j ].callback );
} else if( callback === bound[ j ].originalCallback ) {
this.detachEvent( "on" + evt, bound[ j ].callback );
// custom event
document.documentElement.detachEvent( "onpropertychange", bound[ j ].callback );
}
}
}
}
}

function unbindAll( namespace, callback ) {
for( var evtKey in this.shoestringData.events ) {
unbind.call( this, evtKey, namespace, callback );
}
}

shoestring.fn.unbind = function( str, callback ){
var evts = str ? str.split( " " ) : [];
return this.each(function(){
if( !this.shoestringData || !this.shoestringData.events ) {
return;
}

for( var i = 0, il = evts.length; i < il; i++ ){
//>>includeStart("development", pragmas.development);
if( evts[ i ].indexOf( "." ) === 0 ) {
shoestring.error( 'event-namespaces' );
}
//>>includeEnd("development");
if( !evts.length ) {
unbindAll.call( this );
} else {
var split, evt, namespace;
for( var i = 0, il = evts.length; i < il; i++ ){
split = evts[ i ].split( "." ),
evt = split[ 0 ],
namespace = split.length > 0 ? split[ 1 ] : null;

var bound = this.shoestringData.events[ evts[ i ] ];
if( bound ) {
for( var j = 0, jl = bound.length; j < jl; j++ ) {
if( "removeEventListener" in window ){
if( callback === undefined ) {
this.removeEventListener( evts[ i ], bound[ j ].callback, false );
} else if( callback === bound[ j ].originalCallback ) {
this.removeEventListener( evts[ i ], bound[ j ].callback, false );
}
} else if( this.detachEvent ){
if( callback === undefined ) {
this.detachEvent( "on" + evts[ i ], bound[ j ].callback );
// custom event
docEl.detachEvent( "onpropertychange", bound[ j ].callback );
} else if( callback === bound[ j ].originalCallback ) {
this.detachEvent( "on" + evts[ i ], bound[ j ].callback );
// custom event
docEl.detachEvent( "onpropertychange", bound[ j ].callback );
}
}
if( evt ) {
unbind.call( this, evt, namespace, callback );
} else {
unbindAll.call( this, namespace, callback );
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/util/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ define([ "shoestring" ], function(){

"click": "the click method. Try using trigger( 'click' ) instead.",
"css-get" : "getting computed attributes from the DOM.",
"event-namespaces": "event namespacing, especially on .unbind( '.myNamespace' ). An event namespace is treated as part of the event name.",
"has-class" : "the hasClass method. Try using .is( '.klassname' ) instead.",
"live-delegate" : "the .live or .delegate methods. Use .bind or .on instead.",
"map": "the map method. Try using .each to make a new object.",
Expand Down
Loading

0 comments on commit 0d7d210

Please sign in to comment.