Skip to content

Instantly share code, notes, and snippets.

@alunny
Created April 21, 2011 22:47
Show Gist options
  • Save alunny/935642 to your computer and use it in GitHub Desktop.
Save alunny/935642 to your computer and use it in GitHub Desktop.
xui demo
This is some text right here
<!doctype html>
<html>
<head>
<title>XUI Demo</title>
<style>
.go {
background: green;
}
.stop {
background: red;
}
#color-block {
color: white;
width: 200px;
height: 250px;
}
#fx-test {
width: 100px;
height: 100px;
background: #000000;
left: 15px;
position: absolute;
}
</style>
</head>
<body>
<p class="summer" data-secret="it's actually spring">Here comes the summer! </p>
<p>
<a href="#" id="goodLink">This is the link with the id attribute "goodLink"</a>
</p>
<div id="color-block" class="go">
COLOR BLOCK
</div>
<div id="placeholder">
</div>
<div id="fx-test">FX</div>
</body>
<script src="xui-2.0.0.js"></script>
</html>
<h2>Drinks you can make with Bourbon</h2>
<ul>
<li>Manhattan</li>
<li>Old Fashioned</li>
<li>Brown Derby</li>
</ul>
(function () {
/**
Basics
======
xui is available as the global `x$` function. It accepts a CSS selector string or DOM element, or an array of a mix of these, as parameters,
and returns the xui object. For example:
var header = x$('#header'); // returns the element with id attribute equal to "header".
For more information on CSS selectors, see the [W3C specification](http://www.w3.org/TR/CSS2/selector.html). Please note that there are
different levels of CSS selector support (Levels 1, 2 and 3) and different browsers support each to different degrees. Be warned!
The functions described in the docs are available on the xui object and often manipulate or retrieve information about the elements in the
xui collection.
*/
var undefined,
xui,
window = this,
string = new String('string'), // prevents Goog compiler from removing primative and subsidising out allowing us to compress further
document = window.document, // obvious really
simpleExpr = /^#?([\w-]+)$/, // for situations of dire need. Symbian and the such
idExpr = /^#/,
tagExpr = /<([\w:]+)/, // so you can create elements on the fly a la x$('<img href="/foo" /><strong>yay</strong>')
slice = function (e) { return [].slice.call(e, 0); };
try { var a = slice(document.documentElement.childNodes)[0].nodeType; }
catch(e){ slice = function (e) { var ret=[]; for (var i=0; e[i]; i++) ret.push(e[i]); return ret; }; }
window.x$ = window.xui = xui = function(q, context) {
return new xui.fn.find(q, context);
};
// patch in forEach to help get the size down a little and avoid over the top currying on event.js and dom.js (shortcuts)
if (! [].forEach) {
Array.prototype.forEach = function(fn) {
var len = this.length || 0,
i = 0,
that = arguments[1]; // wait, what's that!? awwww rem. here I thought I knew ya!
// @rem - that that is a hat tip to your thats :)
if (typeof fn == 'function') {
for (; i < len; i++) {
fn.call(that, this[i], i, this);
}
}
};
}
/*
* Array Remove - By John Resig (MIT Licensed)
*/
function removex(array, from, to) {
var rest = array.slice((to || from) + 1 || array.length);
array.length = from < 0 ? array.length + from: from;
return array.push.apply(array, rest);
}
xui.fn = xui.prototype = {
/**
extend
------
Extends XUI's prototype with the members of another object.
### syntax ###
xui.extend( object );
### arguments ###
- object `Object` contains the members that will be added to XUI's prototype.
### example ###
Given:
var sugar = {
first: function() { return this[0]; },
last: function() { return this[this.length - 1]; }
}
We can extend xui's prototype with members of `sugar` by using `extend`:
xui.extend(sugar);
Now we can use `first` and `last` in all instances of xui:
var f = x$('.button').first();
var l = x$('.notice').last();
*/
extend: function(o) {
for (var i in o) {
xui.fn[i] = o[i];
}
},
/**
find
----
Find the elements that match a query string. `x$` is an alias for `find`.
### syntax ###
x$( window ).find( selector, context );
### arguments ###
- selector `String` is a CSS selector that will query for elements.
- context `HTMLElement` is the parent element to search from _(optional)_.
### example ###
Given the following markup:
<ul id="first">
<li id="one">1</li>
<li id="two">2</li>
</ul>
<ul id="second">
<li id="three">3</li>
<li id="four">4</li>
</ul>
We can select list items using `find`:
x$('li'); // returns all four list item elements.
x$('#second').find('li'); // returns list items "three" and "four"
*/
find: function(q, context) {
var ele = [], tempNode;
if (!q) {
return this;
} else if (context == undefined && this.length) {
ele = this.each(function(el) {
ele = ele.concat(slice(xui(q, el)));
}).reduce(ele);
} else {
context = context || document;
// fast matching for pure ID selectors and simple element based selectors
if (typeof q == string) {
if (simpleExpr.test(q) && context.getElementById && context.getElementsByTagName) {
ele = idExpr.test(q) ? [context.getElementById(q.substr(1))] : context.getElementsByTagName(q);
// nuke failed selectors
if (ele[0] == null) {
ele = [];
}
// match for full html tags to create elements on the go
} else if (tagExpr.test(q)) {
tempNode = document.createElement('i');
tempNode.innerHTML = q;
slice(tempNode.childNodes).forEach(function (el) {
ele.push(el);
});
} else {
// one selector, check if Sizzle is available and use it instead of querySelectorAll.
if (window.Sizzle !== undefined) {
ele = Sizzle(q, context);
} else {
ele = context.querySelectorAll(q);
}
}
// blanket slice
ele = slice(ele);
} else if (q instanceof Array) {
ele = q;
} else if (q.toString() == '[object NodeList]' || q.toString() == '[object HTMLCollection]') {
ele = slice(q);
} else if (q.nodeName || q === window) { // only allows nodes in
// an element was passed in
ele = [q];
}
}
// disabling the append style, could be a plugin (found in more/base):
// xui.fn.add = function (q) { this.elements = this.elements.concat(this.reduce(xui(q).elements)); return this; }
return this.set(ele);
},
/**
set
---
Sets the objects in the xui collection.
### syntax ###
x$( window ).set( array );
*/
set: function(elements) {
var ret = xui();
ret.cache = slice(this.length ? this : []);
ret.length = 0;
[].push.apply(ret, elements);
return ret;
},
/**
reduce
------
Reduces the set of elements in the xui object to a unique set.
### syntax ###
x$( window ).reduce( elements, index );
### arguments ###
- elements `Array` is an array of elements to reduce _(optional)_.
- index `Number` is the last array index to include in the reduction. If unspecified, it will reduce all elements _(optional)_.
*/
reduce: function(elements, b) {
var a = [],
elements = elements || slice(this);
elements.forEach(function(el) {
// question the support of [].indexOf in older mobiles (RS will bring up 5800 to test)
if (a.indexOf(el, 0, b) < 0)
a.push(el);
});
return a;
},
/**
has
---
Returns the elements that match a given CSS selector.
### syntax ###
x$( window ).has( selector );
### arguments ###
- selector `String` is a CSS selector that will match all children of the xui collection.
### example ###
Given:
<div>
<div class="round">Item one</div>
<div class="round">Item two</div>
</div>
We can use `has` to select specific objects:
var divs = x$('div'); // got all three divs.
var rounded = divs.has('.round'); // got two divs with the class .round
*/
has: function(q) {
var list = xui(q);
return this.filter(function () {
var that = this;
var found = null;
list.each(function (el) {
found = (found || el == that);
});
return found;
});
},
/**
filter
------
Extend XUI with custom filters. This is an interal utility function, but is also useful to developers.
### syntax ###
x$( window ).filter( fn );
### arguments ###
- fn `Function` is called for each element in the XUI collection.
// `index` is the array index of the current element
function( index ) {
// `this` is the element iterated on
// return true to add element to new XUI collection
}
### example ###
Filter all the `<input />` elements that are disabled:
x$('input').filter(function(index) {
return this.checked;
});
*/
filter: function(fn) {
var elements = [];
return this.each(function(el, i) {
if (fn.call(el, i)) elements.push(el);
}).set(elements);
},
/**
not
---
The opposite of `has`. It modifies the elements and returns all of the elements that do __not__ match a CSS query.
### syntax ###
x$( window ).not( selector );
### arguments ###
- selector `String` a CSS selector for the elements that should __not__ be matched.
### example ###
Given:
<div>
<div class="round">Item one</div>
<div class="round">Item two</div>
<div class="square">Item three</div>
<div class="shadow">Item four</div>
</div>
We can use `not` to select objects:
var divs = x$('div'); // got all four divs.
var notRound = divs.not('.round'); // got two divs with classes .square and .shadow
*/
not: function(q) {
var list = slice(this),
omittedNodes = xui(q);
if (!omittedNodes.length) {
return this;
}
return this.filter(function(i) {
var found;
omittedNodes.each(function(el) {
return found = list[i] != el;
});
return found;
});
},
/**
each
----
Element iterator for an XUI collection.
### syntax ###
x$( window ).each( fn )
### arguments ###
- fn `Function` callback that is called once for each element.
// `element` is the current element
// `index` is the element index in the XUI collection
// `xui` is the XUI collection.
function( element, index, xui ) {
// `this` is the current element
}
### example ###
x$('div').each(function(element, index, xui) {
alert("Here's the " + index + " element: " + element);
});
*/
each: function(fn) {
// we could compress this by using [].forEach.call - but we wouldn't be able to support
// fn return false breaking the loop, a feature I quite like.
for (var i = 0, len = this.length; i < len; ++i) {
if (fn.call(this[i], this[i], i, this) === false)
break;
}
return this;
}
};
xui.fn.find.prototype = xui.fn;
xui.extend = xui.fn.extend;
/**
DOM
===
Set of methods for manipulating the Document Object Model (DOM).
*/
xui.extend({
/**
html
----
Manipulates HTML in the DOM. Also just returns the inner HTML of elements in the collection if called with no arguments.
### syntax ###
x$( window ).html( location, html );
or this method will accept just a HTML fragment with a default behavior of inner:
x$( window ).html( html );
or you can use shorthand syntax by using the location name argument as the function name:
x$( window ).outer( html );
x$( window ).before( html );
or you can just retrieve the inner HTML of elements in the collection with:
x$( document.body ).html();
### arguments ###
- location `String` can be one of: _inner_, _outer_, _top_, _bottom_, _remove_, _before_ or _after_.
- html `String` is a string of HTML markup or a `HTMLElement`.
### example ###
x$('#foo').html('inner', '<strong>rock and roll</strong>');
x$('#foo').html('outer', '<p>lock and load</p>');
x$('#foo').html('top', '<div>bangers and mash</div>');
x$('#foo').html('bottom','<em>mean and clean</em>');
x$('#foo').html('remove');
x$('#foo').html('before', '<p>some warmup html</p>');
x$('#foo').html('after', '<p>more html!</p>');
or
x$('#foo').html('<p>sweet as honey</p>');
x$('#foo').outer('<p>free as a bird</p>');
x$('#foo').top('<b>top of the pops</b>');
x$('#foo').bottom('<span>bottom of the barrel</span>');
x$('#foo').before('<pre>first in line</pre>');
x$('#foo').after('<marquee>better late than never</marquee>');
*/
html: function(location, html) {
clean(this);
if (arguments.length == 0) {
var i = [];
this.each(function(el) {
i.push(el.innerHTML);
});
return i;
}
if (arguments.length == 1 && arguments[0] != 'remove') {
html = location;
location = 'inner';
}
if (location != 'remove' && html && html.each !== undefined) {
if (location == 'inner') {
var d = document.createElement('p');
html.each(function(el) {
d.appendChild(el);
});
this.each(function(el) {
el.innerHTML = d.innerHTML;
});
} else {
var that = this;
html.each(function(el){
that.html(location, el);
});
}
return this;
}
return this.each(function(el) {
var parent,
list,
len,
i = 0;
if (location == "inner") { // .html
if (typeof html == string || typeof html == "number") {
el.innerHTML = html;
list = el.getElementsByTagName('SCRIPT');
len = list.length;
for (; i < len; i++) {
eval(list[i].text);
}
} else {
el.innerHTML = '';
el.appendChild(html);
}
} else if (location == "outer") { // .replaceWith
el.parentNode.replaceChild(wrapHelper(html, el), el);
} else if (location == "top") { // .prependTo
el.insertBefore(wrapHelper(html, el), el.firstChild);
} else if (location == "bottom") { // .appendTo
el.insertBefore(wrapHelper(html, el), null);
} else if (location == "remove") {
el.parentNode.removeChild(el);
} else if (location == "before") { // .insertBefore
el.parentNode.insertBefore(wrapHelper(html, el.parentNode), el);
} else if (location == "after") { // .insertAfter
el.parentNode.insertBefore(wrapHelper(html, el.parentNode), el.nextSibling);
}
});
},
/**
attr
----
Gets or sets attributes on elements. If getting, returns an array of attributes matching the xui element collection's indices.
### syntax ###
x$( window ).attr( attribute, value );
### arguments ###
- attribute `String` is the name of HTML attribute to get or set.
- value `Varies` is the value to set the attribute to. Do not use to get the value of attribute _(optional)_.
### example ###
To get an attribute value, simply don't provide the optional second parameter:
x$('.someClass').attr('class');
To set an attribute, use both parameters:
x$('.someClass').attr('disabled', 'disabled');
*/
attr: function(attribute, val) {
if (arguments.length == 2) {
return this.each(function(el) {
(el.setAttribute?(attribute=='checked'&&(val==''||val==false||typeof val=="undefined"))?el.removeAttribute(attribute):el.setAttribute(attribute, val):0);
});
} else {
var attrs = [];
this.each(function(el) {
if (el.getAttribute) {
attrs.push(el.getAttribute(attribute));
}
});
return attrs;
}
}
});
"inner outer top bottom remove before after".split(' ').forEach(function (method) {
xui.fn[method] = function(where) { return function (html) { return this.html(where, html); }; }(method);
});
// private method for finding a dom element
function getTag(el) {
return (el.firstChild === null) ? {'UL':'LI','DL':'DT','TR':'TD'}[el.tagName] || el.tagName : el.firstChild.tagName;
}
function wrapHelper(html, el) {
return (typeof html == string) ? wrap(html, getTag(el)) : html;
}
// private method
// Wraps the HTML in a TAG, Tag is optional
// If the html starts with a Tag, it will wrap the context in that tag.
function wrap(xhtml, tag) {
var attributes = {},
re = /^<([A-Z][A-Z0-9]*)([^>]*)>([\s\S]*)<\/\1>/i,
element,
x,
a,
i = 0,
attr,
node,
attrList,
result;
if (re.test(xhtml)) {
result = re.exec(xhtml);
tag = result[1];
// if the node has any attributes, convert to object
if (result[2] !== "") {
attrList = result[2].split(/([A-Z\-]*\s*=\s*['|"][A-Z0-9:;#\s]*['|"])/i);
for (; i < attrList.length; i++) {
attr = attrList[i].replace(/^\s*|\s*$/g, "");
if (attr !== "" && attr !== " ") {
node = attr.split('=');
attributes[node[0]] = node[1].replace(/(["']?)/g, '');
}
}
}
xhtml = result[3];
}
element = document.createElement(tag);
for (x in attributes) {
a = document.createAttribute(x);
a.nodeValue = attributes[x];
element.setAttributeNode(a);
}
element.innerHTML = xhtml;
return element;
}
/*
* Removes all erronious nodes from the DOM.
*
*/
function clean(collection) {
var ns = /\S/;
collection.each(function(el) {
var d = el,
n = d.firstChild,
ni = -1,
nx;
while (n) {
nx = n.nextSibling;
if (n.nodeType == 3 && !ns.test(n.nodeValue)) {
d.removeChild(n);
} else {
n.nodeIndex = ++ni; // FIXME not sure what this is for, and causes IE to bomb (the setter) - @rem
}
n = nx;
}
});
}
/**
Event
=====
A good old fashioned events with new skool handling. Shortcuts exist for:
- click
- load
- touchstart
- touchmove
- touchend
- touchcancel
- gesturestart
- gesturechange
- gestureend
- orientationchange
*/
xui.events = {}; var cache = {};
xui.extend({
/**
on
--
Registers a callback function to a DOM event on the element collection.
### syntax ###
x$( 'button' ).on( type, fn );
or
x$( 'button' ).click( fn );
### arguments ###
- type `String` is the event to subscribe (e.g. _load_, _click_, _touchstart_, etc).
- fn `Function` is a callback function to execute when the event is fired.
### example ###
x$( 'button' ).on( 'click', function(e) {
alert('hey that tickles!');
});
or
x$(window).load(function(e) {
x$('.save').touchstart( function(evt) { alert('tee hee!'); }).css(background:'grey');
});
*/
on: function(type, fn, details) {
return this.each(function (el) {
if (xui.events[type]) {
var id = _getEventID(el),
responders = _getRespondersForEvent(id, type);
details = details || {};
details.handler = function (event, data) {
xui.fn.fire.call(xui(this), type, data);
};
// trigger the initialiser - only happens the first time around
if (!responders.length) {
xui.events[type].call(el, details);
}
}
el.addEventListener(type, _createResponder(el, type, fn), false);
});
},
/**
un
--
Unregisters a specific callback, or if no specific callback is passed in,
unregisters all event callbacks of a specific type.
### syntax ###
Unregister the given function, for the given type, on all button elements:
x$( 'button' ).un( type, fn );
Unregisters all callbacks of the given type, on all button elements:
x$( 'button' ).un( type );
### arguments ###
- type `String` is the event to unsubscribe (e.g. _load_, _click_, _touchstart_, etc).
- fn `Function` is the callback function to unsubscribe _(optional)_.
### example ###
// First, create a click event that display an alert message
x$('button').on('click', function() {
alert('hi!');
});
// Now unsubscribe all functions that response to click on all button elements
x$('button').un('click');
or
var greeting = function() { alert('yo!'); };
x$('button').on('click', greeting);
x$('button').on('click', function() {
alert('hi!');
});
// When any button is clicked, the 'hi!' message will fire, but not the 'yo!' message.
x$('button').un('click', greeting);
*/
un: function(type, fn) {
return this.each(function (el) {
var id = _getEventID(el), responders = _getRespondersForEvent(id, type), i = responders.length;
while (i--) {
if (fn === undefined || fn.guid === responders[i].guid) {
el.removeEventListener(type, responders[i], false);
removex(cache[id][type], i, 1);
}
}
if (cache[id][type].length === 0) delete cache[id][type];
for (var t in cache[id]) {
return;
}
delete cache[id];
});
},
/**
fire
----
Triggers a specific event on the xui collection.
### syntax ###
x$( selector ).fire( type, data );
### arguments ###
- type `String` is the event to fire (e.g. _load_, _click_, _touchstart_, etc).
- data `Object` is a JSON object to use as the event's `data` property.
### example ###
x$('button#reset').fire('click', { died:true });
x$('.target').fire('touchstart');
*/
fire: function (type, data) {
return this.each(function (el) {
if (el == document && !el.dispatchEvent)
el = document.documentElement;
var event = document.createEvent('HTMLEvents');
event.initEvent(type, true, true);
event.data = data || {};
event.eventName = type;
el.dispatchEvent(event);
});
}
});
"click load submit touchstart touchmove touchend touchcancel gesturestart gesturechange gestureend orientationchange".split(' ').forEach(function (event) {
xui.fn[event] = function(action) { return function (fn) { return fn ? this.on(action, fn) : this.fire(action); }; }(event);
});
// patched orientation support - Andriod 1 doesn't have native onorientationchange events
xui(window).on('load', function() {
if (!('onorientationchange' in document.body)) {
(function (w, h) {
xui(window).on('resize', function () {
var portraitSwitch = (window.innerWidth < w && window.innerHeight > h) && (window.innerWidth < window.innerHeight),
landscapeSwitch = (window.innerWidth > w && window.innerHeight < h) && (window.innerWidth > window.innerHeight);
if (portraitSwitch || landscapeSwitch) {
window.orientation = portraitSwitch ? 0 : 90; // what about -90? Some support is better than none
xui('body').fire('orientationchange'); // will this bubble up?
w = window.innerWidth;
h = window.innerHeight;
}
});
})(window.innerWidth, window.innerHeight);
}
});
// this doesn't belong on the prototype, it belongs as a property on the xui object
xui.touch = (function () {
try{
return !!(document.createEvent("TouchEvent").initTouchEvent)
} catch(e) {
return false;
};
})();
// lifted from Prototype's (big P) event model
function _getEventID(element) {
if (element._xuiEventID) return element._xuiEventID;
return element._xuiEventID = ++_getEventID.id;
}
_getEventID.id = 1;
function _getRespondersForEvent(id, eventName) {
var c = cache[id] = cache[id] || {};
return c[eventName] = c[eventName] || [];
}
function _createResponder(element, eventName, handler) {
var id = _getEventID(element), r = _getRespondersForEvent(id, eventName);
var responder = function(event) {
if (handler.call(element, event) === false) {
event.preventDefault();
event.stopPropagation();
}
};
responder.guid = handler.guid = handler.guid || ++_getEventID.id;
responder.handler = handler;
r.push(responder);
return responder;
}
/**
Fx
==
Animations, transforms, and transitions for getting the most out of hardware accelerated CSS.
*/
xui.extend({
/**
Tween
-----
Transforms a CSS property's value.
### syntax ###
x$( selector ).tween( properties, callback );
### arguments ###
- properties `Object` or `Array` of CSS properties to tween.
- `Object` is a JSON object that defines the CSS properties.
- `Array` is a `Object` set that is tweened sequentially.
- callback `Function` to be called when the animation is complete. _(optional)_.
### properties ###
A property can be any CSS style, referenced by the JavaScript notation.
A property can also be an option from [emile.js](https://github.com/madrobby/emile):
- duration `Number` of the animation in milliseconds.
- after `Function` is called after the animation is finished.
- easing `Function` allows for the overriding of the built-in animation function.
// Receives one argument `pos` that indicates position
// in time between animation's start and end.
function(pos) {
// return the new position
return (-Math.cos(pos * Math.PI) / 2) + 0.5;
}
### example ###
// one JSON object
x$('#box').tween({ left:'100px', backgroundColor:'blue' });
x$('#box').tween({ left:'100px', backgroundColor:'blue' }, function() {
alert('done!');
});
// array of two JSON objects
x$('#box').tween([{left:'100px', backgroundColor:'green', duration:.2 }, { right:'100px' }]);
*/
tween: function( props, callback ) {
// creates an options obj for emile
var emileOpts = function(o) {
var options = {};
"duration after easing".split(' ').forEach( function(p) {
if (props[p]) {
options[p] = props[p];
delete props[p];
}
});
return options;
}
// serialize the properties into a string for emile
var serialize = function(props) {
var serialisedProps = [], key;
if (typeof props != string) {
for (key in props) {
serialisedProps.push(key + ':' + props[key]);
}
serialisedProps = serialisedProps.join(';');
} else {
serialisedProps = props;
}
return serialisedProps;
};
// queued animations
if (props instanceof Array) {
// animate each passing the next to the last callback to enqueue
props.forEach(function(a){
});
}
// this branch means we're dealing with a single tween
var opts = emileOpts(props);
var prop = serialize(props);
return this.each(function(e){
emile(e, prop, opts, callback);
});
}
});
/**
Style
=====
Everything related to appearance. Usually, this is CSS.
*/
function hasClass(el, className) {
return getClassRegEx(className).test(el.className);
}
// Via jQuery - used to avoid el.className = ' foo';
// Used for trimming whitespace
var rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
function trim(text) {
return (text || "").replace( rtrim, "" );
}
xui.extend({
/**
setStyle
--------
Sets the value of a single CSS property.
### syntax ###
x$( selector ).setStyle( property, value );
### arguments ###
- property `String` is the name of the property to modify.
- value `String` is the new value of the property.
### example ###
x$('.flash').setStyle('color', '#000');
x$('.button').setStyle('backgroundColor', '#EFEFEF');
*/
setStyle: function(prop, val) {
prop = prop.replace(/\-[a-z]/g,function(m) { return m[1].toUpperCase(); });
return this.each(function(el) {
el.style[prop] = val;
});
},
/**
getStyle
--------
Returns the value of a single CSS property. Can also invoke a callback to perform more specific processing tasks related to the property value.
Please note that the return type is always an Array of strings. Each string corresponds to the CSS property value for the element with the same index in the xui collection.
### syntax ###
x$( selector ).getStyle( property, callback );
### arguments ###
- property `String` is the name of the CSS property to get.
- callback `Function` is called on each element in the collection and passed the property _(optional)_.
### example ###
<ul id="nav">
<li class="trunk" style="font-size:12px;background-color:blue;">hi</li>
<li style="font-size:14px;">there</li>
</ul>
x$('ul#nav li.trunk').getStyle('font-size'); // returns ['12px']
x$('ul#nav li.trunk').getStyle('fontSize'); // returns ['12px']
x$('ul#nav li').getStyle('font-size'); // returns ['12px', '14px']
x$('ul#nav li.trunk').getStyle('backgroundColor', function(prop) {
alert(prop); // alerts 'blue'
});
*/
getStyle: function(prop, callback) {
// shortcut getComputedStyle function
var s = function(el, p) {
// this *can* be written to be smaller - see below, but in fact it doesn't compress in gzip as well, the commented
// out version actually *adds* 2 bytes.
// return document.defaultView.getComputedStyle(el, "").getPropertyValue(p.replace(/([A-Z])/g, "-$1").toLowerCase());
return document.defaultView.getComputedStyle(el, "").getPropertyValue(p.replace(/[A-Z]/g, function(m) { return '-'+m.toLowerCase(); }));
}
if (callback === undefined) {
var styles = [];
this.each(function(el) {styles.push(s(el, prop))});
return styles;
} else this.each(function(el) { callback(s(el, prop)); });
},
/**
addClass
--------
Adds a class to all of the elements in the collection.
### syntax ###
$( selector ).addClass( className );
### arguments ###
- className `String` is the name of the CSS class to add.
### example ###
$('.foo').addClass('awesome');
*/
addClass: function(className) {
return this.each(function(el) {
if (hasClass(el, className) === false) {
el.className = trim(el.className + ' ' + className);
}
});
},
/**
hasClass
--------
Checks if the class is on _all_ elements in the xui collection.
### syntax ###
$( selector ).hasClass( className, fn );
### arguments ###
- className `String` is the name of the CSS class to find.
- fn `Function` is a called for each element found and passed the element _(optional)_.
// `element` is the HTMLElement that has the class
function(element) {
console.log(element);
}
### example ###
<div id="foo" class="foo awesome"></div>
<div class="foo awesome"></div>
<div class="foo"></div>
// returns true
x$('#foo').hasClass('awesome');
// returns false (not all elements with class 'foo' have class 'awesome'),
// but the callback gets invoked with the elements that did match the 'awesome' class
x$('.foo').hasClass('awesome', function(element) {
console.log('Hey, I found: ' + element + ' with class "awesome"');
});
// returns true (all DIV elements have the 'foo' class)
x$('div').hasClass('foo');
*/
hasClass: function(className, callback) {
var self = this;
return this.length && (function() {
var hasIt = true;
self.each(function(el) {
if (hasClass(el, className)) {
if (callback) callback(el);
} else hasIt = false;
});
return hasIt;
})();
},
/**
removeClass
-----------
Removes the specified class from all elements in the collection. If no class is specified, removes all classes from the collection.
### syntax ###
x$( selector ).removeClass( className );
### arguments ###
- className `String` is the name of the CSS class to remove. If not specified, then removes all classes from the matched elements. _(optional)_
### example ###
x$('.foo').removeClass('awesome');
*/
removeClass: function(className) {
if (className === undefined) this.each(function(el) { el.className = ''; });
else this.each(function(el) { el.className = trim(el.className.replace(getClassRegEx(className), '$1')); });
return this;
},
/**
toggleClass
-----------
Removes the specified class if it exists on the elements in the xui collection, otherwise adds it.
### syntax ###
x$( selector ).toggleClass( className );
### arguments ###
- className `String` is the name of the CSS class to toggle.
### example ###
<div class="foo awesome"></div>
x$('.foo').toggleClass('awesome'); // div above loses its awesome class.
*/
toggleClass: function(className) {
return this.each(function(el) {
if (hasClass(el, className)) el.className = trim(el.className.replace(getClassRegEx(className), '$1'));
else el.className = trim(el.className + ' ' + className);
});
},
/**
css
---
Set multiple CSS properties at once.
### syntax ###
x$( selector ).css( properties );
### arguments ###
- properties `Object` is a JSON object that defines the property name/value pairs to set.
### example ###
x$('.foo').css({ backgroundColor:'blue', color:'white', border:'2px solid red' });
*/
css: function(o) {
for (var prop in o) {
this.setStyle(prop, o[prop]);
}
return this;
}
});
// RS: now that I've moved these out, they'll compress better, however, do these variables
// need to be instance based - if it's regarding the DOM, I'm guessing it's better they're
// global within the scope of xui
// -- private methods -- //
var reClassNameCache = {},
getClassRegEx = function(className) {
var re = reClassNameCache[className];
if (!re) {
// Preserve any leading whitespace in the match, to be used when removing a class
re = new RegExp('(^|\\s+)' + className + '(?:\\s+|$)');
reClassNameCache[className] = re;
}
return re;
};
/**
XHR
===
Everything related to remote network connections.
*/
xui.extend({
/**
xhr
---
The classic `XMLHttpRequest` sometimes also known as the Greek God: _Ajax_. Not to be confused with _AJAX_ the cleaning agent.
### detail ###
This method has a few new tricks.
It is always invoked on an element collection and uses the behaviour of `html`.
If there is no callback, then the `responseText` will be inserted into the elements in the collection.
### syntax ###
x$( selector ).xhr( location, url, options )
or accept a url with a default behavior of inner:
x$( selector ).xhr( url, options );
or accept a url with a callback:
x$( selector ).xhr( url, fn );
### arguments ###
- location `String` is the location to insert the `responseText`. See `html` for values.
- url `String` is where to send the request.
- fn `Function` is called on status 200 (i.e. success callback).
- options `Object` is a JSON object with one or more of the following:
- method `String` can be _get_, _put_, _delete_, _post_. Default is _get_.
- async `Boolean` enables an asynchronous request. Defaults to _false_.
- data `String` is a url encoded string of parameters to send.
- callback `Function` is called on status 200 (i.e. success callback).
- headers `Object` is a JSON object with key:value pairs that get set in the request's header set.
### response ###
- The response is available to the callback function as `this`.
- The response is not passed into the callback.
- `this.reponseText` will have the resulting data from the file.
### example ###
x$('#status').xhr('inner', '/status.html');
x$('#status').xhr('outer', '/status.html');
x$('#status').xhr('top', '/status.html');
x$('#status').xhr('bottom','/status.html');
x$('#status').xhr('before','/status.html');
x$('#status').xhr('after', '/status.html');
or
// same as using 'inner'
x$('#status').xhr('/status.html');
// define a callback, enable async execution and add a request header
x$('#left-panel').xhr('/panel', {
async: true,
callback: function() {
alert("The response is " + this.responseText);
},
headers:{
'Mobile':'true'
}
});
// define a callback with the shorthand syntax
x$('#left-panel').xhr('/panel', function() {
alert("The response is " + this.responseText);
});
*/
xhr:function(location, url, options) {
// this is to keep support for the old syntax (easy as that)
if (!/^(inner|outer|top|bottom|before|after)$/.test(location)) {
options = url;
url = location;
location = 'inner';
}
var o = options ? options : {};
if (typeof options == "function") {
// FIXME kill the console logging
// console.log('we been passed a func ' + options);
// console.log(this);
o = {};
o.callback = options;
};
var that = this,
req = new XMLHttpRequest(),
method = o.method || 'get',
async = (typeof o.async != 'undefined'?o.async:true),
params = o.data || null,
key;
req.queryString = params;
req.open(method, url, async);
for (key in o.headers) {
if (o.headers.hasOwnProperty(key)) {
req.setRequestHeader(key, o.headers[key]);
}
}
req.handleResp = (o.callback != null) ? o.callback : function() { that.html(location, req.responseText); };
req.handleError = (o.error && typeof o.error == 'function') ? o.error : function () {};
function hdl(){
if(req.readyState==4) {
delete(that.xmlHttpRequest);
if(req.status===0 || req.status==200) req.handleResp();
if((/^[45]/).test(req.status)) req.handleError();
}
}
if(async) {
req.onreadystatechange = hdl;
this.xmlHttpRequest = req;
}
req.send(params);
if(!async) hdl();
return this;
}
});
// emile.js (c) 2009 Thomas Fuchs
// Licensed under the terms of the MIT license.
(function(emile, container){
var parseEl = document.createElement('div'),
props = ('backgroundColor borderBottomColor borderBottomWidth borderLeftColor borderLeftWidth '+
'borderRightColor borderRightWidth borderSpacing borderTopColor borderTopWidth bottom color fontSize '+
'fontWeight height left letterSpacing lineHeight marginBottom marginLeft marginRight marginTop maxHeight '+
'maxWidth minHeight minWidth opacity outlineColor outlineOffset outlineWidth paddingBottom paddingLeft '+
'paddingRight paddingTop right textIndent top width wordSpacing zIndex').split(' ');
function interpolate(source,target,pos){ return (source+(target-source)*pos).toFixed(3); }
function s(str, p, c){ return str.substr(p,c||1); }
function color(source,target,pos){
var i = 2, j, c, tmp, v = [], r = [];
while(j=3,c=arguments[i-1],i--)
if(s(c,0)=='r') { c = c.match(/\d+/g); while(j--) v.push(~~c[j]); } else {
if(c.length==4) c='#'+s(c,1)+s(c,1)+s(c,2)+s(c,2)+s(c,3)+s(c,3);
while(j--) v.push(parseInt(s(c,1+j*2,2), 16)); }
while(j--) { tmp = ~~(v[j+3]+(v[j]-v[j+3])*pos); r.push(tmp<0?0:tmp>255?255:tmp); }
return 'rgb('+r.join(',')+')';
}
function parse(prop){
var p = parseFloat(prop), q = prop.replace(/^[\-\d\.]+/,'');
return isNaN(p) ? { v: q, f: color, u: ''} : { v: p, f: interpolate, u: q };
}
function normalize(style){
var css, rules = {}, i = props.length, v;
parseEl.innerHTML = '<div style="'+style+'"></div>';
css = parseEl.childNodes[0].style;
while(i--) if(v = css[props[i]]) rules[props[i]] = parse(v);
return rules;
}
container[emile] = function(el, style, opts, after){
el = typeof el == 'string' ? document.getElementById(el) : el;
opts = opts || {};
var target = normalize(style), comp = el.currentStyle ? el.currentStyle : getComputedStyle(el, null),
prop, current = {}, start = +new Date, dur = opts.duration||200, finish = start+dur, interval,
easing = opts.easing || function(pos){ return (-Math.cos(pos*Math.PI)/2) + 0.5; };
for(prop in target) current[prop] = parse(comp[prop]);
interval = setInterval(function(){
var time = +new Date, pos = time>finish ? 1 : (time-start)/dur;
for(prop in target)
el.style[prop] = target[prop].f(current[prop].v,target[prop].v,easing(pos)) + target[prop].u;
if(time>finish) { clearInterval(interval); opts.after && opts.after(); after && setTimeout(after,1); }
},10);
}
})('emile', this);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment