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
!DOCTYPE
that 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
margin
andpadding
from 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
handler
in a debounce routine that will be called only afterdelay
milliseconds 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
, callinghandler
for each item. - Collection can be of type
array
,HtmlCollection
,NodeList
orobject
. handler
passed arguments ofvalue
andindex
for typesarray
,HtmlCollection
andNodeList
.handler
passed arguments ofvalue
,key
name anditeration
count for typeobject
.- Returning
false
fromhandler
will 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
handler
to the givenobject
of the giventype
. - Event
type
can 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
handler
from the givenobject
of the giventype
. - Event
type
can be given as a space separated list for removing multiple events from a singleobject
.
- Returns the DOM element that the given
event
was 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
query
is 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
handler
upon firing of thedocument.DOMContentLoaded
event. - Can be called with multiple
handler
functions, each of which be called in turn at the point of DOM load completion. - If called after DOM has already loaded, the given
handler
will 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
string
will 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
name
toelement
- providing multiple CSS class names space separated. - CSS classes already present on
element
will be silently ignored.
- Remove one or more CSS classes of the given
name
fromelement
. - 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] = value
assignment, thereforestyleList
key(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
key
associated toelement
. - If the given
key
does not exist returnsnull
.
- Returns the left/top pixel offset of the given
element
to either the top left corner of the document, or iftoParent
istrue
- 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
handler
upon completion of a CSS3 animation applied toelement
. Lifetime of the handler is one animation end event. - For browsers that do not support CSS3 animations,
handler
will be called instantaneously. - Handler will be passed arguments of
element
and 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
, returningtrue
if the call was successful made by the browser (e.g. supportsXMLHttpRequest()
). - The
method
can be one ofGET
orPOST
, withfalse
/undefined
defaulting toGET
. - Optional
handler
will 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:
Settrue
if 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
parameterCollection
given as key/value pairs with be passed either:- On the query string with HTTP
GET
. - Form data of content type
application/x-www-form-urlencoded
with 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
window
object, 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.$$()
.