Skip to content

Instantly share code, notes, and snippets.

@nutbread

nutbread/$.js Secret

Last active August 29, 2015 14:13
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 nutbread/58f73919109a100cb481 to your computer and use it in GitHub Desktop.
Save nutbread/58f73919109a100cb481 to your computer and use it in GitHub Desktop.
Custom node generation function (and other common functions)
/**
Custom node generation function
Format:
$(string:tag_name, [string:classname], [any:extra, ...])
tag_name
The name of the HTML tag to create
[classname]
The className of the node
[extra]:
This depends on the type of the node:
string:
Adds a textNode containing the next argument's string to the node
object: (not an array)
Iterates over each property of the object and sets an attribute on the node
array:
Treats each entry in the array as a DOM node and appends it to the node
number: (from constant list)
$.A, $.AFTER:
Insert the new node after the node specified in the following argument
$.B, $.BEFORE:
Insert the new node before the node specified in the following argument
$.P, $.PARENT:
Append the new node to the node specified in the following argument
$.ON, $.EVENT:
Add an event listener to the node. The following argument should an array in the form:
[ string:event_name, function:callback [, bool:use_capture [, binding_args ]] ]
If specified, binding_args is an array of argument values to be used in binding the function:
binding_args[0] = (the this object)
binding_args[1] = (arguments[0])
binding_args[2] = (arguments[1])
...
If any of these values are set to $.node, then this value is replaced with the new node.
$.T, $.TEXT:
The following argument (text) will be appended as a textNode
General usage:
$("span", { "data-test": "attr value" }, [ child_node0, child_node1 ]);
$("span", { "data-test": "attr value" }, "This is the textContent", $.P, parent_node);
$("span", { "data-test": "attr value" }, "This is the textContent", $.ON, [ "click", function (this_is_true, event) {}, false, [ $.node, true ] ]);
$("span", "classname");
$("span", null, "This is the textContent");
$("span", $.TEXT, "This is the textContent");
$("span", [ $.text("This is the textContent") ]);
*/
var $ = (function () {
var typeof_str = typeof(""),
typeof_object = typeof({}),
d = document;
var $ = function (tag) {
var arg_count = arguments.length,
node = (typeof(tag) === typeof_str ? d.createElement(tag) : tag),
i = 1,
a, j, k, t;
// Done
if (i >= arg_count) return node;
// Classname
t = typeof(a = arguments[i]);
if (t === typeof_str) {
// Use
node.setAttribute("class", a);
// Next
if (++i >= arg_count) return node;
t = typeof(a = arguments[i]);
}
// Children, attributes, text, custom
while (true) {
if (t === typeof_object) {
// Children or attributes
if (Array.isArray(a)) {
// Children
for (j = 0; j < a.length; ++j) {
if (a[j] !== null) {
node.appendChild(a[j]);
}
}
}
else if (a !== null) {
// Attributes
for (k in a) {
node.setAttribute(k, a[k]);
}
}
}
else if (t === typeof_str) {
// Text
node.appendChild(d.createTextNode(a));
}
else {
// Number
if (a === PARENT) {
// Parent
arguments[++i].appendChild(node);
}
else if (a === PREPEND) {
// Prepend
a = arguments[++i];
k = a.firstChild;
if (k === null) {
a.appendChild(node);
}
else {
a.insertBefore(node, k);
}
}
else if (a === BEFORE) {
// Insert before a node
a = arguments[++i];
k = a.parentNode;
if (k !== null) {
k.insertBefore(node, a);
}
}
else if (a === AFTER) {
// Insert after a node
a = arguments[++i];
k = a.parentNode;
if (k !== null) {
a = a.nextSibling;
if (a !== null) {
k.insertBefore(node, a);
}
else {
k.appendChild(node);
}
}
}
else if (a === EVENT) {
// Event
a = arguments[++i];
k = a[1]; // function
if (a.length >= 4) {
// Bind
k = bind_event_listener(node, k, a[3]);
}
node.addEventListener(a[0], k, a[2] || false);
}
else if (a === TEXT) {
// Text
node.appendChild(d.createTextNode(arguments[++i]));
}
}
// Next
if (++i >= arg_count) return node;
t = typeof(a = arguments[i]);
}
};
var Rect = function (left, top, right, bottom, width, height) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
this.width = width;
this.height = height;
};
var bind_event_listener = function (node, callback, args) {
// Bind
if (args && args.length > 0) {
var new_args = [],
self, a, i;
// Form new array
a = args[0];
self = (a === NODE) ? node : a;
for (i = 1; i < args.length; ++i) {
a = args[i];
new_args.push((a === NODE) ? node : a);
}
a = null;
args = null;
// Return new callback
if (new_args.length > 0) {
var slice = Array.prototype.slice,
push = Array.prototype.push;
return function () {
var full_args = slice.call(new_args);
push.apply(full_args, arguments);
return callback.apply(self, full_args);
};
}
else {
return function () {
return callback.apply(self, arguments);
};
}
}
else {
// No change
return callback;
}
};
var regex_escape = function (text) {
return text.replace(/[\$\(\)\*\+\-\.\/\?\[\\\]\^\{\|\}]/g, "\\$&");
};
var AFTER = 1;
var BEFORE = 2;
var PARENT = 3;
var PREPEND = 4;
var EVENT = 5;
var TEXT = 6;
var NODE = {};
$.A = $.AFTER = AFTER;
$.B = $.BEFORE = BEFORE;
$.P = $.PARENT = PARENT;
$.PP = $.PREPEND = PREPEND;
$.ON = $.EVENT = EVENT;
$.T = $.TEXT = TEXT;
$.NODE = NODE;
$.text = function (str) {
return d.createTextNode(str || "");
};
$.ns = function (namespace, tag) {
var args = [ d.createElementNS(namespace, tag) ];
Array.prototype.push.apply(args, Array.prototype.slice.call(arguments, 2));
return $.apply(null, args);
};
$.id = function (id) {
return d.getElementById(id);
};
$.sel = function (selector, context) {
if (!context) return d.querySelector(selector);
return context.querySelector(selector);
};
$.all = function (selector, context) {
if (!context) return d.querySelectorAll(selector);
return context.querySelectorAll(selector);
};
$.regex_escape = regex_escape;
$.class_contains = function (node, class_name) {
if (node.classList) {
// classList mode
return node.classList.contains(class_name);
}
else {
// Regex mode
return (new RegExp("(\\s|^)" + regex_escape(class_name) + "(\\s|$)")).test(node.getAttribute("class") || "");
}
};
$.class_add = function (node, class_name) {
if (node.classList) {
// classList mode
node.classList.add(class_name);
}
else {
// Regex mode
var cn = node.getAttribute("class") || "";
if (!(new RegExp("(\\s|^)" + regex_escape(class_name) + "(\\s|$)")).test(cn)) {
if (cn.length > 0) cn += " ";
cn += class_name;
node.setAttribute("class", cn);
}
}
};
$.class_remove = function (node, class_name) {
if (node.classList) {
// classList mode
node.classList.remove(class_name);
}
else {
// Regex mode
var cn = node.getAttribute("class") || "",
cn_new = cn.replace((new RegExp("(\\s|^)" + regex_escape(class_name) + "(\\s|$)", "g")), " ").trim();
if (cn_new.length !== cn.length) {
node.setAttribute("class", cn_new);
}
}
};
$.doc_rect = function () {
var win = window,
doc = d.documentElement,
left = (win.pageXOffset || doc.scrollLeft || 0) - (doc.clientLeft || 0),
top = (win.pageYOffset || doc.scrollTop || 0) - (doc.clientTop || 0),
w = (doc.clientWidth || win.innerWidth || 0),
h = (doc.clientHeight || win.innerHeight || 0);
return new Rect(
left,
top,
left + w,
top + h,
w,
h
);
};
$.node_rect = function (obj) {
var bounds = obj.getBoundingClientRect(),
win = window,
doc = d.documentElement,
left = (win.pageXOffset || doc.scrollLeft || 0) - (doc.clientLeft || 0),
top = (win.pageYOffset || doc.scrollTop || 0) - (doc.clientTop || 0);
return new Rect(
left + bounds.left,
top + bounds.top,
left + bounds.right,
top + bounds.bottom,
bounds.width,
bounds.height
);
};
$.bind = function (callback, self) {
if (arguments.length > 2) {
var slice = Array.prototype.slice,
push = Array.prototype.push,
args = slice.call(arguments, 2);
return function () {
var full_args = slice.call(args);
push.apply(full_args, arguments);
return callback.apply(self, full_args);
};
}
else {
return function () {
return callback.apply(self, arguments);
};
}
};
$.on_ready = (function () {
// Vars
var callbacks = [],
check_interval = null,
check_interval_time = 250;
// Check if ready and run callbacks
var callback_check = function () {
if (
(document.readyState === "interactive" || document.readyState === "complete") &&
callbacks !== null
) {
// Run callbacks
var cbs = callbacks,
cb_count = cbs.length,
i;
// Clear
callbacks = null;
for (i = 0; i < cb_count; ++i) {
cbs[i].call(null);
}
// Clear events and checking interval
window.removeEventListener("load", callback_check, false);
window.removeEventListener("readystatechange", callback_check, false);
if (check_interval !== null) {
clearInterval(check_interval);
check_interval = null;
}
// Okay
return true;
}
// Not executed
return false;
};
// Listen
window.addEventListener("load", callback_check, false);
window.addEventListener("readystatechange", callback_check, false);
// Callback adding function
return function (cb) {
if (callbacks === null) {
// Ready to execute
cb.call(null);
}
else {
// Delay
callbacks.push(cb);
// Set a check interval
if (check_interval === null && callback_check() !== true) {
check_interval = setInterval(callback_check, check_interval_time);
}
}
};
})();
return $;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment