techy
Version:
Flat CMS based on Gulp and AbsurdJS
1,732 lines (1,660 loc) • 68.5 kB
JavaScript
/* version: 0.3.145, born: 10-2-2014 16:20 */
var Absurd = (function(w) {
var lib = {
api: {},
helpers: {},
plugins: {},
processors: {
css: { plugins: {}},
html: {
plugins: {},
helpers: {}
},
component: { plugins: {}}
}
};
var require = function(v) {
// css preprocessor
if(v.indexOf('css/CSS.js') > 0 || v == '/../CSS.js') {
return lib.processors.css.CSS;
} else if(v.indexOf('html/HTML.js') > 0) {
return lib.processors.html.HTML;
} else if(v.indexOf('component/Component.js') > 0) {
return lib.processors.component.Component;
} else if(v == 'js-beautify') {
return {
html: function(html) {
return html;
}
}
} else if(v == './helpers/PropAnalyzer') {
return lib.processors.html.helpers.PropAnalyzer;
} else if(v == '../../helpers/TransformUppercase') {
return lib.helpers.TransformUppercase;
} else if(v == './helpers/TemplateEngine') {
return lib.processors.html.helpers.TemplateEngine;
} else if(v == '../helpers/Extend') {
return lib.helpers.Extend;
} else if(v == '../helpers/Clone') {
return lib.helpers.Clone;
} else if(v == '../helpers/Prefixes' || v == '/../../../helpers/Prefixes') {
return lib.helpers.Prefixes;
} else if(v == __dirname + '/../../../../') {
return Absurd;
} else {
return function() {}
}
};
var __dirname = "";
var queue = function(funcs, scope) {
(function next() {
if(funcs.length > 0) {
funcs.shift().apply(scope || {}, [next].concat(Array.prototype.slice.call(arguments, 0)));
}
})();
}
var str2DOMElement = function(html) {
var wrapMap = {
option: [ 1, "<select multiple='multiple'>", "</select>" ],
legend: [ 1, "<fieldset>", "</fieldset>" ],
area: [ 1, "<map>", "</map>" ],
param: [ 1, "<object>", "</object>" ],
thead: [ 1, "<table>", "</table>" ],
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
body: [0, "", ""],
_default: [ 1, "<div>", "</div>" ]
};
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
var match = /<\s*\w.*?>/g.exec(html);
var element = document.createElement('div');
if(match != null) {
var tag = match[0].replace(/</g, '').replace(/>/g, '').split(' ')[0];
if(tag.toLowerCase() === 'body') {
var dom = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null);
var body = document.createElement("body");
// keeping the attributes
element.innerHTML = html.replace(/<body/g, '<div').replace(/<\/body>/g, '</div>');
var attrs = element.firstChild.attributes;
body.innerHTML = html;
for(var i=0; i<attrs.length; i++) {
body.setAttribute(attrs[i].name, attrs[i].value);
}
return body;
} else {
var map = wrapMap[tag] || wrapMap._default, element;
html = map[1] + html + map[2];
element.innerHTML = html;
// Descend through wrappers to the right content
var j = map[0]+1;
while(j--) {
element = element.lastChild;
}
}
} else {
element.innerHTML = html;
element = element.lastChild;
}
return element;
}
var addEventListener = function(obj, evt, fnc) {
if (obj.addEventListener) { // W3C model
obj.addEventListener(evt, fnc, false);
return true;
} else if (obj.attachEvent) { // Microsoft model
return obj.attachEvent('on' + evt, fnc);
}
}
var removeEmptyTextNodes = function(elem) {
var children = elem.childNodes;
var child;
var len = children.length;
var i = 0;
var whitespace = /^\s*$/;
for(; i < len; i++){
child = children[i];
if(child.nodeType == 3){
if(whitespace.test(child.nodeValue)){
elem.removeChild(child);
i--;
len--;
}
}
}
return elem;
}
var createNode = function(type, attrs, content) {
var node = document.createElement(type);
for(var i=0; i<attrs.length, a=attrs[i]; i++) {
node.setAttribute(a.name, a.value);
}
node.innerHTML = content;
return node;
}
var qs = function(selector, parent) {
if(parent === false) { parent = document; }
else { parent = parent || this.el || document; }
return parent.querySelector(selector);
};
var qsa = function(selector, parent) {
if(parent === false) { parent = document; }
else { parent = parent || this.el || document; }
return parent.querySelectorAll(selector);
};
var getStyle = function(styleProp, el) {
el = el || this.el;
if(el && el.currentStyle) {
return el.currentStyle[styleProp];
} else if (window.getComputedStyle) {
return document.defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
}
return null;
};
var addClass = function(className, el) {
el = el || this.el;
if(el.classList) {
el.classList.add(className);
} else {
var current = el.className;
if(current.indexOf(className) < 0) {
if(current == '') el.className = className;
else el.className += ' ' + className;
}
}
return this;
};
var removeClass = function(className, el) {
el = el || this.el;
if (el.classList) {
el.classList.remove(className);
} else {
var current = el.className.split(' ');
var newClasses = [];
for(var i=0; i<current.length; i++) {
if(current[i] != className) newClasses.push(current[i]);
}
el.className = newClasses.join(' ');
}
return this;
}
var replaceClass = function(classNameA, classNameB, el) {
el = el || this.el;
var current = el.className.split(' '), found = false;
for(var i=0; i<current.length; i++) {
if(current[i] == classNameA) {
found = true;
current[i] = classNameB;
}
}
if(!found) {
return addClass(classNameB, el);
}
el.className = current.join(' ');
return this;
}
var toggleClass = function(className, el) {
el = el || this.el;
if (el.classList) {
el.classList.toggle(className);
} else {
var classes = el.className.split(' ');
var existingIndex = -1;
for (var i = classes.length; i--;) {
if (classes[i] === className)
existingIndex = i;
}
if(existingIndex >= 0)
classes.splice(existingIndex, 1);
else
classes.push(className);
el.className = classes.join(' ');
}
return this;
}
var bind = function(func, scope, args) {
if(scope instanceof Array) { args = scope; scope = this; }
if(!scope) scope = this;
return function() {
func.apply(scope, (args || []).concat(Array.prototype.slice.call(arguments, 0)));
}
}
var Component = function(componentName, absurd, eventBus, cls) {
var api = lib.helpers.Extend({
__name: componentName
}, cls);
var extend = lib.helpers.Extend;
var l = [];
api.listeners = l;
api.on = function(eventName, callback, scope) {
if(!l[eventName]) {
l[eventName] = [];
}
l[eventName].push({callback: callback, scope: scope});
return this;
};
api.off = function(eventName, handler) {
if(!l[eventName]) return this;
if(!handler) l[eventName] = []; return this;
var newArr = [];
for(var i=0; i<l[eventName].length; i++) {
if(l[eventName][i].callback !== handler) {
newArr.push(l[eventName][i]);
}
}
l[eventName] = newArr;
return this;
};
api.dispatch = function(eventName, data, scope) {
if(data && typeof data === 'object' && !(data instanceof Array)) {
data.target = this;
}
if(l[eventName]) {
for(var i=0; i<l[eventName].length; i++) {
var callback = l[eventName][i].callback;
callback.apply(scope || l[eventName][i].scope || {}, [data]);
}
}
if(this[eventName] && typeof this[eventName] === 'function') {
this[eventName](data);
}
if(eventBus) eventBus.dispatch(eventName, data);
return this;
};
var storage = {};
api.set = function(key, value) {
storage[key] = value;
return this;
};
api.get = function(key) {
return storage[key];
};
var CSS = false;
api.__handleCSS = function(next) {
if(this.css) {
absurd.flush().add(this.css).compile(function(err, css) {
if(!CSS) {
var style = createNode(
'style', [
{ name: "id", value: componentName + '-css' },
{ name: "type", value: "text/css"}
],
css
);
(qs("head") || qs("body")).appendChild(style);
CSS = { raw: css, element: style };
} else if(CSS.raw !== css) {
CSS.raw = css;
CSS.element.innerHTML = css;
}
next();
});
} else {
next();
}
return this;
};
api.applyCSS = function(data, preventComposition, skipAutoPopulation) {
if(this.html && typeof this.html === 'string' && !preventComposition) {
var res = {};
res[this.html] = data;
data = res;
}
this.css = data;
if(!skipAutoPopulation) {
this.populate();
}
return this;
};
var HTMLSource = false;
api.__mergeDOMElements = function(e1, e2) {
removeEmptyTextNodes(e1);
removeEmptyTextNodes(e2);
if(typeof e1 === 'undefined' || typeof e2 === 'undefined' || e1.isEqualNode(e2)) return;
// replace the whole node
if(e1.nodeName !== e2.nodeName) {
if(e1.parentNode) {
e1.parentNode.replaceChild(e2, e1);
}
return;
}
// nodeValue
if(e1.nodeValue !== e2.nodeValue) {
e1.nodeValue = e2.nodeValue;
}
// attributes
if(e1.attributes) {
var attr1 = e1.attributes, attr2 = e2.attributes, a1, a2, found = {};
for(var i=0; i<attr1.length, a1=attr1[i]; i++) {
for(var j=0; j<attr2.length, a2=attr2[j]; j++) {
if(a1.name === a2.name) {
e1.setAttribute(a1.name, a2.value);
found[a1.name] = true;
}
}
if(!found[a1.name]) {
e1.removeAttribute(a1.name);
}
}
for(var i=0; i<attr2.length, a2=attr2[i]; i++) {
if(!found[a2.name]) {
e1.setAttribute(a2.name, a2.value);
}
}
}
// childs
var newNodesToMerge = [];
if(e1.childNodes.length >= e2.childNodes.length) {
for(var i=0; i<e1.childNodes.length; i++) {
if(!e2.childNodes[i]) { e2.appendChild(document.createTextNode("")); }
newNodesToMerge.push([e1.childNodes[i], e2.childNodes[i]]);
}
} else {
for(var i=0; i<e2.childNodes.length; i++) {
e1.appendChild(document.createTextNode(""));
newNodesToMerge.push([e1.childNodes[i], e2.childNodes[i]]);
}
}
for(var i=0; i<newNodesToMerge.length; i++) {
api.__mergeDOMElements(newNodesToMerge[i][0], newNodesToMerge[i][1]);
}
};
api.__handleHTML = function(next) {
var self = this;
var compile = function() {
absurd.flush().morph("html").add(HTMLSource).compile(function(err, html) {
if(!self.el) {
self.el = str2DOMElement(html);
} else {
api.__mergeDOMElements(self.el, str2DOMElement(html));
}
next();
}, self);
}
if(this.html) {
if(typeof this.html === 'string') {
if(!this.el) {
var element = qs(this.html);
if(element) {
this.el = element;
HTMLSource = {'': this.el.outerHTML.replace(/</g, '<').replace(/>/g, '>') };
}
}
compile();
} else if(typeof this.html === 'object') {
HTMLSource = extend({}, this.html);
compile();
} else {
next();
}
} else {
next();
}
return this;
};
api.applyHTML = function(data, skipAutoPopulation) {
this.html = data;
if(!skipAutoPopulation) {
this.populate();
}
return this;
};
var appended = false
api.__append = function(next) {
if(!appended && this.el && this.get("parent")) {
appended = true;
this.get("parent").appendChild(this.el);
}
next();
return this;
}
var cache = { events: {} };
api.__handleEvents = function(next) {
if(this.el) {
var self = this;
var registerEvent = function(el) {
var attrValue = el.getAttribute('data-absurd-event');
var processAttributes = function(attrValue) {
attrValue = attrValue.split(":");
if(attrValue.length >= 2) {
var eventType = attrValue[0];
var methodName = attrValue[1];
attrValue.splice(0, 2);
var args = attrValue;
if(!cache.events[eventType] || cache.events[eventType].indexOf(el) < 0) {
if(!cache.events[eventType]) cache.events[eventType] = [];
cache.events[eventType].push(el);
addEventListener(el, eventType, function(e) {
if(typeof self[methodName] === 'function') {
var f = self[methodName];
f.apply(self, [e].concat(args));
}
});
}
}
}
attrValue = attrValue.split(/, ?/g);
for(var i=0; i<attrValue.length; i++) processAttributes(attrValue[i]);
}
if(this.el.hasAttribute && this.el.hasAttribute('data-absurd-event')) {
registerEvent(this.el);
}
var els = this.el.querySelectorAll ? this.el.querySelectorAll('[data-absurd-event]') : [];
for(var i=0; i<els.length; i++) {
registerEvent(els[i]);
}
}
next();
return this;
}
api.__getAnimAndTransEndEventName = function(el) {
if(!el) return;
var a;
var animations = {
'animation': ['animationend', 'transitionend'],
'OAnimation': ['oAnimationEnd', 'oTransitionEnd'],
'MozAnimation': ['animationend', 'transitionend'],
'WebkitAnimation': ['webkitAnimationEnd', 'webkitTransitionEnd']
}
for(a in animations){
if( el.style[a] !== undefined ){
return animations[a];
}
}
}
api.onAnimationEnd = function(el, func) {
if(arguments.length == 1) {
func = el;
el = this.el;
}
var self = this;
var eventName = api.__getAnimAndTransEndEventName(el);
if(!eventName) { func.apply(this, [{error: 'Animations not supported.'}]); return; };
this.addEventListener(el, eventName[0], function(e) {
func.apply(self, [e]);
});
}
api.onTransitionEnd = function(el, func) {
if(arguments.length == 1) {
func = el;
el = this.el;
}
var self = this;
var eventName = api.__getAnimAndTransEndEventName(el);
if(!eventName) { func.apply(this, [{error: 'Animations not supported.'}]); return; };
this.addEventListener(el, eventName[1], function(e) {
func.apply(self, [e]);
});
}
var async = { funcs: {}, index: 0 };
api.__handleAsyncFunctions = function(next) {
if(this.el) {
var funcs = [];
if(this.el.hasAttribute && this.el.hasAttribute("data-absurd-async")) {
funcs.push(this.el);
} else {
var els = this.el.querySelectorAll ? this.el.querySelectorAll('[data-absurd-async]') : [];
for(var i=0; i<els.length; i++) {
funcs.push(els[i]);
}
}
if(funcs.length === 0) {
next();
} else {
var self = this;
(function callFuncs() {
if(funcs.length === 0) {
next();
} else {
var el = funcs.shift(),
value = el.getAttribute("data-absurd-async"),
replaceNodes = function(childElement) {
if(typeof childElement === 'string') {
el.parentNode.replaceChild(str2DOMElement(childElement), el);
} else {
el.parentNode.replaceChild(childElement, el);
}
callFuncs();
};
if(typeof self[async.funcs[value].name] === 'function') {
self[async.funcs[value].name].apply(self, [replaceNodes].concat(async.funcs[value].args));
} else if(typeof async.funcs[value].func === 'function') {
async.funcs[value].func.apply(self, [replaceNodes].concat(async.funcs[value].args));
}
}
})();
}
} else {
next();
}
return this;
}
api.async = function() {
var args = Array.prototype.slice.call(arguments, 0),
func = args.shift(),
index = '_' + (async.index++);
async.funcs[index] = {args: args, name: func};
return '<script data-absurd-async="' + index + '"></script>';
};
api.child = function() {
var args = Array.prototype.slice.call(arguments, 0),
children = this.get("children"),
component = children && children[args.shift()],
index = '_' + (async.index++);
async.funcs[index] = {args: args, func: function(callback) {
component.populate({callback: function(data) {
callback(data.html.element);
}});
}};
return '<script data-absurd-async="' + index + '"></script>';
};
api.wire = function(event) {
absurd.components.events.on(event, this[event] || function() {}, this);
return this;
};
var isPopulateInProgress = false;
api.populate = function(options) {
if(isPopulateInProgress) return;
isPopulateInProgress = true;
queue([
api.__handleCSS,
api.__handleHTML,
api.__append,
api.__handleEvents,
api.__handleAsyncFunctions,
function() {
isPopulateInProgress = false;
async = { funcs: {}, index: 0 }
var data = {
css: CSS,
html: {
element: this.el
}
};
this.dispatch("populated", data);
if(options && typeof options.callback === 'function') { options.callback(data); }
}
], this);
return this;
};
api.str2DOMElement = str2DOMElement;
api.addEventListener = addEventListener;
api.queue = queue;
api.qs = qs;
api.qsa = qsa;
api.getStyle = getStyle;
api.addClass = addClass;
api.removeClass = removeClass;
api.replaceClass = replaceClass;
api.bind = bind;
api.toggleClass = toggleClass;
api.compileHTML = function(HTML, callback, data) {
absurd.flush().morph("html").add(HTML).compile(callback, data);
};
api.compileCSS = function(CSS, callback, options) {
absurd.flush().add(CSS).compile(callback, options);
};
api.delay = function(time, fn, args) {
var self = this;
setTimeout(function() {
fn.apply(self, args);
}, time);
}
return api;
};
var injecting = function(absurd) {
absurd.di.register('is', {
appended: function(selector) {
if(typeof selector == 'undefined') selector = this.host.html;
return qs(selector) ? true : false;
},
hidden: function(el) {
el = el || this.host.el;
return el.offsetParent === null;
}
});
absurd.di.register('router', {
routes: [],
mode: null,
root: '/',
getFragment: function() {
var fragment = '';
if(this.mode === 'history') {
if(!location) return '';
fragment = this.clearSlashes(decodeURI(location.pathname + location.search));
fragment = fragment.replace(/\?(.*)$/, '');
fragment = this.root != '/' ? fragment.replace(this.root, '') : fragment;
} else {
if(!window) return '';
var match = window.location.href.match(/#(.*)$/);
fragment = match ? match[1] : '';
}
return this.clearSlashes(fragment);
},
clearSlashes: function(path) {
return path.toString().replace(/\/$/, '').replace(/^\//, '');
},
add: function(re, handler) {
if(typeof re == 'function') {
handler = re;
re = '';
}
this.routes.push({ re: re, handler: handler});
return this;
},
remove: function(param) {
for(var i=0, r; i<this.routes.length, r = this.routes[i]; i++) {
if(r.handler === param || r.re === param) {
this.routes.splice(i, 1);
return this;
}
}
return this;
},
flush: function() {
this.routes = [];
this.mode = null;
this.root = '/';
return this;
},
config: function(options) {
this.mode = options && options.mode && options.mode == 'history' && !!(history.pushState) ? 'history' : 'hash';
this.root = options && options.root ? '/' + this.clearSlashes(options.root) + '/' : '/';
return this;
},
listen: function(loopInterval) {
var self = this;
var current = self.getFragment();
var fn = function() {
if(current !== self.getFragment()) {
current = self.getFragment();
self.check(current);
}
}
clearInterval(this.interval);
this.interval = setInterval(fn, loopInterval || 50);
return this;
},
check: function(f) {
var fragment = f || this.getFragment();
for(var i=0; i<this.routes.length; i++) {
var match = fragment.match(this.routes[i].re);
if(match) {
match.shift();
this.routes[i].handler.apply(this.host || {}, match);
return this;
}
}
return this;
},
navigate: function(path) {
path = path ? path : '';
if(this.mode === 'history') {
history.pushState(null, null, this.root + this.clearSlashes(path));
} else {
window.location.href.match(/#(.*)$/);
window.location.href = window.location.href.replace(/#(.*)$/, '') + '#' + path;
}
return this;
}
});
absurd.di.register('ajax', {
request: function(ops) {
if(typeof ops == 'string') ops = { url: ops };
ops.url = ops.url || '';
ops.method = ops.method || 'get'
ops.data = ops.data || {};
var getParams = function(data, url) {
var arr = [], str;
for(var name in data) {
arr.push(name + '=' + encodeURIComponent(data[name]));
}
str = arr.join('&');
if(str != '') {
return url ? (url.indexOf('?') < 0 ? '?' + str : '&' + str) : str;
}
return '';
}
var api = {
host: this.host || {},
process: function(ops) {
var self = this;
this.xhr = null;
if(window.ActiveXObject) { this.xhr = new ActiveXObject('Microsoft.XMLHTTP'); }
else if(window.XMLHttpRequest) { this.xhr = new XMLHttpRequest(); }
if(this.xhr) {
this.xhr.onreadystatechange = function() {
if(self.xhr.readyState == 4 && self.xhr.status == 200) {
var result = self.xhr.responseText;
if(ops.json === true && typeof JSON != 'undefined') {
result = JSON.parse(result);
}
self.doneCallback && self.doneCallback.apply(self.host, [result, self.xhr]);
} else if(self.xhr.readyState == 4) {
self.failCallback && self.failCallback.apply(self.host, [self.xhr]);
}
self.alwaysCallback && self.alwaysCallback.apply(self.host, [self.xhr]);
}
if(ops.method == 'get') {
this.xhr.open("GET", ops.url + getParams(ops.data, ops.url), true);
} else {
this.xhr.open(ops.method, ops.url, true);
this.setHeaders({
'X-Requested-With': 'XMLHttpRequest',
'Content-type': 'application/x-www-form-urlencoded'
});
}
if(ops.headers && typeof ops.headers == 'object') {
this.setHeaders(ops.headers);
}
setTimeout(function() {
ops.method == 'get' ? self.xhr.send() : self.xhr.send(getParams(ops.data));
}, 20);
}
return this;
},
done: function(callback) {
this.doneCallback = callback;
return this;
},
fail: function(callback) {
this.failCallback = callback;
return this;
},
always: function(callback) {
this.alwaysCallback = callback;
return this;
},
setHeaders: function(headers) {
for(var name in headers) {
this.xhr && this.xhr.setRequestHeader(name, headers[name]);
}
}
}
return api.process(ops);
}
});
var dom = function(el, parent) {
var host = dom.prototype.host;
var api = { el: null };
// defining the scope
switch(typeof el) {
case 'undefined':
api.el = host.el;
break;
case 'string':
parent = parent && typeof parent === 'string' ? qs.apply(host, [parent]) : parent;
api.el = qs(el, parent || host.el || document);
break;
case 'object':
if(typeof el.nodeName != 'undefined') {
api.el = el;
} else {
var loop = function(value, obj) {
obj = obj || this;
for(var prop in obj) {
if(typeof obj[prop].el != 'undefined') {
obj[prop] = obj[prop].val(value);
} else if(typeof obj[prop] == 'object') {
obj[prop] = loop(value, obj[prop]);
}
}
delete obj.val;
return obj;
}
var res = { val: loop };
for(var key in el) {
res[key] = dom.apply(this, [el[key]]);
}
return res;
}
break;
}
// getting or setting a value
api.val = function(value) {
if(!this.el) return null;
var set = !!value;
var useValueProperty = function(value) {
if(set) { this.el.value = value; return api; }
else { return this.el.value; }
}
switch(this.el.nodeName.toLowerCase()) {
case 'input':
var type = this.el.getAttribute('type');
if(type == 'radio' || type == 'checkbox') {
var els = qsa('[name="' + this.el.getAttribute('name') + '"]', parent);
var values = [];
for(var i=0; i<els.length; i++) {
if(set && els[i].checked && els[i].value !== value) {
els[i].removeAttribute('checked');
} else if(set && els[i].value === value) {
els[i].setAttribute('checked', 'checked');
els[i].checked = 'checked';
} else if(els[i].checked) {
values.push(els[i].value);
}
}
if(!set) { return type == 'radio' ? values[0] : values; }
} else {
return useValueProperty.apply(this, [value]);
}
break;
case 'textarea': return useValueProperty.apply(this, [value]); break;
case 'select':
if(set) {
var options = qsa('option', this.el);
for(var i=0; i<options.length; i++) {
if(options[i].getAttribute('value') === value) {
this.el.selectedIndex = i;
} else {
options[i].removeAttribute('selected');
}
}
} else {
return this.el.value;
}
break;
default:
if(set) {
this.el.innerHTML = value;
} else {
if(typeof this.el.textContent != 'undefined') {
return this.el.textContent;
} else if(typeof this.el.innerText != 'undefined') {
return typeof this.el.innerText;
} else {
return this.el.innerHTML;
}
}
break;
}
return set ? api : null;
}
// chaining dom module
api.dom = function(el, parent) {
return dom(el, parent || api.el);
}
return api;
}
absurd.di.register('dom', dom);
var mq = function(query, callback, usePolyfill) {
var host = mq.prototype.host;
var isMatchMediaSupported = !!(window && window.matchMedia) && !usePolyfill;
if(isMatchMediaSupported) {
var res = window.matchMedia(query);
callback.apply(host, [res.matches, res.media]);
res.addListener(function(changed) {
callback.apply(host, [changed.matches, changed.media]);
});
} else {
var id = ".match-media-" + absurd.components.numOfComponents;
var css = {}, html = {};
css[id] = { display: 'block' };
css[id]['@media ' + query] = { display: 'none' };
html['span' + id] = '';
absurd.component(id + '-component', {
css: css,
html: html,
intervaliTime: 30,
status: '',
loop: function(dom) {
var self = this;
if(this.el) {
var d = this.getStyle('display');
if(this.status != d) {
this.status = d;
callback.apply(host, [d === 'none'])
}
}
setTimeout(function() { self.loop(); }, this.intervaliTime);
},
constructor: ['dom', function(dom) {
var self = this;
this.set('parent', dom('body').el).populate();
setTimeout(function() { self.loop(); }, this.intervaliTime);
}]
})();
}
};
absurd.di.register('mq', mq);
}
var client = function() {
return function(arg) {
/******************************************* Copied directly from /lib/API.js */
var extend = function(destination, source) {
for (var key in source) {
if (hasOwnProperty.call(source, key)) {
destination[key] = source[key];
}
}
return destination;
};
var _api = {
defaultProcessor: lib.processors.css.CSS()
},
_rules = {},
_storage = {},
_plugins = {},
_hooks = {};
_api.getRules = function(stylesheet) {
if(typeof stylesheet === 'undefined') {
return _rules;
} else {
if(typeof _rules[stylesheet] === 'undefined') {
_rules[stylesheet] = [];
}
return _rules[stylesheet];
}
}
_api.getPlugins = function() {
return _plugins;
}
_api.getStorage = function() {
return _storage;
}
_api.flush = function() {
_rules = {};
_storage = [];
_hooks = {};
_api.defaultProcessor = lib.processors.css.CSS();
return _api;
}
_api.import = function() {
if(_api.callHooks("import", arguments)) return _api;
return _api;
}
// hooks
_api.addHook = function(method, callback) {
if(!_hooks[method]) _hooks[method] = [];
var isAlreadyAdded = false;
for(var i=0; c=_hooks[method][i]; i++) {
if(c === callback) {
isAlreadyAdded = true;
}
}
isAlreadyAdded === false ? _hooks[method].push(callback) : null;
}
_api.callHooks = function(method, args) {
if(_hooks[method]) {
for(var i=0; c=_hooks[method][i]; i++) {
if(c.apply(_api, args) === true) return true;
}
}
return false;
}
// internal variables
_api.numOfAddedRules = 0;
// absurd.components API
_api.components = (function(api) {
var extend = lib.helpers.Extend,
clone = lib.helpers.Clone,
comps = {},
instances = [],
events = extend({}, Component()),
exports = {};
(function(fn) {
if(!window) return;
if (window.addEventListener) {
window.addEventListener('load', fn);
} else if(window.attachEvent) {
window.attachEvent('onload', fn);
}
})(function() {
exports.broadcast("ready");
})
return exports = {
numOfComponents: 0,
events: events,
register: function(name, cls) {
this.numOfComponents += 1;
return comps[name] = function() {
var c = extend({}, Component(name, api, events, clone(cls)));
api.di.resolveObject(c);
instances.push(c);
if(typeof c.constructor === 'function') {
c.constructor.apply(c, Array.prototype.slice.call(arguments, 0));
}
return c;
};
},
get: function(name) {
if(comps[name]) { return comps[name]; }
else { throw new Error("There is no component with name '" + name + "'."); }
},
remove: function(name) {
if(comps[name]) { delete comps[name]; return true; }
return false;
},
list: function() {
var l = [];
for(var name in comps) l.push(name);
return l;
},
flush: function() {
comps = {};
instances = [];
return this;
},
broadcast: function(event, data) {
for(var i=0; i<instances.length, instance=instances[i]; i++) {
if(typeof instance[event] === 'function') {
instance[event](data);
}
}
return this;
}
}
})(_api);
// absurd.component shortcut
_api.component = (function(api) {
return function(name, cls) {
if(typeof cls == 'undefined') {
return api.components.get(name);
} else {
return api.components.register(name, cls);
}
}
})(_api);
// dependency injector
_api.di = lib.DI(_api);
injecting(_api);
/******************************************* Copied directly from /lib/API.js */
// client side specific methods
_api.compile = function(callback, options) {
if(_api.callHooks("compile", arguments)) return _api;
var defaultOptions = {
combineSelectors: true,
minify: false,
processor: _api.defaultProcessor,
keepCamelCase: false,
api: _api
};
options = extend(defaultOptions, options || {});
options.processor(
_api.getRules(),
callback || function() {},
options
);
_api.flush();
}
// registering api methods
for(var method in lib.api) {
if(method !== "compile") {
_api[method] = lib.api[method](_api);
_api[method] = (function(method) {
return function() {
var f = lib.api[method](_api);
if(_api.callHooks(method, arguments)) return _api;
return f.apply(_api, arguments);
}
})(method);
}
}
// registering plugins
for(var pluginName in lib.processors.css.plugins) {
_api.plugin(pluginName, lib.processors.css.plugins[pluginName]());
}
// accept function
if(typeof arg === "function") {
arg(_api);
}
// check for Organic
if(typeof Organic != 'undefined') {
Organic.init(_api);
}
// attaching utils functions
_api.utils = {
str2DOMElement: str2DOMElement
}
return _api;
}
};lib.DI = function(api) {
var injector = {
dependencies: {},
register: function(key, value) {
this.dependencies[key] = value;
return this;
},
resolve: function() {
var func, deps, scope, self = this, isForResolving = false;
if(typeof arguments[0] === 'string') {
func = arguments[1];
deps = arguments[0].replace(/ /g, '').split(',');
scope = arguments[2] || {};
} else {
func = arguments[0];
deps = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].replace(/ /g, '').split(',');
scope = arguments[1] || {};
}
for(var i=0; i<deps.length; i++) {
if(typeof this.dependencies[deps[i]] != 'undefined') isForResolving = true;
}
if(isForResolving) {
return function() {
var args = [];
var a = Array.prototype.slice.call(arguments, 0);
for(var i=0; i<deps.length; i++) {
var d = deps[i];
if(typeof self.dependencies[d] != 'undefined') {
var diModule = self.dependencies[d];
if(typeof diModule == 'function') {
diModule.prototype.host = scope;
} else if(typeof diModule == 'object') {
diModule.host = scope;
}
args.push(diModule);
} else {
args.push(a.shift())
}
}
return func.apply(scope, args);
}
}
return func;
},
resolveObject: function(o) {
if(typeof o == 'object') {
for(var key in o) {
if(typeof o[key] == 'function') {
o[key] = this.resolve(o[key], o);
} else if(o[key] instanceof Array && o[key].length == 2 && typeof o[key][0] == 'string' && typeof o[key][1] == 'function') {
o[key] = this.resolve(o[key][0], o[key][1], o);
}
}
}
return this;
},
flush: function() {
this.dependencies = {};
return this;
}
}
return injector;
};
lib.api.add = function(API) {
var extend = require("../helpers/Extend"),
prefixes = require("../helpers/Prefixes"),
toRegister = [],
options = {
combineSelectors: true,
preventCombining: ['@font-face']
};
var checkAndExecutePlugin = function(selector, prop, value, stylesheet, parentSelector) {
var prefix = prefixes.nonPrefixProp(prop);
var plugin = API.getPlugins()[prefix.prop];
// console.log("\nChecking for plugin: " + prefix.prop + " (" + prop + ")");
if(typeof plugin !== 'undefined') {
var pluginResponse = plugin(API, value, prefix.prefix);
if(pluginResponse) {
addRule(selector, pluginResponse, stylesheet, parentSelector);
}
return true;
} else {
return false;
}
}
var addRule = function(selector, props, stylesheet, parentSelector) {
// console.log("\n---------- addRule ---------", parentSelector + ' >>> ' + selector, "\n", props);
stylesheet = stylesheet || "mainstream";
// catching null values
if(props === null || typeof props === 'undefined' || props === false) return;
if(!parentSelector && !selector) selector = '';
// multiple selectors
if(/, ?/g.test(selector) && options.combineSelectors) {
var parts = selector.replace(/, /g, ',').split(',');
for(var i=0; i<parts.length, p=parts[i]; i++) {
addRule(p, props, stylesheet, parentSelector);
}
return;
}
// check for plugin
if(checkAndExecutePlugin(null, selector, props, stylesheet, parentSelector)) {
return;
}
// if array is passed
if(typeof props.length !== 'undefined' && typeof props === "object") {
for(var i=0; i<props.length, prop=props[i]; i++) {
addRule(selector, prop, stylesheet, parentSelector);
}
return;
}
var _props = {},
_selector = selector,
_objects = {},
_functions = {};
// processing props
for(var prop in props) {
// classify
if(props[prop] && typeof props[prop].classify != 'undefined' && props[prop].classify === true) {
props[prop] = typeof props[prop].toJSON != 'undefined' ? props[prop].toJSON() : props[prop].toString();
}
var type = typeof props[prop];
if(type !== 'object' && type !== 'function' && props[prop] !== false && props[prop] !== true) {
if(checkAndExecutePlugin(selector, prop, props[prop], stylesheet, parentSelector) === false) {
// moving the selector to the top of the chain
if(_selector.indexOf("^") === 0) {
_selector = _selector.substr(1, _selector.length-1) + (typeof parentSelector !== "undefined" ? " " + parentSelector : '');
} else {
_selector = typeof parentSelector !== "undefined" ? parentSelector + " " + selector : selector;
}
_props[prop] = props[prop];
prefixes.addPrefixes(prop, _props);
}
} else if(type === 'object') {
_objects[prop] = props[prop];
} else if(type === 'function') {
_functions[prop] = props[prop];
}
}
toRegister.push({
selector: _selector,
props: _props,
stylesheet: stylesheet
});
for(var prop in _objects) {
// check for pseudo classes
if(prop.charAt(0) === ":") {
addRule(selector + prop, _objects[prop], stylesheet, parentSelector);
// check for ampersand operator
} else if(/&/g.test(prop)) {
if(/, ?/g.test(prop) && options.combineSelectors) {
var parts = prop.replace(/, /g, ',').split(',');
for(var i=0; i<parts.length, p=parts[i]; i++) {
if(p.indexOf('&') >= 0) {
addRule(p.replace(/&/g, selector), _objects[prop], stylesheet, parentSelector);
} else {
addRule(p, _objects[prop], stylesheet, typeof parentSelector !== "undefined" ? parentSelector + " " + selector : selector);
}
}
} else {
addRule(prop.replace(/&/g, selector), _objects[prop], stylesheet, parentSelector);
}
// check for media query
} else if(prop.indexOf("@media") === 0 || prop.indexOf("@supports") === 0) {
addRule(selector, _objects[prop], prop, parentSelector);
// check for media query
} else if(selector.indexOf("@media") === 0 || prop.indexOf("@supports") === 0) {
addRule(prop, _objects[prop], selector, parentSelector);
// moving the selector to the top of the chain
} else if(selector.indexOf("^") === 0) {
// selector, props, stylesheet, parentSelector
addRule(
selector.substr(1, selector.length-1) + (typeof parentSelector !== "undefined" ? " " + parentSelector : '') + " " + prop,
_objects[prop],
stylesheet
);
// check for plugins
} else if(checkAndExecutePlugin(selector, prop, _objects[prop], stylesheet, parentSelector) === false) {
addRule(prop, _objects[prop], stylesheet, (parentSelector ? parentSelector + " " : "") + selector);
}
}
for(var prop in _functions) {
var o = {};
o[prop] = _functions[prop]();
addRule(selector, o, stylesheet, parentSelector);
}
}
var add = function(rules, stylesheet, opts) {
try {
toRegister = [];
API.numOfAddedRules += 1;
if(typeof stylesheet === 'object' && typeof opts === 'undefined') {
options = {
combineSelectors: typeof stylesheet.combineSelectors != 'undefined' ? stylesheet.combineSelectors : options.combineSelectors,
preventCombining: options.preventCombining.concat(stylesheet.preventCombining || [])
};
stylesheet = null;
}
if(typeof opts != 'undefined') {
options = {
combineSelectors: opts.combineSelectors || options.combineSelectors,
preventCombining: options.preventCombining.concat(opts.preventCombining || [])
};
}
var typeOfPreprocessor = API.defaultProcessor.type, uid;
for(var selector in rules) {
addRule(selector, rules[selector], stylesheet || "mainstream");
}
// looping through the rules for registering
for(var i=0; i<toRegister.length; i++) {
var stylesheet = toRegister[i].stylesheet,
selector = toRegister[i].selector,
props = toRegister[i].props,
allRules = API.getRules(stylesheet);
var pc = options && options.preventCombining ? '|' + options.preventCombining.join('|') : '';
var uid = pc.indexOf('|' + selector) >= 0 ? '~~' + API.numOfAddedRules + '~~' : '';
// overwrite already added value
var current = allRules[uid + selector] || {};
for(var propNew in props) {
var value = props[propNew];
propNew = uid + propNew;
if(typeof value != 'object') {
if(typeOfPreprocessor == "css") {
// appending values
if(value.toString().charAt(0) === "+") {
if(current && current[propNew]) {
current[propNew] = current[propNew] + ", " + value.substr(1, value.length-1);
} else {
current[propNew] = value.substr(1, value.length-1);
}
} else if(value.toString().charAt(0) === ">") {
if(current && current[propNew]) {
current[propNew] = current[propNew] + " " + value.substr(1, value.length-1);
} else {
current[propNew] = value.substr(1, value.length-1);
}
} else {
current[propNew] = value;
}
} else {
current[propNew] = value;
}
}
}
allRules[uid + selector] = current;
}
return API;
} catch(err) {
throw new Error("Error adding: " + JSON.stringify({rules: rules, error: err.toString()}));
}
}
return add;
}
var extend = require("../helpers/Extend");
lib.api.compile = function(api) {
return function() {
var path = null, callback = null, options = null;
for(var i=0; i<arguments.length; i++) {
switch(typeof arguments[i]) {
case "function": callback = arguments[i]; break;
case "string": path = arguments[i]; break;
case "object": options = arguments[i]; break;
}
}
var _defaultOptions = {
combineSelectors: true,
minify: false,
keepCamelCase: false,
processor: api.defaultProcessor,
api: api
};
options = extend(_defaultOptions, options || {});
options.processor(
api.getRules(),
function(err, result) {
if(path != null) {
try {
fs.writeFile(path, result, function (err) {
callback(err, result);
});
} catch(err) {
callback.apply({}, arguments);
}
} else {
callback.apply({}, arguments);
}
api.flush();
},
options
);
}
}
lib.api.compileFile = function(api) {
return api.compile;
}
var ColorLuminance = function (hex, lum) {
// validate hex string
hex = String(hex).replace(/[^0-9a-f]/gi, '');
if (hex.length < 6) {
hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
}
lum = lum || 0;
// convert to decimal and change luminosity
var rgb = "#", c, i;
for (i = 0; i < 3; i++) {
c = parseInt(hex.substr(i*2,2), 16);
c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
rgb += ("00"+c).substr(c.length);
}
return rgb;
};
lib.api.darken = function(api) {
return function(color, percents) {
return ColorLuminance(color, -(percents/100));
}
}
lib.api.define = function(api) {
return function(prop, value) {
if(!api.getStorage().__defined) api.getStorage().__defined = {};
api.getStorage().__defined[prop] = value;
return api;
}
}
lib.api.hook = function(api) {
return function(method, callback) {
api.addHook(method, callback);
return api;
}
}
var ColorLuminance = function (hex, lum) {
// validate hex string
hex = String(hex).replace(/[^0-9a-f]/gi, '');
if (hex.length < 6) {
hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
}
lum = lum || 0;
// convert to decimal and change luminosity
var rgb = "#", c, i;
for (i = 0; i < 3; i++) {
c = parseInt(hex.substr(i*2,2), 16);
c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
rgb += ("00"+c).substr(c.length);
}
return rgb;
};
lib.api.lighten = function(api) {
return function(color, percents) {
return ColorLuminance(color, percents/100);
}
}
var metamorphosis = {
html: function(api) {
api.defaultProcessor = require(__dirname + "/../processors/html/HTML.js")();
api.hook("add", function(tags, template) {
api.getRules(template || "mainstream").push(tags);
return true;
});
},
component: function(api) {
api.defaultProcessor = require(__dirname + "/../processors/component/Component.js")();
api.hook("add", function(component) {
if(!(component instanceof Array)) component = [component];
for(var i=0; i<component.length, c = component[i]; i++) {
api.getRules("mainstream").push(c);
}
return true;
});
}
}
lib.api.morph = function(api) {
return function(type) {
if(metamorphosis[type]) {
api.flush();
metamorphosis[type](api);
}
return api;
}
}
lib.api.plugin = function(api) {
var plugin = function(name, func) {
api.getPlugins()[name] = func;
return api;
}
return plugin;
}
lib.api.raw = function(api) {
return function(raw) {
var o = {}, v = {};
var id = "____raw_" + api.numOfAddedRules;
v[id] = raw;
o[id] = v;
api.add(o);
return api;
}
}
var fs = require("fs"),
path = require("path");
lib.api.rawImport = function(API) {
var importFile = function(path) {
var fileContent = fs.readFileSync(path, {encoding: "utf8"});
API.raw(fileContent);
}
return function(path) {
var p, _i, _len;
if (typeof path === 'string') {
importFile(path);
} else {
for (_i = 0, _len = path.length; _i < _len; _i++) {
p = path[_i];
importFile(p);
}
}
return API;
};
}
lib.api.register = function(api) {
return function(method, func) {
api[method] = func;
return api;
}
}
lib.api.storage = function(API) {
var _s = API.getStorage();
var storage = function(name, value) {
if(typeof value !== "undefined") {
_s[name] = value;
} else if(typeof name === "object") {
for(var _name in name) {
if(Object.prototype.hasOwnProperty.call(name, _name)) {
storage(_name, name[_name]);
}
}
} else {
if(_s[name]) {
return _s[name];
} else {
throw new Error("There is no data in the storage associated with '" + name + "'");
}
}
return API;
}
return storage;
}
lib.helpers.Clone = function clone(item) {
if (!item) { return item; } // null, undefined values check
var types = [ Number, String, Boolean ],
result;
// normalizing primitives if someone did new String('aaa'), or new Number('444');
types.forEach(function(type) {
if (item instanceof type) {
result = type( item );
}
});
if (typeof result == "undefined") {
if (Object.prototype.toString.call( item ) === "[object Array]") {
result = [];
item.forEach(function(child, index, array) {
result[index] = clone( child );
});
} else if (typeof item == "object") {
// testing that this is DOM
if (item.nodeType && typeof item.cloneNode == "function") {
var result = item.cloneNode( true );
} else if (!item.prototype) { // check that this is a literal
if (item instanceof Date) {
result = new Date(item);
} else {
// it is an object literal
result = {};
for (var i in item) {
result[i] = clone( item[i] );
}
}
} else {
// depending what you would like here,
// just keep the reference, or create new object
if (false && item.constructor) {
// would not advice to do that, reason? Read below
result = new item.constructor();
} else {
result = item;
}
}
} else {
result = item;
}
}
return result;
}
// credits: http://www.sitepoint.com/javascript-generate-lighter-darker-color/
lib.helpers.ColorLuminance = function (hex, lum) {
// validate hex string
hex = String(hex).replace(/[^0-9a-f]/gi, '');
if (hex.length < 6) {
hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
}
lum = lum || 0;
// convert to decimal and change luminosity
var rgb = "#", c, i;
for (i = 0; i < 3; i++) {
c = parseInt(hex.substr(i*2,2), 16);
c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
rgb += ("00"+c).substr(c.length);
}
return rgb;
}
lib.helpers.Extend = function() {
var process = function(destination, source) {
for (var key in source) {
if (hasOwnProperty.call(source, key)) {
destination[key] = source[key];
}
}
return destination;
};
var result = arguments[0];
for(var i=1; i<arguments.length; i++) {
result = process(result, arguments[i]);
}
return result;
}
// http://docs.emmet.io/css-abbreviations/vendor-prefixes/ (w: webkit, m: moz, s: ms, o: o)
var prefixExtract = function(prop) {
var result, match;
if(match = prop.match(/^\-(w|m|s|o)+\-/) || prop.charAt(0) === '-') {
if(match !== null && match[0]) {
result = { prefix: match[0].replace(/-/g, '') }
result.prop = prop.replace(match[0], '');
} else {
result = { prefix: '' }
result.prop = prop.substr(1, prop.length);
}
} else {
result = {
prefix: false,
prop: prop
}
}
return result;
}
lib.helpers.Prefixes = {
addPrefixes: function(prop, obj) {
var originalProp = prop, p = prefixExtract(prop), value = obj[prop];
if(p.prefix !== false) {
delete obj[originalProp];
obj[p.prop] = value;
if(p.prefix === '' || p.prefix.indexOf('w') >= 0)
obj['-webkit-' + p.prop] = value;
if(p.prefix === '' || p.prefix.i