/*
* ----------------------------------------------------------------
* Event Management
* ----------------------------------------------------------------
*/
var _listeners = {};
/**
* Scene start event.
* Fires whenever the scroll position its the starting point of the scene.
* It will also fire when scrolling back up going over the start position of the scene. If you want something to happen only when scrolling down/right, use the scrollDirection parameter passed to the callback.
*
* For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.
*
* @event ScrollMagic.Scene#start
*
* @example
* scene.on("start", function (event) {
* console.log("Hit start point of scene.");
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {number} event.progress - Reflects the current progress of the scene
* @property {string} event.state - The current state of the scene `"BEFORE"` or `"DURING"`
* @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`
*/
/**
* Scene end event.
* Fires whenever the scroll position its the ending point of the scene.
* It will also fire when scrolling back up from after the scene and going over its end position. If you want something to happen only when scrolling down/right, use the scrollDirection parameter passed to the callback.
*
* For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.
*
* @event ScrollMagic.Scene#end
*
* @example
* scene.on("end", function (event) {
* console.log("Hit end point of scene.");
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {number} event.progress - Reflects the current progress of the scene
* @property {string} event.state - The current state of the scene `"DURING"` or `"AFTER"`
* @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`
*/
/**
* Scene enter event.
* Fires whenever the scene enters the "DURING" state.
* Keep in mind that it doesn't matter if the scene plays forward or backward: This event always fires when the scene enters its active scroll timeframe, regardless of the scroll-direction.
*
* For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.
*
* @event ScrollMagic.Scene#enter
*
* @example
* scene.on("enter", function (event) {
* console.log("Scene entered.");
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {number} event.progress - Reflects the current progress of the scene
* @property {string} event.state - The current state of the scene - always `"DURING"`
* @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`
*/
/**
* Scene leave event.
* Fires whenever the scene's state goes from "DURING" to either "BEFORE" or "AFTER".
* Keep in mind that it doesn't matter if the scene plays forward or backward: This event always fires when the scene leaves its active scroll timeframe, regardless of the scroll-direction.
*
* For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.
*
* @event ScrollMagic.Scene#leave
*
* @example
* scene.on("leave", function (event) {
* console.log("Scene left.");
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {number} event.progress - Reflects the current progress of the scene
* @property {string} event.state - The current state of the scene `"BEFORE"` or `"AFTER"`
* @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`
*/
/**
* Scene update event.
* Fires whenever the scene is updated (but not necessarily changes the progress).
*
* @event ScrollMagic.Scene#update
*
* @example
* scene.on("update", function (event) {
* console.log("Scene updated.");
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {number} event.startPos - The starting position of the scene (in relation to the conainer)
* @property {number} event.endPos - The ending position of the scene (in relation to the conainer)
* @property {number} event.scrollPos - The current scroll position of the container
*/
/**
* Scene progress event.
* Fires whenever the progress of the scene changes.
*
* For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.
*
* @event ScrollMagic.Scene#progress
*
* @example
* scene.on("progress", function (event) {
* console.log("Scene progress changed to " + event.progress);
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {number} event.progress - Reflects the current progress of the scene
* @property {string} event.state - The current state of the scene `"BEFORE"`, `"DURING"` or `"AFTER"`
* @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`
*/
/**
* Scene change event.
* Fires whenvever a property of the scene is changed.
*
* @event ScrollMagic.Scene#change
*
* @example
* scene.on("change", function (event) {
* console.log("Scene Property \"" + event.what + "\" changed to " + event.newval);
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {string} event.what - Indicates what value has been changed
* @property {mixed} event.newval - The new value of the changed property
*/
/**
* Scene shift event.
* Fires whenvever the start or end **scroll offset** of the scene change.
* This happens explicitely, when one of these values change: `offset`, `duration` or `triggerHook`.
* It will fire implicitly when the `triggerElement` changes, if the new element has a different position (most cases).
* It will also fire implicitly when the size of the container changes and the triggerHook is anything other than `onLeave`.
*
* @event ScrollMagic.Scene#shift
* @since 1.1.0
*
* @example
* scene.on("shift", function (event) {
* console.log("Scene moved, because the " + event.reason + " has changed.)");
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {string} event.reason - Indicates why the scene has shifted
*/
/**
* Scene destroy event.
* Fires whenvever the scene is destroyed.
* This can be used to tidy up custom behaviour used in events.
*
* @event ScrollMagic.Scene#destroy
* @since 1.1.0
*
* @example
* scene.on("enter", function (event) {
* // add custom action
* $("#my-elem").left("200");
* })
* .on("destroy", function (event) {
* // reset my element to start position
* if (event.reset) {
* $("#my-elem").left("0");
* }
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {boolean} event.reset - Indicates if the destroy method was called with reset `true` or `false`.
*/
/**
* Scene add event.
* Fires when the scene is added to a controller.
* This is mostly used by plugins to know that change might be due.
*
* @event ScrollMagic.Scene#add
* @since 2.0.0
*
* @example
* scene.on("add", function (event) {
* console.log('Scene was added to a new controller.');
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
* @property {boolean} event.controller - The controller object the scene was added to.
*/
/**
* Scene remove event.
* Fires when the scene is removed from a controller.
* This is mostly used by plugins to know that change might be due.
*
* @event ScrollMagic.Scene#remove
* @since 2.0.0
*
* @example
* scene.on("remove", function (event) {
* console.log('Scene was removed from its controller.');
* });
*
* @property {object} event - The event Object passed to each callback
* @property {string} event.type - The name of the event
* @property {Scene} event.target - The Scene object that triggered this event
*/
/**
* Add one ore more event listener.
* The callback function will be fired at the respective event, and an object containing relevant data will be passed to the callback.
* @method ScrollMagic.Scene#on
*
* @example
* function callback (event) {
* console.log("Event fired! (" + event.type + ")");
* }
* // add listeners
* scene.on("change update progress start end enter leave", callback);
*
* @param {string} names - The name or names of the event the callback should be attached to.
* @param {function} callback - A function that should be executed, when the event is dispatched. An event object will be passed to the callback.
* @returns {Scene} Parent object for chaining.
*/
this.on = function (names, callback) {
if (_util.type.Function(callback)) {
names = names.trim().split(' ');
names.forEach(function (fullname) {
var
nameparts = fullname.split('.'),
eventname = nameparts[0],
namespace = nameparts[1];
if (eventname != "*") { // disallow wildcards
if (!_listeners[eventname]) {
_listeners[eventname] = [];
}
_listeners[eventname].push({
namespace: namespace || '',
callback: callback
});
}
});
} else {
log(1, "ERROR when calling '.on()': Supplied callback for '" + names + "' is not a valid function!");
}
return Scene;
};
/**
* Remove one or more event listener.
* @method ScrollMagic.Scene#off
*
* @example
* function callback (event) {
* console.log("Event fired! (" + event.type + ")");
* }
* // add listeners
* scene.on("change update", callback);
* // remove listeners
* scene.off("change update", callback);
*
* @param {string} names - The name or names of the event that should be removed.
* @param {function} [callback] - A specific callback function that should be removed. If none is passed all callbacks to the event listener will be removed.
* @returns {Scene} Parent object for chaining.
*/
this.off = function (names, callback) {
if (!names) {
log(1, "ERROR: Invalid event name supplied.");
return Scene;
}
names = names.trim().split(' ');
names.forEach(function (fullname, key) {
var
nameparts = fullname.split('.'),
eventname = nameparts[0],
namespace = nameparts[1] || '',
removeList = eventname === '*' ? Object.keys(_listeners) : [eventname];
removeList.forEach(function (remove){
var
list = _listeners[remove] || [],
i = list.length;
while(i--) {
var listener = list[i];
if (listener && (namespace === listener.namespace || namespace === '*') && (!callback || callback == listener.callback)) {
list.splice(i, 1);
}
}
if (!list.length) {
delete _listeners[remove];
}
});
});
return Scene;
};
/**
* Trigger an event.
* @method ScrollMagic.Scene#trigger
*
* @example
* this.trigger("change");
*
* @param {string} name - The name of the event that should be triggered.
* @param {object} [vars] - An object containing info that should be passed to the callback.
* @returns {Scene} Parent object for chaining.
*/
this.trigger = function (name, vars) {
if (name) {
var
nameparts = name.trim().split('.'),
eventname = nameparts[0],
namespace = nameparts[1],
listeners = _listeners[eventname];
log(3, 'event fired:', eventname, vars ? "->" : '', vars || '');
if (listeners) {
listeners.forEach(function (listener, key) {
if (!namespace || namespace === listener.namespace) {
listener.callback.call(Scene, new ScrollMagic.Event(eventname, listener.namespace, Scene, vars));
}
});
}
} else {
log(1, "ERROR: Invalid event name supplied.");
}
return Scene;
};