(function (window) {
/** GLOBAL HELPERS
* ----------
*/
/** used to delete circular references which lead to memory leaks
* ----------
* @param references {Objects}: one or more references to nullify
*/
var free = function (references) {
var i = 0,
l;
for (l = arguments.length; i < l; i += 1) {
arguments[i] = null;
}
};
/** checks if the given node owns the given class
* ----------
* @param node {DOMNode}: the node to check
* @param clnm {String}: the class to be checked
* @returns {Boolean}: true if the given node owns the class, otherwise false
*/
var hasClass = function (node, clnm) {
var regex = new RegExp('\\s+?' + clnm + '\\b');
return regex.test(node.className);
};
/** adds the given class to the given node if the node does not own the class,
* otherwise it removes the given class
* ----------
* @param node {DOMNode}: the node
* @param clnm {String}: the class to add/remove
* @returns {Boolean}: always true
*/
var handleClass = function (node, clnm) {
var regex,
clnms;
if (hasClass(node, clnm)) {
regex = new RegExp('\\s+?' + clnm + '\\b', 'g');
node.className = node.className.replace(regex, '');
free(regex);
return true;
}
regex = /\s+/;
clnms = node.className.split(regex);
clnms[clnms.length] = clnm;
node.className = clnms.join(' ');
free(regex, clnms);
return true;
};
/** binds ('hitches') a function to be executed in the given context, e. g.: sets
* the this keyword to refer to the given context
* ----------
* @param handler {Function}: function to hitch
* @param context {Object}: the new scope for handler
* @returns {Function}: a new function with bound ('hitched') scope
*/
var hitch = function (handler, context) {
return function () {
var args = Array.prototype.slice.call(arguments);
handler.apply(context, args);
};
};
/** same as hitch, but designed for usage with eventListeners
* ----------
* @param handler {Function}: function to hitch
* @param context {Object}: the new scope for handler
* @returns {Function}: a new function with bound ('hitched') scope
*/
hitch.event = function (handler, context) {
return function (event) {
var args = Array.prototype.slice.call(arguments, 1);
args.unshift(fixEvents(event, context));
handler.apply(context, args);
};
};
/** wipes out some differences between Microsofts implementation of the event object
* and the standard (W3C) event object
* ----------
* @param event {Event Object}: generic event object
* @param context {Object}: context to be set as event.target
* @returns {Event Object}: a somewhat 'unified' generic event object
*/
var fixEvents = function (event, context) {
var e = event || window.event;
if (typeof e.target === 'undefined') {
e.target = e.srcElement || context;
}
if (typeof e.preventDefault === 'undefined') {
e.preventDefault = function () {e.returnValue = false;};
}
if (typeof e.stopPropagation === 'undefined') {
e.stopPropagation = function () {e.cancelBubble = true;};
}
return e;
};
/** adds eventListeners to the given node. the given handler will be executed in the scope
* of context or, if context is omitted, in the scope of the given node
* ----------
* @param node {DOMNode}: the node to add the listener to
* @param type {String}: the type of event to listen to (e. g.: 'click')
* @param handler {Function}: function to executed if the given eventtype occurs
* @param context {Object}: the context (scope) for the handler
* @param propagate {Boolean}: true the event should propagate (rarely needed)
* @returns {Boolean}: true on success, false if no listener has been added
*/
var addListener = function (node, type, handler, context, propagate) {
var bound = hitch.event(handler, (context || node));
if (typeof node.addEventListener === 'function') {
node.addEventListener(type, bound, (propagate || false));
free(bound);
return true;
} else if (typeof node.attachEvent === 'function') {
node.attachEvent('on' + type, bound);
free(bound);
return true;
}
return false;
};
/** PLUGIN
* ----------
*/
/** plugin constructor function, awaits a nodelist/array/nodecollection as argument
* ----------
* @param nodelist {DOMCollection|Array}: a collection or array of all <video>-elements
* @returns {Object}: the new created Videofader instance
*/
var Videofader = function (nodeList) {
var videoNodes = [],
node,
i = 0;
if ((typeof nodeList !== 'object') &&
(typeof nodeList.length !== 'number') ||
(nodeList.length < 1)
) {
for (; node = nodeList[i]; i += 1) {
if ((typeof node === 'object') &&
(typeof node.nodeType === 'number') &&
(typeof node.nodeName === 'string') &&
(node.nodeName.toLowerCase() === 'video')) {
videoNodes[i] = node;
}
}
}
this.nodes = videoNodes;
this.length = videoNodes.length;
free(videoNodes, node);
return this.wrap();
};
Videofader.prototype = {
constructor: Videofader
};
/** wraps every given <video>-element into its very own <div>-container
* ----------
* @returns {Object}: same as constructor [[INTERNAL_USE]]
*/
Videofader.prototype.wrap = function () {
var nodes = this.nodes.slice(),
sandbox,
node,
tmp,
i = 0;
this.nodes = [];
for (; node = nodes[i]; i += 1) {
tmp = node.*****Node(true);
sandbox = document.createElement('div');
sandbox.appendChild(tmp);
this.nodes[i] = sandbox;
node.parentNode.replaceChild(sandbox, node);
}
free(nodes, sandbox, node, tmp);
return this;
};
/** adds eventlisteners to the instances <div>-wrappers
* ----------
* @param type {String}: the type of event that should be listened to
* @returns {Object}: same as constructor [[INTERNAL_USE]]
*/
Videofader.prototype.listenTo = function (type) {
var node,
i = 0;
for (; node = this.nodes[i]; i += 1) {
addListener(node, type, this.onEventHandle);
}
free(node);
return this;
};
Videofader.prototype.onEventHandle = function () {
handleClass(this, 'protects-opacity');
};
window.Videofader = Videofader;
})(this);