// /** * TEST : OOP JAVASCRIPT LIBRARY * @author Dan Dean * @version 0.0.4 * Changes: * Added XML namespace and 3rd party xml2json method * Added String.addQueryParams() * TO DO: (lots!) * FX * Fix Cookies * Note: This library is subject to MASSIVE changes */ var uspopinit = { init: function() { if (typeof window.us == "undefined") { us = new Object(); } if (typeof window.us.pops == "undefined") { us.popdt = new Object(); } /** * AUGMENT * Used to augment Native JS Object capabilities. * FROM: Object.extend in Prototype base.js * NOTE: Added typeof check to make sure there isn't already a native version * @param destination: The Object to augment * @param source: The Object Literal to augment destination with. */ Object.augment = function(destination, source) { for (property in source) { if (typeof destination[property] == "undefined") { // [UNCOMMEND TO SEE WHAT IS BEING AUGMENTED IN YOUR TARGET BROWSER] // alert(source[property]); destination[property] = source[property]; } } return destination; } } } uspopinit.init(); /** * Mimicks the Firebug console object for non-firebug browsers. * To Do: create function to build onscreen debugger instead of alerts. */ dbug = { build: function(type, args) { // (this.viewer != true) ? this.buildViewer() : true ; // future check for html log widget var o = ''; for (var i=0; i)((\n|\r|.)*?)(?:<\/script>)' } /** * Augment Native JavaScript Objects, where necessary * @author Dan Dean */ us.popdt.jsaugment = function() { var ns = us.popdt; // referenced in multiple places in this function, enables easy updating of NameSpace /** * Augment the browser String capabilities, where necessary * Taken directly from prototype.js */ Object.augment(String.prototype, { /** * Remove whitespace at the front and back of a String * FROM: http://kasimchen.com/2005/03/27/javascript-trim/#comment-789 */ trim: function() { return this.replace(/^\s*|\s*$/g,''); }, stripTags: function() { return this.replace(/<\/?[^>]+>/gi, ''); }, stripScripts: function() { return this.replace(new RegExp(ns.snippet.ScriptFragment, 'img'), ''); }, extractScripts: function() { var matchAll = new RegExp(ns.snippet.ScriptFragment, 'img'); var matchOne = new RegExp(ns.snippet.ScriptFragment, 'im'); return (this.match(matchAll) || []).map(function(scriptTag) { return (scriptTag.match(matchOne) || ['', ''])[1]; }); }, evalScripts: function() { return this.extractScripts().map(eval); }, escapeHTML: function() { var div = document.createElement('div'); var text = document.createTextNode(this); div.appendChild(text); return div.innerHTML; }, unescapeHTML: function() { var div = document.createElement('div'); div.innerHTML = this.stripTags(); return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; }, /** * Prototype.js version of this was dependent on other Prototype.js Objects. * Rewritten for Library independence. * @author Dan Dean * @return Object containing name/value pairs * @return Value of supplied "key" * @usage alert("firstname=dan&lastname=dean".toQueryParams()["lastname"]); */ toQueryParams: function() { var query_array = this.substr(this.indexOf("?") + 1).split("&"); var queryObj = {}; var query_count = query_array.length; for (var i=0; i < query_count; i++) { query_pair = query_array[i].split("="); queryObj[query_pair[0]] = query_pair[1]; } return queryObj; }, /** * Add/Update query parameters in a string. * Example: 'index.aspx?hi=ho'.addQueryParams({hi:'there',id:'500'}) will return: * 'index.aspx?hi=there?id=500' * @param new_p JSON object to update the string with * @author Dan Dean */ addQueryParams: function(new_p) { var url = this.split('?'); // find non-query params var out = (typeof url[0] != 'undefined' && url[0].trim() != '') ? url[0].trim() + '?' : '' ; // add query symbol var params = (typeof url[1] != 'undefined') ? url[1].toQueryParams() : {} ; // find existing params for (p in new_p) { // iterate new params, updating old values params[p] = new_p[p]; } var i = 0; for (p in params) { // iterate updated params, appending to 'out' string if (typeof params[p] != 'undefined') { // keep undefined params from adding out += (i>0) ? '&' : '' ; out += (p + '=' + params[p]); i++; } } return out; // update self }, toArray: function() { return this.split(''); }, camelize: function() { // converts css style props to js style props: 'border-color' = 'borderColor' var oStringList = this.split('-'); if (oStringList.length == 1) return oStringList[0]; var camelizedString = this.indexOf('-') == 0 ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) : oStringList[0]; for (var i = 1, len = oStringList.length; i < len; i++) { var s = oStringList[i]; camelizedString += s.charAt(0).toUpperCase() + s.substring(1); } return camelizedString; }, inspect: function() { return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; }, /** * C# style String.format(); * @param nth Arguments to format the String with. * Example: "Rock and {0} {1}!".format("Roll", "Forever") will output "Rock and Roll Forever!". */ format: function() { var val = this; for (var i=0; i < arguments.length; i++) { // Since we're building this on the fly, we have to double escape. I think that's the case, anyways. var regex = new RegExp("\\{" + i + "\\}", "g"); val = val.replace(regex, arguments[i]); } return val; }, contains: function(re, str) { if (str.search(re) != -1) { return true; } else { return false; } }, getHostname: function() { return this.toString().replace(/^\w+\:\/\//,'').split('/')[0]; } }); /** * Augment the browser Function capabilities, where necessary */ Object.augment(Function.prototype, { // both call() and apply() are need by IE5 for some of the Array methods to work. // FROM: http://www.browserland.org/scripts/dragdrop/ apply: function(scope, args) { if (!args) args = []; var index = 0, result; do { -- index } while (typeof scope[index] != "undefined"); scope[index] = this; switch (args.length) { case 0: result = scope[index](); break; case 1: result = scope[index](args[0]); break; case 2: result = scope[index](args[0], args[1]); break; case 3: result = scope[index](args[0], args[1], args[2]); break; case 4: result = scope[index](args[0], args[1], args[2], args[3]); break; default: result = scope[index](args[0], args[1], args[2], args[3], args[4]); break; } delete scope[index]; return result; }, // FROM: http://www.browserland.org/scripts/dragdrop/ call: function(scope) { var args = new Array(Math.max(arguments.length-1, 0)); for (var i = 1; i < arguments.length; i++) args[i-1] = arguments[i]; return this.apply(scope, args); } }); /** * Augment the browser Array capabilities, where necessary * For a full explanation of JS Array capabilities, see the Array documentation: * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference */ Object.augment(Array.prototype, { // FROM DECONCEPT // Adds one or more elements to the end of an array and returns the new length of the array. push: function(item) { // IE5 this[this.length] = item; return this.length; }, /** * Adds and/or removes elements from an array. * @param index: Index at which to start changing the array. * @param count: An integer indicating the number of old array elements to remove. * If count is 0, no elements are removed. In this case, you should specify at least one new element. * @return An array containing the removed elements. * FROM http://www.webreference.com/dhtml/column33/13.html */ splice: function(index,count){ if(arguments.length == 0) return index; if(typeof index != "number") index = 0; if(index < 0) index = Math.max(0,this.length + index); if(index > this.length) { if(arguments.length > 2) index = this.length; else return []; } if(arguments.length < 2) count = this.length-index; count = (typeof count == "number") ? Math.max(0,count) : 0; removeArray = this.slice(index,index+count); endArray = this.slice(index+count); this.length = index; for(var i=2;i < arguments.length;i++){ this[this.length] = arguments[i]; } for(var i=0;i < endArray.length;i++){ this[this.length] = endArray[i]; } return removeArray; }, /** * Returns the first (least) index of an element within the array equal to the specified value, or -1 if none is found. * @param obj: needle * @param si: index to start search. Optional. * FROM http://erik.eae.net */ indexOf: function (obj, si) { if (si == null) { si = 0; } else if (si < 0) { si = Math.max(0, this.length + si); } for (var i=si; i < this.length; i++) { if (this[i] === obj) { return i; } } return -1; }, /** * Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. * @param obj: needle * @param si: index to start search. Optional. * FROM http://erik.eae.net */ lastIndexOf: function (obj, si) { if (si == null) { si = this.length - 1; } else if (si < 0) { si = Math.max(0, this.length + si); } for (var i = si; i >= 0; i--) { if (this[i] === obj) { return i; } } return -1; }, /** * Calls a function for each element in the array. * @param f: callback function to apply to each element in the array. * @param obj: Optional object to apply function to. Defaults to 'this'. * FROM http://erik.eae.net */ forEach: function (f, obj) { var obj = (obj != null) ? obj : this; // IE5 [dd] var l = this.length; for (var i = 0; i < l; i++) { f.call(obj, this[i], i, this); } }, /** * Creates a new array with all of the elements of this array for which the provided filtering function returns true. * @param f: callback function to apply to each element in the array. * @param obj: Optional object to apply function to. Defaults to 'this'. * FROM http://erik.eae.net */ filter: function (f, obj) { var obj = (obj != null) ? obj : this; // IE5 [dd] var l = this.length; var res = []; for (var i = 0; i < l; i++) { if (f.call(obj, this[i], i, this)) { res.push(this[i]); } } return res; }, // Creates a new array with the results of calling a provided function on every element in this array. map: function (f, obj) { var obj = (obj != null) ? obj : this; // IE5 [dd] var l = this.length; var res = []; for (var i = 0; i < l; i++) { res.push(f.call(obj, this[i], i, this)); } return res; }, // Determines the existance of the needle in the stack contains: function (obj) { return this.indexOf(obj) != -1; }, // Duplicates the subject array to a new array: var blah = myArray.copy() copy: function (obj) { return this.concat(); }, // Duplicates the passes array into the new array: var blah = new Array(); blah.copyFrom(arguments); // Useful for copying non Array types into arrays copyFrom: function(arr) { for (var i=0; i" + this.req.responseText +""); } else { alert("There was a problem retrieving the XML data:\n" + this.req.statusText); } } } }, /** * Attach a script element to the DOM. Only occurs after page load. * @param {String} js The JavaScript file to load */ DOMAttach: function(js) { var lib = us.popdt; var js_path = lib.config.PKG_DIR + "/" + js; this.head = (typeof this.head == "undefined") ? document.getElementsByTagName("head")[0] : this.head; var s = document.createElement("script"); s.setAttribute("type","text/javascript"); s.setAttribute("src",js_path); this.head.appendChild(s); } } /** * WINDOW * Encapsulates all functionality related to windows: Print, Popup, Non-Modal, etc * @author Dan Dean */ us.popdt.window = { // PRINT: Encapsulates all functionality relating to PRINTING THE PAGE print: { /** * Send the current page to the printer * @author Dan Dean */ send: function() { if (typeof window.print != "undefined"){ window.print(); return true; } else { alert("Please use your web browsers Print button."); return false; } }, /** * Attaches PRINT functionality to any link on the page of "print_btn", or the supplied class name * @author TBD */ attach: function() { alert('attach'); return true; } } } /** * NAVIGATION * Things like redirection, select navigation, etc */ us.popdt.navigation = { redirect: function(where) { document.location = where; } } /** * Add and Remove events from objects */ us.popdt.event = { /** * Adds an event to an object * @param obj The object to attach an event to * @param type [load | blur | focus | etc] * @param fn The function to call when the even fires */ add: function( obj, type, fn ) { if (obj.addEventListener) { obj.addEventListener( type, fn, false ); } else if (obj.attachEvent) { obj["e"+type+fn] = fn; obj[type+fn] = function() { obj["e"+type+fn]( window.event ); } obj.attachEvent( "on"+type, obj[type+fn] ); } }, /** * The exact same as event.add, but removing instead of adding */ remove: function( obj, type, fn ) { if (obj.removeEventListener) { obj.removeEventListener( type, fn, false ); } else if (obj.detachEvent) { obj.detachEvent( "on"+type, obj[type+fn] ); obj[type+fn] = null; obj["e"+type+fn] = null; } }, /** * Stop an event from firing * This does no work in Safari prior to 2.0.? (find webkit version) */ stop: function(e) { if (e) { // event object if (e.preventDefault) { // W3C e.preventDefault(); e.stopPropagation(); return false; } else { // IE e.returnValue = false; e.cancelBubble = true; } } else { dbug.log("onSubmit: try to cancel submit"); return false; } } } /** * DOM * More advanced functionality will reside in an external dom.js file * NOTE: This is *heavily* influence by the prototype library */ us.popdt.dom = { /** * Create a new DOM node * @param nodeName {string} The kind of node to create (div, br, p, etc); * @param attributes {object} Optional object map of attributes and values. Example: {id: 'myEl', class: 'myClass'} * @param text {string, number} Optional text to set as the textNode within the returned element * @return DOM Node */ create: function(nodeName /* obj attributes, str text */) { node = document.createElement(nodeName); if (arguments.length == 3) { this._attributes(node, arguments[1]); node.appendChild(this._text(arguments[2])); } else if (arguments.length == 2) { (typeof arguments[1] == 'object') ? this._attributes(node, arguments[1]) : node.appendChild(this._text(arguments[1])); } return node; }, /** * Cycles through the supplied attributes and applies them to the supplied element * @param node {node} The node to apply attributes to * @param attributes {object} A JSON Object of attributes: {className:'myclass', id:'myID'} * WARNING: An attibute can NOT be named 'class', but must be 'className' */ _attributes: function(node, attributes) { for (attr in attributes) { switch (true) { case (attr=='className'): node.className = attributes[attr]; break; case (attr=='htmlFor'): // must pass htmlFor, as 'for' is a keyword node.htmlFor = attributes[attr]; break; default: node.setAttribute(attr, attributes[attr]); } } }, /** * Creates and returns a text node with the supplied value */ _text: function(text) { return document.createTextNode(text); }, /** * Combination of getElementById and getElementsByTagName * Example: var els = us.popdt.dom.get('div','home_table','p') will be an array of * all div's, the table#home_table, and all p's. * @param Comma seperated list of ID's and Tag Names * @return {array | node | false} Returns either a single node, an array of nodes, or false */ get: function() { var elements = new Array(); for(var i=0; i 0) ? elements : false ; }, /** * Get all nodes with the given className * @param cls {string} The node.className to check for * @return An array of Nodes or false */ getByClass: function(cls) { var o = new Array(); var all = (typeof document.getElementsByTagName != 'undefined') ? document.getElementsByTagName('*') : document.all ; for (var i=0; i 0) ? o : false ; }, /** * Add a class to an element */ addClass: function(node, cls) { var c = node.className.split(' '); (!c.contains(cls)) ? c.push(cls) : true ; node.className = c.join(' '); }, /** * Remove a class from an element */ removeClass: function(node, cls) { var c = node.className.split(' '); (c.contains(cls)) ? c.remove(cls) : true ; node.className = c.join(' '); }, /** * Check an element for the given className */ hasClass: function(node, cls) { return (node.className.split(' ').contains(cls)); } } $d = us.popdt.dom; // shortcut to the DOM methods