A Conversation for The H2G2 Programmers' Corner
Javascript dynamic menu
Titania (gone for lunch) Started conversation Oct 25, 2002
*floating in, in her usual vague, elf-like manner, more than usually confused*
...or whatever you call it...
I've started making my own web site, and I'm having great fun doing it!
Unfortunately, the only thing I know is GuideML (having learnt it here at h2g2) which helps me understand HTML
My problem is this - my site has two frames; one with the menu, and one with the pages linked to from the menu
I'd like to make the menu look really nifty, with just the titles of each section showing, and a 'mouseover' showing the links beneath selected section. It would also make the menu a lot shorter, meaning I could probably skip the scroll bar.
It has to bee small and simple, and not require any gifs - I tried searching the web for javascripts, but the ones I managed to find were a wee bit too complicated and flashy
I'm about as non- as they come, so I'd like the javascript code needs to be very simple and - hopefully - understandable (more or less)
Would anyone happen to know about a javascript like that?
...and this is my site:
http://hem.passagen.se/kristina.r
Javascript dynamic menu
Tango Posted Oct 25, 2002
I expect there is a perfect script out there on the web somewhere. I don't think you can do what you want with anything simple, what you need is something you can copy and paste straight into your site. Keep looking and good luck with the site!
Tango
Javascript dynamic menu
DoctorMO (Keeper of the Computer, Guru, Community Artist) Posted Oct 25, 2002
have a look at the menu's I developed here
http://www.infranet-partners.com/cgi-bin/index.pm
This is a bit complex but it shows you what you can achive. I just wish I could understand what you want.
-- DoctorMO --
Javascript dynamic menu
Pastey Posted Oct 26, 2002
Okay, get ready for some rambling code.
First off, Don't Panic!
It's no where near as complicated as it looks and there's only one bit that needs to be altered. I admit that it needs images, but only two, true.gif and false.gif
This involved three additional files to make the menu work, but the joy is you don't need to play around with them if you don't want to.
Here goes...
remember, if there's anything you need explaining, just ask.
////////////////////////////////////////
The Menu bit
alter this to point to the pages you have, and the names you want.
if you look at the code you can see how each sublist is built up
this goes in the part of your document.
////////////////////////////////////////
function init()
{
var width = 150;
var height = 30;
var bgColor = "#FFA101";
var menulist = new List(true, width, height, bgColor);
menulist.setFont("","<\/b>");
menulist.addItem("");
menulist.addItem("");
var breweries = new List(false, width, height, bgColor);
breweries.addItem("List");
breweries.addItem("Search");
menulist.addList(breweries, "Breweries");
menulist.addItem("");
var beers = new List(false, width, height, bgColor);
beers.setFont("","<\/FONT>");
beers.addItem("List");
beers.addItem("Search");
menulist.addList(beers, "Beers");
menulist.addItem("");
var pubs = new List(false, width, height, bgColor);
pubs.addItem("List");
pubs.addItem("Search");
menulist.addList(pubs, "Pubs");
menulist.addItem("");
var festivals = new List(false, width, height, bgColor);
festivals.addItem("List");
menulist.addList(festivals, "Festivals");
menulist.addItem("");
var members = new List(false, width, height, bgColor);
members.addItem("Login");
members.addItem("Register");
members.addItem("Member List");
members.addItem("Logout");
menulist.addList(members, "Members");
menulist.addItem("");
var infor = new List(false, width, height, bgColor);
infor.addItem("Stats");
infor.addItem("For Brewers");
infor.addItem("For Publicans");
infor.addItem("For Drinkers");
menulist.addList(infor, "Information");
menulist.build(0, 0);
}
// -->
function redo()
{
document.location.reload();
}
///////////////////////////////////////////////////////////////////
now for the other files.
each of these need to be saved as a seperate file in the same folder as the menu page.
//////////////////////////////////////////////////////////////////
filename: xbCollapsibleLists.js
//////////////////////////////////////////////////////////////////
/*
The contents of this file are subject to the Netscape Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 2001 Netscape Communications Corporation. All
Rights Reserved.
Alternatively, the contents of this file may be used under the
terms of the GNU Public License (the "GPL"), in which case the
provisions of the GPL are applicable instead of those above.
If you wish to allow use of your version of this file only
under the terms of the GPL and not to allow others to use your
version of this file under the NPL, indicate your decision by
deleting the provisions above and replace them with the notice
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the NPL or the GPL.
Contributor(s): Michael Bostock, Netscape Communications, Copyright 1997
Bob Clary, Netscape Communications, Copyright 2001
2001-06-26 bclary: fixed erroneous reference to this in getNewItem()
*/
var _list_id = 0;
var _item_id = 0;
var _mLists = new Array();
document.lists = _mLists;
function setInnerHTML(elm, str)
{
if (navigator.family == 'nn4')
{
elm.document.writeln(str);
elm.document.close();
}
else if (typeof(elm.innerHTML) != 'undefined')
elm.innerHTML = str;
}
function List(visible, width, height, bgColor)
{
this.lists = new Array(); // sublists
this.items = new Array(); // layers
this.types = new Array(); // type
this.strs = new Array(); // content
this.visible = visible;
this.id = _list_id;
this.width = width || 350;
this.height = height || 22;
if (bgColor)
this.bgColor = bgColor;
_mLists[_list_id++] = this;
}
function _listSetFont(i,j)
{
this.fontIntro = i;
this.fontOutro = j;
}
function setIndent(indent)
{
this.i = indent;
if (this.i < 0)
{
this.i = 0;
this.space = false;
}
}
function _writeList()
{
self.status = 'List: Writing list...';
var item;
var str;
var clip;
var styleObj;
var i;
var cellStyle = '';
/*
* Note IE 5.x treats the background color set on the containing DIV as being
* inherited by it's children. But that is not the case in CSS1, so for a compliant
* browser such as Mozilla or Netscape 6, you must set the Table cell's background
* color as transparent so the parent's background color will show through.
* Also, Navigator 4, screws up with background color of transparent, so leave it out...
*/
if (navigator.DOMCSS1)
cellStyle = ' style="background-color: transparent;"';
for (i = 0; i < this.types.length; i++)
{
item = this.items[i];
styleObj = new xbStyle(item);
styleObj.setVisibility('hidden');
str = '';
str += '';
if (this.types[i] == 'list')
{
str += '';
str += '';
str += '';
str += '';
}
else if (this.space)
str += ' ';
if (this.l>0 && this.i>0)
str += ' ';
str += '';
if (this.fontIntro)
str += this.fontIntro;
str += this.strs[i];
if (this.fontOutro)
str += this.fontOutro;
str += '';
setInnerHTML(item, str);
if (this.types[i] == 'list' && this.lists[i].visible)
this.lists[i]._writeList();
}
this.built = true;
this.needsRewrite = false;
self.status = '';
}
function _showList()
{
var item;
var styleObj;
var i;
for (i = 0; i < this.types.length; i++)
{
item = this.items[i];
styleObj = new xbStyle(item);
styleObj.setClipLeft(0);
styleObj.setClipRight(this.width);
styleObj.setClipTop(0);
styleObj.setClipBottom(this.height);
styleObj.setWidth(this.width);
styleObj.setHeight(this.height);
var bg = item.oBgColor || this.bgColor;
if ((bg == null) || (bg == 'null'))
bg = '';
styleObj.setBackgroundColor(bg);
if (this.types[i] == 'list' && this.lists[i].visible)
this.lists[i]._showList();
}
this.shown = true;
this.needsUpdate = false;
}
function setImage(list, item, file)
{
var id = '_img' + list.id;
var img = null;
// for DOMHTML or IE4 use cross browser getElementById from xbStyle
// can't use it for NN4 since it only works for layers in NN4
if (navigator.DOMHTML || navigator.family == 'ie4')
img = document.getElementById(id);
else if (navigator.family == 'nn4')
img = item.document.images[0];
if (img)
img.src = file;
}
function _updateList(pVis, x, y)
{
var currTop = y;
var item;
var styleObj;
var i;
for (i = 0; i < this.types.length; i++)
{
item = this.items[i];
styleObj = new xbStyle(item);
if (this.visible && pVis)
{
styleObj.setVisibility('visible');
styleObj.setTop(currTop);
styleObj.setLeft(x);
currTop += this.height;
}
else
{
styleObj.setVisibility('hidden');
}
if (this.types[i] == 'list')
{
if (this.lists[i].visible)
{
if (!this.lists[i].built || this.lists[i].needsRewrite)
this.lists[i]._writeList();
if (!this.lists[i].shown || this.lists[i].needsUpdate)
this.lists[i]._showList();
setImage(this.lists[i], item, 'true.gif');
}
else
setImage(this.lists[i], item, 'false.gif');
if (this.lists[i].built)
currTop = this.lists[i]._updateList(this.visible && pVis, x, currTop);
}
}
return currTop;
}
function _updateParent(pid, l)
{
var i;
if (!l)
l = 0;
this.pid = pid;
this.l = l;
for (i = 0; i < this.types.length; i++)
if (this.types[i] == 'list')
this.lists[i]._updateParent(pid, l+1);
}
function expand(i)
{
_mLists[i].visible = !_mLists[i].visible;
if (_mLists[i].onexpand != null)
_mLists[i].onexpand(_mLists[i].id);
_mLists[_mLists[i].pid].rebuild();
if (_mLists[i].postexpand != null)
_mLists[i].postexpand(_mLists[i].id);
}
function build(x, y)
{
this._updateParent(this.id);
this._writeList();
this._showList();
this._updateList(true, x, y);
this.x = x;
this.y = y;
}
function rebuild()
{
this._updateList(true, this.x, this.y);
}
function getNewItem(parentList)
{
var newItem = null;
var parentElement = null;
newItem = document.getElementById('lItem' + _item_id);
if (!newItem)
{
if (parentList)
parentElement = document.getElementById(parentList.id);
if (navigator.DOMHTML)
{
newItem = document.createElement('div');
newItem.id = 'lItem' + _item_id;
newItem.style.position = 'absolute';
if (parentElement)
parentElement.appendChild(newItem);
else
document.body.appendChild(newItem);
}
else if (navigator.family == 'ie4')
{
if (!parentElement)
parentElement = document.body;
parentElement.insertAdjacentHTML('beforeEnd', '');
newItem = document.all['lItem' + _item_id];
}
else if (navigator.family == 'nn4')
{
if (parentElement)
newItem = new Layer(parentList.width, parentElement);
else
newItem = new Layer(parentList.width);
}
}
return newItem;
}
function addItem(str, bgColor)
{
var item;
item = getNewItem(this);
if (!item)
return;
if (bgColor)
item.oBgColor = bgColor;
this.items[this.items.length] = item;
this.types[this.types.length] = 'item';
this.strs[this.strs.length] = str;
++_item_id;
}
function addList(list, str, bgColor)
{
var item;
item = getNewItem(this);
if (!item)
return;
if (bgColor)
item.oBgColor = bgColor;
this.lists[this.items.length] = list;
this.items[this.items.length] = item;
this.types[this.types.length] = 'list';
this.strs[this.strs.length] = str;
++_item_id;
list.parentList = this;
}
List.prototype.setIndent = setIndent;
List.prototype.addItem = addItem;
List.prototype.addList = addList;
List.prototype.build = build;
List.prototype.rebuild = rebuild;
List.prototype.setFont = _listSetFont;
List.prototype._writeList = _writeList;
List.prototype._showList = _showList;
List.prototype._updateList = _updateList;
List.prototype._updateParent = _updateParent;
List.prototype.onexpand = null;
List.prototype.postexpand = null;
List.prototype.lists = null; // sublists
List.prototype.items = null; // layers
List.prototype.types = null; // type
List.prototype.strs = null; // content
List.prototype.x = 0;
List.prototype.y = 0;
List.prototype.visible = false;
List.prototype.id = -1;
List.prototype.i = 18;
List.prototype.space = true;
List.prototype.pid = 0;
List.prototype.fontIntro = false;
List.prototype.fontOutro = false;
List.prototype.width = 350;
List.prototype.height = 22;
List.prototype.built = false;
List.prototype.shown = false;
List.prototype.needsUpdate = false;
List.prototype.needsRewrite = false;
List.prototype.l = 0;
List.prototype.bgColor = null;
List.prototype.parentList = null;
List.prototype.parentElement = null;
/////////////////////////////////////////////////////////////
filename: xbStyle.js
////////////////////////////////////////////////////////////
/*
The contents of this file are subject to the Netscape Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Initial Developer of the Original Code is Bob Clary.
Contributor(s): Bob Clary, Original Work, Copyright 1999-2000
Bob Clary, Netscape Communications, Copyright 2001
Alternatively, the contents of this file may be used under the
terms of the GNU Public License (the "GPL"), in which case the
provisions of the GPL are applicable instead of those above.
If you wish to allow use of your version of this file only
under the terms of the GPL and not to allow others to use your
version of this file under the NPL, indicate your decision by
deleting the provisions above and replace them with the notice
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the NPL or the GPL.
Change Log:
2001-07-19: bclary - fixed function cssStyleGetLeft() and cssStyleGetTop() to
correctly handle the case where the initial style.left/style.top
are not initialized. This fixes positioning for relatively positioned
DIVS and as a result fixes behavior for ILAYERs exposed as relatively
positioned divs.
*/
if (!(navigator.DOMHTML || navigator.family == 'ie4' || navigator.family == 'nn4'))
{
alert('Your browser does not support DOM1, Internet Explorer 4 or Navigator 4. You will not be able to use xbStyle');
window.history.go(-1);
}
function noop() {}
function getWindowWidth()
{
var width = 0;
if(navigator.family == 'nn4' || navigator.family == 'gecko')
width = window.innerWidth;
else if (navigator.family == 'ie4')
width = document.body.clientWidth;
return width;
}
function getWindowHeight()
{
var height = 0;
if(navigator.family == 'nn4' || navigator.family == 'gecko')
height = window.innerHeight;
else if (navigator.family == 'ie4')
height = document.body.clientHeight;
return height;
}
function nav4GetLayerById(id)
{
return nav4FindLayer(this, id);
}
function nav4FindLayer(doc, id)
{
var i;
var subdoc;
var obj;
for (i = 0; i < doc.layers.length; ++i)
{
if (doc.layers[i].id && id == doc.layers[i].id)
return doc.layers[i];
subdoc = doc.layers[i].document;
obj = nav4FindLayer(subdoc, id);
if (obj != null)
return obj;
}
return null;
}
if (navigator.family == 'ie4' && navigator.version < 5)
document.getElementById = new Function("id", "return document.all[id];");
else if (navigator.family == 'nn4')
document.getElementById = nav4GetLayerById;
/////////////////////////////////////////////////////////////
// xbClipRect
function xbClipRect(a1, a2, a3, a4)
{
this.top = 0;
this.right = 0;
this.bottom = 0;
this.left = 0;
if (typeof(a1) == 'string')
{
var val;
var ca;
var i;
if (a1.indexOf('rect(') == 0)
{
ca = a1.substring(5, a1.length-1).split(' ');
for (i = 0; i < 4; ++i)
{
val = parseInt(ca[i]);
if (val != 0 && ca[i].indexOf('px') == -1)
if (!confirm('A clipping region ' + a1 + ' was detected that did not use pixels as units. Click Ok to continue, Cancel to Abort'))
return;
ca[i] = val;
}
this.top = ca[0];
this.right = ca[1];
this.bottom = ca[2];
this.left = ca[3];
}
}
else if (typeof(a1) == 'number' && typeof(a2) == 'number' && typeof(a3) == 'number' && typeof(a4) == 'number')
{
this.top = a1;
this.right = a2;
this.bottom = a3;
this.left = a4;
}
}
xbClipRect.prototype.top = 0;
xbClipRect.prototype.right = 0;
xbClipRect.prototype.bottom = 0;
xbClipRect.prototype.left = 0;
function xbClipRectSetWidth(width)
{
this.right = this.left + width;
}
xbClipRect.prototype.setWidth = xbClipRectSetWidth;
function xbClipRectSetHeight(height)
{
this.bottom = this.top + height;
}
xbClipRect.prototype.setHeight = xbClipRectSetHeight;
function xbClipRectToString()
{
return 'rect(' + this.top + ' ' + this.right + ' ' + this.bottom + ' ' + this.left + ' ' + ')' ;
}
xbClipRect.prototype.toString = xbClipRectToString;
/////////////////////////////////////////////////////////////
// xbStyle
function xbStyle(obj, position)
{
if (navigator.DOMCSS1)
this.styleObj = obj.style;
else if (navigator.family == 'nn4')
{
if (typeof(position) == 'undefined')
position = '';
this.styleObj = obj;
this.styleObj.position = position;
}
this.object = obj;
}
xbStyle.prototype.styleObj = null;
xbStyle.prototype.object = null;
/////////////////////////////////////////////////////////////
// xbStyle.getClip()
function cssStyleGetClip()
{
return this.styleObj.clip;
}
function nsxbStyleGetClip()
{
var rect = new xbClipRect(this.styleObj.clip.top, this.styleObj.clip.right, this.styleObj.clip.bottom, this.styleObj.clip.left);
return rect.toString();
}
/////////////////////////////////////////////////////////////
// xbStyle.setClip()
function cssStyleSetClip(sClipString)
{
this.styleObj.clip = sClipString;
}
function nsxbStyleSetClip(sClipString)
{
var rect = new xbClipRect(sClipString);
this.styleObj.clip.top = rect.top;
this.styleObj.clip.right = rect.right;
this.styleObj.clip.bottom = rect.bottom;
this.styleObj.clip.left = rect.left;
}
/////////////////////////////////////////////////////////////
// xbStyle.getClipTop()
function cssStyleGetClipTop()
{
var rect = new xbClipRect(this.styleObj.clip);
return rect.top;
}
function nsxbStyleGetClipTop()
{
return this.styleObj.clip.top;
}
/////////////////////////////////////////////////////////////
// xbStyle.setClipTop()
function cssStyleSetClipTop(top)
{
var rect = new xbClipRect(this.styleObj.clip);
rect.top = top;
this.styleObj.clip = rect.toString();
}
function nsxbStyleSetClipTop(top)
{
return this.styleObj.clip.top = top;
}
/////////////////////////////////////////////////////////////
// xbStyle.getClipRight()
function cssStyleGetClipRight()
{
var rect = new xbClipRect(this.styleObj.clip);
return rect.right;
}
function nsxbStyleGetClipRight()
{
return this.styleObj.clip.right;
}
/////////////////////////////////////////////////////////////
// xbStyle.setClipRight()
function cssStyleSetClipRight(right)
{
var rect = new xbClipRect(this.styleObj.clip);
rect.right = right;
this.styleObj.clip = rect.toString();
}
function nsxbStyleSetClipRight(right)
{
return this.styleObj.clip.right = right;
}
/////////////////////////////////////////////////////////////
// xbStyle.getClipBottom()
function cssStyleGetClipBottom()
{
var rect = new xbClipRect(this.styleObj.clip);
return rect.bottom;
}
function nsxbStyleGetClipBottom()
{
return this.styleObj.clip.bottom;
}
/////////////////////////////////////////////////////////////
// xbStyle.setClipBottom()
function cssStyleSetClipBottom(bottom)
{
var rect = new xbClipRect(this.styleObj.clip);
rect.bottom = bottom;
this.styleObj.clip = rect.toString();
}
function nsxbStyleSetClipBottom(bottom)
{
return this.styleObj.clip.bottom = bottom;
}
/////////////////////////////////////////////////////////////
// xbStyle.getClipLeft()
function cssStyleGetClipLeft()
{
var rect = new xbClipRect(this.styleObj.clip);
return rect.left;
}
function nsxbStyleGetClipLeft()
{
return this.styleObj.clip.left;
}
/////////////////////////////////////////////////////////////
// xbStyle.setClipLeft()
function cssStyleSetClipLeft(left)
{
var rect = new xbClipRect(this.styleObj.clip);
rect.left = left;
this.styleObj.clip = rect.toString();
}
function nsxbStyleSetClipLeft(left)
{
return this.styleObj.clip.left = left;
}
/////////////////////////////////////////////////////////////
// xbStyle.getClipWidth()
function cssStyleGetClipWidth()
{
var rect = new xbClipRect(this.styleObj.clip);
return rect.getWidth();
}
function nsxbStyleGetClipWidth()
{
return this.styleObj.clip.width;
}
/////////////////////////////////////////////////////////////
// xbStyle.setClipWidth()
function cssStyleSetClipWidth(width)
{
var rect = new xbClipRect(this.styleObj.clip);
rect.setWidth(width);
this.styleObj.clip = rect.toString();
}
function nsxbStyleSetClipWidth(width)
{
return this.styleObj.clip.width = width;
}
/////////////////////////////////////////////////////////////
// xbStyle.getClipHeight()
function cssStyleGetClipHeight()
{
var rect = new xbClipRect(this.styleObj.clip);
return rect.getHeight();
}
function nsxbStyleGetClipHeight()
{
return this.styleObj.clip.height;
}
/////////////////////////////////////////////////////////////
// xbStyle.setClipHeight()
function cssStyleSetClipHeight(height)
{
var rect = new xbClipRect(this.styleObj.clip);
rect.setHeight(height);
this.styleObj.clip = rect.toString();
}
function nsxbStyleSetClipHeight(height)
{
return this.styleObj.clip.height = height;
}
// the CSS attributes left,top are for absolutely positioned elements
// measured relative to the containing element. for relatively positioned
// elements, left,top are measured from the element's normal inline position.
// getLeft(), setLeft() operate on this type of coordinate.
//
// to allow dynamic positioning the getOffsetXXX and setOffsetXXX methods are
// defined to return and set the position of either an absolutely or relatively
// positioned element relative to the containing element.
//
//
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getLeft()
function cssStyleGetLeft()
{
var left = this.styleObj.left;
if (left != '' && left.indexOf('px') == -1)
if (!confirm('DIV ID=' + this.object.id + ' does not use pixels as units. left=' + left + ' Click Ok to continue, Cancel to Abort'))
return 0;
if (left == '')
this.styleObj.left = '0px';
return parseInt('0' + this.styleObj.left, 10);
}
function nsxbStyleGetLeft()
{
return this.styleObj.left;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setLeft()
function cssStyleSetLeft(left)
{
this.styleObj.left = left + 'px';
}
function nsxbStyleSetLeft(left)
{
this.styleObj.left = left;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getTop()
function cssStyleGetTop()
{
var top = this.styleObj.top;
if (top != '' && top.indexOf('px') == -1)
if (!confirm('DIV ID=' + this.object.id + ' does not use pixels as units. top=' + top + ' Click Ok to continue, Cancel to Abort'))
return 0;
if (top == '')
this.styleObj.top = '0px';
return parseInt('0' + this.styleObj.top, 10);
}
function nsxbStyleGetTop()
{
return this.styleObj.top;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setTop()
function cssStyleSetTop(top)
{
this.styleObj.top = top + 'px';
}
function nsxbStyleSetTop(top)
{
this.styleObj.top = top;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getPageX()
function cssStyleGetPageX()
{
var x = 0;
var elm = this.object;
while (elm)
{
x += elm.offsetLeft;
elm = elm.offsetParent;
}
return x;
}
function nsxbStyleGetPageX()
{
return this.styleObj.pageX;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setPageX()
function cssStyleSetPageX(x)
{
var xParent = 0;
var elm = this.object.offsetParent;
while (elm)
{
xParent += elm.offsetLeft;
elm = elm.offsetParent;
}
this.setLeft(x - xParent);
}
function nsxbStyleSetPageX(x)
{
this.styleObj.pageX = x;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getPageY()
function cssStyleGetPageY()
{
var y = 0;
var elm = this.object;
while (elm)
{
y += elm.offsetLeft;
elm = elm.offsetParent;
}
return y;
}
function nsxbStyleGetPageY()
{
return this.styleObj.pageY;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setPageY()
function cssStyleSetPageY(y)
{
var yParent = 0;
var elm = this.object.offsetParent;
while (elm)
{
yParent += elm.offsetTop;
elm = elm.offsetParent;
}
this.setTop(y - yParent);
}
function nsxbStyleSetPageY(y)
{
this.styleObj.pageY = y;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getHeight()
function cssStyleGetHeight()
{
var height = this.styleObj.height;
if (height != '' && height.indexOf('px') == -1)
if (!confirm('DIV ID=' + this.object.id + ' does not use pixels as units. height=' + height + ' Click Ok to continue, Cancel to Abort'))
return 0;
height = parseInt('0' + this.styleObj.height, 10);
if (height == 0)
height = this.object.offsetHeight;
return height;
}
function nsxbStyleGetHeight()
{
return this.styleObj.clip.height;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setHeight()
function cssStyleSetHeight(height)
{
this.styleObj.height = height + 'px';
}
function nsxbStyleSetHeight(height)
{
this.styleObj.clip.height = height;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getWidth()
function cssStyleGetWidth()
{
var width = this.styleObj.width;
if (width != '' && width.indexOf('px') == -1)
if (!confirm('DIV ID=' + this.object.id + ' does not use pixels as units. width=' + width + ' Click Ok to continue, Cancel to Abort'))
return 0;
width = parseInt('0' + this.styleObj.width, 10);
if (width == 0)
width = this.object.offsetWidth;
return width;
}
function nsxbStyleGetWidth()
{
return this.styleObj.clip.width;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setWidth()
function cssStyleSetWidth(width)
{
this.styleObj.width = width + 'px';
}
// netscape will not dynamically change the width of a
// layer. It will only happen upon a refresh.
function nsxbStyleSetWidth(width)
{
this.styleObj.clip.width = width;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getVisibility()
function cssStyleGetVisibility()
{
return this.styleObj.visibility;
}
function nsxbStyleGetVisibility()
{
switch(this.styleObj.visibility)
{
case 'hide':
return 'hidden';
case 'show':
return 'visible';
}
return '';
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setVisibility()
function cssStyleSetVisibility(visibility)
{
this.styleObj.visibility = visibility;
}
function nsxbStyleSetVisibility(visibility)
{
switch(visibility)
{
case 'hidden':
visibility = 'hide';
break;
case 'visible':
visibility = 'show';
break;
case 'inherit':
break;
default:
visibility = 'show';
break;
}
this.styleObj.visibility = visibility;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getzIndex()
function cssStyleGetzIndex()
{
return this.styleObj.zIndex;
}
function nsxbStyleGetzIndex()
{
return this.styleObj.zIndex;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setzIndex()
function cssStyleSetzIndex(zIndex)
{
this.styleObj.zIndex = zIndex;
}
function nsxbStyleSetzIndex(zIndex)
{
this.styleObj.zIndex = zIndex;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getBackgroundColor()
function cssStyleGetBackgroundColor()
{
return this.styleObj.backgroundColor;
}
function nsxbStyleGetBackgroundColor()
{
return this.styleObj.bgColor;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setBackgroundColor()
function cssStyleSetBackgroundColor(color)
{
this.styleObj.backgroundColor = color;
}
function nsxbStyleSetBackgroundColor(color)
{
if (color)
{
this.styleObj.bgColor = color;
this.object.document.bgColor = color;
this.resizeTo(this.getWidth(), this.getHeight());
}
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.getColor()
function cssStyleGetColor()
{
return this.styleObj.color;
}
function nsxbStyleGetColor()
{
return '#ffffff';
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setColor()
function cssStyleSetColor(color)
{
this.styleObj.color = color;
}
function nsxbStyleSetColor(color)
{
this.object.document.fgColor = color;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.moveAbove()
function xbStyleMoveAbove(cont)
{
this.setzIndex(cont.getzIndex()+1);
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.moveBelow()
function xbStyleMoveBelow(cont)
{
var zindex = cont.getzIndex() - 1;
if (zindex < 0)
zindex = 0;
this.setzIndex(zindex);
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.moveBy()
function xbStyleMoveBy(deltaX, deltaY)
{
this.moveTo(this.getLeft() + deltaX, this.getTop() + deltaY);
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.moveTo()
function xbStyleMoveTo(x, y)
{
this.setLeft(x);
this.setTop(y);
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.resizeBy()
function xbStyleResizeBy(deltaX, deltaY)
{
this.setWidth( this.getWidth() + deltaX );
this.setHeight( this.getHeight() + deltaY );
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.resizeTo()
function xbStyleResizeTo(x, y)
{
this.setWidth(x);
this.setHeight(y);
}
////////////////////////////////////////////////////////////////////////
// Navigator 4.x resizing...
function nsxbStyleOnresize()
{
if (saveInnerWidth != getWindowWidth() || saveInnerHeight != getWindowHeight())
location.reload();
return false;
}
/////////////////////////////////////////////////////////////////////////////
// xbStyle.setInnerHTML()
function xbSetInnerHTML(str)
{
if (typeof(this.object.innerHTML) != 'undefined')
this.object.innerHTML = str;
}
function nsxbSetInnerHTML(str)
{
this.object.document.write(str);
this.object.document.close();
}
////////////////////////////////////////////////////////////////////////
xbStyle.prototype.moveAbove = xbStyleMoveAbove;
xbStyle.prototype.moveBelow = xbStyleMoveBelow;
xbStyle.prototype.moveBy = xbStyleMoveBy;
xbStyle.prototype.moveTo = xbStyleMoveTo;
xbStyle.prototype.resizeBy = xbStyleResizeBy;
xbStyle.prototype.resizeTo = xbStyleResizeTo;
if (navigator.DOMCSS1)
{
xbStyle.prototype.getClip = cssStyleGetClip;
xbStyle.prototype.setClip = cssStyleSetClip;
xbStyle.prototype.getClipTop = cssStyleGetClipTop;
xbStyle.prototype.setClipTop = cssStyleSetClipTop;
xbStyle.prototype.getClipRight = cssStyleGetClipRight;
xbStyle.prototype.setClipRight = cssStyleSetClipRight;
xbStyle.prototype.getClipBottom = cssStyleGetClipBottom;
xbStyle.prototype.setClipBottom = cssStyleSetClipBottom;
xbStyle.prototype.getClipLeft = cssStyleGetClipLeft;
xbStyle.prototype.setClipLeft = cssStyleSetClipLeft;
xbStyle.prototype.getClipWidth = cssStyleGetClipWidth;
xbStyle.prototype.setClipWidth = cssStyleSetClipWidth;
xbStyle.prototype.getClipHeight = cssStyleGetClipHeight;
xbStyle.prototype.setClipHeight = cssStyleSetClipHeight;
xbStyle.prototype.getLeft = cssStyleGetLeft;
xbStyle.prototype.setLeft = cssStyleSetLeft;
xbStyle.prototype.getTop = cssStyleGetTop;
xbStyle.prototype.setTop = cssStyleSetTop;
xbStyle.prototype.getPageX = cssStyleGetPageX;
xbStyle.prototype.setPageX = cssStyleSetPageX;
xbStyle.prototype.getPageY = cssStyleGetPageY;
xbStyle.prototype.setPageY = cssStyleSetPageY;
xbStyle.prototype.getVisibility = cssStyleGetVisibility;
xbStyle.prototype.setVisibility = cssStyleSetVisibility;
xbStyle.prototype.getzIndex = cssStyleGetzIndex;
xbStyle.prototype.setzIndex = cssStyleSetzIndex;
xbStyle.prototype.getHeight = cssStyleGetHeight;
xbStyle.prototype.setHeight = cssStyleSetHeight;
xbStyle.prototype.getWidth = cssStyleGetWidth;
xbStyle.prototype.setWidth = cssStyleSetWidth;
xbStyle.prototype.getBackgroundColor = cssStyleGetBackgroundColor;
xbStyle.prototype.setBackgroundColor = cssStyleSetBackgroundColor;
xbStyle.prototype.getColor = cssStyleGetColor;
xbStyle.prototype.setColor = cssStyleSetColor;
xbStyle.prototype.setInnerHTML = xbSetInnerHTML;
}
else if (navigator.family == 'nn4')
{
xbStyle.prototype.getClip = nsxbStyleGetClip;
xbStyle.prototype.setClip = nsxbStyleSetClip;
xbStyle.prototype.getClipTop = nsxbStyleGetClipTop;
xbStyle.prototype.setClipTop = nsxbStyleSetClipTop;
xbStyle.prototype.getClipRight = nsxbStyleGetClipRight;
xbStyle.prototype.setClipRight = nsxbStyleSetClipRight;
xbStyle.prototype.getClipBottom = nsxbStyleGetClipBottom;
xbStyle.prototype.setClipBottom = nsxbStyleSetClipBottom;
xbStyle.prototype.getClipLeft = nsxbStyleGetClipLeft;
xbStyle.prototype.setClipLeft = nsxbStyleSetClipLeft;
xbStyle.prototype.getClipWidth = nsxbStyleGetClipWidth;
xbStyle.prototype.setClipWidth = nsxbStyleSetClipWidth;
xbStyle.prototype.getClipHeight = nsxbStyleGetClipHeight;
xbStyle.prototype.setClipHeight = nsxbStyleSetClipHeight;
xbStyle.prototype.getLeft = nsxbStyleGetLeft;
xbStyle.prototype.setLeft = nsxbStyleSetLeft;
xbStyle.prototype.getTop = nsxbStyleGetTop;
xbStyle.prototype.setTop = nsxbStyleSetTop;
xbStyle.prototype.getPageX = nsxbStyleGetPageX;
xbStyle.prototype.setPageX = nsxbStyleSetPageX;
xbStyle.prototype.getPageY = nsxbStyleGetPageY;
xbStyle.prototype.setPageY = nsxbStyleSetPageY;
xbStyle.prototype.getVisibility = nsxbStyleGetVisibility;
xbStyle.prototype.setVisibility = nsxbStyleSetVisibility;
xbStyle.prototype.getzIndex = nsxbStyleGetzIndex;
xbStyle.prototype.setzIndex = nsxbStyleSetzIndex;
xbStyle.prototype.getHeight = nsxbStyleGetHeight;
xbStyle.prototype.setHeight = nsxbStyleSetHeight;
xbStyle.prototype.getWidth = nsxbStyleGetWidth;
xbStyle.prototype.setWidth = nsxbStyleSetWidth;
xbStyle.prototype.getBackgroundColor = nsxbStyleGetBackgroundColor;
xbStyle.prototype.setBackgroundColor = nsxbStyleSetBackgroundColor;
xbStyle.prototype.getColor = nsxbStyleGetColor;
xbStyle.prototype.setColor = nsxbStyleSetColor;
xbStyle.prototype.setInnerHTML = nsxbSetInnerHTML;
window.saveInnerWidth = window.innerWidth;
window.saveInnerHeight = window.innerHeight;
window.onresize = nsxbStyleOnresize;
}
else
{
xbStyle.prototype.toString = noop;
xbStyle.prototype.getClip = noop;
xbStyle.prototype.setClip = noop;
xbStyle.prototype.getClipTop = noop;
xbStyle.prototype.setClipTop = noop;
xbStyle.prototype.getClipRight = noop;
xbStyle.prototype.setClipRight = noop;
xbStyle.prototype.getClipBottom = noop;
xbStyle.prototype.setClipBottom = noop;
xbStyle.prototype.getClipLeft = noop;
xbStyle.prototype.setClipLeft = noop;
xbStyle.prototype.getClipWidth = noop;
xbStyle.prototype.setClipWidth = noop;
xbStyle.prototype.getClipHeight = noop;
xbStyle.prototype.setClipHeight = noop;
xbStyle.prototype.getLeft = noop;
xbStyle.prototype.setLeft = noop;
xbStyle.prototype.getTop = noop;
xbStyle.prototype.setTop = noop;
xbStyle.prototype.getVisibility = noop;
xbStyle.prototype.setVisibility = noop;
xbStyle.prototype.getzIndex = noop;
xbStyle.prototype.setzIndex = noop;
xbStyle.prototype.getHeight = noop;
xbStyle.prototype.setHeight = noop;
xbStyle.prototype.getWidth = noop;
xbStyle.prototype.setWidth = noop;
xbStyle.prototype.getBackgroundColor = noop;
xbStyle.prototype.setBackgroundColor = noop;
xbStyle.prototype.getColor = noop;
xbStyle.prototype.setColor = noop;
xbStyle.prototype.setInnerHTML = noop;
}
/////////////////////////////////////////////////////////////////////
filename: ua.js
/////////////////////////////////////////////////////////////////////
/*
The contents of this file are subject to the Netscape Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Initial Developer of the Original Code is Bob Clary.
Contributor(s): Bob Clary, Original Work, Copyright 1999-2000
Bob Clary, Netscape Communications, Copyright 2001
Alternatively, the contents of this file may be used under the
terms of the GNU Public License (the "GPL"), in which case the
provisions of the GPL are applicable instead of those above.
If you wish to allow use of your version of this file only
under the terms of the GPL and not to allow others to use your
version of this file under the NPL, indicate your decision by
deleting the provisions above and replace them with the notice
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the NPL or the GPL.
*/
// work around bug in xpcdom Mozilla 0.9.1
window.saveNavigator = window.navigator;
// Handy functions
function noop() {}
function noerror() { return true; }
function defaultOnError(msg, url, line)
{
// customize this for your site
if (top.location.href.indexOf('_files/errors/') == -1)
top.location = '/evangelism/xbProjects/_files/errors/index.html?msg=' + escape(msg) + '&url=' + escape(url) + '&line=' + escape(line);
}
// Display Error page...
// XXX: more work to be done here
//
function reportError(message)
{
// customize this for your site
if (top.location.href.indexOf('_files/errors/') == -1)
top.location = '/evangelism/xbProjects/_files/errors/index.html?msg=' + escape(message);
}
function pageRequires(cond, msg, redirectTo)
{
if (!cond)
{
msg = 'This page requires ' + msg;
top.location = redirectTo + '?msg=' + escape(msg);
}
// return cond so can use in onclick handlers to exclude browsers
// from pages they do not support.
return cond;
}
function detectBrowser()
{
var oldOnError = window.onerror;
var element = null;
window.onerror = defaultOnError;
navigator.OS = '';
navigator.version = 0;
navigator.org = '';
navigator.family = '';
var platform;
if (typeof(window.navigator.platform) != 'undefined')
{
platform = window.navigator.platform.toLowerCase();
if (platform.indexOf('win') != -1)
navigator.OS = 'win';
else if (platform.indexOf('mac') != -1)
navigator.OS = 'mac';
else if (platform.indexOf('unix') != -1 || platform.indexOf('linux') != -1 || platform.indexOf('sun') != -1)
navigator.OS = 'nix';
}
var i = 0;
var ua = window.navigator.userAgent.toLowerCase();
if (ua.indexOf('opera') != -1)
{
i = ua.indexOf('opera');
navigator.family = 'opera';
navigator.org = 'opera';
navigator.version = parseFloat('0' + ua.substr(i+6), 10);
}
else if ((i = ua.indexOf('msie')) != -1)
{
navigator.org = 'microsoft';
navigator.version = parseFloat('0' + ua.substr(i+5), 10);
if (navigator.version < 4)
navigator.family = 'ie3';
else
navigator.family = 'ie4'
}
else if (typeof(window.controllers) != 'undefined' && typeof(window.locationbar) != 'undefined')
{
i = ua.lastIndexOf('/')
navigator.version = parseFloat('0' + ua.substr(i+1), 10);
navigator.family = 'gecko';
if (ua.indexOf('netscape') != -1)
navigator.org = 'netscape';
else if (ua.indexOf('compuserve') != -1)
navigator.org = 'compuserve';
else
navigator.org = 'mozilla';
}
else if ((ua.indexOf('mozilla') !=-1) && (ua.indexOf('spoofer')==-1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera')==-1)&& (ua.indexOf('webtv')==-1) && (ua.indexOf('hotjava')==-1))
{
var is_major = parseFloat(navigator.appVersion);
if (is_major < 4)
navigator.version = is_major;
else
{
i = ua.lastIndexOf('/')
navigator.version = parseFloat('0' + ua.substr(i+1), 10);
}
navigator.org = 'netscape';
navigator.family = 'nn' + parseInt(navigator.appVersion);
}
else if ((i = ua.indexOf('aol')) != -1 )
{
// aol
navigator.family = 'aol';
navigator.org = 'aol';
navigator.version = parseFloat('0' + ua.substr(i+4), 10);
}
navigator.DOMCORE1 = (typeof(document.getElementsByTagName) != 'undefined' && typeof(document.createElement) != 'undefined');
navigator.DOMCORE2 = (navigator.DOMCORE1 && typeof(document.getElementById) != 'undefined' && typeof(document.createElementNS) != 'undefined');
navigator.DOMHTML = (navigator.DOMCORE1 && typeof(document.getElementById) != 'undefined');
navigator.DOMCSS1 = ( (navigator.family == 'gecko') || (navigator.family == 'ie4') );
navigator.DOMCSS2 = false;
if (navigator.DOMCORE1)
{
element = document.createElement('p');
navigator.DOMCSS2 = (typeof(element.style) == 'object');
}
navigator.DOMEVENTS = (typeof(document.createEvent) != 'undefined');
window.onerror = oldOnError;
}
detectBrowser();
//////////////////////////////////////////////////////////////
There you go. As you can probably tell because of the open source licences I didn't write these, but they're free and they work.
This is used here...
http://www.technoimbiber.co.uk
Javascript dynamic menu
Titania (gone for lunch) Posted Oct 26, 2002
Goodness me...
DoctorMO - your menu is one of the 'cleanest' ones I've seen, exactly what I'm after
Pastey - would you happen to have an example of what yours looks like?
Thanks for the response!
Javascript dynamic menu
Titania (gone for lunch) Posted Oct 26, 2002
Oh - sorry - now I see the link Pastey! *rubs eyes*
Very nice looking!
...but I'm looking for something... something... that looks more - uh - don't know how to describe it - containing as few colours and gifs as possible?
Javascript dynamic menu
Pastey Posted Oct 26, 2002
What exactly do you want the menu for?
Is there a site we can look at with a current menu so we can get the idea? Add to that what you want the menu to be able to do? One of hte best ways is to just start rambling on about what you'd like and then we might, well you never know, be able to help
Javascript dynamic menu
Titania (gone for lunch) Posted Oct 26, 2002
Whoppeeeee! Yihaaaa! Yes! Yes! Yes!
*delirious with success*
I managed to find a script for a foldout menu that looked exactly like what I was looking for - and I managed to make it work!
..and I managed to find the correct sections so that I could change font sizes, and font colours, and margins...
Now I've only got 3 more questions:
1) Is there a way to add the VLINK function to a script? I'd like the already visited links to turn up in a different colour, so that previous visitors can easily see what I've added since their last visit...
2) Before I added the script, the text in my left frame (with the menu) wrapped itself according to the width I had set for the frame - all text was visible, and I didn't need to use any - but now some of the text is hidden by the scroll bar...
I've tried adjusting this section at the beginning of the code that goes inside my HEAD textbox:
Originally:
#divCont {position:absolute; z-index:1; left:50px; top:70px; height:400px; width:170px; visibility:hidden;}
.clTop {position:absolute; z-index:1; width:170px; line-height:17px;}
.clSub {position:absolute; z-index:1; left:0px; top:20px; width:170px; line-height:14px;}
Adjusted to:
#divCont {position:absolute; z-index:1; left:10px; top:100px; height:400px; width:145px; visibility:hidden;}
.clTop {position:absolute; z-index:1; width:155px; line-height:17px;}
.clSub {position:absolute; z-index:1; left:15px; top:20px; width:140px; line-height:14px;}
My frame width is 155, so I tried to make all width measures end up 155 put together...
3) The menu is now so short that I tried removing the scroll bar from the menu section by setting SCROLLING="no" - but there still remains a border between my 2 frames - how do I get rid of it? (changed it back to scroll bar yes for the time being)
I got the script from here:
http://www.dhtmlcentral.com/script/search.asp?category=menu
...and chose to use FoldoutMenu written 07/30/2001 by Thomas Brattli
...and my site is here:
http://hem.passagen.se/kristina.r
Javascript dynamic menu
Titania (gone for lunch) Posted Oct 26, 2002
Oh - and about the frame width - the size of the gif used for the foldout menu is 12
Javascript dynamic menu
DoctorMO (Keeper of the Computer, Guru, Community Artist) Posted Oct 27, 2002
Ah I see... thouse kind of menu's. Doh.
I've got a great place for you to vist... *Rumages though bookmarks*
http://www.ivanpeters.com/
you will find a great little menu system here that has been well tested, at least by me and many others.
p.s, for anyone woundering if you go the the microsoft website, there menus only work in IE, I got mine working in Netscape too Yipee.
-- DoctorMO --
Javascript dynamic menu
Zak T Duck Posted Oct 27, 2002
Possibly one of the easiest (but not the most cost efficient unless you can blag a copy off a friend) ways to do this would be to get yourself a copy of Fireworks as it allows you to create the graphics and the javascript code to do all the fancy mouseover effects too. The tutorials to do this should be in the accomanying help files, or can be worked out with a bit of dabbling.
Javascript dynamic menu
DoctorMO (Keeper of the Computer, Guru, Community Artist) Posted Oct 27, 2002
I thought it was free?
-- DoctorMO --
Javascript dynamic menu
Zak T Duck Posted Oct 27, 2002
The 30 day trial version is, if you want to use it after that you either need to pay for it or download the crack if you're of the dishonest persuasion.
Javascript dynamic menu
DoctorMO (Keeper of the Computer, Guru, Community Artist) Posted Oct 28, 2002
I gues that sorts that out then.
-- DoctorMO --
Key: Complain about this post
Javascript dynamic menu
- 1: Titania (gone for lunch) (Oct 25, 2002)
- 2: Tango (Oct 25, 2002)
- 3: DoctorMO (Keeper of the Computer, Guru, Community Artist) (Oct 25, 2002)
- 4: Pastey (Oct 26, 2002)
- 5: Titania (gone for lunch) (Oct 26, 2002)
- 6: Titania (gone for lunch) (Oct 26, 2002)
- 7: Pastey (Oct 26, 2002)
- 8: Titania (gone for lunch) (Oct 26, 2002)
- 9: Titania (gone for lunch) (Oct 26, 2002)
- 10: DoctorMO (Keeper of the Computer, Guru, Community Artist) (Oct 27, 2002)
- 11: Zak T Duck (Oct 27, 2002)
- 12: DoctorMO (Keeper of the Computer, Guru, Community Artist) (Oct 27, 2002)
- 13: Zak T Duck (Oct 27, 2002)
- 14: DoctorMO (Keeper of the Computer, Guru, Community Artist) (Oct 28, 2002)
More Conversations for The H2G2 Programmers' Corner
Write an Entry
"The Hitchhiker's Guide to the Galaxy is a wholly remarkable book. It has been compiled and recompiled many times and under many different editorships. It contains contributions from countless numbers of travellers and researchers."