changeset 450:4255c09a8147

experimental intermediary release - more object-orientation in javascript - more changes afoot - reloading works properly - setting a mark reloads quickly
author robcast
date Mon, 23 Jan 2006 18:29:52 +0100
parents e01e9112adc3
children a6c83fa262b2
files client/digitallibrary/greyskin/baselib.js client/digitallibrary/greyskin/diginew.jsp client/digitallibrary/greyskin/dllib.js
diffstat 3 files changed, 485 insertions(+), 429 deletions(-) [+]
line wrap: on
line diff
--- a/client/digitallibrary/greyskin/baselib.js	Mon Jan 16 20:53:44 2006 +0100
+++ b/client/digitallibrary/greyskin/baselib.js	Mon Jan 23 18:29:52 2006 +0100
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003,2004 IT-Group MPIWG, WTWG Uni Bern and others
+/* Copyright (C) 2003-2006 IT-Group MPIWG, WTWG Uni Bern and others
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
@@ -17,13 +17,13 @@
 Authors: 
   Christian Luginbuehl, 01.05.2003 (first version)
   DW 24.03.2004 (Changed for digiLib in Zope)
-  Robert Casties, 2.11.2004
+  Robert Casties, 2.11.2004 (almost complete rewrite)
   Martin Raspe, 12.12.2005 (changes for Digilib NG)
 
 */
 
 // was: function base_init() {
-baseLibVersion = "2.008";
+baseLibVersion = "2.010";
 browserType = getBrowserType();
 
 sliders = {};
@@ -32,8 +32,7 @@
 function getInt(n) {
     // returns always an integer
     n = parseInt(n);
-    if (isNaN(n)) return 0;
-    return n;
+    return (isNaN(n)) ? 0 : n;
 }
 
 function defined(x) {
@@ -118,11 +117,19 @@
 Position.prototype.equals = function(other) {
 	return (this.x == other.x
         &&  this.y == other.y)
-    }
+}
 /*
  * Rectangle class
  */
 function Rectangle(x, y, w, h) {
+	if (typeof x == "object") {
+		// assume x and y are Position
+		this.x = x.x;
+		this.y = x.y;
+		this.width = y.x - x.x;
+		this.height = y.y - x.y;
+		return this;
+	}
     this.x = parseFloat(x);
     this.y = parseFloat(y);
     this.width = parseFloat(w);
@@ -141,19 +148,20 @@
     return new Position(this.x, this.y);
 }
 Rectangle.prototype.getPt1 = Rectangle.prototype.getPosition;
+// returns the upper left corner position
 
 Rectangle.prototype.getPt2 = function() {
-    // returns the second point position of this Rectangle
+    // returns the lower right corner position of this Rectangle
     return new Position(this.x + this.width, this.y + this.height);
 }
 Rectangle.prototype.setPt1 = function(pos) {
-    // sets the first point to position pos
+    // sets the upper left corner to position pos
     this.x = pos.x;
     this.y = pos.y;
     return this;
 }
 Rectangle.prototype.setPt2 = function(pos) {
-    // sets the second point to position pos
+    // sets the lower right corner to position pos
     this.width = pos.x - this.x;
     this.height = pos.y - this.y;
     return this;
@@ -201,11 +209,8 @@
 }
 Rectangle.prototype.containsRect = function(rect) {
     // returns if rectangle "rect" is contained in this rectangle
-    return (this.containsPosition(rect) 
-        && this.containsPosition(new Position(
-        rect.x + rect.width,
-        rect.y + rect.height
-        )));
+    return (this.containsPosition(rect.getPt1()) 
+        && this.containsPosition(rect.getPt2()));
 }
 Rectangle.prototype.stayInside = function(rect) {
     // changes this rectangle's x/y values so it stays inside of rectangle rect
@@ -220,9 +225,9 @@
 }
 Rectangle.prototype.clipTo = function(rect) {
     // clips this rectangle so it stays inside of rectangle rect
-    p1 = rect.getPt1();
-    p2 = rect.getPt2();
-    this2 = this.getPt2();
+    var p1 = rect.getPt1();
+    var p2 = rect.getPt2();
+    var this2 = this.getPt2();
     this.setPt1(new Position(Math.max(this.x, p1.x), Math.max(this.y, p1.y)));
     this.setPt2(new Position(Math.min(this2.x, p2.x), Math.min(this2.y, p2.y)));
     return this;
@@ -307,6 +312,11 @@
     var det = this.m00 * this.m11 - this.m01 * this.m10;
     var x = (this.m11 * pos.x - this.m01 * pos.y - this.m11 * this.m02 + this.m01 * this.m12) / det;
     var y = (- this.m10 * pos.x + this.m00 * pos.y + this.m10 * this.m02 - this.m00 * this.m12) / det;
+    if (pos.width) {
+        var width = (this.m11 * pos.width - this.m01 * pos.height - this.m11 * this.m02 + this.m01 * this.m12) / det;
+    		var height = (- this.m10 * pos.width + this.m00 * pos.height + this.m10 * this.m02 - this.m00 * this.m12) / det;
+    		return new Rectangle(x, y, width, height);
+    	}
     return new Position(x, y);
 }
 function getRotation(angle, pos) {
@@ -339,55 +349,56 @@
 }
 
 
-/* **********************************************
- *     parameter routines
- * ******************************************** */
-dlParams = new Object();
+/*
+ *  parameters class
+ */
 
