diff --git a/build.sh b/build.sh index 9596ad13..72c35317 100755 --- a/build.sh +++ b/build.sh @@ -1,11 +1,52 @@ #!/bin/bash -# Path to the Closure Compiler .jar file +usage() +{ + echo "Flags:" + echo " -h Show this message" + echo " -r (version) Specify release version" + echo " -c (closure) Specify closure compiler location" + echo " " + echo "Build options:" + echo " all Builds CSS and Javascript, copies source to build directory" + echo " less Compiles CSS from the LESS source" + echo " minify Builds Javascript source" + echo " test Runs unit tests with PhantomJS" + echo " release Builds release package" + + exit 1 +} + +# Default path to the Closure Compiler CLOSURE_COMPILER_PATH="/usr/local/bin/closure-compiler" +RELEASE= + +SKIP=0 + +while getopts "hr:c:" OPT; do + case $OPT in + h) + usage;; + r) + RELEASE=$OPTARG + SKIP=$(($SKIP + 2));; + c) + CLOSURE_COMPILER_PATH=$OPTARG + SKIP=$(($SKIP + 2));; + esac +done + +args=("$@") +TYPE=${args[$SKIP]} + # If running in Travis CI, use local compiler.jar if [ "$TRAVIS" = "true" ]; then CLOSURE_COMPILER_PATH="java -jar ../../compiler.jar" +elif [ ! -f $CLOSURE_COMPILER_PATH ]; then + echo "Closure Compiler not found at:" $CLOSURE_COMPILER_PATH + echo "Please specify using -c flag." + exit 1 fi less () @@ -14,6 +55,7 @@ less () # Creates a minified version called diva.min.css in build/css # and a non-minified version called diva.css. # See build/css/readme.md for more information. + echo "Compiling CSS." mkdir -p build/css lessc source/css/imports.less > build/css/diva.css lessc source/css/imports.less > build/css/diva.min.css -x @@ -26,20 +68,20 @@ minify () # all the relevant Javascript (except for jQuery, which must # be included separately). # See build/js/readme.md for more information. - echo "Using Closure path:" $CLOSURE_COMPILER_PATH + echo "Compiling JS." source_files=( "utils.js" "diva.js" "plugins/*" ) mkdir -p build/js cd source/js && eval $CLOSURE_COMPILER_PATH" --js "${source_files[@]:0}" --js_output_file ../../build/js/diva.min.js" cd ../../ - cp -R source/js/ build/js/ + cp -R source/js/* build/js/ } all () { if [ -d "build" ]; then - echo "Removing old build directory" + echo "Removing old build directory." rm -r build/* fi @@ -70,7 +112,7 @@ release() # Creates a zip file containing just the files we need for the release. VERSION=$1 if [ -z "$1"]; then - echo "Syntax: ./build.sh release VERSION" + echo "Syntax: ./build.sh -r VERSION release" exit 1 fi @@ -103,19 +145,12 @@ release() zip -r $release_dir".zip" $release_dir } -case "$1" in +case $TYPE in "less" ) less;; "minify" ) minify;; "test" ) test;; "all" ) all;; - "release" ) release $2;; - * ) - echo "Build options:" - echo " all - Builds CSS and Javascript, copies source to build directory" - echo " less - Compiles CSS from the LESS source" - echo " minify - Builds Javascript source" - echo " test - Runs unit tests with PhantomJS" - echo " release VERSION - Builds release package" - ;; + "release" ) release $RELEASE;; + * ) usage;; esac diff --git a/build/css/diva.css b/build/css/diva.css index 89b447f4..b9152a8c 100644 --- a/build/css/diva.css +++ b/build/css/diva.css @@ -58,13 +58,11 @@ display: none; padding: 8px; float: left; - clear: left; } .diva-tools .diva-tools-left .diva-zoom-buttons-label { display: none; padding: 8px; float: left; - clear: left; } .diva-tools .diva-tools-left .diva-zoom-out-button { display: none; @@ -92,7 +90,6 @@ display: none; padding: 8px; float: left; - clear: left; } .diva-tools .diva-tools-left.in-fullscreen { float: left; @@ -140,7 +137,6 @@ top: 0px; right: 30px; z-index: 101; - width: 230px; height: 73px; padding: 15px; border: 1px solid #dddddd; @@ -250,19 +246,21 @@ border-left: 0px; float: right; } -.diva-link-popup { - font-size: 10pt; +.diva-popup { background: #ffffff; - border: 1px solid #dddddd; - position: absolute; + border: 1px solid #99bbe8; padding: .6em; z-index: 101; + position: absolute; -webkit-box-shadow: 2px 2px 4px 0 rgba(0, 0, 0, 0.5); -moz-box-shadow: 2px 2px 4px 0 rgba(0, 0, 0, 0.5); box-shadow: 2px 2px 4px 0 rgba(0, 0, 0, 0.5); } +.diva-link-popup { + font-size: 10pt; +} .diva-link-popup input { - width: 15em; + width: 18em; } .diva-link-popup input:focus { outline: none; @@ -559,3 +557,23 @@ background-position: -25px center; } /* End download plugin */ +/* Begin autoscroll plugin */ +.diva-autoscroll-icon { + float: right; + border-right: none; + background-image: url("../img/plugins/play.png"); +} +.diva-autoscroll-prefs { + display: none; + margin-right: .6em; +} +.diva-autoscroll-prefs-text { + float: left; +} +.diva-autoscroll-prefs-input { + float: right; + margin-left: .6em; +} +.diva-autoscroll-pps { + width: 9em; +} diff --git a/build/css/diva.min.css b/build/css/diva.min.css index 09a88726..b7474b69 100644 --- a/build/css/diva.min.css +++ b/build/css/diva.min.css @@ -1 +1 @@ -.hidden{display:none}.grab{cursor:url("../img/openhand.cur"),pointer}.grabbing{cursor:url("../img/closedhand.cur"),move !important}.loading{background:url("../img/loading.gif") no-repeat center}.full-width{width:100% !important;max-width:100% !important}.full-height{height:100% !important;max-height:100% !important}.prevent-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.button{cursor:pointer;height:32px;width:32px;background-color:#f1f1f1;background-repeat:no-repeat;background-position:center;border:1px solid #99bbe8}@media screen and (min-device-width:769px){.button:hover{background-color:#fdfdfd}}.diva-title{text-align:center;font-weight:bold;font-size:2em}.diva-tools{margin-top:15px}.diva-tools .diva-tools-left{float:left}.diva-tools .diva-tools-left .diva-slider-label{display:none;padding:8px;float:left;clear:left}.diva-tools .diva-tools-left .diva-zoom-buttons-label{display:none;padding:8px;float:left;clear:left}.diva-tools .diva-tools-left .diva-zoom-out-button{display:none;float:left;background-image:url("../img/zoomout.png")}.diva-tools .diva-tools-left .diva-zoom-in-button{display:none;float:left;background-image:url("../img/zoomin.png");margin-left:-1px}.diva-tools .diva-tools-left .diva-grid-out-button{display:none;float:left;background-image:url("../img/zoomout.png")}.diva-tools .diva-tools-left .diva-grid-in-button{display:none;float:left;background-image:url("../img/zoomin.png");margin-left:-1px}.diva-tools .diva-tools-left .diva-buttons-label{display:none;padding:8px;float:left;clear:left}.diva-tools .diva-tools-left.in-fullscreen{float:left;clear:none}.diva-tools .diva-tools-right{float:right;height:42px}.diva-tools .diva-tools-right .diva-grid-icon{float:right;background-image:url("../img/grid.png")}.diva-tools .diva-tools-right .diva-grid-icon.diva-in-grid{background-image:url("../img/document.png")}.diva-tools .diva-tools-right .diva-link-icon{float:right;background-image:url("../img/link.png")}.diva-tools .diva-tools-right .diva-page-nav{float:left;text-align:right;padding-right:4px;white-space:nowrap;line-height:32px}.diva-tools .diva-tools-right .diva-page-nav .diva-page-label{float:left;padding-top:1px;padding-right:.5em;line-height:32px}.diva-tools .diva-tools-right .diva-page-nav .diva-goto-form{float:right}.diva-tools .diva-tools-right .diva-page-nav .diva-goto-form .diva-input{width:30px;outline:none;margin:0;padding-top:0}.diva-tools.diva-fullscreen-tools{position:fixed;top:0;right:30px;z-index:101;width:230px;height:73px;padding:15px;border:1px solid #ddd;background:#fff;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5)}.diva-tools.diva-fullscreen-tools .diva-buttons-label{margin-top:5px;padding:0;clear:both}.diva-tools.diva-fullscreen-tools .diva-page-nav{float:none;line-height:1em}.diva-tools.diva-fullscreen-tools .diva-page-nav .diva-goto-form{margin-top:9px}.diva-tools.diva-fullscreen-tools .diva-page-nav .diva-page-label{float:none;clear:both;line-height:1em}.diva-outer{clear:both;background:#f1f1f1;border:1px solid #99bbe8;position:relative;min-height:100px;min-width:200px;height:700px;overflow:auto}.diva-outer .diva-inner{position:relative;overflow:hidden;margin:0 auto}.diva-outer .diva-inner .diva-page{-webkit-box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);background:url("../img/loading.gif") no-repeat center;position:absolute}.diva-outer .diva-inner .diva-document-page{-webkit-box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);background:url("../img/loading.gif") no-repeat center;position:absolute;left:0;right:0}.diva-outer .diva-inner .diva-document-page .diva-page-tools{position:absolute;top:-25px;left:0;height:25px;z-index:3}.diva-outer .diva-inner .diva-document-page .diva-page-tools div{display:inline-block;height:25px;width:25px;cursor:pointer}.diva-outer .diva-inner .diva-page-vertical{margin:0 auto;display:inline-block}.diva-outer .diva-inner .diva-page-horizontal{vertical-align:middle;display:inline-block;top:50%;transform:translate(0, -50%);-webkit-transform:translate(0, -50%);-moz-transform:translate(0, -50%);-ms-transform:translate(0, -50%)}.diva-outer .diva-inner .diva-row{position:absolute;width:100%}.diva-outer .diva-inner.diva-grab{cursor:url("../img/openhand.cur"),pointer}.diva-outer .diva-inner.diva-grabbing{cursor:url("../img/closedhand.cur"),move !important}.diva-outer.diva-fullscreen{width:100% !important;max-width:100% !important;height:100% !important;max-height:100% !important;z-index:100;position:fixed !important;top:0;left:0;margin:0;border:0}.diva-fullscreen-icon{background-image:url("../img/fullscreen.png");border-left:0;float:right}.diva-link-popup{font-size:10pt;background:#fff;border:1px solid #ddd;position:absolute;padding:.6em;z-index:101;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5)}.diva-link-popup input{width:15em}.diva-link-popup input:focus{outline:none}.diva-link-popup.in-fullscreen{top:150px;right:30px}.diva-hide-scrollbar{overflow:hidden !important}.diva-relative-position{position:relative}.zoom-slider{position:relative;top:.6em;display:none;float:left}@media (max-width:480px){.zoom-slider{width:100px}}.grid-slider{position:relative;top:.6em;display:none;float:left}@media (max-width:480px){.grid-slider{width:100px}}.diva-throbber{display:none;position:absolute;width:50px;height:50px;background:url("../img/loading.gif") no-repeat center;background-color:#fff;border:1px solid #ddd;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);top:50%;left:50%;margin-left:-25px;margin-top:-25px}.diva-error{position:absolute;width:400px;height:200px;background-color:#fff;border:1px solid #ddd;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);top:50%;left:50%;margin-left:-220px;margin-top:-120px;z-index:120;padding:0 1em}.diva-canvas-icon{background:url('../img/plugins/canvas.png') no-repeat;background-position:left center}.diva-canvas-icon:hover{background-position:-25px center}.diva-canvas-icon.new{background-position:-50px center}.diva-canvas-icon.new:hover{background-position:-75px center}#diva-canvas-backdrop{z-index:105;position:fixed;top:0;left:0;bottom:0;right:0;display:none;background:rgba(50,50,50,0.9)}#diva-canvas-tools{color:#333;position:fixed;top:10px;left:10px;width:230px;z-index:108;background:#fff;padding-bottom:10px;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5)}#diva-canvas-tools .action-buttons{clear:both;margin-bottom:5px;text-align:right}#diva-canvas-tools .action-buttons a{color:#333;text-decoration:none;background:#f1f1f1;padding:5px;border:1px solid #99bbe8}#diva-canvas-tools .action-buttons a:last-child{border-left:0}#diva-canvas-tools .action-buttons a:hover{background:#fdfdfd}#diva-canvas-toolbar{height:16px;padding:10px;padding-bottom:0}#diva-canvas-toolbar div{height:18px;width:18px;background-repeat:no-repeat;cursor:pointer;z-index:109;display:inline-block;margin-right:5px;background-image:url("../img/actions.png")}#diva-canvas-toolbar span{vertical-align:top;float:right}#diva-canvas-toolwindow{position:relative;margin:10px}#diva-canvas-close:hover{background-position:-20px 0}#diva-canvas-minimise{background-position:-40px 0}#diva-canvas-minimise:hover{background-position:-60px 0}#diva-canvas-buttons div{cursor:pointer;background-image:url("../img/plugins/canvas-buttons.png");background-repeat:no-repeat;width:20px;height:20px;padding:5px;display:inline-block}#diva-canvas-buttons div.clicked{background-color:#ddd}#diva-canvas-buttons .contrast{background-position:5px 5px}#diva-canvas-buttons .contrast:hover,#diva-canvas-buttons .contrast.clicked{background-position:5px -25px}#diva-canvas-buttons .brightness{background-position:-25px 5px}#diva-canvas-buttons .brightness:hover,#diva-canvas-buttons .brightness.clicked{background-position:-25px -25px}#diva-canvas-buttons .rotation{background-position:-55px 5px}#diva-canvas-buttons .rotation:hover,#diva-canvas-buttons .rotation.clicked{background-position:-55px -25px}#diva-canvas-buttons .zoom{background-position:-85px 5px}#diva-canvas-buttons .zoom:hover,#diva-canvas-buttons .zoom.clicked{background-position:-85px -25px}#diva-canvas-buttons .red{background-position:-115px 5px}#diva-canvas-buttons .red:hover,#diva-canvas-buttons .red.clicked{background-position:-115px -25px}#diva-canvas-buttons .green{background-position:-145px 5px}#diva-canvas-buttons .green:hover,#diva-canvas-buttons .green.clicked{background-position:-145px -25px}#diva-canvas-buttons .blue{background-position:-175px 5px}#diva-canvas-buttons .blue:hover,#diva-canvas-buttons .blue.clicked{background-position:-175px -25px}#diva-canvas-pane{background:#ddd;padding-bottom:10px}#diva-canvas-pane p{margin-left:10px;padding-top:10px}#diva-canvas-pane p .link{cursor:pointer}#diva-canvas-pane p .link:hover{text-decoration:underline}#diva-canvas-mode{text-transform:capitalize}#diva-canvas-slider{width:188px;margin:0 auto;display:block}#diva-canvas-slider .handle{margin-left:-6px}#diva-canvas-minimap{height:210px;width:210px;cursor:crosshair;margin-bottom:10px;background:#000}#diva-canvas{position:absolute;left:0;right:0;margin:0 auto;z-index:107;cursor:url("../img/openhand.cur"),pointer}#diva-map-viewbox{border:2px solid #99bbe8;position:absolute;top:10px;left:10px;cursor:crosshair;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:none}.overflow-hidden{overflow:hidden !important}#diva-canvas-wrapper{z-index:106;position:absolute;top:0;left:0;bottom:0;right:0;overflow:scroll}.canvas-throbber{z-index:110;position:fixed}.diva-download-icon{background:url('../img/plugins/download.png') no-repeat;background-position:left center}.diva-download-icon:hover{background-position:-25px center} \ No newline at end of file +.hidden{display:none}.grab{cursor:url("../img/openhand.cur"),pointer}.grabbing{cursor:url("../img/closedhand.cur"),move !important}.loading{background:url("../img/loading.gif") no-repeat center}.full-width{width:100% !important;max-width:100% !important}.full-height{height:100% !important;max-height:100% !important}.prevent-selection{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.button{cursor:pointer;height:32px;width:32px;background-color:#f1f1f1;background-repeat:no-repeat;background-position:center;border:1px solid #99bbe8}@media screen and (min-device-width:769px){.button:hover{background-color:#fdfdfd}}.diva-title{text-align:center;font-weight:bold;font-size:2em}.diva-tools{margin-top:15px}.diva-tools .diva-tools-left{float:left}.diva-tools .diva-tools-left .diva-slider-label{display:none;padding:8px;float:left}.diva-tools .diva-tools-left .diva-zoom-buttons-label{display:none;padding:8px;float:left}.diva-tools .diva-tools-left .diva-zoom-out-button{display:none;float:left;background-image:url("../img/zoomout.png")}.diva-tools .diva-tools-left .diva-zoom-in-button{display:none;float:left;background-image:url("../img/zoomin.png");margin-left:-1px}.diva-tools .diva-tools-left .diva-grid-out-button{display:none;float:left;background-image:url("../img/zoomout.png")}.diva-tools .diva-tools-left .diva-grid-in-button{display:none;float:left;background-image:url("../img/zoomin.png");margin-left:-1px}.diva-tools .diva-tools-left .diva-buttons-label{display:none;padding:8px;float:left}.diva-tools .diva-tools-left.in-fullscreen{float:left;clear:none}.diva-tools .diva-tools-right{float:right;height:42px}.diva-tools .diva-tools-right .diva-grid-icon{float:right;background-image:url("../img/grid.png")}.diva-tools .diva-tools-right .diva-grid-icon.diva-in-grid{background-image:url("../img/document.png")}.diva-tools .diva-tools-right .diva-link-icon{float:right;background-image:url("../img/link.png")}.diva-tools .diva-tools-right .diva-page-nav{float:left;text-align:right;padding-right:4px;white-space:nowrap;line-height:32px}.diva-tools .diva-tools-right .diva-page-nav .diva-page-label{float:left;padding-top:1px;padding-right:.5em;line-height:32px}.diva-tools .diva-tools-right .diva-page-nav .diva-goto-form{float:right}.diva-tools .diva-tools-right .diva-page-nav .diva-goto-form .diva-input{width:30px;outline:none;margin:0;padding-top:0}.diva-tools.diva-fullscreen-tools{position:fixed;top:0;right:30px;z-index:101;height:73px;padding:15px;border:1px solid #ddd;background:#fff;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5)}.diva-tools.diva-fullscreen-tools .diva-buttons-label{margin-top:5px;padding:0;clear:both}.diva-tools.diva-fullscreen-tools .diva-page-nav{float:none;line-height:1em}.diva-tools.diva-fullscreen-tools .diva-page-nav .diva-goto-form{margin-top:9px}.diva-tools.diva-fullscreen-tools .diva-page-nav .diva-page-label{float:none;clear:both;line-height:1em}.diva-outer{clear:both;background:#f1f1f1;border:1px solid #99bbe8;position:relative;min-height:100px;min-width:200px;height:700px;overflow:auto}.diva-outer .diva-inner{position:relative;overflow:hidden;margin:0 auto}.diva-outer .diva-inner .diva-page{-webkit-box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);background:url("../img/loading.gif") no-repeat center;position:absolute}.diva-outer .diva-inner .diva-document-page{-webkit-box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 6px 0 rgba(0,0,0,0.5);background:url("../img/loading.gif") no-repeat center;position:absolute;left:0;right:0}.diva-outer .diva-inner .diva-document-page .diva-page-tools{position:absolute;top:-25px;left:0;height:25px;z-index:3}.diva-outer .diva-inner .diva-document-page .diva-page-tools div{display:inline-block;height:25px;width:25px;cursor:pointer}.diva-outer .diva-inner .diva-page-vertical{margin:0 auto;display:inline-block}.diva-outer .diva-inner .diva-page-horizontal{vertical-align:middle;display:inline-block;top:50%;transform:translate(0, -50%);-webkit-transform:translate(0, -50%);-moz-transform:translate(0, -50%);-ms-transform:translate(0, -50%)}.diva-outer .diva-inner .diva-row{position:absolute;width:100%}.diva-outer .diva-inner.diva-grab{cursor:url("../img/openhand.cur"),pointer}.diva-outer .diva-inner.diva-grabbing{cursor:url("../img/closedhand.cur"),move !important}.diva-outer.diva-fullscreen{width:100% !important;max-width:100% !important;height:100% !important;max-height:100% !important;z-index:100;position:fixed !important;top:0;left:0;margin:0;border:0}.diva-fullscreen-icon{background-image:url("../img/fullscreen.png");border-left:0;float:right}.diva-popup{background:#fff;border:1px solid #99bbe8;padding:.6em;z-index:101;position:absolute;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5)}.diva-link-popup{font-size:10pt}.diva-link-popup input{width:18em}.diva-link-popup input:focus{outline:none}.diva-link-popup.in-fullscreen{top:150px;right:30px}.diva-hide-scrollbar{overflow:hidden !important}.diva-relative-position{position:relative}.zoom-slider{position:relative;top:.6em;display:none;float:left}@media (max-width:480px){.zoom-slider{width:100px}}.grid-slider{position:relative;top:.6em;display:none;float:left}@media (max-width:480px){.grid-slider{width:100px}}.diva-throbber{display:none;position:absolute;width:50px;height:50px;background:url("../img/loading.gif") no-repeat center;background-color:#fff;border:1px solid #ddd;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);top:50%;left:50%;margin-left:-25px;margin-top:-25px}.diva-error{position:absolute;width:400px;height:200px;background-color:#fff;border:1px solid #ddd;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);top:50%;left:50%;margin-left:-220px;margin-top:-120px;z-index:120;padding:0 1em}.diva-canvas-icon{background:url('../img/plugins/canvas.png') no-repeat;background-position:left center}.diva-canvas-icon:hover{background-position:-25px center}.diva-canvas-icon.new{background-position:-50px center}.diva-canvas-icon.new:hover{background-position:-75px center}#diva-canvas-backdrop{z-index:105;position:fixed;top:0;left:0;bottom:0;right:0;display:none;background:rgba(50,50,50,0.9)}#diva-canvas-tools{color:#333;position:fixed;top:10px;left:10px;width:230px;z-index:108;background:#fff;padding-bottom:10px;-webkit-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);-moz-box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5);box-shadow:2px 2px 4px 0 rgba(0,0,0,0.5)}#diva-canvas-tools .action-buttons{clear:both;margin-bottom:5px;text-align:right}#diva-canvas-tools .action-buttons a{color:#333;text-decoration:none;background:#f1f1f1;padding:5px;border:1px solid #99bbe8}#diva-canvas-tools .action-buttons a:last-child{border-left:0}#diva-canvas-tools .action-buttons a:hover{background:#fdfdfd}#diva-canvas-toolbar{height:16px;padding:10px;padding-bottom:0}#diva-canvas-toolbar div{height:18px;width:18px;background-repeat:no-repeat;cursor:pointer;z-index:109;display:inline-block;margin-right:5px;background-image:url("../img/actions.png")}#diva-canvas-toolbar span{vertical-align:top;float:right}#diva-canvas-toolwindow{position:relative;margin:10px}#diva-canvas-close:hover{background-position:-20px 0}#diva-canvas-minimise{background-position:-40px 0}#diva-canvas-minimise:hover{background-position:-60px 0}#diva-canvas-buttons div{cursor:pointer;background-image:url("../img/plugins/canvas-buttons.png");background-repeat:no-repeat;width:20px;height:20px;padding:5px;display:inline-block}#diva-canvas-buttons div.clicked{background-color:#ddd}#diva-canvas-buttons .contrast{background-position:5px 5px}#diva-canvas-buttons .contrast:hover,#diva-canvas-buttons .contrast.clicked{background-position:5px -25px}#diva-canvas-buttons .brightness{background-position:-25px 5px}#diva-canvas-buttons .brightness:hover,#diva-canvas-buttons .brightness.clicked{background-position:-25px -25px}#diva-canvas-buttons .rotation{background-position:-55px 5px}#diva-canvas-buttons .rotation:hover,#diva-canvas-buttons .rotation.clicked{background-position:-55px -25px}#diva-canvas-buttons .zoom{background-position:-85px 5px}#diva-canvas-buttons .zoom:hover,#diva-canvas-buttons .zoom.clicked{background-position:-85px -25px}#diva-canvas-buttons .red{background-position:-115px 5px}#diva-canvas-buttons .red:hover,#diva-canvas-buttons .red.clicked{background-position:-115px -25px}#diva-canvas-buttons .green{background-position:-145px 5px}#diva-canvas-buttons .green:hover,#diva-canvas-buttons .green.clicked{background-position:-145px -25px}#diva-canvas-buttons .blue{background-position:-175px 5px}#diva-canvas-buttons .blue:hover,#diva-canvas-buttons .blue.clicked{background-position:-175px -25px}#diva-canvas-pane{background:#ddd;padding-bottom:10px}#diva-canvas-pane p{margin-left:10px;padding-top:10px}#diva-canvas-pane p .link{cursor:pointer}#diva-canvas-pane p .link:hover{text-decoration:underline}#diva-canvas-mode{text-transform:capitalize}#diva-canvas-slider{width:188px;margin:0 auto;display:block}#diva-canvas-slider .handle{margin-left:-6px}#diva-canvas-minimap{height:210px;width:210px;cursor:crosshair;margin-bottom:10px;background:#000}#diva-canvas{position:absolute;left:0;right:0;margin:0 auto;z-index:107;cursor:url("../img/openhand.cur"),pointer}#diva-map-viewbox{border:2px solid #99bbe8;position:absolute;top:10px;left:10px;cursor:crosshair;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:none}.overflow-hidden{overflow:hidden !important}#diva-canvas-wrapper{z-index:106;position:absolute;top:0;left:0;bottom:0;right:0;overflow:scroll}.canvas-throbber{z-index:110;position:fixed}.diva-download-icon{background:url('../img/plugins/download.png') no-repeat;background-position:left center}.diva-download-icon:hover{background-position:-25px center}.diva-autoscroll-icon{float:right;border-right:none;background-image:url("../img/plugins/play.png")}.diva-autoscroll-prefs{display:none;margin-right:.6em}.diva-autoscroll-prefs-text{float:left}.diva-autoscroll-prefs-input{float:right;margin-left:.6em}.diva-autoscroll-pps{width:9em} \ No newline at end of file diff --git a/build/demo/autoscroll.html b/build/demo/autoscroll.html new file mode 100644 index 00000000..2b24eeb7 --- /dev/null +++ b/build/demo/autoscroll.html @@ -0,0 +1,43 @@ + + + + + Diva.js Demo Page + + + + + + + + + + +
+ + diff --git a/build/img/plugins/play.png b/build/img/plugins/play.png new file mode 100644 index 00000000..d3348b21 Binary files /dev/null and b/build/img/plugins/play.png differ diff --git a/build/index.html b/build/index.html index 7a8f97bb..3ba4d076 100644 --- a/build/index.html +++ b/build/index.html @@ -13,6 +13,7 @@
  • A basic Diva instance.
  • A demonstration of horizontal scrolling.
  • A demonstration of the highlight plugin.
  • +
  • A demonstration of the autoscroll plugin.
  • diff --git a/build/js/diva.js b/build/js/diva.js index c809f2b5..e3a6dbdf 100644 --- a/build/js/diva.js +++ b/build/js/diva.js @@ -1,5 +1,5 @@ /* -Copyright (C) 2011-2014 by Wendy Liu, Evan Magoni, Andrew Hankinson, Andrew Horwitz, Laurent Pugin +Copyright (C) 2011-2015 by Wendy Liu, Evan Magoni, Andrew Hankinson, Andrew Horwitz, Laurent Pugin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -40,6 +40,7 @@ window.divaPlugins = []; enableGotoPage: true, // A "go to page" jump box enableGridIcon: true, // A grid view of all the pages enableGridControls: 'buttons', // Specify control of pages per grid row in Grid view. Possible values: 'buttons' (+/-), 'slider'. Any other value disables the controls. + enableImageTitles: true, // Adds "Page {n}" title to page images if true enableKeyScroll: true, // Captures scrolling using the arrow and page up/down keys regardless of page focus. When off, defers to default browser scrolling behavior. enableLinkIcon: true, // Controls the visibility of the link icon enableSpaceScroll: false, // Scrolling down by pressing the space key @@ -77,7 +78,7 @@ window.divaPlugins = []; tileHeight: 256, // The height of each tile, in pixels; usually 256 tileWidth: 256, // The width of each tile, in pixels; usually 256 toolbarParentObject: options.parentObject, // The toolbar parent object. - verticallyOriented: true, // Determines vertical vs. horizontal orientation + verticallyOriented: true, // Determines vertical vs. horizontal orientation viewportMargin: 200, // Pretend tiles +/- 200px away from viewport are in zoomLevel: 2 // The initial zoom level (used to store the current zoom level) }; @@ -309,7 +310,7 @@ window.divaPlugins = []; pageElement.classList.add('diva-document-page'); pageElement.setAttribute('data-index', pageIndex); pageElement.setAttribute('data-filename', filename); - pageElement.title = "Page " + (pageIndex + 1); + if (settings.enableImageTitles) pageElement.title = "Page " + (pageIndex + 1); pageElement.innerHTML = settings.pageTools; pageElement.style.width = width + 'px'; pageElement.style.height = height + 'px'; @@ -344,7 +345,7 @@ window.divaPlugins = []; var pageElement = document.getElementById(settings.ID + 'page-' + pageIndex); // If the page is no longer in the viewport, don't load any tiles - if (!isPageVisible(pageIndex)) + if (!isPageLoaded(pageIndex)) return; var imdir = settings.imageDir + "/"; @@ -375,13 +376,14 @@ window.divaPlugins = []; while (row < rows) { col = 0; + // If the tile is in the last row or column, its dimensions will be different + tileHeight = (row === rows - 1) ? lastHeight : settings.tileHeight; + while (col < cols) { top = row * settings.tileHeight; left = col * settings.tileWidth; - // If the tile is in the last row or column, its dimensions will be different - tileHeight = (row === rows - 1) ? lastHeight : settings.tileHeight; tileWidth = (col === cols - 1) ? lastWidth : settings.tileWidth; imageURL = baseImageURL + tileIndex; @@ -392,10 +394,10 @@ window.divaPlugins = []; { if (isTileVisible(pageIndex, row, col)) { - /* - content.push('
    '); */ var tileElem = document.createElement('div'); @@ -408,7 +410,7 @@ window.divaPlugins = []; tileElem.style.backgroundImage = "url('" + imageURL + "')"; tileElem.style.height = tileHeight + "px"; tileElem.style.width = tileWidth + "px"; - + // content.push(tileElem); pageElement.appendChild(tileElem); } @@ -428,7 +430,7 @@ window.divaPlugins = []; executeCallback(settings.onPageLoaded, pageIndex, filename, pageSelector); diva.Events.publish("PageDidLoad", [pageIndex, filename, pageSelector], self); }; - settings.pageTimeouts.push(setTimeout(pageLoadFunction(pageIndex), settings.pageLoadTimeout)); + settings.pageTimeouts.push(setTimeout(pageLoadFunction, settings.pageLoadTimeout, pageIndex)); }; // Delete a page from the DOM; will occur when a page is scrolled out of the viewport @@ -436,10 +438,10 @@ window.divaPlugins = []; { // $(document.getElementById(settings.ID + 'page-' + pageIndex)).empty().remove(); var theNode = document.getElementById(settings.ID + 'page-' + pageIndex); - + if (theNode === null) return; - + while (theNode.firstChild) { theNode.removeChild(theNode.firstChild); @@ -623,7 +625,7 @@ window.divaPlugins = []; // scrolling backwards executeCallback(settings.onScrollUp, scrollSoFar); diva.Events.publish("ViewerDidScrollUp", [scrollSoFar], self); - } + } }; // Check if a row index is valid @@ -657,7 +659,7 @@ window.divaPlugins = []; var heightFromTop = (settings.rowHeight * rowIndex) + settings.fixedPadding; var content = []; var innerElem = document.getElementById(settings.ID + "inner"); - + // Create the row div var rowDiv = document.createElement('div'); rowDiv.id = settings.ID + 'row-' + rowIndex; @@ -701,7 +703,7 @@ window.divaPlugins = []; settings.pageTopOffsets[pageIndex] = heightFromTop; settings.pageLeftOffsets[pageIndex] = leftOffset; - + // Append the HTML for this page to the string builder array var pageDiv = document.createElement('div'); pageDiv.id = settings.ID + 'page-' + pageIndex; @@ -712,10 +714,10 @@ window.divaPlugins = []; pageDiv.style.left = leftOffset + 'px'; pageDiv.setAttribute('data-index', pageIndex); pageDiv.setAttribute('data-filename', filename); - pageDiv.title = "Page " + (pageIndex + 1); - + if (settings.enableImageTitles) pageDiv.title = "Page " + (pageIndex + 1); + rowDiv.appendChild(pageDiv); - + diva.Events.publish("PageWillLoad", [pageIndex, filename, pageSelector], self); // Add each image to a queue so that images aren't loaded unnecessarily @@ -728,7 +730,7 @@ window.divaPlugins = []; var theNode = document.getElementById(settings.ID + 'row-' + rowIndex); if (theNode === null) return; - + while (theNode.firstChild) { theNode.removeChild(theNode.firstChild); @@ -856,7 +858,7 @@ window.divaPlugins = []; { var loadFunction = function (rowIndex, pageIndex, imageURL, pageWidth, pageHeight) { - if (isRowVisible(rowIndex)) + if (isRowLoaded(rowIndex)) { var imgEl = document.createElement('img'); imgEl.src = imageURL; @@ -864,10 +866,10 @@ window.divaPlugins = []; imgEl.style.height = pageHeight + 'px'; document.getElementById(settings.ID + 'page-' + pageIndex).appendChild(imgEl); } - }; + }; settings.pageTimeouts.push( - window.setTimeout(loadFunction(rowIndex, pageIndex, imageURL, pageWidth, pageHeight), settings.rowLoadTimeout)); + window.setTimeout(loadFunction, settings.rowLoadTimeout, rowIndex, pageIndex, imageURL, pageWidth, pageHeight)); }; // Determines and sets the "current page" (settings.currentPageIndex); called within adjustPages @@ -877,7 +879,7 @@ window.divaPlugins = []; var currentPage = settings.currentPageIndex; var pageToConsider = currentPage + direction; - if(!isPageValid(pageToConsider)) + if (!isPageValid(pageToConsider)) return false; var middleOfViewport = (settings.verticallyOriented ? document.getElementById(settings.ID + "outer").scrollTop + (settings.panelHeight / 2) : document.getElementById(settings.ID + "outer").scrollLeft + (settings.panelWidth / 2)); @@ -900,7 +902,7 @@ window.divaPlugins = []; if (pageToConsider >= 0 && (settings.pageLeftOffsets[pageToConsider] + getPageData(pageToConsider, 'w') + (settings.horizontalPadding) >= middleOfViewport)) { changeCurrentPage = true; - } + } } } else if (direction > 0) @@ -1016,11 +1018,14 @@ window.divaPlugins = []; settings.outerObject.scrollLeft(desiredLeft); // Pretend that this is the current page - settings.currentPageIndex = pageIndex; - var filename = settings.pages[pageIndex].f; + if (pageIndex !== settings.currentPageIndex) + { + settings.currentPageIndex = pageIndex; + var filename = settings.pages[pageIndex].f; - executeCallback(settings.onSetCurrentPage, pageIndex, filename); - diva.Events.publish("VisiblePageDidChange", [pageIndex, filename], self); + executeCallback(settings.onSetCurrentPage, pageIndex, filename); + diva.Events.publish("VisiblePageDidChange", [pageIndex, filename], self); + } // Execute the onJump callback executeCallback(settings.onJump, pageIndex); @@ -1197,7 +1202,7 @@ window.divaPlugins = []; var pageIndex = settings.currentPageIndex; settings.verticalOffset = (settings.verticallyOriented ? (settings.panelHeight / 2) : getPageData(pageIndex, "h") / 2); settings.horizontalOffset = (settings.verticallyOriented ? getPageData(pageIndex, "w") / 2 : (settings.panelWidth / 2)); - + clearViewer(); // Make sure the pages per row setting is valid @@ -1242,7 +1247,7 @@ window.divaPlugins = []; //Shortcut for closing fullscreen with the escape key var escapeListener = function (e) { - if(e.keyCode == 27) + if (e.keyCode == 27) toggleFullscreen(); }; @@ -1250,54 +1255,44 @@ window.divaPlugins = []; // Should only be called after changing settings.inFullscreen var handleModeChange = function (changeView) { - var storedOffsetY = getCurrentYOffset(); - var storedOffsetX = getCurrentXOffset(); - var outerElem = document.getElementById(settings.ID + "outer"); - - settings.panelHeight = outerElem.clientHeight - (outerElem.scrollWidth > outerElem.clientWidth ? settings.scrollbarWidth : 0); - settings.panelWidth = outerElem.clientWidth - (outerElem.scrollHeight > outerElem.clientHeight ? settings.scrollbarWidth : 0); - var storedHeight = settings.panelHeight; - var storedWidth = settings.panelWidth; - // Toggle the classes settings.outerObject.toggleClass('diva-fullscreen'); $('body').toggleClass('diva-hide-scrollbar'); settings.parentObject.toggleClass('diva-full-width'); // Adjust margin a bit if in mobile - if(settings.mobileWebkit) + if (settings.mobileWebkit) { var leftMarginComped = parseInt(settings.outerObject.css('margin-left'), 10) - parseInt($('body').css('margin-left'), 10); settings.outerObject.css('margin-left', leftMarginComped); } - // Execute callbacks - executeCallback(settings.onModeToggle, settings.inFullscreen); - diva.Events.publish("ModeDidSwitch", [settings.inFullscreen], self); - - // If it has changed, adjust panel size coming out of fullscreen - if (!settings.inFullscreen) - { - updatePanelSize(); - } + // Adjust Diva's internal panel size, keeping the old values + var storedHeight = settings.panelHeight; + var storedWidth = settings.panelWidth; + updatePanelSize(); + // If this isn't the original load... if (settings.oldZoomLevel >= 0 && !settings.inGrid) { + //get the updated panel size var newHeight = settings.panelHeight; var newWidth = settings.panelWidth; - if(settings.inFullscreen) + + //and re-center the new panel on the same point + if (settings.inFullscreen) { - settings.verticalOffset = ((newHeight - storedHeight) / 2) + storedOffsetY; - settings.horizontalOffset = ((newWidth - storedWidth) / 2) + storedOffsetX; + settings.verticalOffset -= ((newHeight - storedHeight) / 2); + settings.horizontalOffset -= ((newWidth - storedWidth) / 2); } else { - settings.verticalOffset = storedOffsetY - ((storedHeight - newHeight) / 2); - settings.verticalOffset = storedOffsetX - ((storedWidth - newWidth) / 2); + settings.verticalOffset += ((storedHeight - newHeight) / 2); + settings.horizontalOffset += ((storedWidth - newWidth) / 2); } } - // Used by setState when we need to change the view and the mode + // If setState changes both view and mode, trigger that here if (changeView) { settings.inGrid = !settings.inGrid; @@ -1308,10 +1303,15 @@ window.divaPlugins = []; loadViewer(); } - if(settings.inFullscreen) + //turn on/off escape key listener + if (settings.inFullscreen) $(document).on('keyup', escapeListener); else $(document).off('keyup', escapeListener); + + // Execute callbacks + executeCallback(settings.onModeToggle, settings.inFullscreen); + diva.Events.publish("ModeDidSwitch", [settings.inFullscreen], self); }; // Handles switching in and out of grid view @@ -1478,7 +1478,7 @@ window.divaPlugins = []; var getYOffset = function (pageIndex, anchor) { pageIndex = (typeof(pageIndex) === "undefined" ? settings.currentPageIndex : pageIndex); - + if (anchor === "center" || anchor === "centre") //how you can tell an American coded this { return parseInt(getPageData(pageIndex, "h") / 2, 10); @@ -1571,8 +1571,8 @@ window.divaPlugins = []; var updatePanelSize = function () { var outerElem = document.getElementById(settings.ID + 'outer'); - settings.panelHeight = outerElem.clientHeight - (outerElem.scrollWidth > outerElem.clientWidth ? settings.scrollbarWidth : 0); - settings.panelWidth = outerElem.clientWidth - (outerElem.scrollHeight > outerElem.clientHeight ? settings.scrollbarWidth : 0); + settings.panelHeight = outerElem.clientHeight - (outerElem.scrollWidth > outerElem.clientWidth ? settings.scrollbarWidth : 0); + settings.panelWidth = outerElem.clientWidth - (outerElem.scrollHeight > outerElem.clientHeight ? settings.scrollbarWidth : 0); settings.horizontalOffset = getCurrentXOffset(); settings.verticalOffset = getCurrentYOffset(); @@ -1674,7 +1674,7 @@ window.divaPlugins = []; if (settings.verticallyOriented || settings.inGrid) direction = newScrollTop - settings.previousTopScroll; else - direction = newScrollLeft - settings.previousLeftScroll; + direction = newScrollLeft - settings.previousLeftScroll; //give adjustPages the direction we care about if (settings.inGrid) @@ -1691,6 +1691,79 @@ window.divaPlugins = []; settings.outerObject.scroll(scrollFunction); + var upArrowKey = 38, + downArrowKey = 40, + leftArrowKey = 37, + rightArrowKey = 39, + spaceKey = 32, + pageUpKey = 33, + pageDownKey = 34, + homeKey = 36, + endKey = 35; + + // Catch the key presses in document + $(document).keydown(function (event) + { + if (!settings.isActiveDiva) + return true; + + // Space or page down - go to the next page + if ((settings.enableSpaceScroll && !event.shiftKey && event.keyCode === spaceKey) || (settings.enableKeyScroll && event.keyCode === pageDownKey)) + { + settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop + settings.panelHeight); + return false; + } + else if (!settings.enableSpaceScroll && event.keyCode === spaceKey) + { + event.preventDefault(); + } + + if (settings.enableKeyScroll) + { + switch (event.keyCode) + { + case pageUpKey: + // Page up - go to the previous page + settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop - settings.panelHeight); + return false; + + case upArrowKey: + // Up arrow - scroll up + settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop - settings.arrowScrollAmount); + return false; + + case downArrowKey: + // Down arrow - scroll down + settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop + settings.arrowScrollAmount); + return false; + + case leftArrowKey: + // Left arrow - scroll left + settings.outerObject.scrollLeft(document.getElementById(settings.ID + "outer").scrollLeft - settings.arrowScrollAmount); + return false; + + case rightArrowKey: + // Right arrow - scroll right + settings.outerObject.scrollLeft(document.getElementById(settings.ID + "outer").scrollLeft + settings.arrowScrollAmount); + return false; + + case homeKey: + // Home key - go to the beginning of the document + settings.outerObject.scrollTop(0); + return false; + + case endKey: + // End key - go to the end of the document + settings.outerObject.scrollTop(settings.totalHeight); + return false; + + default: + return true; + } + } + return true; + }); + // Check if the user is on a iPhone or iPod touch or iPad if (settings.mobileWebkit) { @@ -1814,117 +1887,47 @@ window.divaPlugins = []; // Grid view: Double-tap to jump to current page in document view settings.outerObject.on('touchend', '.diva-page', bindDoubleTap); - } - - // Only check if either scrollBySpace or scrollByKeys is enabled - if (settings.enableSpaceScroll || settings.enableKeyScroll) - { - var upArrowKey = 38, - downArrowKey = 40, - leftArrowKey = 37, - rightArrowKey = 39, - spaceKey = 32, - pageUpKey = 33, - pageDownKey = 34, - homeKey = 36, - endKey = 35; - // Catch the key presses in document - $(document).keydown(function (event) + // Handle window resizing events + var orientationEvent = "onorientationchange" in window ? "orientationchange" : "resize"; + $(window).bind(orientationEvent, function (event) { - if (!settings.isActiveDiva) - return; - - // Space or page down - go to the next page - if ((settings.enableSpaceScroll && event.keyCode === spaceKey) || (settings.enableKeyScroll && event.keyCode === pageDownKey)) - { - settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop + settings.panelHeight); - return false; - } + var oldWidth = settings.panelWidth; + var oldHeight = settings.panelHeight; + updatePanelSize(); - if (settings.enableKeyScroll) - { - switch (event.keyCode) - { - case pageUpKey: - // Page up - go to the previous page - settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop - settings.panelHeight); - return false; - - case upArrowKey: - // Up arrow - scroll up - settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop - settings.arrowScrollAmount); - return false; - - case downArrowKey: - // Down arrow - scroll down - settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop + settings.arrowScrollAmount); - return false; - - case leftArrowKey: - // Left arrow - scroll left - settings.outerObject.scrollLeft(document.getElementById(settings.ID + "outer").scrollLeft - settings.arrowScrollAmount); - return false; - - case rightArrowKey: - // Right arrow - scroll right - settings.outerObject.scrollLeft(document.getElementById(settings.ID + "outer").scrollLeft + settings.arrowScrollAmount); - return false; - - case homeKey: - // Home key - go to the beginning of the document - settings.outerObject.scrollTop(0); - return false; - - case endKey: - // End key - go to the end of the document - settings.outerObject.scrollTop(settings.totalHeight); - return false; - } - } - }); + settings.horizontalOffset -= (settings.panelWidth - oldWidth) / 2; + settings.verticalOffset -= (settings.panelHeight - oldHeight) / 2; - // Handle window resizing events - if (!settings.mobileWebkit) + // Reload the viewer to account for the resized viewport + settings.goDirectlyTo = settings.currentPageIndex; + loadViewer(); + }); + } + // Handle window resizing events + else + { + $(window).resize(function () { - $(window).resize(function () - { - updatePanelSize(); - // Cancel any previously-set resize timeouts - clearTimeout(settings.resizeTimer); + updatePanelSize(); + // Cancel any previously-set resize timeouts + clearTimeout(settings.resizeTimer); - settings.resizeTimer = setTimeout(function () - { - settings.goDirectlyTo = settings.currentPageIndex; - settings.verticalOffset = getCurrentYOffset(); - settings.horizontalOffset = getCurrentXOffset(); - loadViewer(); - }, 200); - }); - } - else - { - var orientationEvent = "onorientationchange" in window ? "orientationchange" : "resize"; - $(window).bind(orientationEvent, function (event) + settings.resizeTimer = setTimeout(function () { - var oldWidth = settings.panelWidth; - var oldHeight = settings.panelHeight; - updatePanelSize(); - - settings.horizontalOffset -= (settings.panelWidth - oldWidth) / 2; - settings.verticalOffset -= (settings.panelHeight - oldHeight) / 2; - - // Reload the viewer to account for the resized viewport settings.goDirectlyTo = settings.currentPageIndex; + settings.verticalOffset = getCurrentYOffset(); + settings.horizontalOffset = getCurrentXOffset(); loadViewer(); - }); - } - diva.Events.subscribe('PanelSizeDidChange', updatePanelSize); + }, 200); + }); } + diva.Events.subscribe('PanelSizeDidChange', updatePanelSize); + }; // Handles all status updating etc (both fullscreen and not) - var createToolbar = function () + var createToolbar = function () { // Prepare the HTML for the various components var gridIconHTML = (settings.enableGridIcon) ? '
    ' : ''; @@ -1941,7 +1944,7 @@ window.divaPlugins = []; var pageNumberHTML = '
    Page 1 of ' + settings.numPages + '
    '; var fullscreenIconHTML = (settings.enableFullscreen) ? '
    ' : ''; - var toolbarHTML = '
    ' + zoomSliderHTML + zoomButtonsHTML + gridSliderHTML + gridButtonsHTML + zoomSliderLabelHTML + zoomButtonsLabelHTML + gridSliderLabelHTML + gridButtonsLabelHTML + '
    ' + fullscreenIconHTML + linkIconHTML + gridIconHTML + '
    ' + gotoPageHTML + pageNumberHTML + '
    '; + var toolbarHTML = '
    ' + zoomSliderHTML + zoomButtonsHTML + gridSliderHTML + gridButtonsHTML + zoomSliderLabelHTML + zoomButtonsLabelHTML + gridSliderLabelHTML + gridButtonsLabelHTML + '
    ' + fullscreenIconHTML + linkIconHTML + gridIconHTML + '
    ' + gotoPageHTML + pageNumberHTML + '
    '; settings.toolbarParentObject.prepend('
    ' + toolbarHTML + '
    '); @@ -1992,7 +1995,7 @@ window.divaPlugins = []; }); // Bind fullscreen button - $(settings.selector + 'fullscreen').click(function() + $(settings.selector + 'fullscreen').click(function() { toggleFullscreen(); }); @@ -2036,10 +2039,11 @@ window.divaPlugins = []; return false; }); + var linkIcon = $(settings.selector + 'link-icon'); // Handle the creation of the link popup box - $(settings.selector + 'link-icon').click(function () + linkIcon.click(function () { - $('body').prepend(''); + $('body').prepend(''); if (settings.inFullscreen) { @@ -2048,10 +2052,8 @@ window.divaPlugins = []; else { // Calculate the left and top offsets - // Compensate for border, popup width - var leftOffset = settings.outerObject.offset().left + settings.panelWidth; - leftOffset += settings.scrollbarWidth - 240 - 1; - var topOffset = settings.outerObject.offset().top + 1; + var leftOffset = linkIcon.offset().left - 222 + linkIcon.outerWidth(); + var topOffset = linkIcon.offset().top + linkIcon.outerHeight() - 1; $(settings.selector + 'link-popup').removeClass('in-fullscreen').css( { @@ -2151,7 +2153,7 @@ window.divaPlugins = []; }, updateZoomButtons: function () { - // Update the buttons label + // Update the buttons label document.getElementById(settings.ID + 'zoom-level').textContent = settings.zoomLevel; }, updateGridSlider: function () @@ -2170,6 +2172,10 @@ window.divaPlugins = []; // Update the buttons label document.getElementById(settings.ID + 'pages-per-row').textContent = settings.pagesPerRow; }, + closePopups: function () + { + $('.diva-popup').css('display', 'none'); + }, switchView: switchView, switchMode: switchMode }; @@ -2363,11 +2369,11 @@ window.divaPlugins = []; } // Adjust the document panel dimensions - updatePanelSize(); + updatePanelSize(); // Make sure the value for settings.goDirectlyTo is valid if (!isPageValid(parseInt(settings.goDirectlyTo), 10)) - settings.goDirectlyTo = 0; + settings.goDirectlyTo = 0; // Calculate the horizontal and vertical inter-page padding if (settings.adaptivePadding > 0) @@ -2387,7 +2393,7 @@ window.divaPlugins = []; if (settings.pageTools.length) { settings.verticalPadding = Math.max(40, settings.verticalPadding); - } + } // y - vertical offset from the top of the relevant page var yParam = parseInt($.getHashParam('y' + settings.hashParamSuffix), 10); @@ -2411,7 +2417,7 @@ window.divaPlugins = []; else { settings.horizontalOffset = getXOffset(settings.currentPageIndex, "center"); - } + } if (settings.inFullscreen) handleModeChange(false); @@ -2687,12 +2693,25 @@ window.divaPlugins = []; return isPageVisible(pageIndex); }; + //Public wrapper for isPageLoaded + //Determines if a page is currently in the DOM + this.isPageInDOM = function (pageIndex) + { + return isPageLoaded(pageIndex); + }; + // Toggle fullscreen mode this.toggleFullscreenMode = function () { toggleFullscreen(); }; + // Close toolbar popups + this.closePopups = function () + { + settings.toolbar.closePopups(); + }; + // Enter fullscreen mode if currently not in fullscreen mode // Returns false if in fullscreen mode initially, true otherwise // This function will work even if enableFullscreen is set to false @@ -2730,7 +2749,7 @@ window.divaPlugins = []; // Returns false if in grid view initially, true otherwise this.enterGridView = function () { - if (!settings.inGrid) + if (!settings.inGrid) { toggleGrid(); return true; @@ -2940,7 +2959,7 @@ window.divaPlugins = []; return toggleOrientation(); }; - //Returns distance between the northwest corners of diva-inner and current page + //Returns distance between the northwest corners of diva-inner and page index this.getPageOffset = function(pageIndex) { return { @@ -2949,6 +2968,12 @@ window.divaPlugins = []; }; }; + //shortcut to getPageOffset for current page + this.getCurrentPageOffset = function() + { + return this.getPageOffset(settings.currentPageIndex); + }; + //Returns the page position and size (ulx, uly, h, w properties) of page pageIndex when there are pagesPerRow pages per row //TODO: calculate all grid height levels and store them so this can be AtGridLevel(pageIndex, pagesPerRow) ? this.getPageDimensionsAtCurrentGridLevel = function(pageIndex) @@ -2964,62 +2989,57 @@ window.divaPlugins = []; }; }; - //Returns the page index at a given pageX/pageY value + /* + Given a pageX and pageY value (as could be retreived from a jQuery event object), + returns either the page visible at that (x,y) position or "false" if no page is. + */ this.getPageIndexForPageXYValues = function(pageX, pageY) { - var outerObj = $("#" + settings.ID + "outer"); - var outerOffset = outerObj.offset(); + //get the four edges of the outer element + var outerObj = document.getElementById(settings.ID + "outer") + var outerOffset = outerObj.getBoundingClientRect(); var outerTop = outerOffset.top; var outerLeft = outerOffset.left; - var outerBottom = outerTop + outerObj.outerHeight(); - var outerRight = outerLeft + outerObj.outerWidth(); - - //because pages extend outside the diva-outer class, we want to exclude those values as the pageX/pageY values aren't actually on them + var outerBottom = outerOffset.bottom; + var outerRight = outerOffset.right; + + //if the clicked position was outside the diva-outer object, it was not on a visible portion of a page if (pageX < outerLeft || pageX > outerRight) return false; if (pageY < outerTop || pageY > outerBottom) return false; - //navigate through all divs starting with "x-diva-page" - var curPageIdx = $("div[id^=" + settings.ID + "page]").length; + //navigate through all diva page objects + var pages = document.getElementsByClassName("diva-document-page"); + var curPageIdx = pages.length; while (curPageIdx--) { - var curPage = $($("div[id^=" + settings.ID + "page]")[curPageIdx]); - var pageIndex = curPage.attr('data-index'); - var curPosition = curPage.position(); - var curOffset = curPage.offset(); - var curTop, curLeft; + //get the offset for each page + var curPage = pages[curPageIdx]; + var curOffset = curPage.getBoundingClientRect(); - if (settings.verticallyOriented) - { - curTop = curPosition.top - outerObj.scrollTop() + outerTop; - curLeft = curOffset.left - outerObj.scrollLeft() + outerLeft; - } - else - { - curTop = curOffset.top - outerObj.scrollTop() + outerTop; - curLeft = curPosition.left - outerObj.scrollLeft() + outerLeft; - } - - var curBottom = curTop + curPage.outerHeight(); - var curRight = curLeft + curPage.outerWidth(); - - //if this point is outside the horizontal boundaries, continue - if (pageX < curLeft || pageX > curRight) - continue + //if this point is outside the horizontal boundaries of the page, continue + if (pageX < curOffset.left || pageX > curOffset.right) + continue; //same with vertical boundaries - if (pageY < curTop || pageY > curBottom) - continue + if (pageY < curOffset.top || pageY > curOffset.bottom) + continue; - //if we made it through the above two, we found the page we're looking for - return pageIndex; + //if we made it through the above two, we found the page we're looking for + return curPage.getAttribute('data-index'); } //if we made it through that entire while loop, we didn't click on a page return false; - } + }; + + //Pretty self-explanatory. + this.isVerticallyOriented = function() + { + return settings.verticallyOriented; + }; this.activate = function () { diff --git a/build/js/diva.min.js b/build/js/diva.min.js index aaa328b0..869548bc 100644 --- a/build/js/diva.min.js +++ b/build/js/diva.min.js @@ -1,118 +1,127 @@ -Storage.prototype.setObject=function(b,f){this.setItem(b,JSON.stringify(f))};Storage.prototype.getObject=function(b){return(b=this.getItem(b))&&JSON.parse(b)};(function(b){var f=1;b.generateId=function(b){var d;do d=f++ +(b?"-"+b:"");while(document.getElementById(d));return d}})(jQuery); -(function(b){b.getScrollbarWidth=function(){var b=document.createElement("p");b.style.width="100%";b.style.height="200px";var e=document.createElement("div");e.style.position="absolute";e.style.top="0px";e.style.left="0px";e.style.visibility="hidden";e.style.width="200px";e.style.height="150px";e.style.overflow="hidden";e.appendChild(b);document.body.appendChild(e);var d=b.offsetWidth;e.style.overflow="scroll";b=b.offsetWidth;d==b&&(b=e.clientWidth);document.body.removeChild(e);return d-b}})(jQuery); -(function(b){b.getHashParam=function(b){var e=window.location.hash;if(""!==e){var d=0d?e.substring(d,b):0>b?e.substring(d):""}return!1}})(jQuery); -(function(b){b.updateHashParam=function(f,e){var d=b.getHashParam(f),a=window.location.hash;if(d!==e)if("string"==typeof d){var k=0:first",acceptPropagatedEvent:!0,preventDefault:!0},f||{}),d={mouseDownHandler:function(a){if(1!=a.which||!a.data.acceptPropagatedEvent&&a.target!=this)return!1;a.data.lastCoord={left:a.clientX,top:a.clientY};b.event.add(document,"mouseup",d.mouseUpHandler,a.data);b.event.add(document,"mousemove",d.mouseMoveHandler,a.data);if(a.data.preventDefault)return a.preventDefault(),!1},mouseMoveHandler:function(a){var b=a.clientX- -a.data.lastCoord.left,d=a.clientY-a.data.lastCoord.top;a.data.scrollable.scrollLeft(a.data.scrollable.scrollLeft()-b);a.data.scrollable.scrollTop(a.data.scrollable.scrollTop()-d);a.data.lastCoord={left:a.clientX,top:a.clientY};if(a.data.preventDefault)return a.preventDefault(),!1},mouseUpHandler:function(a){b.event.remove(document,"mousemove",d.mouseMoveHandler);b.event.remove(document,"mouseup",d.mouseUpHandler);if(a.data.preventDefault)return a.preventDefault(),!1}};this.each(function(){var a={scrollable:b(this), -acceptPropagatedEvent:e.acceptPropagatedEvent,preventDefault:e.preventDefault};b(this).find(e.dragSelector).bind("mousedown",a,d.mouseDownHandler)})}})(jQuery); +Storage.prototype.setObject=function(b,f){this.setItem(b,JSON.stringify(f))};Storage.prototype.getObject=function(b){return(b=this.getItem(b))&&JSON.parse(b)};(function(b){var f=1;b.generateId=function(b){var c;do c=f++ +(b?"-"+b:"");while(document.getElementById(c));return c}})(jQuery); +(function(b){b.getScrollbarWidth=function(){var b=document.createElement("p");b.style.width="100%";b.style.height="200px";var e=document.createElement("div");e.style.position="absolute";e.style.top="0px";e.style.left="0px";e.style.visibility="hidden";e.style.width="200px";e.style.height="150px";e.style.overflow="hidden";e.appendChild(b);document.body.appendChild(e);var c=b.offsetWidth;e.style.overflow="scroll";b=b.offsetWidth;c==b&&(b=e.clientWidth);document.body.removeChild(e);return c-b}})(jQuery); +(function(b){b.getHashParam=function(b){var e=window.location.hash;if(""!==e){var c=0c?e.substring(c,b):0>b?e.substring(c):""}return!1}})(jQuery); +(function(b){b.updateHashParam=function(f,e){var c=b.getHashParam(f),a=window.location.hash;if(c!==e)if("string"==typeof c){var h=0:first",acceptPropagatedEvent:!0,preventDefault:!0},f||{}),c={mouseDownHandler:function(a){if(1!=a.which||!a.data.acceptPropagatedEvent&&a.target!=this)return!1;a.data.lastCoord={left:a.clientX,top:a.clientY};b.event.add(document,"mouseup",c.mouseUpHandler,a.data);b.event.add(document,"mousemove",c.mouseMoveHandler,a.data);if(a.data.preventDefault)return a.preventDefault(),!1},mouseMoveHandler:function(a){var b=a.clientX- +a.data.lastCoord.left,c=a.clientY-a.data.lastCoord.top;a.data.scrollable.scrollLeft(a.data.scrollable.scrollLeft()-b);a.data.scrollable.scrollTop(a.data.scrollable.scrollTop()-c);a.data.lastCoord={left:a.clientX,top:a.clientY};if(a.data.preventDefault)return a.preventDefault(),!1},mouseUpHandler:function(a){b.event.remove(document,"mousemove",c.mouseMoveHandler);b.event.remove(document,"mouseup",c.mouseUpHandler);if(a.data.preventDefault)return a.preventDefault(),!1}};this.each(function(){var a={scrollable:b(this), +acceptPropagatedEvent:e.acceptPropagatedEvent,preventDefault:e.preventDefault};b(this).find(e.dragSelector).bind("mousedown",a,c.mouseDownHandler)})}})(jQuery); (function(b){var f={cursor:"move",decelerate:!0,triggerHardware:!1,y:!0,x:!0,slowdown:0.9,maxvelocity:40,throttleFPS:60,movingClass:{up:"kinetic-moving-up",down:"kinetic-moving-down",left:"kinetic-moving-left",right:"kinetic-moving-right"},deceleratingClass:{up:"kinetic-decelerating-up",down:"kinetic-decelerating-down",left:"kinetic-decelerating-left",right:"kinetic-decelerating-right"}};window.requestAnimationFrame||(window.requestAnimationFrame=function(){return window.webkitRequestAnimationFrame|| -window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a,b){window.setTimeout(a,1E3/60)}}());b.support=b.support||{};b.extend(b.support,{touch:"ontouchend"in document});var e=function(){return!1},d=function(a,b){return 0===Math.floor(Math.abs(a))?0:a*b},a=function(a,b){var d=a;0b&&(d=b):a<0-b&&(d=0-b);return d},k=function(a,b){this.removeClass(a.movingClass.up).removeClass(a.movingClass.down).removeClass(a.movingClass.left).removeClass(a.movingClass.right).removeClass(a.deceleratingClass.up).removeClass(a.deceleratingClass.down).removeClass(a.deceleratingClass.left).removeClass(a.deceleratingClass.right); -0a.velocity&&this.addClass(b.left);0a.velocityY&&this.addClass(b.up)},g=function(a,b){b.velocity=0;b.velocityY=0;b.decelerate=!0;"function"===typeof b.stopped&&b.stopped.call(a,b)},l=function(a,b){var e=a[0];b.x&&0new Date(H.getTime()+z))H=new Date,v&&(p||r)&&(A&&(b(A).blur(),A=null,g.focus()),h.decelerate=!1,h.velocity=h.velocityY=0,g[0].scrollLeft=h.scrollLeft=h.x?g[0].scrollLeft-(a-p):g[0].scrollLeft, -g[0].scrollTop=h.scrollTop=h.y?g[0].scrollTop-(d-r):g[0].scrollTop,s=p,x=r,p=a,r=d,m(),k.call(g,h,h.movingClass),"function"===typeof h.moved&&h.moved.call(g,h))};h.events={touchStart:function(a){var b;if(q(a.target)){b=a.originalEvent.touches[0];var d=b.clientX;b=b.clientY;v=!0;h.velocity=s=0;h.velocityY=x=0;p=d;r=b;a.stopPropagation()}},touchMove:function(a){var b;v&&(b=a.originalEvent.touches[0],n(b.clientX,b.clientY),a.preventDefault&&a.preventDefault())},inputDown:function(a){if(q(a.target)){var b= -a.clientX,d=a.clientY;v=!0;h.velocity=s=0;h.velocityY=x=0;p=b;r=d;A=a.target;"IMG"===a.target.nodeName&&a.preventDefault();a.stopPropagation()}},inputEnd:function(a){p&&s&&!1===h.decelerate&&(h.decelerate=!0,m(),p=s=v=!1,l(g,h));A=null;a.preventDefault&&a.preventDefault()},inputMove:function(a){v&&(n(a.clientX,a.clientY),a.preventDefault&&a.preventDefault())},scroll:function(a){"function"===typeof h.moved&&h.moved.call(g,h);a.preventDefault&&a.preventDefault()},inputClick:function(a){if(0=e&&c<=f||c<=e&&d>=f||d>=e&&d<=f},p=function(c,d){var e=b("#"+a.ID+"outer").scrollTop()-a.viewportMargin,f=e+a.panelHeight+2*a.viewportMargin;return c>=e&&c<=f||c<=e&&d>=f||d>=e&&d<=f},t=function(c){return 0<= -c&&cb},r=function(c,b){0b},q=function(c,b){0c?a.verticallyOriented?0<=d&&a.pageTopOffsets[d]+ -l(d,"h")+a.verticalPadding>=e&&(m=!0):0<=d&&a.pageLeftOffsets[d]+l(d,"w")+a.horizontalPadding>=e&&(m=!0):0c?0<=d&&(a.rowHeight*b>=m||a.rowHeight*d>=e)&&(q=!0):0=a.minZoomLevel&&c<=a.maxZoomLevel?c:a.minZoomLevel},N=function(c){return c>=a.minPagesPerRow&&c<=a.maxPagesPerRow?c:a.maxPagesPerRow},ha=function(){a.allTilesLoaded= -[];a.outerObject.scrollTop(0);a.innerObject.empty();a.firstPageLoaded=0;a.firstRowLoaded=-1;a.previousTopScroll=0;a.previousLeftScroll=0;for(clearTimeout(a.resizeTimer);a.pageTimeouts.length;)clearTimeout(a.pageTimeouts.pop())},Q=function(){a.inGrid?ia():aa()},aa=function(){ha();a.zoomLevel=D(a.zoomLevel);var c=a.zoomLevel;a.totalHeight=a.totalHeights[c]+a.verticalPadding*(a.numPages+1);a.totalWidth=a.totalWidths[c]+a.horizontalPadding*(a.numPages+1);var b=a.maxHeights[c]+2*a.verticalPadding,d=Math.max(a.maxWidths[c]+ -2*a.horizontalPadding,a.panelWidth),b=Math.max(b,a.panelHeight),e=document.getElementById(a.ID+"inner");a.verticallyOriented?(e.style.height=Math.round(a.totalHeight)+"px",e.style.width=Math.round(d)+"px"):(e.style.height=Math.round(b)+"px",e.style.width=Math.round(a.totalWidth)+"px");var m=0,q=0;a.pageTopOffsets=[];a.pageLeftOffsets=[];for(e=0;ea.firstRowLoaded?b:a.firstRowLoaded,H(b),a.lastRowLoaded=b)},ja=function(a){27== -a.keyCode&&B()},ba=function(c){var d=R(),e=S(),m=document.getElementById(a.ID+"outer");a.panelHeight=m.clientHeight-(m.scrollWidth>m.clientWidth?a.scrollbarWidth:0);a.panelWidth=m.clientWidth-(m.scrollHeight>m.clientHeight?a.scrollbarWidth:0);var m=a.panelHeight,q=a.panelWidth;a.outerObject.toggleClass("diva-fullscreen");b("body").toggleClass("diva-hide-scrollbar");a.parentObject.toggleClass("diva-full-width");if(a.mobileWebkit){var n=parseInt(a.outerObject.css("margin-left"),10)-parseInt(b("body").css("margin-left"), -10);a.outerObject.css("margin-left",n)}g(a.onModeToggle,a.inFullscreen);diva.Events.publish("ModeDidSwitch",[a.inFullscreen],f);a.inFullscreen||T();if(0<=a.oldZoomLevel&&!a.inGrid){var n=a.panelHeight,h=a.panelWidth;a.inFullscreen?(a.verticalOffset=(n-m)/2+d,a.horizontalOffset=(h-q)/2+e):(a.verticalOffset=d-(m-n)/2,a.verticalOffset=e-(q-h)/2)}c?(a.inGrid=!a.inGrid,E()):Q();if(a.inFullscreen)b(document).on("keyup",ja);else b(document).off("keyup",ja)},E=function(){Q();g(a.onViewToggle,a.inGrid);diva.Events.publish("ViewDidSwitch", -[a.inGrid],f)},B=function(){a.goDirectlyTo=a.currentPageIndex;a.inFullscreen=!a.inFullscreen;ba(!1)},C=function(){a.goDirectlyTo=a.currentPageIndex;a.inGrid=!a.inGrid;E()},F=function(c){var d=b(this).offset();a.doubleClickZoom=!0;a.horizontalOffset=c.pageX-d.left;a.verticalOffset=c.pageY-d.top;a.goDirectlyTo=parseInt(b(this).attr("data-index"),10);O(c.ctrlKey?a.zoomLevel-1:a.zoomLevel+1)},ka=function(c){var d=parseInt(b(this).attr("data-index"),10);a.goDirectlyTo=d;var e=b(this).offset(),d=l(d,"w")/ -b(this).width();a.horizontalOffset=(c.pageX-e.left)*d;a.verticalOffset=(c.pageY-e.top)*d;a.inGrid=!1;E()},O=function(c){var b=D(c);if(b!==c)return!1;c=Math.pow(2,b-a.zoomLevel);a.doubleClickZoom?(a.verticalOffset*=c,a.horizontalOffset*=c,a.doubleClickZoom=!1):(a.goDirectlyTo=a.currentPageIndex,a.verticalOffset=c*R(),a.horizontalOffset=c*S());a.oldZoomLevel=a.zoomLevel;a.zoomLevel=b;diva.Events.publish("ZoomLevelDidChange",[b],f);aa();return!0},Z=function(c){var b=N(c);if(b!==c)return!1;a.pagesPerRow= -b;diva.Events.publish("GridRowNumberDidChange",[b],f);a.goDirectlyTo=a.currentPageIndex;ia();return!0},U=function(c,b){c="undefined"===typeof c?a.currentPageIndex:c;return"center"===b||"centre"===b?parseInt(l(c,"h")/2,10):"bottom"===b?parseInt(l(c,"h")-a.panelHeight/2,10):parseInt(a.panelHeight/2,10)},V=function(c,b){c="undefined"===typeof c?a.currentPageIndex:c;return"left"===b?parseInt(a.panelWidth/2,10):"right"===b?parseInt(l(c,"w")-a.panelWidth/2,10):parseInt(l(c,"w")/2,10)},R=function(){return document.getElementById(a.ID+ -"outer").scrollTop-a.pageTopOffsets[a.currentPageIndex]+parseInt(a.panelHeight/2,10)},S=function(){return document.getElementById(a.ID+"outer").scrollLeft-a.pageLeftOffsets[a.currentPageIndex]+parseInt(a.panelWidth/2,10)},la=function(){return{f:a.inFullscreen,g:a.inGrid,z:a.zoomLevel,n:a.pagesPerRow,i:a.enableFilename?a.pages[a.currentPageIndex].f:!1,p:a.enableFilename?!1:a.currentPageIndex+1,y:a.inGrid?!1:R(),x:a.inGrid?!1:S()}},ma=function(){var c=la(),b=[],d;for(d in c)!1!==c[d]&&b.push(d+a.hashParamSuffix+ -"="+c[d]);return b.join("&")},na=function(){return location.protocol+"//"+location.host+location.pathname+"#"+ma()},T=function(){var c=document.getElementById(a.ID+"outer");a.panelHeight=c.clientHeight-(c.scrollWidth>c.clientWidth?a.scrollbarWidth:0);a.panelWidth=c.clientWidth-(c.scrollHeight>c.clientHeight?a.scrollbarWidth:0);a.horizontalOffset=S();a.verticalOffset=R();M(a.currentPageIndex,a.verticalOffset,a.horizontalOffset);return!0},oa=function(){a.mobileWebkit||(a.outerObject.dragscrollable({dragSelector:".diva-dragger", -acceptPropagatedEvent:!0}),a.innerObject.dragscrollable({dragSelector:".diva-dragger",acceptPropagatedEvent:!0}));a.outerObject.on("dblclick",".diva-document-page",function(a){F.call(this,a)});a.outerObject.on("contextmenu",".diva-document-page",function(c){if(c.ctrlKey)return clearTimeout(a.singleClickTimeout),a.singleClick?(F.call(this,c),a.singleClick=!1):(a.singleClick=!0,a.singleClickTimeout=setTimeout(function(){a.singleClick=!1},500)),!1});a.outerObject.on("dblclick",".diva-row",function(a){ka.call(b(a.target).parent(), -a)})},ca=function(a,b,d,e){return Math.sqrt((a-b)*(a-b)+(d-e)*(d-e))},ra=function(){a.innerObject.mouseover(function(){b(this).removeClass("diva-grabbing").addClass("diva-grab")});a.innerObject.mouseout(function(){b(this).removeClass("diva-grab")});a.innerObject.mousedown(function(){b(this).removeClass("diva-grab").addClass("diva-grabbing")});a.innerObject.mouseup(function(){b(this).removeClass("diva-grabbing").addClass("diva-grab")});oa();a.outerObject.scroll(function(){var c,b=document.getElementById(a.ID+ -"outer").scrollTop,d=document.getElementById(a.ID+"outer").scrollLeft;c=a.verticallyOriented||a.inGrid?b-a.previousTopScroll:d-a.previousLeftScroll;if(a.inGrid){0>c?(q(a.firstRowLoaded,-1),G(-1),n(a.lastRowLoaded,-1)):0c)r(a.firstPageLoaded,c),w(-1),x(a.lastPageLoaded,c);else if(0c&&(g(a.onScrollUp,e),diva.Events.publish("ViewerDidScrollUp",[e],f));a.previousTopScroll=b;a.previousLeftScroll=d;a.horizontalOffset=S();a.verticalOffset=R()});if(a.mobileWebkit){var c=[];c.push(''); -c.push('');c.push('');b("head").append(c.join("\n"));a.blockMobileMove&&b("body").bind("touchmove",function(a){a.originalEvent.preventDefault();return!1});a.outerObject.kinetic({triggerHardware:!0});var d=[],e=[],m=0;a.outerObject.on("touchstart",".diva-document-page",function(a){2===a.originalEvent.touches.length&&(d=[a.originalEvent.touches[0].clientX,a.originalEvent.touches[0].clientY, -a.originalEvent.touches[1].clientX,a.originalEvent.touches[1].clientY],m=ca(d[2],d[0],d[3],d[1]))});a.outerObject.on("touchmove",".diva-document-page",function(c){if(2===c.originalEvent.touches.length){e=[c.originalEvent.touches[0].clientX,c.originalEvent.touches[0].clientY,c.originalEvent.touches[1].clientX,c.originalEvent.touches[1].clientY];var d=ca(e[2],e[0],e[3],e[1])-m;if(!a.scaleWait)if(a.goDirectlyTo=a.currentPageIndex,a.inGrid)a.inGrid=!1,E();else a:{var f=a.zoomLevel;if(100d&&f>a.minZoomLevel)f--;else break a;a.scaleWait=!0;d=b(this).offset();a.horizontalOffset=c.pageX-d.left;a.verticalOffset=c.pageY-d.top;a.goDirectlyTo=parseInt(b(this).attr("data-index"),10);O(f)}}});var h={},l=0,c=function(c){if(a.singleTap){var d={pageX:c.originalEvent.changedTouches[0].clientX,pageY:c.originalEvent.changedTouches[0].clientY};l=ca(h.pageX,d.pageX,h.pageY,d.pageY);50>l&&a.zoomLevel'+('
    '+("slider"===a.enableZoomControls?'':"")+("buttons"===a.enableZoomControls?'
    ':"")+("slider"===a.enableGridControls?'':"")+("buttons"===a.enableGridControls?'
    ':"")+("slider"===a.enableZoomControls?'
    Zoom level: '+a.zoomLevel+"
    ":"")+("buttons"===a.enableZoomControls?'
    Zoom level: '+a.zoomLevel+"
    ":"")+("slider"===a.enableGridControls?'
    Pages per row: '+a.pagesPerRow+"
    ":"")+("buttons"===a.enableGridControls?'
    Pages per row: '+a.pagesPerRow+"
    ":"")+'
    '+(a.enableFullscreen?'
    ':"")+(a.enableLinkIcon?'':"")+(a.enableGridIcon?'
    ':"")+'
    '+(a.enableGotoPage?'
    ':"")+('
    Page 1 of '+a.numPages+"
    ")+"
    ")+"");b(a.selector+"zoom-slider").on("input",function(a){a=parseInt(this.value,10);O(a)});b(a.selector+"zoom-slider").on("change",function(c){c=parseInt(this.value,10);c!==a.zoomLevel&&O(c)});b(a.selector+"zoom-out-button").click(function(){O(a.zoomLevel+-1)});b(a.selector+"zoom-in-button").click(function(){O(a.zoomLevel+1)});b(a.selector+"grid-slider").on("input",function(a){a=parseInt(this.value, -10);Z(a)});b(a.selector+"grid-slider").on("change",function(c){c=parseInt(this.value,10);c!==a.zoomLevel&&Z(c)});b(a.selector+"fullscreen").click(function(){B()});b(a.selector+"grid-out-button").click(function(){Z(a.pagesPerRow-1)});b(a.selector+"grid-in-button").click(function(){Z(a.pagesPerRow+1)});b(a.selector+"grid-icon").click(function(){C()});b(a.selector+"goto-page").submit(function(){var c=parseInt(b(a.selector+"goto-page-input").val(),10)-1;if(t(c))if(a.inGrid)ga(c);else{var d=U(c,"top"), -e=V(c,"center");M(c,d,e)}else alert("Invalid page number");return!1});b(a.selector+"link-icon").click(function(){b("body").prepend('');if(a.inFullscreen)b(a.selector+"link-popup").addClass("in-fullscreen");else{var c=a.outerObject.offset().left+a.panelWidth,c=c+(a.scrollbarWidth-240-1),d=a.outerObject.offset().top+1;b(a.selector+"link-popup").removeClass("in-fullscreen").css({top:d+ -"px",left:c+"px"})}b("body").mouseup(function(c){c=c.target.id;c!==a.ID+"link-popup"&&c!==a.ID+"link-popup-input"&&b(a.selector+"link-popup").remove()});a.outerObject.scroll(function(){b(a.selector+"link-popup").remove()});b(a.selector+"link-popup input").click(function(){b(this).focus().select()});return!1});var c=a.inGrid?"grid":"zoom";b(a.selector+c+"-slider").show();b(a.selector+c+"-out-button").show();b(a.selector+c+"-in-button").show();b(a.selector+c+"-slider-label").show();b(a.selector+c+"-buttons-label").show(); -return{updateCurrentPage:function(){document.getElementById(a.ID+"current-page").textContent=a.currentPageIndex+1},setNumPages:function(c){document.getElementById(a.ID+"num-pages").textContent=c},updateZoomSlider:function(){a.zoomLevel!==b(a.selector+"zoom-slider").val()&&b(a.selector+"zoom-slider").val(a.zoomLevel);document.getElementById(a.ID+"zoom-level").textContent=a.zoomLevel},updateZoomButtons:function(){document.getElementById(a.ID+"zoom-level").textContent=a.zoomLevel},updateGridSlider:function(){a.pagesPerRow!== -b(a.selector+"grid-slider").val()&&b(a.selector+"grid-slider").val(a.pagesPerRow);document.getElementById(a.ID+"pages-per-row").textContent=a.pagesPerRow},updateGridButtons:function(){document.getElementById(a.ID+"pages-per-row").textContent=a.pagesPerRow},switchView:function(){b(a.selector+c+"-slider").hide();b(a.selector+c+"-out-button").hide();b(a.selector+c+"-in-button").hide();b(a.selector+c+"-slider-label").hide();b(a.selector+c+"-buttons-label").hide();c=a.inGrid?"grid":"zoom";b(a.selector+ -c+"-slider").show();b(a.selector+c+"-out-button").show();b(a.selector+c+"-in-button").show();b(a.selector+c+"-slider-label").show();b(a.selector+c+"-buttons-label").show();b(a.selector+"grid-icon").toggleClass("diva-in-grid")},switchMode:function(){b(a.selector+"tools").toggleClass("diva-fullscreen-tools");a.inFullscreen?b(a.selector+"tools-left").addClass("in-fullscreen"):b(a.selector+"tools-left").removeClass("in-fullscreen")}}},ta=function(){if(window.divaPlugins){var c=[];b.each(window.divaPlugins, -function(b,d){var e=d.pluginName[0].toUpperCase()+d.pluginName.substring(1);a["enable"+e]&&d.init(a,f)&&(e=d.titleText||e+" plugin","function"===typeof d.handleClick&&(c.push('
    '),a.outerObject.on(a.mobileWebkit?"touchend":"click",".diva-"+d.pluginName+"-icon",function(c){d.handleClick.call(this,c,a,f)})),a.plugins.push(d))});c.length&&(a.pageTools='
    '+c.join("")+"
    ")}},pa=function(){clearTimeout(a.throbberTimeoutID); -b(a.selector+"throbber").hide()},ua=function(){a.outerObject.append('
    ');a.throbberTimeoutID=setTimeout(function(){b(a.selector+"throbber").show()},a.throbberTimeout);b.ajax({url:a.objectData,cache:!0,dataType:"json",error:function(c,b,d){pa();c='

    Error

    Invalid objectData. Error code: '+b+" "+d+"

    ";0===a.objectData.lastIndexOf("http",0)&&""===d&&(d=a.objectData.replace(/https?:\/\//i, -"").split(/[/?#]/)[0],location.hostname!==d&&(c+='

    Attempted to access cross-origin data without CORS.

    You may need to update your server configuration to support CORS. For help, see the cross-site request documentation.

    '));a.outerObject.append(c+"
    ")},success:function(c,d,e){pa();a.pages=c.pgs;a.maxRatio=c.dims.max_ratio;a.minRatio=c.dims.min_ratio;a.itemTitle=c.item_title; -a.numPages=c.pgs.length;a.maxWidths=c.dims.max_w;a.maxHeights=c.dims.max_h;a.averageWidths=c.dims.a_wid;a.averageHeights=c.dims.a_hei;a.totalHeights=c.dims.t_hei;a.totalWidths=c.dims.t_wid;a.realMaxZoom=c.max_zoom;a.maxZoomLevel=0<=a.maxZoomLevel&&a.maxZoomLevel<=c.max_zoom?a.maxZoomLevel:c.max_zoom;a.minZoomLevel=0<=a.minZoomLevel&&a.minZoomLevel<=a.maxZoomLevel?a.minZoomLevel:0;a.zoomLevel=D(a.zoomLevel);a.minPagesPerRow=Math.max(2,a.minPagesPerRow);a.maxPagesPerRow=Math.max(a.minPagesPerRow,a.maxPagesPerRow); -a.enableFilename?(c=b.getHashParam("i"+a.hashParamSuffix),c=s(c)):c=parseInt(b.getHashParam("p"+a.hashParamSuffix),10)-1;t(c)&&(a.goDirectlyTo=c,a.currentPageIndex=c);b.each(a.plugins,function(c,b){g(b.setupHook,a)});a.enableToolbar&&(a.toolbar=sa(),diva.Events.subscribe("VisiblePageDidChange",a.toolbar.updateCurrentPage),diva.Events.subscribe("ModeDidSwitch",a.toolbar.switchMode),diva.Events.subscribe("ViewDidSwitch",a.toolbar.switchView),diva.Events.subscribe("ZoomLevelDidChange",a.toolbar.updateZoomSlider), -diva.Events.subscribe("ZoomLevelDidChange",a.toolbar.updateZoomButtons),diva.Events.subscribe("GridRowNumberDidChange",a.toolbar.updateGridSlider),diva.Events.subscribe("ZoomLevelDidChange",a.toolbar.updateGridButtons));b(a.selector+"current label").text(a.numPages);a.enableAutoTitle&&a.parentObject.prepend('
    '+a.itemTitle+"
    ");a.parentObject.parent()[0]!==document.body||a.parentObject.siblings().not("#diva-canvas-backdrop")[0]||(a.divaIsFullWindow=!0); -T();t(parseInt(a.goDirectlyTo),10)||(a.goDirectlyTo=0);0');a.outerObject=b(a.selector+"outer");a.outerObject.append('
    ');a.innerObject=b(a.selector+"inner");c=parseInt(b.getHashParam("n"+a.hashParamSuffix),10);c>=a.minPagesPerRow&&c<=a.maxPagesPerRow&&(a.pagesPerRow=c);c=b.getHashParam("z"+a.hashParamSuffix); -""!==c&&(c=parseInt(c,10),c>=a.minZoomLevel&&(a.zoomLevel=c));var c=b.getHashParam("g"+a.hashParamSuffix),d="true"===c,e=b.getHashParam("f"+a.hashParamSuffix);a.inGrid=a.inGrid&&"false"!==c||d;a.inFullscreen=a.inFullscreen&&"false"!==e||"true"===e;ua();ta();ra()})();this.getItemTitle=function(){return a.itemTitle};this.gotoPageByNumber=function(a,b,d){a-=1;return t(a)?(M(a,U(a,d),V(a,b)),!0):!1};this.gotoPageByIndex=function(a,b,d){return t(a)?(M(a,U(a,d),V(a,b)),!0):!1};this.getCurrentPage=function(){console.warn("The call to getCurrentPage is deprecated. Use getCurrentPageIndex instead."); -return a.currentPageIndex};this.getNumberOfPages=function(){return da()?a.numPages:!1};this.getPageDimensionsAtZoomLevel=function(c,b){if(!da())return!1;b>a.maxZoomLevel&&(b=a.maxZoomLevel);var d=a.pages[c].d[parseInt(b,10)];return{width:d.w,height:d.h}};this.getCurrentPageDimensionsAtCurrentZoomLevel=function(){return this.getPageDimensionsAtZoomLevel(a.currentPageIndex,a.zoomLevel)};this.isReady=function(){return a.loaded};this.getCurrentPageIndex=function(){return a.currentPageIndex};this.getCurrentPageFilename= -function(){return a.pages[a.currentPageIndex].f};this.getCurrentPageNumber=function(){return a.currentPageIndex+1};this.getFilenames=function(){for(var c=[],b=0;b=a.minZoomLevel&&c.z<=a.maxZoomLevel&&(a.zoomLevel=c.z);c.n>=a.minPagesPerRow&&c.n<=a.maxPagesPerRow&&(a.pagesPerRow=c.n);a.inFullscreen!==c.f? -(a.inFullscreen=c.f,ba(a.inGrid!==c.g),a.horizontalOffset=horizontalOffset,a.verticalOffset=verticalOffset,M(b,a.verticalOffset,a.horizontalOffset)):(a.horizontalOffset=horizontalOffset,a.verticalOffset=verticalOffset,a.inGrid!==c.g?(a.inGrid=c.g,E()):Q())};this.enableScrollable=function(){a.isScrollable||(oa(),a.enableKeyScroll=a.initialKeyScroll,a.enableSpaceScroll=a.initialSpaceScroll,a.outerObject.css("overflow","auto"),a.isScrollable=!0)};this.disableScrollable=function(){a.isScrollable&&(a.innerObject.hasClass("diva-dragger")&& -a.innerObject.unbind("mousedown"),a.outerObject.unbind("dblclick"),a.outerObject.unbind("contextmenu"),a.outerObject.css("overflow","hidden"),a.initialKeyScroll=a.enableKeyScroll,a.initialSpaceScroll=a.enableSpaceScroll,a.enableKeyScroll=!1,a.enableSpaceScroll=!1,a.isScrollable=!1)};this.toggleOrientation=function(){a.verticallyOriented=!a.verticallyOriented;a.verticalOffset=U();a.horizontalOffset=V();a.goDirectlyTo=a.currentPageIndex;aa();return a.verticallyOriented};this.getPageOffset=function(c){return{top:parseInt(a.pageTopOffsets[c]), -left:parseInt(a.pageLeftOffsets[c])}};this.getPageDimensionsAtCurrentGridLevel=function(c){c=t(c)?c:a.currentPageIndex;var b=a.rowHeight-a.fixedPadding;c=a.fixedHeightGrid?(a.rowHeight-a.fixedPadding)*l(c,"w")/l(c,"h"):a.gridPageWidth;return{height:parseInt(b,10),width:parseInt(c,10)}};this.getPageIndexForPageXYValues=function(c,d){var e=b("#"+a.ID+"outer"),f=e.offset(),m=f.top,f=f.left,q=m+e.outerHeight(),k=f+e.outerWidth();if(ck||dq)return!1;for(q=b("div[id^="+a.ID+"page]").length;q--;){var n= -b(b("div[id^="+a.ID+"page]")[q]),k=n.attr("data-index"),g=n.position(),h=n.offset(),l;a.verticallyOriented?(l=g.top-e.scrollTop()+m,g=h.left-e.scrollLeft()+f):(l=h.top-e.scrollTop()+m,g=g.left-e.scrollLeft()+f);h=l+n.outerHeight();n=g+n.outerWidth();if(!(cn||dh))return k}return!1};this.activate=function(){a.isActiveDiva=!0};this.deactivate=function(){a.isActiveDiva=!1};this.destroy=function(){b("body").removeClass("diva-hide-scrollbar");a.parentObject.empty().removeData("diva");b.each(a.plugins, -function(c,b){g(b.destroy,a,f)});a.parentObject.removeAttr("style").removeAttr("class");diva.Events.unsubscribeAll()}};b.fn.diva=function(e){return this.each(function(){e.parentObject=b(this);if(!e.parentObject.data("diva")){var d=new f(this,e);e.parentObject.data("diva",d)}})}})(jQuery);(function(b){window.divaPlugins.push(function(){var f={},e={},d={},a,k,g,l={brightnessMax:150,brightnessMin:-100,brightnessStep:1,contrastMax:3,contrastMin:-1,contrastStep:0.05,localStoragePrefix:"canvas-",mobileWebkitMaxZoom:2,onInit:null,rgbMax:50,rgbMin:-50,throbberFadeSpeed:200,throbberTimeout:100,buttons:["contrast","brightness","rotation","zoom"]},s=function(b,d){var e=b.context,f=b.size/2,k=-(b.width/2),g=-(b.height/2);e.clearRect(0,0,b.size,b.size);e.save();e.translate(f,f);e.rotate(d*Math.PI/ -180);e.drawImage(a,k,g,b.width,b.height);e.restore();b.data=e.getImageData(0,0,b.size,b.size)},u=function(){for(var a in k)if(k[a].current!==k[a].previous)return!0;return!1},p=function(){s(e,k.rotation.current);K(e)},t=function(){var a=k.rotation.current,e=k.zoom.current,g=k.zoom.previous;if(a!==k.rotation.previous||e!==g){var h=b("#diva-canvas-wrapper").scrollLeft(),l=b("#diva-canvas-wrapper").scrollTop(),r=d.viewport.width/2,p=d.viewport.height/2,h=h+r-f.centerX,t=-(l+p-f.centerY),D=(k.rotation.previous- -a)*Math.PI/180,l=Math.cos(D)*h-Math.sin(D)*t+f.centerX,h=-(Math.sin(D)*h+Math.cos(D)*t)+f.centerY,e=Math.pow(2,e-g),r=e*l-r,p=e*h-p;s(f,a);b("#diva-canvas-wrapper").scrollLeft(r);b("#diva-canvas-wrapper").scrollTop(p)}if(u()){K(f);for(var N in k)k[N].previous=k[N].current}},y=function(a){var b=k[a].current!==k[a].initial;return k[a].current!==k[a].previous||b},K=function(a){var b=a.data,e=a.context.createImageData(b),f=e.data,g,h;g=0;for(h=f.length;g";if("SecurityError"!==g.name)throw g;m+='

    You may need to update your server configuration in order to use the image manipulation tools. For help, see the canvas cross-site data documentation.

    '; -b("#diva-canvas-backdrop").append(m);z()}void 0===k&&(m=a,e.canvas=document.getElementById("diva-canvas-minimap"),e.size=d.mapSize,e.canvas.width=e.size,e.canvas.height=e.size,e.context=e.canvas.getContext("2d"),e.context.fillRect(0,0,e.size,e.size),e.scaleFactor=d.mapSize/f.size,e.cornerX=f.cornerX*e.scaleFactor,e.cornerY=f.cornerY*e.scaleFactor,e.width=m.width*e.scaleFactor,e.height=m.height*e.scaleFactor,e.context.drawImage(m,e.cornerX,e.cornerY,e.width,e.height),e.data=e.context.getImageData(0, -0,d.mapSize,d.mapSize),b("#diva-map-viewbox").show(),h());p();t(f);z();"function"===typeof k&&k.call(k)}},I=function(){var a=k[g],d=a.current,a=a.transform?a.transform(d):d;b("#diva-canvas-value").html(a)},r=function(){b("#diva-canvas-slider").val(k[g].current)},x=function(a){a=d.zoomWidthRatio*Math.pow(2,a);return d.proxyURL?d.proxyURL+"?f="+d.filename+"&w="+a:d.iipServerURL+"?FIF="+(d.imageDir+"/")+d.filename+"&WID="+a+"&CVT=JPEG"},v=function(){(0',s.push(w);s='
    '+('
    Test
    '+s.join("")+ -'

    contrast: 0 (Reset)


    ')+'
    ';b("body").append(s); -d.mapSize=b("#diva-canvas-minimap").width();b("#diva-canvas-buttons div").click(function(){b("#diva-canvas-buttons .clicked").removeClass("clicked");y(b(this).attr("class"))});var y=function(a){g=a;a=k[g];b("#diva-canvas-buttons ."+g).addClass("clicked");b("#diva-canvas-mode").text(g);var d=a.current,e=a.transform?a.transform(d):d,f=document.getElementById("diva-canvas-slider");f.min=a.min;f.max=a.max;f.step=a.step;b("#diva-canvas-slider").val(d);b("#diva-canvas-value").html(e)};y("contrast");b("#diva-canvas-slider").on("input", -function(a){k[g].current=parseFloat(this.value);I();p()});b("#diva-canvas-reset-all").click(function(){for(var a in k)k[a].current=k[a].initial;I();r();p()});b("#diva-canvas-reset").click(function(){k[g].current=k[g].initial;I();r();p()});b("#diva-canvas-apply").click(function(){u()&&(v(),setTimeout(function(){k.zoom.current!==k.zoom.previous?A(k.zoom.current):(t(),z(),H())},d.throbberTimeout))});b("#diva-canvas-close").click(function(){b("body").removeClass("overflow-hidden");f.context.clearRect(0, -0,f.size,f.size);e.context.clearRect(0,0,e.size,e.size);b("#diva-canvas-wrapper").scrollTop(0).scrollLeft(0);b("#diva-canvas-backdrop").hide();b("#diva-map-viewbox").hide();z();q.enableScrollable();b(document).off("keydown",J);n();I();r();b("#diva-canvas-buttons .clicked").removeClass("clicked");y("contrast");diva.Events.publish("CanvasViewDidHide")});b("#diva-canvas-minimise").click(function(){b("#diva-canvas-toolwindow").slideToggle("fast")});b(window).resize(function(){d.viewport={height:window.innerHeight- -a.scrollbarWidth,width:window.innerWidth-a.scrollbarWidth};d.inCanvas&&h()});b("#diva-canvas-wrapper").scroll(function(){d.inCanvas&&h()});b("#diva-canvas-minimap, #diva-map-viewbox").mouseup(function(a){var f=b("#diva-canvas-minimap").offset(),g=(a.pageX-f.left)/e.scaleFactor;a=(a.pageY-f.top)/e.scaleFactor;b("#diva-canvas-wrapper").scrollTop(a-d.viewport.height/2);b("#diva-canvas-wrapper").scrollLeft(g-d.viewport.width/2)});b("#diva-canvas").mousedown(function(){b(this).addClass("grabbing")}).mouseup(function(){b(this).removeClass("grabbing")}); -d.mobileWebkit?b("#diva-canvas-wrapper").kinetic():b("#diva-canvas-wrapper").dragscrollable({acceptPropagatedEvent:!0});"function"===typeof d.onInit&&d.onInit.call(this,d);return!0},pluginName:"canvas",titleText:"View the image on a canvas and adjust various settings",setupHook:function(a){d.viewport={height:window.innerHeight-a.scrollbarWidth,width:window.innerWidth-a.scrollbarWidth};d.minZoomLevel=a.minZoomLevel;d.maxZoomLevel=a.maxZoomLevel;d.mobileWebkit&&(d.maxZoomLevel=Math.min(d.maxZoomLevel, -d.mobileWebkitMaxZoom));k.zoom.min=d.minZoomLevel;k.zoom.max=d.maxZoomLevel},handleClick:function(a,e,f){a=b(this).parent().parent();var h=b(a).attr("data-filename"),l=b(a).width()-1;e=e.zoomLevel;var p;d.zoomWidthRatio=l/Math.pow(2,e);d.pluginIcon=b(this);d.mobileWebkit&&(e=Math.min(d.maxZoomLevel,e));d.filename=h;k.zoom.initial=e;k.zoom.current=e;if(h=localStorage.getObject(d.localStoragePrefix+d.filename))for(p in h)k[p].current=h[p],p===g&&(I(),r()),"zoom"===p&&(e=h[p]);k.zoom.previous=e;b("body").addClass("overflow-hidden"); -b("#diva-canvas-backdrop").show();f.disableScrollable();b(document).keydown(J);d.inCanvas=!0;f=x(e);b("#diva-canvas-info").text(b(a).attr("title"));v();diva.Events.publish("CanvasViewDidActivate",[a]);W(f)},onPageLoad:function(a,e,f){null!==localStorage.getItem(d.localStoragePrefix+e)&&b(f).find(".diva-canvas-icon").addClass("new")},destroy:function(a,d){b("#diva-canvas-backdrop").remove()}}}())})(jQuery);(function(b){window.divaPlugins.push(function(){var f,e;return{init:function(b,a){f=b.iipServerURL;e=b.imageDir;return!0},pluginName:"download",titleText:"Download image at the given zoom level",handleClick:function(d){var a=b(this).parent().parent();d=b(a).attr("data-filename");a=b(a).width()-1;window.open(f+"?FIF="+(e+"/")+d+"&WID="+a+"&CVT=JPEG")}}}())})(jQuery);(function(b){window.divaPlugins.push(function(){return{init:function(b,e){function d(a,d,g){var l=b.parentObject.data("highlights");if("undefined"!==typeof l){if(l.hasOwnProperty(a)){d=e.getInstanceId()+"page-"+a;d=document.getElementById(d);g=l[a].regions;var s=l[a].colour,l=l[a].divClass,u=e.getMaxZoomLevel();b.inGrid?(a=e.getPageDimensionsAtZoomLevel(a,u).width,a=Math.log(a/d.clientWidth)/Math.log(2)):a=u-e.getZoomLevel();for(u=g.length;u--;){var p=document.createElement("div");p.style.width=g[u].width/ -Math.pow(2,a)+"px";p.style.height=g[u].height/Math.pow(2,a)+"px";p.style.top=g[u].uly/Math.pow(2,a)+"px";p.style.left=g[u].ulx/Math.pow(2,a)+"px";p.style.background=s;p.style.border="1px solid #555";p.style.position="absolute";p.style.zIndex=100;p.className=l;"undefined"!==typeof g[u].divID&&(p.id=g[u].divID);d.appendChild(p)}}diva.Events.publish("HighlightCompleted")}}b.parentObject.data("highlights",{});diva.Events.subscribe("PageWillLoad",d);e.resetHighlights=function(){for(var a=document.getElementById(b.ID+ -"inner").getElementsByClassName(b.ID+"highlight"),d=a.length;d--;)a[d].parentNode.removeChild(a[d]);b.parentObject.data("highlights",{})};e.removeHighlightsOnPage=function(a){var d=b.parentObject.data("highlights");if(d.hasOwnProperty(a)){for(var g=e.getInstanceId()+"page-"+a,g=document.getElementById(g),l=g.getElementsByTagName("div"),s=d[a].divClass,u=l.length;u--;)l[u].className===s&&g.removeChild(l[u]);delete d[a]}};e.highlightOnPages=function(a,b,d,f){for(var s=a.length;s--;)e.highlightOnPage(a[s], -b,d,f)};e.highlightOnPage=function(a,k,g,l){"undefined"===typeof g&&(g="rgba(255, 0, 0, 0.2)");l="undefined"===typeof l?b.ID+"highlight":b.ID+"highlight "+l;e.getMaxZoomLevel();b.parentObject.data("highlights")[a]={regions:k,colour:g,divClass:l};e.isPageInViewport(a)&&d(a,null,null);return!0};return!0},destroy:function(b,e){b.parentObject.removeData("highlights")},pluginName:"highlight",titleText:"Highlight regions of pages"}}())})(jQuery);(function(b){window.divaPlugins.push(function(){return{init:function(b,e){void 0===b.pageAliases&&(b.pageAliases={});void 0===b.pageAliasFunction&&(b.pageAliasFunction=function(){return!1});e.getAliasForPageIndex=function(d){return b.pageAliases[d]||b.pageAliasFunction(d)||d+1};e.getPageIndexForAlias=function(d){for(var a=0;ab&&(c=b):a<0-b&&(c=0-b);return c},h=function(a,b){this.removeClass(a.movingClass.up).removeClass(a.movingClass.down).removeClass(a.movingClass.left).removeClass(a.movingClass.right).removeClass(a.deceleratingClass.up).removeClass(a.deceleratingClass.down).removeClass(a.deceleratingClass.left).removeClass(a.deceleratingClass.right); +0a.velocity&&this.addClass(b.left);0a.velocityY&&this.addClass(b.up)},g=function(a,b){b.velocity=0;b.velocityY=0;b.decelerate=!0;"function"===typeof b.stopped&&b.stopped.call(a,b)},k=function(a,b){var e=a[0];b.x&&0new Date(I.getTime()+A))I=new Date,z&&(l||x)&&(G&&(b(G).blur(),G=null,g.focus()),m.decelerate=!1,m.velocity=m.velocityY=0,g[0].scrollLeft=m.scrollLeft=m.x?g[0].scrollLeft-(a-l):g[0].scrollLeft, +g[0].scrollTop=m.scrollTop=m.y?g[0].scrollTop-(c-x):g[0].scrollTop,r=l,y=x,l=a,x=c,p(),h.call(g,m,m.movingClass),"function"===typeof m.moved&&m.moved.call(g,m))};m.events={touchStart:function(a){var b;if(w(a.target)){b=a.originalEvent.touches[0];var c=b.clientX;b=b.clientY;z=!0;m.velocity=r=0;m.velocityY=y=0;l=c;x=b;a.stopPropagation()}},touchMove:function(a){var b;z&&(b=a.originalEvent.touches[0],F(b.clientX,b.clientY),a.preventDefault&&a.preventDefault())},inputDown:function(a){if(w(a.target)){var b= +a.clientX,c=a.clientY;z=!0;m.velocity=r=0;m.velocityY=y=0;l=b;x=c;G=a.target;"IMG"===a.target.nodeName&&a.preventDefault();a.stopPropagation()}},inputEnd:function(a){l&&r&&!1===m.decelerate&&(m.decelerate=!0,p(),l=r=z=!1,k(g,m));G=null;a.preventDefault&&a.preventDefault()},inputMove:function(a){z&&(F(a.clientX,a.clientY),a.preventDefault&&a.preventDefault())},scroll:function(a){"function"===typeof m.moved&&m.moved.call(g,m);a.preventDefault&&a.preventDefault()},inputClick:function(a){if(0=e&&d<=f||d<=e&&c>=f||c>=e&&c<=f},r=function(d,c){var e=b("#"+a.ID+"outer").scrollTop()- +a.viewportMargin,f=e+a.panelHeight+2*a.viewportMargin;return d>=e&&d<=f||d<=e&&c>=f||c>=e&&c<=f},q=function(d){return 0<=d&&db},y=function(d,b){0b},F=function(d,b){0d?a.verticallyOriented?0<=c&&a.pageTopOffsets[c]+k(c,"h")+a.verticalPadding>=e&&(p=!0):0<=c&&a.pageLeftOffsets[c]+k(c,"w")+a.horizontalPadding>=e&&(p=!0):0d?0<=c&&(a.rowHeight*b>=g||a.rowHeight*c>=e)&&(p=!0):0=a.minZoomLevel&&d<=a.maxZoomLevel?d:a.minZoomLevel},ha=function(d){return d>=a.minPagesPerRow&&d<=a.maxPagesPerRow?d:a.maxPagesPerRow},ia=function(){a.allTilesLoaded=[];a.outerObject.scrollTop(0);a.innerObject.empty();a.firstPageLoaded=0;a.firstRowLoaded=-1;a.previousTopScroll=0;a.previousLeftScroll=0;for(clearTimeout(a.resizeTimer);a.pageTimeouts.length;)clearTimeout(a.pageTimeouts.pop())},O=function(){a.inGrid?ja():aa()},aa=function(){ia();a.zoomLevel= +t(a.zoomLevel);var d=a.zoomLevel;a.totalHeight=a.totalHeights[d]+a.verticalPadding*(a.numPages+1);a.totalWidth=a.totalWidths[d]+a.horizontalPadding*(a.numPages+1);var b=a.maxHeights[d]+2*a.verticalPadding,c=Math.max(a.maxWidths[d]+2*a.horizontalPadding,a.panelWidth),b=Math.max(b,a.panelHeight),e=document.getElementById(a.ID+"inner");a.verticallyOriented?(e.style.height=Math.round(a.totalHeight)+"px",e.style.width=Math.round(c)+"px"):(e.style.height=Math.round(b)+"px",e.style.width=Math.round(a.totalWidth)+ +"px");var p=0,n=0;a.pageTopOffsets=[];a.pageLeftOffsets=[];for(e=0;ea.firstRowLoaded?b:a.firstRowLoaded,G(b),a.lastRowLoaded=b)},ka=function(a){27==a.keyCode&&C()},ba=function(d){a.outerObject.toggleClass("diva-fullscreen");b("body").toggleClass("diva-hide-scrollbar");a.parentObject.toggleClass("diva-full-width");if(a.mobileWebkit){var c=parseInt(a.outerObject.css("margin-left"),10)-parseInt(b("body").css("margin-left"),10); +a.outerObject.css("margin-left",c)}var c=a.panelHeight,e=a.panelWidth;P();if(0<=a.oldZoomLevel&&!a.inGrid){var p=a.panelHeight,n=a.panelWidth;a.inFullscreen?(a.verticalOffset-=(p-c)/2,a.horizontalOffset-=(n-e)/2):(a.verticalOffset+=(c-p)/2,a.horizontalOffset+=(e-n)/2)}d?(a.inGrid=!a.inGrid,D()):O();if(a.inFullscreen)b(document).on("keyup",ka);else b(document).off("keyup",ka);g(a.onModeToggle,a.inFullscreen);diva.Events.publish("ModeDidSwitch",[a.inFullscreen],f)},D=function(){O();g(a.onViewToggle, +a.inGrid);diva.Events.publish("ViewDidSwitch",[a.inGrid],f)},C=function(){a.goDirectlyTo=a.currentPageIndex;a.inFullscreen=!a.inFullscreen;ba(!1)},E=function(){a.goDirectlyTo=a.currentPageIndex;a.inGrid=!a.inGrid;D()},ca=function(d){var c=b(this).offset();a.doubleClickZoom=!0;a.horizontalOffset=d.pageX-c.left;a.verticalOffset=d.pageY-c.top;a.goDirectlyTo=parseInt(b(this).attr("data-index"),10);L(d.ctrlKey?a.zoomLevel-1:a.zoomLevel+1)},la=function(d){var c=parseInt(b(this).attr("data-index"),10);a.goDirectlyTo= +c;var e=b(this).offset(),c=k(c,"w")/b(this).width();a.horizontalOffset=(d.pageX-e.left)*c;a.verticalOffset=(d.pageY-e.top)*c;a.inGrid=!1;D()},L=function(d){var b=t(d);if(b!==d)return!1;d=Math.pow(2,b-a.zoomLevel);a.doubleClickZoom?(a.verticalOffset*=d,a.horizontalOffset*=d,a.doubleClickZoom=!1):(a.goDirectlyTo=a.currentPageIndex,a.verticalOffset=d*U(),a.horizontalOffset=d*V());a.oldZoomLevel=a.zoomLevel;a.zoomLevel=b;diva.Events.publish("ZoomLevelDidChange",[b],f);aa();return!0},Y=function(d){var b= +ha(d);if(b!==d)return!1;a.pagesPerRow=b;diva.Events.publish("GridRowNumberDidChange",[b],f);a.goDirectlyTo=a.currentPageIndex;ja();return!0},Q=function(d,b){d="undefined"===typeof d?a.currentPageIndex:d;return"center"===b||"centre"===b?parseInt(k(d,"h")/2,10):"bottom"===b?parseInt(k(d,"h")-a.panelHeight/2,10):parseInt(a.panelHeight/2,10)},R=function(d,b){d="undefined"===typeof d?a.currentPageIndex:d;return"left"===b?parseInt(a.panelWidth/2,10):"right"===b?parseInt(k(d,"w")-a.panelWidth/2,10):parseInt(k(d, +"w")/2,10)},U=function(){return document.getElementById(a.ID+"outer").scrollTop-a.pageTopOffsets[a.currentPageIndex]+parseInt(a.panelHeight/2,10)},V=function(){return document.getElementById(a.ID+"outer").scrollLeft-a.pageLeftOffsets[a.currentPageIndex]+parseInt(a.panelWidth/2,10)},ma=function(){return{f:a.inFullscreen,g:a.inGrid,z:a.zoomLevel,n:a.pagesPerRow,i:a.enableFilename?a.pages[a.currentPageIndex].f:!1,p:a.enableFilename?!1:a.currentPageIndex+1,y:a.inGrid?!1:U(),x:a.inGrid?!1:V()}},na=function(){var d= +ma(),b=[],c;for(c in d)!1!==d[c]&&b.push(c+a.hashParamSuffix+"="+d[c]);return b.join("&")},oa=function(){return location.protocol+"//"+location.host+location.pathname+"#"+na()},P=function(){var d=document.getElementById(a.ID+"outer");a.panelHeight=d.clientHeight-(d.scrollWidth>d.clientWidth?a.scrollbarWidth:0);a.panelWidth=d.clientWidth-(d.scrollHeight>d.clientHeight?a.scrollbarWidth:0);a.horizontalOffset=V();a.verticalOffset=U();H(a.currentPageIndex,a.verticalOffset,a.horizontalOffset);return!0}, +pa=function(){a.mobileWebkit||(a.outerObject.dragscrollable({dragSelector:".diva-dragger",acceptPropagatedEvent:!0}),a.innerObject.dragscrollable({dragSelector:".diva-dragger",acceptPropagatedEvent:!0}));a.outerObject.on("dblclick",".diva-document-page",function(a){ca.call(this,a)});a.outerObject.on("contextmenu",".diva-document-page",function(d){if(d.ctrlKey)return clearTimeout(a.singleClickTimeout),a.singleClick?(ca.call(this,d),a.singleClick=!1):(a.singleClick=!0,a.singleClickTimeout=setTimeout(function(){a.singleClick= +!1},500)),!1});a.outerObject.on("dblclick",".diva-row",function(a){la.call(b(a.target).parent(),a)})},da=function(a,b,c,e){return Math.sqrt((a-b)*(a-b)+(c-e)*(c-e))},sa=function(){a.innerObject.mouseover(function(){b(this).removeClass("diva-grabbing").addClass("diva-grab")});a.innerObject.mouseout(function(){b(this).removeClass("diva-grab")});a.innerObject.mousedown(function(){b(this).removeClass("diva-grab").addClass("diva-grabbing")});a.innerObject.mouseup(function(){b(this).removeClass("diva-grabbing").addClass("diva-grab")}); +pa();a.outerObject.scroll(function(){var b,d=document.getElementById(a.ID+"outer").scrollTop,c=document.getElementById(a.ID+"outer").scrollLeft;b=a.verticallyOriented||a.inGrid?d-a.previousTopScroll:c-a.previousLeftScroll;if(a.inGrid){0>b?(F(a.firstRowLoaded,-1),N(-1),n(a.lastRowLoaded,-1)):0b)y(a.firstPageLoaded,b),M(-1),z(a.lastPageLoaded,b);else if(0b&&(g(a.onScrollUp,e),diva.Events.publish("ViewerDidScrollUp",[e],f));a.previousTopScroll=d;a.previousLeftScroll=c;a.horizontalOffset=V(); +a.verticalOffset=U()});b(document).keydown(function(b){if(!a.isActiveDiva)return!0;if(a.enableSpaceScroll&&!b.shiftKey&&32===b.keyCode||a.enableKeyScroll&&34===b.keyCode)return a.outerObject.scrollTop(document.getElementById(a.ID+"outer").scrollTop+a.panelHeight),!1;a.enableSpaceScroll||32!==b.keyCode||b.preventDefault();if(a.enableKeyScroll)switch(b.keyCode){case 33:return a.outerObject.scrollTop(document.getElementById(a.ID+"outer").scrollTop-a.panelHeight),!1;case 38:return a.outerObject.scrollTop(document.getElementById(a.ID+ +"outer").scrollTop-a.arrowScrollAmount),!1;case 40:return a.outerObject.scrollTop(document.getElementById(a.ID+"outer").scrollTop+a.arrowScrollAmount),!1;case 37:return a.outerObject.scrollLeft(document.getElementById(a.ID+"outer").scrollLeft-a.arrowScrollAmount),!1;case 39:return a.outerObject.scrollLeft(document.getElementById(a.ID+"outer").scrollLeft+a.arrowScrollAmount),!1;case 36:return a.outerObject.scrollTop(0),!1;case 35:return a.outerObject.scrollTop(a.totalHeight),!1}return!0});if(a.mobileWebkit){var d= +[];d.push('');d.push('');d.push('');b("head").append(d.join("\n"));a.blockMobileMove&&b("body").bind("touchmove",function(a){a.originalEvent.preventDefault();return!1});a.outerObject.kinetic({triggerHardware:!0});var c=[],e=[],p=0;a.outerObject.on("touchstart",".diva-document-page", +function(a){2===a.originalEvent.touches.length&&(c=[a.originalEvent.touches[0].clientX,a.originalEvent.touches[0].clientY,a.originalEvent.touches[1].clientX,a.originalEvent.touches[1].clientY],p=da(c[2],c[0],c[3],c[1]))});a.outerObject.on("touchmove",".diva-document-page",function(d){if(2===d.originalEvent.touches.length){e=[d.originalEvent.touches[0].clientX,d.originalEvent.touches[0].clientY,d.originalEvent.touches[1].clientX,d.originalEvent.touches[1].clientY];var c=da(e[2],e[0],e[3],e[1])-p;if(!a.scaleWait)if(a.goDirectlyTo= +a.currentPageIndex,a.inGrid)a.inGrid=!1,D();else a:{var f=a.zoomLevel;if(100c&&f>a.minZoomLevel)f--;else break a;a.scaleWait=!0;c=b(this).offset();a.horizontalOffset=d.pageX-c.left;a.verticalOffset=d.pageY-c.top;a.goDirectlyTo=parseInt(b(this).attr("data-index"),10);L(f)}}});var w={},l=0,d=function(d){if(a.singleTap){var c={pageX:d.originalEvent.changedTouches[0].clientX,pageY:d.originalEvent.changedTouches[0].clientY};l=da(w.pageX,c.pageX,w.pageY,c.pageY);50> +l&&a.zoomLevel'+('
    '+ +("slider"===a.enableZoomControls?'':"")+("buttons"===a.enableZoomControls?'
    ':"")+("slider"===a.enableGridControls?'':"")+("buttons"===a.enableGridControls?'
    ':"")+("slider"===a.enableZoomControls?'
    Zoom level: '+a.zoomLevel+"
    ":"")+("buttons"===a.enableZoomControls? +'
    Zoom level: '+a.zoomLevel+"
    ":"")+("slider"===a.enableGridControls?'
    Pages per row: '+a.pagesPerRow+"
    ":"")+("buttons"===a.enableGridControls?'
    Pages per row: '+a.pagesPerRow+"
    ":"")+ +'
    '+(a.enableFullscreen?'
    ':"")+(a.enableLinkIcon?'':"")+(a.enableGridIcon?'
    ': +"")+'
    '+(a.enableGotoPage?'
    ':"")+('
    Page 1 of '+a.numPages+"
    ")+"
    ")+"");b(a.selector+"zoom-slider").on("input",function(a){a=parseInt(this.value, +10);L(a)});b(a.selector+"zoom-slider").on("change",function(b){b=parseInt(this.value,10);b!==a.zoomLevel&&L(b)});b(a.selector+"zoom-out-button").click(function(){L(a.zoomLevel+-1)});b(a.selector+"zoom-in-button").click(function(){L(a.zoomLevel+1)});b(a.selector+"grid-slider").on("input",function(a){a=parseInt(this.value,10);Y(a)});b(a.selector+"grid-slider").on("change",function(b){b=parseInt(this.value,10);b!==a.zoomLevel&&Y(b)});b(a.selector+"fullscreen").click(function(){C()});b(a.selector+"grid-out-button").click(function(){Y(a.pagesPerRow- +1)});b(a.selector+"grid-in-button").click(function(){Y(a.pagesPerRow+1)});b(a.selector+"grid-icon").click(function(){E()});b(a.selector+"goto-page").submit(function(){var d=parseInt(b(a.selector+"goto-page-input").val(),10)-1;if(q(d))if(a.inGrid)B(d);else{var c=Q(d,"top"),e=R(d,"center");H(d,c,e)}else alert("Invalid page number");return!1});var d=b(a.selector+"link-icon");d.click(function(){b("body").prepend('');if(a.inFullscreen)b(a.selector+"link-popup").addClass("in-fullscreen");else{var c=d.offset().left-222+d.outerWidth(),e=d.offset().top+d.outerHeight()-1;b(a.selector+"link-popup").removeClass("in-fullscreen").css({top:e+"px",left:c+"px"})}b("body").mouseup(function(d){d=d.target.id;d!==a.ID+"link-popup"&&d!==a.ID+"link-popup-input"&&b(a.selector+"link-popup").remove()});a.outerObject.scroll(function(){b(a.selector+"link-popup").remove()});b(a.selector+"link-popup input").click(function(){b(this).focus().select()}); +return!1});var c=a.inGrid?"grid":"zoom";b(a.selector+c+"-slider").show();b(a.selector+c+"-out-button").show();b(a.selector+c+"-in-button").show();b(a.selector+c+"-slider-label").show();b(a.selector+c+"-buttons-label").show();return{updateCurrentPage:function(){document.getElementById(a.ID+"current-page").textContent=a.currentPageIndex+1},setNumPages:function(b){document.getElementById(a.ID+"num-pages").textContent=b},updateZoomSlider:function(){a.zoomLevel!==b(a.selector+"zoom-slider").val()&&b(a.selector+ +"zoom-slider").val(a.zoomLevel);document.getElementById(a.ID+"zoom-level").textContent=a.zoomLevel},updateZoomButtons:function(){document.getElementById(a.ID+"zoom-level").textContent=a.zoomLevel},updateGridSlider:function(){a.pagesPerRow!==b(a.selector+"grid-slider").val()&&b(a.selector+"grid-slider").val(a.pagesPerRow);document.getElementById(a.ID+"pages-per-row").textContent=a.pagesPerRow},updateGridButtons:function(){document.getElementById(a.ID+"pages-per-row").textContent=a.pagesPerRow},closePopups:function(){b(".diva-popup").css("display", +"none")},switchView:function(){b(a.selector+c+"-slider").hide();b(a.selector+c+"-out-button").hide();b(a.selector+c+"-in-button").hide();b(a.selector+c+"-slider-label").hide();b(a.selector+c+"-buttons-label").hide();c=a.inGrid?"grid":"zoom";b(a.selector+c+"-slider").show();b(a.selector+c+"-out-button").show();b(a.selector+c+"-in-button").show();b(a.selector+c+"-slider-label").show();b(a.selector+c+"-buttons-label").show();b(a.selector+"grid-icon").toggleClass("diva-in-grid")},switchMode:function(){b(a.selector+ +"tools").toggleClass("diva-fullscreen-tools");a.inFullscreen?b(a.selector+"tools-left").addClass("in-fullscreen"):b(a.selector+"tools-left").removeClass("in-fullscreen")}}},ua=function(){if(window.divaPlugins){var d=[];b.each(window.divaPlugins,function(b,c){var e=c.pluginName[0].toUpperCase()+c.pluginName.substring(1);a["enable"+e]&&c.init(a,f)&&(e=c.titleText||e+" plugin","function"===typeof c.handleClick&&(d.push('
    '),a.outerObject.on(a.mobileWebkit? +"touchend":"click",".diva-"+c.pluginName+"-icon",function(b){c.handleClick.call(this,b,a,f)})),a.plugins.push(c))});d.length&&(a.pageTools='
    '+d.join("")+"
    ")}},qa=function(){clearTimeout(a.throbberTimeoutID);b(a.selector+"throbber").hide()},va=function(){a.outerObject.append('
    ');a.throbberTimeoutID=setTimeout(function(){b(a.selector+"throbber").show()},a.throbberTimeout);b.ajax({url:a.objectData,cache:!0,dataType:"json", +error:function(b,c,e){qa();b='

    Error

    Invalid objectData. Error code: '+c+" "+e+"

    ";0===a.objectData.lastIndexOf("http",0)&&""===e&&(e=a.objectData.replace(/https?:\/\//i,"").split(/[/?#]/)[0],location.hostname!==e&&(b+='

    Attempted to access cross-origin data without CORS.

    You may need to update your server configuration to support CORS. For help, see the cross-site request documentation.

    ')); +a.outerObject.append(b+"
    ")},success:function(d,c,e){qa();a.pages=d.pgs;a.maxRatio=d.dims.max_ratio;a.minRatio=d.dims.min_ratio;a.itemTitle=d.item_title;a.numPages=d.pgs.length;a.maxWidths=d.dims.max_w;a.maxHeights=d.dims.max_h;a.averageWidths=d.dims.a_wid;a.averageHeights=d.dims.a_hei;a.totalHeights=d.dims.t_hei;a.totalWidths=d.dims.t_wid;a.realMaxZoom=d.max_zoom;a.maxZoomLevel=0<=a.maxZoomLevel&&a.maxZoomLevel<=d.max_zoom?a.maxZoomLevel:d.max_zoom;a.minZoomLevel=0<=a.minZoomLevel&&a.minZoomLevel<= +a.maxZoomLevel?a.minZoomLevel:0;a.zoomLevel=t(a.zoomLevel);a.minPagesPerRow=Math.max(2,a.minPagesPerRow);a.maxPagesPerRow=Math.max(a.minPagesPerRow,a.maxPagesPerRow);a.enableFilename?(d=b.getHashParam("i"+a.hashParamSuffix),d=l(d)):d=parseInt(b.getHashParam("p"+a.hashParamSuffix),10)-1;q(d)&&(a.goDirectlyTo=d,a.currentPageIndex=d);b.each(a.plugins,function(b,d){g(d.setupHook,a)});a.enableToolbar&&(a.toolbar=ta(),diva.Events.subscribe("VisiblePageDidChange",a.toolbar.updateCurrentPage),diva.Events.subscribe("ModeDidSwitch", +a.toolbar.switchMode),diva.Events.subscribe("ViewDidSwitch",a.toolbar.switchView),diva.Events.subscribe("ZoomLevelDidChange",a.toolbar.updateZoomSlider),diva.Events.subscribe("ZoomLevelDidChange",a.toolbar.updateZoomButtons),diva.Events.subscribe("GridRowNumberDidChange",a.toolbar.updateGridSlider),diva.Events.subscribe("ZoomLevelDidChange",a.toolbar.updateGridButtons));b(a.selector+"current label").text(a.numPages);a.enableAutoTitle&&a.parentObject.prepend('
    '+ +a.itemTitle+"
    ");a.parentObject.parent()[0]!==document.body||a.parentObject.siblings().not("#diva-canvas-backdrop")[0]||(a.divaIsFullWindow=!0);P();q(parseInt(a.goDirectlyTo),10)||(a.goDirectlyTo=0);0');a.outerObject=b(a.selector+"outer");a.outerObject.append('
    ');a.innerObject=b(a.selector+"inner");d=parseInt(b.getHashParam("n"+a.hashParamSuffix),10);d>=a.minPagesPerRow&& +d<=a.maxPagesPerRow&&(a.pagesPerRow=d);d=b.getHashParam("z"+a.hashParamSuffix);""!==d&&(d=parseInt(d,10),d>=a.minZoomLevel&&(a.zoomLevel=d));var d=b.getHashParam("g"+a.hashParamSuffix),c="true"===d,e=b.getHashParam("f"+a.hashParamSuffix);a.inGrid=a.inGrid&&"false"!==d||c;a.inFullscreen=a.inFullscreen&&"false"!==e||"true"===e;va();ua();sa()})();this.getItemTitle=function(){return a.itemTitle};this.gotoPageByNumber=function(a,b,c){a-=1;return q(a)?(H(a,Q(a,c),R(a,b)),!0):!1};this.gotoPageByIndex=function(a, +b,c){return q(a)?(H(a,Q(a,c),R(a,b)),!0):!1};this.getCurrentPage=function(){console.warn("The call to getCurrentPage is deprecated. Use getCurrentPageIndex instead.");return a.currentPageIndex};this.getNumberOfPages=function(){return ea()?a.numPages:!1};this.getPageDimensionsAtZoomLevel=function(b,c){if(!ea())return!1;c>a.maxZoomLevel&&(c=a.maxZoomLevel);var e=a.pages[b].d[parseInt(c,10)];return{width:e.w,height:e.h}};this.getCurrentPageDimensionsAtCurrentZoomLevel=function(){return this.getPageDimensionsAtZoomLevel(a.currentPageIndex, +a.zoomLevel)};this.isReady=function(){return a.loaded};this.getCurrentPageIndex=function(){return a.currentPageIndex};this.getCurrentPageFilename=function(){return a.pages[a.currentPageIndex].f};this.getCurrentPageNumber=function(){return a.currentPageIndex+1};this.getFilenames=function(){for(var b=[],c=0;c=a.minZoomLevel&&b.z<=a.maxZoomLevel&&(a.zoomLevel=b.z);b.n>=a.minPagesPerRow&&b.n<=a.maxPagesPerRow&&(a.pagesPerRow=b.n);a.inFullscreen!==b.f?(a.inFullscreen=b.f,ba(a.inGrid!==b.g),a.horizontalOffset=horizontalOffset,a.verticalOffset=verticalOffset,H(c,a.verticalOffset,a.horizontalOffset)):(a.horizontalOffset=horizontalOffset,a.verticalOffset=verticalOffset,a.inGrid!==b.g?(a.inGrid=b.g,D()):O())};this.enableScrollable=function(){a.isScrollable|| +(pa(),a.enableKeyScroll=a.initialKeyScroll,a.enableSpaceScroll=a.initialSpaceScroll,a.outerObject.css("overflow","auto"),a.isScrollable=!0)};this.disableScrollable=function(){a.isScrollable&&(a.innerObject.hasClass("diva-dragger")&&a.innerObject.unbind("mousedown"),a.outerObject.unbind("dblclick"),a.outerObject.unbind("contextmenu"),a.outerObject.css("overflow","hidden"),a.initialKeyScroll=a.enableKeyScroll,a.initialSpaceScroll=a.enableSpaceScroll,a.enableKeyScroll=!1,a.enableSpaceScroll=!1,a.isScrollable= +!1)};this.toggleOrientation=function(){a.verticallyOriented=!a.verticallyOriented;a.verticalOffset=Q();a.horizontalOffset=R();a.goDirectlyTo=a.currentPageIndex;aa();return a.verticallyOriented};this.getPageOffset=function(b){return{top:parseInt(a.pageTopOffsets[b]),left:parseInt(a.pageLeftOffsets[b])}};this.getCurrentPageOffset=function(){return this.getPageOffset(a.currentPageIndex)};this.getPageDimensionsAtCurrentGridLevel=function(b){b=q(b)?b:a.currentPageIndex;var c=a.rowHeight-a.fixedPadding; +b=a.fixedHeightGrid?(a.rowHeight-a.fixedPadding)*k(b,"w")/k(b,"h"):a.gridPageWidth;return{height:parseInt(c,10),width:parseInt(b,10)}};this.getPageIndexForPageXYValues=function(b,c){var e=document.getElementById(a.ID+"outer").getBoundingClientRect(),f=e.bottom,p=e.right;if(bp||cf)return!1;e=document.getElementsByClassName("diva-document-page");for(f=e.length;f--;){var p=e[f],g=p.getBoundingClientRect();if(!(bg.right||cg.bottom))return p.getAttribute("data-index")}return!1}; +this.isVerticallyOriented=function(){return a.verticallyOriented};this.activate=function(){a.isActiveDiva=!0};this.deactivate=function(){a.isActiveDiva=!1};this.destroy=function(){b("body").removeClass("diva-hide-scrollbar");a.parentObject.empty().removeData("diva");b.each(a.plugins,function(b,c){g(c.destroy,a,f)});a.parentObject.removeAttr("style").removeAttr("class");diva.Events.unsubscribeAll()}};b.fn.diva=function(e){return this.each(function(){e.parentObject=b(this);if(!e.parentObject.data("diva")){var c= +new f(this,e);e.parentObject.data("diva",c)}})}})(jQuery);(function(b){window.divaPlugins.push(function(){var f={};return{init:function(e,c){var a,h,g,k,l;c.startScrolling=function(){e.currentlyAutoScrolling?console.warn("You are trying to start autoscrolling, but it is already scrolling."):(b("#"+e.ID+"autoscroll-toggle").text("Turn off"),h&&c.disableScrollable(),e.currentlyAutoScrolling=!0,restartScrollingInterval())};restartScrollingInterval=function(){clearInterval(e.autoScrollInterval);e.autoScrollInterval=e.verticallyOriented?setInterval(function(){e.outerObject.scrollTop(e.outerObject.scrollTop()+ +a)},g):setInterval(function(){e.outerObject.scrollLeft(e.outerObject.scrollLeft()+a)},g)};c.stopScrolling=function(){e.currentlyAutoScrolling?(b("#"+e.ID+"autoscroll-toggle").text("Turn on"),h&&c.enableScrollable(),e.currentlyAutoScrolling=!1,clearInterval(e.autoScrollInterval)):console.warn("You are trying to stop autoscrolling, but it is not currently active.")};c.toggleScrolling=function(){e.currentlyAutoScrolling?c.stopScrolling():c.startScrolling()};c.changeRefresh=function(a){g=a;u()};c.changeScrollSpeed= +function(a){l=a;u();b("#"+e.ID+"autoscroll-pps").val(Math.log(l)/Math.log(10));e.currentlyAutoScrolling&&restartScrollingInterval()};var u=function(){g=k;a=l/(1E3/g);1>a&&(g*=1/a,a=l/(1E3/g))};c.disableManualScroll=function(){h=!0;e.currentlyAutoScrolling&&c.disableScrollable()};c.enableManualScroll=function(){h=!1;e.currentlyAutoScrolling&&c.enableScrollable()};e.currentlyAutoScrolling=!1;e.autoScrollInterval="";h=e.disableManualScroll||!1;k=g=e.autoScrollRefresh||50;c.changeScrollSpeed(e.scrollSpeed|| +10);b(window).on("keyup",function(a){a.shiftKey&&32===a.keyCode&&c.toggleScrolling()});if(!e.disableAutoscrollPrefs){var r=function(a){if(e.inFullscreen){a=b(e.selector+"tools");var c=a.css("right");f.jqObj.css({right:c,"margin-right":0,top:a.offset().top+a.outerHeight()+15})}else f.jqObj.css({right:b(window).width()-(e.outerObject.offset().left+e.outerObject.outerWidth())+e.scrollbarWidth,"margin-right":".6em"}),f.jqObj.offset({top:e.outerObject.offset().top+1})};diva.Events.subscribe("ModeDidSwitch", +r);diva.Events.subscribe("ViewerDidLoad",function(a){a="
    Autoscrolling options:
    Speed:
    Allow manual scroll:
    ";b("#"+e.ID+"page-nav").before("
    ");b("body").prepend(a);b("#"+e.ID+"autoscroll-pps").on("change",function(a){c.changeScrollSpeed(Math.pow(10,a.target.value))});b("#"+e.ID+"autoscroll-manual").on("change",function(a){a.target.checked?c.enableManualScroll():c.disableManualScroll()}); +b("#"+e.ID+"autoscroll-toggle").on("click",c.toggleScrolling);b("#"+e.ID+"autoscroll-icon").on("click",function(a){f.jqObj=b("#"+e.ID+"autoscroll-prefs");"none"===f.jqObj.css("display")?(f.jqObj.css({display:"block"}),r(e.inFullscreen)):f.jqObj.css("display","none")})})}},pluginName:"autoscroll",titleText:"Automatically scrolls page along primary axis"}}())})(jQuery);(function(b){window.divaPlugins.push(function(){var f={},e={},c={},a,h,g,k={brightnessMax:150,brightnessMin:-100,brightnessStep:1,contrastMax:3,contrastMin:-1,contrastStep:0.05,localStoragePrefix:"canvas-",mobileWebkitMaxZoom:2,onInit:null,rgbMax:50,rgbMin:-50,throbberFadeSpeed:200,throbberTimeout:100,buttons:["contrast","brightness","rotation","zoom"]},l=function(b,c){var e=b.context,f=b.size/2,g=-(b.width/2),h=-(b.height/2);e.clearRect(0,0,b.size,b.size);e.save();e.translate(f,f);e.rotate(c*Math.PI/ +180);e.drawImage(a,g,h,b.width,b.height);e.restore();b.data=e.getImageData(0,0,b.size,b.size)},u=function(){for(var a in h)if(h[a].current!==h[a].previous)return!0;return!1},r=function(){l(e,h.rotation.current);v(e)},q=function(){var a=h.rotation.current,e=h.zoom.current,g=h.zoom.previous;if(a!==h.rotation.previous||e!==g){var n=b("#diva-canvas-wrapper").scrollLeft(),k=b("#diva-canvas-wrapper").scrollTop(),m=c.viewport.width/2,q=c.viewport.height/2,n=n+m-f.centerX,r=-(k+q-f.centerY),B=(h.rotation.previous- +a)*Math.PI/180,k=Math.cos(B)*n-Math.sin(B)*r+f.centerX,n=-(Math.sin(B)*n+Math.cos(B)*r)+f.centerY,e=Math.pow(2,e-g),m=e*k-m,q=e*n-q;l(f,a);b("#diva-canvas-wrapper").scrollLeft(m);b("#diva-canvas-wrapper").scrollTop(q)}if(u()){v(f);for(var t in h)h[t].previous=h[t].current}},s=function(a){var b=h[a].current!==h[a].initial;return h[a].current!==h[a].previous||b},v=function(a){var b=a.data,e=a.context.createImageData(b),f=e.data,g,k;g=0;for(k=f.length;g";if("SecurityError"!==g.name)throw g;p+='

    You may need to update your server configuration in order to use the image manipulation tools. For help, see the canvas cross-site data documentation.

    '; +b("#diva-canvas-backdrop").append(p);A()}void 0===h&&(p=a,e.canvas=document.getElementById("diva-canvas-minimap"),e.size=c.mapSize,e.canvas.width=e.size,e.canvas.height=e.size,e.context=e.canvas.getContext("2d"),e.context.fillRect(0,0,e.size,e.size),e.scaleFactor=c.mapSize/f.size,e.cornerX=f.cornerX*e.scaleFactor,e.cornerY=f.cornerY*e.scaleFactor,e.width=p.width*e.scaleFactor,e.height=p.height*e.scaleFactor,e.context.drawImage(p,e.cornerX,e.cornerY,e.width,e.height),e.data=e.context.getImageData(0, +0,c.mapSize,c.mapSize),b("#diva-map-viewbox").show(),m());r();q(f);A();"function"===typeof h&&h.call(h)}},J=function(){var a=h[g],c=a.current,a=a.transform?a.transform(c):c;b("#diva-canvas-value").html(a)},x=function(){b("#diva-canvas-slider").val(h[g].current)},y=function(a){a=c.zoomWidthRatio*Math.pow(2,a);return c.proxyURL?c.proxyURL+"?f="+c.filename+"&w="+a:c.iipServerURL+"?FIF="+(c.imageDir+"/")+c.filename+"&WID="+a+"&CVT=JPEG"},z=function(){(0',n.push(s);n='
    '+('
    Test
    '+n.join("")+ +'

    contrast: 0 (Reset)


    ')+'
    ';b("body").append(n); +c.mapSize=b("#diva-canvas-minimap").width();b("#diva-canvas-buttons div").click(function(){b("#diva-canvas-buttons .clicked").removeClass("clicked");H(b(this).attr("class"))});var H=function(a){g=a;a=h[g];b("#diva-canvas-buttons ."+g).addClass("clicked");b("#diva-canvas-mode").text(g);var c=a.current,e=a.transform?a.transform(c):c,f=document.getElementById("diva-canvas-slider");f.min=a.min;f.max=a.max;f.step=a.step;b("#diva-canvas-slider").val(c);b("#diva-canvas-value").html(e)};H("contrast");b("#diva-canvas-slider").on("input", +function(a){h[g].current=parseFloat(this.value);J();r()});b("#diva-canvas-reset-all").click(function(){for(var a in h)h[a].current=h[a].initial;J();x();r()});b("#diva-canvas-reset").click(function(){h[g].current=h[g].initial;J();x();r()});b("#diva-canvas-apply").click(function(){u()&&(z(),setTimeout(function(){h.zoom.current!==h.zoom.previous?G(h.zoom.current):(q(),A(),I())},c.throbberTimeout))});b("#diva-canvas-close").click(function(){b("body").removeClass("overflow-hidden");f.context.clearRect(0, +0,f.size,f.size);e.context.clearRect(0,0,e.size,e.size);b("#diva-canvas-wrapper").scrollTop(0).scrollLeft(0);b("#diva-canvas-backdrop").hide();b("#diva-map-viewbox").hide();A();l.enableScrollable();b(document).off("keydown",K);v();J();x();b("#diva-canvas-buttons .clicked").removeClass("clicked");H("contrast");diva.Events.publish("CanvasViewDidHide")});b("#diva-canvas-minimise").click(function(){b("#diva-canvas-toolwindow").slideToggle("fast")});b(window).resize(function(){c.viewport={height:window.innerHeight- +a.scrollbarWidth,width:window.innerWidth-a.scrollbarWidth};c.inCanvas&&m()});b("#diva-canvas-wrapper").scroll(function(){c.inCanvas&&m()});b("#diva-canvas-minimap, #diva-map-viewbox").mouseup(function(a){var f=b("#diva-canvas-minimap").offset(),g=(a.pageX-f.left)/e.scaleFactor;a=(a.pageY-f.top)/e.scaleFactor;b("#diva-canvas-wrapper").scrollTop(a-c.viewport.height/2);b("#diva-canvas-wrapper").scrollLeft(g-c.viewport.width/2)});b("#diva-canvas").mousedown(function(){b(this).addClass("grabbing")}).mouseup(function(){b(this).removeClass("grabbing")}); +c.mobileWebkit?b("#diva-canvas-wrapper").kinetic():b("#diva-canvas-wrapper").dragscrollable({acceptPropagatedEvent:!0});"function"===typeof c.onInit&&c.onInit.call(this,c);return!0},pluginName:"canvas",titleText:"View the image on a canvas and adjust various settings",setupHook:function(a){c.viewport={height:window.innerHeight-a.scrollbarWidth,width:window.innerWidth-a.scrollbarWidth};c.minZoomLevel=a.minZoomLevel;c.maxZoomLevel=a.maxZoomLevel;c.mobileWebkit&&(c.maxZoomLevel=Math.min(c.maxZoomLevel, +c.mobileWebkitMaxZoom));h.zoom.min=c.minZoomLevel;h.zoom.max=c.maxZoomLevel},handleClick:function(a,e,f){a=b(this).parent().parent();var k=b(a).attr("data-filename"),l=b(a).width()-1;e=e.zoomLevel;var m;c.zoomWidthRatio=l/Math.pow(2,e);c.pluginIcon=b(this);c.mobileWebkit&&(e=Math.min(c.maxZoomLevel,e));c.filename=k;h.zoom.initial=e;h.zoom.current=e;if(k=localStorage.getObject(c.localStoragePrefix+c.filename))for(m in k)h[m].current=k[m],m===g&&(J(),x()),"zoom"===m&&(e=k[m]);h.zoom.previous=e;b("body").addClass("overflow-hidden"); +b("#diva-canvas-backdrop").show();f.disableScrollable();b(document).keydown(K);c.inCanvas=!0;f=y(e);b("#diva-canvas-info").text(b(a).attr("title"));z();diva.Events.publish("CanvasViewDidActivate",[a]);S(f)},onPageLoad:function(a,e,f){null!==localStorage.getItem(c.localStoragePrefix+e)&&b(f).find(".diva-canvas-icon").addClass("new")},destroy:function(a,c){b("#diva-canvas-backdrop").remove()}}}())})(jQuery);(function(b){window.divaPlugins.push(function(){var f,e;return{init:function(b,a){f=b.iipServerURL;e=b.imageDir;return!0},pluginName:"download",titleText:"Download image at the given zoom level",handleClick:function(c){var a=b(this).parent().parent();c=b(a).attr("data-filename");a=b(a).width()-1;window.open(f+"?FIF="+(e+"/")+c+"&WID="+a+"&CVT=JPEG")}}}())})(jQuery);(function(b){window.divaPlugins.push(function(){return{init:function(b,e){function c(a,c,g){var k=b.parentObject.data("highlights");if("undefined"!==typeof k){if(k.hasOwnProperty(a)){var l=e.getInstanceId()+"page-"+a,l=document.getElementById(l),u=k[a].regions,r=k[a].colour,k=k[a].divClass,q=e.getMaxZoomLevel();b.inGrid?(q=e.getPageDimensionsAtZoomLevel(a,q).width,q=Math.log(q/l.clientWidth)/Math.log(2)):q-=e.getZoomLevel();for(var s=u.length;s--;){var v=document.createElement("div");v.style.width= +u[s].width/Math.pow(2,q)+"px";v.style.height=u[s].height/Math.pow(2,q)+"px";v.style.top=u[s].uly/Math.pow(2,q)+"px";v.style.left=u[s].ulx/Math.pow(2,q)+"px";v.style.background=r;v.style.border="1px solid #555";v.style.position="absolute";v.style.zIndex=100;v.className=k;"undefined"!==typeof u[s].divID&&(v.id=u[s].divID);l.appendChild(v)}}diva.Events.publish("HighlightCompleted",[a,c,g])}}b.parentObject.data("highlights",{});diva.Events.subscribe("PageWillLoad",c);e.resetHighlights=function(){for(var a= +document.getElementById(b.ID+"inner").getElementsByClassName(b.ID+"highlight"),c=a.length;c--;)a[c].parentNode.removeChild(a[c]);b.parentObject.data("highlights",{})};e.removeHighlightsOnPage=function(a){var c=b.parentObject.data("highlights");if(c.hasOwnProperty(a)){for(var g=e.getInstanceId()+"page-"+a,g=document.getElementById(g),k=g.getElementsByTagName("div"),l=c[a].divClass,u=k.length;u--;)k[u].className===l&&g.removeChild(k[u]);delete c[a]}};e.highlightOnPages=function(a,b,c,f){for(var l=a.length;l--;)e.highlightOnPage(a[l], +b[l],c,f)};e.highlightOnPage=function(a,h,g,k){"undefined"===typeof g&&(g="rgba(255, 0, 0, 0.2)");k="undefined"===typeof k?b.ID+"highlight":b.ID+"highlight "+k;e.getMaxZoomLevel();b.parentObject.data("highlights")[a]={regions:h,colour:g,divClass:k};e.isPageInDOM(a)&&c(a,null,null);return!0};e.gotoHighlight=function(a){var c,g,k,l=b.parentObject.data("highlights"),u=!1;if(null!==document.getElementById(a)){c=parseInt(document.getElementById(a).parentNode.getAttribute("data-index"),10);for(var r=l[c].regions.length;r--;)if(l[c].regions[r].divID=== +a){g=l[c].regions[r];k=parseFloat(g.uly)+parseFloat(g.height)/2;g=parseFloat(g.ulx)+parseFloat(g.width)/2;u=!0;break}}else for(var r=Object.keys(l),q=r.length;q--;){for(var s=l[r[q]].regions,v=s.length;v--;)if(s[v].divID===a){c=r[q];g=s[v];k=parseFloat(g.uly)+parseFloat(g.height)/2;g=parseFloat(g.ulx)+parseFloat(g.width)/2;u=!0;break}if(u)break}if(!u)return console.warn("Diva just tried to find a highlight that doesn't exist."),!1;l=e.getSettings().outerObject;k=e.translateFromMaxZoomLevel(k);g=e.translateFromMaxZoomLevel(g); +e.gotoPageByIndex(c);c=l.scrollTop()+k-l.height()/2+b.verticalPadding;k=l.scrollLeft()+g-l.width()/2+b.horizontalPadding;l.scrollTop(c);l.scrollLeft(k);b.currentHighlight=a;return!0};return!0},destroy:function(b,e){b.parentObject.removeData("highlights")},pluginName:"highlight",titleText:"Highlight regions of pages"}}())})(jQuery);(function(b){window.divaPlugins.push(function(){return{init:function(b,e){void 0===b.pageAliases&&(b.pageAliases={});void 0===b.pageAliasFunction&&(b.pageAliasFunction=function(){return!1});e.getAliasForPageIndex=function(c){return b.pageAliases[c]||b.pageAliasFunction(c)||c+1};e.getPageIndexForAlias=function(c){for(var a=0;a" + + "Autoscrolling options:
    " + + "Speed:" + + "
    " + + "Allow manual scroll:" + + "
    " + + "" + + ""; + $("#" + divaSettings.ID + "page-nav").before("
    "); + $("body").prepend(autoscrollPrefsString); + + $("#" + divaSettings.ID + "autoscroll-pps").on('change', function(e) + { + divaInstance.changeScrollSpeed(Math.pow(10, e.target.value)); + }); + + $("#" + divaSettings.ID + "autoscroll-manual").on('change', function(e) + { + e.target.checked ? divaInstance.enableManualScroll() : divaInstance.disableManualScroll(); + }); + + $("#" + divaSettings.ID + "autoscroll-toggle").on('click', divaInstance.toggleScrolling); + + $("#" + divaSettings.ID + "autoscroll-icon").on('click', function(e) + { + settings.jqObj = $("#" + divaSettings.ID + "autoscroll-prefs"); + + if (settings.jqObj.css('display') === 'none') + { + settings.jqObj.css({'display': 'block'}); + + setPosition(divaSettings.inFullscreen); + + } + else + { + settings.jqObj.css('display', 'none'); + } + }); + }); + } + }, + pluginName: 'autoscroll', + titleText: 'Automatically scrolls page along primary axis' + }; + return retval; + })()); +})(jQuery); \ No newline at end of file diff --git a/build/js/plugins/highlight.js b/build/js/plugins/highlight.js index 5d80679c..3a04fa78 100644 --- a/build/js/plugins/highlight.js +++ b/build/js/plugins/highlight.js @@ -31,7 +31,7 @@ Allows you to highlight regions of a page image @param pageIdx The page index of the page that is to be highlighted @param filename The image filename of the page - @param pageSelector The + @param pageSelector The selector for the page (unused here) */ function _highlight(pageIdx, filename, pageSelector) { @@ -57,11 +57,11 @@ Allows you to highlight regions of a page image var currentWidth = pageObj.clientWidth; var widthProportion = maxZoomWidth / currentWidth; zoomDifference = Math.log(widthProportion) / Math.log(2); - } + } else { zoomDifference = maxZoom - divaInstance.getZoomLevel(); - } + } var j = regions.length; while (j--) @@ -86,7 +86,7 @@ Allows you to highlight regions of a page image pageObj.appendChild(box); } } - diva.Events.publish("HighlightCompleted"); + diva.Events.publish("HighlightCompleted", [pageIdx, filename, pageSelector]); } // subscribe the highlight method to the page change notification @@ -151,7 +151,7 @@ Allows you to highlight regions of a page image var j = pageIdxs.length; while (j--) { - divaInstance.highlightOnPage(pageIdxs[j], regions, colour, divClass); + divaInstance.highlightOnPage(pageIdxs[j], regions[j], colour, divClass); } }; @@ -185,14 +185,96 @@ Allows you to highlight regions of a page image 'regions': regions, 'colour': colour, 'divClass': divClass }; - // Since the highlighting won't take place until the viewer is scrolled - // to a new page we should explicitly call the _highlight method for visible page. - // (only if the current page is the one to be highlighted) - if (divaInstance.isPageInViewport(pageIdx)) + + //Highlights are created on load; create them for all loaded pages now + if (divaInstance.isPageInDOM(pageIdx)) { _highlight(pageIdx, null, null); } + return true; + }; + + /* + Jumps to a highlight somewhere in the document. + @param divID The ID of the div to jump to. This ID must be attached to the div using .highlightOnPage(s) as the highlight may not be appended to the DOM. + */ + divaInstance.gotoHighlight = function(divID) + { + var page; + var thisDiv; + var centerYOfDiv; + var centerXOfDiv; + + var highlightsObj = divaSettings.parentObject.data('highlights'); + var highlightFound = false; //used to break both loops + + //see if it exists in the DOM already first + if (document.getElementById(divID) !== null) + { + page = parseInt(document.getElementById(divID).parentNode.getAttribute('data-index'), 10); + + var numDivs = highlightsObj[page].regions.length; + while (numDivs--) + { + if (highlightsObj[page].regions[numDivs].divID === divID) + { + thisDiv = highlightsObj[page].regions[numDivs]; + centerYOfDiv = parseFloat(thisDiv.uly) + parseFloat(thisDiv.height) / 2; + centerXOfDiv = parseFloat(thisDiv.ulx) + parseFloat(thisDiv.width) / 2; + + highlightFound = true; + break; + } + } + } + else + { + var pageArr = Object.keys(highlightsObj); + var pageIdx = pageArr.length; + while (pageIdx--) + { + var regionArr = highlightsObj[pageArr[pageIdx]].regions; + var arrIndex = regionArr.length; + + while (arrIndex--) + { + if (regionArr[arrIndex].divID === divID) + { + page = pageArr[pageIdx]; + thisDiv = regionArr[arrIndex]; + centerYOfDiv = parseFloat(thisDiv.uly) + parseFloat(thisDiv.height) / 2; + centerXOfDiv = parseFloat(thisDiv.ulx) + parseFloat(thisDiv.width) / 2; + + highlightFound = true; + break; + } + } + + if (highlightFound) break; + } + } + + if (!highlightFound) + { + console.warn("Diva just tried to find a highlight that doesn't exist."); + return false; + } + + var outerObject = divaInstance.getSettings().outerObject; + + var desiredY = divaInstance.translateFromMaxZoomLevel(centerYOfDiv); + var desiredX = divaInstance.translateFromMaxZoomLevel(centerXOfDiv); + + divaInstance.gotoPageByIndex(page); + var currentTop = outerObject.scrollTop() + desiredY - (outerObject.height() / 2) + divaSettings.verticalPadding; + var currentLeft = outerObject.scrollLeft() + desiredX - (outerObject.width() / 2) + divaSettings.horizontalPadding; + + outerObject.scrollTop(currentTop); + outerObject.scrollLeft(currentLeft); + + divaSettings.currentHighlight = divID; + return true; }; diff --git a/build/js/utils.js b/build/js/utils.js index 93e268b0..f2e971c6 100644 --- a/build/js/utils.js +++ b/build/js/utils.js @@ -755,18 +755,18 @@ var diva = (function() { return pub; }()); -var multiDiva; - -var multiDivaController = function () +//Used to keep track of whether Diva was last clicked or which Diva was last clicked when there are multiple +var activeDivaController = function () { var active; + //global click listener $(document).on('click', function(e) { updateActive($(e.target)); }); - //parameter should already be selected in jQuery + //parameter should already be a jQuery selector var updateActive = function (target) { var nearestOuter; @@ -774,47 +774,50 @@ var multiDivaController = function () //these will find 0 or 1 objects, never more var findOuter = target.find('.diva-outer'); var closestOuter = target.closest('.diva-outer'); + var outers = document.getElementsByClassName('diva-outer'); + var outerLen = outers.length; + var idx; - if (findOuter.length > 0) //clicked on something that was not either a parent or sibling of diva-outer + //clicked on something that was not either a parent or sibling of a diva-outer + if (findOuter.length > 0) { nearestOuter = findOuter; } - else if (closestOuter.length > 0) //clicked on something that was a child of diva-outer + //clicked on something that was a child of a diva-outer + else if (closestOuter.length > 0) { nearestOuter = closestOuter; } - else //clicked on something unrelated + //clicked on something that was not in any Diva tree + else { + //deactivate everything and return + for (idx = 0; idx < outerLen; idx++) + { + $(outers[idx].parentElement).data('diva').deactivate(); + } return; } - //activate this one + //if we found one, activate it... nearestOuter.parent().data('diva').activate(); active = nearestOuter.parent(); - //deactivate all the others - var curOuter = $(".diva-outer").length; - while (curOuter--) + //...and deactivate all the others + outers = document.getElementsByClassName('diva-outer'); + for(idx = 0; idx < outerLen; idx++) { - if ($($(".diva-outer")[curOuter]).attr('id') != nearestOuter.attr('id')) - $($(".diva-outer")[curOuter]).parent().data('diva').deactivate(); + //getAttribute to attr - comparing DOM element to jQuery element + if (outers[idx].getAttribute('id') != nearestOuter.attr('id')) + $(outers[idx].parentElement).data('diva').deactivate(); } }; + //public accessor in case. Will return a jQuery selector. this.getActive = function() { return active; }; }; -diva.Events.subscribe("ViewerDidLoad", function(settings) -{ - if($(".diva-outer").length > 1){ - //make sure there's only one active diva; deactivate any newer ones - this.deactivate(); - - //create the controller if it doesn't already exist - if(!multiDiva) - multiDiva = new multiDivaController(); - } -}); \ No newline at end of file +var activeDiva = new activeDivaController(); \ No newline at end of file diff --git a/build/processing/generate_json.py b/build/processing/generate_json.py index b7c0a338..b23fe1ae 100644 --- a/build/processing/generate_json.py +++ b/build/processing/generate_json.py @@ -87,13 +87,24 @@ def __generate(self): for j in xrange(lowest_max_zoom + 1): h = self.__incorporate_zoom(im['mx_h'], lowest_max_zoom - j) w = self.__incorporate_zoom(im['mx_w'], lowest_max_zoom - j) - c = int(math.ceil(w / 256.)) - r = int(math.ceil(h / 256.)) + # if the dimensions of the original image are an exact multiple of 256 + # we need to check whether the remainder will be less than 1 pixel. If so + # we round down; otherwise, we round up. + if w % 256 < 1: + c = int(math.floor(w / 256.)) + else: + c = int(math.ceil(w / 256.)) + + if h % 256 < 1: + r = int(math.floor(h / 256.)) + else: + r = int(math.ceil(h / 256.)) + page_data.append({ 'c': c, 'r': r, - 'h': h, - 'w': w + 'h': math.floor(h), + 'w': math.floor(w) }) t_wid[j] = t_wid[j] + w diff --git a/build/processing/process.py b/build/processing/process.py index e99bdf4c..6aee84f3 100644 --- a/build/processing/process.py +++ b/build/processing/process.py @@ -89,6 +89,7 @@ def __init__(self, input_directory, output_directory, data_output_directory, **k sys.exit(-1) if self.image_type == "tiff": + self.extension = "tiff" try: from vipsCC import VImage except ImportError as e: @@ -96,6 +97,7 @@ def __init__(self, input_directory, output_directory, data_output_directory, **k sys.exit(-1) elif self.image_type == "jpeg": + self.extension = "jp2" if not os.path.exists(self.kdu_compress_location): print(("You have specified JP2 as the output format, but do not have the kdu_compress executable installed at {0}.").format(self.kdu_compress_location)) print("If this path is incorrect, please specify an alternate location using the '-k (location)' command line option for this script.") @@ -122,7 +124,7 @@ def convert(self): tdir = tempfile.mkdtemp() input_file = os.path.join(tdir, "{0}.tiff".format(name)) - output_file = os.path.join(self.output_directory, "{0}.{1}".format(name, self.image_type)) + output_file = os.path.join(self.output_directory, "{0}.{1}".format(name, self.extension)) if self.verbose: print("Using ImageMagick to pre-convert {0} to TIFF".format(image)) diff --git a/build/readme.md b/build/readme.md index 33719d53..6a2f03f0 100644 --- a/build/readme.md +++ b/build/readme.md @@ -34,7 +34,7 @@ The IIP Image Server is required by Diva to serve image data. IIP creates the im Diva relies on a JavaScript Object Notation (JSON) file that contains data about your document. This JSON file is automatically generated when you use the image conversion scripts that we distribute with Diva. These files can be served using a regular web server. _(If you used previous versions of Diva, we had a dedicated `divaserve` script to do this. This dependency has been removed in version 3.0)_. -Download the [latest release](https://github.com/DDMAL/diva.js/releases) of Diva. In the `build` directory you can find a pre-compiled version of Diva. The `css`, `js` and `img` directories contain the files necessary to use Diva. You will also find a number of demos and some helper scripts for processing your image files. +Download the [latest release](https://github.com/DDMAL/diva.js/releases) of Diva. In the `diva.js` directory (or `build` if you have the source code) you can find a pre-compiled version of Diva. The `css`, `js` and `img` directories contain the files necessary to use Diva. You will also find a number of demos and some helper scripts for processing your image files. There are two image formats supported by IIP: Pyramid TIFF and, with the inclusion of the Kakadu libraries, JPEG2000. These formats support multiple file resolutions and image tiling. @@ -51,11 +51,12 @@ $('#diva-wrapper').diva({ }); ``` - * `#diva-wrapper`: A selector pointing to a `div` element where you want the scrollable page images to appear; * `iipServerURL`: The URL to your IIP installation. In most cases this should point to the iipsrv.fcgi file; * `objectData`: The URL (absolute or relative) to the document's `.json` file * `imageDir`: Either the absolute path to your images on your server, OR the path relative to your IIP installation's [`FILESYSTEM_PREFIX`](http://iipimage.sourceforge.net/documentation/server/) configuration option. +The `#diva-wrapper` selector points to a `div` element where you want the scrollable page images to appear. + Since IIP will be serving the images you should not place your images in directory accessible by your web server. In other words, if your web server uses `/srv/www` as its root directory you do not need to place your images there -- they can reside in any directory on your server as long as it they can be read by the IIP instance. See [Installation](https://github.com/DDMAL/diva.js/wiki/Installation) for full instructions. @@ -73,10 +74,10 @@ To fix this you must ensure that the Diva HTML page, and the location pointed to ### Running the Demos -Running the demos works best using a web server. The easiest is to use Python to start a small web server in the 'build' directory: +Running the demos works best using a web server. The easiest is to use Python to start a small web server in the `diva.js` directory (or `build` if you have the source code): ``` -$> cd diva.js/build +$> cd diva-v3.0.0/diva.js/ # (or cd diva.js/build) $> python -m SimpleHTTPServer Serving HTTP on 0.0.0.0 port 8000 ... ``` diff --git a/demo/diva/autoscroll.html b/demo/diva/autoscroll.html new file mode 100644 index 00000000..2b24eeb7 --- /dev/null +++ b/demo/diva/autoscroll.html @@ -0,0 +1,43 @@ + + + + + Diva.js Demo Page + + + + + + + + + + +
    + + diff --git a/demo/index.html b/demo/index.html index 7a8f97bb..3ba4d076 100644 --- a/demo/index.html +++ b/demo/index.html @@ -13,6 +13,7 @@
  • A basic Diva instance.
  • A demonstration of horizontal scrolling.
  • A demonstration of the highlight plugin.
  • +
  • A demonstration of the autoscroll plugin.
  • diff --git a/readme.md b/readme.md index 1d5cbdde..203b286b 100644 --- a/readme.md +++ b/readme.md @@ -51,11 +51,12 @@ $('#diva-wrapper').diva({ }); ``` - * `#diva-wrapper`: A selector pointing to a `div` element where you want the scrollable page images to appear; * `iipServerURL`: The URL to your IIP installation. In most cases this should point to the iipsrv.fcgi file; * `objectData`: The URL (absolute or relative) to the document's `.json` file * `imageDir`: Either the absolute path to your images on your server, OR the path relative to your IIP installation's [`FILESYSTEM_PREFIX`](http://iipimage.sourceforge.net/documentation/server/) configuration option. +The `#diva-wrapper` selector points to a `div` element where you want the scrollable page images to appear. + Since IIP will be serving the images you should not place your images in directory accessible by your web server. In other words, if your web server uses `/srv/www` as its root directory you do not need to place your images there -- they can reside in any directory on your server as long as it they can be read by the IIP instance. See [Installation](https://github.com/DDMAL/diva.js/wiki/Installation) for full instructions. diff --git a/source/css/diva.less b/source/css/diva.less index 6e5a2c30..7df55825 100644 --- a/source/css/diva.less +++ b/source/css/diva.less @@ -104,7 +104,6 @@ top: 0px; right: 30px; z-index: @fullscreenZIndex + 1; - width: 230px; height: 73px; padding: 15px; .frame(@toolsFrame); @@ -221,17 +220,20 @@ float: right; } -.diva-link-popup { - font-size: 10pt; +.diva-popup { background: @linkBg; - .frame(@linkFrame); - position: absolute; + .frame(@buttonFrame); padding: .6em; z-index: @fullscreenZIndex + 1; + position: absolute; .pretty-shadow; +} + +.diva-link-popup { + font-size: 10pt; input { - width: 15em; + width: 18em; &:focus { outline: none; } diff --git a/source/css/imports.less b/source/css/imports.less index e1035ac1..d51cd239 100644 --- a/source/css/imports.less +++ b/source/css/imports.less @@ -8,3 +8,4 @@ // Plugins @import "plugins/canvas.less"; @import "plugins/download.less"; +@import "plugins/autoscroll.less"; diff --git a/source/css/plugins/autoscroll.less b/source/css/plugins/autoscroll.less new file mode 100644 index 00000000..b3adccbd --- /dev/null +++ b/source/css/plugins/autoscroll.less @@ -0,0 +1,25 @@ +/* Begin autoscroll plugin */ + +.diva-autoscroll-icon { + float: right; + border-right: none; + background-image: url("@{iconPath}plugins/play.png"); +} + +.diva-autoscroll-prefs { + display: none; + margin-right: .6em; +} + +.diva-autoscroll-prefs-text { + float: left; +} + +.diva-autoscroll-prefs-input { + float: right; + margin-left: .6em; +} + +.diva-autoscroll-pps { + width: 9em; +} diff --git a/source/img/plugins/play.png b/source/img/plugins/play.png new file mode 100644 index 00000000..d3348b21 Binary files /dev/null and b/source/img/plugins/play.png differ diff --git a/source/js/diva.js b/source/js/diva.js index c809f2b5..e3a6dbdf 100644 --- a/source/js/diva.js +++ b/source/js/diva.js @@ -1,5 +1,5 @@ /* -Copyright (C) 2011-2014 by Wendy Liu, Evan Magoni, Andrew Hankinson, Andrew Horwitz, Laurent Pugin +Copyright (C) 2011-2015 by Wendy Liu, Evan Magoni, Andrew Hankinson, Andrew Horwitz, Laurent Pugin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -40,6 +40,7 @@ window.divaPlugins = []; enableGotoPage: true, // A "go to page" jump box enableGridIcon: true, // A grid view of all the pages enableGridControls: 'buttons', // Specify control of pages per grid row in Grid view. Possible values: 'buttons' (+/-), 'slider'. Any other value disables the controls. + enableImageTitles: true, // Adds "Page {n}" title to page images if true enableKeyScroll: true, // Captures scrolling using the arrow and page up/down keys regardless of page focus. When off, defers to default browser scrolling behavior. enableLinkIcon: true, // Controls the visibility of the link icon enableSpaceScroll: false, // Scrolling down by pressing the space key @@ -77,7 +78,7 @@ window.divaPlugins = []; tileHeight: 256, // The height of each tile, in pixels; usually 256 tileWidth: 256, // The width of each tile, in pixels; usually 256 toolbarParentObject: options.parentObject, // The toolbar parent object. - verticallyOriented: true, // Determines vertical vs. horizontal orientation + verticallyOriented: true, // Determines vertical vs. horizontal orientation viewportMargin: 200, // Pretend tiles +/- 200px away from viewport are in zoomLevel: 2 // The initial zoom level (used to store the current zoom level) }; @@ -309,7 +310,7 @@ window.divaPlugins = []; pageElement.classList.add('diva-document-page'); pageElement.setAttribute('data-index', pageIndex); pageElement.setAttribute('data-filename', filename); - pageElement.title = "Page " + (pageIndex + 1); + if (settings.enableImageTitles) pageElement.title = "Page " + (pageIndex + 1); pageElement.innerHTML = settings.pageTools; pageElement.style.width = width + 'px'; pageElement.style.height = height + 'px'; @@ -344,7 +345,7 @@ window.divaPlugins = []; var pageElement = document.getElementById(settings.ID + 'page-' + pageIndex); // If the page is no longer in the viewport, don't load any tiles - if (!isPageVisible(pageIndex)) + if (!isPageLoaded(pageIndex)) return; var imdir = settings.imageDir + "/"; @@ -375,13 +376,14 @@ window.divaPlugins = []; while (row < rows) { col = 0; + // If the tile is in the last row or column, its dimensions will be different + tileHeight = (row === rows - 1) ? lastHeight : settings.tileHeight; + while (col < cols) { top = row * settings.tileHeight; left = col * settings.tileWidth; - // If the tile is in the last row or column, its dimensions will be different - tileHeight = (row === rows - 1) ? lastHeight : settings.tileHeight; tileWidth = (col === cols - 1) ? lastWidth : settings.tileWidth; imageURL = baseImageURL + tileIndex; @@ -392,10 +394,10 @@ window.divaPlugins = []; { if (isTileVisible(pageIndex, row, col)) { - /* - content.push('
    '); */ var tileElem = document.createElement('div'); @@ -408,7 +410,7 @@ window.divaPlugins = []; tileElem.style.backgroundImage = "url('" + imageURL + "')"; tileElem.style.height = tileHeight + "px"; tileElem.style.width = tileWidth + "px"; - + // content.push(tileElem); pageElement.appendChild(tileElem); } @@ -428,7 +430,7 @@ window.divaPlugins = []; executeCallback(settings.onPageLoaded, pageIndex, filename, pageSelector); diva.Events.publish("PageDidLoad", [pageIndex, filename, pageSelector], self); }; - settings.pageTimeouts.push(setTimeout(pageLoadFunction(pageIndex), settings.pageLoadTimeout)); + settings.pageTimeouts.push(setTimeout(pageLoadFunction, settings.pageLoadTimeout, pageIndex)); }; // Delete a page from the DOM; will occur when a page is scrolled out of the viewport @@ -436,10 +438,10 @@ window.divaPlugins = []; { // $(document.getElementById(settings.ID + 'page-' + pageIndex)).empty().remove(); var theNode = document.getElementById(settings.ID + 'page-' + pageIndex); - + if (theNode === null) return; - + while (theNode.firstChild) { theNode.removeChild(theNode.firstChild); @@ -623,7 +625,7 @@ window.divaPlugins = []; // scrolling backwards executeCallback(settings.onScrollUp, scrollSoFar); diva.Events.publish("ViewerDidScrollUp", [scrollSoFar], self); - } + } }; // Check if a row index is valid @@ -657,7 +659,7 @@ window.divaPlugins = []; var heightFromTop = (settings.rowHeight * rowIndex) + settings.fixedPadding; var content = []; var innerElem = document.getElementById(settings.ID + "inner"); - + // Create the row div var rowDiv = document.createElement('div'); rowDiv.id = settings.ID + 'row-' + rowIndex; @@ -701,7 +703,7 @@ window.divaPlugins = []; settings.pageTopOffsets[pageIndex] = heightFromTop; settings.pageLeftOffsets[pageIndex] = leftOffset; - + // Append the HTML for this page to the string builder array var pageDiv = document.createElement('div'); pageDiv.id = settings.ID + 'page-' + pageIndex; @@ -712,10 +714,10 @@ window.divaPlugins = []; pageDiv.style.left = leftOffset + 'px'; pageDiv.setAttribute('data-index', pageIndex); pageDiv.setAttribute('data-filename', filename); - pageDiv.title = "Page " + (pageIndex + 1); - + if (settings.enableImageTitles) pageDiv.title = "Page " + (pageIndex + 1); + rowDiv.appendChild(pageDiv); - + diva.Events.publish("PageWillLoad", [pageIndex, filename, pageSelector], self); // Add each image to a queue so that images aren't loaded unnecessarily @@ -728,7 +730,7 @@ window.divaPlugins = []; var theNode = document.getElementById(settings.ID + 'row-' + rowIndex); if (theNode === null) return; - + while (theNode.firstChild) { theNode.removeChild(theNode.firstChild); @@ -856,7 +858,7 @@ window.divaPlugins = []; { var loadFunction = function (rowIndex, pageIndex, imageURL, pageWidth, pageHeight) { - if (isRowVisible(rowIndex)) + if (isRowLoaded(rowIndex)) { var imgEl = document.createElement('img'); imgEl.src = imageURL; @@ -864,10 +866,10 @@ window.divaPlugins = []; imgEl.style.height = pageHeight + 'px'; document.getElementById(settings.ID + 'page-' + pageIndex).appendChild(imgEl); } - }; + }; settings.pageTimeouts.push( - window.setTimeout(loadFunction(rowIndex, pageIndex, imageURL, pageWidth, pageHeight), settings.rowLoadTimeout)); + window.setTimeout(loadFunction, settings.rowLoadTimeout, rowIndex, pageIndex, imageURL, pageWidth, pageHeight)); }; // Determines and sets the "current page" (settings.currentPageIndex); called within adjustPages @@ -877,7 +879,7 @@ window.divaPlugins = []; var currentPage = settings.currentPageIndex; var pageToConsider = currentPage + direction; - if(!isPageValid(pageToConsider)) + if (!isPageValid(pageToConsider)) return false; var middleOfViewport = (settings.verticallyOriented ? document.getElementById(settings.ID + "outer").scrollTop + (settings.panelHeight / 2) : document.getElementById(settings.ID + "outer").scrollLeft + (settings.panelWidth / 2)); @@ -900,7 +902,7 @@ window.divaPlugins = []; if (pageToConsider >= 0 && (settings.pageLeftOffsets[pageToConsider] + getPageData(pageToConsider, 'w') + (settings.horizontalPadding) >= middleOfViewport)) { changeCurrentPage = true; - } + } } } else if (direction > 0) @@ -1016,11 +1018,14 @@ window.divaPlugins = []; settings.outerObject.scrollLeft(desiredLeft); // Pretend that this is the current page - settings.currentPageIndex = pageIndex; - var filename = settings.pages[pageIndex].f; + if (pageIndex !== settings.currentPageIndex) + { + settings.currentPageIndex = pageIndex; + var filename = settings.pages[pageIndex].f; - executeCallback(settings.onSetCurrentPage, pageIndex, filename); - diva.Events.publish("VisiblePageDidChange", [pageIndex, filename], self); + executeCallback(settings.onSetCurrentPage, pageIndex, filename); + diva.Events.publish("VisiblePageDidChange", [pageIndex, filename], self); + } // Execute the onJump callback executeCallback(settings.onJump, pageIndex); @@ -1197,7 +1202,7 @@ window.divaPlugins = []; var pageIndex = settings.currentPageIndex; settings.verticalOffset = (settings.verticallyOriented ? (settings.panelHeight / 2) : getPageData(pageIndex, "h") / 2); settings.horizontalOffset = (settings.verticallyOriented ? getPageData(pageIndex, "w") / 2 : (settings.panelWidth / 2)); - + clearViewer(); // Make sure the pages per row setting is valid @@ -1242,7 +1247,7 @@ window.divaPlugins = []; //Shortcut for closing fullscreen with the escape key var escapeListener = function (e) { - if(e.keyCode == 27) + if (e.keyCode == 27) toggleFullscreen(); }; @@ -1250,54 +1255,44 @@ window.divaPlugins = []; // Should only be called after changing settings.inFullscreen var handleModeChange = function (changeView) { - var storedOffsetY = getCurrentYOffset(); - var storedOffsetX = getCurrentXOffset(); - var outerElem = document.getElementById(settings.ID + "outer"); - - settings.panelHeight = outerElem.clientHeight - (outerElem.scrollWidth > outerElem.clientWidth ? settings.scrollbarWidth : 0); - settings.panelWidth = outerElem.clientWidth - (outerElem.scrollHeight > outerElem.clientHeight ? settings.scrollbarWidth : 0); - var storedHeight = settings.panelHeight; - var storedWidth = settings.panelWidth; - // Toggle the classes settings.outerObject.toggleClass('diva-fullscreen'); $('body').toggleClass('diva-hide-scrollbar'); settings.parentObject.toggleClass('diva-full-width'); // Adjust margin a bit if in mobile - if(settings.mobileWebkit) + if (settings.mobileWebkit) { var leftMarginComped = parseInt(settings.outerObject.css('margin-left'), 10) - parseInt($('body').css('margin-left'), 10); settings.outerObject.css('margin-left', leftMarginComped); } - // Execute callbacks - executeCallback(settings.onModeToggle, settings.inFullscreen); - diva.Events.publish("ModeDidSwitch", [settings.inFullscreen], self); - - // If it has changed, adjust panel size coming out of fullscreen - if (!settings.inFullscreen) - { - updatePanelSize(); - } + // Adjust Diva's internal panel size, keeping the old values + var storedHeight = settings.panelHeight; + var storedWidth = settings.panelWidth; + updatePanelSize(); + // If this isn't the original load... if (settings.oldZoomLevel >= 0 && !settings.inGrid) { + //get the updated panel size var newHeight = settings.panelHeight; var newWidth = settings.panelWidth; - if(settings.inFullscreen) + + //and re-center the new panel on the same point + if (settings.inFullscreen) { - settings.verticalOffset = ((newHeight - storedHeight) / 2) + storedOffsetY; - settings.horizontalOffset = ((newWidth - storedWidth) / 2) + storedOffsetX; + settings.verticalOffset -= ((newHeight - storedHeight) / 2); + settings.horizontalOffset -= ((newWidth - storedWidth) / 2); } else { - settings.verticalOffset = storedOffsetY - ((storedHeight - newHeight) / 2); - settings.verticalOffset = storedOffsetX - ((storedWidth - newWidth) / 2); + settings.verticalOffset += ((storedHeight - newHeight) / 2); + settings.horizontalOffset += ((storedWidth - newWidth) / 2); } } - // Used by setState when we need to change the view and the mode + // If setState changes both view and mode, trigger that here if (changeView) { settings.inGrid = !settings.inGrid; @@ -1308,10 +1303,15 @@ window.divaPlugins = []; loadViewer(); } - if(settings.inFullscreen) + //turn on/off escape key listener + if (settings.inFullscreen) $(document).on('keyup', escapeListener); else $(document).off('keyup', escapeListener); + + // Execute callbacks + executeCallback(settings.onModeToggle, settings.inFullscreen); + diva.Events.publish("ModeDidSwitch", [settings.inFullscreen], self); }; // Handles switching in and out of grid view @@ -1478,7 +1478,7 @@ window.divaPlugins = []; var getYOffset = function (pageIndex, anchor) { pageIndex = (typeof(pageIndex) === "undefined" ? settings.currentPageIndex : pageIndex); - + if (anchor === "center" || anchor === "centre") //how you can tell an American coded this { return parseInt(getPageData(pageIndex, "h") / 2, 10); @@ -1571,8 +1571,8 @@ window.divaPlugins = []; var updatePanelSize = function () { var outerElem = document.getElementById(settings.ID + 'outer'); - settings.panelHeight = outerElem.clientHeight - (outerElem.scrollWidth > outerElem.clientWidth ? settings.scrollbarWidth : 0); - settings.panelWidth = outerElem.clientWidth - (outerElem.scrollHeight > outerElem.clientHeight ? settings.scrollbarWidth : 0); + settings.panelHeight = outerElem.clientHeight - (outerElem.scrollWidth > outerElem.clientWidth ? settings.scrollbarWidth : 0); + settings.panelWidth = outerElem.clientWidth - (outerElem.scrollHeight > outerElem.clientHeight ? settings.scrollbarWidth : 0); settings.horizontalOffset = getCurrentXOffset(); settings.verticalOffset = getCurrentYOffset(); @@ -1674,7 +1674,7 @@ window.divaPlugins = []; if (settings.verticallyOriented || settings.inGrid) direction = newScrollTop - settings.previousTopScroll; else - direction = newScrollLeft - settings.previousLeftScroll; + direction = newScrollLeft - settings.previousLeftScroll; //give adjustPages the direction we care about if (settings.inGrid) @@ -1691,6 +1691,79 @@ window.divaPlugins = []; settings.outerObject.scroll(scrollFunction); + var upArrowKey = 38, + downArrowKey = 40, + leftArrowKey = 37, + rightArrowKey = 39, + spaceKey = 32, + pageUpKey = 33, + pageDownKey = 34, + homeKey = 36, + endKey = 35; + + // Catch the key presses in document + $(document).keydown(function (event) + { + if (!settings.isActiveDiva) + return true; + + // Space or page down - go to the next page + if ((settings.enableSpaceScroll && !event.shiftKey && event.keyCode === spaceKey) || (settings.enableKeyScroll && event.keyCode === pageDownKey)) + { + settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop + settings.panelHeight); + return false; + } + else if (!settings.enableSpaceScroll && event.keyCode === spaceKey) + { + event.preventDefault(); + } + + if (settings.enableKeyScroll) + { + switch (event.keyCode) + { + case pageUpKey: + // Page up - go to the previous page + settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop - settings.panelHeight); + return false; + + case upArrowKey: + // Up arrow - scroll up + settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop - settings.arrowScrollAmount); + return false; + + case downArrowKey: + // Down arrow - scroll down + settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop + settings.arrowScrollAmount); + return false; + + case leftArrowKey: + // Left arrow - scroll left + settings.outerObject.scrollLeft(document.getElementById(settings.ID + "outer").scrollLeft - settings.arrowScrollAmount); + return false; + + case rightArrowKey: + // Right arrow - scroll right + settings.outerObject.scrollLeft(document.getElementById(settings.ID + "outer").scrollLeft + settings.arrowScrollAmount); + return false; + + case homeKey: + // Home key - go to the beginning of the document + settings.outerObject.scrollTop(0); + return false; + + case endKey: + // End key - go to the end of the document + settings.outerObject.scrollTop(settings.totalHeight); + return false; + + default: + return true; + } + } + return true; + }); + // Check if the user is on a iPhone or iPod touch or iPad if (settings.mobileWebkit) { @@ -1814,117 +1887,47 @@ window.divaPlugins = []; // Grid view: Double-tap to jump to current page in document view settings.outerObject.on('touchend', '.diva-page', bindDoubleTap); - } - - // Only check if either scrollBySpace or scrollByKeys is enabled - if (settings.enableSpaceScroll || settings.enableKeyScroll) - { - var upArrowKey = 38, - downArrowKey = 40, - leftArrowKey = 37, - rightArrowKey = 39, - spaceKey = 32, - pageUpKey = 33, - pageDownKey = 34, - homeKey = 36, - endKey = 35; - // Catch the key presses in document - $(document).keydown(function (event) + // Handle window resizing events + var orientationEvent = "onorientationchange" in window ? "orientationchange" : "resize"; + $(window).bind(orientationEvent, function (event) { - if (!settings.isActiveDiva) - return; - - // Space or page down - go to the next page - if ((settings.enableSpaceScroll && event.keyCode === spaceKey) || (settings.enableKeyScroll && event.keyCode === pageDownKey)) - { - settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop + settings.panelHeight); - return false; - } + var oldWidth = settings.panelWidth; + var oldHeight = settings.panelHeight; + updatePanelSize(); - if (settings.enableKeyScroll) - { - switch (event.keyCode) - { - case pageUpKey: - // Page up - go to the previous page - settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop - settings.panelHeight); - return false; - - case upArrowKey: - // Up arrow - scroll up - settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop - settings.arrowScrollAmount); - return false; - - case downArrowKey: - // Down arrow - scroll down - settings.outerObject.scrollTop(document.getElementById(settings.ID + "outer").scrollTop + settings.arrowScrollAmount); - return false; - - case leftArrowKey: - // Left arrow - scroll left - settings.outerObject.scrollLeft(document.getElementById(settings.ID + "outer").scrollLeft - settings.arrowScrollAmount); - return false; - - case rightArrowKey: - // Right arrow - scroll right - settings.outerObject.scrollLeft(document.getElementById(settings.ID + "outer").scrollLeft + settings.arrowScrollAmount); - return false; - - case homeKey: - // Home key - go to the beginning of the document - settings.outerObject.scrollTop(0); - return false; - - case endKey: - // End key - go to the end of the document - settings.outerObject.scrollTop(settings.totalHeight); - return false; - } - } - }); + settings.horizontalOffset -= (settings.panelWidth - oldWidth) / 2; + settings.verticalOffset -= (settings.panelHeight - oldHeight) / 2; - // Handle window resizing events - if (!settings.mobileWebkit) + // Reload the viewer to account for the resized viewport + settings.goDirectlyTo = settings.currentPageIndex; + loadViewer(); + }); + } + // Handle window resizing events + else + { + $(window).resize(function () { - $(window).resize(function () - { - updatePanelSize(); - // Cancel any previously-set resize timeouts - clearTimeout(settings.resizeTimer); + updatePanelSize(); + // Cancel any previously-set resize timeouts + clearTimeout(settings.resizeTimer); - settings.resizeTimer = setTimeout(function () - { - settings.goDirectlyTo = settings.currentPageIndex; - settings.verticalOffset = getCurrentYOffset(); - settings.horizontalOffset = getCurrentXOffset(); - loadViewer(); - }, 200); - }); - } - else - { - var orientationEvent = "onorientationchange" in window ? "orientationchange" : "resize"; - $(window).bind(orientationEvent, function (event) + settings.resizeTimer = setTimeout(function () { - var oldWidth = settings.panelWidth; - var oldHeight = settings.panelHeight; - updatePanelSize(); - - settings.horizontalOffset -= (settings.panelWidth - oldWidth) / 2; - settings.verticalOffset -= (settings.panelHeight - oldHeight) / 2; - - // Reload the viewer to account for the resized viewport settings.goDirectlyTo = settings.currentPageIndex; + settings.verticalOffset = getCurrentYOffset(); + settings.horizontalOffset = getCurrentXOffset(); loadViewer(); - }); - } - diva.Events.subscribe('PanelSizeDidChange', updatePanelSize); + }, 200); + }); } + diva.Events.subscribe('PanelSizeDidChange', updatePanelSize); + }; // Handles all status updating etc (both fullscreen and not) - var createToolbar = function () + var createToolbar = function () { // Prepare the HTML for the various components var gridIconHTML = (settings.enableGridIcon) ? '
    ' : ''; @@ -1941,7 +1944,7 @@ window.divaPlugins = []; var pageNumberHTML = '
    Page 1 of ' + settings.numPages + '
    '; var fullscreenIconHTML = (settings.enableFullscreen) ? '
    ' : ''; - var toolbarHTML = '
    ' + zoomSliderHTML + zoomButtonsHTML + gridSliderHTML + gridButtonsHTML + zoomSliderLabelHTML + zoomButtonsLabelHTML + gridSliderLabelHTML + gridButtonsLabelHTML + '
    ' + fullscreenIconHTML + linkIconHTML + gridIconHTML + '
    ' + gotoPageHTML + pageNumberHTML + '
    '; + var toolbarHTML = '
    ' + zoomSliderHTML + zoomButtonsHTML + gridSliderHTML + gridButtonsHTML + zoomSliderLabelHTML + zoomButtonsLabelHTML + gridSliderLabelHTML + gridButtonsLabelHTML + '
    ' + fullscreenIconHTML + linkIconHTML + gridIconHTML + '
    ' + gotoPageHTML + pageNumberHTML + '
    '; settings.toolbarParentObject.prepend('
    ' + toolbarHTML + '
    '); @@ -1992,7 +1995,7 @@ window.divaPlugins = []; }); // Bind fullscreen button - $(settings.selector + 'fullscreen').click(function() + $(settings.selector + 'fullscreen').click(function() { toggleFullscreen(); }); @@ -2036,10 +2039,11 @@ window.divaPlugins = []; return false; }); + var linkIcon = $(settings.selector + 'link-icon'); // Handle the creation of the link popup box - $(settings.selector + 'link-icon').click(function () + linkIcon.click(function () { - $('body').prepend(''); + $('body').prepend(''); if (settings.inFullscreen) { @@ -2048,10 +2052,8 @@ window.divaPlugins = []; else { // Calculate the left and top offsets - // Compensate for border, popup width - var leftOffset = settings.outerObject.offset().left + settings.panelWidth; - leftOffset += settings.scrollbarWidth - 240 - 1; - var topOffset = settings.outerObject.offset().top + 1; + var leftOffset = linkIcon.offset().left - 222 + linkIcon.outerWidth(); + var topOffset = linkIcon.offset().top + linkIcon.outerHeight() - 1; $(settings.selector + 'link-popup').removeClass('in-fullscreen').css( { @@ -2151,7 +2153,7 @@ window.divaPlugins = []; }, updateZoomButtons: function () { - // Update the buttons label + // Update the buttons label document.getElementById(settings.ID + 'zoom-level').textContent = settings.zoomLevel; }, updateGridSlider: function () @@ -2170,6 +2172,10 @@ window.divaPlugins = []; // Update the buttons label document.getElementById(settings.ID + 'pages-per-row').textContent = settings.pagesPerRow; }, + closePopups: function () + { + $('.diva-popup').css('display', 'none'); + }, switchView: switchView, switchMode: switchMode }; @@ -2363,11 +2369,11 @@ window.divaPlugins = []; } // Adjust the document panel dimensions - updatePanelSize(); + updatePanelSize(); // Make sure the value for settings.goDirectlyTo is valid if (!isPageValid(parseInt(settings.goDirectlyTo), 10)) - settings.goDirectlyTo = 0; + settings.goDirectlyTo = 0; // Calculate the horizontal and vertical inter-page padding if (settings.adaptivePadding > 0) @@ -2387,7 +2393,7 @@ window.divaPlugins = []; if (settings.pageTools.length) { settings.verticalPadding = Math.max(40, settings.verticalPadding); - } + } // y - vertical offset from the top of the relevant page var yParam = parseInt($.getHashParam('y' + settings.hashParamSuffix), 10); @@ -2411,7 +2417,7 @@ window.divaPlugins = []; else { settings.horizontalOffset = getXOffset(settings.currentPageIndex, "center"); - } + } if (settings.inFullscreen) handleModeChange(false); @@ -2687,12 +2693,25 @@ window.divaPlugins = []; return isPageVisible(pageIndex); }; + //Public wrapper for isPageLoaded + //Determines if a page is currently in the DOM + this.isPageInDOM = function (pageIndex) + { + return isPageLoaded(pageIndex); + }; + // Toggle fullscreen mode this.toggleFullscreenMode = function () { toggleFullscreen(); }; + // Close toolbar popups + this.closePopups = function () + { + settings.toolbar.closePopups(); + }; + // Enter fullscreen mode if currently not in fullscreen mode // Returns false if in fullscreen mode initially, true otherwise // This function will work even if enableFullscreen is set to false @@ -2730,7 +2749,7 @@ window.divaPlugins = []; // Returns false if in grid view initially, true otherwise this.enterGridView = function () { - if (!settings.inGrid) + if (!settings.inGrid) { toggleGrid(); return true; @@ -2940,7 +2959,7 @@ window.divaPlugins = []; return toggleOrientation(); }; - //Returns distance between the northwest corners of diva-inner and current page + //Returns distance between the northwest corners of diva-inner and page index this.getPageOffset = function(pageIndex) { return { @@ -2949,6 +2968,12 @@ window.divaPlugins = []; }; }; + //shortcut to getPageOffset for current page + this.getCurrentPageOffset = function() + { + return this.getPageOffset(settings.currentPageIndex); + }; + //Returns the page position and size (ulx, uly, h, w properties) of page pageIndex when there are pagesPerRow pages per row //TODO: calculate all grid height levels and store them so this can be AtGridLevel(pageIndex, pagesPerRow) ? this.getPageDimensionsAtCurrentGridLevel = function(pageIndex) @@ -2964,62 +2989,57 @@ window.divaPlugins = []; }; }; - //Returns the page index at a given pageX/pageY value + /* + Given a pageX and pageY value (as could be retreived from a jQuery event object), + returns either the page visible at that (x,y) position or "false" if no page is. + */ this.getPageIndexForPageXYValues = function(pageX, pageY) { - var outerObj = $("#" + settings.ID + "outer"); - var outerOffset = outerObj.offset(); + //get the four edges of the outer element + var outerObj = document.getElementById(settings.ID + "outer") + var outerOffset = outerObj.getBoundingClientRect(); var outerTop = outerOffset.top; var outerLeft = outerOffset.left; - var outerBottom = outerTop + outerObj.outerHeight(); - var outerRight = outerLeft + outerObj.outerWidth(); - - //because pages extend outside the diva-outer class, we want to exclude those values as the pageX/pageY values aren't actually on them + var outerBottom = outerOffset.bottom; + var outerRight = outerOffset.right; + + //if the clicked position was outside the diva-outer object, it was not on a visible portion of a page if (pageX < outerLeft || pageX > outerRight) return false; if (pageY < outerTop || pageY > outerBottom) return false; - //navigate through all divs starting with "x-diva-page" - var curPageIdx = $("div[id^=" + settings.ID + "page]").length; + //navigate through all diva page objects + var pages = document.getElementsByClassName("diva-document-page"); + var curPageIdx = pages.length; while (curPageIdx--) { - var curPage = $($("div[id^=" + settings.ID + "page]")[curPageIdx]); - var pageIndex = curPage.attr('data-index'); - var curPosition = curPage.position(); - var curOffset = curPage.offset(); - var curTop, curLeft; + //get the offset for each page + var curPage = pages[curPageIdx]; + var curOffset = curPage.getBoundingClientRect(); - if (settings.verticallyOriented) - { - curTop = curPosition.top - outerObj.scrollTop() + outerTop; - curLeft = curOffset.left - outerObj.scrollLeft() + outerLeft; - } - else - { - curTop = curOffset.top - outerObj.scrollTop() + outerTop; - curLeft = curPosition.left - outerObj.scrollLeft() + outerLeft; - } - - var curBottom = curTop + curPage.outerHeight(); - var curRight = curLeft + curPage.outerWidth(); - - //if this point is outside the horizontal boundaries, continue - if (pageX < curLeft || pageX > curRight) - continue + //if this point is outside the horizontal boundaries of the page, continue + if (pageX < curOffset.left || pageX > curOffset.right) + continue; //same with vertical boundaries - if (pageY < curTop || pageY > curBottom) - continue + if (pageY < curOffset.top || pageY > curOffset.bottom) + continue; - //if we made it through the above two, we found the page we're looking for - return pageIndex; + //if we made it through the above two, we found the page we're looking for + return curPage.getAttribute('data-index'); } //if we made it through that entire while loop, we didn't click on a page return false; - } + }; + + //Pretty self-explanatory. + this.isVerticallyOriented = function() + { + return settings.verticallyOriented; + }; this.activate = function () { diff --git a/source/js/plugins/autoscroll.js b/source/js/plugins/autoscroll.js new file mode 100644 index 00000000..bc9ee3ec --- /dev/null +++ b/source/js/plugins/autoscroll.js @@ -0,0 +1,242 @@ +/* +Diva.JS autoscroll plugin +Author: Andrew Horwitz + +Lets Diva scroll in the primary direction (as determined by +settings.verticallyOriented) automatically at a given/changeable rate. + +Relevant settings: + -scrollSpeed: pixels per second (defaults to 10) + -disableManualScroll: disables manual scroll while automatic scroll is on (defaults to false) + -currentlyAutoScrolling: whether or not autoscroll is currently on + -autoScrollRefresh: ms between scrolling actions + -disableAutoscrollPrefs: disables the autoscroll preferences panel + +Relevant methods: + -startScrolling, stopScrolling, toggleScrolling + -changeRefresh, changeScrollSpeed (setters for respective options) + -disableManualScroll, enableManualScroll +*/ + +(function ($) +{ + window.divaPlugins.push((function() + { + var settings = {}; + var retval = + { + init: function(divaSettings, divaInstance) + { + var pixelsPerScroll; + var disableManualScroll; + var autoScrollRefresh; + var defaultAutoRefresh; + var scrollSpeed; + + function log10(x) + { + return Math.log(x) / Math.log(10); + } + + divaInstance.startScrolling = function() + { + if (divaSettings.currentlyAutoScrolling) + { + console.warn("You are trying to start autoscrolling, but it is already scrolling."); + return; + } + + $("#" + divaSettings.ID + "autoscroll-toggle").text("Turn off"); + if (disableManualScroll) + { + divaInstance.disableScrollable(); + } + + divaSettings.currentlyAutoScrolling = true; + restartScrollingInterval(); + }; + + restartScrollingInterval = function() + { + clearInterval(divaSettings.autoScrollInterval); + if (divaSettings.verticallyOriented) + { + divaSettings.autoScrollInterval = setInterval(function(){ + divaSettings.outerObject.scrollTop(divaSettings.outerObject.scrollTop() + pixelsPerScroll); + }, autoScrollRefresh); + } + else + { + divaSettings.autoScrollInterval = setInterval(function(){ + divaSettings.outerObject.scrollLeft(divaSettings.outerObject.scrollLeft() + pixelsPerScroll); + }, autoScrollRefresh); + } + }; + + divaInstance.stopScrolling = function() + { + if (!divaSettings.currentlyAutoScrolling) + { + console.warn("You are trying to stop autoscrolling, but it is not currently active."); + return; + } + + $("#" + divaSettings.ID + "autoscroll-toggle").text("Turn on"); + if (disableManualScroll) + { + divaInstance.enableScrollable(); + } + + divaSettings.currentlyAutoScrolling = false; + clearInterval(divaSettings.autoScrollInterval); + }; + + divaInstance.toggleScrolling = function() + { + divaSettings.currentlyAutoScrolling ? divaInstance.stopScrolling() : divaInstance.startScrolling(); + }; + + divaInstance.changeRefresh = function(newRefresh) + { + autoScrollRefresh = newRefresh; + updatePixelsPerScroll(); + }; + + divaInstance.changeScrollSpeed = function(newSpeed) + { + scrollSpeed = newSpeed; + updatePixelsPerScroll(); + + $("#" + divaSettings.ID + "autoscroll-pps").val(log10(scrollSpeed)); + if (divaSettings.currentlyAutoScrolling) + { + restartScrollingInterval(); + } + }; + + var updatePixelsPerScroll = function() + { + autoScrollRefresh = defaultAutoRefresh; + pixelsPerScroll = scrollSpeed / (1000 / autoScrollRefresh); + + //should be minimum of one otherwise it won't change the actual value + //user can change autoscrollrefresh or scrollspeed; this may overwrite autoScrollRefresh + if (pixelsPerScroll < 1) + { + autoScrollRefresh = autoScrollRefresh * (1 / pixelsPerScroll); + pixelsPerScroll = scrollSpeed / (1000 / autoScrollRefresh); + } + }; + + divaInstance.disableManualScroll = function() + { + disableManualScroll = true; + if (divaSettings.currentlyAutoScrolling) + { + divaInstance.disableScrollable(); + } + }; + + divaInstance.enableManualScroll = function() + { + disableManualScroll = false; + if (divaSettings.currentlyAutoScrolling) + { + divaInstance.enableScrollable(); + } + }; + + divaSettings.currentlyAutoScrolling = false; + divaSettings.autoScrollInterval = ""; + + disableManualScroll = divaSettings.disableManualScroll || false; + autoScrollRefresh = divaSettings.autoScrollRefresh || 50; + defaultAutoRefresh = autoScrollRefresh; + + divaInstance.changeScrollSpeed((divaSettings.scrollSpeed || 10)); + + $(window).on('keyup', function(e) + { + if (e.shiftKey && e.keyCode === 32) + { + divaInstance.toggleScrolling(); + } + }); + + if (!divaSettings.disableAutoscrollPrefs) + { + var setPosition = function(isFullscreen) + { + if (divaSettings.inFullscreen) + { + var fullscreenTools = $(divaSettings.selector + 'tools'); + var toolsMargin = fullscreenTools.css('right'); + settings.jqObj.css({ + 'right': toolsMargin, + 'margin-right': 0, + 'top': fullscreenTools.offset().top + fullscreenTools.outerHeight() + 15 + }); + } + else + { + settings.jqObj.css({ + 'right': $(window).width() - (divaSettings.outerObject.offset().left + divaSettings.outerObject.outerWidth()) + divaSettings.scrollbarWidth, + 'margin-right': '.6em' + }); + settings.jqObj.offset({'top': divaSettings.outerObject.offset().top + 1}); + } + } + + diva.Events.subscribe('ModeDidSwitch', setPosition); + + diva.Events.subscribe('ViewerDidLoad', function(s) + { + var autoscrollPrefsString = + "
    " + + "Autoscrolling options:
    " + + "Speed:" + + "
    " + + "Allow manual scroll:" + + "
    " + + "" + + "
    "; + $("#" + divaSettings.ID + "page-nav").before("
    "); + $("body").prepend(autoscrollPrefsString); + + $("#" + divaSettings.ID + "autoscroll-pps").on('change', function(e) + { + divaInstance.changeScrollSpeed(Math.pow(10, e.target.value)); + }); + + $("#" + divaSettings.ID + "autoscroll-manual").on('change', function(e) + { + e.target.checked ? divaInstance.enableManualScroll() : divaInstance.disableManualScroll(); + }); + + $("#" + divaSettings.ID + "autoscroll-toggle").on('click', divaInstance.toggleScrolling); + + $("#" + divaSettings.ID + "autoscroll-icon").on('click', function(e) + { + settings.jqObj = $("#" + divaSettings.ID + "autoscroll-prefs"); + + if (settings.jqObj.css('display') === 'none') + { + settings.jqObj.css({'display': 'block'}); + + setPosition(divaSettings.inFullscreen); + + } + else + { + settings.jqObj.css('display', 'none'); + } + }); + }); + } + }, + pluginName: 'autoscroll', + titleText: 'Automatically scrolls page along primary axis' + }; + return retval; + })()); +})(jQuery); \ No newline at end of file diff --git a/source/js/plugins/highlight.js b/source/js/plugins/highlight.js index 5d80679c..3a04fa78 100644 --- a/source/js/plugins/highlight.js +++ b/source/js/plugins/highlight.js @@ -31,7 +31,7 @@ Allows you to highlight regions of a page image @param pageIdx The page index of the page that is to be highlighted @param filename The image filename of the page - @param pageSelector The + @param pageSelector The selector for the page (unused here) */ function _highlight(pageIdx, filename, pageSelector) { @@ -57,11 +57,11 @@ Allows you to highlight regions of a page image var currentWidth = pageObj.clientWidth; var widthProportion = maxZoomWidth / currentWidth; zoomDifference = Math.log(widthProportion) / Math.log(2); - } + } else { zoomDifference = maxZoom - divaInstance.getZoomLevel(); - } + } var j = regions.length; while (j--) @@ -86,7 +86,7 @@ Allows you to highlight regions of a page image pageObj.appendChild(box); } } - diva.Events.publish("HighlightCompleted"); + diva.Events.publish("HighlightCompleted", [pageIdx, filename, pageSelector]); } // subscribe the highlight method to the page change notification @@ -151,7 +151,7 @@ Allows you to highlight regions of a page image var j = pageIdxs.length; while (j--) { - divaInstance.highlightOnPage(pageIdxs[j], regions, colour, divClass); + divaInstance.highlightOnPage(pageIdxs[j], regions[j], colour, divClass); } }; @@ -185,14 +185,96 @@ Allows you to highlight regions of a page image 'regions': regions, 'colour': colour, 'divClass': divClass }; - // Since the highlighting won't take place until the viewer is scrolled - // to a new page we should explicitly call the _highlight method for visible page. - // (only if the current page is the one to be highlighted) - if (divaInstance.isPageInViewport(pageIdx)) + + //Highlights are created on load; create them for all loaded pages now + if (divaInstance.isPageInDOM(pageIdx)) { _highlight(pageIdx, null, null); } + return true; + }; + + /* + Jumps to a highlight somewhere in the document. + @param divID The ID of the div to jump to. This ID must be attached to the div using .highlightOnPage(s) as the highlight may not be appended to the DOM. + */ + divaInstance.gotoHighlight = function(divID) + { + var page; + var thisDiv; + var centerYOfDiv; + var centerXOfDiv; + + var highlightsObj = divaSettings.parentObject.data('highlights'); + var highlightFound = false; //used to break both loops + + //see if it exists in the DOM already first + if (document.getElementById(divID) !== null) + { + page = parseInt(document.getElementById(divID).parentNode.getAttribute('data-index'), 10); + + var numDivs = highlightsObj[page].regions.length; + while (numDivs--) + { + if (highlightsObj[page].regions[numDivs].divID === divID) + { + thisDiv = highlightsObj[page].regions[numDivs]; + centerYOfDiv = parseFloat(thisDiv.uly) + parseFloat(thisDiv.height) / 2; + centerXOfDiv = parseFloat(thisDiv.ulx) + parseFloat(thisDiv.width) / 2; + + highlightFound = true; + break; + } + } + } + else + { + var pageArr = Object.keys(highlightsObj); + var pageIdx = pageArr.length; + while (pageIdx--) + { + var regionArr = highlightsObj[pageArr[pageIdx]].regions; + var arrIndex = regionArr.length; + + while (arrIndex--) + { + if (regionArr[arrIndex].divID === divID) + { + page = pageArr[pageIdx]; + thisDiv = regionArr[arrIndex]; + centerYOfDiv = parseFloat(thisDiv.uly) + parseFloat(thisDiv.height) / 2; + centerXOfDiv = parseFloat(thisDiv.ulx) + parseFloat(thisDiv.width) / 2; + + highlightFound = true; + break; + } + } + + if (highlightFound) break; + } + } + + if (!highlightFound) + { + console.warn("Diva just tried to find a highlight that doesn't exist."); + return false; + } + + var outerObject = divaInstance.getSettings().outerObject; + + var desiredY = divaInstance.translateFromMaxZoomLevel(centerYOfDiv); + var desiredX = divaInstance.translateFromMaxZoomLevel(centerXOfDiv); + + divaInstance.gotoPageByIndex(page); + var currentTop = outerObject.scrollTop() + desiredY - (outerObject.height() / 2) + divaSettings.verticalPadding; + var currentLeft = outerObject.scrollLeft() + desiredX - (outerObject.width() / 2) + divaSettings.horizontalPadding; + + outerObject.scrollTop(currentTop); + outerObject.scrollLeft(currentLeft); + + divaSettings.currentHighlight = divID; + return true; }; diff --git a/source/js/utils.js b/source/js/utils.js index 93e268b0..f2e971c6 100644 --- a/source/js/utils.js +++ b/source/js/utils.js @@ -755,18 +755,18 @@ var diva = (function() { return pub; }()); -var multiDiva; - -var multiDivaController = function () +//Used to keep track of whether Diva was last clicked or which Diva was last clicked when there are multiple +var activeDivaController = function () { var active; + //global click listener $(document).on('click', function(e) { updateActive($(e.target)); }); - //parameter should already be selected in jQuery + //parameter should already be a jQuery selector var updateActive = function (target) { var nearestOuter; @@ -774,47 +774,50 @@ var multiDivaController = function () //these will find 0 or 1 objects, never more var findOuter = target.find('.diva-outer'); var closestOuter = target.closest('.diva-outer'); + var outers = document.getElementsByClassName('diva-outer'); + var outerLen = outers.length; + var idx; - if (findOuter.length > 0) //clicked on something that was not either a parent or sibling of diva-outer + //clicked on something that was not either a parent or sibling of a diva-outer + if (findOuter.length > 0) { nearestOuter = findOuter; } - else if (closestOuter.length > 0) //clicked on something that was a child of diva-outer + //clicked on something that was a child of a diva-outer + else if (closestOuter.length > 0) { nearestOuter = closestOuter; } - else //clicked on something unrelated + //clicked on something that was not in any Diva tree + else { + //deactivate everything and return + for (idx = 0; idx < outerLen; idx++) + { + $(outers[idx].parentElement).data('diva').deactivate(); + } return; } - //activate this one + //if we found one, activate it... nearestOuter.parent().data('diva').activate(); active = nearestOuter.parent(); - //deactivate all the others - var curOuter = $(".diva-outer").length; - while (curOuter--) + //...and deactivate all the others + outers = document.getElementsByClassName('diva-outer'); + for(idx = 0; idx < outerLen; idx++) { - if ($($(".diva-outer")[curOuter]).attr('id') != nearestOuter.attr('id')) - $($(".diva-outer")[curOuter]).parent().data('diva').deactivate(); + //getAttribute to attr - comparing DOM element to jQuery element + if (outers[idx].getAttribute('id') != nearestOuter.attr('id')) + $(outers[idx].parentElement).data('diva').deactivate(); } }; + //public accessor in case. Will return a jQuery selector. this.getActive = function() { return active; }; }; -diva.Events.subscribe("ViewerDidLoad", function(settings) -{ - if($(".diva-outer").length > 1){ - //make sure there's only one active diva; deactivate any newer ones - this.deactivate(); - - //create the controller if it doesn't already exist - if(!multiDiva) - multiDiva = new multiDivaController(); - } -}); \ No newline at end of file +var activeDiva = new activeDivaController(); \ No newline at end of file diff --git a/source/processing/generate_json.py b/source/processing/generate_json.py index b7c0a338..b23fe1ae 100644 --- a/source/processing/generate_json.py +++ b/source/processing/generate_json.py @@ -87,13 +87,24 @@ def __generate(self): for j in xrange(lowest_max_zoom + 1): h = self.__incorporate_zoom(im['mx_h'], lowest_max_zoom - j) w = self.__incorporate_zoom(im['mx_w'], lowest_max_zoom - j) - c = int(math.ceil(w / 256.)) - r = int(math.ceil(h / 256.)) + # if the dimensions of the original image are an exact multiple of 256 + # we need to check whether the remainder will be less than 1 pixel. If so + # we round down; otherwise, we round up. + if w % 256 < 1: + c = int(math.floor(w / 256.)) + else: + c = int(math.ceil(w / 256.)) + + if h % 256 < 1: + r = int(math.floor(h / 256.)) + else: + r = int(math.ceil(h / 256.)) + page_data.append({ 'c': c, 'r': r, - 'h': h, - 'w': w + 'h': math.floor(h), + 'w': math.floor(w) }) t_wid[j] = t_wid[j] + w diff --git a/source/processing/process.py b/source/processing/process.py index e99bdf4c..6aee84f3 100644 --- a/source/processing/process.py +++ b/source/processing/process.py @@ -89,6 +89,7 @@ def __init__(self, input_directory, output_directory, data_output_directory, **k sys.exit(-1) if self.image_type == "tiff": + self.extension = "tiff" try: from vipsCC import VImage except ImportError as e: @@ -96,6 +97,7 @@ def __init__(self, input_directory, output_directory, data_output_directory, **k sys.exit(-1) elif self.image_type == "jpeg": + self.extension = "jp2" if not os.path.exists(self.kdu_compress_location): print(("You have specified JP2 as the output format, but do not have the kdu_compress executable installed at {0}.").format(self.kdu_compress_location)) print("If this path is incorrect, please specify an alternate location using the '-k (location)' command line option for this script.") @@ -122,7 +124,7 @@ def convert(self): tdir = tempfile.mkdtemp() input_file = os.path.join(tdir, "{0}.tiff".format(name)) - output_file = os.path.join(self.output_directory, "{0}.{1}".format(name, self.image_type)) + output_file = os.path.join(self.output_directory, "{0}.{1}".format(name, self.extension)) if self.verbose: print("Using ImageMagick to pre-convert {0} to TIFF".format(image)) diff --git a/tests/run.js b/tests/run.js index 5df67593..70ca5bdb 100644 --- a/tests/run.js +++ b/tests/run.js @@ -51,7 +51,7 @@ else var page = require('webpage').create(); -// patch to remove get/setState tests from Travis CI build due to off-by-one pixel error when run in Travis +// patch to remove get/setState tests from Travis CI/Ubuntu builds due to off-by-one pixel error when run in Linux var env = system.env; var isTravis = false; @@ -61,6 +61,8 @@ for (var key in env) isTravis = true; } +if (!isTravis) isTravis = navigator.appVersion.indexOf("Linux") != -1; + // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") page.onConsoleMessage = function(msg) { console.log(msg); diff --git a/tests/unit/settings.js b/tests/unit/settings.js index c3141e93..ef4b495a 100644 --- a/tests/unit/settings.js +++ b/tests/unit/settings.js @@ -20,7 +20,7 @@ asyncTest("adaptivePadding disabled, fixedPadding set", function () { adaptivePadding: 0, fixedPadding: 11, onReady: function (settings) { - equal(settings.verticalPadding, 40, "Vertical padding should be 40 (the minimum)"); + equal(settings.verticalPadding, 40, "Vertical padding should be 40 (the minimum with plugins enabled)"); equal(settings.horizontalPadding, 11, "Horizontal padding should be 11 (fixedPadding)"); start(); } diff --git a/tests/utils.js b/tests/utils.js index b129f500..7e9edea8 100644 --- a/tests/utils.js +++ b/tests/utils.js @@ -4,8 +4,8 @@ // Allows you to clone, create a document viewer on, then remove an element $.tempDiva = function (settings) { // If the divaserveURL, imageDir, iconPath and iipServerURL settings aren't defined, define them - settings.imageDir = settings.imageDir || "/mnt/images/beromunster"; - settings.iipServerURL = settings.iipServerURL || "http://coltrane.music.mcgill.ca/fcgi-bin/iipsrv.fcgi"; + settings.imageDir = settings.imageDir || "/srv/images/beromunster"; + settings.iipServerURL = settings.iipServerURL || "http://diva.simssa.ca/fcgi-bin/iipsrv.fcgi"; settings.iconPath = settings.iconPath || "../build/img/"; settings.objectData = settings.objectData || "../demo/beromunster.json"; settings.enableCanvas = settings.enableCanvas || true;