While I am a veteran OOP programmer, I am stumped on aspects of the scope of javascript objects.
What follows is a self-contained custom javascript class who's function is to manage a suite of containers as accordion sliders. I got it to work but must-be I'm not sure why it works because I cannot now use it with a 2nd suite of containers - ie reuse the class as an object managing additional suites of accordion containers.
Probably the easiest way to understand is to re-create the sample and script files and then load the sample into a browser.
You will find:
- -the Left column working just fine.
The challenge:
- -fix my cluggie script to then work with a second object which manages the Right column as elegantly.
- -explain what I've done wrong.
Background:
The object, upon instantiation, receives a tag name eg h3 and an attribute to look for eg SliderL - it then init()'s upon document.load event and attaches a sliddown event to each of the h3/SliderL elements it finds on the page, thereby collecting the h3/SliderL's into said accordion suite, the sliderEngine then keeps track of which element might be opened and then closes it upon a subsequent slidedown event on another member of the suite - you'll see this working in the demo.
What I want is to enable the 2nd suite of accordion sliders on the right which are managed independently of the left.
!Most appreciative to any/everyone who can enlighten me
sliderTester.js
/**
*/
/**
*/
function Slider(sliderTagType, sliderAttribute) {
if (sliderTagType) {
this.sliderTagType = sliderTagType;
} else {
this.sliderTagType = 'Slider';
}
$ = function(id) {return document.getElementById(id);};
dc = function(tag) {return document.createElement(tag);};
// sorry
isIE = !! document.all && !! window.attachEvent && ! window.opera;
this.sliders = {};
this.timerlen = 100;
this.slideAniLen = 1500;
this.timerID = {};
this.startTime = {};
this.sliderObjs = {};
this.endHeight = {};
this.moving = {};
this.dir = {};
this.orighgts = {};
this.showing;
if (sliderAttribute) {
this.sliderAttribute = sliderAttribute;
} else {
this.sliderAttribute = 'Slider';
}
this.sliderEngine = this;
this.addEvent = function(element, ev, handler) {
var doHandler = function(e) {
return handler(e||window.event);
}
if (element.addEventListener) {
element.addEventListener(ev, doHandler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + ev, doHandler);
}
}
this.get_height = function(obj) {
if (Boolean(this.orighgts[obj.id])) {
return this.orighgts[obj.id];
} else if (parseInt(obj.height) > 0) {
hgt = parseInt(obj.height);
} else if (Boolean(obj.scrollHeight)){
hgt = obj.scrollHeight;
} else if (Boolean(obj.offsetHeight)) {
hgt = obj.offsetHeight;
} else {
hgt = 0; //may be display:none;
}
this.orighgts[obj.id] = hgt;
return hgt;
}
this.set_static_height = function(obj) {
if (Boolean(obj.style.height)) {
return obj;
} else {
hgt = this.get_height(obj);
obj.style.height = hgt + 'px';
obj.style.display = 'none';
return obj;
}
}
this.slidedownevent = function(e) {
var etarg;
if (! e) var e = window.event;
if (e.target) etarg = e.target;
else if (e.srcElement) etarg = e.srcElement;
if (etarg.nodeType == 3) // defeat Safari bug
etarg = etarg.parentNode;
var aS;
if (aS = etarg.getAttribute(sliderEngine.sliderAttribute)) {
var q = "";
if (Boolean(sliderEngine.showing) && sliderEngine.showing == aS) {
sliderEngine.slideup(aS);
} else {
sliderEngine.slidedown(aS);
}
} else {
return false;
}
}
this.slidedown = function(objid){
//this bit keeps opening object parents from closing if nested and then expands a parents height should its child need opening
var parent = $(objid).parentNode;
if (Boolean(this.showing)) {
if (this.showing != parent.id) {//don't close a parent
this.moving[this.showing] = true;
this.dir[this.showing] = "up";
this.startslide(this.showing);
parent = false;//we need this later
} else if (this.showing == parent.id) {//expand the parent
parent.style.height = this.get_height(parent) + this.get_height($(objid)) + 9 + 'px';
}
} else {
parent = false;
}
if (this.moving[objid]) {
return;
}
if (this.sliders[objid] && this.sliders[objid].style.display != "none") {
return; // cannot slide down something that is already visible
}
this.moving[objid] = true;
this.dir[objid] = "down";
this.startslide(objid);
if (Boolean(parent)) {//setup to close the parent in case a parent sibling needs closing
this.showing = parent.id;
} else {
this.showing = objid;
}
}
this.slideup = function(objid){
if (this.moving[objid])
return;
if (this.sliders[objid].style.display == "none")
return; // cannot slide up something that is already hidden
this.moving[objid] = true;
this.dir[objid] = "up";
this.startslide(objid);
if (this.showing == objid) {
this.showing = null;
}
}
this.startslide = function(objid) {
this.sliderObjs[objid] = this.sliders[objid];
this.endHeight[objid] = parseInt(this.sliderObjs[objid].style.height);
this.startTime[objid] = (new Date()).getTime();
if (this.dir[objid] == "down"){
this.sliderObjs[objid].style.height = "1px";
} else {
this.sliderObjs[objid].style.zIndex -= 50;
}
this.sliderObjs[objid].style.display = "block";
this.sliderObjs[objid].style.opacity = .5;
//timerID[objid] = setInterval('slidetick(\'' + objid + '\');', timerlen);
this.timerID[objid] = setInterval(function(){sliderEngine.slidetick(objid)}, this.timerlen);
}
this.slidetick = function(objid) {
var elapsed = (new Date()).getTime() - sliderEngine.startTime[objid];
if (elapsed > sliderEngine.slideAniLen) {
sliderEngine.endSlide(objid)
} else {
var d =Math.round(elapsed / sliderEngine.slideAniLen * sliderEngine.endHeight[objid]);
// document.write(d+' =Math.round(elapsed / '+sliderEngine.slideAniLen+' * '+sliderEngine.endHeight[objid]);
if (sliderEngine.dir[objid] == "up") {
d = sliderEngine.endHeight[objid] - d;
}
sliderEngine.sliderObjs[objid].style.height = d + "px";
}
return;
}
this.endSlide = function(objid){
clearInterval(this.timerID[objid]);
if(this.dir[objid] == "up") {
this.sliderObjs[objid].style.display = "none";
this.sliderObjs[objid].style.zIndex += 50;
}
this.sliderObjs[objid].style.height = this.endHeight[objid] + "px";
this.sliderObjs[objid].style.opacity = 1;
delete(this.moving[objid]);
delete(this.timerID[objid]);
delete(this.startTime[objid]);
delete(this.endHeight[objid]);
delete(this.sliderObjs[objid]);
delete(this.dir[objid]);
return;
}
// addEvent("onclick", sliderAttribute.slideDown);
/**
* attach an event to all rel="-slider" elements
* that will open its accompanying (nextSibling) container
* and close all others
*/
this.init = function() {
if ('undefined' == typeof sliderTagType) {
sliderTagType = 'h3';
}
var elems = document.getElementsByTagName(sliderTagType);
for (i in elems) {
elem = elems[i];
if (elem.getAttribute) {
var elemVal = elem.getAttribute(this.sliderAttribute);
if (elemVal != null) {
sliderEngine.sliders[elemVal] = sliderEngine.set_static_height($(elemVal));
this.addEvent(elem, "click", sliderEngine.slidedownevent);
elem.style.cursor="pointer";
}
}
}
}
return;
};
/**
* @usage
* var sliderEngine = new Slider('h3');
* sliderEngine.addEvent(window, "load", sliderEngine.init);
*/
sliderTester.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Codename: Steeve Knight :: JavaScript Slider Tester</title>
</head>
<html>
<body>
<div style="width:90%; margin:auto;">
<h2 style="text-align:center; border-bottom:1px solid grey;">Slider Tester</h2>
<div style="width:40%; float:left; padding:1em; margin:0px auto; text-align:justify;">
<h3 class="" style="background-color:#CDCDCD;" SliderL="L_one">Left One</h3>
<div id="L_one" style="display:block; overflow:hidden;">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam id urna ut nulla dictum ultricies. In sapien dui, pretium eget tempus vulputate, congue vel nulla. Mauris est neque, rhoncus elementum tempus nec, rhoncus ut diam. Integer mi mauris, pharetra sed luctus ac, facilisis vestibulum leo. Mauris id mi vitae enim congue sodales in id nulla. Nunc luctus, dolor ut varius pellentesque, purus augue dictum sapien, sed molestie sapien nisi nec dolor. Suspendisse dictum arcu ut ante dictum id consequat dui suscipit. </p>
</div>
<h3 class="" style="background-color:#CDCDCD;" SliderL="L_two">Left Two</h3>
<div id="L_two" style="display:block; overflow:hidden;">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam id urna ut nulla dictum ultricies. In sapien dui, pretium eget tempus vulputate, congue vel nulla. Mauris est neque, rhoncus elementum tempus nec, rhoncus ut diam. Integer mi mauris, pharetra sed luctus ac, facilisis vestibulum leo. Mauris id mi vitae enim congue sodales in id nulla. Nunc luctus, dolor ut varius pellentesque, purus augue dictum sapien, sed molestie sapien nisi nec dolor. Suspendisse dictum arcu ut ante dictum id consequat dui suscipit. </p>
</div>
<h3 class="" style="background-color:#CDCDCD;" SliderL="L_three">Left Three</h3>
<div id="L_three" style="display:block; overflow:hidden;">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam id urna ut nulla dictum ultricies. In sapien dui, pretium eget tempus vulputate, congue vel nulla. Mauris est neque, rhoncus elementum tempus nec, rhoncus ut diam. Integer mi mauris, pharetra sed luctus ac, facilisis vestibulum leo. Mauris id mi vitae enim congue sodales in id nulla. Nunc luctus, dolor ut varius pellentesque, purus augue dictum sapien, sed molestie sapien nisi nec dolor. Suspendisse dictum arcu ut ante dictum id consequat dui suscipit. </p>
</div>
</div>
<div style="width:50%; float:left; padding:1em; margin:0px auto; text-align:justify; border-left:1px solid grey;">
<h3 class="" style="background-color:#CDCDCD;" SliderR="R_one">Right One</h3>
<div id="R_one" style="display:block; overflow:hidden;">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam id urna ut nulla dictum ultricies. In sapien dui, pretium eget tempus vulputate, congue vel nulla. Mauris est neque, rhoncus elementum tempus nec, rhoncus ut diam. Integer mi mauris, pharetra sed luctus ac, facilisis vestibulum leo. Mauris id mi vitae enim congue sodales in id nulla. Nunc luctus, dolor ut varius pellentesque, purus augue dictum sapien, sed molestie sapien nisi nec dolor. Suspendisse dictum arcu ut ante dictum id consequat dui suscipit. </p>
</div>
<h3 class="" style="background-color:#CDCDCD; overflow:hidden;" SliderR="R_two">Right Two</h3>
<div id="R_two" style="display:block; overflow:hidden;">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam id urna ut nulla dictum ultricies. In sapien dui, pretium eget tempus vulputate, congue vel nulla. Mauris est neque, rhoncus elementum tempus nec, rhoncus ut diam. Integer mi mauris, pharetra sed luctus ac, facilisis vestibulum leo. Mauris id mi vitae enim congue sodales in id nulla. Nunc luctus, dolor ut varius pellentesque, purus augue dictum sapien, sed molestie sapien nisi nec dolor. Suspendisse dictum arcu ut ante dictum id consequat dui suscipit. </p>
</div>
<h3 class="" style="background-color:#CDCDCD; overflow:hidden;" SliderR="R_two">Right Three</h3>
<div id="R_Three" style="display:block; overflow:hidden;">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam id urna ut nulla dictum ultricies. In sapien dui, pretium eget tempus vulputate, congue vel nulla. Mauris est neque, rhoncus elementum tempus nec, rhoncus ut diam. Integer mi mauris, pharetra sed luctus ac, facilisis vestibulum leo. Mauris id mi vitae enim congue sodales in id nulla. Nunc luctus, dolor ut varius pellentesque, purus augue dictum sapien, sed molestie sapien nisi nec dolor. Suspendisse dictum arcu ut ante dictum id consequat dui suscipit. </p>
</div>
</div>
</div>
<script type="text/javascript" src="sliderTester.js"></script>
<script language="JavaScript" type="text/javascript"><!--//--><![CDATA[//><!--
var sliderEngine = new Slider('h3', 'SliderL');
function start_slider() {
sliderEngine.init();
sliderEngine.slidedown('L_one');
//sliderEngineR.init();
//sliderEngineR.slidedown('sv_profile_details');
}
sliderEngine.addEvent(window, "load", start_slider);
//--><!]]></script>
</body>
</html>