libNog:A little library to save you from common JS browser quirks

What is libNog?


libNog is a project that started out as a browser-independent wrapper for the various implementations of the XMLHttpRequest Object, as submitted in 2006 to ByteMyCode. As I grew more fluent in the versions of the Event model and other browser quirks, I found that I was reusing a lot of functions.

libNog is class-based, that is, it's built into a single object, for a couple of reasons. First, JavaScript has an easier time with finding a variable when the global namespace isn't all filled with crap. Second, a single variable with a funny name is less likely to interfere with other variables. Third, I like the fact that JavaScript can handle classes, if in a roundabout way.

The name, Nog, comes from my girlfriend, Amy. I asked her what a good name is for a script built to overcome browser quirks, and she, mishearing what I said, came up with 'Nog'.

'Nog?'

'Isn't that Quark's brother?'

'... OH! No, that's Rom; Nog was his nephew ... and I'd said 'quirk', not 'Quark' - also, Rom is already a computer term. I like Nog. I'll use it.'

The logo is a tracing of Rom's lobes from the image of him on Wikipedia.

No, I am not a geek. I swear. Stop looking at me like that.

If you catch a bug with the lib, want to suggest a feature, or just want to discuss Javascript techniques in general, please feel free to ping me at fordiman [at the) gmail (pop} com

API Documentation
Download libNog 'Quirky' (v1.0 RC2)

Table of Contents

Dynamic loading functions

Nog.getXMLObject ()

Arguments: none

Description:

Locates the best method for creating an XMLHttpRequest object on the client's browser.

Example:

myXMLObject = Nog.getXMLObject();

Returns: an XMLHttpRequest Object

Nog.buildQuery (Object query)

Arguments:

Description:

Concatenates and escapes form data from an Object into a string suitable for use as GET data. Remove the leading '?' to make it suitable for POST data.

Example:

var myPOSTData = Nog.buildQuery({q:'A query',hl:'en'}).substr(1);
myPOSTData is now equal to "q=A+query&hl=en"

Returns: string representing a valid GET querystring

Nog.asyncRequest (String method, String uri, String content, Function callback, Function fallback)

Description:

The base function for all asynchronous request functions. Performs an XMLHttpRequest and provides the object via callback/fallback after the request completes.

Arguments:

Example:

Nog.asyncRequest(
     'POST',
     'getdata.php',
     Nog.buildRequest({data:'all'}).substr(1),
     function (xml) {
          alert(xml.responseText);
     },      function (uri) {
          alert('Failed to get '+uri);
     }
);

Nog.blockRequest (String method, String uri, String content)

Description:

The base function for all blocking request functions. Performs an XMLHttpRequest and provides the object via return value after the request completes.

Arguments:

Example:

var X = Nog.blockRequest('GET','index.html',null);

Nog.GET (String URL, Object query, Function callback, Function fallback)

Description:

Performs a GET request, running your callback/fallback upon completion.

Arguments:

Example:

Nog.GET(
     'getdata.php',
     {data:'all'},
     function (xml) {
          alert(xml.responseText);
     },      function (uri) {
          alert('Failed to get '+uri);
     }
);

Nog.HEAD (String URL, Object query, Function callback, Function fallback)

Description:

Performs a HEAD request, running your callback/fallback upon completion.

Arguments:

Example:

Nog.HEAD(
     'getdata.php',
     {data:'all'},
     function (xml) {
          alert(xml.responseText);
     },      function (uri) {
          alert('Failed to get '+uri);
     }
);

Nog.POST (String URL, Object query, Object content, Function callback, Function fallback)

Description:

Performs a POST request, running your callback/fallback upon completion.

Arguments:

Example:

Nog.POST(
     'getdata.php',
     {},
     {q:'my query',hl:'en'},
     function (xml) {
          alert(xml.responseText);
     },      function (uri) {
          alert('Failed to get '+uri);
     }
);

Nog.scriptInclude (String URL, Object query)

Description:

Retrieves and runs a JavaScript from your server. Is a blocking function.

Arguments:

Notes:

Unlike the XMLHttpRequest functions, this one can actually get a script from off-site or locally, by falling back on the DOM 1 version, then on the innerHTML append trick. It is, however, limited in that you can't gather a script with POST data.

