等同”selectorAPI”, 基于状态机,每个css指令调用其对应的特定函数
if (!String.prototype.trim)
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
};
if (!Array.prototype.indexOf)
Array.prototype.indexOf = function(searchElement /*, fromIndex */) {
var n, k, t = Object(this), len = t.length >>> 0;
if (len === 0) return -1;
n = 0;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (n != n) {
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) return -1;
for (k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); k < len; k++)
if (k in t && t[k] === searchElement) return k;
return -1;
};
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
var O = Object(this);
var len = O.length >>> 0;
if (thisArg) T = thisArg;
A = new Array(len);
k = 0;
while (k < len) {
var kValue, mappedValue;
if (k in O) {
kValue = O[k];
mappedValue = callback.call(T, kValue, k, O);
A[ k ] = mappedValue;
}
k++;
}
return A;
};
}
window.joop = joop = (function() {
var fn = {
extend: function(destination) {
for (var i = 1, length = arguments.length; i < length; i++)
for (var property in arguments[i]) destination[property] = arguments[i][property];
return destination;
},
isFunction: function(object) {
return typeof object === "function";
},
isString: function(object) {
return typeof object === "string";
},
isNumber: function(object) {
return typeof object === "number";
},
toArray: function(iterable) {
if (!iterable) return new Array;
if ("toArray" in iterable) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
},
unique: function(array) {
for (var i = 0, results = [], length = array.length; i < length; i++)
if (results.indexOf(array[i]) === -1) results.push(array[i]);
return results;
}
};
var ready = (function(arg) {
var queue = [], loaded = 0, onload = window.onload || function() {
};
function init() {
if (loaded) return;
loaded = 1;
for (var i = 0, length = queue.length; i < length; i++) queue[i](arg);
}
function delay() {
/loaded|complete/.test(document.readyState) ? init() : window.setTimeout(delay, 0);
}
if (window.attachEvent) window.attachEvent("onload", init);
if (window.addEventListener) window.addEventListener("load", init, false);
if (document.addEventListener) document.addEventListener("DOMContentLoaded", init, false);
window.onload = function() {
onload();
init();
};
delay();
return function(fn) {
loaded ? fn(arg) : queue.push(fn);
};
})(entry);
var cssSelector = (function(document) {
"use strict";
var pattern = {grou: "\\s*(,)\\s*", rela: "\\s*([\\s\\+>~])\\s*", elem: "(\\*|[\\.#]?[\\w-]+)", attr: "(\\[)\\s*([\\w-]+)\\s*(?:([~\\^\\$\\*\\|]?=)\\s*(['\"]?)(.*?)(\\4)\\s*)?(\\])"};
pattern.pseu = "(:{1,2}[\\w-]+)(?:\\(([\\s\\w\\+-]+|(?:" + pattern.elem + '|' + pattern.attr.replace("\\4", "\\7") + "|pseu)+)\\))?";
pattern.pseu = pattern.pseu.replace("|pseu", '|' + pattern.pseu.replace("|pseu", '').replace("\\7", "\\17"));
pattern.all = (pattern.grou + '|' + pattern.rela + '|' + pattern.elem + '|' + pattern.attr + '|' + pattern.pseu).replace("\\17", "\\27").replace("\\7", "\\17").replace("\\4", "\\7");
var regexp = {
all: new RegExp(pattern.all, "gim"),
grou: new RegExp('^' + pattern.grou + '$', "im"),
elem: new RegExp('^' + pattern.elem + '$', "im"),
rela: new RegExp('^' + pattern.rela + '$', "im"),
attr: new RegExp('^' + pattern.attr + '$', "im"),
pseu: new RegExp('^' + pattern.pseu + '$', "im")
};
function parse(selectors) {
var chains = [[]], index = 0, result;
var chain = selectors.trim().match(regexp.all);
function chainRel(rel, tag) {
chains[index].push(["rel", rel, tag]);
}
function chainEle(tag) {
if (!chains[index].length) chainRel(' ', tag);
chains[index][chains[index].length - 1][2] = chains[index][chains[index].length - 1][2] || tag;
}
function chainAtt(att, exp, val) {
if (!chains[index].length) chainEle('*');
if (chains[index][chains[index].length - 1][0] === "rel") chainEle('*');
chains[index].push(["att", att, exp, val]);
}
function chainPse(name, val) {
if (!chains[index].length) chainEle('*');
if (chains[index][chains[index].length - 1][0] === "rel") chainEle('*');
chains[index].push(["pse", name, val]);
}
function chainNew() {
chains.push([]);
index++;
}
for (var i = 0; i < chain.length; i++) {
if (regexp.grou.test(chain[i])) {
chainNew();
} else if (regexp.elem.test(chain[i])) {
switch (chain[i].charAt(0)) {
case '.':
chainAtt("class", "~=", chain[i].substr(1));
break;
case '#':
chainAtt("id", '=', chain[i].substr(1));
break;
default:
chainEle(chain[i]);
}
} else if (!!(result = regexp.rela.exec(chain[i]))) {
chainRel(result[1]);
} else if (!!(result = regexp.attr.exec(chain[i]))) {
chainAtt(result[2], result[3], result[5]);
} else if (!!(result = regexp.pseu.exec(chain[i]))) {
chainPse(result[1], result[2]);
} else {
throw "Unrecognized at-rule or error parsing at-rule '" + chain[i] + "'.";
}
}
return chains;
}
function query(elements, chain) {
for (var i = 0; i < chain.length; i++) {
switch (chain[i][0]) {
case "rel":
elements = getByRel(elements, chain[i][1], chain[i][2]);
break;
case "att":
elements = getByAtt(elements, chain[i][1], chain[i][2], chain[i][3]);
break;
case "pse":
elements = getByPse(elements, chain[i][1], chain[i][2]);
break;
default:
throw "Selector expected. Ruleset ignored due to bad selector.";
}
}
return elements;
}
function getByRel(elements, rel, tag) {
for (var i = 0, lctag = tag.toLowerCase(), results = []; i < elements.length; i++) {
var element = elements[i];
switch (rel) {
case ' ':
results = results.concat(fn.toArray(element.getElementsByTagName(tag)));
break;
case '>':
for (var j = 0; j < element.children.length; j++)
if (lctag === '*' || (element.children[j].tagName.toLowerCase() === lctag))
results.push(element.children[j]);
break;
case '+':
case '~':
element = element.nextSibling;
do {
if (element && element.tagName && element.tagName.toLowerCase() === lctag)
results.push(element);
} while (element && (rel === '+' ? !element.tagName : true) && !!(element = element.nextSibling));
break;
default:
if (element.tagName.toLowerCase() === lctag) results.push(element);
}
}
return results;
}
function getByAtt(elements, att, exp, val) {
for (var i = 0, results = []; i < elements.length; i++) {
var element = elements[i], value = element.getAttribute(att);
switch (exp) {
case '=':
if (val === value) results.push(element);
break;
case "~=":
if (new RegExp("(^|\\s)" + val + "(\\s|$)").test(value)) results.push(element);
break;
case "^=":
if (new RegExp('^' + val).test(value)) results.push(element);
break;
case "$=":
if (new RegExp(val + '$').test(value)) results.push(element);
break;
case "*=":
if (new RegExp(val).test(value)) results.push(element);
break;
case "|=":
if (new RegExp("(^|-)" + val + "(-|$)").test(value)) results.push(element);
break;
default:
if (value !== null) results.push(element);
}
}
return results;
}
function getByPse(elements, name, arg) {
for (var i = 0, results = []; i < elements.length; i++) {
var element = elements[i], parent = element.parentNode, children = parent.children;
switch (name) {
case ":checked":
if (element.checked) results.push(element);
break;
case ":disabled":
if (element.disabled) results.push(element);
break;
case ":empty":
if (!element.childNodes.length) results.push(element);
break;
case ":enabled":
if (!element.disabled) results.push(element);
break;
case ":first-child":
if (children[0] === element) results.push(element);
break;
case ":first-of-type":
for (var j = 0; j < children.length; j++) {
if (children[j].tagName === element.tagName) {
if (children[j] === element) results.push(element);
break;
}
}
break;
case ":lang":
if (new RegExp("(^|-)" + arg + "(-|$)").test(element.lang)) results.push(element);
break;
case ":last-child":
if (children[children.length - 1] === element) results.push(element);
break;
case ":last-of-type":
for (var j = children.length; j > 0; j--) {
if (children[j - 1].tagName === element.tagName) {
if (children[j - 1] === element) results.push(element);
break;
}
}
break;
case ":not":
if (!query([element], simchain(arg)).length) results.push(element);
break;
case ":nth-child":
for (var j = 0; j < children.length; j++) {
if (children[j] === element) {
if (comparen(arg, j + 1)) results.push(element);
break;
}
}
break;
case ":nth-last-child":
for (var j = children.length; j > 0; j--) {
if (children[j - 1] === element) {
if (comparen(arg, children.length - j + 1)) results.push(element);
break;
}
}
break;
case ":nth-last-of-type":
for (var j = children.length, k = 0; j > 0; j--) {
if (children[j - 1].tagName === element.tagName) k++;
if (children[j - 1] === element) {
if (comparen(arg, k)) results.push(element);
break;
}
}
break;
case ":nth-of-type":
for (var j = 0, k = 0; j < children.length; j++) {
if (children[j].tagName === element.tagName) k++;
if (children[j] === element) {
if (comparen(arg, k)) results.push(element);
break;
}
}
break;
case ":only-child":
if (children.length === 1) results.push(element);
break;
case ":only-of-type":
for (var j = 0, k = 0; j < children.length; j++)
if (children[j].tagName === element.tagName) k++;
if (k === 1) results.push(element);
break;
case ":root":
if (element === document.documentElement) results.push(element);
break;
case ":target":
if (window.location && window.location.hash === '#' + element.id)
results.push(element);
break;
default:
throw "Don't support this pseudo-class: " + name;
}
}
return results;
}
function simchain(str) {
var chain = parse(str)[0];
if (chain[0][2] === '*') {
chain.shift();
} else {
chain[0][1] = '';
}
return chain;
}
function comparen(exp, val) {
if (!isNaN(exp)) return parseInt(exp) === val;
if (exp === "odd") return val % 2 === 1;
if (exp === "even") return val % 2 === 0;
if (/\d+n/.test(exp)) {
var formula = exp.replace(/(\d+)n/, "$1*n"), pv, nv, n = 0;
do {
pv = eval(formula.replace('n', n++));
nv = eval(formula.replace('n', n));
if (pv === val) return true;
} while (pv !== val && (pv < nv ? pv < val : pv > val));
}
}
return function(element, selectors) {
var elements = new Array().concat(arguments.length === 1 ? document : element);
for (var i = 0, results = [], chains = parse(arguments.length === 1 ? element : selectors); i < chains.length; i++)
results = results.concat(query(elements, chains[i]));
return fn.unique(results);
};
})(document);
function namespace(ns) {
var parts = ns.split('.'), obj = window;
for (var i = 0; i < parts.length; i++)
obj = obj[parts[i]] = obj[parts[i]] || {};
return obj;
}
function jclass() {
var bclass, bproto = {}, proto = {initialize: function() {
}};
function nclass() {
this.initialize.apply(this, arguments);
}
for (var i = 0, length = arguments.length; i < length; i++) {
var methods = arguments[i];
if (fn.isFunction(methods)) {
bclass = function() {
};
bclass.prototype = methods.prototype;
methods = new bclass;
fn.extend(bproto, methods);
}
fn.extend(proto, methods);
}
nclass.prototype = proto;
nclass.parent = bproto;
return nclass;
}
function wrapper(element) {
if (!element || isFunction(element) || element._element || element.initialize)
return element;
var wrapClass, object;
if (element === window) {
wrapClass = Element.Window;
} else if (element === document) {
wrapClass = Element.Document;
} else if (element.nodeType !== 1) {
return element;
} else {
wrapClass = Element['tag' + element.tagName.toUpperCase()] || Element;
}
wrapper.cache = wrapper.cache || [];
for (var i = 0, length = wrapper.cache.length; i < length; i++)
if (wrapper.cache[i]._element === element)
return wrapper.cache[i];
object = new wrapClass(element);
wrapper.cache.push(object);
return object;
}
function getById() {
if (arguments.length > 1) {
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
elements.push(getById(arguments[i]));
return elements;
}
return wrapper(isString(arguments[0]) ? document.getElementById(arguments[0]) : arguments[0]);
}
function getBySelector(selectors) {
return cssSelector(selectors);
}
function entry(arg) {
if (arguments.length > 1) {
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
elements.push(entry(arguments[i]));
return elements;
}
return fn.isFunction(arg) ? ready(arg) : getById(arg);
}
return fn.extend(entry, {
version: 20131102,
fn: fn,
ready: ready,
namespace: namespace,
jclass: jclass,
wrapper: wrapper,
getById: getById,
getBySelector: getBySelector,
cssSelector: cssSelector
});
})();
Leave a Reply