Monday, November 08, 2010 at 12:03 AM.

system.verbs.builtins.html.data.standardMacros.navbar

on navbar (outlineName, orientation="vertical", itemSeparator=" | ", lineSeparator="<p>", maxPerLine=nil, linkColor=nil, hoverColor=nil, boldLinks=false, boldCurrentPage=false, boldCategories=false, categoryColor=nil, showCategories=true, breakAtCategories=false, extraCategoryLine=false, indentSpaces=0, linkClass=nil, adrPageTable=nil, flXmlOutline=false) {
	<<This is a general macro for creating text-based navigation bars.
		<<Thu, May 14, 1998 at 4:57:12 PM by PBS
		<<The outlineName parameter should be the name of an outline that's in your #prefs table.
		<<This macro uses an outline in this form:
			<<[odb address or URL] [Text title]
			<<websites.mySite.default Home
			<<http://www.scripting.com/ Scripting News
		<<Any line that is a comment or has subheads is a category line.
			<<Categories are not links -- they're a type of header.
		<<Navbars can be horizontal or vertical.
		<<The current page is not a link.
	<<Changes:
		<<Thu, Dec 10, 1998 at 12:14:55 PM by PBS
			<<Added support for ftp links.
		<<Tue, 15 Jun 1999 21:24:43 GMT by DW and AR
			<<Bug fix: If the navbar is built from an old-style outline, we work on a copy to be thread-safe.
			<<Bug fix: If breakAtCategories is true, we no longer remove a random number of chars from the end of the last line before the new category.
			<<Added new optional parameter flXmlOutline to support XML-formatted outlines. We compile the outline to a structure, in the same table as the outline, with the same name, with "Structure" appended to the end of the name. We watch the mod date of the outline, if it hasn't changed since the last compilation, we don't recompile it. 
			<<Example XML outline:
				<<<navbar>
					<<<category title="Samples Site"/>
					<<<odb>websites.samples.default</odb>
					<<<odb title="Random Stuff">websites.samples.randomStuff</odb>
					<<<category title="Other Sites"/>
					<<<url title="Frontier">http://frontier.userland.com/</url>
					<<<glossref>Scripting News</glossref>
					<<</navbar>
	
	local (htmlText, indent);
	local (flVertical = (string.lower (orientation) == "vertical"));
	
	if indentSpaces > 0 {
		indent = string.filledString (" ", number (indentSpaces))};
	
	<<Try to convert link, hover, and category colors to a hex number.
	bundle {
		on convertColor (oneColor) {
			if defined (system.verbs.colors.[oneColor]) {
				return ("#" + system.verbs.colors.[oneColor])};
			return (oneColor)}; //PBS 12/16/98: support color parameters of the form #336699
		if linkColor != nil {
			linkColor = convertColor (linkColor)};
		if hoverColor != nil {
			hoverColor = convertColor (hoverColor)};
		if categoryColor != nil {
			categoryColor = convertColor (categoryColor)}};
	
	if maxPerLine == nil {
		maxPerLine = infinity};
	
	if adrPageTable == nil { //get the address of the current page table
		adrPageTable = html.getPageTableAddress ()};
	
	on add (s) { //add a string to the html text
		htmlText = htmlText + s};
	
	on addLineSeparator () { //add a line separator
		if lineCt != sizeOutline {
			add (lineSeparator + "\r");
			lastSeparatorLength = string.length (lineSeparator) + 1;
			itemCt = 0};
		return (true)};
	on addItemSeparator () { //add an item separator
		if lineCt != sizeOutline {
			add (itemSeparator);
			lastSeparatorLength = string.length (itemSeparator)};
		return (true)};
	on subtractLastSeparator () { //subtract an item separator
		<<An item separator is the last thing added.
		local (lenText = string.length (htmlText));
		htmlText = string.mid (htmlText, 1, lenText - lastSeparatorLength);
		return (true)};
	on addSeparators () { //add appropriate separator
		itemCt++;
		if flVertical { //it's a vertical navbar
			addLineSeparator ()}
		else { //it's a horizontal navbar, a little more complex
			if itemCt == maxPerLine {
				addLineSeparator ()}
			else {
				addItemSeparator ()}};
		return (true)};
	
	on addThisPage (s) { //add the current page
		if indent != nil {
			add (indent)};
		if boldCurrentPage {
			add ("<b>" + s + "</b>")}
		else {
			add (s)};
		return (true)};
	on addOneLink (s) { //add an anchor tag
		local (styleTag = "<span");
		
		if linkColor != nil { //add the link color
			styleTag = styleTag + " style=\"color: '" + linkColor + "'\""};
		if hoverColor != nil { //add the hover color
			<<Note: this requires that you have some JavaScript in your pageHeader.
				<<Like this:
					<<<script>
						<<<!--
							<<var oldcolor
							<<function highlight (s, highlightcolor) {
								<<oldcolor = s.style.color
								<<s.style.color = highlightcolor
								<<return (true)
								<<} //highlight
							<<function unhighlight (s) {
								<<s.style.color = oldcolor
								<<return (true)
								<<} //unhighlight
						<<-->
					<<</script>
			styleTag = styleTag + " onmouseover=\"highlight (this, '" + hoverColor + "')\" onmouseout=\"unhighlight (this)\""};
		
		styleTag = styleTag + ">";
		
		if styleTag != "<span>" { //only strip this in if we added something
			s = string.replace (s, ">", ">" + styleTag); //add the style
			s = string.replace (s, "</a>", "</span></a>")};
		
		if linkClass != nil {
			s = string.replace (s, "<a ", "<a class=\"" + linkClass + "\" ")};
		if indent != nil {
			add (indent)};
		if boldLinks {
			add ("<b>" + s + "</b>")}
		else {
			add (s)};
		return (true)};
	on addCategory (s) { //add a category
		if breakAtCategories and not (lineCt == 1) {
			subtractLastSeparator ();
			addLineSeparator ()};
		if showCategories {
			if extraCategoryLine and not (lineCt == 1) {
				add ("<br>")};
			if categoryColor != nil {
				s = "<font color=\"" + categoryColor + "\">" + s + "</font>"};
			if boldCategories {
				add ("<b>" + s + "</b>")}
			else {
				add (s)}}
		else {
			return (false)}; //we didn't add anything
		return (true)};
	
	local (itemCt = 0, lineCt=0, lastSeparatorLength = 0, flAdded);
	local (adrOutline = @adrPageTable^.[outlineName]^); //get the address of the outline
	
	if flXmlOutline {
		local (adrparent = parentof (adroutline^));
		local (adrstruct = @adrparent^.[nameof (adroutline^) + "Structure"]);
		
		bundle { //compile the outline if it changed
			local (flcompile = true);
			if defined (adrstruct^) {
				if timemodified (adrOutline) <= timemodified (adrstruct) {
					flcompile = false}};
			if flcompile {
				xml.compile (string (adrOutline^), adrstruct)}};
		
		local (adrNavbar = xml.getAddress (adrstruct, "navbar"));
		local (adritem, itemname);
		local (sizeOutline = sizeof (adrNavbar^));
		on getValue (adritem) {
			if defined (adritem^.["/pcdata"]) {
				return (adritem^.["/pcdata"])}
			else {
				return (adritem^)}};
		for lineCt = 1 to sizeOutline {
			flAdded = true;
			adritem = @adrNavbar^ [lineCt];
			itemname = string.nthField (nameOf (adritem^), "\t", 2);
			case itemname {
				"url" {
					local (linkTitle, reference = getValue (adritem));
					try {
						linkTitle = xml.getAttributeValue (adritem, "title")}
					else {
						linkTitle = reference};
					addOneLink (html.getLink (linkTitle, reference))};
				"odb" {
					local (reference = getValue (adritem));
					local (absoluteAddress = adrPageTable^.adrSiteRootTable + "." + reference);
					if defined (absoluteAddress^) { //the reference may be relative, for gdb support. PBS 10/26/98
						reference = absoluteAddress};
					if defined (reference^) {
						local (linkTitle);
						try {
							linkTitle = xml.getAttributeValue (adritem, "title")}
						else {
							linkTitle = html.getPagePref ("title", reference, adrPageTable)};
						if adrPageTable^.adrObject == address (reference) { //Does this refer the current page
							addThisPage (linkTitle)}
						else {
							addOneLink (html.getLink (linkTitle, html.getPath (adrPageTable^.adrObject, reference, adrPageTable)))}}
					else {
						scripterror ("Can't build the navbar because \"" + reference + "\" is not defined.")}};
				"glossref" {
					local (reference = getValue (adritem));
					try {
						local (linkTitle = xml.getAttributeValue (adritem, "title"));
						with adrPageTable^.tools^, user.html.macros, html.data.standardMacros {
							addOneLink (glossSub (reference, linkTitle))}}
					else {
						addOneLink (html.refGlossary (reference))}};
				"category" {
					flAdded = addCategory (xml.getAttributeValue (adritem, "title"))}}
			else {
				continue};
			if flAdded {
				addSeparators ()}}}
	else {
		local (localoutline = adrOutline^); //work on a copy for thread-safety
		local (sizeOutline = sizeOf (localoutline));
		local (oldTarget = target.set (@localoutline)); //set the target to this outline
		op.setDisplay (false);
		op.firstSummit (); //go to the top of the outline
		op.fullExpand (); //fully expand the outline (defensive driving -- it should be flat)
		
		local (oneLine, ixSpace, reference, linkTitle);
		loop { //loop through the outline, one line at a time
			on moveDown () {
				if not (op.go (flatdown, 1)) {
					break}};
			lineCt++;
			oneLine = op.getLineText ();
			if oneLine == "" { //it's an empty line
				moveDown ();
				continue};
			ixSpace = string.patternMatch (" ", oneLine);
			reference = string.mid (oneLine, 1, ixSpace - 1);
			linkTitle = string.mid (oneLine, ixSpace + 1, infinity);
			flAdded = true;
			local (oneLink);
			
			if script.isComment () or op.countSubs (1) > 0 { //is it a category?
				flAdded = addCategory (oneLine)} //the whole line is the category text
			else {
				if reference beginsWith "http://" or reference beginsWith "ftp://" { //is this an http or ftp link?
					 addOneLink (html.getLink (linkTitle, reference))}
				else {
					local (absoluteAddress = adrPageTable^.adrSiteRootTable + "." + reference);
					if defined (absoluteAddress^) { //the reference may be relative, for gdb support. PBS 10/26/98
						reference = absoluteAddress};
					if defined (reference^) or defined (adrRoot + "." + reference) { //is this a local reference?
						if adrPageTable^.adrObject == address (reference) { //Does this refer the current page
							addThisPage (linkTitle)}
						else {
							addOneLink (html.getLink (linkTitle, html.getPath (adrPageTable^.adrObject, reference, adrPageTable)))}}
					else { //is this an email address?
						if reference contains "@" and string.nthField (reference, '@', 2) contains "." {
							addOneLink ("<a href=\"mailto:" + reference + "\">" + linkTitle + "</a>")}
						else {
							flAdded = false}}}};
			
			if flAdded {
				addSeparators ()};
			
			moveDown ()}; //move down one line
		
		op.setDisplay (true);
		target.set (oldTarget)}; //restore the target
	
	return (htmlText)} //return the html



This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.