A JavaScript library used by CodeFelony
Version vom
Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/9003/44594/CodeFelony%20JS%20Library.js
// ==UserScript==
// @name CodeFelony JS Library
// @namespace https://greasyfork.org/en/users/10166-moriarty
// @description A JavaScript library used by CodeFelony
// @include *
// @copyright (c) 2015 CodeFelony. All Rights Reserved
// @author Moriarty
// @version 1.3.1
// @license LGPL version 3 or any later version; http://www.gnu.org/copyleft/lgpl.html
// @grant GM_addStyle
// ==/UserScript==
/**
WIKI ==> https://github.com/codefelony/cfl/wiki/
**/
(function (window, undefined) {
'use strict'; // use strict mode in ECMAScript-5
var version = '1.3.1'; // this will be used for CFL.prototype.version
var intervals = []; // for the setInterval/clearInterval methods
// regular expressions
var rSelector = /^\*|^\.[a-z][\w\d-]*|^#[^ ]+|^[a-z]+|^\[a-z]+/i; // matches a CSS selector
var rXpath = /^(\.*\/{1,2})+[a-zA-Z\*]+/; // matches an XPath query
var rHTML = /<[^>]+>/; // matches a string of HTML
var rHyphenated = /-([a-zA-Z])/g; // matches alphabetic, hyphenated strings
var rElementObject = /^\[object HTML([a-zA-Z]+)?Element\]$/; // matches the toString value of an element
var rWindowObject = /^\[object Window\]$/; // matches the toString value of a window object
var rValidVarname = /^[a-zA-Z$_][a-zA-Z0-9$_]*$/; // matches a valid variable name
// compatibility methods for browsers that don't support ECMAScript-5 completely
var compat = {
'arr_indexOf' : function (searchElement, fromIndex) {
var index = parseInt(fromIndex || 0, 10), len = this.length;
index = index < 0 ? len + index : index; // handle negative fromIndex
index = !(index > 0) ? 0 : index; // handle out of range and/or NaN fromIndex
while (index < len && index >= 0) {
if (this[index] === searchElement) {
return index;
}
index += 1;
}
return -1;
},
/*
'filter' : function (fn, oThis) {
var index, value, len = this.length, ret = [];
for (index = 0; index < len; index += 1) {
value = this[index];
if ( fn.call(oThis, value, index, this) ) {
ret.push(value);
}
}
return ret;
},
*/
'forEach' : function (fn, oThis) {
var index, len;
for (index = 0, len = this.length; index < len; index += 1) {
fn.call(oThis, this[index], index, this);
}
},
'map' : function (fn, oThis) {
var index, newArr = [], len;
for (index = 0, len = this.length; index < len; index += 1) {
newArr[index] = fn.call(oThis, this[index], index, this);
}
return newArr;
},
'reduce' : function (fn, initialValue) {
var index, len, value, isValueSet = false;
if (arguments.length > 1) {
value = initialValue;
isValueSet = true;
}
for (index = 0, len = this.length; index < len; index += 1) {
if (isValueSet) {
value = fn(value, this[index], index, this);
} else {
value = this[index];
isValueSet = true;
}
}
return value;
}
};
// gets a method from an object's prototype. returns undefined if not found
var getMethod = function (obj, method) {
if (typeof XPCNativeWrapper === 'function' && typeof XPCNativeWrapper.unwrap === 'function') {
obj = XPCNativeWrapper.unwrap(obj);
} else if (obj.wrappedJSObject) {
obj = obj.wrappedJSObject;
}
if (obj.prototype && typeof obj.prototype[method] === 'function') {
return obj.prototype[method];
}
};
// original methods for some common uses
var core = {
// array
'arr_indexOf' : getMethod(Array, 'indexOf') || compat.arr_indexOf,
'concat' : getMethod(Array, 'concat'),
'filter' : getMethod(Array, 'filter') || compat.filter,
'forEach' : getMethod(Array, 'forEach') || compat.forEach,
'map' : getMethod(Array, 'map') || compat.map,
'reduce' : getMethod(Array, 'reduce') || compat.reduce,
'slice' : getMethod(Array, 'slice'),
// object
'hasOwnProperty' : getMethod(Object, 'hasOwnProperty'),
'toString' : getMethod(Object, 'toString'),
};
var CFL = function CFL(selector, context) {
return new CFL.fn.init(selector, context);
};
// a simple class for dealing with event listener handlers
var handlers = {
stack : [],
add : function (thisElement, type, fn) {
this.stack.push({
element : thisElement,
type : type,
fn : fn
});
},
get : function (thisElement, type) {
var events = [];
type = typeof type === 'string' ? type : '*';
CFL.each(this.stack, function (thisEventObj) {
if (thisElement === thisEventObj.element) {
if (type === '*' || thisEventObj.type === type) {
events.push(thisEventObj);
}
}
});
return events;
},
remove : function (thisElement, type) {
var handlerIndices = [], that = this;
// find all the indices of what we need to remove
CFL.each(handlers.get(thisElement, type), function (thisEventObj, index, array) {
handlerIndices.push(
core.arr_indexOf.call(that.stack, thisEventObj)
);
});
// remove all the indices here, using a separate array of indices
// we can't do this as we loop over the (stack) array itself, because
// we would be removing values as they are being iterated through
CFL.each(handlerIndices, function (thisIndex) {
that.stack.splice(thisIndex, 1);
});
}
};
// Node.prototype.matchesSelector compat for vendor prefixes
function matchesSelector(element, selector) {
if (element && typeof selector === 'string') {
if (typeof element.mozMatchesSelector === 'function') {
// Mozilla
return element.mozMatchesSelector(selector);
} else if (typeof element.webkitMatchesSelector === 'function') {
// Webkit
return element.webkitMatchesSelector(selector);
} else if (typeof element.oMatchesSelector === 'function') {
// Opera
return element.oMatchesSelector(selector);
} else if (typeof element.msMatchesSelector === 'function') {
// IE
return element.msMatchesSelector(selector);
}
}
return false;
}
// calls 'this' with the first parameter as the first argument
function call(a) {
return this(a);
}
function toCamelCase(string) {
return string.replace(rHyphenated, function (fullMatch, firstGroup) {
return firstGroup.toUpperCase();
});
}
// walkTheDom by Douglas Crockford
function walkTheDom(node, func) {
func(node);
node = node.firstChild;
while (node) {
walkTheDom(node, func);
node = node.nextSibling;
}
}
// can pluck a key out of an object
function pluck(obj) {
var subs = this.split('.'),
ret = obj, i;
for (i = 0; i < subs.length; i += 1) {
ret = ret[ subs[i] ];
if (ret == null) {
return '';
}
}
return ret;
}
function sum(curValue, nextValue) {
return curValue + nextValue;
}
function sumInt(curValue, nextValue) {
return parseInt(curValue, 10) + parseInt(nextValue, 10);
}
// internal function for throwing errors, so the user gets
// some sort of hint as to why their operation failed
function error(errorString) {
if (typeof console !== 'undefined' && typeof console.error === 'function') {
console.error(errorString);
}
return null; // always return null
}
// will copy an element and return a new copy with the same event listeners
function cloneElement(thisElement) {
var newElement = thisElement.cloneNode(true);
// clone event listeners of element
CFL.each(handlers.get(thisElement), function (thisEventObj) {
CFL.addEvent(newElement, thisEventObj.type, thisEventObj.fn);
});
return newElement;
}
function getEachElements(array, selector, key, type) {
var newElementsArray = [],
isValidSelector = typeof selector === 'string' && selector.trim() !== '';
CFL.each(array, function (currentElement) {
while ( currentElement = currentElement[key] ) { // note: intentional assignment
if (type > 0 ? currentElement.nodeType === type : true) {
if ( isValidSelector === false || CFL(currentElement).filter(selector).exists ) {
newElementsArray.push(currentElement);
return;
}
}
}
});
return newElementsArray;
}
// this will take
function doElementOperationOnEach(args, op) {
var newElementsArray = [], newElement,
passedElements = CFL.create.apply(CFL, args);
if (this.exists) {
if (CFL.typeOf(passedElements) === 'array') {
this.each(function (thisElement) {
CFL.each(passedElements, function (passedElement) {
// clone the element
var newElement = cloneElement(passedElement);
// add the new elements to an array
newElementsArray.push(newElement);
// perform the passed operation on the element
op(thisElement, newElement);
});
});
} else {
this.each(function (thisElement) {
// clone the element
var newElement = cloneElement(passedElements);
// add the new elements to an array
newElementsArray.push(newElement);
// perform the passed operation on the element
op(thisElement, newElement);
});
}
}
return newElementsArray;
}
// define CFL's prototype, aka CFL.fn
CFL.fn = CFL.prototype = {
isCFL : true,
constructor : CFL,
length : 0,
version : version,
// similar to jQuery. CFL is just the init constructor
init : function (selector, context) {
var selectorStringValue = core.toString.call(selector),
that = this,
elems = [];
switch (typeof selector) {
case 'string': { // -- STRING --
if ( selector.match(rXpath) ) {
// handle an XPath expression
elems = CFL.xpath({expression : selector, type : 7, context : context});
} else if ( selector.match(rHTML) ) {
// reserved for html code creation
// not sure if I want to implement it
} else if ( selector.match(rSelector) ) {
if (CFL.typeOf(context) === 'array') {
// handle an array being passed as the context
return that.find.call(context, selector);
} else if (typeof context === 'string') {
// handle a selector being passsed as the context
context = CFL(context);
if (context.exists) {
return CFL(selector, context[0]);
}
} else if (context != null && context.isCFL === true && context.exists) {
// handle a CFL object being passsed as the context
return CFL( selector, context[0] );
} else {
// handle a regular element being passed as the context
context = context != null && context.querySelectorAll ? context : document;
elems = context.querySelectorAll(selector);
}
}
break;
}
// ---------------------------------------------------
case 'object': { // -- OBJECT --
if (selector != null) {
if (selector.isCFL === true) {
// handle a CFL object
return selector;
} else if ( core.hasOwnProperty.call(selector, 'length') ) {
// handle an array-like object
elems = selector;
} else if ( selectorStringValue.match(rElementObject) || selectorStringValue.match(rWindowObject) ) {
// handle a single element
elems = [selector];
}
}
break;
}
// ---------------------------------------------------
default: { // -- UNKNOWN --
if ( selectorStringValue.match(rElementObject) || selectorStringValue.match(rWindowObject) ) {
// handle elements that are typeof === 'function'
// e.g., object, applet, embed
elems = [selector];
}
}
}
// define the length property of our object wrapper
that.length = elems.length;
// bind the elements to array-like key:value pairs in our wrapper
// e.g., this[0] ==> element
CFL.each(elems, function (value, index) {
that[index] = value;
});
return that;
},
// --- STARTING LINE FOR THE CFL WRAPPER METHODS
add : function (selector, context) {
var newElements = CFL(selector, context).raw(),
allElements = core.concat.call(this.raw(), newElements);
return CFL(allElements);
},
addEvent : function (type, fn) {
return this.each(function (thisElement) {
CFL.addEvent(thisElement, type, fn);
});
},
after : function () {
var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
var parent = baseElement.parentNode,
next = baseElement.nextSibling;
if (parent) {
if (next) {
// add the newElement after the current element
parent.insertBefore(newElement, next);
} else {
// nextSibling didn't exist. just append to its parent
parent.appendChild(newElement);
}
}
});
return CFL(newElementsArray);
},
append : function () {
var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
baseElement.appendChild(newElement);
});
return CFL(newElementsArray);
},
attribute : function (name, value) {
var ret = '', valueIsValid = value != null;
if ( typeof name === 'string' && this.exists ) {
this.each(function (elem) {
if (valueIsValid) {
elem.setAttribute(name, value);
} else {
ret += elem.getAttribute(name) || '';
}
});
}
return valueIsValid ? this : ret;
},
before : function () {
var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
var parent = baseElement.parentNode;
// add the newElement before the current element
if (parent) {
parent.insertBefore(newElement, baseElement);
}
});
return CFL(newElementsArray);
},
center : function () {
return this.each(function (thisElement) {
thisElement = CFL(thisElement);
thisElement.css('position', 'fixed');
thisElement.css('top', Math.floor( (window.innerHeight - thisElement.height) / 2 ) + 'px');
thisElement.css('left', Math.floor( (window.innerWidth - thisElement.width) / 2 ) + 'px');
});
},
clone : function () {
var clonedElements = core.map.call(this, cloneElement); // variable for clarity
return CFL(clonedElements);
},
css : function (name, value) {
if (typeof name === 'string') {
// convert the hyphenated string to camel-case
name = toCamelCase(name);
if (typeof value === 'string') {
return this.each(function (thisElement) {
if (name in thisElement.style) {
thisElement.style[name] = value;
}
});
}
return core.map.call(this, pluck, 'style.' + name).join('');
} else {
return error('.css() was not passed a string for the first argument.');
}
},
each : function (fn, oThis) {
if (this.exists) {
CFL.each(this, fn, oThis);
}
return this;
},
get exists() {
return this.length > 0 && this[0] != null;
},
filter : function (selector) {
var newElementsArray = [];
if (typeof selector === 'string') {
this.each(function (thisElement) {
if ( matchesSelector(thisElement, selector) ) {
newElementsArray.push(thisElement);
}
});
}
// returns an empty CFL object if no elements are matched
return CFL(newElementsArray);
},
find : function (selector) {
var arrayOfMatchesArrays = core.map.call(this, function (thisElement) {
var matches = thisElement.querySelectorAll(selector);
return CFL.toArray(matches);
});
var singleArrayOfMatches = arrayOfMatchesArrays.length > 0 ?
core.reduce.call(arrayOfMatchesArrays, function (a, b) {
return core.concat.call(a, b);
}) : [];
return CFL(singleArrayOfMatches);
},
first : function () {
return this.get(0);
},
focus : function () {
var firstElement;
if (this.exists) {
firstElement = this[0];
if (typeof firstElement.focus === 'function') {
firstElement.focus();
}
}
},
get : function (index) {
index = index === 'first' ? 0 : index === 'last' ? -1 : parseInt(index, 10);
if ( !isNaN(index) ) {
return CFL( index < 0 ? this[this.length + index] : this[index] );
}
return CFL.toArray(this);
},
get height() {
var arrayOfElemHeights = core.map.call(this, pluck, 'offsetHeight');
return core.reduce.call(arrayOfElemHeights, sum);
},
has : function (selector) {
var newElementsArray = [];
if ( typeof selector === 'string' && selector.match(rSelector) ) {
this.each(function (thisElement) {
if ( CFL(selector, thisElement).exists ) {
newElementsArray.push(thisElement);
}
});
}
return CFL(newElementsArray);
},
hide : function () {
return this.css('display', 'none');
},
/*
get inView(passedContainer) {
var isInView = false;
this.each(function (thisElement) {
var container = passedContainer || thisElement.parentNode;
var visible = !!( (container.scrollTop + container.offsetHeight) >= thisElement.offsetTop &&
(container.scrollTop - thisElement.offsetHeight) <= thisElement.offsetTop );
if (visible) {
isInView = true;
return 'stop';
}
});
return isInView;
},
*/
is : function (selector) {
for (var i = 0; i < this.length; i += 1) {
if ( matchesSelector(this[i], selector) ) {
return true;
}
}
return false;
},
isnt : function (selector) {
return !this.is(selector);
},
last : function (selector) {
return this.get(-1);
},
next : function (selector) {
return CFL( getEachElements(this, selector, 'nextSibling', 1) );
},
not : function (selector) {
var newElementsArray = [];
if ( typeof selector === 'string' && selector.match(rSelector) ) {
this.each(function (thisElement) {
if ( CFL(thisElement).isnt(selector) ) {
newElementsArray.push(thisElement);
}
});
}
return CFL(newElementsArray);
},
parent : function (selector) {
return CFL( getEachElements(this, selector, 'parentNode', 1) );
},
prepend : function () {
var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
var firstChild = baseElement.firstChild;
if (firstChild) {
baseElement.insertBefore(newElement, firstChild);
}
});
return CFL(newElementsArray);
},
prev : function (selector) {
return CFL( getEachElements(this, selector, 'previousSibling', 1) );
},
prop : function (name, value) {
var valueIsValid = value != null, ret;
if (typeof name === 'string' && this.exists) {
this.each(function (thisElement) {
if (valueIsValid) {
thisElement[name] = value;
} else {
if (typeof ret === 'undefined') {
ret = thisElement[name];
} else {
ret += thisElement[name];
}
}
});
}
return valueIsValid ? this : ret;
},
raw : function () {
return core.slice.call(this, 0);
},
remove : function () {
return this.each(function (element) {
var parent = element.parentNode;
if (element && parent) {
parent.removeChild(element);
}
});
},
removeAttribute : function (attributeName) {
if (typeof attributeName === 'string') {
return this.each(function (thisElement) {
thisElement.removeAttribute(attributeName);
});
} else {
return error('.removeAttribute() was not passed a string.');
}
},
removeEvent : function (type) {
if (typeof type === 'string') {
return this.each(function (thisElement) {
CFL.removeEvent(thisElement, type);
});
} else {
return error('.removeEvent() was not passed a string.');
}
},
replace : function () {
var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
var parent = baseElement.parentNode;
if (parent) {
parent.replaceChild(newElement, baseElement);
}
});
return CFL(newElementsArray);
},
show : function (value) {
value = typeof value === 'string' ? value : 'inline';
return this.css('display', value);
},
text : function (passedText, append) {
// convert a number to a string
if ( typeof passedText === 'number' && !isNaN(passedText) && isFinite(passedText) ) {
passedText += '';
}
// handle setting text
if (typeof passedText === 'string') {
if (append !== true) {
this.each(function (thisElement) {
CFL('.//text()', thisElement).each(function (textNode) {
textNode.data = '';
});
});
}
this.append('text', passedText);
return this;
}
// handle getting text
return core.reduce.call(this, function (curValue, nextElement) {
return curValue + nextElement.textContent;
}, '');
},
toggle : function () {
return this.each(function (thisElement) {
thisElement = CFL(thisElement);
if (thisElement.visible) {
thisElement.hide();
} else {
thisElement.show();
}
});
},
value : function (passedValue) {
var elem = this[0],
tagName = elem && elem.tagName || '',
selectedOptions = [],
rInputTypeBlacklist = /button|checkbox|file|image|radio|reset|submit/,
passedValueType = CFL.typeOf(passedValue);
if (passedValue == null) {
// no arguments were passed, return a value
if (tagName === 'SELECT') {
if ( elem.hasAttribute('multiple') ) {
CFL.each(elem.options, function (thisOption) {
if (thisOption.selected) {
selectedOptions.push(thisOption.value);
}
});
return selectedOptions;
} else {
return elem.options[elem.selectedIndex].value;
}
} else if ( tagName === 'INPUT' && !elem.type.match(rInputTypeBlacklist) ) {
return elem.value;
}
if (tagName === 'TEXTAREA') {
return elem.value;
}
} else {
// an argument was passed, set the value on each element
return this.each(function (thisElement) {
var tagName = thisElement.tagName;
if (tagName === 'SELECT') {
if (thisElement.hasAttribute('multiple') && passedValueType === 'array') {
CFL.each(thisElement.options, function (thisOption) {
CFL.each(passedValue, function (thisPassedValue) {
if (thisOption.value == thisPassedValue) {
thisOption.selected = true;
return 'stop';
} else {
thisOption.selected = false;
}
});
});
} else {
CFL.each(thisElement.options, function (thisOption) {
thisOption.selected = thisOption.value == passedValue;
});
}
} else if (tagName === 'INPUT') {
if ( !thisElement.type.match(rInputTypeBlacklist) ) {
thisElement.value = passedValue;
} else if (thisElement.type === 'checkbox' || thisElement.type === 'radio') {
if (passedValueType === 'array') {
CFL.each(passedValue, function (thisPassedValue) {
if (thisElement.value == thisPassedValue) {
thisElement.checked = true;
return 'stop';
} else {
thisElement.checked = false;
}
});
} else if (thisElement.value == passedValue) {
thisElement.checked = true;
}
}
} else if (tagName === 'TEXTAREA') {
thisElement.value = passedValue;
}
});
}
return null;
},
get visible() {
return Math.max(this.width, this.height) > 0;
},
get width() {
var arrayOfElemHeights = core.map.call(this, pluck, 'offsetWidth');
return core.reduce.call(arrayOfElemHeights, sum);
},
};
// give the init function the CFL prototype for later instantiation
CFL.fn.init.prototype = CFL.fn;
// extend method. can extend any object it's run upon
CFL.fn.extend = CFL.extend = function (obj) {
var name, copy;
for (name in obj) {
copy = obj[name];
if ( !core.hasOwnProperty.call(this, name) && typeof copy !== 'undefined' ) {
this[name] = copy;
}
}
};
// --- STARTLING LINE FOR THE DIRECT CFL METHODS
CFL.extend({
addEvent : function addEvent(thisElement, type, fn) {
if (thisElement != null && typeof type === 'string' && typeof fn === 'function') {
if (typeof thisElement.addEventListener === 'function') {
thisElement.addEventListener(type, fn, false);
} else if (typeof thisElement.attachEvent === 'function') {
type = 'on' + type;
thisElement.attachEvent(type, fn);
} else {
return;
}
handlers.add(thisElement, type, fn);
}
},
addScript : function addScript(contents, id, node) {
var newElement = document.createElement('script');
newElement.id = id || ( 'cfl-script-' + CFL.random(999) );
newElement.innerHTML = contents;
node = node || document.head || document.querySelector('html > head');
node.appendChild(newElement);
return {
remove : function () {
node.removeChild(newElement);
}
};
},
addStyle : function addStyle(css, id, node) {
id = id || ( 'cfl-style-' + CFL.random(999) );
node = node || document.head || document.querySelector('html > head');
if (node) {
node.appendChild(
CFL.create('style', {id : id, type : 'text/css'}, [ CFL.create('text', css) ] )
);
}
},
alias : function alias(newAlias) {
if (typeof newAlias === 'string' && newAlias.match(rValidVarname) && typeof window[newAlias] === 'undefined') {
window[newAlias] = CFL;
}
},
clearInterval : function clearInterval(index) {
if (typeof index === 'number' && index < intervals.length) {
window.clearTimeout( intervals[index] );
intervals[index] = null;
}
},
create : function create(elementName, descObj, kidsArray) {
var argsLength = arguments.length,
typeValue, prop, val, HTMLholder, ret, i;
if (argsLength === 2 && elementName === 'text' && typeof descObj === 'string') {
// handle text node creation
return document.createTextNode(descObj);
} else if ( argsLength === 1 && typeof elementName === 'string' && elementName.match(rHTML) ) {
// handle HTML strings
// take the HTML string and put it inside a div
HTMLholder = document.createElement('div');
HTMLholder.innerHTML = elementName;
// add each childNode to an array to return
ret = [];
ret.push.apply(ret, HTMLholder.childNodes);
return ret.length > 0 ? (ret.length === 1 ? ret[0] : ret) : null;
} else if (argsLength > 1 && typeof elementName === 'string' && typeof descObj === 'object') {
// handle the normal element name and descriptor object
ret = document.createElement(elementName + '');
for (prop in descObj) {
if ( core.hasOwnProperty.call(descObj, prop) ) {
val = descObj[prop];
if (prop.indexOf('on') === 0 && typeof val === 'function') {
CFL.addEvent(ret, prop.substring(2), val);
} else if ( prop !== 'style' && prop !== 'class' && prop in ret && typeof ret[prop] !== 'undefined' ) {
ret[prop] = val;
} else {
ret.setAttribute(prop, val);
}
}
}
if (CFL.typeOf(kidsArray) === 'array') {
CFL.each(kidsArray, function (kid) {
var val, item, i;
if (typeof kid === 'string') {
val = CFL.create(kid)
if (CFL.typeOf(val) === 'array') {
for (i = 0; i < val.length; i += 1) {
ret.appendChild( val[i] );
}
} else if (CFL.typeOf(kid) === 'element') {
ret.appendChild(kid);
}
} else if (CFL.typeOf(kid) === 'element') {
ret.appendChild(kid);
}
});
}
return ret;
} else if (argsLength === 1 && CFL.typeOf(elementName) === 'element') {
// handle an element
return elementName;
}
},
each : function each(passedArray, fn, oThis) {
var isOthisUndefined = typeof oThis !== 'undefined',
index, len, otherThis, value;
for (index = 0; index < passedArray.length; index += 1) {
value = passedArray[index];
otherThis = isOthisUndefined ? oThis : value;
if (fn.call(otherThis, value, index, passedArray) === 'stop') {
break;
}
}
},
loop : function loop(maxIterations, fn) {
var args = CFL.toArray(arguments), i;
if (typeof maxIterations === 'number' && maxIterations > 0 && typeof fn === 'function') {
args = args.slice(2);
for (i = 0; i < maxIterations; i += 1) {
fn.apply(null, args);
}
}
},
random : function random(maxInteger, minInteger) {
var rand = -1;
while (rand < 0 || rand > maxInteger || rand < minInteger) {
rand = Math.floor( Math.random() * maxInteger ) + Math.round( Math.random() );
}
return rand;
},
removeEvent : function removeEvent(thisElement, type) {
CFL.each(handlers.get(thisElement, type), function (thisEventObj) {
if (typeof thisElement.removeEventListener === 'function') {
thisEventObj.element.removeEventListener(thisEventObj.type, thisEventObj.fn, false);
} else if (typeof thisElement.detachEvent === 'function') {
type = 'on' + type;
thisEventObj.element.detachEvent(thisEventObj.type, thisEventObj.fn);
}
handlers.remove(thisElement, type);
});
},
runAt : function runAt(state, func, oThis) {
var args = CFL.toArray(arguments), intv,
// compose a list of the 4 states, to use .indexOf() upon later
states = ['uninitialized', 'loading', 'interactive', 'complete'],
// in-case they pass [start/end] instead of [loading/complete]
state = state.replace('start', 'loading').replace('end', 'complete');
// this will run their function with the specified arguments, if any,
// and a custom 'this' value, if specified
function runFunc() {
func.apply( oThis, args.slice(3) );
}
// this will run on each state change if the specified state is
// not achieved yet. it will run their function when it is achieved
function checkState() {
if (document.readyState === state) {
runFunc();
CFL.clearInterval(intv);
}
}
if ( core.arr_indexOf.call(states, state) <= core.arr_indexOf.call(states, document.readyState) ) {
// we are at, or have missed, our desired state
// run the specified function
runFunc();
} else {
intv = CFL.setInterval(checkState, 200);
}
},
setInterval : function setInterval(func, delay) {
var index = intervals.length,
delay_orig = delay,
count = 1, startTime;
function doRe(func, delay) {
return window.setTimeout(function () {
// drift accomodation
var difference = ( new Date().getTime() ) - startTime,
correctTime = delay_orig * count,
drift = difference - correctTime;
// execute the function before setting a new timeout
func.call(null);
// fix for when a timeout takes longer than double the original delay time to execute
if (drift > delay_orig) {
drift = delay_orig;
}
// save the reference of the new timeout in our 'intervals' stack
if (intervals[index] !== null) {
intervals[index] = doRe(func, delay_orig - drift);
}
count += 1;
}, delay);
}
startTime = new Date().getTime();
intervals[index] = doRe(func, delay_orig);
return index;
},
toArray : function toArray(arr) {
var newArr = [], // new array to store the values into
len = arr.length || arr.snapshotLength,
item, i;
if (typeof len === 'number' && len > 0) {
if (typeof arr.snapshotItem === 'function') {
for (i = 0; ( item = arr.snapshotItem(i) ); i += 1) {
newArr.push(item);
}
} else {
// if the specified 'list' is array-like, use slice on it
// to convert it to an array
newArr = core.slice.call(arr, 0);
}
}
return newArr;
},
toString : function toString(item) {
var key, value, values = [];
function stringifyValue(val) {
var typeOfVal = CFL.typeOf(val),
toStringValue = core.toString.call(val);
if (typeOfVal === 'null' || typeOfVal === 'undefined') {
val = typeOfVal;
} else if (typeof val === 'string') {
if (val.length > 15) { // truncate strings longer than 15 characters
val = '"' + val.substring(0, 12) + '"...';
} else {
val = '"' + val + '"';
}
} else if (typeOfVal === 'function') {
val = val.toString().substring(0, 20);
} else if (typeOfVal !== 'number' && typeOfVal !== 'boolean') {
val = toStringValue;
}
return val;
}
switch( CFL.typeOf(item) ) {
case 'object': {
for (key in item) {
if ( item.hasOwnProperty(key) ) {
value = stringifyValue( item[key] );
values.push( '"' + key + '" : ' + value );
}
}
return '{\n ' + values.join(',\n ') + '\n}';
}
// --------------------------------------
case 'array': {
item = core.map.call(item, function (thisValue) {
return stringifyValue(thisValue);
});
return '[\n ' + item.join(',\n ') + '\n]';
}
// --------------------------------------
case 'string': {
return '"' + item + '"';
}
// --------------------------------------
case 'number': {
item = parseInt(item, 10);
if ( isNaN(item) ) { // no ternary operator, for clarity
return 'NaN';
} else {
return item.toString();
}
}
// --------------------------------------
case 'regexp': {
if (item.toString().length <= 20) {
item.toString();
} else {
return '[object RegExp]';
}
}
// --------------------------------------
case 'function': case 'boolean': {
return item.toString();
}
// --------------------------------------
case 'null': {
return 'null';
}
// --------------------------------------
case 'undefined': {
return 'undefined';
}
// --------------------------------------
default: {
return core.toString.call(item);
}
}
},
// typeOf by Douglas Crockford. modified by CodeFelony
typeOf : function typeOf(value) {
var s = typeof value,
ostr = core.toString.call(value);
if (s === 'object' || s === 'function') {
if (value) {
if (ostr === '[object Array]') {
s = 'array';
} else if ( ostr === '[object Text]' || ostr.match(rElementObject) ) {
s = 'element';
} else if (ostr === '[object HTMLCollection]') {
s = 'collection';
} else if (ostr === '[object NodeList]') {
s = 'nodelist';
} else if (ostr === '[object Arguments]') {
s = 'arguments';
} else if (ostr === '[object RegExp]') {
s = 'regexp';
}
} else {
s = 'null';
}
}
return s;
},
waitFor : function waitFor(info) {
var verifier = function () { return true; },
done = info ? info.done : null,
i, selector, context, waitForInterval;
if (info == null || typeof done !== 'function') { return; }
switch ( CFL.typeOf(info.selector) ) {
case 'string': case 'element': case 'array': {
selector = info.selector;
break;
}
default: {
return error('Invalid selector passed to CFL.waitFor()');
}
}
switch ( CFL.typeOf(info.context) ) {
case 'string': case 'element': case 'array': {
context = info.context;
}
}
if (typeof info.verifier === 'function' && info.verifier.toString().indexOf('return ') !== -1) {
verifier = info.verifier;
}
function clear() {
CFL.clearInterval(waitForInterval);
}
function check() {
var elem = CFL(selector, context);
if (elem.exists && verifier(elem) === true) {
done(elem);
return clear();
}
if (i >= 150) { // check for 30 seconds max
return clear();
}
i += 1;
}
waitForInterval = CFL.setInterval(check, 200);
},
xpath : function xpath(obj) {
var type = obj.type || 7,
types = {
'1' : 'numberValue',
'2' : 'stringValue',
'3' : 'booleanValue',
'8' : 'singleNodeValue',
'9' : 'singleNodeValue'
},
expression = obj.expression,
context = obj.context || document,
doc = document, xp;
if (typeof context.evaluate === 'function') {
doc = context;
} else if (typeof context.ownerDocument.evaluate === 'function') {
doc = context.ownerDocument;
}
xp = doc.evaluate(expression, context, null, type, null);
if (!expression) {
error('An expression must be supplied for CFL.xpath()');
return null;
}
if ( types[type] ) {
return xp[ types[ type ] ];
} else {
return CFL.toArray(xp);
}
}
});
// assign CFL to the window object
if (typeof window.CFL !== 'function') {
// if it doesn't exist, just add it
window.CFL = CFL;
window._J = CFL;
} else if (window.CFL.fn && window.CFL.fn.version) {
// if it already exists, only replace it with a newer, yet
// backwards compatible version (check for same major version)
if ( window.CFL.fn.version.substring( 0, window.CFL.fn.version.indexOf('.') )
=== version.substring( 0, version.indexOf('.') ) ) {
window.CFL = CFL;
window._J = CFL;
}
}
// just for testing purposes
// unsafeWindow.CFL = unsafeWindow._J = CFL;
}(window));
// CFL test button
// use it to test code on user click (non-automatic)
/*
(function () {
var mo = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
var target = mutation.target;
if (mutation.attributeName === 'value' && target.value !== 'Run CFL test') {
target.value = 'Run CFL test';
}
});
});
CFL(document.body).append(
'input',
{
id : 'cfl_user_test',
type : 'button',
value : 'Run CFL test',
style : 'display: block; position: fixed; top: 4px; right: 4px; z-index: 999999; padding: 2px 14px; font-size: 11pt; font-family: Arial, Verdana;',
onclick : function () {
// ---- ENTER ONCLICK CODE HERE ----
window.setTimeout(function () {
CFL(document.body).append('<div id="waitForTest">I\'m a CFL.waitFor() test DIV!</div>');
}, 1500);
CFL.waitFor({
selector : '#waitForTest',
done : function (elem) {
alert('#waitForTest is loaded!');
}
});
// ---------------------------------
}
}
);
mo.observe( CFL('#cfl_user_test')[0], { attributes : true } );
}());
*/