libNog:A little library to save you from common JS browser quirkslibNog 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
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
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
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);
}
);
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);
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);
}
);
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);
}
);
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);
}
);
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
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
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
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);
Description:
Adds class membership to an HTML Element.
Arguments:
Example:
document.body.firstChild.addClass('myClass');
Description:
Removes class membership from an HTML Element, if it is a member
Arguments:
Example:
document.body.firstChild.removeClass(document.body.firstChild,'myClass');
Description:
Searches the root element for elements according to the requirements in byParam, and returns an Array of them
Arguments:
itemToCheck:'appropriateValue'
There are also some constants which getElements recognizes. If there are two, separated by a slash, it means that either one will do.
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
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
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);
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.
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
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
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 testedalert(Nog("getStyleDiv").getStyle("borderLeftWidth"));
Test
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);
}
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
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
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
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.
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
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
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
Description:
Implements a 'real' Class structure for JavaScript
Arguments:
classDefinition may have four properties:
- constructor: the construction function for the Class. Run every time you create a new ClassName
- prototype: the non-static members of the Class. Can be addressed as this.nonStaticMember or as the eval'able this.self()+".nonStaticMember".
- static: the static members of the Class. Will be addressed as ClassName.staticMember
Returns: A Class as defined by classDefinition
Notes:
Provided for the user are a couple of features.
- 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