-function newParameter(name, defaultValue, detail) {
+function Parameters() {
+	this.params = new Object();
+	return this;
+}
+Parameters.prototype.define = function(name, defaultValue, detail) {
     // create a new parameter with a name and a default value
-    if (!defined(dlParams[name])) dlParams[name] = new Object(); // no error condition
-        //alert("Fatal: An object with name '" + name + "' already exists - cannot recreate!");
-        //return false;
-    dlParams[name].defaultValue = defaultValue;
-    dlParams[name].hasValue = false;
-    dlParams[name].value = defaultValue;
-    dlParams[name].detail = detail;
-    return dlParams[name];
-    }
-
-function resetParameter(name) {
+    if (!this.params[name]) this.params[name] = new Object();
+    this.params[name].defaultValue = defaultValue;
+    this.params[name].hasValue = false;
+    this.params[name].value = defaultValue;
+    this.params[name].detail = detail;
+    return this.params[name];
+}
+Parameters.prototype.reset = function(name) {
     // resets the given parameter to its default value
-    if (!defined(dlParams[name])) {
-    alert("Could not reset non-existing parameter '" + name + "'");
-    return false;
-        }
-    dlParams[name].hasValue = false;
-    dlParams[name].value = defaultValue;
-    return dlParams[name];
-    }
-
-function deleteParameter(name) {
-    // create a new parameter with a name and a default value
-    if (!defined(dlParams[name])) return false;
-    delete dlParams[name];
-    return true;
+    if (!this.params[name]) {
+    		alert("Could not reset non-existing parameter '" + name + "'");
+		return false;
     }
-
-function getParameter(name) {
+    this.params[name].hasValue = false;
+    this.params[name].value = this.params[name].defaultValue;
+    return this.params[name];
+}
+Parameters.prototype.resetAll = function() {
+    // resets all parameters to their default values
+    for (var p in this.params) {
+    		this.reset(p);
+    	}
+    return true;
+}
+Parameters.prototype.remove = function(name) {
+    if (!defined(this.params[name])) return false;
+    delete this.params[name];
+    return true;
+}
+Parameters.prototype.get = function(name) {
     // returns the named parameter value or its default value
-    if (!defined(dlParams[name])) return null;
-    if (dlParams[name].hasValue)
-        return dlParams[name].value;
-    else
-            return dlParams[name].defaultValue;
-    }
-
-function setParameter(name, value, relative) {
-    // sets parameter value (relative values with +/- unless literal)
-    if (!defined(dlParams[name])) return null;
-    var p = dlParams[name];
+    if (!defined(this.params[name])) return null;
+    return this.params[name].hasValue ? this.params[name].value : this.params[name].defaultValue;
+}
+Parameters.prototype.set = function(name, value, relative) {
+    // sets parameter value (relative values with +/- if relative=true)
+    if (!defined(this.params[name])) return null;
+    var p = this.params[name];
     if (relative && value.slice) {
+    		// value is a string -- check if it starts with +/-
         var sign = value.slice(0, 1);
         if (sign == '+') {
             p.value = parseFloat(p.value) + parseFloat(value.slice(1));
@@ -396,47 +407,114 @@
         } else {
             p.value = value;
         }
-    } else p.value = value;
+    } else {
+    		p.value = value;
+    	}
     p.hasValue = true;
     return p.value;
-    }
-
-function hasParameter(name) {
+}
+Parameters.prototype.isSet = function(name) {
     // returns if the parameter's value has been set
-    if (!defined(dlParams[name])) return null;
-    return dlParams[name].hasValue;
-    }
-
-function getAllParameters(detail) {
+    if (!defined(this.params[name])) return null;
+    return this.params[name].hasValue;
+}
+Parameters.prototype.getAll = function(detail) {
     // returns a string of all parameters in query format
-    if (! detail) {
-        detail = 255;
-    }
-    var params = new Array();
-    for (param in dlParams) {
-        if (((dlParams[param].detail & detail) > 0)
-        && (dlParams[param].hasValue)) {
-            var val = getParameter(param);
+    if (!detail) detail = 255;
+    var pa = new Array();
+    for (p in this.params) {
+        if (((this.params[p].detail & detail) > 0)
+        && (this.params[p].hasValue)) {
+            var val = this.params[p].value;
             if (val != "") {
-                params.push(param + "=" + val);
+                pa.push(p + "=" + val);
             }
         }
     }
-    return params.join("&");
+    return pa.join("&");
 }
-
-function parseParameters(query) {
+Parameters.prototype.parse = function(query) {
     // gets parameter values from query format string
-    var params = query.split("&");
-    for (var i = 0; i < params.length; i++) {
-        var keyval = params[i].split("=");
+    var pa = query.split("&");
+    for (var i = 0; i < pa.length; i++) {
+        var keyval = pa[i].split("=");
         if (keyval.length == 2) {
-            setParameter(keyval[0], keyval[1]);
+            this.set(keyval[0], keyval[1]);
         }
     }
 }
 
-getQueryString = getAllParameters;
+/*
+ * Flags class
+ *
+ * Flags are (hash-) collections of unique strings.
+ */
+function Flags() {
+    this.flags = new Object();
+    return this;
+}
+Flags.prototype.define = function(name, detail) {
+    // create a new flag with a name and detail level
+    this.flags[name] = new Object();
+    this.flags[name].set = false;
+    this.flags[name].detail = detail;
+    return this.flags[name];
+}
+Flags.prototype.get = function(name) {
+	return (this.flags[name]) ? this.flags[name].set : false;
+}
+Flags.prototype.set = function(name, value) {
+	if (!defined(value)) value = true;
+	if (!this.flags[name]) this.flags[name] = new Object;
+	this.flags[name].set = value;
+}
+Flags.prototype.reset = function(name) {
+	if (!this.flags[name]) this.flags[name] = new Object;
+	this.flags[name].set = false;
+}
+Flags.prototype.toggle = function(name) {
+	if (!this.flags[name]) this.flags[name] = new Object;
+	this.flags[name].set = !this.flags[name].set;
+}
+Flags.prototype.resetAll = function() {
+	for (var f in this.flags) {
+		this.flags[f].set = false;
+	}
+}
+Flags.prototype.parse = function(query, sep) {
+    // sets the flags from the string query
+    if (!sep) sep = ",";
+    var fa = query.split(sep);
+    for (var i = 0; i < fa.length ; i++) {
+        var f = fa[i];
+        if (f != "") {
+            this.set(f);
+        }
+    }
+}
+Flags.prototype.getAll = function(detail, sep) {
+    // returns a string of all flags in query format
+    if (!detail) detail = 255;
+    if (!sep) sep = ",";
+    var fa = new Array();
+    for (f in this.flags) {
+        if (this.flags[f].set) {
+        		// if the flag has a detail level it must match
+        		// otherwise we assume detail=128
+        		if (this.flags[f].detail) {
+	        		if ((this.flags[f].detail & detail) > 0) {
+	        			fa.push(f);
+	        		}
+	        	} else {
+        		  	if ((detail & 128) > 0) {
+        				fa.push(f);
+        			}
+        		}
+        	}
+    }
+    return fa.join(sep);
+}
+
 
 /* **********************************************
  *     HTML/DOM routines
--- a/client/digitallibrary/greyskin/diginew.jsp	Mon Jan 16 20:53:44 2006 +0100
+++ b/client/digitallibrary/greyskin/diginew.jsp	Mon Jan 23 18:29:52 2006 +0100
@@ -7,16 +7,14 @@
 	// initialize DocumentBean instance in JSP init
 	public void jspInit() {
 	    try {
-		// set servlet init-parameter
-		docBean.setConfig(getServletConfig());
+            // set servlet init-parameter
+		    docBean.setConfig(getServletConfig());
 	    } catch (javax.servlet.ServletException e) {
-		System.out.println(e);
+		    System.out.println(e);
 	    }
 	}
 	// -- end of JSP init -------------
-%>
-
-<%
+%><%
 	// -- JSP request -------------
 	
 	// parsing the query
@@ -29,10 +27,8 @@
 	dlRequest.setValue("pt", docBean.getNumPages());
 	// store objects for jsp:include
 	pageContext.setAttribute("docBean", docBean, pageContext.REQUEST_SCOPE);
-%>
 
-<html>
-
+%><html>
 <head>
 	<title>Digital Document Library NG</title>
 	
@@ -46,7 +42,7 @@
 
 	<script language="JavaScript">
 
-	var jspVersion = "diginew.jsp 1.013";
+	var jspVersion = "diginew.jsp 1.020";
 	var cookie = new Cookie();
 	// alert(strObject(cookie));
 
@@ -113,38 +109,51 @@
 	function reflectImageStatus() {
 		if (hasFlag("hmir")) setOnImage("hmir", "mirror-horizontal-on.png");
 		if (hasFlag("vmir")) setOnImage("vmir", "mirror-vertical-on.png");
-		if (hasParameter("brgt"))
-			setOnImage("brgt", "brightness-on.png", getParameter("brgt"));
-		if (hasParameter("cont"))
-			setOnImage("cont", "contrast-on.png", getParameter("cont"));
-		if (hasParameter("rot"))
-			setOnImage("rot", "rotate-on.png", getParameter("rot"));
-		if (hasParameter("rgb"))
-			setOnImage("rgb", "rgb-on.png", getParameter("rgb"));
+		if (dlParams.isSet("brgt"))
+			setOnImage("brgt", "brightness-on.png", dlParams.get("brgt"));
+		if (dlParams.isSet("cont"))
+			setOnImage("cont", "contrast-on.png", dlParams.get("cont"));
+		if (dlParams.isSet("rot"))
+			setOnImage("rot", "rotate-on.png", dlParams.get("rot"));
+		if (dlParams.isSet("rgb"))
+			setOnImage("rgb", "rgb-on.png", dlParams.get("rgb"));
 		}
+    
 	function onImgLoad() {
 		// make sure the image is loaded so we know its size
-		if (defined(scalerImg.complete) && !scalerImg.complete && !browserType.isN4 ) {
+    	    if (defined(scalerImg.complete) && !scalerImg.complete && !browserType.isN4 ) {
 			setTimeout("onImgLoad()", 100);
 			waited += 100;
 			return;
-			}
+		}
+        dlTrafo = parseTrafo(scalerImg);
+        // display marks
+        renderMarks();
 		reflectImageStatus();	// adjust icons
 		showOptions(isOptionDivVisible);
 		showBirdDiv(isBirdDivVisible);
 		showArrows();		// show arrow overlays for zoom navigation
 		moveCenter(true);	// click to move point to center
 		// new Slider("sizes", 1, 5, 2);
+        focus();
 		}
 
 	// initialize digilib; called by body.onload
 	function onBodyLoad() {
 		document.id = 'digilib';
-		initParameters();	// load default values and detail
-		dl_param_init();	// parse parameter values
-		loadScalerImage();	// ruft auch dl_init() / initScaler auf
+        scalerDiv = getElement("scaler", true);
+        scalerImg = getElement("pic", true);
+        if (scalerImg == null && scalerDiv) {
+            // in N4 pic is in the scaler layer
+            scalerImg = scalerDiv.document.images[0];
+        }
+        if ((!scalerImg)||(!scalerDiv)) {
+            alert("Sorry, digilib doesn't work here!");
+            return false;
+        }
+		setScalerImage();	// ruft auch dl_init() / initScaler auf
 		loadBirdImage();	// lädt das Bird's Eye Bild
-		onImgLoad();
+		//onImgLoad();
 		}
 
 	function onBodyUnload() {
@@ -153,6 +162,7 @@
 		}
 	// base_init();		// now done on loading baselib.js
 
+    initParameters(); // load default values and detail
 	</script>
 </head>
 
--- a/client/digitallibrary/greyskin/dllib.js	Mon Jan 16 20:53:44 2006 +0100
+++ b/client/digitallibrary/greyskin/dllib.js	Mon Jan 23 18:29:52 2006 +0100
@@ -24,34 +24,131 @@
 
 */
 digilibVersion = "Digilib NG";
-dllibVersion = "2.031";
-isDigilibInitialized = false;    // gets set to true in dl_param_init
-reloadPage = true; // reload the page when parameters are changed, otherwise update only "src" attribute of scaler img 
+dllibVersion = "2.040";
+
+/****************************************************
+ * digilib specific classes (must be defined first)
+ ****************************************************/
+ 
+/*
+ * Marks class
+ */ 
+function Marks() {
+	return this;
+}
+// Marks inherits from Array
+Marks.prototype = new Array();
+Marks.prototype.parse = function(query) {
+	this.length = 0;
+    if (query.indexOf(";") >= 0) {
+        var pa = query.split(";");    // old format with ";"
+    } else {
+        var pa = query.split(",");    // new format
+    }
+    for (var i = 0; i < pa.length ; i++) {
+        var pos = pa[i].split("/");
+        if (pos.length > 1) this.push(new Position(pos[0], pos[1]));
+    }
+}
+Marks.prototype.getAll = function() {
+    var ma = new Array();
+    for (var i = 0; i < this.length; i++) {
+        ma.push(cropFloat(this[i].x) + "/" + cropFloat(this[i].y));
+   	}
+    return ma.join(",");
+}
+Marks.prototype.addEvent = function(evt) {
+    // add a mark from a screen event
+    var pos = dlTrafo.invtransform(evtPosition(evt));
+    this.push(pos);
+}
 
-// global variables
-dlTrafo = new Transform();
-dlMaxArea = new Rectangle(0.0, 0.0, 1.0, 1.0);
-dlArea = null;
-dlMarks = null;
-dlFlags = null;
+/*
+ * DLParameters -- digilibs own parameter class
+ */
+function DLParameters() {
+	// flags for parameter sets
+	this.PARAM_FILE = 1;
+	this.PARAM_MODE = 2;
+	this.PARAM_DIM = 4;
+	this.PARAM_IMAGE = 8;
+	this.PARAM_DPI = 16;
+	this.PARAM_SIZE = 32;
+	this.PARAM_MARK = 64;
+	this.PARAM_PAGES = 128;
+	this.PARAM_ALL = 255;
+	return this;
+}
+DLParameters.prototype = new Parameters();
+// move the inherited getAll because we need it later
+DLParameters.prototype._getAll = Parameters.prototype.getAll;
+DLParameters.prototype.getAll = function(paDetail, moDetail) {
+	// get Flags and Marks first
+    var mo = dlFlags.getAll(moDetail);
+    this.set("mo", mo);
+    var mk = dlMarks.getAll();
+    this.set("mk", mk);
+    var ret = this._getAll(paDetail);
+	return ret;
+}
+
+/*
+ * DLModes -- digilibs own flags class
+ */
+function DLFlags() {
+	// flags for mode sets
+	this.MODE_QUAL = 1;
+	this.MODE_SIZE = 2;
+	this.MODE_MIR = 4;
+	this.MODE_OTHER = 128;
+	this.MODE_ALL = 255;
+	return this;
+}
+// inherits from Flags
+DLFlags.prototype = new Flags();
+
+/********************************
+ * global variables
+ ********************************/
+ 
+var isDigilibInitialized = false;    // gets set to true in dl_param_init
+
+var dlParams;
+var dlTrafo;
+var dlMaxArea = new Rectangle(0.0, 0.0, 1.0, 1.0); // should be CONST
+var dlArea;
+var dlFlags;
+var dlMarks;
 
 // global elements
-scalerDiv = null;
-scalerImg = null;
+var scalerDiv = null;
+var scalerImg = null;
 
 // default inset (for scalerImg relativ to scalerDiv 
 INSET = 40; // because of scrollbars of main window and scaler [Firefox bug?]
 
-// flags for parameter sets
-PARAM_FILE = 1;
-PARAM_MODE = 2;
-PARAM_DIM = 4;
-PARAM_IMAGE = 8;
-PARAM_DPI = 16;
-PARAM_MARK = 32;
-PARAM_PAGES = 64;
-PARAM_SIZE = 128;
-PARAM_ALL = PARAM_FILE | PARAM_MODE | PARAM_DIM | PARAM_IMAGE | PARAM_DPI | PARAM_MARK | PARAM_PAGES | PARAM_SIZE;
+/* old parameter function compatibility stuff */
+function newParameter(a,b,c) {return dlParams.define(a,b,c)};
+function resetParameter(a) {return dlParams.reset(a)};
+function deleteParameter(a) {return dlParams.remove(a)};
+function getParameter(a) {return dlParams.get(a)};
+function setParameter(a,b,c) {return dlParams.set(a,b,c)};
+function hasParameter(a) {return dlParams.isSet(a)};
+function getAllParameters(a) {return dlParams.getAll(a)};
+getQueryString = getAllParameters;
+function parseParameters(a) {return dlParams.parse(a)};
+function getAllMarks() {return dlMarks.getAll()};
+getMarksQueryString = getAllMarks;
+function addMark(evt) {return dlMarks.addEvent(evt)};
+function deleteMark() {return dlMarks.pop()};
+function deleteAllMarks() {return dlMarks = new Marks()};
+function hasFlag(mode) {return dlFlags.get(mode)};
+function addFlag(mode) {return dlFlags.set(mode)};
+function removeFlag(mode) {return dlFlags.reset(mode)};
+function toggleFlag(mode) {return dlFlags.toggle(mode)};
+function getAllFlags() {return dlFlags.getAll()};
+
+
 
 // mouse drag area that counts as one click 
 MIN_AREA_SIZE = 3 * 3 + 1;
@@ -74,56 +171,80 @@
         // Relato uses that function - lugi
         return digilibVersion;
 }
+
 /*
  * more parameter handling
  */
 
-function initParameters() {
-// file
-    newParameter('fn', '',    PARAM_FILE);
-    newParameter('pn', '1',   PARAM_FILE);
-// mode
-    newParameter('mo', '',    PARAM_MODE);
-// relative dimensions of zoomed image
-    newParameter('wx', '0.0', PARAM_DIM);
-    newParameter('wy', '0.0', PARAM_DIM);
-    newParameter('ww', '1.0', PARAM_DIM);
-    newParameter('wh', '1.0', PARAM_DIM);
-// image manipulation
-    newParameter('brgt', '0.0', PARAM_IMAGE);
-    newParameter('cont', '0.0', PARAM_IMAGE);
-    newParameter('rot',  '0.0', PARAM_IMAGE);
-    newParameter('rgba', '',    PARAM_IMAGE);
-    newParameter('rgbm', '',    PARAM_IMAGE);
-// resolution
-    newParameter('ddpi',  '', PARAM_DPI);
-    newParameter('ddpix', '', PARAM_DPI);
-    newParameter('ddpiy', '', PARAM_DPI);
-// marks
-    newParameter('mk', '', PARAM_MARK);
-// pages total
-    newParameter('pt', '0', PARAM_PAGES);
-// size
-    newParameter('ws', '1.0', PARAM_SIZE);
-}
-
 function parseArea() {
     // returns area Rectangle from current parameters
     return new Rectangle(
-        getParameter("wx"),
-        getParameter("wy"),
-        getParameter("ww"),
-        getParameter("wh"));
-    }
+        dlParams.get("wx"),
+        dlParams.get("wy"),
+        dlParams.get("ww"),
+        dlParams.get("wh"));
+}
 
 function setParamFromArea(rect) {
     // sets digilib wx etc. from rect
-    setParameter("wx", cropFloat(rect.x));
-    setParameter("wy", cropFloat(rect.y));
-    setParameter("ww", cropFloat(rect.width));
-    setParameter("wh", cropFloat(rect.height));
+    dlParams.set("wx", cropFloat(rect.x));
+    dlParams.set("wy", cropFloat(rect.y));
+    dlParams.set("ww", cropFloat(rect.width));
+    dlParams.set("wh", cropFloat(rect.height));
     return true;
+}
+
+function initParameters() {
+    // initialisation before onload
+    if (!baseLibVersion) alert("ERROR: baselib.js not loaded!");
+    if (isDigilibInitialized) return false;    // dl_param_init was already run 
+    dlParams = new DLParameters();
+    dlFlags = new DLFlags();
+    dlMarks = new Marks();
+	/* request parameters */
+	with (dlParams) {
+	// file
+	    define('fn', '',    PARAM_FILE);
+	    define('pn', '1',   PARAM_FILE);
+	// mode
+	    define('mo', '',    PARAM_MODE);
+	// relative dimensions of zoomed image
+	    define('wx', '0.0', PARAM_DIM);
+	    define('wy', '0.0', PARAM_DIM);
+	    define('ww', '1.0', PARAM_DIM);
+	    define('wh', '1.0', PARAM_DIM);
+	// image manipulation
+	    define('brgt', '0.0', PARAM_IMAGE);
+	    define('cont', '0.0', PARAM_IMAGE);
+	    define('rot',  '0.0', PARAM_IMAGE);
+	    define('rgba', '',    PARAM_IMAGE);
+	    define('rgbm', '',    PARAM_IMAGE);
+	// resolution
+	    define('ddpi',  '', PARAM_DPI);
+	    define('ddpix', '', PARAM_DPI);
+	    define('ddpiy', '', PARAM_DPI);
+	// marks
+	    define('mk', '', PARAM_MARK);
+	// pages total
+	    define('pt', '0', PARAM_PAGES);
+	// size
+	    define('ws', '1.0', PARAM_SIZE);
     }
+    /* mode flags */
+    with (dlFlags) {
+	    define('q0', MODE_QUAL);
+	    define('q1', MODE_QUAL);
+	    define('q2', MODE_QUAL);
+	    define('fit',   MODE_SIZE);
+	    define('clip',  MODE_SIZE);
+	    define('osize', MODE_SIZE);
+	    define('vmir', MODE_MIR);
+	    define('hmir', MODE_MIR);
+	}
+    // parse parameters
+    parseAllParameters();
+    isDigilibInitialized = true;
+}
 
 /* **********************************************
  *     parse parameters routines
@@ -140,66 +261,20 @@
     trafo.concat(getScale(picsize));
     trafo.concat(getTranslation(picsize));
     // FIX ME: Robert, kannst Du mal nachsehen, ob das folgende tut, was es soll?
-    // oder gibt es dafür neuen Code?
+    // oder gibt es dafuer neuen Code? -- ROC: Bisher funktioniert es nicht!
     // rotate
-    var rot = getRotation(- getParameter("rot"), new Position(0.5*picsize.width, 0.5*picsize.height));
-    trafo.concat(rot);
+    //var rot = getRotation(- dlParams.get("rot"), new Position(0.5*picsize.width, 0.5*picsize.height));
+    //trafo.concat(rot);
     // mirror
-    if (hasFlag("hmir")) trafo.m00 = - trafo.m00; // ??
-    if (hasFlag("vmir")) trafo.m11 = - trafo.m11; // ??
+    //if (hasFlag("hmir")) trafo.m00 = - trafo.m00; // ??
+    //if (hasFlag("vmir")) trafo.m11 = - trafo.m11; // ??
     return trafo;
 }
 
-function parseMarks() {
-    // returns marks array from current parameters
-    var marks = new Array();
-    var param = getParameter("mk");
-    var pairs = (param.indexOf(";") >= 0)
-        ? param.split(";")    // old format with ";"
-        : param.split(",");    // new format
-    for (var i = 0; i < pairs.length ; i++) {
-        var pos = pairs[i].split("/");
-        if (pos.length > 1) marks.push(new Position(pos[0], pos[1]));
-        }
-    return marks;
-    }
-
 /* **********************************************
  *     marks routines
  * ******************************************** */
 
- function getAllMarks() {
-    // returns a string with all marks in query format
-    var marks = new Array();
-    for (var i = 0; i < dlMarks.length; i++)
-        marks.push(cropFloat(dlMarks[i].x) + "/" + cropFloat(dlMarks[i].y));
-    return marks.join(",");
-    }
-
-getMarksQueryString = getAllMarks;
-
-function addMark(evt) {
-    // add a mark
-    var pos = dlTrafo.invtransform(evtPosition(evt));
-    dlMarks.push(pos)
-    setParameter("mk", getAllMarks());
-    return true;
-    }
-
-function deleteMark() {
-    // delete the last mark
-    var mark = dlMarks.pop();
-    setParameter("mk", getAllMarks());
-    return true;
-    }
-
-function deleteAllMarks() {
-    // delete all marks and mk parameters
-    dlMarks.length = 0;
-    resetParameter("mk");
-    return true;
-    }
-
 function createMarkDiv(index) {
     var div = document.createElement("div");
     div.className = "mark";
@@ -207,65 +282,9 @@
     div.innerHTML = index + 1;
     document.body.appendChild(div);
     return div;
-    }
-
-/* **********************************************
- *     flag routines
- * ******************************************** */
-
-function hasFlag(mode) {
-    // returns if mode flag is set
-    return (dlFlags[mode]);
-    }
-
-function addFlag(mode) {
-    // add a mode flag
-    dlFlags[mode] = mode;
-    setParameter("mo", getAllFlags());
-    return true;
-    }
-
-function removeFlag(mode) {
-    // remove a mode flag
-    if (dlFlags[mode]) delete dlFlags[mode];
-    setParameter("mo", getAllFlags());
-    return true;
-    }
-
-function toggleFlag(mode) {
-    // change a mode flag
-    if (dlFlags[mode]) {
-        delete dlFlags[mode];
-    } else {
-        dlFlags[mode] = mode;
-    }
-    setParameter("mo", getAllFlags());
-    return true;
-    }
-
-function getAllFlags() {
-    // returns a string with all flags in query format
-    var fa = new Array();
-    for (var f in dlFlags) {
-        if ((f != "")&&(dlFlags[f] != null)) {
-            fa.push(f);
-        }
-    }
-    return fa.join(",");
 }
 
-function parseFlags() {
-    // sets dlFlags from the current parameters
-    var flags = new Object();
-    var fa = getParameter("mo").split(",");
-    for (var i = 0; i < fa.length ; i++) {
-        var f = fa[i];
-        if (f != "") {
-            flags[f] = f;
-        }
-    }
-    return flags;
-}
+
 
 
 function bestPicSize(elem, inset) {
@@ -294,7 +313,7 @@
         val = s.value;
     }
     if (nam && val) {
-        setParameter(nam, val, relative);
+        dlParams.set(nam, val, relative);
         display();
     } else {
         alert("ERROR: unable to process event!");
@@ -310,138 +329,106 @@
 
 function parseAllParameters() {
     // put the query parameters (sans "?") in the parameters array
-    parseParameters(location.search.slice(1));
+    dlParams.parse(location.search.slice(1));
     // treat special parameters
-    dlMarks = parseMarks();
+    dlMarks.parse(dlParams.get("mk"));
     dlArea = parseArea();
-    dlFlags = parseFlags();
-    }
+    dlFlags.parse(dlParams.get("mo"));
+}
 
 function dl_param_init() {
-    // initialisation before onload
-    if (!baseLibVersion) alert("ERROR: baselib.js not loaded!");
-    if (isDigilibInitialized) return false;    // dl_param_init was already run 
-    // dlArea = new Rectangle(0.0, 0.0, 1.0, 1.0); // overwritten by parseAllParameters() below
-    // dlMarks = new Array(); // dito
-    // dlFlags = new Object(); // dito
-    // parse parameters
-    parseAllParameters();
-    isDigilibInitialized = true;
     return true;
-    }
+}
 
 function dl_init() {
     // initalisation on load
     if (!isDigilibInitialized) dl_param_init();
-    scalerDiv = getElement("scaler");
-    scalerImg = getElement("pic", true);
-    // in N4 pic is in the scaler layer
-    if (scalerImg == null && scalerDiv) {
-        scalerImg = scalerDiv.document.images[0];
-        }
-    // give a name to the window containing digilib
-    window.name = defined(dlTarget) && dlTarget
-        ? dlTarget
-        : "digilib";
-    // put the query parameters (sans "?") in the parameters array
-        // parseAllParameters(); // has already been called in dl_param_init()
     // wait for image to load and display marks
     renderMarks();
     // done
     focus();
-    }
-    
-initScaler = dl_init;
+}
 
-function loadScalerImage(detail) {
-    var pic = getElement('pic');
-    var scaler = getElement('scaler');
-    var zoomdiv = getElement("zoom");    // test for presence only
-    var overlay = getElement("overlay");    // test for presence only
-    var about = getElement("about");        // test for presence only
-    var bird = getElement("bird");        // test for presence only
-    var picsize = bestPicSize(scaler, 50);
+function setScalerImage(detail) {
+	// set the scaler image source (needs the browser size)
+    if (!scalerDiv) scalerDiv = getElement("scaler");
+    if (!scalerImg) scalerImg = getElement("pic");
+    var picsize = bestPicSize(scalerDiv, 50);
     var src = "../servlet/Scaler?" 
-        + getQueryString()
+        + dlParams.getAll(dlParams.PARAM_ALL & ~(dlParams.PARAM_MARK | dlParams.PARAM_PAGES))
         + "&dw=" + picsize.width
         + "&dh=" + picsize.height;
     // debug(src);
-    pic.src = src;
-    initScaler();    // dl_init braucht die endgültigen Maße des pic Elements
-    }
+    scalerImg.onload = onImgLoad;
+    scalerImg.src = src;
+    //initScaler();    // dl_init braucht die endgueltigen Masze des pic Elements
+}
 
-function display(detail) {
+function display(detail, moDetail) {
     // redisplay the page
-    if (! detail) detail = PARAM_ALL;
-    var queryString = getAllParameters(detail);
-    if (reloadPage) {
-        location.href
-            = location.protocol + "//"
-            + location.host
-            + location.pathname
-            + "?" + queryString;
-    } else {
-        loadScalerImage();
-        }
-    }
+    var queryString = dlParams.getAll(detail, moDetail);
+	location.href
+        = location.protocol + "//"
+    	    + location.host
+    	    + location.pathname
+        + "?" + queryString;
+}
 
 /* **********************************************
  *     interactive digilib functions
  * ******************************************** */
 function renderMarks() {
     // make sure the image is loaded so we know its size
-    if (defined(scalerImg.complete) && !scalerImg.complete && !browserType.isN4 ) {
-        setTimeout("renderMarks()", 100);
-        return;
-            }
-    // put the visible marks on the image
-    dlTrafo = parseTrafo(scalerImg);
+    if (!dlTrafo) {
+    		alert("ERROR: cannot render marks!");
+    		return;
+    	}
     // debugProps(dlArea, "dlArea");
     for (var i = 0; i < dlMarks.length; i++) {
-    var div = getElement("mark" + i) || createMarkDiv(i);
-        var mark = dlMarks[i];
-    // debugProps(mark, "mark");
-    if (dlArea.containsPosition(mark)) {
-        var mpos = dlTrafo.transform(mark); // FIX ME: transform does not change anything 
-        // debugProps(mark, "mpos");
-        // suboptimal to place -5 pixels and not half size of mark-image
-        // better not hide the marked spot (MR)
-        // mpos.x = mpos.x -5;
-        // mpos.y = mpos.y -5;
-        moveElement(div, mpos);
-        showElement(div, true);
-    } else {
-        // hide the other marks
-        showElement(div, false);
-        }
-        }
+    	var div = getElement("mark" + i, true) || createMarkDiv(i);
+    	var mark = dlMarks[i];
+    	// debugProps(mark, "mark");
+    	if (dlArea.containsPosition(mark)) {
+        	var mpos = dlTrafo.transform(mark); 
+        	// debugProps(mark, "mpos");
+	       	// suboptimal to place -5 pixels and not half size of mark-image
+	       	// better not hide the marked spot (MR)
+	       	// mpos.x = mpos.x -5;
+	       	// mpos.y = mpos.y -5;
+	       	moveElement(div, mpos);
+	        showElement(div, true);
+	    } else {
+	        // hide the other marks
+	        showElement(div, false);
+	    }
     }
+}
 
 function setMark(reload) {
 
     function markEvent(evt) {
     // event handler adding a new mark
         unregisterEvent("mousedown", scalerDiv, markEvent);
-        addMark(evt);
+        dlMarks.addEvent(evt);
         if ( defined(reload) && !reload ) {
             // don't redisplay
             renderMarks();
             return;
-            }
+        }
         display();
         return stopEvent(evt);
-        }
+    }
     
     // add a mark where clicked
     window.focus();
     moveCenter(false);
     // start event capturing
     registerEvent("mousedown", scalerDiv, markEvent);
-    }
+}
 
 function removeMark(reload) {
     // remove the last mark
-    deleteMark();
+    dlMarks.pop();
     if (defined(reload)&&(!reload)) {
         // don't redisplay
         renderMarks();
@@ -478,13 +465,14 @@
         registerEvent("mousemove", document, zoomMove);
         registerEvent("mouseup", document, zoomEnd);
         return stopEvent(evt);
-        }
+    }
     
 // mouseup handler: end moving
     function zoomEnd(evt) {
         pt2 = evtPosition(evt);
         // assume a click if the area is too small (up to 3 x 3 pixel)
-        var clickRect = getRect(pt1, pt2);
+        var clickRect = new Rectangle(pt1, pt2);
+        clickRect.normalize();
         if (clickRect.getArea() <= MIN_AREA_SIZE) return stopEvent(evt); 
         // hide zoom div
         showElement(zoomdiv, false);
@@ -492,43 +480,26 @@
         // unregister events
         unregisterEvent("mousemove", document, zoomMove);
         unregisterEvent("mouseup", document, zoomMove);
-        // calc offsets
+        // clip and transform
         clickRect.clipTo(picRect);
-        var area = getRect(
-            // FIX ME: liefert negative x/y Werte, wenn hmir/vmir=1
-            dlTrafo.invtransform(clickRect.getPt1()),
-            dlTrafo.invtransform(clickRect.getPt2())
-            );
-        setParameter("wx", cropFloat(area.x));
-        setParameter("wy", cropFloat(area.y));
-        setParameter("ww", cropFloat(area.width));
-        setParameter("wh", cropFloat(area.height));
-        // parseArea(); // why?
+        var area = dlTrafo.invtransform(clickRect);
+        setParamFromArea(area);
         // zoomed is always fit
-        setParameter("ws", 1);
+        dlParams.set("ws", 1);
         display();
         return stopEvent(evt);
-        }
+    }
     
 // mouse move handler
     function zoomMove(evt) {
         pt2 = evtPosition(evt);
-        var rect = getRect(pt1, pt2);
+        var rect = new Rectangle(pt1, pt2);
+        rect.normalize();
         rect.clipTo(picRect);
         // update zoom div
         moveElement(zoomdiv, rect);
         return stopEvent(evt);
-        }
-    
-// get a rectangle from two points
-    function getRect(p1, p2) {
-        return new Rectangle(
-            Math.min(p1.x, p2.x),
-            Math.min(p1.y, p2.y),
-            Math.abs(p1.x - p2.x),
-            Math.abs(p1.y - p2.y)
-            );
-        }
+    	}
 }
 
 function zoomBy(factor) {
@@ -546,10 +517,10 @@
 
 function zoomFullpage() {
     // zooms out to show the whole image
-    setParameter("wx", 0.0);
-    setParameter("wy", 0.0);
-    setParameter("ww", 1.0);
-    setParameter("wh", 1.0);
+    dlParams.set("wx", 0.0);
+    dlParams.set("wy", 0.0);
+    dlParams.set("ww", 1.0);
+    dlParams.set("wh", 1.0);
     display();
 }
 
@@ -622,31 +593,30 @@
         + location.host
         + location.pathname;
     var hyperlinkRef = baseUrl;
-    var params = getAllParameters(PARAM_ALL & ~(PARAM_DPI | PARAM_PAGES)); // all without ddpi, pt
+    var params = dlParams.getAll(dlParams.PARAM_ALL & ~(dlParams.PARAM_DPI | dlParams.PARAM_PAGES)); // all without ddpi, pt
     if (params.length > 0) hyperlinkRef += "?" + params;
     return hyperlinkRef;
-    }
+}
 
 function getRefWin(type, msg) {
     // shows an alert with a reference to the current digilib set
     if (! msg) msg = "URL reference to the current view";
     prompt(msg, getRef());
-    }
+}
 
 function getQuality() {
     // returns the current q setting
     for (var i = 0; i < 3; i++) {
-        if (hasFlag("q"+i)) return i;
-        }
+        if (dlFlags.get("q"+i)) return i;
+    }
     return 1