Example:

Nog.scriptInclude('iJustAlert.js',{});
Test

DOM Extensions

Nog (String id)

Description:

Alias for document.getElementById

Arguments:

Returns: the requested element, or null on failure

Examples: Its use is shown on many other examples on this page

Nog.create (String tagName [, String id | Object elementDefinition])
HTMLElement.create (String tagName [, String id | Object elementDefinition])

Description:

Create an HTML Element and do some automation.

Arguments:

Returns: The HTML Element as defined by the various parameters

Notes:

elementDefinition can handle anything you throw at it, including stylesheets and eventHandlers.

stylesheets should be defined as the style parameter, and should be defined as an immediate object using camelCase, e.g., style:{borderLeft:'1px solid black',borderRight:'2px groove'}

event handlers should be defined as they would in an HTML tag, e.g., onmouseover:myMouseOverHandler. They will be attached to the new element using Nog.attach().

The className parameter can be a string of space-separated class names, or an array of class names.

Example:

The following example creates an IMG tag, as the previous brother of an element called 'bar', with an id of 'foo', and a small inline stylesheet and a reaction to the 'click' event.
var bar = Nog('bar');
var foo = Nog.create('img',{
     id:'foo',
     nextSibling:bar,
     src:'img/nog.png',
     style:{
          border:'1px solid red',
          padding:'1em'
     },
     onclick:function (e) {
          alert("Hey! Don't click me there!");
     }
});
I'm just a span. I'm another one.
Test | Reset

Nog.isClass (Object HTMLElement, String className)
HTMLElement.isClass (Object HTMLElement, String className)

Description:

Checks if an HTML Element is a member of a given class.

Arguments:

Returns: true if the element is a member of the given class, otherwise, false.

Example:

if (document.body.firstChild.isClass('myClass'))
     doSomethingUseful(document.body.firstChild);

Nog.addClass (Object HTMLElement, String className)
HTMLElement.addClass (String className)

Description:

Adds class membership to an HTML Element.

Arguments:

Example:

document.body.firstChild.addClass('myClass');

Nog.removeClass (Object HTMLElement, String className)
HTMLElement.removeClass (String className)

Description:

Removes class membership from an HTML Element, if it is a member

Arguments:

Example:

document.body.firstChild.removeClass(document.body.firstChild,'myClass');

Nog.getElements (Object root, Object byParam)
root.getElements (Object byParam)

Description:

Searches the root element for elements according to the requirements in byParam, and returns an Array of them

Arguments:

Returns: an Array containing the HTML Elements that matched byParam

Example:

Get an array of all images pointing to 'img/nog.png', and pop up their rendered locations.
img/nog.png, by the way, happens to be the Nog logo at the top of the page.
var img = document.getElements({tag:'img',src:'img/nog.png'});
var lst = [];
for (var i=0; i<img.length; i++) {
     var pos=img[i].getOffset();
     lst.push('('+pos.left+','+pos.top+')');
}
alert(lst.join('\n'));
Test

Nog.attach (Object HTMLElement, String eventName, Function eventHandler)
HTMLElement.attach (String eventName, Function eventHandler)

Description:

Browser-independently attaches an event handler to an event for a given object

Arguments:

Notes:

Nog/HTMLElement.attach() automatically normalizes the resulting Event object, so you don't have to go doing a bunch of browser testing.

Example:

function attachTest(e) {
     alert('Hey, you clicked it!');
}
Nog('attachTest').attach('click',attachTest);
...
Nog('attachTest').detach('click',attachTest);
Attach | Detach

Nog.detach (Object HTMLElement, String eventName, Function eventHandler)
HTMLElement.deatch (String eventName, Function eventHandler)

Description:

Browser-independently detaches an event handler from an event for a given object

Arguments:

Example:

Nog.detach(window,'load',myWindowLoadHandler);
window.detach('load',myWindowLoadHandler);

Nog.cancelEvent (Event e)
e.cancel()

Description:

Browser-independently cancels all remaining event handling for a given Event

Arguments:

Example:

