Skip to content

Instantly share code, notes, and snippets.

@dblock
Created May 3, 2019 17:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dblock/5f97961819d4c2162abdcd5e4712f2ff to your computer and use it in GitHub Desktop.
Save dblock/5f97961819d4c2162abdcd5e4712f2ff to your computer and use it in GitHub Desktop.
star orgs/artsy
/*
Create Element:
$Rainb.el('div',{'attribute':"value",style:{"color":"red"}},[ (childnodes) ])
becomes: <div attribute="value" style="color: red;"></div>
Append Element
$Rainb.add(element,elementToAppend)
Get Element By Id
$Rainb.id(id);
Create TextNode
$Rainb.tn(text);
Create a RainbNode (an element wrapper)
$Rainb.node(elem);
You can modify RainbNode attributes and children and it will not affect DOM until you call .render
Parameter is boolean, true for rendering children, false for not rendering children
$Rainb.node.render(boolean);
*/
//This probably proves I've gotten better at programming.
//DOM helper functions.
var genParser = (function(tys, tree, start) {
var source, index;
var treeRewrite = tree;
//Apparently, you don't tokenize and then parse, you do it on the go, but with more specific techniques which people call grammars, oh well, how was I suppesd to know that anyway.
//reference {type:"type",is:"type"} "hue"
//repetition {type:"repeat",optional:false,from:1,to:Infinity,contains:{},delimiting:null,multipleDelimeters:null} optional to and from are defaulted, delimiters can be used for lists like a,b,c and stuff
//array {type:"tyArray",contains:[]}
//alternate {type:"alternate",contains:[]}
//Expression {type:"expression",contains:{},operators:[{precedence:1,rightAssociative:false,tokens:[]}}],delimeters=[["(",")"]],whiteSpaceIgnore:null}
var mains = { //START PARSE
type: "type",
is: start
}
//yay extendibility
var funcs = { //funcions/types used, hue
expression: function(o) { //parse it like an expression
//this is probably a little bit hard to understand
var r = {
type: "alternate",
contains: [o.contains]
}, //is it a token, an operator, or a parenthesis?
opers = {
type: "alternate",
contains: []
},
delims = {
type: "alternate",
contains: []
},
i, I, l, L, props, t, n, ret = {},
_ind = index,
EXPRS = [],
OPERATORS = [],
O, precedence, rightAssociative, arg1, arg2, k; //I use and reuse most variables I can, damn
if (O = o.operators) {
for (i = 0, l = O.length; i < l; i++) {
for (I = 0, L = O[i].tokens.length; I < L; I++) {
t = O[i].tokens[I];
if (o.whiteSpaceIgnore) {
if (typeof t === "string") {
opers.contains.push(new RegExp("\\s*(?:" + t.replace(/([-+\\?.!$^&*(){}[\]])/g, "\\$1") + ")\\s*"));
} else if (t instanceof RegExp) {
opers.contains.push(new RegExp("\\s*(?:" + t.source + ")\\s*", (t.multiline ? "m" : "") + (t.ignoreCase ? "i" : "")))
} else {
opers.contains.push({
type: "tyArray",
contains: [/\s*/, t, /\s*/]
}); /*Ahh I HATE THIS! D:*/
}
} else {
opers.contains.push(t);
}
}
}
r.contains[1] = opers; //ADD THEM TO THE LIST
}
if (O = o.delimeters) { //this is like a carbon copy of the previous if, should I try to make it a function? Don't repeat yourself
for (i = 0, l = O.length; i < l; i++) {
for (I = 0, L = O[i].length; I < L; I++) {
t = O[i][I];
if (o.whiteSpaceIgnore) {
if (typeof t === "string") {
delims.contains.push(new RegExp("\s*(?:" + t + ")\s*"));
} else if (t instanceof RegExp) {
delims.contains.push(new RegExp("\s*(?:" + t.source + ")\s*", (t.multiline ? "m" : "") + (t.ignoreCase ? "i" : "")))
} else {
delims.contains.push({
type: "tyArray",
contains: [/\s*/, t, /\s*/]
}); /*Ahh I HATE THIS! D:*/
}
} else {
delims.contains.push(t);
}
}
}
r.contains[2] = delims;
}
/*Shunting Yard Algorithm*/
while (n = isIndexItem(r, props = {})) { //While there are tokens to be read
//read a token
if (props._matched === r.contains[0]) { //If the token is a number, then add it to the output queue.
EXPRS.push(n);
} else
if (props._matched === opers) { //If the token is an operator, o1, then
if ((I = opers.contains.indexOf(props.props._matched)) !== -1) {
for (i = 0, l = (O = o.operators).length, k = 0; i < l; i++) { //
if ((k += O[i].tokens.length) > I) {
precedence = O[i].precedence;
rightAssociative = O[i].rightAssociative;
break;
}
}
} else {
throw new Error("props.props._matched not found at oper.contains, This is impossible.. or is it?");
}
while ((L = OPERATORS.length) && (((!rightAssociative) && precedence === OPERATORS[L - 1][1]) || precedence < OPERATORS[L - 1][1])) { //while there is an operator token, o2, at the top of the stack, and
//either o1 is left-associative and its precedence is equal to that of o2,
//or o1 has precedence less than that of o2,
/*POPPINGG!!*/
//pop o2 off the stack, onto the output queue;
//This popping is also a bit of PRN execution, basically it is shunting yard and prn, or something weird
arg2 = EXPRS.pop();
arg1 = EXPRS.pop();
if (!(EXPRS.length || arg1)) {
console.warn("NOT ENOUGH TERMS");
}
t = OPERATORS.pop();
for (i = 0, l = (O = o.operators).length, k = 0; i < l; i++) {
if ((k += O[i].tokens.length) > t[2]) {
EXPRS.push({
operation: O[i].tokens[t[2] - (k - O[i].tokens.length)],
op: t[0],
arguments: [arg1, arg2],
name: "operator"
});
break;
}
}
}
OPERATORS.push([n, precedence, I]);
} else
if (props._match === delims) {} else {
throw Error("This is impossible! It has matched an unknown value..???");
}
}
//When there are no more tokens to read
while (L = OPERATORS.length) { //While there are still operator tokens in the stack
//Pop the operator onto the output queue.
arg2 = EXPRS.pop();
arg1 = EXPRS.pop();
if (!(EXPRS.length || arg1)) {
console.warn("NOT ENOUGH TERMS");
}
t = OPERATORS.pop();
for (i = 0, l = (O = o.operators).length, k = 0; i < l; i++) {
if ((k += O[i].tokens.length) > t[2]) {
EXPRS.push({
operation: O[i].tokens[t[2] - (k - O[i].tokens.length)],
op: t[0],
arguments: [arg1, arg2],
name: "operator"
});
break;
}
}
}
if (EXPRS.length < 1) {
return null;
}
if (EXPRS.length !== 1) {
throw new Error("Operators and expressions mismatch!!");
}
return EXPRS[0];
},
type: function(o) { //get type and parse it
var props = {},
a = isIndexItem(tys[o.is], props),
t, ret; //this is where props originally started, in short words, it is used to pass properties from other functions to here
if (a === null) return null;
//console.log()
ret = {
type: (t = tys[o.is]) && (t.delimiting ? "list" : t.type || ((typeof t === "string" || t instanceof RegExp) ? "String" : undefined)),
name: o.is,
content: a
}
for (var k in props) {
if (props.hasOwnProperty(k) && (!ret[k])) {
ret[k] = props[k];
}
}
return ret;
},
repeat: function(o, props) { //repeat
var reto = [],
e, d, _ind = index,
l, p, D = o.delimiting,
i = 0,
p = D && o.multipleDelimeters, //say, if the delimeter is just once, there is no point in putting it each time it appears.. right? so an CSV like "abc,dfe,ege" will appear as ["abc","dfe","ege"] instead of ["abc",',',"dfe",',',"ege"]
props2;
d = o.contains;
props.props = [];
do {
e = isIndexItem(D ? i & 1 ? D : d : d, props2 = {});
if ((!p) && D && i & 1) {
i++;
if (e !== null) {
continue;
} else {
break;
}
}
i++;
if (e !== null) {
reto.push(e)
props.props.push(props2)
}
} while (e !== null && i !== o.to);
l = reto.length;
if (((!o.optional) && l == 0) || ((!isNaN(p = o.from)) && l < p)) {
index = _ind;
return null;
}
if (D && !p) {
props.delimeter = D
}
return reto;
},
tyArray: function(o, props) { //tokens are in some order
var reto = [],
e, _ind = index,
opt = o.optional || [],
props2;
props.props = [];
for (var i = 0, l = o.contains.length, d; i < l; i++) {
d = o.contains[i];
e = isIndexItem(d, props2 = {});
if (e === null && (opt.indexOf(i) < 0)) {
index = _ind;
return null;
}
if (e !== null) props.props.push(props2);
reto.push(e);
}
return reto;
},
alternate: function(o, props) { //It alternates
var reto = null,
e, props2 = {};
for (var i = 0, l = o.contains.length, d; i < l; i++) {
d = o.contains[i];
e = isIndexItem(d, props2);
if (e !== null) {
reto = e;
props.props = props2;
props._matched = d;
break;
}
}
return reto;
}
}
function isIndexItem(item, props) { //recursive
//returns item or null
var s, t, r,
f;
if (!item) {
return null
} else
if (item instanceof RegExp) {
r = new RegExp
r.compile("^(?:" + item.source + ")", (item.multiline ? "m" : "") + (item.eturnignoreCase ? "i" : ""))
//r.lastIndex = index;
s = r.exec(source.substr(index)); //RAAAWR damn it
t = s && s[0];
if (t === null) return null;
index += t.length;
return t;
} else if (typeof item == "string") { //literal match
//console.log("DOES "+item+" and"+source.substr(index,item.length)+" MATCHES??");
if (item === source.substr(index, item.length)) return (index += item.length), item;
return null;
} else {
t = item.type;
f = funcs[t];
s = f(item, props);
if (f) return s;
else return null;
}
}
function Parser(arg) {
source = arg,
index = 0; //index is 0!!!
return treeRewrite.unknown(isIndexItem(mains)); //wasn't that just pretty understandable?
}
return Parser;
});
var CssSelectorParser = genParser({ //tys, meaning types
"type selector": /\*|(?:[\w_]|\\x?[a-f0-9]{2,6}\s?|\\[\S\s])(?:[^\\\s#.>&+~:,="'[\]\)]|\\x?[a-f0-9]{2,6}\s?|\\[\S\s])*/i, //regex for tagname
attributeValue: { //the vaue of an attibute, it can be
type: "alternate",
contains: [/"(?:[^"\\]|\\[\s\S])*"|'(?:[^'\\]|\\[\s\S])*'/i, {
type: "type",
is: "type selector"
}]
},
"pseudo-class": {
type: "alternate",
contains: [{
type: "tyArray",
contains: [":not", {
type: "tyArray",
contains: ["(", {
type: "type",
is: "selectorArray"
}, ")"]
}],
}, {
type: "tyArray",
contains: [/::?(?:[\w_]|\\x?[a-f0-9]{2,6}\s?|\\[\S\s])(?:[^\\\s#.>&+~:,(]|\\x?[a-f0-9]{2,6}\s?|\\[\S\s])*/, {
type: "tyArray",
contains: ["(", /(?:[^)\\]|\\[\S\s])*/, ")"]
}],
optional: [1]
}]
}, //is for this I was thinking of implementing my own regex, this is beyond ridiculous
operator: /\s*(?:\$=|\^=|~=|\|=|\*=|=)\s*/, //you know the thing at [attr=value]
"attribute selector": {
type: "tyArray",
contains: ['[', {
type: "tyArray",
contains: [{
type: "type",
is: "type selector"
}, {
type: "type",
is: "operator"
}, {
type: "type",
is: "attributeValue"
}],
optional: [1, 2]
}, ']']
},
"ID selector": {
type: "tyArray",
contains: ['#', { //an id starts with an #
type: "type",
is: "type selector"
}]
},
"class selector": { //a classname starts with a dot
type: "tyArray",
contains: ['.', {
type: "type",
is: "type selector"
}]
},
"simple selector": { //a element selector is composed from tagname, clasname,attributesm, and pseudoclasses
//this is a sequence of simple selectors
type: "repeat",
contains: {
type: "alternate",
contains: [{
type: "type",
is: "type selector"
}, {
type: "type",
is: "class selector"
}, {
type: "type",
is: "ID selector"
}, {
type: "type",
is: "attribute selector"
}, {
type: "type",
is: "pseudo-class"
}]
}
},
selector:
/* {OLD LOL
type: "repeat",
delimiting: {
type: "type",
is: "relationship"
},
contains: {
type: "type",
is: "element"
}*/
{
type: "expression",
contains: {
type: "type",
is: "simple selector"
},
whiteSpaceIgnore: true,
rightAssociative: true,
operators: [{
precedence: 1,
tokens: ['>', '&', '+', '~', /\s/] //these are not actually operators this are combinators
}]
},
selectorArray: { //this is a selector group
type: "repeat",
delimiting: /\s*,\s*/, //it is separated by a comma, and optionally whitespace
contains: {
type: "type",
is: "selector"
}
}
}, {
unknown: function(a) {
return a.name ? this[a.name](a) : a;
},
selectorArray: function(a) {
var b = {
name: "selector group",
list: []
};
for (var i = 0, l = a.content.length; i < l; i++) b.list.push(this.unknown(a.content[i]))
return b
},
selector: function(a) {
return this.unknown(a.content)
},
"simple selector": function(a) {
var b = {},
att, c;
b.class = [];
b.attributes = [];
b.pseudoClass = [];
for (var i = 0, l = a.content.length, d; i < l; i++) {
d = a.content[i];
switch (d.name) {
case "type selector":
if (!b.tagName) {
b.tagname = this.unescape(d.content);
}
break;
case "class selector":
b.class.push(this.unescape(d.content[1].content))
break;
case "ID selector":
if (!b.ID) {
b.ID = this.unescape(d.content[1].content);
}
break;
case "attribute selector":
att = {
attributeName: this.unescape(d.content[1][0].content)
}
if (c = d.content[1][1]) {
att.operator = c.content;
att.attributeValue = this.unescape(d.content[1][2].content)
}
b.attributes.push(att);
break;
case "pseudo-class":
b.pseudoClass.push({
class: this.unescape(d.content[0]),
value: d.content[1] && this.unknown(d.content[1][1])
})
break;
}
}
return b;
},
operator: function(a) {
var b = this.unknown(a.arguments[1]);
b.parent = this.unknown(a.arguments[0]);
b.parentRelationship = a.op;
return b;
},
unescape: function(string) {
var unescape = [{
search: /\\([0-9A-fa-f]{1,6} ?)/g,
replace: {
f: "hexadecimal",
for: 1
}
}, {
search: /\\(.)/g,
replace: {
for: 1
}
}];
var replacement, string2 = string,
func;
if ((string[0] == '"' || string[0] == "'") && (string[0] === string[string.length - 1])) {
string2 = string.substring(1, string.length - 1)
}
for (var i = 0; i < unescape.length; i++) {
if ((func = unescape[i].replace.f) === undefined) {
replacement = "$" + unescape[i].replace.for
} else {
if (func == "hexadecimal") replacement = function(s) {
return String.fromCharCode(parseInt(arguments[unescape[i].replace.for], 16))
}
}
string2 = string2.replace(unescape[i].search, replacement)
}
return string2;
}
}, "selectorArray");
$Rainb = {
d: document.documentElement
}
$Rainb.id = function(id) {
return document.getElementById(id);
};
$Rainb.ready = function(fc) {
var cb;
if (document.readyState !== 'loading') {
fc();
return;
}
cb = function() {
$Rainb.off(document, 'DOMContentLoaded', cb);
return fc();
};
return $Rainb.on(document, 'DOMContentLoaded', cb);
};
$Rainb.formData = function(form) {
var fd, key, val;
if (form instanceof HTMLFormElement) {
return new FormData(form);
}
fd = new FormData();
for (key in form) {
val = form[key];
if (val) {
if (typeof val === 'object' && 'newName' in val) {
fd.append(key, val, val.newName);
} else {
fd.append(key, val);
}
}
}
return fd;
};
$Rainb.extend = function(object, properties) {
var key, val;
for (key in properties) {
val = properties[key];
object[key] = val;
}
};
$Rainb.deepCompare = function() {
var i, l, leftChain, rightChain;
function compare2Objects(x, y) {
var p;
// remember that NaN === NaN returns false
// and isNaN(undefined) returns true
if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
return true;
}
// Compare primitives and functions.
// Check if both arguments link to the same object.
// Especially useful on step when comparing prototypes
if (x === y) {
return true;
}
// Works in case when functions are created in constructor.
// Comparing dates is a common scenario. Another built-ins?
// We can even handle functions passed across iframes
if ((typeof x === 'function' && typeof y === 'function') || (x instanceof Date && y instanceof Date) || (x instanceof RegExp && y instanceof RegExp) || (x instanceof String && y instanceof String) || (x instanceof Number && y instanceof Number)) {
return x.toString() === y.toString();
}
// At last checking prototypes as good a we can
if (!(x instanceof Object && y instanceof Object)) {
return false;
}
if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
return false;
}
if (x.constructor !== y.constructor) {
return false;
}
if (x.prototype !== y.prototype) {
return false;
}
// Check for infinitive linking loops
if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
return false;
}
// Quick checking of one object beeing a subset of another.
// todo: cache the structure of arguments[0] for performance
for (p in y) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
} else if (typeof y[p] !== typeof x[p]) {
return false;
}
}
for (p in x) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
} else if (typeof y[p] !== typeof x[p]) {
return false;
}
switch (typeof(x[p])) {
case 'object':
case 'function':
leftChain.push(x);
rightChain.push(y);
if (!compare2Objects(x[p], y[p])) {
return false;
}
leftChain.pop();
rightChain.pop();
break;
default:
if (x[p] !== y[p]) {
return false;
}
break;
}
}
return true;
}
if (arguments.length < 1) {
return true; //Die silently? Don't know how to handle such case, please help...
// throw "Need two or more arguments to compare";
}
for (i = 1, l = arguments.length; i < l; i++) {
leftChain = []; //Todo: this can be cached
rightChain = [];
if (!compare2Objects(arguments[0], arguments[i])) {
return false;
}
}
return true;
}
$Rainb.on = function(el, events, handler) {
var event, _i, _len, _ref;
_ref = events.split(' ');
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
event = _ref[_i];
el.addEventListener(event, handler, false);
}
};
$Rainb.off = function(el, events, handler) {
var event, _i, _len, _ref;
_ref = events.split(' ');
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
event = _ref[_i];
el.removeEventListener(event, handler, false);
}
};
$Rainb.el = function(elem, attributes, childnodes, listeners) {
//listener format: {lstng:"click",cb:callback}
var e = (elem instanceof Element) ? elem : document.createElement(elem),
l;
for (var a in attributes) {
if (a == "style") {
for (var d in attributes[a]) {
e.style[d] = attributes[a][d];
}
continue;
}
if (a == "__properties") {
for (d in attributes[a]) {
e[d] = attributes[a][d];
}
continue;
}
e.setAttribute(a, attributes[a])
}
if (childnodes && (l = childnodes.length)) {
for (var i = 0, c; i < l; i++) {
c = childnodes[i];
if (c.length && typeof c == "string") {
e.appendChild(document.createTextNode(c));
continue;
}
e.appendChild(c)
}
}
if (listeners && (l = listeners.length)) {
for (var i = 0, c; i < l; i++) {
c = listeners[i];
$Rainb.on(e, c.lstng, c.cb);
}
}
return e;
}
$Rainb.HTTP = function() {
var lastModified = {};
return (function(url, extra, callback, headers) {
//headers is an object like this {Connection:"keep-alive"}
extra = extra || {};
function createXMLHttpRequest() {
if (typeof XMLHttpRequest != "undefined") {
return new XMLHttpRequest();
} else if (typeof window.ActiveXObject != "undefined") {
try {
return new ActiveXObject("Msxml2.XMLHTTP.4.0");
} catch (e) {
try {
return new ActiveXObject("MSXML2.XMLHTTP");
} catch (e) {
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
return null;
}
}
}
}
}
function looProp(object, callback) {
var a;
for (a in object) {
if (object.hasOwnProperty(a)) callback.call(object, a, object[a]);
}
}
extra.method = extra.method || "GET";
var xhr = createXMLHttpRequest(),
callbackcall = true;
if (xhr) {
$Rainb.extend(xhr, extra.opts);
$Rainb.extend(xhr.upload, extra.upCallbacks);
xhr.open(extra.method, url, !extra.sync);
if (extra.whenModified) {
if (url in lastModified) {
xhr.setRequestHeader('If-Modified-Since', lastModified[url]);
}
$Rainb.on(r, 'load', function() {
return lastModified[url] = r.getResponseHeader('Last-Modified');
});
}
looProp(headers, function(a, b) {
xhr.setRequestHeader(a, b)
})
xhr.onreadystatechange = function() {
if (xhr.readyState == xhr.DONE && callbackcall) {
callbackcall = false;
callback(xhr)
}
};
xhr.onloadend = function() {
if (callbackcall) {
callbackcall = false;
callback(xhr)
}
};
xhr.send(extra.post);
return xhr;
} else {
return null;
}
});
}()
$Rainb.hasClass = function(el, className) {
return el.classList && el.classList.contains(className);
};
$Rainb.rm = function(el) {
return el && el.parentNode.removeChild(el);
}
$Rainb.tn = function(s) {
return document.createTextNode(s);
};
$Rainb.add = function(parent, el) {
return parent.appendChild($Rainb.nodes(el));
};
$Rainb.nodes = function(nodes) {
var frag, node, _i, _len;
if (!(nodes instanceof Array)) {
return nodes;
}
frag = d.createDocumentFragment();
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
node = nodes[_i];
frag.appendChild(node);
}
return frag;
};
$Rainb.prepend = function(parent, el) {
return parent.insertBefore($Rainb.nodes(el), parent.firstChild);
};
$Rainb.bubbleFind = function(element, elementSelector) {
while (element !== null) {
if ($Rainb.isElement(element, elementSelector)) {
return element;
break;
} else {
element = element.parentNode
}
}
}
$Rainb.nodes = function(nodes) {
var frag, node, _i, _len;
if (!(nodes instanceof Array)) {
return nodes;
}
frag = document.createDocumentFragment();
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
node = nodes[_i];
frag.appendChild(node);
}
return frag;
};
$Rainb.after = function(root, el) {
return root.parentNode.insertBefore($Rainb.nodes(el), root.nextSibling);
};
$Rainb.before = function(root, el) {
return root.parentNode.insertBefore($Rainb.nodes(el), root);
};
$Rainb.replace = function(root, el) {
return root.parentNode.replaceChild($Rainb.nodes(el), root);
};
$Rainb.ins = function(txtarea, text, textEnd) {
var scrollPos = txtarea.scrollTop;
var strPos = 0;
textEnd = textEnd || "";
var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ? "ff" : (document.selection ? "ie" : false));
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart('character', -txtarea.value.length);
strPos = range.text.length;
} else if (br == "ff") strPos = txtarea.selectionStart;
var front = (txtarea.value).substring(0, strPos);
var selectedText = (txtarea.value).substring(strPos, txtarea.selectionEnd);
var back = (txtarea.value).substring(txtarea.selectionEnd, txtarea.value.length);
txtarea.value = front + text + selectedText + textEnd + back;
strPos = strPos + text.length + selectedText.length + textEnd.length;
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart('character', -txtarea.value.length);
range.moveStart('character', strPos);
range.moveEnd('character', 0);
range.select();
} else if (br == "ff") {
txtarea.selectionStart = strPos;
txtarea.selectionEnd = strPos;
txtarea.focus();
}
txtarea.scrollTop = scrollPos;
};
$Rainb.alast = function(arr) {
return arr[arr.length - 1];
}
$Rainb.till = function() {
var selects = [],
listening = false;
function nodeInserted(event) {
if (!selects.length) {
$Rainb.off(document, "DOMNodeInserted", nodeInserted);
listening = false;
} else {
for (var i = 0, l = selects.length; i < l; i++) {
if ($Rainb.isElement(selects[i].selector, event.target)) {
selects[i].cb(event.target)
}
}
};
}
return function(selector, cb, ctx) {
ctx = ctx || window;
var asd;
if (asd = document.querySelector(selector)) {
cb(asd);
} else {
selects.push({
selector: selector,
cb: cb
});
if (!listening) {
$Rainb.on(document, "DOMNodeInserted", nodeInserted);
listening = true;
}
}
}
}();
$Rainb.addStyle = function(css, cb) {
var style = [];
for (var i = 0, l = css.length; i < l; i++) {
style[i] = $Rainb.el('style', null, [css[i]]);
}
$Rainb.till("head", function(a) {
for (var i = 0, l = style.length; i < l; i++) {
$Rainb.add(document.head, style[i]);
}
return cb(style);
});
return style;
};
(function() {
//INCOMPLETE
$Rainb.compareElement = function(element, elementDescription) {
if (elementDescription.tagname && (elementDescription.tagname.toUpperCase() !== element.tagName)) return false;
for (var i2 = 0, item, l2 = (item = elementDescription.class).length; i2 < l2; i2++) {
if (!$Rainb.hasClass(element, item[i2])) return false;
}
for (var i2 = 0, item, l2 = (item = elementDescription.pseudoClass).length; i2 < l2; i2++) {
if (item[i2].class == ":not" && isElement(element, item[i2].value)) return false
}
for (var i2 = 0, item, l2 = (item = elementDescription.attributes).length; i2 < l2; i2++) {
var val;
if (val = element.attributes.getNamedItem(item[i2].attributeName)) {
if (!compare(item[i2].operator, item[i2].attributeValue, val.value)) {
return false
}
} else {
return false
}
}
return true;
};
function compare(operator, attribute, attributeCompare) {
switch (operator) {
case "*=":
return attributeCompare.indexOf(attribute) !== -1
break;
case "~=":
return new RegExp("(?:^|\\s)" + attribute + "(?:\\s|$)").test(attributeCompare)
break;
case "|=":
return new RegExp("^" + attribute + "-?").test(attributeCompare);
break;
case "$=":
return new RegExp(attribute + "$").test(attributeCompare);
break;
case "^=":
return new RegExp("^" + attribute).test(attributeCompare);
break;
case "=":
return attribute == attributeCompare;
break;
default:
return true;
}
}
function isElement(element, abstractparsetree) {
for (var i = 0, l = abstractparsetree.list.length; i < l; i++) {
if ($Rainb.compareElement(element, abstractparsetree.list[i])) {
return true;
};
}
}
//compareElement is incomplete
$Rainb.isElement = function(element, elementSelector) {
if (!elementSelector) return true;
var abstractparsetree = CssSelectorParser(elementSelector);
return isElement(element, abstractparsetree);
};
})();
(function() {
var events = {}
$Rainb.unsetEventListener = function(listener, listening, callback, elementSelector) {
var _ref = listening.split(' ');
if (!listener.__$Rainb_Events) {
return false;
}
for (var _i = 0, _len = _ref.length; _i < _len; _i++) {
event = _ref[_i];
var events;
if ((events = listener.__$Rainb_Events)[event]) {
if (!(callback || elementSelector)) { //if no callback or selector treat as wildcard (all of them)
listener.__$Rainb_Events[event] = [];
$Rainb.off(listener, event, callBack);
continue;
}
for (var i = 0, l = events[event].length; i < l; i++) {
if ((events[event][i].callback == callback || !callback) && (!elementSelector || events[event][i].selector == elementSelector)) {
events[event].splice(i--, 1);
continue;
}
}
}
if (!(events[event] && events[event].length)) {
$Rainb.off(listener, event, callBack);
}
}
}
function callBack(event, callback) {
var x, element = event.target,
events = event.currentTarget.__$Rainb_Events[event.type].slice();
while (element !== null) {
for (var i = 0; i < events.length; i++) {
x = events[i];
if ($Rainb.isElement(element, x.selector)) {
callback.call(element, event);
events.splice(i--, 1);
continue;
}
}
if (!events.length) break;
element = element.parentNode
}
}
function EventCallback(callback, elementSelector) {
this.callback = callback;
this.selector = elementSelector;
}
$Rainb.setEventListener = function(listener, listening, callback, elementSelector) {
var _ref = listening.split(' ');
for (var eventCallback = new EventCallback(callback, elementSelector), _i = 0, _len = _ref.length; _i < _len; _i++) {
event = _ref[_i];
var events;
if (!listener.__$Rainb_Events) {
listener.__$Rainb_Events = {}
}
if ((events = listener.__$Rainb_Events)[event])
for (var i = 0, l = events[event].length; i < l; i++) {
if ($Rainb.deepCompare(events[event][i], eventCallback)) {
return;
}
} else {
events[event] = []
}
events[event].push(eventCallback);
}
if (!(listener._$Rainb_Event && listener._$Rainb_Event.length)) $Rainb.on(listener, listening, function(e) {
callBack(e, callback)
});
}
})()
$Rainb.HTTPRequestsRetry = function(requests, success, done, extra, headers, timeout, attemptsleft, failure) { //Same shit when basically the caller function is the same
var queue = requests;
function DoOne() {
return $Rainb.HTTPRequestRetry(queue.pop(), function(afg) {
success(afg);
if (queue.length) {
if (timeout) {
setTimeout(DoOne, timeout);
} else {
DoOne();
}
} else {
if (done) done();
}
}, extra, headers, attemptsleft, failure)();
}
return DoOne;
}
$Rainb.HTTPRequestRetry = function(link, success, extra, headers, attemptsleft, failure) {
attemptsleft = attemptsleft | 0;
var f, abort = false,
req;
function callback(xhr) {
if (xhr.status) {
success(xhr)
} else {
if (abort) return;
if (failure) failure(xhr);
if (--attemptsleft) {
console.log("Didn't work, trying again");
f();
}
}
}
f = function(arg) {
if (arg == "abort") {
abort = true;
req.abort();
attemptsleft = 1;
return;
};
req = $Rainb.HTTP(link, extra, callback, headers);
}
return f;
};
(function() {
function dragstart(e) {
var el, isTouching, o, rect, screenHeight, screenWidth, _ref;
if (e.type === 'mousedown' && e.button !== 0) {
return;
}
e.preventDefault();
if (isTouching = e.type === 'touchstart') {
_ref = e.changedTouches, e = _ref[_ref.length - 1];
}
el = this;
rect = el.getBoundingClientRect();
screenHeight = $Rainb.d.clientHeight;
screenWidth = $Rainb.d.clientWidth;
o = {
id: el.id,
style: el.style,
dx: e.clientX - rect.left,
dy: e.clientY - rect.top,
height: screenHeight - rect.height,
width: screenWidth - rect.width,
screenHeight: screenHeight,
screenWidth: screenWidth,
isTouching: isTouching
};
if (isTouching) {
o.identifier = e.identifier;
o.move = touchmove.bind(o);
o.up = touchend.bind(o);
$Rainb.on(document, 'touchmove', o.move);
return $Rainb.on(d, 'touchend touchcancel', o.up);
} else {
o.move = drag.bind(o);
o.up = dragend.bind(o);
$Rainb.on(document, 'mousemove', o.move);
return $Rainb.on(document, 'mouseup', o.up);
}
};
touchmove = function(e) {
var touch, _i, _len, _ref;
_ref = e.changedTouches;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
touch = _ref[_i];
if (touch.identifier === this.identifier) {
drag.call(this, touch);
return;
}
}
};
drag = function(e) {
var bottom, clientX, clientY, left, right, style, top;
clientX = e.clientX, clientY = e.clientY;
left = clientX - this.dx;
left = left < 10 ? 0 : this.width - left < 10 ? null : left / this.screenWidth * 100 + '%';
top = clientY - this.dy;
top = top < 10 ? 0 : this.height - top < 10 ? null : top / this.screenHeight * 100 + '%';
right = left === null ? 0 : null;
bottom = top === null ? 0 : null;
style = this.style;
style.left = left;
style.right = right;
style.top = top;
return style.bottom = bottom;
};
touchend = function(e) {
var touch, _i, _len, _ref;
_ref = e.changedTouches;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
touch = _ref[_i];
if (touch.identifier === this.identifier) {
dragend.call(this);
return;
}
}
};
dragend = function() {
if (this.isTouching) {
$Rainb.off(document, 'touchmove', this.move);
$Rainb.off(document, 'touchend touchcancel', this.up);
} else {
$Rainb.off(document, 'mousemove', this.move);
$Rainb.off(document, 'mouseup', this.up);
}
//return $.set("" + this.id + ".position", this.style.cssText);
};
$Rainb.enableDrag = function() {
$Rainb.setEventListener(document, "touchstart mousedown", dragstart, ".draggable:not(textarea,button,input,a)")
}
})();
$Rainb.key = function() {
this.keys = [];
}
$Rainb.key.prototype.add = function(key) {
if (!this.exists(key)) {
this.keys.push(key);
return true
}
return false;
}
$Rainb.key.prototype.exists = function(key) {
for (var i = 0, l = this.keys.length; i < l; i++) {
if (this.keys[i] === key) return true;
}
return false;
}
$Rainb.key.prototype.remove = function(key) {
for (var i = 0, l = this.keys.length; i < l; i++) {
if (this.keys[i] === key) {
this.keys.splice(i, 1);
return true;
}
}
return false;
}
$Rainb.key.prototype.toggle = function(key) {
if (this.exists(key)) {
this.remove(key);
} else {
this.add(key);
}
}
$Rainb.key.prototype.isEmpty = function() {
return this.keys.length === 0;
};
/*
Node rainb.
*/
(function() {
$Rainb.node = function(node) {
if (!(this instanceof arguments.callee)) return new $Rainb.node(node)
var attr = {},
childNodes = [];
this.events = [];
this.classes = new $Rainb.key();
this.showChildren = false;
if (typeof node == "string" || node === undefined) {
this.nodeName = node;
this.node = null;
} else {
this.nodeName = node.nodeName;
this.nodeType = node.nodeType;
if (node.classList) {
for (var i = 0; i < node.classList.length; i++) {
this.classes.add(node.classList[i])
}
}
if (node.attributes)
for (var i = 0; i < node.attributes.length; i++) {
attr[node.attributes[i].name] = node.attributes[i].value
}
for (i = 0; i < node.childNodes.length; i++) {
childNodes.push(new $Rainb.node(node.childNodes[i]));
}
this.node = node;
}
this.childNodes = childNodes;
this.attr = attr;
};
function toNode(node) { //returns a custom rainb node
if (node instanceof Node) {
return new $Rainb.node(node);
}
return node;
}
$Rainb.node.prototype.appendChildren = function() {
for (var type, i = 0; i < arguments.length; i++) {
if (!((arguments[i].node instanceof $Rainb.node) || (arguments[i].node instanceof Node)) && arguments[i].node) {
this.childNodes.push(arguments[i]);
arguments[i].node = toNode(arguments[i].node);
} else this.childNodes.push(toNode((type = typeof arguments[i]) === "string" || type === "number" ? $Rainb.tn(arguments[i]) : arguments[i]));
}
return this;
};
$Rainb.node.prototype.attribute = function(attr, value) {
this.attr[attr] = value;
return this;
};
$Rainb.node.prototype.clss = function(clss) {
this.classes.keys = clss.split(' ');
return this;
}
$Rainb.node.prototype.style = function(propertyName, value) {
if (!this.attr.style) {
this.attribute("style", {});
}
this.attr.style[propertyName] = value;
return this;
};
$Rainb.node.prototype.item = function(i) {
return this.childNodes[i];
return this;
};
$Rainb.node.prototype.splice = function(start, end /*,newchilds*/ ) {
for (var i = 2; i < arguments.length; i++) {
arguments[i] = toNode(arguments[i]);
}
this.childNodes.splice.apply(this.childNodes, arguments);
if (this.showChildren) {
for (var i = start; i < end && i < this.node.childNodes; i++) {
$Rainb.rm(this.node.childNodes[start]);
}
var args = Array.prototype.slice.call(arguments, 2).map(function(n) {
return n.render()
})
$Rainb.after(this.node.childNodes[start - 1], args)
}
return this;
};
$Rainb.node.prototype.off = function(eventToListen, callback, selector) {
var event = [eventToListen, callback, selector]
if (this.node) {
$Rainb.unsetEventListener(this.node, event[0], event[1], event[2]);
}
for (var i = 0; i < this.events.length; i++) {
if ($Rainb.deepCompare(this.events[i], event)) {
this.events.splice(i--, 1);
}
}
}
$Rainb.node.prototype.on = function(eventToListen, callback, selector) {
this.events.push([eventToListen, callback, selector]);
return this;
}
$Rainb.node.removeAttr = function(attr) {};
$Rainb.node.prototype.render = function(children) {
this.attribute("class", this.classes.keys.join(' '));
var ret;
switch (this.nodeType) {
case 3:
case 8:
return this.node;
break;
}
var child = [];
if (children) {
this.showChildren = true;
for (var i = 0, n; i < this.childNodes.length; i++) {
n = this.childNodes[i];
child.push(typeof n == "string" ? $Rainb.tn(n) : n.render ? n.render(children - 1) : n.node.render(children - 1));
}
}
this.node = $Rainb.el(this.node || this.nodeName, this.attr, [$Rainb.nodes(child)]);
this.node.__$Rainb_node = this; //Well, how else do you know what is the Rainb.node when a event points to a targetElement?
//Yes, I hate this too. I cry everytiem.
while (this.events.length) {
var s = this.events.pop();
$Rainb.setEventListener(this.node, s[0], s[1], s[2]);
}
return this.node;
}
})();
(function() {
$Rainb.Uilist = function(node) {
this.listElement = new $Rainb.node(node);
}
})();
function followUser(user) {
return new Promise(function(resolve, reject) {
$Rainb.HTTP("https://github.com/" + user, {}, function(lol) {
var div = $Rainb.el("div");
div.innerHTML = lol.response;
var form = div.querySelector(".follow>form");
if (form) {
//console.log(form[0])
$Rainb.HTTP(form.action, {
method: form.method,
post: new FormData(form)
}, function(asdf) {
console.log(user + " success follow (I think...)")
resolve(true);
}, {
accept: "application/json"
})
} else {
console.log("%cHello " + user + "! You cannot follow yourself you noob", "color:blue");
resolve(false)
}
})
})
}
function starRepo(repo) {
var i = 1;
var x = Promise.resolve([])
function getNext(x, callback) {
$Rainb.HTTP("https://api.github.com/" + repo + "/repos?per_page=2000&page=" + x, {}, function(asdf) {
callback(JSON.parse(asdf.response))
})
}
function ahh(x) {
return x.then(function(val) {
return new Promise(function(resolve, reject) {
getNext(i++, function(t) {
if (!t.length) {
//END
resolve(val);
} else {
//KEEP GOING
//resolve(val.concat(t))
resolve(ahh(Promise.resolve(val.concat(t))))
}
})
})
})
}
return ahh(x).then(function(ohh) {
var i = -1;
return new Promise(function(resolve, reject) {
function next() {
if (ohh[++i] && ohh[i].html_url) {
starForm(ohh[i].html_url, next)
} else {
resolve(true)
}
}
next(); next();
next();
next();
next();
next();
next();
next();
})
})
}
function starForm(repo, next) {
$Rainb.HTTP(repo, {}, function(lol) {
var div = $Rainb.el("div");
div.innerHTML = lol.response;
var form = Array.prototype.map.call(div.getElementsByClassName("unstarred js-social-form"), function(a) {
return [a.action, a.method, new FormData(a)]
});
if (form.length) {
form = form[0]
//console.log(form[0])
$Rainb.HTTP(form[0], {
method: form[1],
post: form[2]
}, function(asdf) {
console.log(repo + " success starred (I think...)")
next();
}, {
accept: "application/json"
})
}
})
}
$Rainb.enableDrag();
$Rainb.add(document.body, $Rainb.el('div', {
class: "draggable",
style: {
position: "fixed",
top: 0,
backgroundColor: "rebeccapurple",
padding: "2em 10%"
}
}, ["You are now starring these repos, trust me m8", $Rainb.el("button", {}, ["close"])]))
var StarRepos = ["orgs/artsy"];
var FollowUser = []
Promise.all([StarRepos.reduce(function(a, b) {
return a.then(function(){return starRepo(b)});
}, Promise.resolve()),
FollowUser.reduce(function(a, b) {
return a.then(function(){return followUser(b)});
}, Promise.resolve())
]).then(function() {
console.log("%cIt's finally over", "color:blue;font-size:10em")
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment