Mercurial > hg > digilib
annotate client/digitallibrary/greyskin/baselib.js @ 672:f996df5dea63 jquery
dragging birdview zooms correctly now
| author | hertzhaft |
|---|---|
| date | Wed, 26 Jan 2011 01:26:45 +0100 |
| parents | 8652a5837432 |
| children |
| rev | line source |
|---|---|
| 446 | 1 /* Copyright (C) 2003-2006 IT-Group MPIWG, WTWG Uni Bern and others |
| 394 | 2 |
| 3 This program is free software; you can redistribute it and/or | |
| 4 modify it under the terms of the GNU General Public License | |
| 5 as published by the Free Software Foundation; either version 2 | |
| 6 of the License, or (at your option) any later version. | |
| 7 | |
| 8 This program is distributed in the hope that it will be useful, | |
| 9 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 11 GNU General Public License for more details. | |
| 12 | |
| 13 You should have received a copy of the GNU General Public License | |
| 14 along with this program; if not, write to the Free Software | |
| 15 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | |
| 16 | |
| 17 Authors: | |
| 18 Christian Luginbuehl, 01.05.2003 (first version) | |
| 19 DW 24.03.2004 (Changed for digiLib in Zope) | |
| 446 | 20 Robert Casties, 2.11.2004 (almost complete rewrite) |
| 403 | 21 Martin Raspe, 12.12.2005 (changes for Digilib NG) |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
22 Robert Casties, 3.9.2009 |
| 394 | 23 */ |
| 24 | |
| 403 | 25 // was: function base_init() { |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
26 baseLibVersion = "2.011"; |
| 403 | 27 browserType = getBrowserType(); |
| 394 | 28 |
| 440 | 29 sliders = {}; |
| 30 activeSlider = null; | |
| 394 | 31 |
| 32 function getInt(n) { | |
| 33 // returns always an integer | |
| 34 n = parseInt(n); | |
| 446 | 35 return (isNaN(n)) ? 0 : n; |
| 394 | 36 } |
| 37 | |
| 38 function defined(x) { | |
| 39 // returns if x is defined | |
| 40 return (typeof arguments[0] != "undefined"); | |
| 41 } | |
| 42 | |
| 43 function cropFloat(x) { | |
| 44 // auxiliary function to crop senseless precision | |
| 403 | 45 return parseInt(10000 * x) / 10000; |
| 394 | 46 } |
| 47 | |
| 48 function getBrowserType() { | |
| 49 // browser sniffer | |
| 50 var bt = Object(); | |
| 51 bt.doDHTML = false; | |
| 52 bt.versIE = 0; | |
| 53 | |
| 54 if ((! document.cssonly && document.layers) || document.all || document.getElementById) { | |
| 55 var vers = navigator.appVersion.split('MSIE '); | |
| 56 vers = vers[vers.length - 1]; | |
| 57 bt.versIE = getInt(vers); | |
| 58 bt.isIE = navigator.userAgent.indexOf('MSIE') >= 0; | |
| 59 bt.isMac = navigator.platform.indexOf('Mac') >= 0; | |
| 60 bt.isWin = navigator.platform.indexOf('Win') >= 0; | |
| 61 bt.isN4 = (navigator.userAgent.indexOf('Mozilla/4.') >= 0) && ! bt.isIE; | |
| 62 bt.isIEWin = bt.versIE > 0 && bt.isWin; | |
| 63 if (navigator.appVersion.indexOf('MSIE') < 0 || ! bt.isMac || bt.versIE >= 5) { | |
| 64 bt.doDHTML = true; | |
| 65 bt.isOpera = navigator.userAgent.indexOf(' Opera ') >= 0; | |
| 66 bt.isKonq = navigator.userAgent.indexOf(' Konqueror') >= 0; | |
| 67 } | |
| 68 } | |
| 69 return bt; | |
| 70 } | |
| 71 | |
| 72 // fixes for javascript < 1.2 | |
| 73 if (! Array.prototype.push) { | |
| 74 Array.prototype.push = function(val) { | |
| 75 this[this.length] = val; | |
| 76 return this.length; | |
| 77 } | |
| 78 Array.prototype.pop = function() { | |
| 79 var val = this[this.length-1]; | |
| 80 this.length -= 1; | |
| 81 return val; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 | |
| 86 /* ********************************************** | |
| 87 * geometry classes | |
| 88 * ******************************************** */ | |
| 89 | |
| 90 /* | |
| 91 * Size class | |
| 92 */ | |
| 93 function Size(w, h) { | |
| 94 this.width = parseFloat(w); | |
| 95 this.height = parseFloat(h); | |
| 96 return this; | |
| 97 } | |
| 98 Size.prototype.toString = function() { | |
| 99 return this.width + "x" + this.height; | |
| 100 } | |
| 422 | 101 Size.prototype.equals = function(other) { |
| 102 return (this.width == other.width | |
| 103 && this.height == other.height) | |
| 104 } | |
| 394 | 105 |
| 106 /* | |
| 107 * Position class | |
| 108 */ | |
| 109 function Position(x, y) { | |
| 110 this.x = parseFloat(x); | |
| 111 this.y = parseFloat(y); | |
| 112 return this; | |
| 113 } | |
| 114 Position.prototype.toString = function() { | |
| 115 return this.x + "," + this.y; | |
| 116 } | |
| 422 | 117 Position.prototype.equals = function(other) { |
| 118 return (this.x == other.x | |
| 119 && this.y == other.y) | |
| 446 | 120 } |
| 394 | 121 /* |
| 122 * Rectangle class | |
| 123 */ | |
| 124 function Rectangle(x, y, w, h) { | |
| 446 | 125 if (typeof x == "object") { |
| 126 // assume x and y are Position | |
| 127 this.x = x.x; | |
| 128 this.y = x.y; | |
| 129 this.width = y.x - x.x; | |
| 130 this.height = y.y - x.y; | |
| 131 return this; | |
| 132 } | |
| 394 | 133 this.x = parseFloat(x); |
| 134 this.y = parseFloat(y); | |
| 135 this.width = parseFloat(w); | |
| 136 this.height = parseFloat(h); | |
| 137 return this; | |
| 138 } | |
| 139 Rectangle.prototype.toString = function() { | |
| 140 return this.width+"x"+this.height+"@"+this.x+","+this.y; | |
| 141 } | |
| 142 Rectangle.prototype.copy = function() { | |
| 143 // returns a copy of this Rectangle | |
| 144 return new Rectangle(this.x, this.y, this.width, this.height); | |
| 145 } | |
| 146 Rectangle.prototype.getPosition = function() { | |
| 147 // returns the position of this Rectangle | |
| 148 return new Position(this.x, this.y); | |
| 149 } | |
| 429 | 150 Rectangle.prototype.getPt1 = Rectangle.prototype.getPosition; |
| 446 | 151 // returns the upper left corner position |
| 429 | 152 |
| 153 Rectangle.prototype.getPt2 = function() { | |
| 446 | 154 // returns the lower right corner position of this Rectangle |
| 429 | 155 return new Position(this.x + this.width, this.y + this.height); |
| 156 } | |
| 157 Rectangle.prototype.setPt1 = function(pos) { | |
| 446 | 158 // sets the upper left corner to position pos |
| 429 | 159 this.x = pos.x; |
| 160 this.y = pos.y; | |
| 161 return this; | |
| 162 } | |
| 163 Rectangle.prototype.setPt2 = function(pos) { | |
| 446 | 164 // sets the lower right corner to position pos |
| 429 | 165 this.width = pos.x - this.x; |
| 166 this.height = pos.y - this.y; | |
| 167 return this; | |
| 168 } | |
| 169 Rectangle.prototype.getCenter = function() { | |
| 170 // returns the center position of this Rectangle | |
| 171 return new Position(this.x + this.width / 2, this.y + this.height / 2); | |
| 172 } | |
| 173 Rectangle.prototype.setCenter = function(pos) { | |
| 174 // moves this Rectangle's center to position pos | |
| 175 this.x = pos.x - this.width / 2; | |
| 176 this.y = pos.y - this.height / 2; | |
| 177 return this; | |
| 178 } | |
| 394 | 179 Rectangle.prototype.getSize = function() { |
| 180 // returns the size of this Rectangle | |
| 181 return new Size(this.width, this.height); | |
| 182 } | |
| 422 | 183 Rectangle.prototype.equals = function(other) { |
| 184 // equal props | |
| 185 return (this.getPosition().equals(other.getPosition()) | |
| 186 && this.getSize().equals(other.getSize()) | |
| 187 ); | |
| 188 } | |
| 394 | 189 Rectangle.prototype.getArea = function() { |
| 190 // returns the area of this Rectangle | |
| 191 return (this.width * this.height); | |
| 192 } | |
| 429 | 193 Rectangle.prototype.normalize = function() { |
| 194 // eliminates negative width and height | |
| 195 var p = this.getPt2(); | |
| 196 this.x = Math.min(this.x, p.x); | |
| 197 this.y = Math.min(this.y, p.y); | |
| 198 this.width = Math.abs(this.width); | |
| 199 this.height = Math.abs(this.height); | |
| 200 return this; | |
| 201 } | |
| 394 | 202 Rectangle.prototype.containsPosition = function(pos) { |
| 408 | 203 // returns if Position "pos" lies inside of this rectangle |
| 204 return ((pos.x >= this.x) | |
| 205 && (pos.y >= this.y) | |
| 206 && (pos.x <= this.x + this.width) | |
| 207 && (pos.y <= this.y + this.width) | |
| 208 ); | |
| 209 } | |
| 210 Rectangle.prototype.containsRect = function(rect) { | |
| 211 // returns if rectangle "rect" is contained in this rectangle | |
| 446 | 212 return (this.containsPosition(rect.getPt1()) |
| 213 && this.containsPosition(rect.getPt2())); | |
| 408 | 214 } |
| 215 Rectangle.prototype.stayInside = function(rect) { | |
| 216 // changes this rectangle's x/y values so it stays inside of rectangle rect | |
| 429 | 217 // keeping the proportions |
| 408 | 218 if (this.x < rect.x) this.x = rect.x; |
| 219 if (this.y < rect.y) this.y = rect.y; | |
| 220 if (this.x + this.width > rect.x + rect.width) | |
| 221 this.x = rect.x + rect.width - this.width; | |
| 222 if (this.y + this.height > rect.y + rect.height) | |
| 223 this.y = rect.y + rect.height - this.height; | |
| 224 return this; | |
| 394 | 225 } |
| 429 | 226 Rectangle.prototype.clipTo = function(rect) { |
| 227 // clips this rectangle so it stays inside of rectangle rect | |
| 446 | 228 var p1 = rect.getPt1(); |
| 229 var p2 = rect.getPt2(); | |
| 230 var this2 = this.getPt2(); | |
| 429 | 231 this.setPt1(new Position(Math.max(this.x, p1.x), Math.max(this.y, p1.y))); |
| 232 this.setPt2(new Position(Math.min(this2.x, p2.x), Math.min(this2.y, p2.y))); | |
| 233 return this; | |
| 234 } | |
| 394 | 235 Rectangle.prototype.intersect = function(rect) { |
| 236 // returns the intersection of the given Rectangle and this one | |
| 408 | 237 // FIX ME: not really, it should return null if there is no overlap |
| 394 | 238 var sec = rect.copy(); |
| 239 if (sec.x < this.x) { | |
| 240 sec.width = sec.width - (this.x - sec.x); | |
| 241 sec.x = this.x; | |
| 242 } | |
| 243 if (sec.y < this.y) { | |
| 244 sec.height = sec.height - (this.y - sec.y); | |
| 245 sec.y = this.y; | |
| 246 } | |
| 247 if (sec.x + sec.width > this.x + this.width) { | |
| 248 sec.width = (this.x + this.width) - sec.x; | |
| 249 } | |
| 250 if (sec.y + sec.height > this.y + this.height) { | |
| 251 sec.height = (this.y + this.height) - sec.y; | |
| 252 } | |
| 253 return sec; | |
| 254 } | |
| 255 Rectangle.prototype.fit = function(rect) { | |
| 256 // returns a Rectangle that fits into this one (by moving first) | |
| 257 var sec = rect.copy(); | |
| 258 sec.x = Math.max(sec.x, this.x); | |
| 422 | 259 sec.y = Math.max(sec.y, this.x); |
| 394 | 260 if (sec.x + sec.width > this.x + this.width) { |
| 261 sec.x = this.x + this.width - sec.width; | |
| 262 } | |
| 263 if (sec.y + sec.height > this.y + this.height) { | |
| 264 sec.y = this.y + this.height - sec.height; | |
| 265 } | |
| 266 return sec.intersect(this); | |
| 267 } | |
| 268 | |
| 269 /* | |
| 270 * Transform class | |
| 271 * | |
| 272 * defines a class of affine transformations | |
| 273 */ | |
| 274 function Transform() { | |
| 275 this.m00 = 1.0; | |
| 276 this.m01 = 0.0; | |
| 277 this.m02 = 0.0; | |
| 278 this.m10 = 0.0; | |
| 279 this.m11 = 1.0; | |
| 280 this.m12 = 0.0; | |
| 281 this.m20 = 0.0; | |
| 282 this.m21 = 0.0; | |
| 283 this.m22 = 1.0; | |
| 284 return this; | |
| 285 } | |
| 286 Transform.prototype.concat = function(traf) { | |
| 287 // add Transform traf to this Transform | |
| 288 for (var i = 0; i < 3; i++) { | |
| 289 for (var j = 0; j < 3; j++) { | |
| 290 var c = 0.0; | |
| 291 for (var k = 0; k < 3; k++) { | |
| 292 c += traf["m"+i+k] * this["m"+k+j]; | |
| 293 } | |
| 294 this["m"+i+j] = c; | |
| 295 } | |
| 296 } | |
| 297 return this; | |
| 298 } | |
| 299 Transform.prototype.transform = function(rect) { | |
| 300 // returns transformed Rectangle or Position with this Transform applied | |
| 301 var x = this.m00 * rect.x + this.m01 * rect.y + this.m02; | |
| 302 var y = this.m10 * rect.x + this.m11 * rect.y + this.m12; | |
| 303 if (rect.width) { | |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
304 // transform the other corner points |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
305 var pt2 = rect.getPt2(); |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
306 var x2 = this.m00 * pt2.x + this.m01 * pt2.y + this.m02; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
307 var y2 = this.m10 * pt2.x + this.m11 * pt2.y + this.m12; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
308 var width = x2 - x; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
309 var height = y2 - y; |
| 394 | 310 return new Rectangle(x, y, width, height); |
| 311 } | |
| 312 return new Position(x, y); | |
| 313 } | |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
314 Transform.prototype.invtransform = function(rect) { |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
315 // returns transformed Rectangle or Position with the inverse of this Transform applied |
| 394 | 316 var det = this.m00 * this.m11 - this.m01 * this.m10; |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
317 var x = (this.m11 * rect.x - this.m01 * rect.y - this.m11 * this.m02 + this.m01 * this.m12) / det; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
318 var y = (- this.m10 * rect.x + this.m00 * rect.y + this.m10 * this.m02 - this.m00 * this.m12) / det; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
319 if (rect.width) { |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
320 /* transforming width and height like points seems to be wrong |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
321 var width = (this.m11 * rect.width - this.m01 * rect.height - this.m11 * this.m02 + this.m01 * this.m12) / det; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
322 var height = (- this.m10 * rect.width + this.m00 * rect.height + this.m10 * this.m02 - this.m00 * this.m12) / det; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
323 */ |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
324 // transform the other corner points |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
325 var pt2 = rect.getPt2(); |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
326 var x2 = (this.m11 * pt2.x - this.m01 * pt2.y - this.m11 * this.m02 + this.m01 * this.m12) / det; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
327 var y2 = (- this.m10 * pt2.x + this.m00 * pt2.y + this.m10 * this.m02 - this.m00 * this.m12) / det; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
328 var width = x2 - x; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
329 var height = y2 - y; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
330 return new Rectangle(x, y, width, height); |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
331 } |
| 394 | 332 return new Position(x, y); |
| 333 } | |
| 334 function getRotation(angle, pos) { | |
| 335 // returns a Transform that is a rotation by angle degrees around [pos.x, pos.y] | |
| 336 var traf = new Transform(); | |
| 337 if (angle != 0) { | |
| 338 var t = 2.0 * Math.PI * parseFloat(angle) / 360.0; | |
| 339 traf.m00 = Math.cos(t); | |
| 340 traf.m01 = - Math.sin(t); | |
| 341 traf.m10 = Math.sin(t); | |
| 342 traf.m11 = Math.cos(t); | |
| 343 traf.m02 = pos.x - pos.x * Math.cos(t) + pos.y * Math.sin(t); | |
| 344 traf.m12 = pos.y - pos.x * Math.sin(t) - pos.y * Math.cos(t); | |
| 345 } | |
| 346 return traf; | |
| 347 } | |
| 450 | 348 Transform.prototype.getRotation = getRotation; |
| 394 | 349 function getTranslation(pos) { |
| 350 // returns a Transform that is a translation by [pos.x, pos,y] | |
| 351 var traf = new Transform(); | |
| 352 traf.m02 = pos.x; | |
| 353 traf.m12 = pos.y; | |
| 354 return traf; | |
| 355 } | |
| 450 | 356 Transform.prototype.getTranslation = getTranslation; |
| 394 | 357 function getScale(size) { |
| 358 // returns a Transform that is a scale by [size.width, size.height] | |
| 359 var traf = new Transform(); | |
| 360 traf.m00 = size.width; | |
| 361 traf.m11 = size.height; | |
| 362 return traf; | |
| 363 } | |
| 450 | 364 Transform.prototype.getScale = getScale; |
| 394 | 365 |
| 366 | |
| 446 | 367 /* |
| 368 * parameters class | |
| 369 */ | |
| 394 | 370 |
| 446 | 371 function Parameters() { |
| 372 this.params = new Object(); | |
| 448 | 373 this.PARAM_ALL = 65535; |
| 446 | 374 return this; |
| 375 } | |
| 376 Parameters.prototype.define = function(name, defaultValue, detail) { | |
| 394 | 377 // create a new parameter with a name and a default value |
| 446 | 378 if (!this.params[name]) this.params[name] = new Object(); |
| 379 this.params[name].defaultValue = defaultValue; | |
| 380 this.params[name].hasValue = false; | |
| 381 this.params[name].value = defaultValue; | |
| 382 this.params[name].detail = detail; | |
| 383 return this.params[name]; | |
| 384 } | |
| 385 Parameters.prototype.reset = function(name) { | |
| 408 | 386 // resets the given parameter to its default value |
| 446 | 387 if (!this.params[name]) { |
| 388 alert("Could not reset non-existing parameter '" + name + "'"); | |
| 389 return false; | |
| 408 | 390 } |
| 446 | 391 this.params[name].hasValue = false; |
| 392 this.params[name].value = this.params[name].defaultValue; | |
| 393 return this.params[name]; | |
| 394 } | |
| 395 Parameters.prototype.resetAll = function() { | |
| 396 // resets all parameters to their default values | |
| 397 for (var p in this.params) { | |
| 398 this.reset(p); | |
| 399 } | |
| 400 return true; | |
| 401 } | |
| 402 Parameters.prototype.remove = function(name) { | |
| 403 if (!defined(this.params[name])) return false; | |
| 404 delete this.params[name]; | |
| 405 return true; | |
| 406 } | |
| 407 Parameters.prototype.get = function(name) { | |
| 394 | 408 // returns the named parameter value or its default value |
| 446 | 409 if (!defined(this.params[name])) return null; |
| 410 return this.params[name].hasValue ? this.params[name].value : this.params[name].defaultValue; | |
| 411 } | |
| 412 Parameters.prototype.set = function(name, value, relative) { | |
| 413 // sets parameter value (relative values with +/- if relative=true) | |
| 414 if (!defined(this.params[name])) return null; | |
| 415 var p = this.params[name]; | |
| 408 | 416 if (relative && value.slice) { |
| 446 | 417 // value is a string -- check if it starts with +/- |
| 408 | 418 var sign = value.slice(0, 1); |
| 419 if (sign == '+') { | |
| 420 p.value = parseFloat(p.value) + parseFloat(value.slice(1)); | |
| 421 } else if (sign == '-') { | |
| 422 p.value = parseFloat(p.value) - parseFloat(value.slice(1)); | |
| 423 } else { | |
| 424 p.value = value; | |
| 425 } | |
| 446 | 426 } else { |
| 427 p.value = value; | |
| 428 } | |
| 408 | 429 p.hasValue = true; |
| 430 return p.value; | |
| 446 | 431 } |
| 432 Parameters.prototype.isSet = function(name) { | |
| 408 | 433 // returns if the parameter's value has been set |
| 446 | 434 if (!defined(this.params[name])) return null; |
| 435 return this.params[name].hasValue; | |
| 436 } | |
| 437 Parameters.prototype.getAll = function(detail) { | |
| 394 | 438 // returns a string of all parameters in query format |
| 448 | 439 if (!detail) detail = this.PARAM_ALL; |
| 446 | 440 var pa = new Array(); |
| 441 for (p in this.params) { | |
| 442 if (((this.params[p].detail & detail) > 0) | |
| 443 && (this.params[p].hasValue)) { | |
| 444 var val = this.params[p].value; | |
| 394 | 445 if (val != "") { |
| 446 | 446 pa.push(p + "=" + val); |
| 394 | 447 } |
| 448 } | |
| 449 } | |
| 446 | 450 return pa.join("&"); |
| 394 | 451 } |
| 446 | 452 Parameters.prototype.parse = function(query) { |
| 394 | 453 // gets parameter values from query format string |
| 446 | 454 var pa = query.split("&"); |
| 455 for (var i = 0; i < pa.length; i++) { | |
| 456 var keyval = pa[i].split("="); | |
| 394 | 457 if (keyval.length == 2) { |
| 446 | 458 this.set(keyval[0], keyval[1]); |
| 394 | 459 } |
| 460 } | |
| 461 } | |
| 462 | |
| 446 | 463 /* |
| 464 * Flags class | |
| 465 * | |
| 466 * Flags are (hash-) collections of unique strings. | |
| 467 */ | |
| 468 function Flags() { | |
| 469 this.flags = new Object(); | |
| 470 return this; | |
| 471 } | |
| 472 Flags.prototype.define = function(name, detail) { | |
| 473 // create a new flag with a name and detail level | |
| 474 this.flags[name] = new Object(); | |
| 475 this.flags[name].set = false; | |
| 476 this.flags[name].detail = detail; | |
| 477 return this.flags[name]; | |
| 478 } | |
| 479 Flags.prototype.get = function(name) { | |
| 480 return (this.flags[name]) ? this.flags[name].set : false; | |
| 481 } | |
| 482 Flags.prototype.set = function(name, value) { | |
| 483 if (!defined(value)) value = true; | |
| 484 if (!this.flags[name]) this.flags[name] = new Object; | |
| 485 this.flags[name].set = value; | |
| 486 } | |
| 487 Flags.prototype.reset = function(name) { | |
| 488 if (!this.flags[name]) this.flags[name] = new Object; | |
| 489 this.flags[name].set = false; | |
| 490 } | |
| 491 Flags.prototype.toggle = function(name) { | |
| 492 if (!this.flags[name]) this.flags[name] = new Object; | |
| 493 this.flags[name].set = !this.flags[name].set; | |
| 494 } | |
| 495 Flags.prototype.resetAll = function() { | |
| 496 for (var f in this.flags) { | |
| 497 this.flags[f].set = false; | |
| 498 } | |
| 499 } | |
| 500 Flags.prototype.parse = function(query, sep) { | |
| 501 // sets the flags from the string query | |
| 502 if (!sep) sep = ","; | |
| 503 var fa = query.split(sep); | |
| 504 for (var i = 0; i < fa.length ; i++) { | |
| 505 var f = fa[i]; | |
| 506 if (f != "") { | |
| 507 this.set(f); | |
| 508 } | |
| 509 } | |
| 510 } | |
| 511 Flags.prototype.getAll = function(detail, sep) { | |
| 512 // returns a string of all flags in query format | |
| 513 if (!detail) detail = 255; | |
| 514 if (!sep) sep = ","; | |
| 515 var fa = new Array(); | |
| 516 for (f in this.flags) { | |
| 517 if (this.flags[f].set) { | |
| 518 // if the flag has a detail level it must match | |
| 519 // otherwise we assume detail=128 | |
| 520 if (this.flags[f].detail) { | |
| 521 if ((this.flags[f].detail & detail) > 0) { | |
| 522 fa.push(f); | |
| 523 } | |
| 524 } else { | |
| 525 if ((detail & 128) > 0) { | |
| 526 fa.push(f); | |
| 527 } | |
| 528 } | |
| 529 } | |
| 530 } | |
| 531 return fa.join(sep); | |
| 532 } | |
| 533 | |
| 394 | 534 |
| 535 /* ********************************************** | |
| 536 * HTML/DOM routines | |
| 537 * ******************************************** */ | |
| 538 | |
| 539 function getElement(tagid, quiet) { | |
| 540 // returns the element object with the id tagid | |
| 541 var e; | |
| 542 if (document.getElementById) { | |
| 543 e = document.getElementById(tagid); | |
| 544 } else if (document.all) { | |
| 545 alert("document.all!"); | |
| 546 e = document.all[tagid]; | |
| 547 } else if (document.layers) { | |
| 548 e = document.layers[tagid]; | |
| 549 } | |
| 550 if (e) { | |
| 551 return e; | |
| 552 } else { | |
| 553 if (! quiet) { | |
| 554 alert("unable to find element: "+tagid); | |
| 555 } | |
| 556 return null; | |
| 557 } | |
| 558 } | |
| 559 | |
| 560 function getElementPosition(elem) { | |
| 561 // returns a Position with the position of the element | |
| 562 var x = 0; | |
| 563 var y = 0; | |
| 564 if (defined(elem.offsetLeft)) { | |
| 565 var e = elem; | |
| 566 while (e) { | |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
567 if (browserType.isIE) { |
| 394 | 568 if (browserType.isMac) { |
| 569 if (e.offsetParent.tagName == "BODY") { | |
| 570 // IE for Mac extraspecial | |
| 571 x += e.clientLeft; | |
| 572 y += e.clientTop; | |
| 573 break; | |
| 574 } | |
| 575 } else { | |
| 576 if ((e.tagName != "TABLE") && (e.tagName != "BODY")) { | |
| 577 x += e.clientLeft; | |
| 578 y += e.clientTop; | |
| 579 } | |
| 580 } | |
| 581 } | |
| 582 x += e.offsetLeft; | |
| 583 y += e.offsetTop; | |
| 584 e = e.offsetParent; | |
| 585 } | |
| 586 } else if (defined(elem.x)) { | |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
587 // use .x for other (which?) |
| 394 | 588 x = elem.x; |
| 589 y = elem.y; | |
| 590 } else if (defined(elem.pageX)) { | |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
591 // use pageX for N4 |
| 394 | 592 x = elem.pageX; |
| 593 y = elem.pageY; | |
| 594 } else { | |
| 434 | 595 alert("unable to get position of " + elem + " (id:" + elem.id + ")"); |
| 394 | 596 } |
| 597 return new Position(getInt(x), getInt(y)); | |
| 598 } | |
| 599 | |
| 600 function getElementSize(elem) { | |
| 601 // returns a Rectangle with the size of the element | |
| 602 var width = 0; | |
| 603 var height = 0; | |
| 604 if (defined(elem.offsetWidth)) { | |
| 605 width = elem.offsetWidth; | |
| 606 height = elem.offsetHeight; | |
| 607 } else if (defined(elem.width)) { | |
| 608 width = elem.width; | |
| 609 height = elem.height; | |
| 610 } else if (defined(elem.clip.width)) { | |
| 611 width = elem.clip.width; | |
| 612 height = elem.clip.height; | |
| 613 } else { | |
| 434 | 614 alert("unable to get size of " + elem + " (id:" + elem.id + ")"); |
| 394 | 615 } |
| 616 return new Size(getInt(width), getInt(height)); | |
| 617 } | |
| 618 | |
| 619 function getElementRect(elem) { | |
| 620 // returns a Rectangle with the size and position of the element | |
| 408 | 621 // FIX ME: what about borders? |
| 394 | 622 var pos = getElementPosition(elem); |
| 623 var size = getElementSize(elem); | |
| 624 return new Rectangle(pos.x, pos.y, size.width, size.height); | |
| 625 } | |
| 626 | |
| 627 function moveElement(elem, rect) { | |
| 628 // moves and sizes the element | |
| 629 if (elem.style) { | |
| 630 if (defined(rect.x)) { | |
| 631 elem.style.left = Math.round(rect.x) + "px"; | |
| 632 elem.style.top = Math.round(rect.y) + "px"; | |
| 633 } | |
| 634 if (defined(rect.width)) { | |
| 635 elem.style.width = Math.round(rect.width) + "px"; | |
| 636 elem.style.height = Math.round(rect.height) + "px"; | |
| 637 } | |
| 638 } else if (document.layers) { | |
| 639 if (defined(rect.x)) { | |
| 640 elem.pageX = getInt(rect.x); | |
| 641 elem.pageY = getInt(rect.y); | |
| 642 } | |
| 643 if (defined(rect.width)) { | |
| 644 elem.clip.width = getInt(rect.width); | |
| 645 elem.clip.height = getInt(rect.height); | |
| 646 } | |
| 647 } else { | |
| 434 | 648 alert("moveElement(): element has no style or layer property!"); |
| 394 | 649 return false; |
| 650 } | |
| 651 return true; | |
| 652 } | |
| 653 | |
| 654 function showElement(elem, show) { | |
| 655 // shows or hides the element | |
| 431 | 656 if (elem.style) |
| 657 elem.style.visibility = show ? "visible" : "hidden"; | |
| 434 | 658 else if (defined(elem.visibility)) |
| 431 | 659 elem.visibility = show ? "show" : "hide"; |
| 434 | 660 else |
| 431 | 661 alert("showElement(): element has no style or layer property!"); |
| 394 | 662 return true; |
| 663 } | |
| 664 | |
| 665 function evtPosition(evt) { | |
| 666 // returns the on-screen Position of the Event | |
| 667 var x; | |
| 668 var y; | |
| 669 evt = (evt) ? evt : window.event; | |
| 670 if (!evt) { | |
| 431 | 671 alert("no event found! " + evt); |
| 394 | 672 return; |
| 431 | 673 } |
| 394 | 674 if (defined(evt.pageX)) { |
| 675 x = parseInt(evt.pageX); | |
| 676 y = parseInt(evt.pageY); | |
| 677 } else if (defined(evt.clientX)) { | |
| 431 | 678 x = parseInt(document.body.scrollLeft + evt.clientX); |
| 679 y = parseInt(document.body.scrollTop + evt.clientY); | |
| 394 | 680 } else { |
| 431 | 681 alert("evtPosition(): don't know how to deal with " + evt); |
| 682 } | |
| 394 | 683 return new Position(x, y); |
| 684 } | |
| 685 | |
| 686 function registerEvent(type, elem, handler) { | |
| 408 | 687 // register the given event handler on the indicated element |
| 688 if (elem.addEventListener) { | |
| 689 elem.addEventListener(type, handler, false); // bubble | |
| 690 } | |
| 691 else if (elem.attachEvent) { | |
| 692 elem.attachEvent("on" + type, handler); | |
| 693 } | |
| 694 else if (elem.captureEvents) { | |
| 695 if (Event) { | |
| 696 t = type.toUpperCase(); | |
| 697 elem.captureEvents(Event[t]); | |
| 434 | 698 elem[ "on" + type ] = handler; |
| 408 | 699 } |
| 700 } | |
| 701 else { | |
| 702 alert("Could not register event of type " + type); | |
| 703 return false; | |
| 704 } | |
| 705 return true; | |
| 706 } | |
| 707 | |
| 403 | 708 function unregisterEvent(type, elem, handler) { |
| 408 | 709 // unregister the given event handler from the indicated element |
| 710 if (elem.removeEventListener) { | |
| 711 elem.removeEventListener(type, handler, false); | |
| 712 } | |
| 713 else if (elem.detachEvent) { | |
| 434 | 714 elem.detachEvent("on" + type, handler); |
| 408 | 715 } |
| 716 else if (elem.releaseEvents) { | |
| 717 if (Event) { | |
| 718 t = type.toUpperCase(); | |
| 719 elem.releaseEvents(Event[t]); | |
| 434 | 720 elem[ "on" + type ] = null; |
| 408 | 721 } |
| 722 } | |
| 723 else { | |
| 724 alert("Could not register event of type " + type); | |
| 725 return false; | |
| 726 } | |
| 727 return true; | |
| 394 | 728 } |
| 729 | |
| 403 | 730 function registerEventById(type, id, handler) { |
| 438 | 731 registerEvent(type, getElement(id), handler); |
| 408 | 732 } |
| 403 | 733 |
| 734 function unregisterEventById(type, id, handler) { | |
| 438 | 735 unregisterEvent(type, getElement(id), handler); |
| 408 | 736 } |
| 403 | 737 |
| 738 function stopEvent(e) { | |
| 408 | 739 if (!e) var e = window.event; |
| 740 e.cancelBubble = true; | |
| 741 if (e.stopPropagation) e.stopPropagation(); | |
| 742 return false; | |
| 394 | 743 } |
| 744 | |
| 403 | 745 function getEventSrc(e) { |
| 408 | 746 if (e.target) return e.target; |
| 747 if (e.srcElement) return e.srcElement; | |
| 403 | 748 } |
| 394 | 749 |
| 750 // old registerXXYY API for compatibility | |
| 751 function registerMouseDown(elem, handler) { | |
| 752 return registerEvent("mousedown", elem, handler); | |
| 753 } | |
| 754 function unregisterMouseDown(elem, handler) { | |
| 755 return unregisterEvent("mousedown", elem, handler); | |
| 756 } | |
| 757 function registerMouseMove(elem, handler) { | |
| 758 return registerEvent("mousemove", elem, handler); | |
| 759 } | |
| 760 function unregisterMouseMove(elem, handler) { | |
| 761 return unregisterEvent("mousemove", elem, handler); | |
| 762 } | |
| 763 function registerKeyDown(handler) { | |
| 764 return registerEvent("keypress", elem, handler); | |
| 765 } | |
| 766 | |
| 767 | |
| 768 function getWinSize() { | |
| 769 // returns a Size with the current window size (mostly from www.quirksmode.org) | |
| 770 var wsize = new Size(100, 100); | |
| 771 if (defined(self.innerHeight)) { | |
| 772 // all except Explorer | |
| 773 if ((self.innerWidth == 0)||(self.innerHeight == 0)) { | |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
774 // Safari 1.2 (and other) bug |
| 394 | 775 if (parent) { |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
776 wsize.height = parent.innerHeight; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
777 wsize.width = parent.innerWidth; |
| 394 | 778 } |
|
509
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
779 } else { |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
780 wsize.width = self.innerWidth; |
|
8652a5837432
fixed bug with double-zoom (Transform was broken for Rectangles)
robcast
parents:
450
diff
changeset
|
781 wsize.height = self.innerHeight; |
| 394 | 782 } |
| 783 } else if (document.documentElement && document.documentElement.clientHeight) { | |
| 784 // Explorer 6 Strict Mode | |
| 785 wsize.width = document.documentElement.clientWidth; | |
| 786 wsize.height = document.documentElement.clientHeight; | |
| 787 } else if (document.body) { | |
| 788 // other Explorers | |
| 789 wsize.width = document.body.clientWidth; | |
| 790 wsize.height = document.body.clientHeight; | |
| 791 } | |
| 792 return wsize; | |
| 793 } | |
| 794 | |
| 429 | 795 function getWinRect() { |
| 796 var size = getWinSize(); | |
| 797 return new Rectangle(0, 0, size.width, size.height); | |
| 798 } | |
| 799 | |
| 394 | 800 function openWin(url, name, params) { |
| 801 // open browser window | |
| 802 var ow = window.open(url, name, params); | |
| 803 ow.focus(); | |
| 804 } | |
| 429 | 805 |
| 806 /* ********************************************** | |
| 807 * cookie class | |
| 808 * ******************************************** */ | |
| 809 | |
| 810 function Cookie() { | |
| 811 return this.read(); | |
| 812 } | |
| 813 | |
| 814 Cookie.prototype.read = function() { | |
| 815 var s = document.cookie; | |
| 431 | 816 var lines = s.split("; "); // semicolon and space for all browsers? |
| 429 | 817 for (var i in lines) { |
| 818 var line = lines[i]; | |
| 819 var sep = line.indexOf("="); | |
| 820 if (sep != -1) this.add( | |
| 821 line.substr(0, sep), | |
| 822 line.substr(sep + 1) | |
| 823 ); | |
| 824 } | |
| 825 return this; | |
| 826 } | |
| 827 | |
| 828 Cookie.prototype.store = function() { | |
| 829 var lines = new Array(); | |
| 830 for (var i in this) { | |
| 831 var item = this[i]; | |
| 832 if (typeof(item) == typeof(lines)) // Array | |
| 833 lines.push(i + "=" + item.join(",")); | |
| 834 else if (typeof(item) != "function") // single item | |
| 835 lines.push(i + "=" + item); | |
| 836 } | |
| 837 // var s = lines.join(";") | |
| 838 for (line in lines) document.cookie = lines[line]; | |
| 839 return this; | |
| 840 } | |
| 841 | |
| 842 Cookie.prototype.add = function(key, value) { | |
| 434 | 843 value = value.toString(); |
| 429 | 844 if (value.indexOf(",") == -1) |
| 845 this[key] = value; // single value | |
| 846 else | |
| 847 this[key] = value.split(","); // list of values | |
| 848 return this[key]; | |
| 849 } | |
| 850 | |
| 851 Cookie.prototype.get = function(key) { | |
| 852 return this[key]; | |
| 853 } | |
| 854 | |
| 855 Cookie.prototype.addbool = function(key, value) { | |
| 856 this[key] = Boolean(value).toString(); | |
| 857 return this[key]; | |
| 858 } | |
| 859 | |
| 860 Cookie.prototype.getbool = function(key) { | |
| 861 var val = this[key]; | |
| 862 return (val > "") && (val != "0") && (val != "false"); | |
| 863 } | |
| 864 | |
| 865 Cookie.prototype.remove = function(key) { | |
| 866 delete this[key]; | |
| 867 } | |
| 868 | |
| 438 | 869 function Slider(id, valMin, valMax, valStart, stepSize, onChange) { |
| 870 // a (horizontal) slider widget | |
| 871 this.id = id; | |
| 872 this.elem = getElement(id); | |
| 440 | 873 this.slider = getElement(id + "-slider"); // the slider handle |
| 874 this.input = getElement(id + "-input", 1); // optional input field | |
| 875 this.bar = getElement(id + "-bar"); // the slider bar | |
| 438 | 876 this.barRect = getElementRect(this.bar); |
| 440 | 877 this.sliderRect = getElementRect(this.slider); |
| 878 this.xMin = this.barRect.x; | |
| 879 this.xMax = this.xMin + this.barRect.width; | |
| 880 this.xDiff = this.xMax - this.xMin; | |
| 881 this.Y = this.barRect.getCenter().y; // middle axis of bar | |
| 438 | 882 this.valMin = valMin; |
| 883 this.valMax = valMax; | |
| 440 | 884 this.valDiff = Math.abs(valMax - valMin); |
| 438 | 885 this.valStart = valStart; |
| 886 this.value = valStart; | |
| 887 this.stepSize = stepSize; | |
| 440 | 888 this.valueLabel = getElement(id + "-value", 1); |
| 889 this.valMinLabel = getElement(id + "-valmin", 1); | |
| 890 this.valMaxLabel = getElement(id + "-valmax", 1); | |
| 438 | 891 this.onChange = onChange ? onChange : function() {}; |
| 440 | 892 this.update(); |
| 893 this.activate(); | |
| 894 sliders[id + '-slider'] = this; // make a handle to the object | |
| 438 | 895 return this; |
| 896 } | |
| 897 | |
| 898 Slider.prototype.show = function(show) { | |
| 899 showElement(this.elem, show); | |
| 440 | 900 this.activate(); |
| 438 | 901 } |
| 902 | |
| 903 Slider.prototype.activate = function() { | |
| 440 | 904 this.setupEvents(); |
| 438 | 905 } |
| 906 | |
| 440 | 907 Slider.prototype.deactivate = function() { |
| 908 unregisterEvent("mousedown", this.slider, this.onDragStart); | |
| 438 | 909 } |
| 910 | |
| 911 Slider.prototype.reset = function() { | |
| 912 this.setValue(this.startVal); | |
| 913 } | |
| 914 | |
| 915 Slider.prototype.setValue = function(newVal) { | |
| 916 // sets slider to new value and updates | |
| 917 this.value = newVal; | |
| 440 | 918 this.update(); |
| 919 } | |
| 920 | |
| 921 Slider.prototype.calcValue = function() { | |
| 922 // calculates value from slider position | |
| 923 var xSlider = this.sliderRect.getCenter().x - this.xMin; | |
| 924 this.value = xSlider * this.valDiff / this.xDiff; | |
| 925 return this.value; | |
| 438 | 926 } |
| 927 | |
| 928 Slider.prototype.update = function() { | |
| 929 // updates slider position to new value | |
| 440 | 930 var xSlider = this.value * this.xDiff / this.valDiff; |
| 931 moveElement(this.slider, this.sliderRect.setCenter( | |
| 932 new Position(xSlider + this.xMin, this.Y))); | |
| 933 var strVal = this.value.toString(); | |
| 934 if (this.valueLabel) this.valueLabel.innerHTML = strVal; | |
| 935 if (this.input) this.input.value = strVal; | |
| 438 | 936 } |
| 937 | |
| 938 Slider.prototype.setupEvents = function() { | |
| 939 // installs all event callbacks | |
| 940 registerEvent("mousedown", this.slider, this.onDragStart); | |
| 941 } | |
| 942 | |
| 943 Slider.prototype.onDragStart = function(evt) { | |
| 440 | 944 var slider = sliders[this.id]; |
| 945 activeSlider = slider; | |
| 946 unregisterEvent("mousedown", slider.slider, slider.onDragStart); | |
| 947 registerEvent("mousemove", document, slider.onDrag); | |
| 948 registerEvent("mouseup", document, slider.onDragEnd); | |
| 949 slider.startPos = evtPosition(evt); | |
| 950 slider.startX = slider.sliderRect.getCenter().x; | |
| 438 | 951 return stopEvent(evt); |
| 952 } | |
| 953 | |
| 954 Slider.prototype.onDrag = function(evt) { | |
| 440 | 955 var slider = activeSlider; |
| 438 | 956 var pos = evtPosition(evt); |
| 440 | 957 var currX = slider.slider |
| 958 var newX = pos.x - slider.startPos + slider.startX; | |
| 959 if (newX < slider.xMin) newX = slider.xMin; | |
| 960 if (newX > slider.xMax) newX = slider.xMax; | |
| 961 moveElement(slider.slider, slider.sliderRect.setCenter( | |
| 962 new Position(newX, slider.Y))); | |
| 438 | 963 return stopEvent(evt); |
| 964 } | |
| 965 | |
| 966 Slider.prototype.onDragEnd = function(evt) { | |
| 440 | 967 var slider = activeSlider; |
| 968 unregisterEvent("mousemove", document, slider.onDrag); | |
| 969 unregisterEvent("mouseup", document, slider.onDragEnd); | |
| 970 slider.onChange(slider.calcValue()); | |
| 971 activeSlider = null; | |
| 438 | 972 return stopEvent(evt); |
| 973 } | |
| 974 | |
| 975 Slider.prototype.onInputChange = function() { | |
| 440 | 976 var slider = activeSlider; |
| 977 slider.onChange(s.value); | |
| 438 | 978 } |
| 979 | |
| 440 | 980 // :tabSize=4:indentSize=4:noTabs=true: |
| 981 |
