-Xms256m # more memory
-Xmx512m # the same
-XX:MaxPermSize=256m # the same
-ea # needed for assertions?
-server # recommended for long running processes
-XX:-UseParallelGC # usefull on multicore machines
#container{
background-color:#0ff;
float:left;
width:500px;
border-left:150px solid #0f0; »
/* The width and color of the left rail */
border-right:200px solid #f00; »
/* The width and color of the right rail */
}
#leftRail{
float:left;
width:150px;
margin-left:-150px;
position:relative;
}
#center{
float:left;
width:500px;
margin-right:-500px;
}
#rightRail{
float:right;
width:200px;
margin-right:-200px;
position:relative;
}
/*
Offspring.js -- adds the following classes as needed:
.first-child
.last-child
.only-child
.nth-child-odd
.nth-child-even
.nth-child-##
Configuration:
Offspring can be configured by defining an "offspringConfiguration"
object before referencing offspring.js. That object can contain
one or more of these parameters. (If any parameter is omitted -- which
is fine -- it gets the default value as described below.)
offspringConfiguration =
{
runningMode: 'full', <-- valid values are 'full' and 'light' (default: 'full')
autoStart: true, <-- valid values are true and false (default: true)
shouldRemoveOldOffspringClassesFirst: false <-- valid values are true and false (default: false)
}
* runningMode:
'full' -- Offspring applies all of its classes (as listed at the very top) [default]
'light' -- Offspring only applies 'first-child', 'last-child', and 'only-child',
omitting 'nth-child-odd', 'nth-child-even', and 'nth-child-##'.
(This may allow for faster page-processing in certain scenarios.)
* autoStart:
true -- Offspring runs automatically as soon as the DOM is ready [default]
false -- Offspring must be run manually. This can be done by calling Offspring.start();
* shouldRemoveOldOffspringClassesFirst:
true --Offspring first removes any old Offspring classes before applying the new ones.
(This might be of use if Offspring is to be called on a page that has already
been processed, such as if a table has been sorted or content has been loaded
via Ajax.)
false -- Offspring applies its classes without first removing old Offspring classes that
might be there. Unless you're doing fancy DOM updates, this is probably the
better option in most cases. [default]
================================================================== */
var offspring = {
firstChildClass: "first-child",
lastChildClass: "last-child",
oddChildClass: "nth-child-odd",
evenChildClass: "nth-child-even",
onlyChildClass: "only-child",
nthChildClassPrefix: "nth-child-",
classNamesArray: [],
classNameSubstringsArray: [],
cacheLevel: 0, // current size of the classNames cache
nthChildren: [],
regularHashTable: [],
regularHashTableArray: [],
lastChildHashTable: [],
lastChildHashTableArray: [],
/* Configuration defaults */
configuration:
{
runningMode: 'full', /* Possible values: 'full' / 'light' */
autoStart: true, /* If Offspring is configured in autoStart mode (which it is by default),
it runs as soon as the DOM is ready */
shouldRemoveOldOffspringClassesFirst: false /* If this is set to 'true', Offspring first
removes any old Offspring-related classes
before applying the new ones */
},
// Initialize
init: function() {
/*
Offspring's configuration is stored in Offspring.configuration, but
that con be overridden by users by defining an "offspringConfiguratin"
object.
*/
if (typeof offspringConfiguration != "undefined")
{
for (var configParameter in offspringConfiguration)
{
this.configuration[configParameter] = offspringConfiguration[configParameter];
}
// Make sure this option is stored in lowercase
this.configuration.runningMode = this.configuration.runningMode.toLowerCase();
}
/* Set the values for classNamesArray & classNameSubstringArray */
switch (this.configuration.runningMode)
{
case 'full':
// this represents all possible offspring-related classnames
this.classNamesArray = [this.firstChildClass, this.lastChildClass, this.oddChildClass, this.evenChildClass, this.onlyChildClass];
// this represents a list of substrings to match such as for removing classNames
this.classNameSubstringsArray = [this.nthChildClassPrefix];
break;
case 'light':
// this represents all possible offspring-related classnames
this.classNamesArray = [this.firstChildClass, this.lastChildClass, this.onlyChildClass];
// this represents a list of substrings to match such as for removing classNames
this.classNameSubstringsArray = [];
break;
}
// Define the iterator function on-the-fly depending
// on the configuration options that were sent in
this.defineTraverseChildrenFunction();
// Define the fillCacheTo funtion's iterator on-the-fly
// depending on the configuration options that were sent in
this.defineFillCacheToFunction();
this.fillCacheTo(); // seed the cache with a basic set of values
/* If Offspring is configured in autoStart mode (which it is by default),
it runs as soon as the DOM is ready */
if (this.configuration.autoStart)
{
var _this = this; // Closure
this.ContentLoaded(window, function() {
_this.start();
});
}
},
// Executed once the page has loaded
start: function() {
var startTime = new Date();
this.traverseChildren(document.getElementsByTagName("body")[0]);
var endTime = new Date();
// alert("Offspring Exec time: " + (endTime.getTime() - startTime.getTime()) + "ms");
// window.status += "Offspring Exec time: " + (endTime.getTime() - startTime.getTime()) + "ms";
},
/* Maintenance note for defineTraverseChildrenFunction:
There are several blocks of code that are marked off as "traverseChildren.A"
or "traverseChildren.B" -- each of these are identical, respectively. (That is,
all "traverseChildren.A" blocks are the same and all "traverseChildren.B" are
the same.)
So, why not just create a function where the code can be kept in one place?
While normally a sensible idea, I decided against that approach only so
that the speed hits associated with the creation of the function stack
could be averted. At the same time, I didn't want to compromise
the code's maintainability; so, if any block needs to be updated, they
can all be kept in sync with some basic copy-n-pasting from one
block to the next.
*/
/* This defines the internal iterator function on-the-fly,
depending on the configuration options */
defineTraverseChildrenFunction: function() {
switch (this.configuration.shouldRemoveOldOffspringClassesFirst)
{
case true: // shouldRemoveOldOffspringClassesFirst is true
switch (this.configuration.runningMode)
{
case 'full': // 'full' running mode and shouldRemoveOldOffspringClassesFirst is true
this.traverseChildren = function(parent)
{
/* ============= Begin Code Block "traverseChildren.A" ================ */
// If the node has no children, exit
if (!parent.childNodes.length) return;
/* First, gather up all the element nodes */
var childElementNodes = [];
var testNode = parent.childNodes[0]; // initialize
while (testNode)
{
if (testNode.nodeType == 1)
{
childElementNodes.push(testNode);
}
testNode = testNode.nextSibling;
}
/*
empty this variable to ensure that the JavaScript
interpreter doesn't have to update the variable's
nodelist as DOM changes are made
*/
testNode = null;
var childElementNodesLength = childElementNodes.length;
// If no element nodes were found, exit
if (!childElementNodesLength) return;
// Make sure that the CSS-classnames cache has enough entries to cover
// the number of child nodes
if (childElementNodesLength > this.cacheLevel)
{
this.fillCacheTo(childElementNodesLength);
}
var lastIndex = childElementNodesLength - 1; // index of the last element node
/* ============= /End Code Block "traverseChildren.A" ================ */
// First, take care of all but the last element
for (var i = 0; i < lastIndex; i++)
{
var currentElement = childElementNodes[i];
this.removeMultipleClassNames(currentElement, this.classNamesArray, this.classNameSubstringsArray);
// argument syntax: node to act upon, current index, boolean for whether isLast
this._addOffspringClassNames(currentElement, i, false);
this.traverseChildren(currentElement);
}
currentElement = null; // prevent memory leaks
// Then, take care of the last one
var lastElement = childElementNodes[lastIndex];
this.removeMultipleClassNames(lastElement, this.classNamesArray, this.classNameSubstringsArray);
this._addOffspringClassNames(lastElement, lastIndex, true);
this.traverseChildren(lastElement);
lastElement = null; // prevent memory leaks
/* ============= Begin Code Block "traverseChildren.B" ================ */
// prevent memory leaks
lastElement = null;
parent = null;
/* ============= /End Code Block "traverseChildren.B" ================ */
}; // end of traverseChildren function definition
break;
case 'light': // 'light' running mode and shouldRemoveOldOffspringClassesFirst is true
this.traverseChildren = function(parent)
{
/* ============= Begin Code Block "traverseChildren.A" ================ */
// If the node has no children, exit
if (!parent.childNodes.length) return;
/* First, gather up all the element nodes */
var childElementNodes = [];
var testNode = parent.childNodes[0]; // initialize
while (testNode)
{
if (testNode.nodeType == 1)
{
childElementNodes.push(testNode);
}
testNode = testNode.nextSibling;
}
/*
empty this variable to ensure that the JavaScript
interpreter doesn't have to update the variable's
nodelist as DOM changes are made
*/
testNode = null;
var childElementNodesLength = childElementNodes.length;
// If no element nodes were found, exit
if (!childElementNodesLength) return;
// Make sure that the CSS-classnames cache has enough entries to cover
// the number of child nodes
if (childElementNodesLength > this.cacheLevel)
{
this.fillCacheTo(childElementNodesLength);
}
var lastIndex = childElementNodesLength - 1; // index of the last element node
/* ============= /End Code Block "traverseChildren.A" ================ */
switch (childElementNodesLength)
{
case 0: return;
break;
case 1:
/* Take care of the only element */
var onlyElement = childElementNodes[0];
this.removeMultipleClassNames(onlyElement, this.classNamesArray, this.classNameSubstringsArray);
// argument syntax: node to act upon, current index, boolean for whether isLast
this._addOffspringClassNames( onlyElement, lastIndex, true );
onlyElement = null; // prevent memory leaks
break;
default:
/* Take care of the first element */
var firstElement = childElementNodes[0];
this.removeMultipleClassNames(firstElement, this.classNamesArray, this.classNameSubstringsArray);
// argument syntax: node to act upon, current index, boolean for whether isLast
this._addOffspringClassNames( firstElement, 0, false );
firstElement = null; // prevent memory leaks
/* Take care of the last element */
var lastElement = childElementNodes[lastIndex];
this.removeMultipleClassNames(lastElement, this.classNamesArray, this.classNameSubstringsArray);
// argument syntax: node to act upon, current index, boolean for whether isLast
this._addOffspringClassNames( lastElement , lastIndex, true );
lastElement = null; // prevent memory leaks
break;
} // end of switch statement for childElementNodesLength
// Lastly, loop over all the childern elements
for (var i = 0; i < childElementNodesLength; i++)
{
this.traverseChildren( childElementNodes[i] );
}
/* ============= Begin Code Block "traverseChildren.B" ================ */
// prevent memory leaks
lastElement = null;
parent = null;
/* ============= /End Code Block "traverseChildren.B" ================ */
}; // end of traverseChildren function definition
break;
} // end of switch-statement for configuration.runningMode
break;
case false: // shouldRemoveOldOffspringClassesFirst is false
switch (this.configuration.runningMode)
{
case 'full': // 'full' running mode and shouldRemoveOldOffspringClassesFirst is false
this.traverseChildren = function(parent)
{
/* ============= Begin Code Block "traverseChildren.A" ================ */
// If the node has no children, exit
if (!parent.childNodes.length) return;
/* First, gather up all the element nodes */
var childElementNodes = [];
var testNode = parent.childNodes[0]; // initialize
while (testNode)
{
if (testNode.nodeType == 1)
{
childElementNodes.push(testNode);
}
testNode = testNode.nextSibling;
}
/*
empty this variable to ensure that the JavaScript
interpreter doesn't have to update the variable's
nodelist as DOM changes are made
*/
testNode = null;
var childElementNodesLength = childElementNodes.length;
// If no element nodes were found, exit
if (!childElementNodesLength) return;
// Make sure that the CSS-classnames cache has enough entries to cover
// the number of child nodes
if (childElementNodesLength > this.cacheLevel)
{
this.fillCacheTo(childElementNodesLength);
}
var lastIndex = childElementNodesLength - 1; // index of the last element node
/* ============= /End Code Block "traverseChildren.A" ================ */
// First, take care of all but the last element
for (var i = 0; i < lastIndex; i++)
{
var currentElement = childElementNodes[i];
// argument syntax: node to act upon, current index, boolean for whether isLast
this._addOffspringClassNames(currentElement, i, false);
this.traverseChildren(currentElement);
}
currentElement = null; // prevent memory leaks
/*
Then, take care of the last one
(this set of code isn't integrated into
the for-loop above so as to avoid having
an addiitional if-statement inside there)
*/
var lastElement = childElementNodes[lastIndex];
this._addOffspringClassNames(lastElement, lastIndex, true);
this.traverseChildren(lastElement);
lastElement = null; // prevent memory leaks
/* ============= Begin Code Block "traverseChildren.B" ================ */
// prevent memory leaks
lastElement = null;
parent = null;
/* ============= /End Code Block "traverseChildren.B" ================ */
}; // end of traverseChildren function definition
break;
case 'light': // 'light' running mode and shouldRemoveOldOffspringClassesFirst is false
this.traverseChildren = function(parent)
{
/* ============= Begin Code Block "traverseChildren.A" ================ */
// If the node has no children, exit
if (!parent.childNodes.length) return;
/* First, gather up all the element nodes */
var childElementNodes = [];
var testNode = parent.childNodes[0]; // initialize
while (testNode)
{
if (testNode.nodeType == 1)
{
childElementNodes.push(testNode);
}
testNode = testNode.nextSibling;
}
/*
empty this variable to ensure that the JavaScript
interpreter doesn't have to update the variable's
nodelist as DOM changes are made
*/
testNode = null;
var childElementNodesLength = childElementNodes.length;
// If no element nodes were found, exit
if (!childElementNodesLength) return;
// Make sure that the CSS-classnames cache has enough entries to cover
// the number of child nodes
if (childElementNodesLength > this.cacheLevel)
{
this.fillCacheTo(childElementNodesLength);
}
var lastIndex = childElementNodesLength - 1; // index of the last element node
/* ============= /End Code Block "traverseChildren.A" ================ */
switch (childElementNodesLength)
{
case 0: break;
case 1:
/* Take care of the only element */
// argument syntax: node to act upon, current index, boolean for whether isLast
this._addOffspringClassNames( childElementNodes[0], lastIndex, true );
// Lastly, loop over all the childern elements
for (var i = 0; i < childElementNodesLength; i++)
{
this.traverseChildren( childElementNodes[i] );
}
break;
default:
/* Take care of the first element */
// argument syntax: node to act upon, current index, boolean for whether isLast
this._addOffspringClassNames( childElementNodes[0], 0, false );
/* Take care of the last element */
// argument syntax: node to act upon, current index, boolean for whether isLast
this._addOffspringClassNames( childElementNodes[lastIndex] , lastIndex, true );
// Lastly, loop over all the childern elements
for (var i = 0; i < childElementNodesLength; i++)
{
this.traverseChildren( childElementNodes[i] );
}
break;
}
/* ============= Begin Code Block "traverseChildren.B" ================ */
// prevent memory leaks
lastElement = null;
parent = null;
/* ============= /End Code Block "traverseChildren.B" ================ */
}; // end of traverseChildren function definition
break;
} // end of switch-statement for configuration.runningMode
break;
} // end of switch-statement for configuration.shouldRemoveOldOffspringClassesFirst
}, // end of defineTraverseChildrenFunction
// Recursive
/*
If "shouldRemoveOldOffspringClassesFirst" is deined and set to true
(it's optional), traverseChildren will remove old Offspring-related
classes before applying new ones to a node. This could be useful
for reapplying classes if the DOM is rejiggered.
*/
traverseChildren: function(parent) {
/* ============= Begin Code Block "traverseChildren.A" ================ */
// If the node has no children, exit
if (!parent.childNodes.length) return;
/* First, gather up all the element nodes */
var childElementNodes = [];
var testNode = parent.childNodes[0]; // initialize
while (testNode)
{
if (testNode.nodeType == 1)
{
childElementNodes.push(testNode);
}
testNode = testNode.nextSibling;
}
/*
empty this variable to ensure that the JavaScript
interpreter doesn't have to update the variable's
nodelist as DOM changes are made
*/
testNode = null;
var childElementNodesLength = childElementNodes.length;
// If no element nodes were found, exit
if (!childElementNodesLength) return;
// Make sure that the CSS-classnames cache has enough entries to cover
// the number of child nodes
if (childElementNodesLength > this.cacheLevel)
{
this.fillCacheTo(childElementNodesLength);
}
var lastIndex = childElementNodesLength - 1; // index of the last element node
/* ============= /End Code Block "traverseChildren.A" ================ */
/* ==== Add the classes ====== */
this._childrenIterator(childElementNodes, childElementNodesLength, lastIndex);
/* ============= Begin Code Block "traverseChildren.B" ================ */
// prevent memory leaks
lastElement = null;
parent = null;
/* ============= /End Code Block "traverseChildren.B" ================ */
},
/*
This function adds the Offspring classnames to a given element,
given its position among it siblings (with zero being "first")
and whether it's the last element in its set.
*/
_addOffspringClassNames: function(element, index, isLastElement) {
index++; // normalize since the arrays are indexed with a "1" starting point
// Steps if the element has no existing classnames...
if ((!element.className) || (!element.className.length))
{
switch (isLastElement)
{
case false: // it isn't the last element
element.className = this.regularHashTable[index];
return;
break;
case true: // it is the last element
element.className = this.lastChildHashTable[index];
return;
break;
} // end of isLastElement switch-statement
} // end of if-statement for checking whether the element has no existing className
// At this point, the incoming element already has className(s)
switch (isLastElement)
{
case false: // it isn't the last element
var applicableClassNames = this.regularHashTableArray[index];
break;
case true: // it is the last element
var applicableClassNames = this.lastChildHashTableArray[index];
break;
} // end of isLastElement switch-statement
var originalClassNames = element.className.split(' ');
var classNamesToAdd = originalClassNames; // initialize
for (var i = 0, applicableClassNamesLength = applicableClassNames.length; i < applicableClassNamesLength; i++)
{
var alreadyThere = false; // boolean for whether a given class name is already assigned to the element
var testApplicableClassName = applicableClassNames[i];
for (var j = 0, originalClassNamesLength = originalClassNames.length; j < originalClassNamesLength; j++)
{
if (originalClassNames[j] == testApplicableClassName)
{
alreadyThere = true;
break;
} // end of if-statement for checking if the element already has a given className
} // end of the originalClassNames for-loop
if (!alreadyThere)
{
classNamesToAdd.push(testApplicableClassName);
}
} // end of applicableClassNames for-loop
// Then, after checking over the element's existing classNames, add the new version
element.className = classNamesToAdd.join(' ');
element = null; // prevent memory leaks
return;
}, // end of _addOffspringClassNames()
/* Maintenance note for defineFillCacheToFunction:
[Aside: This is basically conveys the same idea as the comment above
defineTraverseChildrenFunction. So, if you're read that one, you
probably already have the basic idea of what's going on here.]
There are several blocks of code that are marked off as "fillCacheTo.A"
or "fillCacheTo.B" -- each of these are identical, respectively. (That is,
all "fillCacheTo.A" blocks are the same and all "fillCacheTo.B" are
the same.)
So, why not just create a function where the code can be kept in one place?
While normally a sensible idea, I decided against that approach only so
that the speed hits associated with the creation of the function stack
could be averted. At the same time, I didn't want to compromise
the code's maintainability; so, if any block needs to be updated, they
can all be kept in sync with some basic copy-n-pasting from one
block to the next.
*/
/* This defines the internal loop function for fillCacheTo,
depending on how the configuration options are set */
defineFillCacheToFunction: function() {
switch (this.configuration.runningMode)
{
case 'full': // 'full' running mode
this.fillCacheTo = function(fillAmount)
{
/* ============= Begin Code Block "fillCacheTo.A" ================ */
var fillAmount = fillAmount || 15; // default value
if (!this.cacheLevel) this.cacheLevel = 0; // set this to a default value if needed
// If the cache level is already full enough, exit
if (this.cacheLevel >= fillAmount) return;
var startingPoint = this.cacheLevel++;
/* ============= /End Code Block "fillCacheTo.A" ================ */
var isOdd = !((startingPoint % 2) == 0); // initialize
// cache these object name resolutions
var firstChildClass = this.firstChildClass;
var lastChildClass = this.lastChildClass;
var oddChildClass = this.oddChildClass;
var evenChildClass = this.evenChildClass;
var onlyChildClass = this.onlyChildClass;
var nthChildClassPrefix = this.nthChildClassPrefix;
for (var i = startingPoint; i <= fillAmount; i++)
{
this.nthChildren[i] = [nthChildClassPrefix, i].join('');
var nthChildrenI = this.nthChildren[i]; // cache this look-up
switch (i)
{
case 1:
this.regularHashTableArray[i] = [firstChildClass, oddChildClass, nthChildrenI];
this.lastChildHashTableArray[i] = [firstChildClass, oddChildClass, onlyChildClass, nthChildrenI, lastChildClass];
break;
default:
switch (isOdd)
{
case true: // "odd" is true
this.regularHashTableArray[i] = [oddChildClass, nthChildrenI];
this.lastChildHashTableArray[i] = [oddChildClass, nthChildrenI, lastChildClass];
break;
case false: // "odd" is false
this.regularHashTableArray[i] = [evenChildClass, nthChildrenI];
this.lastChildHashTableArray[i] = [evenChildClass, nthChildrenI, lastChildClass];
break;
} // end of isOdd switch-statement
} // end of switch-statement for i
// Now make the joined versions for a given "i"
this.regularHashTable[i] = this.regularHashTableArray[i].join(' ');
this.lastChildHashTable[i] = this.lastChildHashTableArray[i].join(' ');
isOdd = !isOdd; // flip the isOdd flag
} // end of filling for-loop
/* ============= Begin Code Block "fillCacheTo.B" ================ */
// If it got this far, the cacheLevel must made it to the fill amount, so update that
this.cacheLevel = fillAmount;
/* ============= /End Code Block "fillCacheTo.B" ================ */
}; // end of fillCacheTo function definition
break;
case 'light': // 'light' running mode
this.fillCacheTo = function(fillAmount)
{
/* ============= Begin Code Block "fillCacheTo.A" ================ */
var fillAmount = fillAmount || 15; // default value
if (!this.cacheLevel) this.cacheLevel = 0; // set this to a default value if needed
// If the cache level is already full enough, exit
if (this.cacheLevel >= fillAmount) return;
var startingPoint = this.cacheLevel++;
/* ============= /End Code Block "fillCacheTo.A" ================ */
// cache these object name resolutions
var firstChildClass = this.firstChildClass;
var lastChildClass = this.lastChildClass;
var onlyChildClass = this.onlyChildClass;
for (var i = startingPoint; i <= fillAmount; i++)
{
switch (i)
{
case 1:
this.regularHashTableArray[i] = [firstChildClass];
this.lastChildHashTableArray[i] = [firstChildClass, onlyChildClass, lastChildClass];
break;
default:
this.regularHashTableArray[i] = [];
this.lastChildHashTableArray[i] = [lastChildClass];
} // end of switch-statement for i
// Now make the joined versions for a given "i"
this.regularHashTable[i] = this.regularHashTableArray[i].join(' ');
this.lastChildHashTable[i] = this.lastChildHashTableArray[i].join(' ');
} // end of filling for-loop
/* ============= Begin Code Block "fillCacheTo.B" ================ */
// If it got this far, the cacheLevel must made it to the fill amount, so update that
this.cacheLevel = fillAmount;
/* ============= /End Code Block "fillCacheTo.B" ================ */
}; // end of fillCacheTo function definition
break;
} // end of switch statement for this.configuration.runningMode
}, // end of defineFillCacheToFunction
// This fills the className caches to the specified amount
fillCacheTo: function(fillAmount) {
/* ============= Begin Code Block "fillCacheTo.A" ================ */
var fillAmount = fillAmount || 15; // default value
if (!this.cacheLevel) this.cacheLevel = 0; // set this to a default value if needed
// If the cache level is already full enough, exit
if (this.cacheLevel >= fillAmount) return;
var startingPoint = this.cacheLevel++;
/* ============= /End Code Block "fillCacheTo.A" ================ */
this._fillCacheToIterator(startingPoint, fillAmount);
/* ============= Begin Code Block "fillCacheTo.B" ================ */
// If it got this far, the cacheLevel must made it to the fill amount, so update that
this.cacheLevel = fillAmount;
/* ============= /End Code Block "fillCacheTo.B" ================ */
}, // end of fillCacheTo()
/* Returns true if testString is found in the array,
or returns false otherwise */
_checkIfStringFoundInArray: function(testString, testArray) {
// Loop through all testArray[] and if/when there's a match, return true
for (var i = 0, len=testArray.length; i < len; i++)
{
if (testString == testArray[i]) return true;
}
// If it got this far, it must not have found the string in the array
return false;
}, // end of _checkIfStringFoundInArray
/* Returns true if the beginning of testString matches one of the substrings
in the array. Otherwise, it returns false.
For example, given the array ['plum', 'orange', 'pine'] and
the testString 'pineapples', the function would return true. However,
given the testString 'range', it would return false (since none of
the strings in the array start with 'range')
*/
_checkIfStringMatchInSubstringArray: function(testString, testArray) {
// Loop through all testArray[] and if/when there's a match, return true
for (var i = 0, len=testArray.length; i < len; i++)
{
var currentArrayItem = testArray[i];
/* string.substr() accepts two parameters:
- The starting point of the substring
- The length of the substring
*/
var testSubstring = testString.substr(0, currentArrayItem.length);
if (testSubstring == currentArrayItem) return true;
}
// If it got this far, it must not have found the string in the array
return false;
}, // end of _checkIfStringMatchInSubstringArray
/*
This removes multiple classnames from an element. It does this by
checking each of an element's class names against
classNameStrings[] for an exact match and, if a given class name
didn't match there, it's then checked to see if it matches
as a substring against classNAmeSubstrings[].
Of note, when comparing substrings, this intentionally only compares
the beginning of the strings for a match. So, for example, "ora" would
match as a substring of "orange", but "range" would not match as a substring
of "orange". It was done this way because that was the only type of substring-
comparison that was needed in this case, and a more thorough substring
comparison would needlesslly use processor time.
*/
removeMultipleClassNames: function(element, classNameStrings, classNameSubstrings) {
if (!element) return;
var newClassName = '';
var classNamesArray = element.className.split(' ');
for (var i = 0, len = classNamesArray.length; i < len; i++)
{
var currentClassName = classNamesArray[i];
var isStringInClassNameStrings = this._checkIfStringFoundInArray(currentClassName, classNameStrings);
if (isStringInClassNameStrings) continue;
var isStringMatchingClassNameSubstrings = this._checkIfStringMatchInSubstringArray(currentClassName, classNameSubstrings);
if (isStringMatchingClassNameSubstrings) continue;
// If it got this far, it must not have matched any of the potential classNameStrings
// or classNameRegexes, so add the current iteration to the neClassName
if (i > 0) newClassName = newClassName + ' ';
newClassName = newClassName + currentClassName;
}
element.className = newClassName;
}, // end of removeMultipleClassNames
/*
*
* ContentLoaded.js
*
* Author: Diego Perini (diego.perini at gmail.com)
* Summary: Cross-browser wrapper for DOMContentLoaded
* Updated: 05/10/2007
* License: GPL/CC
* Version: 1.0
*
* http://javascript.nwbox.com/ContentLoaded/
*
* Notes:
*
* based on code by Dean Edwards and John Resig
* http://dean.edwards.name/weblog/2006/06/again/
*
*
*/
/*
* Example call, in this case:
Offspring.ContentLoaded(window,
function () {
document.body.style.backgroundColor = 'green';
}
);
*
*/
// @w window reference
// @f function reference
ContentLoaded: function (w, fn) {
var d = w.document,
u = w.navigator.userAgent.toLowerCase();
function init(e) {
if (!arguments.callee.done) {
arguments.callee.done = true;
fn(e);
}
}
// konqueror/safari
if (/khtml|webkit/.test(u)) {
(function () {
if (/complete|loaded/.test(d.readyState)) {
init('poll');
} else {
setTimeout(arguments.callee, 10);
}
})();
// internet explorer all versions
} else if (/msie/.test(u) && !w.opera) {
(function () {
try {
d.documentElement.doScroll('left');
} catch (e) {
setTimeout(arguments.callee, 10);
return;
}
init('poll');
})();
d.attachEvent('onreadystatechange',
function (e) {
if (d.readyState == 'complete') {
d.detachEvent('on'+e.type, arguments.callee);
init(e.type);
}
}
);
// browsers having native DOMContentLoaded
} else if (d.addEventListener &&
(/gecko/.test(u) && parseFloat(u.split('rv:')[1]) >= 1.8) ||
(/opera/.test(u) && parseFloat(u.split('opera ')[1]) > 9)) {
d.addEventListener('DOMContentLoaded',
function (e) {
this.removeEventListener(e.type, arguments.callee, false);
init(e.type);
}, false
);
// fallback to last resort
} else {
// from Simon Willison
var oldonload = w.onload;
w.onload = function (e) {
if (typeof oldonload == 'function') {
oldonload(e || w.event);
}
init((e || w.event).type);
};
}
} // end of ContentLoaded
}
// Kick off
offspring.init();
<!--
category: HTML
name: Onclick Popup
toolTip: Onclick Popup
prompt(href): Enter the HREF URL
prompt(width): Enter the popup Width
prompt(height): Enter the poup Height
-->
onclick="window.open('${href}', '_blank', 'width=${width},height=${height},scrollbars=yes,status=yes,resizable=yes,screenx=0,screeny=0');"