Mercurial > hg > digilib
comparison client/src/main/webapp/jquery/jquery.digilib.js @ 883:7ffb45138f61 mvnify
rearrange sources to maven directory standard
| author | robcast |
|---|---|
| date | Tue, 19 Apr 2011 18:44:25 +0200 |
| parents | client/digitallibrary/jquery/jquery.digilib.js@b95510ec127b |
| children | ec077cb6a8dc |
comparison
equal
deleted
inserted
replaced
| 882:2bba166f4608 | 883:7ffb45138f61 |
|---|---|
| 1 /* Copyright (c) 2011 Martin Raspe, Robert Casties | |
| 2 | |
| 3 This program is free software: you can redistribute it and/or modify | |
| 4 it under the terms of the GNU Lesser General Public License as published by | |
| 5 the Free Software Foundation, either version 2 of the License, or | |
| 6 (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 Lesser General Public License for more details. | |
| 12 | |
| 13 You should have received a copy of the GNU Lesser General Public License | |
| 14 along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 15 | |
| 16 Authors: | |
| 17 Martin Raspe, Robert Casties, 11.1.2011 | |
| 18 */ | |
| 19 | |
| 20 /** | |
| 21 * digilib jQuery plugin | |
| 22 **/ | |
| 23 | |
| 24 /*jslint browser: true, debug: true, forin: true | |
| 25 */ | |
| 26 | |
| 27 // fallback for console.log calls | |
| 28 if (typeof console === 'undefined') { | |
| 29 var console = { | |
| 30 log : function(){}, | |
| 31 debug : function(){}, | |
| 32 error : function(){} | |
| 33 }; | |
| 34 var customConsole = false; // set to true if debugging for MS IE | |
| 35 } | |
| 36 | |
| 37 (function($) { | |
| 38 var buttons = { | |
| 39 reference : { | |
| 40 onclick : "reference", | |
| 41 tooltip : "get a reference URL", | |
| 42 icon : "reference.png" | |
| 43 }, | |
| 44 zoomin : { | |
| 45 onclick : ["zoomBy", 1.4], | |
| 46 tooltip : "zoom in", | |
| 47 icon : "zoom-in.png" | |
| 48 }, | |
| 49 zoomout : { | |
| 50 onclick : ["zoomBy", 0.7], | |
| 51 tooltip : "zoom out", | |
| 52 icon : "zoom-out.png" | |
| 53 }, | |
| 54 zoomarea : { | |
| 55 onclick : "zoomArea", | |
| 56 tooltip : "zoom area", | |
| 57 icon : "zoom-area.png" | |
| 58 }, | |
| 59 zoomfull : { | |
| 60 onclick : "zoomFull", | |
| 61 tooltip : "view the whole image", | |
| 62 icon : "zoom-full.png" | |
| 63 }, | |
| 64 pagewidth : { | |
| 65 onclick : ["zoomFull", "width"], | |
| 66 tooltip : "page width", | |
| 67 icon : "pagewidth.png" | |
| 68 }, | |
| 69 back : { | |
| 70 onclick : ["gotoPage", "-1"], | |
| 71 tooltip : "goto previous image", | |
| 72 icon : "back.png" | |
| 73 }, | |
| 74 fwd : { | |
| 75 onclick : ["gotoPage", "+1"], | |
| 76 tooltip : "goto next image", | |
| 77 icon : "fwd.png" | |
| 78 }, | |
| 79 page : { | |
| 80 onclick : "gotoPage", | |
| 81 tooltip : "goto image number", | |
| 82 icon : "page.png" | |
| 83 }, | |
| 84 help : { | |
| 85 onclick : "showAboutDiv", | |
| 86 tooltip : "about Digilib", | |
| 87 icon : "help.png" | |
| 88 }, | |
| 89 reset : { | |
| 90 onclick : "reset", | |
| 91 tooltip : "reset image", | |
| 92 icon : "reset.png" | |
| 93 }, | |
| 94 mark : { | |
| 95 onclick : "setMark", | |
| 96 tooltip : "set a mark", | |
| 97 icon : "mark.png" | |
| 98 }, | |
| 99 delmark : { | |
| 100 onclick : "removeMark", | |
| 101 tooltip : "delete the last mark", | |
| 102 icon : "delmark.png" | |
| 103 }, | |
| 104 hmir : { | |
| 105 onclick : ["mirror", "h"], | |
| 106 tooltip : "mirror horizontally", | |
| 107 icon : "mirror-horizontal.png" | |
| 108 }, | |
| 109 vmir : { | |
| 110 onclick : ["mirror", "v"], | |
| 111 tooltip : "mirror vertically", | |
| 112 icon : "mirror-vertical.png" | |
| 113 }, | |
| 114 rot : { | |
| 115 onclick : "rotate", | |
| 116 tooltip : "rotate image", | |
| 117 icon : "rotate.png" | |
| 118 }, | |
| 119 brgt : { | |
| 120 onclick : "brightness", | |
| 121 tooltip : "set brightness", | |
| 122 icon : "brightness.png" | |
| 123 }, | |
| 124 cont : { | |
| 125 onclick : "contrast", | |
| 126 tooltip : "set contrast", | |
| 127 icon : "contrast.png" | |
| 128 }, | |
| 129 rgb : { | |
| 130 onclick : "javascript:setParamWin('rgb', '...')", | |
| 131 tooltip : "set rgb values", | |
| 132 icon : "rgb.png" | |
| 133 }, | |
| 134 quality : { | |
| 135 onclick : "setQuality", | |
| 136 tooltip : "set image quality", | |
| 137 icon : "quality.png" | |
| 138 }, | |
| 139 size : { | |
| 140 onclick : "javascript:toggleSizeMenu()", | |
| 141 tooltip : "set page size", | |
| 142 icon : "size.png" | |
| 143 }, | |
| 144 calibrationx : { | |
| 145 onclick : "calibrate", | |
| 146 tooltip : "calibrate screen resolution", | |
| 147 icon : "calibration-x.png" | |
| 148 }, | |
| 149 scale : { | |
| 150 onclick : "setScaleMode", | |
| 151 tooltip : "change image scale", | |
| 152 icon : "original-size.png" | |
| 153 }, | |
| 154 toggleoptions : { | |
| 155 onclick : "moreButtons", | |
| 156 tooltip : "more options", | |
| 157 icon : "options.png" | |
| 158 }, | |
| 159 moreoptions : { | |
| 160 onclick : ["moreButtons", "+1"], | |
| 161 tooltip : "more options", | |
| 162 icon : "options.png" | |
| 163 }, | |
| 164 lessoptions : { | |
| 165 onclick : ["moreButtons", "-1"], | |
| 166 tooltip : "less options", | |
| 167 icon : "options.png" | |
| 168 }, | |
| 169 up : { | |
| 170 onclick : ["moveZoomArea", 0, -1], | |
| 171 tooltip : "move zoom area up", | |
| 172 icon : "up.png" | |
| 173 }, | |
| 174 down : { | |
| 175 onclick : ["moveZoomArea", 0, 1], | |
| 176 tooltip : "move zoom area down", | |
| 177 icon : "down.png" | |
| 178 }, | |
| 179 left : { | |
| 180 onclick : ["moveZoomArea", -1, 0], | |
| 181 tooltip : "move zoom area left", | |
| 182 icon : "left.png" | |
| 183 }, | |
| 184 right : { | |
| 185 onclick : ["moveZoomArea", 1, 0], | |
| 186 tooltip : "move zoom area right", | |
| 187 icon : "right.png" | |
| 188 }, | |
| 189 SEP : { | |
| 190 icon : "sep.png" | |
| 191 } | |
| 192 }; | |
| 193 | |
| 194 var defaults = { | |
| 195 // version of this script | |
| 196 'version' : 'jquery.digilib.js 0.9', | |
| 197 // logo url | |
| 198 'logoUrl' : '../img/digilib-logo-text1.png', | |
| 199 // homepage url (behind logo) | |
| 200 'homeUrl' : 'http://digilib.berlios.de', | |
| 201 // base URL to digilib viewer (for reference URLs) | |
| 202 'digilibBaseUrl' : null, | |
| 203 // base URL to Scaler servlet | |
| 204 'scalerBaseUrl' : null, | |
| 205 // list of Scaler parameters | |
| 206 'scalerParamNames' : ['fn','pn','dw','dh','ww','wh','wx','wy','ws','mo', | |
| 207 'rot','cont','brgt','rgbm','rgba','ddpi','ddpix','ddpiy'], | |
| 208 // Scaler parameter defaults | |
| 209 'pn' : 1, | |
| 210 'ww' : 1.0, | |
| 211 'wh' : 1.0, | |
| 212 'wx' : 0.0, | |
| 213 'wy' : 0.0, | |
| 214 'ws' : 1.0, | |
| 215 'mo' : '', | |
| 216 'rot' : 0, | |
| 217 'cont' : 0, | |
| 218 'brgt' : 0, | |
| 219 'rgbm' : '0/0/0', | |
| 220 'rgba' : '0/0/0', | |
| 221 'ddpi' : null, | |
| 222 'ddpix' : null, | |
| 223 'ddpiy' : null, | |
| 224 // list of digilib parameters | |
| 225 'digilibParamNames' : ['fn','pn','ww','wh','wx','wy','ws','mo','rot','cont','brgt','rgbm','rgba','ddpi','mk','clop'], | |
| 226 // digilib parameter defaults | |
| 227 'mk' : '', | |
| 228 'clop' : '', | |
| 229 // mode of operation: | |
| 230 // fullscreen = take parameters from page URL, keep state in page URL | |
| 231 // embedded = take parameters from Javascript options, keep state inside object | |
| 232 'interactionMode' : 'fullscreen', | |
| 233 // buttons | |
| 234 'buttons' : buttons, | |
| 235 // defaults for digilib buttons | |
| 236 'buttonSettings' : { | |
| 237 'fullscreen' : { | |
| 238 // path to button images (must end with a slash) | |
| 239 'imagePath' : 'img/fullscreen/', | |
| 240 'buttonSetWidth' : 36, | |
| 241 'standardSet' : ["reference","zoomin","zoomout","zoomarea","zoomfull","pagewidth","back","fwd","page","help","reset","toggleoptions"], | |
| 242 'specialSet' : ["mark","delmark","hmir","vmir","rot","brgt","cont","rgb","quality","size","calibrationx","scale","lessoptions"], | |
| 243 'arrowSet' : ["up", "down", "left", "right"], | |
| 244 'buttonSets' : ['standardSet', 'specialSet'] | |
| 245 }, | |
| 246 'embedded' : { | |
| 247 'imagePath' : 'img/embedded/16/', | |
| 248 'buttonSetWidth' : 18, | |
| 249 'standardSet' : ["reference","zoomin","zoomout","zoomarea","zoomfull","help","reset","toggleoptions"], | |
| 250 'specialSet' : ["mark","delmark","hmir","vmir","rot","brgt","cont","rgb","quality","scale","lessoptions"], | |
| 251 'arrowSet' : ["up", "down", "left", "right"], | |
| 252 'buttonSets' : ['standardSet', 'specialSet'] | |
| 253 }, | |
| 254 }, | |
| 255 // arrow bar overlays for moving the zoomed area | |
| 256 'showZoomArrows' : true, | |
| 257 // zoom arrow bar minimal width (for small images) | |
| 258 'zoomArrowMinWidth' : 6, | |
| 259 // zoom arrow bar standard width | |
| 260 'zoomArrowWidth' : 32, | |
| 261 // by what percentage should the arrows move the zoomed area? | |
| 262 'zoomArrowMoveFactor' : 0.5, | |
| 263 // number of visible button groups | |
| 264 'visibleButtonSets' : 1, | |
| 265 // is the "about" window shown? | |
| 266 'isAboutDivVisible' : false, | |
| 267 // default size of background image for drag-scroll (same as Bird's Eye View image) | |
| 268 'bgImgWidth' : 200, | |
| 269 'bgImgHeight' : 200, | |
| 270 // maximum width or height of background image for drag-scroll | |
| 271 'maxBgSize' : 10000, | |
| 272 // parameters used by background image | |
| 273 'bgImgParams' : ['fn','pn','dw','dh','mo','rot'], | |
| 274 // reserved space in full page display (default value accounts for vertical scrollbar) | |
| 275 'scalerInset' : 10 | |
| 276 }; | |
| 277 | |
| 278 // list of plugins | |
| 279 var plugins = {}; | |
| 280 // object to export functions to plugins | |
| 281 var fn; | |
| 282 // affine geometry plugin stub | |
| 283 var geom; | |
| 284 | |
| 285 var FULL_AREA; | |
| 286 | |
| 287 var actions = { | |
| 288 // init: digilib initialization | |
| 289 init : function(options) { | |
| 290 // import geometry classes | |
| 291 if (plugins.geometry == null) { | |
| 292 $.error("jquery.digilib.geometry plugin not found!"); | |
| 293 // last straw: old version | |
| 294 geom = dlGeometry(); | |
| 295 } else { | |
| 296 // geometry plugin puts classes in the shared fn | |
| 297 geom = fn.geometry; | |
| 298 } | |
| 299 FULL_AREA = geom.rectangle(0, 0, 1, 1); | |
| 300 | |
| 301 // settings for this digilib instance are merged from defaults and options | |
| 302 var settings = $.extend({}, defaults, options); | |
| 303 var isFullscreen = settings.interactionMode === 'fullscreen'; | |
| 304 var queryParams = {}; | |
| 305 if (isFullscreen) { | |
| 306 queryParams = parseQueryParams(); | |
| 307 // check scalerBaseUrl | |
| 308 if (settings.scalerBaseUrl == null) { | |
| 309 // try the host this came from | |
| 310 var h = window.location.host; | |
| 311 if (window.location.host) { | |
| 312 var url = window.location.href; | |
| 313 // assume the page lives in [webapp]/jquery/ | |
| 314 var pos = url.indexOf('jquery/'); | |
| 315 if (pos > 0) { | |
| 316 settings.scalerBaseUrl = url.substring(0, pos) + 'servlet/Scaler'; | |
| 317 } | |
| 318 } | |
| 319 } | |
| 320 } | |
| 321 return this.each(function() { | |
| 322 var $elem = $(this); | |
| 323 var data = $elem.data('digilib'); | |
| 324 var params, elemSettings; | |
| 325 // if the plugin hasn't been initialized yet | |
| 326 if (!data) { | |
| 327 // merge query parameters | |
| 328 if (isFullscreen) { | |
| 329 params = queryParams; | |
| 330 } else { | |
| 331 params = parseImgParams($elem); | |
| 332 if ($.cookie) { | |
| 333 // retrieve params from cookie | |
| 334 var ck = "digilib-embed:fn:" + escape(params.fn) + ":pn:" + (params.pn || '1'); | |
| 335 var cs = $.cookie(ck); | |
| 336 console.debug("get cookie=", ck, " value=", cs); | |
| 337 if (cs) { | |
| 338 var cp = parseQueryString(cs); | |
| 339 // ignore fn and pn from cookie TODO: should we keep pn? | |
| 340 delete cp.fn; | |
| 341 delete cp.pn; | |
| 342 $.extend(params, cp); | |
| 343 } | |
| 344 } | |
| 345 } | |
| 346 // setup $elem.data, needs "deep copy" because of nesting | |
| 347 elemSettings = $.extend(true, {}, settings, params); | |
| 348 data = { | |
| 349 // let $(this) know about $(this) :-) | |
| 350 $elem : $elem, | |
| 351 // let $elem have its own copy of settings | |
| 352 settings : elemSettings, | |
| 353 // and of the URL query parameters | |
| 354 queryParams : params, | |
| 355 // TODO: move plugins reference out of data | |
| 356 plugins : plugins | |
| 357 }; | |
| 358 // store in jQuery data element | |
| 359 $elem.data('digilib', data); | |
| 360 } | |
| 361 unpackParams(data); | |
| 362 // check if browser knows *background-size | |
| 363 for (var bs in {'':1, '-moz-':1, '-webkit-':1, '-o-':1}) { | |
| 364 if ($elem.css(bs+'background-size')) { | |
| 365 data.hasBgSize = true; | |
| 366 data.bgSizeName = bs+'background-size'; | |
| 367 break; | |
| 368 } | |
| 369 } | |
| 370 // check digilib base URL | |
| 371 if (elemSettings.digilibBaseUrl == null) { | |
| 372 if (isFullscreen) { | |
| 373 // take current host | |
| 374 var url = window.location.toString(); | |
| 375 var pos = url.indexOf('?'); | |
| 376 elemSettings.digilibBaseUrl = url.substring(0, pos); | |
| 377 } else { | |
| 378 var url = elemSettings.scalerBaseUrl; | |
| 379 if (url) { | |
| 380 // build it from scaler URL | |
| 381 var bp = url.indexOf('/servlet/Scaler'); | |
| 382 elemSettings.digilibBaseUrl = url.substring(0, bp) + '/digilib.jsp'; | |
| 383 } | |
| 384 } | |
| 385 } | |
| 386 // initialise plugins | |
| 387 for (n in plugins) { | |
| 388 var p = plugins[n]; | |
| 389 if (typeof p.init === 'function') { | |
| 390 p.init(data); | |
| 391 } | |
| 392 } | |
| 393 // get image info from server if needed | |
| 394 if (data.scaleMode === 'pixel' || data.scaleMode === 'size') { | |
| 395 $(data).bind('imageInfo', handleImageInfo); | |
| 396 loadImageInfo(data); // triggers "imageInfo" on completion | |
| 397 } | |
| 398 // create buttons before scaler | |
| 399 for (var i = 0; i < elemSettings.visibleButtonSets; ++i) { | |
| 400 showButtons(data, true, i); | |
| 401 } | |
| 402 // create HTML structure for scaler, taking width of buttons div into account | |
| 403 setupScalerDiv(data); | |
| 404 highlightButtons(data); | |
| 405 // about window creation - TODO: could be deferred? restrict to only one item? | |
| 406 setupAboutDiv(data); | |
| 407 // arrow overlays for moving zoomed detail | |
| 408 setupZoomArrows(data); | |
| 409 // send setup event | |
| 410 $(data).trigger('setup'); | |
| 411 }); | |
| 412 }, | |
| 413 | |
| 414 // destroy: clean up digilib | |
| 415 destroy : function(data) { | |
| 416 return this.each(function(){ | |
| 417 var $elem = $(this); | |
| 418 $(window).unbind('.digilib'); // unbind all digilibs(?) | |
| 419 data.digilib.remove(); | |
| 420 $elem.removeData('digilib'); | |
| 421 }); | |
| 422 }, | |
| 423 | |
| 424 // show or hide the 'about' window | |
| 425 showAboutDiv : function(data, show) { | |
| 426 var on = showDiv(data.settings.isAboutDivVisible, data.$aboutDiv, show); | |
| 427 data.settings.isAboutDivVisible = on; | |
| 428 highlightButtons(data, 'help', on); | |
| 429 }, | |
| 430 | |
| 431 // goto given page nr (+/-: relative) | |
| 432 gotoPage : function (data, pageNr) { | |
| 433 var settings = data.settings; | |
| 434 var oldpn = settings.pn; | |
| 435 if (pageNr == null) { | |
| 436 pageNr = window.prompt("Goto page number", oldpn); | |
| 437 } | |
| 438 var pn = setNumValue(settings, "pn", pageNr); | |
| 439 if (pn == null) return false; // nothing happened | |
| 440 if (pn < 1) { | |
| 441 alert("no such page (page number too low)"); | |
| 442 settings.pn = oldpn; | |
| 443 return false; | |
| 444 } | |
| 445 // TODO: how do we get pt? | |
| 446 if (settings.pt) { | |
| 447 if (pn > settings.pt) { | |
| 448 alert("no such page (page number too high)"); | |
| 449 settings.pn = oldpn; | |
| 450 return false; | |
| 451 } | |
| 452 } | |
| 453 // reset mk and others(?) | |
| 454 data.marks = []; | |
| 455 data.zoomArea = FULL_AREA; | |
| 456 // then reload | |
| 457 redisplay(data); | |
| 458 }, | |
| 459 | |
| 460 // zoom by a given factor | |
| 461 zoomBy : function (data, factor) { | |
| 462 zoomBy(data, factor); | |
| 463 }, | |
| 464 | |
| 465 // zoom to area (or interactive) | |
| 466 zoomArea : function (data, area) { | |
| 467 var settings = data.settings; | |
| 468 if (area == null) { | |
| 469 // interactively | |
| 470 zoomArea(data); | |
| 471 } else { | |
| 472 data.zoomArea = geom.rectangle(area); | |
| 473 redisplay(data); | |
| 474 } | |
| 475 }, | |
| 476 | |
| 477 // zoom out to full page | |
| 478 zoomFull : function (data, mode) { | |
| 479 data.zoomArea = FULL_AREA; | |
| 480 if (mode === 'width') { | |
| 481 data.dlOpts.fitwidth = 1; | |
| 482 delete data.dlOpts.fitheight; | |
| 483 } else if (mode === 'height') { | |
| 484 data.dlOpts.fitheight = 1; | |
| 485 delete data.dlOpts.fitwidth; | |
| 486 } else { | |
| 487 delete data.dlOpts.fitwidth; | |
| 488 delete data.dlOpts.fitheight; | |
| 489 } | |
| 490 redisplay(data); | |
| 491 }, | |
| 492 | |
| 493 // move zoomed area | |
| 494 moveZoomArea : function (data, dx, dy) { | |
| 495 var za = data.zoomArea; | |
| 496 var factor = data.settings.zoomArrowMoveFactor; | |
| 497 var deltaX = dx * factor * za.width; | |
| 498 var deltaY = dy * factor * za.height; | |
| 499 za.addPosition(geom.position(deltaX, deltaY)); | |
| 500 data.zoomArea = FULL_AREA.fit(za); | |
| 501 redisplay(data); | |
| 502 }, | |
| 503 | |
| 504 // set a mark by clicking (or giving a position) | |
| 505 setMark : function (data, mpos) { | |
| 506 if (mpos == null) { | |
| 507 // interactive | |
| 508 setMark(data); | |
| 509 } else { | |
| 510 // use position | |
| 511 data.marks.push(pos); | |
| 512 redisplay(data); | |
| 513 } | |
| 514 }, | |
| 515 | |
| 516 // remove the last mark | |
| 517 removeMark : function (data) { | |
| 518 data.marks.pop(); | |
| 519 redisplay(data); | |
| 520 }, | |
| 521 | |
| 522 // mirror the image | |
| 523 mirror : function (data, mode) { | |
| 524 var flags = data.scalerFlags; | |
| 525 if (mode === 'h') { | |
| 526 if (flags.hmir) { | |
| 527 delete flags.hmir; | |
| 528 } else { | |
| 529 flags.hmir = 1; | |
| 530 } | |
| 531 } else { | |
| 532 if (flags.vmir) { | |
| 533 delete flags.vmir; | |
| 534 } else { | |
| 535 flags.vmir = 1; | |
| 536 } | |
| 537 } | |
| 538 redisplay(data); | |
| 539 }, | |
| 540 | |
| 541 // rotate the image | |
| 542 rotate : function (data, angle) { | |
| 543 var rot = data.settings.rot; | |
| 544 if (angle == null) { | |
| 545 angle = window.prompt("Rotation angle:", rot); | |
| 546 } | |
| 547 data.settings.rot = angle; | |
| 548 redisplay(data); | |
| 549 }, | |
| 550 | |
| 551 // change brightness | |
| 552 brightness : function (data, factor) { | |
| 553 var brgt = data.settings.brgt; | |
| 554 if (factor == null) { | |
| 555 factor = window.prompt("Brightness (-255..255)", brgt); | |
| 556 } | |
| 557 data.settings.brgt = factor; | |
| 558 redisplay(data); | |
| 559 }, | |
| 560 | |
| 561 // change contrast | |
| 562 contrast : function (data, factor) { | |
| 563 var cont = data.settings.cont; | |
| 564 if (factor == null) { | |
| 565 factor = window.prompt("Contrast (-8, 8)", cont); | |
| 566 } | |
| 567 data.settings.cont = factor; | |
| 568 redisplay(data); | |
| 569 }, | |
| 570 | |
| 571 // display more (or less) button sets | |
| 572 moreButtons : function (data, more) { | |
| 573 var settings = data.settings; | |
| 574 if (more == null) { | |
| 575 // toggle more or less (only works for 2 sets) | |
| 576 var maxbtns = settings.buttonSettings[settings.interactionMode].buttonSets.length; | |
| 577 if (settings.visibleButtonSets >= maxbtns) { | |
| 578 more = '-1'; | |
| 579 } else { | |
| 580 more = '+1'; | |
| 581 } | |
| 582 } | |
| 583 if (more === '-1') { | |
| 584 // remove set | |
| 585 var setIdx = settings.visibleButtonSets - 1; | |
| 586 if (showButtons(data, false, setIdx, true)) { | |
| 587 settings.visibleButtonSets--; | |
| 588 } | |
| 589 } else { | |
| 590 // add set | |
| 591 var setIdx = settings.visibleButtonSets; | |
| 592 if (showButtons(data, true, setIdx, true)) { | |
| 593 settings.visibleButtonSets++; | |
| 594 } | |
| 595 } | |
| 596 // persist setting | |
| 597 storeOptions(data); | |
| 598 }, | |
| 599 | |
| 600 // reset image parameters to defaults | |
| 601 reset : function (data) { | |
| 602 var settings = data.settings; | |
| 603 var paramNames = settings.digilibParamNames; | |
| 604 var params = data.queryParams; | |
| 605 // delete all digilib parameters | |
| 606 for (var i = 0; i < paramNames.length; i++) { | |
| 607 var paramName = paramNames[i]; | |
| 608 delete settings[paramName]; | |
| 609 } | |
| 610 settings.fn = params.fn || ''; // no default defined | |
| 611 settings.pn = params.pn || defaults.pn; | |
| 612 settings.dw = params.dw; | |
| 613 settings.dh = params.dh; | |
| 614 settings.isBirdDivVisible = false; | |
| 615 settings.visibleButtonSets = 1; | |
| 616 // resets zoomArea, marks, scalerflags | |
| 617 data.zoomArea = FULL_AREA; | |
| 618 data.marks = []; | |
| 619 data.scalerFlags = {}; | |
| 620 delete data.dlOpts.fitwidth; | |
| 621 delete data.dlOpts.fitheight; | |
| 622 redisplay(data); | |
| 623 }, | |
| 624 | |
| 625 // presents a reference url (returns value if noprompt) | |
| 626 reference : function (data, noprompt) { | |
| 627 var settings = data.settings; | |
| 628 var url = getDigilibUrl(data); | |
| 629 if (noprompt == null) { | |
| 630 window.prompt("URL reference to the current view", url); | |
| 631 } | |
| 632 return url; | |
| 633 }, | |
| 634 | |
| 635 // set image quality | |
| 636 setQuality : function (data, qual) { | |
| 637 var oldq = getQuality(data); | |
| 638 if (qual == null) { | |
| 639 qual = window.prompt("Image quality (0..2)", oldq); | |
| 640 } | |
| 641 qual = parseInt(qual, 10); | |
| 642 if (qual >= 0 && qual <= 2) { | |
| 643 setQuality(data, qual); | |
| 644 redisplay(data); | |
| 645 } | |
| 646 }, | |
| 647 | |
| 648 // calibrate (only faking) | |
| 649 calibrate : function (data, res) { | |
| 650 var oldRes = data.settings.ddpi; | |
| 651 if (res == null) { | |
| 652 res = window.prompt("Display resolution (dpi)", oldRes); | |
| 653 } | |
| 654 if (res != null) { | |
| 655 data.settings.ddpi = res; | |
| 656 redisplay(data); | |
| 657 } | |
| 658 }, | |
| 659 | |
| 660 // set image scale mode | |
| 661 setScaleMode : function (data, mode) { | |
| 662 var oldM = getScaleMode(data); | |
| 663 if (mode == null) { | |
| 664 mode = window.prompt("Image scale mode (screen, pixel, size)", oldM); | |
| 665 } | |
| 666 if (mode != null) { | |
| 667 setScaleMode(data, mode); | |
| 668 data.scaleMode = mode; | |
| 669 redisplay(data); | |
| 670 } | |
| 671 } | |
| 672 | |
| 673 // end of actions | |
| 674 }; | |
| 675 | |
| 676 // returns parameters from page url | |
| 677 var parseQueryParams = function() { | |
| 678 return parseQueryString(window.location.search.slice(1)); | |
| 679 }; | |
| 680 | |
| 681 // returns parameters from embedded img-element | |
| 682 var parseImgParams = function($elem) { | |
| 683 var src = $elem.find('img').first().attr('src'); | |
| 684 if (!src) return null; | |
| 685 var pos = src.indexOf('?'); | |
| 686 var query = (pos < 0) ? '' : src.substring(pos + 1); | |
| 687 var scalerUrl = src.substring(0, pos); | |
| 688 var params = parseQueryString(query); | |
| 689 params.scalerBaseUrl = scalerUrl; | |
| 690 return params; | |
| 691 }; | |
| 692 | |
| 693 // parses query parameter string into parameter object | |
| 694 var parseQueryString = function(query) { | |
| 695 var params = {}; | |
| 696 if (query == null) return params; | |
| 697 var pairs = query.split("&"); | |
| 698 //var keys = []; | |
| 699 for (var i = 0; i < pairs.length; i++) { | |
| 700 var pair = pairs[i].split("="); | |
| 701 if (pair.length === 2) { | |
| 702 params[pair[0]] = pair[1]; | |
| 703 //keys.push(pair[0]); | |
| 704 } | |
| 705 } | |
| 706 return params; | |
| 707 }; | |
| 708 | |
| 709 // returns a query string from key names from a parameter hash (ignoring if the same value is in defaults) | |
| 710 var getParamString = function (settings, keys, defaults) { | |
| 711 var paramString = ''; | |
| 712 var nx = false; | |
| 713 for (i = 0; i < keys.length; ++i) { | |
| 714 var key = keys[i]; | |
| 715 if ((settings[key] != null) && ((defaults == null) || (settings[key] != defaults[key]))) { | |
| 716 // first param gets no '&' | |
| 717 if (nx) { | |
| 718 paramString += '&'; | |
| 719 } else { | |
| 720 nx = true; | |
| 721 } | |
| 722 // add parm=val | |
| 723 paramString += key + '=' + settings[key]; | |
| 724 } | |
| 725 } | |
| 726 return paramString; | |
| 727 }; | |
| 728 | |
| 729 // returns URL and query string for Scaler | |
| 730 var getScalerUrl = function (data) { | |
| 731 packParams(data); | |
| 732 var settings = data.settings; | |
| 733 if (settings.scalerBaseUrl == null) { | |
| 734 alert("ERROR: URL of digilib Scaler servlet missing!"); | |
| 735 } | |
| 736 var keys = settings.scalerParamNames; | |
| 737 var queryString = getParamString(settings, keys, defaults); | |
| 738 var url = settings.scalerBaseUrl + '?' + queryString; | |
| 739 return url; | |
| 740 }; | |
| 741 | |
| 742 // returns URL for bird's eye view image | |
| 743 var getBgImgUrl = function (data, moreParams) { | |
| 744 var settings = data.settings; | |
| 745 var bgOptions = { | |
| 746 dw : settings.bgImgWidth, | |
| 747 dh : settings.bgImgHeight | |
| 748 }; | |
| 749 var bgSettings = $.extend({}, settings, bgOptions); | |
| 750 // filter scaler flags | |
| 751 if (bgSettings.mo != null) { | |
| 752 var mo = ''; | |
| 753 if (data.scalerFlags.hmir != null) { | |
| 754 mo += 'hmir,'; | |
| 755 } | |
| 756 if (data.scalerFlags.vmir != null) { | |
| 757 mo += 'vmir'; | |
| 758 } | |
| 759 bgSettings.mo = mo; | |
| 760 } | |
| 761 var params = getParamString(bgSettings, settings.bgImgParams, defaults); | |
| 762 var url = settings.scalerBaseUrl + '?' + params; | |
| 763 return url; | |
| 764 }; | |
| 765 | |
| 766 // returns URL and query string for current digilib | |
| 767 var getDigilibUrl = function (data) { | |
| 768 packParams(data); | |
| 769 var settings = data.settings; | |
| 770 var queryString = getParamString(settings, settings.digilibParamNames, defaults); | |
| 771 return settings.digilibBaseUrl + '?' + queryString; | |
| 772 }; | |
| 773 | |
| 774 // loads image information from digilib server via HTTP | |
| 775 var loadImageInfo = function (data) { | |
| 776 var settings = data.settings; | |
| 777 var p = settings.scalerBaseUrl.indexOf('/servlet/Scaler'); | |
| 778 var url = settings.scalerBaseUrl.substring(0, p) + '/ImgInfo-json.jsp'; | |
| 779 url += '?' + getParamString(settings, ['fn', 'pn'], defaults); | |
| 780 // TODO: better error handling | |
| 781 $.getJSON(url, function (json) { | |
| 782 console.debug("got json data=", json); | |
| 783 data.imgInfo = json; | |
| 784 // send event | |
| 785 $(data).trigger('imageInfo', [json]); | |
| 786 }); | |
| 787 }; | |
| 788 | |
| 789 // processes some parameters into objects and stuff | |
| 790 var unpackParams = function (data) { | |
| 791 var settings = data.settings; | |
| 792 // zoom area | |
| 793 var zoomArea = geom.rectangle(settings.wx, settings.wy, settings.ww, settings.wh); | |
| 794 data.zoomArea = zoomArea; | |
| 795 // marks | |
| 796 var marks = []; | |
| 797 if (settings.mk) { | |
| 798 var mk = settings.mk; | |
| 799 if (mk.indexOf(";") >= 0) { | |
| 800 var pa = mk.split(";"); // old format with ";" | |
| 801 } else { | |
| 802 var pa = mk.split(","); // new format | |
| 803 } | |
| 804 for (var i = 0; i < pa.length ; i++) { | |
| 805 var pos = pa[i].split("/"); | |
| 806 if (pos.length > 1) { | |
| 807 marks.push(geom.position(pos[0], pos[1])); | |
| 808 } | |
| 809 } | |
| 810 } | |
| 811 data.marks = marks; | |
| 812 // mo (Scaler flags) | |
| 813 var flags = {}; | |
| 814 if (settings.mo) { | |
| 815 var pa = settings.mo.split(","); | |
| 816 for (var i = 0; i < pa.length ; i++) { | |
| 817 flags[pa[i]] = pa[i]; | |
| 818 } | |
| 819 } | |
| 820 data.scalerFlags = flags; | |
| 821 data.scaleMode = getScaleMode(data); | |
| 822 retrieveOptions(data); | |
| 823 }; | |
| 824 | |
| 825 // put area into parameters | |
| 826 var packArea = function (settings, area) { | |
| 827 if (!area) return; | |
| 828 // zoom area | |
| 829 settings.wx = cropFloat(area.x); | |
| 830 settings.wy = cropFloat(area.y); | |
| 831 settings.ww = cropFloat(area.width); | |
| 832 settings.wh = cropFloat(area.height); | |
| 833 }; | |
| 834 | |
| 835 // put marks into parameters | |
| 836 var packMarks = function (settings, marks) { | |
| 837 if (!marks) return; | |
| 838 settings.mk = ''; | |
| 839 for (var i = 0; i < marks.length; i++) { | |
| 840 if (i) { | |
| 841 settings.mk += ','; | |
| 842 } | |
| 843 settings.mk += | |
| 844 cropFloatStr(marks[i].x) + '/' + | |
| 845 cropFloatStr(marks[i].y); | |
| 846 } | |
| 847 }; | |
| 848 | |
| 849 // pack scaler flags into parameters | |
| 850 var packScalerFlags = function (settings, flags) { | |
| 851 if (!flags) return; | |
| 852 var mo = ''; | |
| 853 for (var f in flags) { | |
| 854 if (mo) { | |
| 855 mo += ','; | |
| 856 } | |
| 857 mo += f; | |
| 858 } | |
| 859 settings.mo = mo; | |
| 860 }; | |
| 861 | |
| 862 // put objects back into parameters | |
| 863 var packParams = function (data) { | |
| 864 var settings = data.settings; | |
| 865 packArea(settings, data.zoomArea); | |
| 866 packMarks(settings, data.marks); | |
| 867 packScalerFlags(settings, data.scalerFlags); | |
| 868 // store user interface options in cookie | |
| 869 storeOptions(data); | |
| 870 }; | |
| 871 | |
| 872 var storeOptions = function (data) { | |
| 873 // save digilib options in cookie | |
| 874 var settings = data.settings; | |
| 875 if (data.dlOpts) { | |
| 876 // save digilib settings in options | |
| 877 data.dlOpts.birdview = settings.isBirdDivVisible ? 1 : 0; | |
| 878 data.dlOpts.buttons = settings.visibleButtonSets; | |
| 879 var clop = ''; | |
| 880 for (var o in data.dlOpts) { | |
| 881 if (clop) { | |
| 882 clop += '&'; | |
| 883 } | |
| 884 clop += o + '=' + data.dlOpts[o]; | |
| 885 } | |
| 886 if ($.cookie) { | |
| 887 var ck = "digilib:fn:" + escape(settings.fn) + ":pn:" + settings.pn; | |
| 888 console.debug("set cookie=", ck, " value=", clop); | |
| 889 $.cookie(ck, clop); | |
| 890 } | |
| 891 } | |
| 892 if (settings.interactionMode !== 'fullscreen' && $.cookie) { | |
| 893 // store normal parameters in cookie for embedded mode | |
| 894 var qs = getParamString(settings, settings.digilibParamNames, defaults); | |
| 895 var ck = "digilib-embed:fn:" + escape(settings.fn) + ":pn:" + settings.pn; | |
| 896 console.debug("set cookie=", ck, " value=", qs); | |
| 897 $.cookie(ck, qs); | |
| 898 } | |
| 899 }; | |
| 900 | |
| 901 var retrieveOptions = function (data) { | |
| 902 // clop (digilib options) | |
| 903 var opts = {}; | |
| 904 var settings = data.settings; | |
| 905 if ($.cookie) { | |
| 906 // read from cookie | |
| 907 var ck = "digilib:fn:" + escape(settings.fn) + ":pn:" + settings.pn; | |
| 908 var cp = $.cookie(ck); | |
| 909 console.debug("get cookie=", ck, " value=", cp); | |
| 910 // in query string format | |
| 911 opts = parseQueryString(cp); | |
| 912 } | |
| 913 data.dlOpts = opts; | |
| 914 // birdview option | |
| 915 if (opts.birdview != null) { | |
| 916 settings.isBirdDivVisible = opts.birdview === '1'; | |
| 917 } | |
| 918 // visible button sets | |
| 919 if (opts.buttons != null) { | |
| 920 settings.visibleButtonSets = opts.buttons; | |
| 921 } | |
| 922 }; | |
| 923 | |
| 924 // (re)load the img from a new scaler URL | |
| 925 var redisplay = function (data) { | |
| 926 var settings = data.settings; | |
| 927 if (settings.interactionMode === 'fullscreen') { | |
| 928 // update location.href (browser URL) in fullscreen mode | |
| 929 var url = getDigilibUrl(data); | |
| 930 var history = window.history; | |
| 931 if (typeof history.pushState === 'function') { | |
| 932 console.debug("faking reload to "+url); | |
| 933 // change url without reloading (stateObj, title, url) | |
| 934 // TODO: we really need to push the state in stateObj and listen to pop-events | |
| 935 history.replaceState({}, '', url); | |
| 936 // change img src | |
| 937 var imgurl = getScalerUrl(data); | |
| 938 data.$img.attr('src', imgurl); | |
| 939 highlightButtons(data); | |
| 940 // send event | |
| 941 $(data).trigger('redisplay'); | |
| 942 } else { | |
| 943 // reload window | |
| 944 window.location = url; | |
| 945 } | |
| 946 } else { | |
| 947 // embedded mode -- just change img src | |
| 948 var url = getScalerUrl(data); | |
| 949 data.$img.attr('src', url); | |
| 950 highlightButtons(data); | |
| 951 // send event | |
| 952 $(data).trigger('redisplay'); | |
| 953 } | |
| 954 }; | |
| 955 | |
| 956 // update display (overlays etc.) | |
| 957 var updateDisplay = function (data) { | |
| 958 updateImgTrafo(data); | |
| 959 renderMarks(data); | |
| 960 setupZoomDrag(data); | |
| 961 renderZoomArrows(data); | |
| 962 // send event | |
| 963 $(data).trigger('update'); | |
| 964 }; | |
| 965 | |
| 966 // returns maximum size for scaler img in fullscreen mode | |
| 967 var getFullscreenImgSize = function (data) { | |
| 968 var mode = data.settings.interactionMode; | |
| 969 var $win = $(window); | |
| 970 var winH = $win.height(); | |
| 971 var winW = $win.width(); | |
| 972 var $body = $('body'); | |
| 973 // include standard body margins and check plausibility | |
| 974 var borderW = $body.outerWidth(true) - $body.width(); | |
| 975 if (borderW === 0 || borderW > 100) { | |
| 976 console.debug("fixing border width for getFullscreenImgSize!"); | |
| 977 borderW = data.settings.scalerInset; | |
| 978 } | |
| 979 var borderH = $body.outerHeight(true) - $body.height(); | |
| 980 if (borderH === 0 || borderH > 100) { | |
| 981 console.debug("fixing border height for getFullscreenImgSize!"); | |
| 982 borderH = 5; | |
| 983 } | |
| 984 var buttonsW = 0; | |
| 985 if (data.settings.visibleButtonSets) { | |
| 986 // get button width from settings | |
| 987 buttonsW = data.settings.buttonSettings[mode].buttonSetWidth; | |
| 988 // TODO: leave space for all button sets? | |
| 989 } | |
| 990 // account for left/right border, body margins and additional requirements | |
| 991 var imgW = winW - borderW - buttonsW; | |
| 992 var imgH = winH - borderH; | |
| 993 console.debug(winW, winH, 'winW:', $win.width(), 'border:', borderW, 'buttonsW:', buttonsW, 'calc:', imgW); | |
| 994 return geom.size(imgW, imgH); | |
| 995 }; | |
| 996 | |
| 997 // creates HTML structure for digilib in elem | |
| 998 var setupScalerDiv = function (data) { | |
| 999 var settings = data.settings; | |
| 1000 var $elem = data.$elem; | |
| 1001 $elem.addClass('digilib'); | |
| 1002 var $img; | |
| 1003 var scalerUrl; | |
| 1004 if (settings.interactionMode === 'fullscreen') { | |
| 1005 // fullscreen | |
| 1006 $elem.addClass('dl_fullscreen'); | |
| 1007 var imgSize = getFullscreenImgSize(data); | |
| 1008 // fitwidth/height omits destination height/width | |
| 1009 if (data.dlOpts.fitheight == null) { | |
| 1010 settings.dw = imgSize.width; | |
| 1011 } | |
| 1012 if (data.dlOpts.fitwidth == null) { | |
| 1013 settings.dh = imgSize.height; | |
| 1014 } | |
| 1015 scalerUrl = getScalerUrl(data); | |
| 1016 $img = $('<img/>'); | |
| 1017 } else { | |
| 1018 // embedded mode -- try to keep img tag | |
| 1019 $elem.addClass('dl_embedded'); | |
| 1020 scalerUrl = getScalerUrl(data); | |
| 1021 $img = $elem.find('img'); | |
| 1022 if ($img.length > 0) { | |
| 1023 var oldUrl = $img.attr('src'); | |
| 1024 // keep img attributes from html | |
| 1025 var title = $img.attr('title'); | |
| 1026 var alt = $img.attr('alt'); | |
| 1027 if (oldUrl === scalerUrl) { | |
| 1028 console.debug("img detach:", $img); | |
| 1029 $img.detach(); | |
| 1030 } else { | |
| 1031 $img = $('<img/>'); | |
| 1032 $img.attr("title", title); | |
| 1033 $img.attr("alt", alt); | |
| 1034 } | |
| 1035 } else { | |
| 1036 $img = $('<img/>'); | |
| 1037 } | |
| 1038 } | |
| 1039 // create new inner html, keeping buttons and content marked with "keep" class | |
| 1040 $elem.contents(":not(.keep)").remove(); | |
| 1041 var $scaler = $('<div class="scaler"/>'); | |
| 1042 // scaler should be the first child element? | |
| 1043 $elem.prepend($scaler); | |
| 1044 $scaler.append($img); | |
| 1045 $img.addClass('pic'); | |
| 1046 data.$scaler = $scaler; | |
| 1047 data.$img = $img; | |
| 1048 // setup image load handler before setting the src attribute (IE bug) | |
| 1049 $img.load(scalerImgLoadedHandler(data)); | |
| 1050 $img.error(function () {console.error("error loading scaler image");}); | |
| 1051 $img.attr('src', scalerUrl); | |
| 1052 }; | |
| 1053 | |
| 1054 // creates HTML structure for a single button | |
| 1055 var createButton = function (data, $div, buttonName) { | |
| 1056 var $elem = data.$elem; | |
| 1057 var settings = data.settings; | |
| 1058 var mode = settings.interactionMode; | |
| 1059 var imagePath = settings.buttonSettings[mode].imagePath; | |
| 1060 var buttonConfig = settings.buttons[buttonName]; | |
| 1061 // button properties | |
| 1062 var action = buttonConfig.onclick; | |
| 1063 var tooltip = buttonConfig.tooltip; | |
| 1064 var icon = imagePath + buttonConfig.icon; | |
| 1065 // construct the button html | |
| 1066 var $button = $('<div class="button"></div>'); | |
| 1067 var $a = $('<a/>'); | |
| 1068 var $img = $('<img class="button"/>'); | |
| 1069 $div.append($button); | |
| 1070 $button.append($a); | |
| 1071 $a.append($img); | |
| 1072 // add attributes and bindings | |
| 1073 $button.attr('title', tooltip); | |
| 1074 $button.addClass('button-' + buttonName); | |
| 1075 $img.attr('src', icon); | |
| 1076 // create handler for the buttons | |
| 1077 $button.bind('click.digilib', (function () { | |
| 1078 // we create a new closure to capture the value of action | |
| 1079 if ($.isArray(action)) { | |
| 1080 // the handler function calls digilib with action and parameters | |
| 1081 return function (evt) { | |
| 1082 console.debug('click action=', action, ' evt=', evt); | |
| 1083 $elem.digilib.apply($elem, action); | |
| 1084 return false; | |
| 1085 }; | |
| 1086 } else { | |
| 1087 // the handler function calls digilib with action | |
| 1088 return function (evt) { | |
| 1089 console.debug('click action=', action, ' evt=', evt); | |
| 1090 $elem.digilib(action); | |
| 1091 return false; | |
| 1092 }; | |
| 1093 } | |
| 1094 })()); | |
| 1095 }; | |
| 1096 | |
| 1097 // creates HTML structure for buttons in elem | |
| 1098 var createButtons = function (data, buttonSetIdx) { | |
| 1099 var $elem = data.$elem; | |
| 1100 var settings = data.settings; | |
| 1101 var mode = settings.interactionMode; | |
| 1102 var buttonSettings = settings.buttonSettings[mode]; | |
| 1103 var buttonGroup = buttonSettings.buttonSets[buttonSetIdx]; | |
| 1104 if (buttonGroup == null) { | |
| 1105 // no buttons here | |
| 1106 return; | |
| 1107 } | |
| 1108 // button divs are marked with class "keep" | |
| 1109 var $buttonsDiv = $('<div class="keep buttons"/>'); | |
| 1110 var buttonNames = buttonSettings[buttonGroup]; | |
| 1111 for (var i = 0; i < buttonNames.length; i++) { | |
| 1112 var buttonName = buttonNames[i]; | |
| 1113 createButton(data, $buttonsDiv, buttonName); | |
| 1114 } | |
| 1115 // make buttons div scroll if too large for window | |
| 1116 if ($buttonsDiv.height() > $(window).height() - 10) { | |
| 1117 $buttonsDiv.css('position', 'absolute'); | |
| 1118 } | |
| 1119 // buttons hidden at first | |
| 1120 $buttonsDiv.hide(); | |
| 1121 $elem.append($buttonsDiv); | |
| 1122 if (data.$buttonSets == null) { | |
| 1123 // first button set | |
| 1124 data.$buttonSets = [$buttonsDiv]; | |
| 1125 } else { | |
| 1126 $elem.append($buttonsDiv); | |
| 1127 data.$buttonSets[buttonSetIdx] = $buttonsDiv; | |
| 1128 } | |
| 1129 return $buttonsDiv; | |
| 1130 }; | |
| 1131 | |
| 1132 // creates arrow overlays for moving the zoomed area | |
| 1133 var setupZoomArrows = function (data) { | |
| 1134 var $elem = data.$elem; | |
| 1135 var settings = data.settings; | |
| 1136 var show = settings.showZoomArrows; | |
| 1137 console.log('zoom arrows:', show); | |
| 1138 if (!show) return; | |
| 1139 var mode = settings.interactionMode; | |
| 1140 var arrowNames = settings.buttonSettings[mode].arrowSet; | |
| 1141 if (arrowNames == null) return; | |
| 1142 // arrow divs are marked with class "keep" | |
| 1143 var $arrowsDiv = $('<div class="keep arrows"/>'); | |
| 1144 $elem.append($arrowsDiv); | |
| 1145 // create all arrow buttons | |
| 1146 $.each(arrowNames, function(i, arrowName){ | |
| 1147 createButton(data, $arrowsDiv, arrowName); | |
| 1148 }); | |
| 1149 }; | |
| 1150 | |
| 1151 // size and show arrow overlays, called after scaler img is loaded | |
| 1152 var renderZoomArrows = function (data) { | |
| 1153 var settings = data.settings; | |
| 1154 var $arrowsDiv = data.$elem.find('div.arrows'); | |
| 1155 if (isFullArea(data.zoomArea) || !settings.showZoomArrows) { | |
| 1156 $arrowsDiv.hide(); | |
| 1157 return; | |
| 1158 } | |
| 1159 $arrowsDiv.show(); | |
| 1160 var r = geom.rectangle(data.$scaler); | |
| 1161 // calculate arrow bar width | |
| 1162 var aw = settings.zoomArrowWidth; | |
| 1163 var minWidth = settings.zoomArrowMinWidth; | |
| 1164 // arrow bar width should not exceed 10% of scaler width/height | |
| 1165 var maxWidth = Math.min(r.width, r.height)/10; | |
| 1166 if (aw > maxWidth) { | |
| 1167 aw = maxWidth; | |
| 1168 if (aw < minWidth) { | |
| 1169 aw = minWidth; | |
| 1170 } | |
| 1171 } | |
| 1172 // vertical position of left/right image | |
| 1173 var arrowData = [{ | |
| 1174 name : 'up', | |
| 1175 rect : geom.rectangle(r.x, r.y, r.width, aw), | |
| 1176 show : canMove(data, 0, -1) | |
| 1177 }, { | |
| 1178 name : 'down', | |
| 1179 rect : geom.rectangle(r.x, r.y + r.height - aw, r.width, aw), | |
| 1180 show : canMove(data, 0, 1) | |
| 1181 }, { | |
| 1182 name : 'left', | |
| 1183 rect : geom.rectangle(r.x, r.y, aw, r.height), | |
| 1184 show : canMove(data, -1, 0) | |
| 1185 }, { | |
| 1186 name : 'right', | |
| 1187 rect : geom.rectangle(r.x + r.width - aw, r.y, aw, r.height), | |
| 1188 show : canMove(data, 1, 0) | |
| 1189 }]; | |
| 1190 // render a single zoom Arrow | |
| 1191 var render = function (i, item) { | |
| 1192 var $arrow = $arrowsDiv.find('div.button-' + item.name); | |
| 1193 if (item.show) { | |
| 1194 $arrow.show(); | |
| 1195 } else { | |
| 1196 $arrow.hide(); | |
| 1197 return; | |
| 1198 } | |
| 1199 var r = item.rect; | |
| 1200 r.adjustDiv($arrow); | |
| 1201 var $a = $arrow.contents('a'); | |
| 1202 var $img = $a.contents('img'); | |
| 1203 $img.width(aw).height(aw); | |
| 1204 // hack for missing vertical-align | |
| 1205 if (item.name.match(/left|right/)) { | |
| 1206 var top = (r.height - $a.height())/2; | |
| 1207 $a.css({'top' : top}); // position : 'relative' | |
| 1208 } | |
| 1209 }; | |
| 1210 $.each(arrowData, render); | |
| 1211 }; | |
| 1212 | |
| 1213 // creates HTML structure for the about view in elem | |
| 1214 var setupAboutDiv = function (data) { | |
| 1215 var $elem = data.$elem; | |
| 1216 var settings = data.settings; | |
| 1217 var $aboutDiv = $('<div class="about" style="display:none"/>'); | |
| 1218 var $header = $('<p>Digilib Image Viewer</p>'); | |
| 1219 var $link = $('<a/>'); | |
| 1220 var $logo = $('<img class="logo" title="digilib"/>'); | |
| 1221 var $content = $('<p/>'); | |
| 1222 $elem.append($aboutDiv); | |
| 1223 $aboutDiv.append($header); | |
| 1224 $aboutDiv.append($link); | |
| 1225 $aboutDiv.append($content); | |
| 1226 $link.append($logo); | |
| 1227 $logo.attr('src', settings.logoUrl); | |
| 1228 $link.attr('href', settings.homeUrl); | |
| 1229 $content.text('Version: ' + settings.version); | |
| 1230 data.$aboutDiv = $aboutDiv; | |
| 1231 // click hides | |
| 1232 $aboutDiv.bind('click.digilib', function () { | |
| 1233 actions['showAboutDiv'](data, false); | |
| 1234 }); | |
| 1235 }; | |
| 1236 | |
| 1237 // shows some window e.g. 'about' (toggle visibility if show is null) | |
| 1238 var showDiv = function (isVisible, $div, show) { | |
| 1239 if (show == null) { | |
| 1240 // toggle visibility | |
| 1241 isVisible = !isVisible; | |
| 1242 } else { | |
| 1243 // set visibility | |
| 1244 isVisible = show; | |
| 1245 } | |
| 1246 if (isVisible) { | |
| 1247 $div.fadeIn(); | |
| 1248 } else { | |
| 1249 $div.fadeOut(); | |
| 1250 } | |
| 1251 return isVisible; | |
| 1252 }; | |
| 1253 | |
| 1254 // display more (or less) button sets | |
| 1255 var showButtons = function (data, more, setIdx, animated) { | |
| 1256 var atime = animated ? 'fast': 0; | |
| 1257 // get button width from settings | |
| 1258 var mode = data.settings.interactionMode; | |
| 1259 var btnWidth = data.settings.buttonSettings[mode].buttonSetWidth; | |
| 1260 if (more) { | |
| 1261 // add set | |
| 1262 var $otherSets = data.$elem.find('div.buttons:visible'); | |
| 1263 var $set; | |
| 1264 if (data.$buttonSets && data.$buttonSets[setIdx]) { | |
| 1265 // set exists | |
| 1266 $set = data.$buttonSets[setIdx]; | |
| 1267 } else { | |
| 1268 $set = createButtons(data, setIdx); | |
| 1269 } | |
| 1270 if ($set == null) return false; | |
| 1271 // include border in calculation | |
| 1272 //var btnWidth = $set.outerWidth(); | |
| 1273 // console.debug("btnWidth", btnWidth); | |
| 1274 // move remaining sets left and show new set | |
| 1275 if ($otherSets.length > 0) { | |
| 1276 $otherSets.animate({right : '+='+btnWidth+'px'}, atime, | |
| 1277 function () {$set.show();}); | |
| 1278 } else { | |
| 1279 $set.show(); | |
| 1280 } | |
| 1281 } else { | |
| 1282 // remove set | |
| 1283 var $set = data.$buttonSets[setIdx]; | |
| 1284 if ($set == null) return false; | |
| 1285 //var btnWidth = $set.outerWidth(); | |
| 1286 // hide last set | |
| 1287 $set.hide(); | |
| 1288 // take remaining sets and move right | |
| 1289 var $otherSets = data.$elem.find('div.buttons:visible'); | |
| 1290 $otherSets.animate({right : '-='+btnWidth+'px'}, atime); | |
| 1291 } | |
| 1292 return true; | |
| 1293 }; | |
| 1294 | |
| 1295 // check for buttons to highlight | |
| 1296 var highlightButtons = function (data, name, on) { | |
| 1297 var $buttons = data.$elem.find('div.buttons:visible'); // include hidden? | |
| 1298 // add a class for highlighted button | |
| 1299 var highlight = function (name, on) { | |
| 1300 var $button = $buttons.find('div.button-' + name); | |
| 1301 if (on) { | |
| 1302 $button.addClass('button-on'); | |
| 1303 } else { | |
| 1304 $button.removeClass('button-on'); | |
| 1305 } | |
| 1306 }; | |
| 1307 if (name != null) { | |
| 1308 return highlight(name, on); | |
| 1309 } | |
| 1310 var flags = data.scalerFlags; | |
| 1311 var settings = data.settings; | |
| 1312 highlight('rot', settings.rot); | |
| 1313 highlight('brgt', settings.brgt); | |
| 1314 highlight('cont', settings.cont); | |
| 1315 highlight('bird', settings.isBirdDivVisible); | |
| 1316 highlight('help', settings.isAboutDivVisible); | |
| 1317 highlight('hmir', flags.hmir); | |
| 1318 highlight('vmir', flags.vmir); | |
| 1319 highlight('quality', flags.q1 || flags.q2); | |
| 1320 highlight('zoomin', ! isFullArea(data.zoomArea)); | |
| 1321 }; | |
| 1322 | |
| 1323 // create Transform from area and $img | |
| 1324 var getImgTrafo = function ($img, area, rot, hmir, vmir, mode, data) { | |
| 1325 var picrect = geom.rectangle($img); | |
| 1326 if (mode != null) { | |
| 1327 var imgInfo = data.imgInfo; | |
| 1328 if (mode === 'pixel') { | |
| 1329 // scaler mo=clip - image area size does not come from ww, wh | |
| 1330 if (imgInfo != null) { | |
| 1331 area.width = picrect.width / imgInfo.width; | |
| 1332 area.height = picrect.height / imgInfo.height; | |
| 1333 } else { | |
| 1334 console.error("No image info for pixel mode!"); | |
| 1335 } | |
| 1336 } | |
| 1337 if (mode === 'size') { | |
| 1338 // scaler mo=osize - image area size does not come from ww, wh | |
| 1339 if (imgInfo != null) { | |
| 1340 var ddpi = parseFloat(data.settings.ddpi); | |
| 1341 area.width = (picrect.width / ddpi) / (imgInfo.width / imgInfo.dpi_x); | |
| 1342 area.height = (picrect.height / ddpi) / (imgInfo.height / imgInfo.dpi_y); | |
| 1343 } else { | |
| 1344 console.error("No image info for original size mode!"); | |
| 1345 } | |
| 1346 } | |
| 1347 } | |
| 1348 var trafo = geom.transform(); | |
| 1349 // move zoom area offset to center | |
| 1350 trafo.concat(trafo.getTranslation(geom.position(-area.x, -area.y))); | |
| 1351 // scale zoom area size to [1,1] | |
| 1352 trafo.concat(trafo.getScale(geom.size(1/area.width, 1/area.height))); | |
| 1353 // rotate and mirror (around transformed image center i.e. [0.5,0.5]) | |
| 1354 if (rot || hmir || vmir) { | |
| 1355 // move [0.5,0.5] to center | |
| 1356 trafo.concat(trafo.getTranslation(geom.position(-0.5, -0.5))); | |
| 1357 if (hmir) { | |
| 1358 // mirror about center | |
| 1359 trafo.concat(trafo.getMirror('y')); | |
| 1360 } | |
| 1361 if (vmir) { | |
| 1362 // mirror about center | |
| 1363 trafo.concat(trafo.getMirror('x')); | |
| 1364 } | |
| 1365 if (rot) { | |
| 1366 // rotate around center | |
| 1367 trafo.concat(trafo.getRotation(parseFloat(rot))); | |
| 1368 } | |
| 1369 // move back | |
| 1370 trafo.concat(trafo.getTranslation(geom.position(0.5, 0.5))); | |
| 1371 } | |
| 1372 // scale to screen position and size | |
| 1373 trafo.concat(trafo.getScale(picrect)); | |
| 1374 trafo.concat(trafo.getTranslation(picrect)); | |
| 1375 return trafo; | |
| 1376 }; | |
| 1377 | |
| 1378 // update scaler image transform | |
| 1379 var updateImgTrafo = function (data) { | |
| 1380 var $img = data.$img; | |
| 1381 if ($img != null && $img.get(0).complete) { | |
| 1382 // create Transform from current zoomArea and image size | |
| 1383 data.imgTrafo = getImgTrafo($img, data.zoomArea, | |
| 1384 data.settings.rot, data.scalerFlags.hmir, data.scalerFlags.vmir, | |
| 1385 data.scaleMode, data); | |
| 1386 // console.debug("imgTrafo=", data.imgTrafo); | |
| 1387 } | |
| 1388 }; | |
| 1389 | |
| 1390 // returns handler for load event of scaler img | |
| 1391 var scalerImgLoadedHandler = function (data) { | |
| 1392 return function () { | |
| 1393 var $img = $(this); | |
| 1394 console.debug("scaler img loaded=",$img); | |
| 1395 var $scaler = data.$scaler; | |
| 1396 var imgRect = geom.rectangle($img); | |
| 1397 // adjust scaler div size | |
| 1398 imgRect.adjustDiv($scaler); | |
| 1399 // show image in case it was hidden (for example in zoomDrag) | |
| 1400 $img.css('visibility', 'visible'); | |
| 1401 $scaler.css({'opacity' : '1', 'background-image' : 'none'}); | |
| 1402 // update display (render marks, etc.) | |
| 1403 updateDisplay(data); | |
| 1404 }; | |
| 1405 }; | |
| 1406 | |
| 1407 // handler for imageInfo loaded event | |
| 1408 var handleImageInfo = function (evt, json) { | |
| 1409 var data = this; | |
| 1410 updateDisplay(data); | |
| 1411 }; | |
| 1412 | |
| 1413 // place marks on the image | |
| 1414 var renderMarks = function (data) { | |
| 1415 if (data.$img == null || data.imgTrafo == null) return; | |
| 1416 console.debug("renderMarks: img=",data.$img," imgtrafo=",data.imgTrafo); | |
| 1417 var $elem = data.$elem; | |
| 1418 var marks = data.marks; | |
| 1419 // clear marks | |
| 1420 $elem.find('div.mark').remove(); | |
| 1421 for (var i = 0; i < marks.length; i++) { | |
| 1422 var mark = marks[i]; | |
| 1423 if (data.zoomArea.containsPosition(mark)) { | |
| 1424 var mpos = data.imgTrafo.transform(mark); | |
| 1425 console.debug("renderMarks: pos=",mpos); | |
| 1426 // create mark | |
| 1427 var html = '<div class="mark overlay">'+(i+1)+'</div>'; | |
| 1428 var $mark = $(html); | |
| 1429 $mark.attr("id", "digilib-mark-"+(i+1)); | |
| 1430 $elem.append($mark); | |
| 1431 mpos.adjustDiv($mark); | |
| 1432 } | |
| 1433 } | |
| 1434 }; | |
| 1435 | |
| 1436 // zooms by the given factor | |
| 1437 var zoomBy = function(data, factor) { | |
| 1438 var area = data.zoomArea; | |
| 1439 var newarea = area.copy(); | |
| 1440 // scale | |
| 1441 newarea.width /= factor; | |
| 1442 newarea.height /= factor; | |
| 1443 // and recenter | |
| 1444 newarea.x -= 0.5 * (newarea.width - area.width); | |
| 1445 newarea.y -= 0.5 * (newarea.height - area.height); | |
| 1446 newarea = FULL_AREA.fit(newarea); | |
| 1447 data.zoomArea = newarea; | |
| 1448 redisplay(data); | |
| 1449 }; | |
| 1450 | |
| 1451 // add a mark where clicked | |
| 1452 var setMark = function (data) { | |
| 1453 var $scaler = data.$scaler; | |
| 1454 // unbind other handler | |
| 1455 $scaler.unbind(".dlZoomDrag"); | |
| 1456 // start event capturing | |
| 1457 $scaler.one('mousedown.dlSetMark', function (evt) { | |
| 1458 // event handler adding a new mark | |
| 1459 console.log("setmark at=", evt); | |
| 1460 var mpos = geom.position(evt); | |
| 1461 var pos = data.imgTrafo.invtransform(mpos); | |
| 1462 data.marks.push(pos); | |
| 1463 redisplay(data); | |
| 1464 return false; | |
| 1465 }); | |
| 1466 }; | |
| 1467 | |
| 1468 // zoom to the area around two clicked points | |
| 1469 var zoomArea = function(data) { | |
| 1470 $elem = data.$elem; | |
| 1471 $scaler = data.$scaler; | |
| 1472 var pt1, pt2; | |
| 1473 var $zoomDiv = $('<div class="zoomrect" style="display:none"/>'); | |
| 1474 $elem.append($zoomDiv); | |
| 1475 // $zoomDiv.css(data.settings.zoomrectStyle); | |
| 1476 var picRect = geom.rectangle($scaler); | |
| 1477 // FIX ME: is there a way to query the border width from CSS info? | |
| 1478 // rect.x -= 2; // account for overlay borders | |
| 1479 // rect.y -= 2; | |
| 1480 | |
| 1481 var zoomStart = function (evt) { | |
| 1482 pt1 = geom.position(evt); | |
| 1483 // setup and show zoom div | |
| 1484 pt1.adjustDiv($zoomDiv); | |
| 1485 $zoomDiv.width(0).height(0); | |
| 1486 $zoomDiv.show(); | |
| 1487 // register events | |
| 1488 $elem.bind("mousemove.dlZoomArea", zoomMove); | |
| 1489 $elem.bind("mouseup.dlZoomArea", zoomEnd); | |
| 1490 return false; | |
| 1491 }; | |
| 1492 | |
| 1493 // mouse move handler | |
| 1494 var zoomMove = function (evt) { | |
| 1495 pt2 = geom.position(evt); | |
| 1496 var rect = geom.rectangle(pt1, pt2); | |
| 1497 rect.clipTo(picRect); | |
| 1498 // update zoom div | |
| 1499 rect.adjustDiv($zoomDiv); | |
| 1500 return false; | |
| 1501 }; | |
| 1502 | |
| 1503 // mouseup handler: end moving | |
| 1504 var zoomEnd = function (evt) { | |
| 1505 pt2 = geom.position(evt); | |
| 1506 // assume a click and continue if the area is too small | |
| 1507 var clickRect = geom.rectangle(pt1, pt2); | |
| 1508 if (clickRect.getArea() <= 5) return false; | |
| 1509 // hide zoom div | |
| 1510 $zoomDiv.remove(); | |
| 1511 // unregister events | |
| 1512 $elem.unbind("mousemove.dlZoomArea", zoomMove); | |
| 1513 $elem.unbind("mouseup.dlZoomArea", zoomEnd); | |
| 1514 // clip and transform | |
| 1515 clickRect.clipTo(picRect); | |
| 1516 var area = data.imgTrafo.invtransform(clickRect); | |
| 1517 data.zoomArea = area; | |
| 1518 // zoomed is always fit | |
| 1519 data.settings.ws = 1; | |
| 1520 delete data.dlOpts.fitwidth; | |
| 1521 delete data.dlOpts.fitheight; | |
| 1522 redisplay(data); | |
| 1523 return false; | |
| 1524 }; | |
| 1525 | |
| 1526 // clear old handler (also ZoomDrag) | |
| 1527 $scaler.unbind('.dlZoomArea'); | |
| 1528 $scaler.unbind(".dlZoomDrag"); | |
| 1529 $elem.unbind('.dlZoomArea'); | |
| 1530 // bind start zoom handler | |
| 1531 $scaler.one('mousedown.dlZoomArea', zoomStart); | |
| 1532 }; | |
| 1533 | |
| 1534 // set zoom background | |
| 1535 var setZoomBG = function(data) { | |
| 1536 var $scaler = data.$scaler; | |
| 1537 var $img = data.$img; | |
| 1538 var fullRect = null; | |
| 1539 // hide the scaler img, show background of div instead | |
| 1540 $img.css('visibility', 'hidden'); | |
| 1541 var scalerCss = { | |
| 1542 'background-image' : 'url(' + $img.attr('src') + ')', | |
| 1543 'background-repeat' : 'no-repeat', | |
| 1544 'background-position' : 'left top', | |
| 1545 'opacity' : '0.5', | |
| 1546 'cursor' : 'move' | |
| 1547 }; | |
| 1548 if (data.hasBgSize) { | |
| 1549 // full-size background using CSS3-background-size | |
| 1550 fullRect = data.imgTrafo.transform(FULL_AREA); | |
| 1551 if (fullRect.height < data.settings.maxBgSize && fullRect.width < data.settings.maxBgSize) { | |
| 1552 // correct offset because background is relative | |
| 1553 var scalerPos = geom.position($scaler); | |
| 1554 fullRect.addPosition(scalerPos.neg()); | |
| 1555 var url = getBgImgUrl(data); | |
| 1556 scalerCss['background-image'] = 'url(' + url + ')'; | |
| 1557 scalerCss[data.bgSizeName] = fullRect.width + 'px ' + fullRect.height + 'px'; | |
| 1558 scalerCss['background-position'] = fullRect.x + 'px '+ fullRect.y + 'px'; | |
| 1559 } else { | |
| 1560 // too big | |
| 1561 fullRect = null; | |
| 1562 } | |
| 1563 } | |
| 1564 $scaler.css(scalerCss); | |
| 1565 // isBgReady = true; | |
| 1566 return fullRect; | |
| 1567 }; | |
| 1568 | |
| 1569 // setup handlers for dragging the zoomed image | |
| 1570 var setupZoomDrag = function(data) { | |
| 1571 var startPos, delta, fullRect; | |
| 1572 var $document = $(document); | |
| 1573 var $data = $(data); | |
| 1574 var $elem = data.$elem; | |
| 1575 var $scaler = data.$scaler; | |
| 1576 var $img = data.$img; | |
| 1577 | |
| 1578 // drag the image and load a new detail on mouse up | |
| 1579 var dragStart = function (evt) { | |
| 1580 console.debug("dragstart at=", evt); | |
| 1581 // don't start dragging if not zoomed | |
| 1582 if (isFullArea(data.zoomArea)) return false; | |
| 1583 $elem.find(".overlay").hide(); // hide all overlays (marks/regions) | |
| 1584 startPos = geom.position(evt); | |
| 1585 delta = null; | |
| 1586 // set low res background immediately on mousedown | |
| 1587 fullRect = setZoomBG(data); | |
| 1588 $document.bind("mousemove.dlZoomDrag", dragMove); | |
| 1589 $document.bind("mouseup.dlZoomDrag", dragEnd); | |
| 1590 return false; | |
| 1591 }; | |
| 1592 | |
| 1593 // mousemove handler: drag zoomed image | |
| 1594 var dragMove = function (evt) { | |
| 1595 var pos = geom.position(evt); | |
| 1596 delta = startPos.delta(pos); | |
| 1597 if (fullRect) { | |
| 1598 var bgPos = fullRect.getPosition().add(delta); | |
| 1599 } else { | |
| 1600 var bgPos = delta; | |
| 1601 } | |
| 1602 // move the background image to the new position | |
| 1603 $scaler.css({ | |
| 1604 'background-position' : bgPos.x + "px " + bgPos.y + "px" | |
| 1605 }); | |
| 1606 // send message event with current zoom position | |
| 1607 var za = geom.rectangle($img); | |
| 1608 za.addPosition(delta.neg()); | |
| 1609 $data.trigger('dragZoom', [za]); | |
| 1610 //TODO: setBirdZoom(data, za); | |
| 1611 return false; | |
| 1612 }; | |
| 1613 | |
| 1614 // mouseup handler: reload zoomed image in new position | |
| 1615 var dragEnd = function (evt) { | |
| 1616 $scaler.css('cursor', 'auto'); | |
| 1617 $document.unbind("mousemove.dlZoomDrag", dragMove); | |
| 1618 $document.unbind("mouseup.dlZoomDrag", dragEnd); | |
| 1619 if (delta == null || delta.distance() < 2) { | |
| 1620 // no movement | |
| 1621 $img.css('visibility', 'visible'); | |
| 1622 $scaler.css({'opacity' : '1', 'background-image' : 'none'}); | |
| 1623 // unhide marks | |
| 1624 data.$elem.find('div.mark').show(); | |
| 1625 $(data).trigger('redisplay'); | |
| 1626 return false; | |
| 1627 } | |
| 1628 // get old zoom area (screen coordinates) | |
| 1629 var za = geom.rectangle($img); | |
| 1630 // move | |
| 1631 za.addPosition(delta.neg()); | |
| 1632 // transform back | |
| 1633 var newArea = data.imgTrafo.invtransform(za); | |
| 1634 data.zoomArea = FULL_AREA.fit(newArea); | |
| 1635 redisplay(data); | |
| 1636 return false; | |
| 1637 }; | |
| 1638 | |
| 1639 // clear old handler | |
| 1640 $document.unbind(".dlZoomDrag"); | |
| 1641 $scaler.unbind(".dlZoomDrag"); | |
| 1642 if (! isFullArea(data.zoomArea)) { | |
| 1643 // set handler | |
| 1644 $scaler.bind("mousedown.dlZoomDrag", dragStart); | |
| 1645 } | |
| 1646 }; | |
| 1647 | |
| 1648 // get image quality as a number (0..2) | |
| 1649 var getQuality = function (data) { | |
| 1650 var flags = data.scalerFlags; | |
| 1651 var q = flags.q2 || flags.q1 || 'q0'; // assume q0 as default | |
| 1652 return parseInt(q[1], 10); | |
| 1653 }; | |
| 1654 | |
| 1655 // set image quality as a number (0..2) | |
| 1656 var setQuality = function (data, qual) { | |
| 1657 var flags = data.scalerFlags; | |
| 1658 // clear flags | |
| 1659 for (var i = 0; i < 3; ++i) { | |
| 1660 delete flags['q'+i]; | |
| 1661 } | |
| 1662 flags['q'+qual] = 'q'+qual; | |
| 1663 }; | |
| 1664 | |
| 1665 // get image scale mode (screen, pixel, size) | |
| 1666 var getScaleMode = function (data) { | |
| 1667 if (data.scalerFlags.clip != null) { | |
| 1668 return 'pixel'; | |
| 1669 } else if (data.scalerFlags.osize != null) { | |
| 1670 return 'size'; | |
| 1671 } | |
| 1672 // mo=fit is default | |
| 1673 return 'screen'; | |
| 1674 }; | |
| 1675 | |
| 1676 // set image scale mode (screen, pixel, size) | |
| 1677 var setScaleMode = function (data, mode) { | |
| 1678 delete data.scalerFlags.fit; | |
| 1679 delete data.scalerFlags.clip; | |
| 1680 delete data.scalerFlags.osize; | |
| 1681 if (mode === 'pixel') { | |
| 1682 data.scalerFlags.clip = 'clip'; | |
| 1683 } else if (mode === 'size') { | |
| 1684 data.scalerFlags.osize = 'osize'; | |
| 1685 } | |
| 1686 // mo=fit is default | |
| 1687 }; | |
| 1688 | |
| 1689 // sets a key to a value (relative values with +/- if relative=true) | |
| 1690 var setNumValue = function(settings, key, value) { | |
| 1691 if (value == null) return null; | |
| 1692 if (isNumber(value)) { | |
| 1693 settings[key] = value; | |
| 1694 return value; | |
| 1695 } | |
| 1696 var sign = value[0]; | |
| 1697 if (sign === '+' || sign === '-') { | |
| 1698 if (settings[key] == null) { | |
| 1699 // this isn't perfect but still... | |
| 1700 settings[key] = 0; | |
| 1701 } | |
| 1702 settings[key] = parseFloat(settings[key]) + parseFloat(value); | |
| 1703 } else { | |
| 1704 settings[key] = value; | |
| 1705 } | |
| 1706 return settings[key]; | |
| 1707 }; | |
| 1708 | |
| 1709 // auxiliary function, assuming equal border width on all sides | |
| 1710 var getBorderWidth = function($elem) { | |
| 1711 var border = $elem.outerWidth() - $elem.width(); | |
| 1712 return border/2; | |
| 1713 }; | |
| 1714 | |
| 1715 // auxiliary function, can the current zoomarea be moved further? | |
| 1716 var canMove = function(data, movx, movy) { | |
| 1717 var za = data.zoomArea; | |
| 1718 if (isFullArea(za)) return false; | |
| 1719 var x2 = za.x + za.width; | |
| 1720 var y2 = za.y + za.height; | |
| 1721 return ((movx < 0) && (za.x > 0)) | |
| 1722 || ((movx > 0) && (x2 < 1.0)) | |
| 1723 || ((movy < 0) && (za.y > 0)) | |
| 1724 || ((movy > 0) && (y2 < 1.0)) | |
| 1725 }; | |
| 1726 | |
| 1727 // auxiliary function (from old dllib.js) | |
| 1728 var isFullArea = function (area) { | |
| 1729 return (area.width === 1.0) && (area.height === 1.0); | |
| 1730 }; | |
| 1731 | |
| 1732 // auxiliary function (from Douglas Crockford, A.10) | |
| 1733 var isNumber = function (value) { | |
| 1734 return typeof value === 'number' && isFinite(value); | |
| 1735 }; | |
| 1736 | |
| 1737 // auxiliary function to crop senseless precision | |
| 1738 var cropFloat = function (x) { | |
| 1739 return parseInt(10000 * x, 10) / 10000; | |
| 1740 }; | |
| 1741 | |
| 1742 // idem, string version | |
| 1743 var cropFloatStr = function (x) { | |
| 1744 return cropFloat(x).toString(); | |
| 1745 }; | |
| 1746 | |
| 1747 // fallback for console.log calls | |
| 1748 if (customConsole) { | |
| 1749 var logFunction = function(type) { | |
| 1750 return function(){ | |
| 1751 var $debug = $('#debug'); // debug div | |
| 1752 if (!$debug) return; | |
| 1753 var args = Array.prototype.slice.call(arguments); | |
| 1754 var argtext = args.join(' '); | |
| 1755 var $logDiv = $('<div/>'); | |
| 1756 $logDiv.addClass(type); | |
| 1757 $logDiv.text(argtext); | |
| 1758 $debug.append($logDiv); | |
| 1759 }; | |
| 1760 }; | |
| 1761 console.log = logFunction('_log'); | |
| 1762 console.debug = logFunction('_debug'); | |
| 1763 console.error = logFunction('_error'); | |
| 1764 } | |
| 1765 | |
| 1766 // functions to export to plugins | |
| 1767 fn = { | |
| 1768 geometry : geom, | |
| 1769 parseQueryString : parseQueryString, | |
| 1770 getScalerUrl : getScalerUrl, | |
| 1771 getParamString : getParamString, | |
| 1772 getDigilibUrl : getDigilibUrl, | |
| 1773 unpackParams : unpackParams, | |
| 1774 packParams : packParams, | |
| 1775 packArea : packArea, | |
| 1776 packMarks : packMarks, | |
| 1777 packScalerFlags : packScalerFlags, | |
| 1778 storeOptions : storeOptions, | |
| 1779 redisplay : redisplay, | |
| 1780 updateDisplay : updateDisplay, | |
| 1781 highlightButtons : highlightButtons, | |
| 1782 showDiv : showDiv, | |
| 1783 setZoomBG : setZoomBG, | |
| 1784 getImgTrafo : getImgTrafo, | |
| 1785 getQuality : getQuality, | |
| 1786 setQuality : setQuality, | |
| 1787 getScaleMode : getScaleMode, | |
| 1788 setScaleMode : setScaleMode, | |
| 1789 canMove : canMove, | |
| 1790 isFullArea : isFullArea, | |
| 1791 isNumber : isNumber, | |
| 1792 getBorderWidth : getBorderWidth, | |
| 1793 cropFloat : cropFloat, | |
| 1794 cropFloatStr : cropFloatStr | |
| 1795 }; | |
| 1796 | |
| 1797 // hook digilib plugin into jquery | |
| 1798 $.fn.digilib = function (action) { | |
| 1799 // plugin extension mechanism, called when the plugins' code is read | |
| 1800 if (action === 'plugin') { | |
| 1801 var plugin = arguments[1]; | |
| 1802 // each plugin needs a name | |
| 1803 if (plugin.name != null) { | |
| 1804 plugins[plugin.name] = plugin; | |
| 1805 // share common objects | |
| 1806 plugin.defaults = defaults; | |
| 1807 plugin.buttons = buttons; | |
| 1808 plugin.actions = actions; | |
| 1809 plugin.fn = fn; | |
| 1810 plugin.plugins = plugins; | |
| 1811 // and install | |
| 1812 if (typeof plugin.install === 'function') { | |
| 1813 plugin.install(plugin); | |
| 1814 } | |
| 1815 } | |
| 1816 // plugins will be initialised when action.init is called | |
| 1817 } else if (actions[action]) { | |
| 1818 // call action on this with the remaining arguments (inserting data as first argument) | |
| 1819 var $elem = $(this); | |
| 1820 var data = $elem.data('digilib'); | |
| 1821 var args = Array.prototype.slice.call(arguments, 1); | |
| 1822 args.unshift(data); | |
| 1823 return actions[action].apply(this, args); | |
| 1824 } else if (typeof action === 'object' || !action) { | |
| 1825 // call init on the digilib jQuery object | |
| 1826 return actions.init.apply(this, arguments); | |
| 1827 } else { | |
| 1828 $.error('action ' + action + ' does not exist on jQuery.digilib'); | |
| 1829 } | |
| 1830 }; | |
| 1831 | |
| 1832 })(jQuery); |
