Picoh is my take on the JavaScript frontend micro framework, providing event handling, DOM querying/manipulation, XMLHTTP requests and a handful of utility methods.
The focus is on a lean code footprint - minified and gzipped everything weighs in around 2.3KB.
All methods are namespaced under window.$ / window.$$ with no modification of any object prototypes.
- Picoh takes advantage of core methods available in more modern browsers (such as
document.querySelectorAll()) avoiding heavy polyfills to keep the code footprint small. - Designed for and tested against the usual suspects of Google Chrome, Firefox and OSX Safari. On the Microsoft front IE9 and above is supported.
- The final revision supporting IE8 is tagged here.
- Expects:
- A
!DOCTYPEthat puts your pages into standards mode, with the HTML5 doctype a good selection. More a requirement for full IE compatibility (historically an IE8 gripe), where some core methods used by Picoh won't make themselves available in 'quirks mode'. You can work around such edge cases, but the result is increased code footprint - exactly what I'm trying to avoid here. - Picoh loaded ideally from page
<head>and executed asynchronously (e.g.<script async src="/uri/to/picoh.js"></script>). - Removal of both
marginandpaddingfrom the<body>element to help cross browser consistency with some DOM methods, such as calculating viewport and document sizes.
- A
- General
- Events
- DOM
- $$(query) / $$(element,query)
- $.DOM.ready(handler)
- $.DOM.create(name[,attributeList][,childElementList])
- $.DOM.insertBefore(element,referenceElement)
- $.DOM.insertAfter(element,referenceElement)
- $.DOM.replace(element,oldElement)
- $.DOM.remove(element)
- $.DOM.removeChildAll(element)
- $.DOM.hasClass(element,name)
- $.DOM.addClass(element,name)
- $.DOM.removeClass(element,name)
- $.DOM.setStyle(element,styleList)
- $.DOM.getData(element,key)
- $.DOM.getOffset(element[,toParent])
- $.DOM.getPageScroll()
- $.DOM.getViewportSize()
- $.DOM.getDocumentSize()
- Animation/transition end DOM events
- XMLHTTP
- Miscellaneous
Returns a single DOM element from the id given. Just a wrapper around document.getElementByID() we all know and love.
- Wraps the given
handlerin a debounce routine that will be called only afterdelaymilliseconds have elapsed since last call to the routine was made. - A
clear()method allows for the reset of the current debounce timeout in progress.
Example:
function callMe() {
console.log('Called');
}
var debounceMe = $.debounce(callMe,500);
// log message will only display once, though debounceMe() is called three times
debounceMe();
debounceMe();
debounceMe();
// to clear a current debounce timeout
//debounceMe.clear();- Iterate over the given
collection, callinghandlerfor each item. - Collection can be of type
array,HtmlCollection,NodeListorobject. handlerpassed arguments ofvalueandindexfor typesarray,HtmlCollectionandNodeList.handlerpassed arguments ofvalue,keyname anditerationcount for typeobject.- Returning
falsefromhandlerwill halt the iteration immediately.
Example:
function handlerArray(value,index) {
console.log([value,index].join(' - '));
}
$.each(
[1,2,3,4],
handlerArray
);
function handlerObject(value,key,iteration) {
console.log([value,key,iteration].join(' - '));
if (key == 'key3') {
// exit right away
return false;
}
}
$.each(
{ key1: 'value1',key2: 'value2',key3: 'value3',key4: 'value4' },
handlerObject
);Note: For evaluating HTMLCollection/NodeList types, $.each() uses Duck typing, looking for item and length properties.
- Emulation of Node.js
process.nextTick()method. - Produces a faster and more efficient callback on the next event loop vs.
window.setTimeout(function() {},0). - Implemented using
window.postMessage()under the hood.
- Wrapper for
window.requestAnimationFrame, a more efficient method of processing animation frames versus traditionalwindow.setTimeout()use. - Handles cross browser API prefixing between browser vendors.
- A fallback
window.setTimeout()polyfill is provided for unsupported browsers which will be called approximately once every 16ms to give a close to 60fps fire rate.
- Attach an event
handlerto the givenobjectof the giventype. - Event
typecan be given as a space separated list for attaching multiple events to a singleobject.
Example:
function clickTouchHandler(event) {
console.log('Clicked or touched!');
console.log(this);
console.log(event);
}
$.Event.add($('domelement'),'click touchstart',clickTouchHandler);- Remove an event
handlerfrom the givenobjectof the giventype. - Event
typecan be given as a space separated list for removing multiple events from a singleobject.
- Returns the DOM element that the given
eventwas dispatched on. - Handles the edge case with older versions of Safari where a text node would be incorrectly returned.
Emulates behavior of the mighty handy and IE only (note: Chrome 30+ and Firefox 10+ also natively support) event types of mouseenter and mouseleave.
Example:
<div id="watchme">
<span>Child element</span>
<span>Another child element</span>
</div>function mouseEnterHandler(event) {
if ($.Event.isMouseEnterLeave(event,this)) {
console.log('mouseenter!');
}
}
function mouseLeaveHandler(event) {
if ($.Event.isMouseEnterLeave(event,this)) {
console.log('mouseleave!');
}
}
var watchMeEl = $('watchme');
$.Event.add(watchMeEl,'mouseover',mouseEnterHandler);
$.Event.add(watchMeEl,'mouseout',mouseLeaveHandler);With above example messages will only log messages when mouse pointer enters or leaves <div id="watchme">, ignoring all mouseover/mouseout child events fired from <span> elements.
- Returns the current mouse x/y pixel coordinates from the given
event. - Data will be returned as an object with the structure of
{ x: 123,y: 456 }. - Note: At time of writing IE10 (and possibly other browser vendors going forward) can/will return mouse coordinates with a sub-pixel resolution,
getMousePosition()will round down to whole pixel units.
- A wrapper for
querySelectorAll(), returning DOM elements for the given CSSquery. - In the first form the query will be based from
document(entire page), otherwise in the second form from the givenelement. - In the instance
queryis matching elements containing one or more classes only (e.g..apple.orange.banana) the function will usegetElementsByClassName()in place ofquerySelectorAll()for query speed advantage. - Returned DOM elements will be provided as an array, rather than a
NodeList. - Note:
querySelectorAll()will only support queries based upon the browsers CSS implementation and it's capabilities.
- Will call the given
handlerupon firing of thedocument.DOMContentLoadedevent. - Can be called with multiple
handlerfunctions, each of which be called in turn at the point of DOM load completion. - If called after DOM has already loaded, the given
handlerwill execute immediately via $.nextTick(handler).
- Creates a new DOM element with the given node
name. - Optional attributes given as a key/value object
attributeList.- Keys are to be given as DOM element properties (e.g.
class="myclass"as{ className: 'myclass' }.
- Keys are to be given as DOM element properties (e.g.
- Optional child DOM elements automatically appended given as an array
childElementList.- Child elements of type
stringwill be appended as a newTextNode.
- Child elements of type
Example:
var myCreatedDOMEl = $.DOM.create(
'div',{ className: 'myclass' },
[
$.DOM.create('span',false,['My span text']),
$.DOM.create('a',{ href: '/link/to/item' },['Click me']),
'Another line of text'
]
);
// append the following tag structure to end of the document
/*
<div class="myclass">
<span>My span text</span>
<a href="/link/to/item">Click me</a>
Another line of text
</div>
*/
document.documentElement.appendChild(myCreatedDOMEl);Insert the given element before referenceElement within the current document.
Insert the given element after referenceElement within the current document.
Replace the given oldElement within the current document with element. Returns oldElement.
Remove the given element from the DOM, returning element.
Remove all child DOM elements from the given element, returning an array of removed elements.
Returns true if element has the given CSS class name assigned, otherwise return false.
- Add one or more CSS classes of the given
nametoelement- providing multiple CSS class names space separated. - CSS classes already present on
elementwill be silently ignored.
- Remove one or more CSS classes of the given
namefromelement. - Provide multiple CSS class names for removal space separated.
- Set the given inline CSS
styleList(as a key/value object) toelement. Essentially an easier way to set multiple inline element style attributes at once. - Internally uses a simplistic
element.style.[styleKey] = valueassignment, thereforestyleListkey(s) must be given using camel cased style names (e.g.backgroundColor).
Example:
var myCreatedDOMEl = $.DOM.create('div',false,['Content']);
$.DOM.setStyle(
myCreatedDOMEl,
{
backgroundColor: '#f00',
left: '10px',
position: 'absolute',
top: '40px'
}
);
// myCreatedDOMEl contains
/*
<div style="background-color:#f00;left:10px;position:absolute;top:40px">
Content
</div>
*/- Returns the value of the HTML5 data attribute
keyassociated toelement. - If the given
keydoes not exist returnsnull.
- Returns the left/top pixel offset of the given
elementto either the top left corner of the document, or iftoParentistrue- to the element's parent. - Data will be returned as an object with the structure of
{ left: 123,top: 456 }.
- Returns the x/y pixel scroll offset from the top left corner of the document.
- Data will be returned as an object with the structure of
{ x: 123,y: 456 }.
- Returns the pixel width and height of the browser viewport.
- Data will be returned as an object with the structure of
{ width: 123,height: 456 }.
- Returns the pixel width and height of the document.
- Data will be returned as an object with the structure of
{ width: 123,height: 456 }. - Uses the techniques suggested by Ryan Van Etten.
For the background behind these methods and their use, refer to the cssanimevent library. The following methods have been integrated here.
- Calls the given
handlerupon completion of a CSS3 animation applied toelement. Lifetime of the handler is one animation end event. - For browsers that do not support CSS3 animations,
handlerwill be called instantaneously. - Handler will be passed arguments of
elementand optionaldata.
Cancel a pending handler assigned to element by a previous call to $.DOM.Anim.onAnimationEnd().
Identical in functionality to $.DOM.Anim.onAnimationEnd(), but for CSS3 transitions.
Identical in functionality to $.DOM.Anim.cancelAnimationEnd(), but for CSS3 transitions.
- Execute a
XMLHttpRequest()call to the givenurl, returningtrueif the call was successful made by the browser (e.g. supportsXMLHttpRequest()). - The
methodcan be one ofGETorPOST, withfalse/undefineddefaulting toGET. - Optional
handlerwill be executed at completion of the URL call (success or fail). Handler will be passed a single parameter of the return status/response as an object with the following keys:ok:Settrueif the call returned successfully, otherwisefalse.status:Numeric HTTP status code returned.text:The response body as a string upon success, otherwise empty string.JSON:If response body is JSON data and could be successfully parsed, will contain a JavaScript object of this data, otherwise an empty object.
- Optional
parameterCollectiongiven as key/value pairs with be passed either:- On the query string with HTTP
GET. - Form data of content type
application/x-www-form-urlencodedwith HTTPPOST.
- On the query string with HTTP
Example:
function myHandler(data) {
if (data.ok) {
console.log('HTTP status: ' + data.status);
console.log('Response text: ' + data.text);
console.dir(data.JSON);
} else {
// handle error
}
}
// make a POST request to /xmlhttp/endpoint with parameters "key1=value,key2=value"
$.request(
'/xmlhttp/endpoint',
'POST',
myHandler,
{
key1: 'value',
key2: 'value'
}
);- Placing a class attribute of
<html class="nojs">on a document's<html>element will be automatically replaced with<html class="js">upon load of Picoh. - Used as a CSS styling hook for no/has JavaScript scenarios.
- By default Picoh is attached to the global
windowobject, providing access to it's methods viawindow.$andwindow.$$()respectively, or simply$and$$(). - Alternatively, Picoh can be attached to an isolated object to avoid namespace clashes, by modification of the library's IIFE arguments.
Example:
var attachHere = {};
// start of Picoh
(function(win,doc,picohAttach,undefined) {
// SNIP
})(window,document,attachHere);Picoh will be accessible at attachHere.$/attachHere.$$().