﻿/*   G E N E R A L   */

function fdebug(fs) {
	// assumes there is a div element with id "debug"
	// displays the formal parameter string in that div.
	document.getElementById("debug").innerHTML = fs;
	}

function Clean (fS) {
	// remove leading and trailing white space
	for ( i=0;  i<fS.length-1;  i++) {
		if ((fS.charAt(i) != " ")&&(fS.charAt(i) != "\n")&&(fS.charAt(i) != "\t")) { break; };
		};
	for ( j=fS.length-1;  j>0;  j--) {
		if ((fS.charAt(j) != " ")&&(fS.charAt(j) != "\n")&&(fS.charAt(j) != "\t")) { break; };
		};
	return fS.substr(i,j-i+1);
	}



/*   H A N D L E   S V G   D R A W I N G S   */

/* 

Allow the user to move and zoom SVG drawings.
Dragging moves the drawing,
Option-dragging left-right zooms out-in from centre of drawing
Shift-clicking restores the original view.


Assume that SVG drawings are present in the page code with this structure:


<div id="SVGN-div" style="width: w; height: h; ">

<svg:svg id="SVGN-svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1"
    viewBox="0 0 vbw vbh"
    preserveAspectRatio="xMinYMin meet" >

<svg:g id="SVGN-OuterGroup" transform="translate(tx,ty) scale(s)">

	<svg:...

	... [svg code] ...

   </svg:g><!-- end of outer group -->

<svg:rect id="SVGN-Tracker" width="100%" height="100%" opacity="0"
	onload      = "SVGInitialise(event);"
    onmousedown = "SVGStartInteraction(event);"
    onmousemove = "SVGDoInteraction(event);"
    onmouseup   = "SVGStopInteraction(event);"
    onmouseout  = "SVGStopInteraction(event);"
	/>
</svg:svg>
</div>


Where:

N is a small integer, unique to each SVG,
w and h are the dimensions of the enclosing div element in em units
vbw and vbh are the sizes of the viewbox
SVGN-OuterGroup is the id of a group that is used exclusively for allowing
the user to translate and scale the drawing interactively.  The drawing
may be placed at a point tx,ty and on scale s so that the space in which
the user can zoom in is larger than the minimum rectangle around the svg. 
SVGN-Tracker is a rectangle that captures the user interaction.

The SVGN-Tracker rectangle triggers the onload event because the SVG elements
need to be loaded before the info can be accessed.

The SVG is rendered in a viewport of pixel dimensions pw,ph (the div) but declares
a viewbox of unit dimensions bw,bh.  We assume the preserveAspectRatio is always
set to "xMinYMin meet" so that the SVG is pushed into the upper left corner but made
as large as possible while still being viewed in total.  Thus:

For a rectangle of width w and height h the value w/h is >1 if it is "wide" and
it is <1 if it is "narrow".

if bw/bh < pw/ph the SVG looks "narrower" than the port; it will adopt the port's
height, leaving space at the right.  The viewbox height then corresponds to the
viewport's height and the unit factor (SVG units/pixel) is bh/ph.
When dragging the SVG around, the mouse distance m is in pixels and must be
multiplied by the unit factor to obtain the value for the translate transformation.

if bw/bh > pw/ph the SVG looks "wider" than the port; it will adopt the port's
width, leaving space at the bottom.  The unit factor is then bw/pw.

Because there is no reliable method of finding the position of the enclosing box,
zooming must be done around a point fixed to the SVG and not fixed at the point
where the mouse went down.

*/

// For all SVGs on the page:
// store the viewbox and viewport dimensions and keep the automatic scale

var SVGViewBoxWidth   = new Array ();  // from the code; never changes
var SVGViewBoxHeight  = new Array ();
var SVGOrgTranslateX  = new Array ();  // from the code; never changes
var SVGOrgTranslateY  = new Array ();
var SVGOrgScale       = new Array ();

var SVGViewPortWidth  = new Array ();  // may change when browser window is resized
var SVGViewPortHeight = new Array ();
var SVGUnitFactor     = new Array ();  // may change when browser window is resized

var SVGTranslateX     = new Array ();  // where the user left it interactively
var SVGTranslateY     = new Array ();
var SVGScale          = new Array ();  // where the user left it interactively

var SVGCurrentTranslateX = new Array ();  // for use during mouse moves only
var SVGCurrentTranslateY = new Array ();
var SVGCurrentScale      = new Array ();

var TheMouse = { IsDown: false, SVGN: -1, DownPointX: 0, DownPointY: 0, AltKey: false, ShiftKey: false };



function SVGNumber (fEvent) {

	// Returns the number of the SVG concerned by the event.
	// id is of the form "SVGN-Tracker" where N is a small integer.

	lFirstPart = fEvent.target.id.split("-");
	return lFirstPart[0].substr(3)*1;

	}



function SVGInitialise (fEvent) {

	// Set up the SVG viewing state for all SVGs in the page.
	// The original translate and scale may be different from (0,0) and 1, store them.
	// This routine is called at loading of the tracker of each SVG.
	// It is assumed that all SVGs have a different id.

	n = SVGNumber(fEvent);

	lOrgTransform = document.getElementById("SVG"+n+"-OuterGroup").getAttribute("transform");  // "translate(tx,ty) scale(s)"
	lTransPart = lOrgTransform.substr(10);  // "tx,ty) scale(s)"
	lTrans = lTransPart.substr( 0 , lTransPart.indexOf(")") );  // "tx,ty"
	lTransXY = lTrans.split(","); lTX = lTransXY[0]*1; lTY = lTransXY[1]*1;
	lTransPart = lTransPart.substr( 1+lTransPart.indexOf(")") );
	lScale = lTransPart.substring( 1+lTransPart.indexOf("(") , lTransPart.indexOf(")") )*1;  // "s"
	SVGOrgTranslateX[n]     = lTX; SVGOrgTranslateY[n]     = lTY; SVGOrgScale[n]     = lScale;
	SVGTranslateX[n]        = lTX; SVGTranslateY[n]        = lTY; SVGScale[n]        = lScale;
	SVGCurrentTranslateX[n] = lTX; SVGCurrentTranslateY[n] = lTY; SVGCurrentScale[n] = lScale;

	lViewBox = document.getElementById("SVG"+n+"-svg").getAttribute("viewBox");
	lViewBoxParts = lViewBox.split(" ");
	SVGViewBoxWidth[n] = lViewBoxParts[2]; SVGViewBoxHeight[n] = lViewBoxParts[3];

	}




function SVGStartInteraction (fEvent) {

	// Remember in which SVG and where the mouse went down and what modifier keys were down at that time.
	// Adjust the viewport dimensions and the unitfactor to the potentially resized window.

	TheMouse.IsDown = true;
	TheMouse.SVGN = n = SVGNumber(fEvent);
	TheMouse.DownPointX = fEvent.clientX; TheMouse.DownPointY = fEvent.clientY;
	TheMouse.AltKey = fEvent.altKey; TheMouse.ShiftKey = fEvent.shiftKey;
	// To calculate the current unit factor (SVG units / pixel) we need to update the viewport dimensions
	// since the window may have been resized:
	lDiv = document.getElementById("SVG"+n+"-div");
	SVGViewPortWidth[n] = lDiv.offsetWidth; SVGViewPortHeight[n] = lDiv.offsetHeight;
	// if bw/bh > pw/ph the SVG looks "wider" than the port; it will adopt the port's
	// width, leaving space at the bottom.  The unit factor is then bw/pw otherwise it is bh/ph.
	if ( SVGViewBoxWidth[n]/SVGViewBoxHeight[n] > SVGViewPortWidth[n]/SVGViewPortHeight[n] ) {
		SVGUnitFactor[n] = SVGCurrentScale[n]*SVGViewBoxWidth[n]/SVGViewPortWidth[n];
		}
	else {
		SVGUnitFactor[n] = SVGCurrentScale[n]*SVGViewBoxHeight[n]/SVGViewPortHeight[n];
		};
	// prepare for mousemoves:
	SVGCurrentTranslateX[n] = SVGTranslateX[n];
	SVGCurrentTranslateY[n] = SVGTranslateY[n];
	SVGCurrentScale[n]      = SVGScale[n];

	}



function SVGDoInteraction (fEvent) {

	// While the mouse moves the translate and scale are based on those in effect at the time of the mousedown.
	// The current values are updated so that they can replace the stored ones once the mouse goes up.
	if ( TheMouse.IsDown ) {
		n = SVGNumber(fEvent);
		lSVG = document.getElementById("SVG"+n+"-OuterGroup");
		lDeltaX = fEvent.clientX - TheMouse.DownPointX;
		lDeltaY = fEvent.clientY - TheMouse.DownPointY;
		if (TheMouse.AltKey) { // Zoom on the centre of the SVG
			lScale = SVGScale[n]*(SVGViewPortWidth[n] + lDeltaX)/SVGViewPortWidth[n];
			// the translate point is also affected since we scale around the centre of the SVG:
			lTX = SVGTranslateX[n] + SVGViewBoxWidth[n] *(SVGScale[n]-lScale)/2;
			lTY = SVGTranslateY[n] + SVGViewBoxHeight[n]*(SVGScale[n]-lScale)/2;
			lSVG.setAttribute("transform","translate("+lTX+","+lTY+") scale("+lScale+")");
			SVGCurrentTranslateX[n] = lTX; SVGCurrentTranslateY[n] = lTY;
			SVGCurrentScale[n] = lScale;
			}
		else { // Drag
			lTX = SVGTranslateX[n] + lDeltaX*SVGUnitFactor[n]/SVGScale[n];
			lTY = SVGTranslateY[n] + lDeltaY*SVGUnitFactor[n]/SVGScale[n];
			lSVG.setAttribute("transform","translate("+lTX+","+lTY+") scale("+SVGScale[n]+")");
			SVGCurrentTranslateX[n] = lTX; SVGCurrentTranslateY[n] = lTY;
			};
		};

	}



