'use strict';
/*@
Ox.$ Generic HTML element, mimics jQuery
value tagname, selector, html element, `window`, or `document`
Passing a tagname ('') creates an element, passing a selector
('tagname', '.classname' or '#id') selects an element.
(value) -> Element object
> Ox.$('
').on({click: function(e) { Ox.test(e.type, 'click'); }}).trigger('click')
true
@*/
Ox.$ = Ox.element = function(value) {
var data = {},
element = !Ox.isString(value) ? value // window, document or element
: value[0] == '<' ? document.createElement(value.slice(1, -1))
: value[0] == '#' ? document.getElementById(value.slice(1))
: value[0] == '.' ? document.getElementsByClassName(value.slice(1))[0]
: document.getElementsByTagName(value)[0],
mousewheelEvents = ['wheel', 'mousewheel'],
originalMousewheelEvents = 'onwheel' in document ? ['wheel']
: ['mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
function normalizeEvents(args) {
var ret = {};
Ox.forEach(Ox.makeObject(args), function(callback, event) {
if (Ox.contains(mousewheelEvents, event)) {
originalMousewheelEvents.forEach(function(event) {
ret[event] = callback;
});
} else {
ret[event] = callback;
}
});
return ret;
}
return element ? {
//@ 0 The DOM element itself
0: element,
/*@
addClass Adds a class name
(className) -> This element
className Class name
@*/
addClass: function(string) {
this[0].className = Ox.unique(((
this[0].className ? this[0].className + ' ' : ''
) + Ox.clean(string)).split(' ')).join(' ');
return this;
},
/*@
append Appends one or more elements to this element
(element[, element[, ...]]) -> This element
element Another element
@*/
append: function() {
var that = this;
Ox.slice(arguments).forEach(function($element) {
that[0].appendChild($element[0]);
});
return this;
},
/*@
appendTo Appends this element object to another element object
(element) -> This element
element Another element
@*/
appendTo: function($element) {
$element[0].appendChild(this[0]);
return this;
},
/*@
attr Gets or sets an attribute
(key) -> Value
(key, value) -> This element
({key0: value0, key1: value1, ...}) -> This element
key Attribute name
value Attribute value
@*/
attr: function() {
var ret, that = this;
if (arguments.length == 1 && Ox.isString(arguments[0])) {
ret = this[0].getAttribute
? this[0].getAttribute(arguments[0])
: null;
// fixme: why exactly is this needed?
if (ret === null) {
ret = void 0;
}
} else {
Ox.forEach(Ox.makeObject(arguments), function(value, key) {
that[0].setAttribute && that[0].setAttribute(key, value);
});
ret = this;
}
return ret;
},
/*@
children Returns the children of this element
() -> <[h]> Children
@*/
children: function() {
return Ox.slice(this[0].childNodes);
},
/*@
css Gets or sets a CSS attribute
(key) -> Value
(key, value) -> This element
({key0: value0, key1: value1, ...}) -> This element
key Attribute name
value Attribute value
@*/
css: function() {
var ret, that = this;
if (arguments.length == 1 && Ox.isString(arguments[0])) {
ret = this[0].style[arguments[0]];
} else {
Ox.forEach(Ox.makeObject(arguments), function(value, key) {
that[0].style[key] = value;
});
ret = this;
}
return ret;
},
/*@
data Gets or sets data
() -> All data
(key) -> Value
(key, value) -> This element
({key0: value0, key1: value1, ...}) -> This element
key Property
value <*> Value
@*/
data: function() {
var ret;
if (arguments.length == 0) {
ret = data;
} else if (arguments.length == 1 && Ox.isString(arguments[0])) {
ret = data[arguments[0]]
} else {
Ox.forEach(Ox.makeObject(arguments), function(value, key) {
data[key] = value;
});
ret = this;
}
return ret;
},
/*@
empty Empties the inner HTML
() -> This element
@*/
empty: function() {
return this.html('');
},
/*@
find Find descendant elements
([selector]) -> <[h]> Elements
selector CSS selector
@*/
find: function(string) {
return Ox.slice(this[0].querySelectorAll(string || '*'));
},
/*@
hasClass Returns true if this element has a given class
(className) -> True if this element has the class
className Class name
@*/
hasClass: function(string) {
return this[0].className.split(' ').indexOf(string) > -1;
},
/*@
height Returns the height of this element
() -> Height in px
@*/
height: function() {
return this[0].offsetHeight;
},
/*@
hide Hides this element
() -> This element
@*/
hide: function() {
return this.css({display: 'none'});
},
/*@
html Gets or sets the inner HTML
() -> The inner HTML
(html) -> This element
html The inner HTML
@*/
html: function(string) {
var ret;
if (arguments.length == 0) {
ret = this[0].innerHTML;
} else {
this[0].innerHTML = string;
ret = this;
}
return ret;
},
/*@
insertAfter Inserts this element after another element
(element) -> This element
element Another element
@*/
insertAfter: function($element) {
$element[0].parentNode.insertBefore(this[0], $element[0].nextSibling);
return this;
},
/*@
insertBefore Inserts this element before another element
(element) -> This element
element Another element
@*/
insertBefore: function($element) {
$element[0].parentNode.insertBefore(this[0], $element[0]);
return this;
},
/*@
next Returns the sibling after this element
() -> Next element
@*/
next: function() {
return this[0].nextSibling;
},
/*@
nextAll Returns all siblings after this element
() -> <[h]> Next elements
@*/
nextAll: function() {
var sibling = this[0], siblings = [];
while (true) {
var sibling = sibling.nextSibling;
if (!sibling) {
break;
}
siblings.push(sibling);
}
return siblings;
},
/*@
off Unbinds a callback from an event
(event) -> This element (unbinds all callbacks)
(event, callback) -> This element
({event0: callback0, event1: callback1, ...}) -> This element
event Event name
callback Callback function
@*/
off: function(event, callback) {
var that = this;
Ox.forEach(normalizeEvents(arguments), function(callback, event) {
if (callback) {
that[0].removeEventListener(event, callback, false);
} else {
that[0]['on' + event] = null;
}
});
return this;
},
/*@
on Binds a callback to an event
(event, callback) -> This element
({event0: callback0, event1: callback1, ...}) -> This element
event Event name
callback Callback function
e Event properties
@*/
on: function() {
var that = this;
Ox.forEach(normalizeEvents(arguments), function(callback, event) {
that[0].addEventListener(event, callback, false);
});
return this;
},
/*@
one Binds a callback to an event and unbinds it on first invocation
(event, callback) -> This element
({event0: callback0, event1: callback1, ...}) -> This element
event Event name
callback Callback function
e Event properties
@*/
one: function(events) {
var args = Ox.slice(arguments), that = this;
Ox.forEach(normalizeEvents(arguments), function(callback, event) {
that.on(event, function fn() {
that.off(event, fn);
return callback.apply(that, args);
});
});
return this;
},
/*@
parent Returns the parent of this element
() -> Parent element
@*/
parent: function() {
return this[0].parentNode;
},
/*@
parents Returns all ancestors of this element
() -> <[h]> Ancestor elements
@*/
parents: function() {
var parent = this[0], parents = [];
while (true) {
var parent = parent.parentNode;
if (!parent) {
break;
}
parents.unshift(parent);
}
return parents;
},
/*@
prepend Prepends one or more elements to this element
(element[, element[, ...]]) -> This element
element Another element
@*/
prepend: function() {
var parent = this[0].parentNode;
Ox.slice(arguments).reverse().forEach(function($element) {
parent.insertBefore($element[0], parent.firstChild);
});
return this;
},
/*@
prependTo Prepends this element object to another element object
(element) -> This element
element Another element
@*/
prependTo: function($element) {
var element = $element[0];
element.insertBefore(this[0], element.firstChild);
return this;
},
/*@
prev Returns the sibling before this element
() -> Next element
@*/
prev: function() {
return this[0].previousSibling;
},
/*@
prevAll Returns all siblings before this element
() -> <[h]> Next elements
@*/
prevAll: function() {
var sibling = this[0], siblings = [];
while (true) {
var sibling = sibling.previousSibling;
if (!sibling) {
break;
}
siblings.unshift(sibling);
}
return siblings;
},
/*@
remove Removes this element from the DOM
() -> This element
@*/
remove: function() {
this[0].parentNode.removeChild(this[0]);
return this;
},
/*@
removeAttr Removes an attribute
(key) -> This element
([key0, key1, ...]) -> This element
key The attribute
@*/
removeAttr: function() {
var that = this;
Ox.makeArray(arguments[0]).forEach(function(key) {
that[0].removeAttribute(key);
});
return this;
},
/*@
removeClass Removes a class name
(className) -> This element
className Class name
@*/
removeClass: function(string) {
var array = Ox.clean(string).split(' ');
this[0].className = this[0].className.split(' ').filter(
function(className) {
return array.indexOf(className) == -1;
}
).join(' ');
return this;
},
/*@
replace Replaces another element with this element
(element) -> This element
element Another element
@*/
replace: function($element) {
var next = $element[0].nextSibling, parent = $element[0].parentNode;
$element.remove();
parent.insertBefore(this[0], next);
return this;
},
/*@
replaceWith Replaces this element with another element
(element) -> This element
element Another element
@*/
replaceWith: function($element) {
var next = this[0].nextSibling, parent = this[0].parentNode;
this.remove();
parent.insertBefore($element[0], next);
return this;
},
/*@
show Shows this element
() -> This element
@*/
show: function() {
return this.css({display: 'block'});
},
/*@
siblings Returns all siblings of this element
() -> <[oh]> Sibling elements
@*/
siblings: function() {
var that = this;
return Ox.filter(this[0].parentNode.childNodes, function(element) {
return element !== that[0];
});
},
/*@
text Gets or sets the text contents
() -> The text contents
(text) -> This element
text The text contents
@*/
text: function(string) {
var ret;
if (arguments.length == 0) {
ret = Ox.isString(this.textContent)
? this.textContent : this.innerText;
} else {
this.empty()[0].appendChild(document.createTextNode(string));
ret = this;
}
return ret;
},
/*@
toggleClass Toggles a class name
(className) -> This element
className Class name
@*/
toggleClass: function(string) {
return this[
this.hasClass(string) ? 'removeClass' : 'addClass'
](string);
},
/*@
trigger Triggers an event
(event) -> This element
@*/
trigger: function(event) {
var e = document.createEvent('MouseEvents');
e.initEvent(event, true, true);
this[0].dispatchEvent(e);
return this;
},
/*@
val Gets or sets the value property of this element
() -> Value
(value) -> This element
value Value
@*/
val: function(value) {
var ret;
if (arguments.length == 0) {
ret = this[0].value;
} else {
this[0].value = value;
ret = this;
}
return ret;
},
/*@
width Returns the width of this element
() -> Width in px
@*/
width: function() {
return this[0].offsetWidth;
}
} : null;
};
/*@
Ox.canvas Generic canvas object
Returns an object with the properties: `canvas`, `context`, `data` and
`imageData`.
(width, height) -> canvas
(image) -> canvas
width Width in px
height Height in px
image Image object
@*/
Ox.canvas = function() {
var c = {}, isImage = arguments.length == 1,
image = isImage ? arguments[0] : {
width: arguments[0], height: arguments[1]
};
c.context = (c.canvas = Ox.$('