-    }
+}
 
 function setQuality(qual) {
     // set the image quality
-    for (var i = 0; i < 3; i++) removeFlag("q" + i);
-    if (qual > 2) return alert("Quality number not supported");
-    addFlag("q" + i);
-    setParameter("mo", getAllFlags());
+    for (var i = 0; i < 3; i++) dlFlags.reset("q" + i);
+    if ((qual < 0)||(qual > 2)) return alert("Quality setting not supported");
+    dlFlags.set("q" + qual);
     display();
 }
 
@@ -656,58 +626,56 @@
     var q = getQuality();
     var newq = window.prompt(msg, q);
     if (newq) setQuality(newq);
-    }
+}
 
 function mirror(dir) {
     // mirror the image horizontally or vertically
-    toggleFlag(dir == "h"
-        ? "hmir"
-        : "vmir"
-        );
-    setParameter("mo", getAllFlags());
+    if (dir == "h") {
+    		dlFlags.toggle("hmir");
+    	} else {
+    		dlFlags.toggle("vmir");
+	}
     display();
 }
 
 function gotoPage(gopage, keep) {
     // goto given page nr (+/-: relative)
-    var oldpn = parseInt(getParameter("pn"));
-    setParameter("pn", gopage, true);
-    var pn = parseInt(getParameter("pn"));
+    var oldpn = parseInt(dlParams.get("pn"));
+    dlParams.set("pn", gopage, true);
+    var pn = parseInt(dlParams.get("pn"));
     if (pn < 1) {
         alert("No such page! (Page number too low)");
-        setParameter("pn", oldpn);
+        dlParams.set("pn", oldpn);
         return;
     }
-    if (hasParameter("pt")) {
-        pt = parseInt(getParameter("pt"))
+    if (dlParams.isSet("pt")) {
+        pt = parseInt(dlParams.get("pt"))
         if (pn > pt) {
             alert("No such page! (Page number too high)");
-            setParameter("pn", oldpn);
+            dlParams.set("pn", oldpn);
             return;
         }
     }
     if (keep) {
-        display(PARAM_ALL & ~PARAM_MARK); // all, no mark
+        display(dlParams.PARAM_ALL & ~dlParams.PARAM_MARK); // all, no mark
     } else {
-        display(PARAM_FILE | PARAM_MODE | PARAM_PAGES); // fn, pn, ws, mo + pt
-// FIX ME: currently the mirror status gets propagated to the other pages
-// hmir and vmir should not be mode flags, but boolean params!!! 
+        display(dlParams.PARAM_FILE | dlParams.PARAM_MODE | dlParams.PARAM_PAGES, dlParams.MODE_QUAL | dlParams.MODE_OTHER); // fn, pn, ws, mo + pt
     }
 }
 
 function gotoPageWin() {
     // dialog to ask for new page nr
-    var pn = getParameter("pn");
+    var pn = dlParams.get("pn");
     var gopage = window.prompt("Go to page", pn);
     if (gopage) gotoPage(gopage);
     }
 
 function setParamWin(param, text, relative) {
     // dialog to ask for new parameter value
-    var val = getParameter(param);
+    var val = dlParams.get(param);
     var newval = window.prompt(text, val);
     if (newval) {
-        setParameter(param, newval, relative);
+        dlParams.set(param, newval, relative);
         display();
     }
 }
@@ -745,7 +713,7 @@
 function loadBirdImage() {
     var img = getElement("bird-image");
     var src = "../servlet/Scaler?" 
-        + getQueryString(PARAM_FILE)
+        + dlParams.getAll(dlParams.PARAM_FILE)
         + "&dw=" + BIRD_MAXX 
         + "&dh=" + BIRD_MAXY;
     img.src = src;
@@ -821,10 +789,10 @@
             startPos = birdAreaRect.getCenter();
             birdAreaMove(evt); // set center to click position
             }
-        setParameter("wx", cropFloat((newRect.x - birdImgRect.x) / birdImgRect.width));
-        setParameter("wy", cropFloat((newRect.y - birdImgRect.y) / birdImgRect.height));
+        dlParams.set("wx", cropFloat((newRect.x - birdImgRect.x) / birdImgRect.width));
+        dlParams.set("wy", cropFloat((newRect.y - birdImgRect.y) / birdImgRect.height));
         // zoomed is always fit
-        setParameter("ws", 1);
+        dlParams.set("ws", 1);
         display();
         return stopEvent(evt);
         }
@@ -932,7 +900,7 @@
             alert("Screen has not yet been calibrated - using default value of 72 dpi");
             dpi = 72;
             }
-        setParameter("ddpi", dpi);
+        dlParams.set("ddpi", dpi);
         addFlag("osize");
         display();
         }
@@ -953,15 +921,15 @@
     divSize.width -= INSET; // allow for scrollbars [Firefox bug?]
     var imgSize = getElementSize(scalerImg);
     if (imgSize.width < divSize.width) {
-        setParameter("ws", cropFloat(divSize.width / imgSize.width));
-        display(PARAM_ALL & ~PARAM_DIM); // no zoom
+        dlParams.set("ws", cropFloat(divSize.width / imgSize.width));
+        display(dlParams.PARAM_ALL & ~dlParams.PARAM_DIM); // no zoom
         };
     // TODO: how to calculate correct width if zoom is on? (plus size?)
 
 }
 
 function resize(factor) {
-    setParameter("ws", factor);
+    dlParams.set("ws", factor);
     showSizeMenu(false);
     display();
 }