function SVGStopInteraction (fEvent) {

	// Clean up:
	n = SVGNumber(fEvent);
	if ( TheMouse.ShiftKey ) { // reset to original view
		lSVG = document.getElementById("SVG"+n+"-OuterGroup");
		lSVG.setAttribute("transform","translate("+SVGOrgTranslateX[n]+","+SVGOrgTranslateY[n]+") scale("+SVGOrgScale[n]+")");
		SVGCurrentTranslateX[n] = SVGTranslateX[n] = SVGOrgTranslateX[n];
		SVGCurrentTranslateY[n] = SVGTranslateY[n] = SVGOrgTranslateY[n];
		SVGCurrentScale[n]      = SVGScale[n]      = SVGOrgScale[n];
		}
	else { // store the state where the user left the drawing
		SVGTranslateX[n] = SVGCurrentTranslateX[n];
		SVGTranslateY[n] = SVGCurrentTranslateY[n];
		SVGScale[n]      = SVGCurrentScale[n];
		};
	TheMouse.IsDown = false;
	TheMouse.SVGN = -1;

	}




/*   S W I T C H   L A N G U A G E   */

/*
Each page has a sets of language-indicators (usually images).  A click on
such an indicator will take the reader to the corresponding page in that language.

Page structure:
---------------
<body onload="ShowLanguages();">
<div id="LanguagesList" style="display: none;">fr nl en</div>

<div>
<span id="LanguageIndicator-en" style="visibility: hidden;" onclick="SwitchLanguage('en');"> English </span>
<span id="LanguageIndicator-nl" style="visibility: hidden;" onclick="SwitchLanguage('nl');"> Nederlands </span>
<span id="LanguageIndicator-fr" style="visibility: hidden;" onclick="SwitchLanguage('fr');"> Français </span>
</div>

Conventions:
------------
The pages in different languages are next to each other at the same file system level.
They have the same names with a different ending:  -en for English, -fr for French etc.

How it works:
-------------
If the page exists in only one language no indicators appear.  A <div> in each page lists
the different language choices; thsi <div> is not displayed and can be set by program.
On loading of the page the contents of the <div> is inspected and indicators shown if
more than one language is present.
A click on an indicator calls "SwitchLanguage", passing a two letter code of the language as a parameter.
The script obtains the URL of the current page, replaces the current two letter code
with the desired two letter code.  It then loads that page with that newly constructed URL.

*/

function ShowLanguages () {
	// get the language of this document:
	lURLOfThisPage = document.location.href;
	lURLParts = lURLOfThisPage.split(".");
	nURLParts = lURLParts.length;
	lPartContainingLanguage = lURLParts[nURLParts-2];
	lLanguage = lPartContainingLanguage.substr(lPartContainingLanguage.length-2,2);
	// show all other language choices:
	lLanguagesList = document.getElementById("LanguagesList").firstChild.nodeValue;
	lLanguages = Clean(lLanguagesList).split(" ");
	for ( i=0; i<lLanguages.length; i++) {
		if ( lLanguages[i] != lLanguage ) {
			lIndicator = document.getElementById("LanguageIndicator-"+lLanguages[i]);
			if (lIndicator != null) { lIndicator.style.visibility = "visible"; };
			};
		};
	}


function SwitchLanguage (fLanguage) {
	// URL is of the form Xxxxxxxxxxxxx-ll.extension
	// where extension can be html or xhtml or svg or whatever, i.e. its length is not known.
	lURLOfThisPage = document.location.href;
	lURLParts = lURLOfThisPage.split(".");
	nURLParts = lURLParts.length;
	lPartContainingLanguage = lURLParts[nURLParts-2];
	lPartWithoutLanguage = lPartContainingLanguage.substr(0,lPartContainingLanguage.length-3);
	// make the new URL:
	lNewURL = "";
	for (i=0; i<nURLParts-2; i++){
		lNewURL = lNewURL + lURLParts[i];
		};
	window.location =  lNewURL + lPartWithoutLanguage + "-" + fLanguage + "." + lURLParts[nURLParts-1];
	}





// ---------------------  end  --------------------