<a id=nocontext href="javascript:alert('ok, so you can left-click...');">You Shall Not Right-Click!</a>
<script> 
     var aNoContext=Nog.getElements(document,{'id':'nocontext'})[0];
     aNoContext.attach('contextmenu',Nog.cancelEvent);
     aNoContext.attach('click',function (e) {
          if (e.buttons|2==0) return e.cancel(e);
     });
</script>
You Shall Not Right-Click! </gandalf>

Note that the above is not so much intended for 'right-click suppression' as for suppressing the default context menu when you want to use your own. Attempting to cancel the click event for the document, for example, won't work in some versions of Firefox.

Though, if you really felt like being a bastard (ie: preventing the non-savvy, sourcecode-averse, cache-avoiding people from copying images that you have on a public website), you could probably apply this sort of suppression to every img tag in your document, using Nog.getElements(document,{nodeName:'img'});. But, you know, that would be wrong and stuff.

Nog.setOpacity (Object HTMLElement, Number Opacity)
HTMLElement.setOpacity(Number Opacity)

Description:

Sets the opacity of an HTML Element

Arguments:

Notes:

If Opacity is between 0 and 1, it will be justified to a percentage. To avoid this, do bounds checking if you're using 0-100, or just use 0-1.

Example:

Nog("opaDiv").setOpacity(50);
Nog("opaDiv").setOpacity(100);
This is 'opaDiv'

Test it | Reset it

Nog.getOffset (Object HTMLElement) HTMLElement.getOffset()

Description:

Retrieve the Width, Height, Left and Top of an element relative to the document.

Arguments:

Returns: Object with the following properties

Example:

The below will get the adjusted offsetHeight of the DIV for the below getStyle example.
alert(Nog("getStyleDiv").getOffset().height);
Test

Nog.getStyle (Object HTMLElement, String styleProperty)
HTMLElement.getStyle (String styleProperty)

Description:

Retrieve a computed style property for an element

Arguments:

Notes:

Always use the most specific style property (e.g., fontSize and fontFamily, rather than font; more importantly, borders must be individually selected per side and property; ie: borderLeftWidth will get you something, while borderWidth will not). Support for the uber-styles in this function is patchy. I'll work on this, as I know there's a lot of lazy people out there like me.
Always use the camelCaseNamingConvention, not the dashed-naming-convention. I know Mozilla likes dashed for this function, but camelCase is more consistent with how styles work in JavaScript, and I have getStyle automatically convert for Mozilla's version.

Example:

This div will be tested
alert(Nog("getStyleDiv").getStyle("borderLeftWidth"));
Test

Nog.moveInWindow (Object HTMLElement, Number X, Number Y, Number offset)
HTMLElement.moveInWindow (Number X, Number Y, Number offset)

Description:

Move an object to any X/Y relative to the upper left corner of the browser pane, while avoiding placing the object past the horizontal or vertical folds.

Arguments:

Example (from the library):

The below is the mouseMove event handler from the debug-window
Nog.debug.mouseMove = function (e) {
     if (!Nog.debug.enabled) return;
     Nog.debug.window().moveInWindow(e.clientX,e.clientY,12);
}

Unit conversion

Nog.DPI ()

Description:

Determines the browser's current DPI setting

Arguments: none

Returns: The browser's current DPI

Notes:

This function will only return a value once the document has loaded. Attempting to run it beforehand will return 'false'.

Example:

alert(Nog.DPI());
//On most computers, this will pop up 72 (Macs) or 96 (Windows)
Test

Nog.px2in (px)
Nog.in2px (inches)
Nog.pt2px (pt)
Nog.px2pt (px)

Description:

Converts between pixels and points or inches

Arguments: px, inches, or pt: number to convert from

Returns: The converted value, based on the DPI.

Notes:

Like Nog.DPI(), this function will only return a value once the document has loaded. Attempting to run it beforehand will return 'false'.

Example:

//Returns the browser's width in logical inches
//Since computer monitors are differnet sizes and resolutions, this is not necessarily 'real' inches.
alert(Nog.px2in(document.body.offsetWidth));
Test

Nog.style2px (Object HTMLElement, String CSSValue)
HTMLElement.style2px (String CSSValue)

Description:

Converts from a valid CSS measurement to pixels

Arguments:

Returns: The converted value in pixels.

Notes:

Like Nog.DPI(), this function will only return a value once the document has loaded. Attempting to run it beforehand will return 'false'.

Example:

alert(document.body.style2px('3em'));
Test

Debugging

debug (String txt)

Description:

Create or add to a Debugging 'DIV' element

Arguments:

Notes:

The debugging div will float with your cursor above the document.
The debugging div will have the id nogDebugWindow. Please skin it with CSS if you want it to be readable.
Debugging must first be enabled with Nog.debug.enable();. You may later disable it with Nog.debug.disable();
You can also clear the debugging buffer with Nog.debug.clear();

Example:

Nog.debug.enable();
if (1!=1) Nog.debug("My browser is insane!");
else Nog.debug("My browser isn't insane; it's just a little quirky");
Test debugger | Turn off debugging

Type checking

Nog.isObject(Variable)
Nog.isString(Variable)
Nog.isNumber(Variable)
Nog.isBool(Variable)
Nog.isFunction(Variable)
Nog.isDate(Variable)
Nog.isArray(Variable)
Nog.isRegExp(Variable)
Nog.isEvent(Variable)
Nog.isElement(Variable)
Nog.isPrototype(Variable)
Nog.isClass(Variable)
Nog.isExtendedEvent(Variable)
Nog.isExtendedElement(Variable)

Type checking.

Arguments: Variable to check

Returns: Boolean, true if variable is of the appropriate type

Notes:

Nog.isExtendedEvent / Nog.isExtendedEvent refer to Nog-extended DOM objects. This should normally only be used for objects gotten using the old-style DOM functions, document.getElementById and HTMLElement.getElementsByTagName. Nog() and HTMLElement.getElements() only return extended elements.

Nog.isClass refers to Classes defined by Nog.Class()

Nog.isPrototype is for checking if 'this' is a function prototype, rather than a method

Example:

function iTypeCheck(a,b,n) {
     var name='iTypeCheck';
     if (!Nog.isArray(a)) throw new Error(name+': a is not an Array; '+(typeof a)+' passed.');
     if (!Nog.isBool(b)) throw new Error(name+': b is not Boolean; '+(typeof b)+' passed.');
     if (!Nog.isNumber(n)) throw new Error(name+': n is not a Number; '+(typeof n)+' passed.');
     /* Do some stuff */
     return a;
}
Bad Array | Bad Boolean | Bad Number

Path resolution

String Nog.baseName(String path[, String ext)
String Nog.baseDir(String path)

Description: Get the filename or directory name for a given URL or path

Arguments:

Example:

alert("Dir: "+Nog.baseDir(window.location)+"\nFile: "+Nog.baseName(window.location));
Test

String Nog.absName(String path)

Description: Converts a relative path to an absolute one, based on current location

Arguments: path: path to convert

Example:

alert(Nog.rel2abs('img/nog.png'));
Test

Classes

var className = new Class (Object classDefinition)

Description:

Implements a 'real' Class structure for JavaScript

Arguments:

Returns: A Class as defined by classDefinition

Notes:

Provided for the user are a couple of features.
  1. Instance tracking. In order to be able to use setTimeout and setInterval, we have to have a way to reference ourself from the global scope. Worse yet, we have to do it via a String. Classes defined with Nog.Class() have a this.self() method that will return what we need to use in place of 'this'.
    setTimeout(this.self()+".callMe();", 500);
    Note that this.self() returns 'Nog.instances['+this.globalIndex+']'. As a result, the prototype/this.globalIndex member is off-limits, for your own sake. You can, of course, edit it, but doing so would break your ability to do timeouts.

Example:

var myClass = new Nog.Class({
     constructor:function () {
          this.value=1;
     },
     prototype:{
          increment:function () {
               this.value++;
          },
          valueOf:function () {
               return this.value;
          }
     },
     static:{},
     eventHandlers:{}
});
var myClassInstance = new myClass();
myClassInstance.increment();
alert(myClassInstance.valueOf());
// Should pop up a box containing '2' at this point

Change log

March 11,2007 (v1.0RC2)

March 10, 2007 (v1.0RC1)