--- /dev/null
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+* {
+ padding: 0;
+ margin: 0;
+}
+
+html {
+ height: 100%;
+}
+
+body {
+ height: 100%;
+ background-color: #404040;
+ background-image: url(../extlib/pdf.js/web/images/texture.png);
+}
+
+body,
+input,
+button,
+select {
+ font: message-box;
+}
+
+.hidden {
+ display: none;
+}
+[hidden] {
+ display: none !important;
+}
+
+#viewerContainer:-webkit-full-screen {
+ top: 0px;
+ border-top: 2px solid transparent;
+ background-color: #404040;
+ background-image: url(../extlib/pdf.js/web/images/texture.png);
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ cursor: none;
+}
+
+#viewerContainer:-moz-full-screen {
+ top: 0px;
+ border-top: 2px solid transparent;
+ background-color: #404040;
+ background-image: url(../extlib/pdf.js/web/images/texture.png);
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ cursor: none;
+}
+
+#viewerContainer:fullscreen {
+ top: 0px;
+ border-top: 2px solid transparent;
+ background-color: #404040;
+ background-image: url(../extlib/pdf.js/web/images/texture.png);
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ cursor: none;
+}
+
+
+:-webkit-full-screen .page {
+ margin-bottom: 100%;
+}
+
+:-moz-full-screen .page {
+ margin-bottom: 100%;
+}
+
+:fullscreen .page {
+ margin-bottom: 100%;
+}
+
+#viewerContainer.presentationControls {
+ cursor: default;
+}
+
+/* outer/inner center provides horizontal center */
+html[dir='ltr'] .outerCenter {
+ float: right;
+ position: relative;
+ right: 50%;
+}
+html[dir='rtl'] .outerCenter {
+ float: left;
+ position: relative;
+ left: 50%;
+}
+html[dir='ltr'] .innerCenter {
+ float: right;
+ position: relative;
+ right: -50%;
+}
+html[dir='rtl'] .innerCenter {
+ float: left;
+ position: relative;
+ left: -50%;
+}
+
+#outerContainer {
+ width: 100%;
+ height: 100%;
+}
+
+#sidebarContainer {
+ left: 0;
+ right: 0;
+ height: 200px;
+ visibility: hidden;
+ -webkit-transition-duration: 200ms;
+ -webkit-transition-timing-function: ease;
+ -moz-transition-duration: 200ms;
+ -moz-transition-timing-function: ease;
+ -ms-transition-duration: 200ms;
+ -ms-transition-timing-function: ease;
+ -o-transition-duration: 200ms;
+ -o-transition-timing-function: ease;
+ transition-duration: 200ms;
+ transition-timing-function: ease;
+
+}
+html[dir='ltr'] #sidebarContainer {
+ -webkit-transition-property: top;
+ -moz-transition-property: top;
+ -ms-transition-property: top;
+ -o-transition-property: top;
+ transition-property: top;
+ top: -200px;
+}
+html[dir='rtl'] #sidebarContainer {
+ -webkit-transition-property: top;
+ -ms-transition-property: top;
+ -o-transition-property: top;
+ transition-property: top;
+ top: -200px;
+}
+
+#outerContainer.sidebarMoving > #sidebarContainer,
+#outerContainer.sidebarOpen > #sidebarContainer {
+ visibility: visible;
+}
+html[dir='ltr'] #outerContainer.sidebarOpen > #sidebarContainer {
+ left: 0px;
+}
+html[dir='rtl'] #outerContainer.sidebarOpen > #sidebarContainer {
+ right: 0px;
+}
+
+#mainContainer {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ min-width: 320px;
+ -webkit-transition-duration: 200ms;
+ -webkit-transition-timing-function: ease;
+ -moz-transition-duration: 200ms;
+ -moz-transition-timing-function: ease;
+ -ms-transition-duration: 200ms;
+ -ms-transition-timing-function: ease;
+ -o-transition-duration: 200ms;
+ -o-transition-timing-function: ease;
+ transition-duration: 200ms;
+ transition-timing-function: ease;
+}
+html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
+ -webkit-transition-property: left;
+ -moz-transition-property: left;
+ -ms-transition-property: left;
+ -o-transition-property: left;
+ transition-property: left;
+ left: 200px;
+}
+html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
+ -webkit-transition-property: right;
+ -moz-transition-property: right;
+ -ms-transition-property: right;
+ -o-transition-property: right;
+ transition-property: right;
+ right: 200px;
+}
+
+#sidebarContent {
+ top: 32px;
+ bottom: 0;
+ overflow: auto;
+ height: 200px;
+
+ background-color: hsla(0,0%,0%,.1);
+ box-shadow: inset -1px 0 0 hsla(0,0%,0%,.25);
+}
+html[dir='ltr'] #sidebarContent {
+ left: 0;
+}
+html[dir='rtl'] #sidebarContent {
+ right: 0;
+}
+
+#viewerContainer {
+ overflow: auto;
+ box-shadow: inset 1px 0 0 hsla(0,0%,100%,.05);
+ top: 32px;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: 480px;
+ width: 640px;
+}
+
+.toolbar {
+ left: 0;
+ right: 0;
+ height: 32px;
+ z-index: 9999;
+ cursor: default;
+}
+
+#toolbarContainer {
+ width: 100%;
+}
+
+#toolbarSidebar {
+ width: 200px;
+ height: 32px;
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ -webkit-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ -moz-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ -ms-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ -o-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
+ box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.25),
+
+ inset 0 -1px 0 hsla(0,0%,100%,.05),
+ 0 1px 0 hsla(0,0%,0%,.15),
+ 0 0 1px hsla(0,0%,0%,.1);
+}
+
+#toolbarViewer, .findbar {
+ position: relative;
+ height: 32px;
+ background-color: #474747; /* IE9 */
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ -webkit-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ -moz-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ -ms-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ -o-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+ background-image: url(../extlib/pdf.js/web/images/texture.png),
+ linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+ box-shadow: inset 1px 0 0 hsla(0,0%,100%,.08),
+ inset 0 1px 1px hsla(0,0%,0%,.15),
+ inset 0 -1px 0 hsla(0,0%,100%,.05),
+ 0 1px 0 hsla(0,0%,0%,.15),
+ 0 1px 1px hsla(0,0%,0%,.1);
+}
+
+.findbar {
+ top: 64px;
+ z-index: 10000;
+ height: 32px;
+
+ min-width: 16px;
+ padding: 0px 6px 0px 6px;
+ margin: 4px 2px 4px 2px;
+ color: hsl(0,0%,85%);
+ font-size: 12px;
+ line-height: 14px;
+ text-align: left;
+ cursor: default;
+}
+
+html[dir='ltr'] .findbar {
+ left: 68px;
+}
+
+html[dir='rtl'] .findbar {
+ right: 68px;
+}
+
+.findbar label {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+}
+
+#findInput[data-status="pending"] {
+ background-image: url(../extlib/pdf.js/web/images/loading-small.png);
+ background-repeat: no-repeat;
+ background-position: right;
+}
+
+.doorHanger {
+ border: 1px solid hsla(0,0%,0%,.5);
+ border-radius: 2px;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
+}
+.doorHanger:after, .doorHanger:before {
+ bottom: 100%;
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ pointer-events: none;
+}
+.doorHanger:after {
+ border-bottom-color: hsla(0,0%,32%,.99);
+ border-width: 8px;
+}
+.doorHanger:before {
+ border-bottom-color: hsla(0,0%,0%,.5);
+ border-width: 9px;
+}
+
+html[dir='ltr'] .doorHanger:after {
+ left: 13px;
+ margin-left: -8px;
+}
+
+html[dir='ltr'] .doorHanger:before {
+ left: 13px;
+ margin-left: -9px;
+}
+
+html[dir='rtl'] .doorHanger:after {
+ right: 13px;
+ margin-right: -8px;
+}
+
+html[dir='rtl'] .doorHanger:before {
+ right: 13px;
+ margin-right: -9px;
+}
+
+#findMsg {
+ font-style: italic;
+ color: #A6B7D0;
+}
+
+.notFound {
+ background-color: rgb(255, 137, 153);
+}
+
+html[dir='ltr'] #toolbarViewerLeft {
+ margin-left: -1px;
+}
+html[dir='rtl'] #toolbarViewerRight {
+ margin-left: -1px;
+}
+
+
+html[dir='ltr'] #toolbarViewerLeft,
+html[dir='rtl'] #toolbarViewerRight {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+html[dir='ltr'] #toolbarViewerRight,
+html[dir='rtl'] #toolbarViewerLeft {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+html[dir='ltr'] #toolbarViewerLeft > *,
+html[dir='ltr'] #toolbarViewerMiddle > *,
+html[dir='ltr'] #toolbarViewerRight > *,
+html[dir='ltr'] .findbar > * {
+ float: left;
+}
+html[dir='rtl'] #toolbarViewerLeft > *,
+html[dir='rtl'] #toolbarViewerMiddle > *,
+html[dir='rtl'] #toolbarViewerRight > *,
+html[dir='rtl'] .findbar > * {
+ float: right;
+}
+
+html[dir='ltr'] .splitToolbarButton {
+ margin: 3px 2px 4px 0;
+ display: inline-block;
+}
+html[dir='rtl'] .splitToolbarButton {
+ margin: 3px 0 4px 2px;
+ display: inline-block;
+}
+html[dir='ltr'] .splitToolbarButton > .toolbarButton {
+ border-radius: 0;
+ float: left;
+}
+html[dir='rtl'] .splitToolbarButton > .toolbarButton {
+ border-radius: 0;
+ float: right;
+}
+
+.toolbarButton {
+ border: 0 none;
+ background-color: rgba(0, 0, 0, 0);
+ width: 32px;
+ height: 25px;
+}
+
+.toolbarButton > span {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+}
+
+.toolbarButton[disabled] {
+ opacity: .5;
+}
+
+.toolbarButton.group {
+ margin-right: 0;
+}
+
+.splitToolbarButton.toggled .toolbarButton {
+ margin: 0;
+}
+
+.splitToolbarButton:hover > .toolbarButton,
+.splitToolbarButton:focus > .toolbarButton,
+.splitToolbarButton.toggled > .toolbarButton,
+.toolbarButton.textButton {
+ background-color: hsla(0,0%,0%,.12);
+ background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-clip: padding-box;
+ border: 1px solid hsla(0,0%,0%,.35);
+ border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
+ box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
+ 0 0 1px hsla(0,0%,100%,.15) inset,
+ 0 1px 0 hsla(0,0%,100%,.05);
+ -webkit-transition-property: background-color, border-color, box-shadow;
+ -webkit-transition-duration: 150ms;
+ -webkit-transition-timing-function: ease;
+ -moz-transition-property: background-color, border-color, box-shadow;
+ -moz-transition-duration: 150ms;
+ -moz-transition-timing-function: ease;
+ -ms-transition-property: background-color, border-color, box-shadow;
+ -ms-transition-duration: 150ms;
+ -ms-transition-timing-function: ease;
+ -o-transition-property: background-color, border-color, box-shadow;
+ -o-transition-duration: 150ms;
+ -o-transition-timing-function: ease;
+ transition-property: background-color, border-color, box-shadow;
+ transition-duration: 150ms;
+ transition-timing-function: ease;
+
+}
+.splitToolbarButton > .toolbarButton:hover,
+.splitToolbarButton > .toolbarButton:focus,
+.dropdownToolbarButton:hover,
+.toolbarButton.textButton:hover,
+.toolbarButton.textButton:focus {
+ background-color: hsla(0,0%,0%,.2);
+ box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
+ 0 0 1px hsla(0,0%,100%,.15) inset,
+ 0 0 1px hsla(0,0%,0%,.05);
+ z-index: 199;
+}
+html[dir='ltr'] .splitToolbarButton > .toolbarButton:first-child,
+html[dir='rtl'] .splitToolbarButton > .toolbarButton:last-child {
+ position: relative;
+ margin: 0;
+ margin-right: -1px;
+ border-top-left-radius: 2px;
+ border-bottom-left-radius: 2px;
+ border-right-color: transparent;
+}
+html[dir='ltr'] .splitToolbarButton > .toolbarButton:last-child,
+html[dir='rtl'] .splitToolbarButton > .toolbarButton:first-child {
+ position: relative;
+ margin: 0;
+ margin-left: -1px;
+ border-top-right-radius: 2px;
+ border-bottom-right-radius: 2px;
+ border-left-color: transparent;
+}
+.splitToolbarButtonSeparator {
+ padding: 8px 0;
+ width: 1px;
+ background-color: hsla(0,0%,00%,.5);
+ z-index: 99;
+ box-shadow: 0 0 0 1px hsla(0,0%,100%,.08);
+ display: inline-block;
+ margin: 5px 0;
+}
+html[dir='ltr'] .splitToolbarButtonSeparator {
+ float: left;
+}
+html[dir='rtl'] .splitToolbarButtonSeparator {
+ float: right;
+}
+.splitToolbarButton:hover > .splitToolbarButtonSeparator,
+.splitToolbarButton.toggled > .splitToolbarButtonSeparator {
+ padding: 12px 0;
+ margin: 1px 0;
+ box-shadow: 0 0 0 1px hsla(0,0%,100%,.03);
+ -webkit-transition-property: padding;
+ -webkit-transition-duration: 10ms;
+ -webkit-transition-timing-function: ease;
+ -moz-transition-property: padding;
+ -moz-transition-duration: 10ms;
+ -moz-transition-timing-function: ease;
+ -ms-transition-property: padding;
+ -ms-transition-duration: 10ms;
+ -ms-transition-timing-function: ease;
+ -o-transition-property: padding;
+ -o-transition-duration: 10ms;
+ -o-transition-timing-function: ease;
+ transition-property: padding;
+ transition-duration: 10ms;
+ transition-timing-function: ease;
+}
+
+.toolbarButton,
+.dropdownToolbarButton {
+ min-width: 16px;
+ padding: 2px 6px 0;
+ border: 1px solid transparent;
+ border-radius: 2px;
+ color: hsl(0,0%,95%);
+ font-size: 12px;
+ line-height: 14px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ /* Opera does not support user-select, use <... unselectable="on"> instead */
+ cursor: default;
+ -webkit-transition-property: background-color, border-color, box-shadow;
+ -webkit-transition-duration: 150ms;
+ -webkit-transition-timing-function: ease;
+ -moz-transition-property: background-color, border-color, box-shadow;
+ -moz-transition-duration: 150ms;
+ -moz-transition-timing-function: ease;
+ -ms-transition-property: background-color, border-color, box-shadow;
+ -ms-transition-duration: 150ms;
+ -ms-transition-timing-function: ease;
+ -o-transition-property: background-color, border-color, box-shadow;
+ -o-transition-duration: 150ms;
+ -o-transition-timing-function: ease;
+ transition-property: background-color, border-color, box-shadow;
+ transition-duration: 150ms;
+ transition-timing-function: ease;
+}
+
+html[dir='ltr'] .toolbarButton,
+html[dir='ltr'] .dropdownToolbarButton {
+ margin: 3px 2px 4px 0;
+}
+html[dir='rtl'] .toolbarButton,
+html[dir='rtl'] .dropdownToolbarButton {
+ margin: 3px 0 4px 2px;
+}
+
+.toolbarButton:hover,
+.toolbarButton:focus,
+.dropdownToolbarButton {
+ background-color: hsla(0,0%,0%,.12);
+ background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-clip: padding-box;
+ border: 1px solid hsla(0,0%,0%,.35);
+ border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
+ box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
+ 0 0 1px hsla(0,0%,100%,.15) inset,
+ 0 1px 0 hsla(0,0%,100%,.05);
+}
+
+.toolbarButton:hover:active,
+.dropdownToolbarButton:hover:active {
+ background-color: hsla(0,0%,0%,.2);
+ background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.4) hsla(0,0%,0%,.45);
+ box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
+ 0 0 1px hsla(0,0%,0%,.2) inset,
+ 0 1px 0 hsla(0,0%,100%,.05);
+ -webkit-transition-property: background-color, border-color, box-shadow;
+ -webkit-transition-duration: 10ms;
+ -webkit-transition-timing-function: linear;
+ -moz-transition-property: background-color, border-color, box-shadow;
+ -moz-transition-duration: 10ms;
+ -moz-transition-timing-function: linear;
+ -ms-transition-property: background-color, border-color, box-shadow;
+ -ms-transition-duration: 10ms;
+ -ms-transition-timing-function: linear;
+ -o-transition-property: background-color, border-color, box-shadow;
+ -o-transition-duration: 10ms;
+ -o-transition-timing-function: linear;
+ transition-property: background-color, border-color, box-shadow;
+ transition-duration: 10ms;
+ transition-timing-function: linear;
+}
+
+.toolbarButton.toggled,
+.splitToolbarButton.toggled > .toolbarButton.toggled {
+ background-color: hsla(0,0%,0%,.3);
+ background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.45) hsla(0,0%,0%,.5);
+ box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
+ 0 0 1px hsla(0,0%,0%,.2) inset,
+ 0 1px 0 hsla(0,0%,100%,.05);
+ -webkit-transition-property: background-color, border-color, box-shadow;
+ -webkit-transition-duration: 10ms;
+ -webkit-transition-timing-function: linear;
+ -moz-transition-property: background-color, border-color, box-shadow;
+ -moz-transition-duration: 10ms;
+ -moz-transition-timing-function: linear;
+ -ms-transition-property: background-color, border-color, box-shadow;
+ -ms-transition-duration: 10ms;
+ -ms-transition-timing-function: linear;
+ -o-transition-property: background-color, border-color, box-shadow;
+ -o-transition-duration: 10ms;
+ -o-transition-timing-function: linear;
+ transition-property: background-color, border-color, box-shadow;
+ transition-duration: 10ms;
+ transition-timing-function: linear;
+}
+
+.toolbarButton.toggled:hover:active,
+.splitToolbarButton.toggled > .toolbarButton.toggled:hover:active {
+ background-color: hsla(0,0%,0%,.4);
+ border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.5) hsla(0,0%,0%,.55);
+ box-shadow: 0 1px 1px hsla(0,0%,0%,.2) inset,
+ 0 0 1px hsla(0,0%,0%,.3) inset,
+ 0 1px 0 hsla(0,0%,100%,.05);
+}
+
+.dropdownToolbarButton {
+ width: 120px;
+ max-width: 120px;
+ padding: 3px 2px 2px;
+ overflow: hidden;
+ background: url(../extlib/pdf.js/web/images/toolbarButton-menuArrows.png) no-repeat;
+}
+html[dir='ltr'] .dropdownToolbarButton {
+ background-position: 95%;
+}
+html[dir='rtl'] .dropdownToolbarButton {
+ background-position: 5%;
+}
+
+.dropdownToolbarButton > select {
+ -webkit-appearance: none;
+ -moz-appearance: none; /* in the future this might matter, see bugzilla bug #649849 */
+ min-width: 140px;
+ font-size: 12px;
+ color: hsl(0,0%,95%);
+ margin: 0;
+ padding: 0;
+ border: none;
+ background: rgba(0,0,0,0); /* Opera does not support 'transparent' <select> background */
+}
+
+.dropdownToolbarButton > select > option {
+ background: hsl(0,0%,24%);
+}
+
+#customScaleOption {
+ display: none;
+}
+
+#pageWidthOption {
+ border-bottom: 1px rgba(255, 255, 255, .5) solid;
+}
+
+html[dir='ltr'] .splitToolbarButton:first-child,
+html[dir='ltr'] .toolbarButton:first-child,
+html[dir='rtl'] .splitToolbarButton:last-child,
+html[dir='rtl'] .toolbarButton:last-child {
+ margin-left: 4px;
+}
+html[dir='ltr'] .splitToolbarButton:last-child,
+html[dir='ltr'] .toolbarButton:last-child,
+html[dir='rtl'] .splitToolbarButton:first-child,
+html[dir='rtl'] .toolbarButton:first-child {
+ margin-right: 4px;
+}
+
+.toolbarButtonSpacer {
+ width: 30px;
+ display: inline-block;
+ height: 1px;
+}
+
+.toolbarButtonFlexibleSpacer {
+ -webkit-box-flex: 1;
+ -moz-box-flex: 1;
+ min-width: 30px;
+}
+
+.toolbarButton#sidebarToggle::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-sidebarToggle.png);
+}
+
+html[dir='ltr'] #findPrevious {
+ margin-left: 3px;
+}
+html[dir='ltr'] #findNext {
+ margin-right: 3px;
+}
+
+html[dir='rtl'] #findPrevious {
+ margin-right: 3px;
+}
+html[dir='rtl'] #findNext {
+ margin-left: 3px;
+}
+
+html[dir='ltr'] .toolbarButton.findPrevious::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/findbarButton-previous.png);
+}
+
+html[dir='rtl'] .toolbarButton.findPrevious::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/findbarButton-previous-rtl.png);
+}
+
+html[dir='ltr'] .toolbarButton.findNext::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/findbarButton-next.png);
+}
+
+html[dir='rtl'] .toolbarButton.findNext::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/findbarButton-next-rtl.png);
+}
+
+html[dir='ltr'] .toolbarButton.pageUp::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-pageUp.png);
+}
+
+html[dir='rtl'] .toolbarButton.pageUp::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-pageUp-rtl.png);
+}
+
+html[dir='ltr'] .toolbarButton.pageDown::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-pageDown.png);
+}
+
+html[dir='rtl'] .toolbarButton.pageDown::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-pageDown-rtl.png);
+}
+
+.toolbarButton.zoomOut::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-zoomOut.png);
+}
+
+.toolbarButton.zoomIn::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-zoomIn.png);
+}
+
+.toolbarButton.fullscreen::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-fullscreen.png);
+}
+
+.toolbarButton.print::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-print.png);
+}
+
+.toolbarButton.openFile::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-openFile.png);
+}
+
+.toolbarButton.download::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-download.png);
+}
+
+.toolbarButton.bookmark {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ margin-top: 3px;
+ padding-top: 4px;
+}
+
+#viewBookmark[href='#'] {
+ opacity: .5;
+ pointer-events: none;
+}
+
+.toolbarButton.bookmark::before {
+ content: url(../extlib/pdf.js/web/images/toolbarButton-bookmark.png);
+}
+
+#viewThumbnail.toolbarButton::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-viewThumbnail.png);
+}
+
+#viewOutline.toolbarButton::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-viewOutline.png);
+}
+
+#viewFind.toolbarButton::before {
+ display: inline-block;
+ content: url(../extlib/pdf.js/web/images/toolbarButton-search.png);
+}
+
+
+.toolbarField {
+ padding: 3px 6px;
+ margin: 4px 0 4px 0;
+ border: 1px solid transparent;
+ border-radius: 2px;
+ background-color: hsla(0,0%,100%,.09);
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-clip: padding-box;
+ border: 1px solid hsla(0,0%,0%,.35);
+ border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
+ box-shadow: 0 1px 0 hsla(0,0%,0%,.05) inset,
+ 0 1px 0 hsla(0,0%,100%,.05);
+ color: hsl(0,0%,95%);
+ font-size: 12px;
+ line-height: 14px;
+ outline-style: none;
+ -moz-transition-property: background-color, border-color, box-shadow;
+ -moz-transition-duration: 150ms;
+ -moz-transition-timing-function: ease;
+}
+
+.toolbarField[type=checkbox] {
+ display: inline-block;
+ margin: 8px 0px;
+}
+
+.toolbarField.pageNumber {
+ min-width: 16px;
+ text-align: right;
+ width: 40px;
+}
+
+.toolbarField.pageNumber::-webkit-inner-spin-button,
+.toolbarField.pageNumber::-webkit-outer-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+
+.toolbarField:hover {
+ background-color: hsla(0,0%,100%,.11);
+ border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.43) hsla(0,0%,0%,.45);
+}
+
+.toolbarField:focus {
+ background-color: hsla(0,0%,100%,.15);
+ border-color: hsla(204,100%,65%,.8) hsla(204,100%,65%,.85) hsla(204,100%,65%,.9);
+}
+
+.toolbarLabel {
+ min-width: 16px;
+ padding: 3px 6px 3px 2px;
+ margin: 4px 2px 4px 0;
+ border: 1px solid transparent;
+ border-radius: 2px;
+ color: hsl(0,0%,85%);
+ font-size: 12px;
+ line-height: 14px;
+ text-align: left;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ cursor: default;
+}
+
+#thumbnailView {
+ top: 0;
+ bottom: 0;
+ padding: 10px 10px 0;
+ overflow: auto;
+}
+
+.thumbnail {
+ float: left;
+}
+
+.thumbnail:not([data-loaded]) {
+ border: 1px dashed rgba(255, 255, 255, 0.5);
+ margin-bottom: 10px;
+}
+
+.thumbnailImage {
+ -moz-transition-duration: 150ms;
+ border: 1px solid transparent;
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);
+ opacity: 0.8;
+ z-index: 99;
+}
+
+.thumbnailSelectionRing {
+ border-radius: 2px;
+ padding: 7px;
+ -moz-transition-duration: 150ms;
+}
+
+a:focus > .thumbnail > .thumbnailSelectionRing > .thumbnailImage,
+.thumbnail:hover > .thumbnailSelectionRing > .thumbnailImage {
+ opacity: .9;
+}
+
+a:focus > .thumbnail > .thumbnailSelectionRing,
+.thumbnail:hover > .thumbnailSelectionRing {
+ background-color: hsla(0,0%,100%,.15);
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-clip: padding-box;
+ box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
+ 0 0 1px hsla(0,0%,100%,.2) inset,
+ 0 0 1px hsla(0,0%,0%,.2);
+ color: hsla(0,0%,100%,.9);
+}
+
+.thumbnail.selected > .thumbnailSelectionRing > .thumbnailImage {
+ box-shadow: 0 0 0 1px hsla(0,0%,0%,.5);
+ opacity: 1;
+}
+
+.thumbnail.selected > .thumbnailSelectionRing {
+ background-color: hsla(0,0%,100%,.3);
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-clip: padding-box;
+ box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
+ 0 0 1px hsla(0,0%,100%,.1) inset,
+ 0 0 1px hsla(0,0%,0%,.2);
+ color: hsla(0,0%,100%,1);
+}
+
+#outlineView {
+ width: 192px;
+ top: 0;
+ bottom: 0;
+ padding: 4px 4px 0;
+ overflow: auto;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+}
+
+html[dir='ltr'] .outlineItem > .outlineItems {
+ margin-left: 20px;
+}
+
+html[dir='rtl'] .outlineItem > .outlineItems {
+ margin-right: 20px;
+}
+
+.outlineItem > a {
+ text-decoration: none;
+ display: inline-block;
+ min-width: 95%;
+ height: auto;
+ margin-bottom: 1px;
+ border-radius: 2px;
+ color: hsla(0,0%,100%,.8);
+ font-size: 13px;
+ line-height: 15px;
+ -moz-user-select: none;
+ white-space: normal;
+}
+
+html[dir='ltr'] .outlineItem > a {
+ padding: 2px 0 5px 10px;
+}
+
+html[dir='rtl'] .outlineItem > a {
+ padding: 2px 10px 5px 0;
+}
+
+.outlineItem > a:hover {
+ background-color: hsla(0,0%,100%,.02);
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-clip: padding-box;
+ box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
+ 0 0 1px hsla(0,0%,100%,.2) inset,
+ 0 0 1px hsla(0,0%,0%,.2);
+ color: hsla(0,0%,100%,.9);
+}
+
+.outlineItem.selected {
+ background-color: hsla(0,0%,100%,.08);
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-clip: padding-box;
+ box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
+ 0 0 1px hsla(0,0%,100%,.1) inset,
+ 0 0 1px hsla(0,0%,0%,.2);
+ color: hsla(0,0%,100%,1);
+}
+
+.noOutline,
+.noResults {
+ font-size: 12px;
+ color: hsla(0,0%,100%,.8);
+ font-style: italic;
+ cursor: default;
+}
+
+#findScrollView {
+ position: absolute;
+ top: 10px;
+ bottom: 10px;
+ left: 10px;
+ width: 280px;
+}
+
+#sidebarControls {
+ position:absolute;
+ width: 180px;
+ height: 32px;
+ left: 15px;
+ bottom: 35px;
+}
+
+canvas {
+ margin: auto;
+ display: block;
+}
+
+.page {
+ direction: ltr;
+ width: 816px;
+ height: 1056px;
+ margin: 1px auto -8px auto;
+ position: relative;
+ overflow: visible;
+ border: 9px solid transparent;
+ background-clip: content-box;
+ border-image: url(../extlib/pdf.js/web/images/shadow.png) 9 9 repeat;
+ background-color: white;
+}
+
+.page > a {
+ display: block;
+ position: absolute;
+}
+
+.page > a:hover {
+ opacity: 0.2;
+ background: #ff0;
+ box-shadow: 0px 2px 10px #ff0;
+}
+
+.loadingIcon {
+ position: absolute;
+ display: block;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ background: url('../extlib/pdf.js/web/images/loading-icon.gif') center no-repeat;
+}
+
+#loadingBox {
+ position: absolute;
+ top: 50%;
+ margin-top: -25px;
+ left: 0;
+ right: 0;
+ text-align: center;
+ color: #ddd;
+ font-size: 14px;
+}
+
+#loadingBar {
+ display: inline-block;
+ clear: both;
+ margin: 0px;
+ margin-top: 5px;
+ line-height: 0;
+ border-radius: 2px;
+ width: 200px;
+ height: 25px;
+
+ background-color: hsla(0,0%,0%,.3);
+ background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+ border: 1px solid #000;
+ box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
+ 0 0 1px hsla(0,0%,0%,.2) inset,
+ 0 0 1px 1px rgba(255, 255, 255, 0.1);
+}
+
+#loadingBar .progress {
+ display: inline-block;
+ float: left;
+
+ background: #666;
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2b2b2), color-stop(100%,#898989));
+ background: -webkit-linear-gradient(top, #b2b2b2 0%,#898989 100%);
+ background: -moz-linear-gradient(top, #b2b2b2 0%,#898989 100%);
+ background: -ms-linear-gradient(top, #b2b2b2 0%,#898989 100%);
+ background: -o-linear-gradient(top, #b2b2b2 0%,#898989 100%);
+ background: linear-gradient(top, #b2b2b2 0%,#898989 100%);
+
+ border-top-left-radius: 2px;
+ border-bottom-left-radius: 2px;
+
+ width: 0%;
+ height: 100%;
+}
+
+#loadingBar .progress.full {
+ border-top-right-radius: 2px;
+ border-bottom-right-radius: 2px;
+}
+
+#loadingBar .progress.indeterminate {
+ width: 100%;
+ height: 25px;
+ background-image: -moz-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040);
+ background-image: -webkit-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040);
+ background-image: -ms-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040);
+ background-image: -o-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040);
+ background-size: 75px 25px;
+ -moz-animation: progressIndeterminate 1s linear infinite;
+ -webkit-animation: progressIndeterminate 1s linear infinite;
+}
+
+@-moz-keyframes progressIndeterminate {
+ from { background-position: 0px 0px; }
+ to { background-position: 75px 0px; }
+}
+
+@-webkit-keyframes progressIndeterminate {
+ from { background-position: 0px 0px; }
+ to { background-position: 75px 0px; }
+}
+
+.textLayer {
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ color: #000;
+ font-family: sans-serif;
+ overflow: hidden;
+}
+
+.textLayer > div {
+ color: transparent;
+ position: absolute;
+ line-height: 1;
+ white-space: pre;
+ cursor: text;
+}
+
+.textLayer .highlight {
+ margin: -1px;
+ padding: 1px;
+
+ background-color: rgba(180, 0, 170, 0.2);
+ border-radius: 4px;
+}
+
+.textLayer .highlight.begin {
+ border-radius: 4px 0px 0px 4px;
+}
+
+.textLayer .highlight.end {
+ border-radius: 0px 4px 4px 0px;
+}
+
+.textLayer .highlight.middle {
+ border-radius: 0px;
+}
+
+.textLayer .highlight.selected {
+ background-color: rgba(0, 100, 0, 0.2);
+}
+
+/* TODO: file FF bug to support ::-moz-selection:window-inactive
+ so we can override the opaque grey background when the window is inactive;
+ see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
+::selection { background:rgba(0,0,255,0.3); }
+::-moz-selection { background:rgba(0,0,255,0.3); }
+
+.annotText > div {
+ z-index: 200;
+ position: absolute;
+ padding: 0.6em;
+ max-width: 20em;
+ background-color: #FFFF99;
+ box-shadow: 0px 2px 10px #333;
+ border-radius: 7px;
+}
+
+.annotText > img {
+ position: absolute;
+ opacity: 0.6;
+}
+
+.annotText > img:hover {
+ cursor: pointer;
+ opacity: 1;
+}
+
+.annotText > div > h1 {
+ font-size: 1.2em;
+ border-bottom: 1px solid #000000;
+ margin: 0px;
+}
+
+#errorWrapper {
+ background: none repeat scroll 0 0 #FF5555;
+ color: white;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 32px;
+ z-index: 1000;
+ padding: 3px;
+ font-size: 0.8em;
+}
+
+#errorMessageLeft {
+ float: left;
+}
+
+#errorMessageRight {
+ float: right;
+}
+
+#errorMoreInfo {
+ background-color: #FFFFFF;
+ color: black;
+ padding: 3px;
+ margin: 3px;
+ width: 98%;
+}
+
+.clearBoth {
+ clear: both;
+}
+
+.fileInput {
+ background: white;
+ color: black;
+ margin-top: 5px;
+}
+
+#PDFBug {
+ background: none repeat scroll 0 0 white;
+ border: 1px solid #666666;
+ position: fixed;
+ top: 32px;
+ right: 0;
+ bottom: 0;
+ font-size: 10px;
+ padding: 0;
+ width: 300px;
+}
+#PDFBug .controls {
+ background:#EEEEEE;
+ border-bottom: 1px solid #666666;
+ padding: 3px;
+}
+#PDFBug .panels {
+ bottom: 0;
+ left: 0;
+ overflow: auto;
+ position: absolute;
+ right: 0;
+ top: 27px;
+}
+#PDFBug button.active {
+ font-weight: bold;
+}
+.debuggerShowText {
+ background: none repeat scroll 0 0 yellow;
+ color: blue;
+ opacity: 0.3;
+}
+.debuggerHideText:hover {
+ background: none repeat scroll 0 0 yellow;
+ opacity: 0.3;
+}
+#PDFBug .stats {
+ font-family: courier;
+ font-size: 10px;
+ white-space: pre;
+}
+#PDFBug .stats .title {
+ font-weight: bold;
+}
+#PDFBug table {
+ font-size: 10px;
+}
+
+#viewer.textLayer-visible .textLayer > div,
+#viewer.textLayer-hover .textLayer > div:hover {
+ background-color: white;
+ color: black;
+}
+
+#viewer.textLayer-shadow .textLayer > div {
+ background-color: rgba(255,255,255, .6);
+ color: black;
+}
+
+@page {
+ margin: 0;
+}
+
+#printContainer {
+ display: none;
+}
+
+@media print {
+ /* Rules for browsers that don't support mozPrintCallback. */
+ #sidebarContainer, .toolbar, #loadingBox, #errorWrapper, .textLayer {
+ display: none;
+ }
+
+ #mainContainer, #viewerContainer, .page, .page canvas {
+ position: static;
+ padding: 0;
+ margin: 0;
+ }
+
+ .page {
+ float: left;
+ display: none;
+ box-shadow: none;
+ }
+
+ .page[data-loaded] {
+ display: block;
+ }
+
+ /* Rules for browsers that support mozPrintCallback */
+ body[data-mozPrintCallback] #outerContainer {
+ display: none;
+ }
+ body[data-mozPrintCallback] #printContainer {
+ display: block;
+ }
+ #printContainer canvas {
+ position: relative;
+ top: 0;
+ left: 0;
+ }
+}
+
+@media all and (max-width: 950px) {
+ html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter,
+ html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter {
+ float: left;
+ left: 180px;
+ }
+ html[dir='rtl'] #outerContainer.sidebarMoving .outerCenter,
+ html[dir='rtl'] #outerContainer.sidebarOpen .outerCenter {
+ float: right;
+ right: 180px;
+ }
+}
+
+@media all and (max-width: 770px) {
+ #sidebarContainer {
+ top: 33px;
+ z-index: 100;
+ }
+ #sidebarContent {
+ top: 32px;
+ background-color: hsla(0,0%,0%,.7);
+ }
+
+ html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
+ left: 0px;
+ }
+ html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
+ right: 0px;
+ }
+
+ html[dir='ltr'] .outerCenter {
+ float: left;
+ left: 180px;
+ }
+ html[dir='rtl'] .outerCenter {
+ float: right;
+ right: 180px;
+ }
+}
+
+@media all and (max-width: 600px) {
+ .hiddenSmallView {
+ display: none;
+ }
+ html[dir='ltr'] .outerCenter {
+ left: 156px;
+ }
+ html[dir='rtr'] .outerCenter {
+ right: 156px;
+ }
+ .toolbarButtonSpacer {
+ width: 0;
+ }
+}
+
+@media all and (max-width: 500px) {
+ #scaleSelectContainer, #pageNumberLabel {
+ display: none;
+ }
+}
+
--- /dev/null
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* globals PDFJS, PDFBug, FirefoxCom, Stats */
+
+'use strict';
+
+var DEFAULT_SCALE = 'auto';
+var DEFAULT_SCALE_DELTA = 1.1;
+var UNKNOWN_SCALE = 0;
+var CACHE_SIZE = 20;
+var CSS_UNITS = 96.0 / 72.0;
+var SCROLLBAR_PADDING = 40;
+var VERTICAL_PADDING = 5;
+var MIN_SCALE = 0.25;
+var MAX_SCALE = 4.0;
+var IMAGE_DIR = './images/';
+var SETTINGS_MEMORY = 20;
+var ANNOT_MIN_SIZE = 10;
+var RenderingStates = {
+ INITIAL: 0,
+ RUNNING: 1,
+ PAUSED: 2,
+ FINISHED: 3
+};
+var FindStates = {
+ FIND_FOUND: 0,
+ FIND_NOTFOUND: 1,
+ FIND_WRAPPED: 2,
+ FIND_PENDING: 3
+};
+
+//#if (FIREFOX || MOZCENTRAL || B2G || GENERIC || CHROME)
+//PDFJS.workerSrc = '../build/pdf.js';
+//#endif
+
+var mozL10n = document.mozL10n || document.webL10n;
+
+function getFileName(url) {
+ var anchor = url.indexOf('#');
+ var query = url.indexOf('?');
+ var end = Math.min(
+ anchor > 0 ? anchor : url.length,
+ query > 0 ? query : url.length);
+ return url.substring(url.lastIndexOf('/', end) + 1, end);
+}
+
+function scrollIntoView(element, spot) {
+ // Assuming offsetParent is available (it's not available when viewer is in
+ // hidden iframe or object). We have to scroll: if the offsetParent is not set
+ // producing the error. See also animationStartedClosure.
+ var parent = element.offsetParent;
+ var offsetY = element.offsetTop + element.clientTop;
+ if (!parent) {
+ console.error('offsetParent is not set -- cannot scroll');
+ return;
+ }
+ while (parent.clientHeight == parent.scrollHeight) {
+ offsetY += parent.offsetTop;
+ parent = parent.offsetParent;
+ if (!parent)
+ return; // no need to scroll
+ }
+ if (spot)
+ offsetY += spot.top;
+ parent.scrollTop = offsetY;
+}
+
+var Cache = function cacheCache(size) {
+ var data = [];
+ this.push = function cachePush(view) {
+ var i = data.indexOf(view);
+ if (i >= 0)
+ data.splice(i);
+ data.push(view);
+ if (data.length > size)
+ data.shift().destroy();
+ };
+};
+
+var ProgressBar = (function ProgressBarClosure() {
+
+ function clamp(v, min, max) {
+ return Math.min(Math.max(v, min), max);
+ }
+
+ function ProgressBar(id, opts) {
+
+ // Fetch the sub-elements for later
+ this.div = document.querySelector(id + ' .progress');
+
+ // Get options, with sensible defaults
+ this.height = opts.height || 100;
+ this.width = opts.width || 100;
+ this.units = opts.units || '%';
+
+ // Initialize heights
+ this.div.style.height = this.height + this.units;
+ }
+
+ ProgressBar.prototype = {
+
+ updateBar: function ProgressBar_updateBar() {
+ if (this._indeterminate) {
+ this.div.classList.add('indeterminate');
+ return;
+ }
+
+ var progressSize = this.width * this._percent / 100;
+
+ if (this._percent > 95)
+ this.div.classList.add('full');
+ else
+ this.div.classList.remove('full');
+ this.div.classList.remove('indeterminate');
+
+ this.div.style.width = progressSize + this.units;
+ },
+
+ get percent() {
+ return this._percent;
+ },
+
+ set percent(val) {
+ this._indeterminate = isNaN(val);
+ this._percent = clamp(val, 0, 100);
+ this.updateBar();
+ }
+ };
+
+ return ProgressBar;
+})();
+
+//#if FIREFOX || MOZCENTRAL
+//#include firefoxcom.js
+//#endif
+
+// Settings Manager - This is a utility for saving settings
+// First we see if localStorage is available
+// If not, we use FUEL in FF
+// Use asyncStorage for B2G
+var Settings = (function SettingsClosure() {
+//#if !(FIREFOX || MOZCENTRAL || B2G)
+ var isLocalStorageEnabled = (function localStorageEnabledTest() {
+ // Feature test as per http://diveintohtml5.info/storage.html
+ // The additional localStorage call is to get around a FF quirk, see
+ // bug #495747 in bugzilla
+ try {
+ return 'localStorage' in window && window['localStorage'] !== null &&
+ localStorage;
+ } catch (e) {
+ return false;
+ }
+ })();
+//#endif
+
+ function Settings(fingerprint) {
+ this.fingerprint = fingerprint;
+ this.initializedPromise = new PDFJS.Promise();
+
+ var resolvePromise = (function settingsResolvePromise(db) {
+ this.initialize(db || '{}');
+ this.initializedPromise.resolve();
+ }).bind(this);
+
+//#if B2G
+// asyncStorage.getItem('database', resolvePromise);
+//#endif
+
+//#if FIREFOX || MOZCENTRAL
+// resolvePromise(FirefoxCom.requestSync('getDatabase', null));
+//#endif
+
+//#if !(FIREFOX || MOZCENTRAL || B2G)
+ if (isLocalStorageEnabled)
+ resolvePromise(localStorage.getItem('database'));
+//#endif
+ }
+
+ Settings.prototype = {
+ initialize: function settingsInitialize(database) {
+ database = JSON.parse(database);
+ if (!('files' in database))
+ database.files = [];
+ if (database.files.length >= SETTINGS_MEMORY)
+ database.files.shift();
+ var index;
+ for (var i = 0, length = database.files.length; i < length; i++) {
+ var branch = database.files[i];
+ if (branch.fingerprint == this.fingerprint) {
+ index = i;
+ break;
+ }
+ }
+ if (typeof index != 'number')
+ index = database.files.push({fingerprint: this.fingerprint}) - 1;
+ this.file = database.files[index];
+ this.database = database;
+ },
+
+ set: function settingsSet(name, val) {
+ if (!this.initializedPromise.isResolved)
+ return;
+
+ var file = this.file;
+ file[name] = val;
+ var database = JSON.stringify(this.database);
+
+//#if B2G
+// asyncStorage.setItem('database', database);
+//#endif
+
+//#if FIREFOX || MOZCENTRAL
+// FirefoxCom.requestSync('setDatabase', database);
+//#endif
+
+//#if !(FIREFOX || MOZCENTRAL || B2G)
+ if (isLocalStorageEnabled)
+ localStorage.setItem('database', database);
+//#endif
+ },
+
+ get: function settingsGet(name, defaultValue) {
+ if (!this.initializedPromise.isResolved)
+ return defaultValue;
+
+ return this.file[name] || defaultValue;
+ }
+ };
+
+ return Settings;
+})();
+
+var cache = new Cache(CACHE_SIZE);
+var currentPageNumber = 1;
+
+var PDFFindController = {
+ startedTextExtraction: false,
+
+ extractTextPromises: [],
+
+ // If active, find results will be highlighted.
+ active: false,
+
+ // Stores the text for each page.
+ pageContents: [],
+
+ pageMatches: [],
+
+ // Currently selected match.
+ selected: {
+ pageIdx: -1,
+ matchIdx: -1
+ },
+
+ // Where find algorithm currently is in the document.
+ offset: {
+ pageIdx: null,
+ matchIdx: null
+ },
+
+ resumePageIdx: null,
+
+ resumeCallback: null,
+
+ state: null,
+
+ dirtyMatch: false,
+
+ findTimeout: null,
+
+ initialize: function() {
+ var events = [
+ 'find',
+ 'findagain',
+ 'findhighlightallchange',
+ 'findcasesensitivitychange'
+ ];
+
+ this.handleEvent = this.handleEvent.bind(this);
+
+ for (var i = 0; i < events.length; i++) {
+ window.addEventListener(events[i], this.handleEvent);
+ }
+ },
+
+ calcFindMatch: function(pageIndex) {
+ var pageContent = this.pageContents[pageIndex];
+ var query = this.state.query;
+ var caseSensitive = this.state.caseSensitive;
+ var queryLen = query.length;
+
+ if (queryLen === 0) {
+ // Do nothing the matches should be wiped out already.
+ return;
+ }
+
+ if (!caseSensitive) {
+ pageContent = pageContent.toLowerCase();
+ query = query.toLowerCase();
+ }
+
+ var matches = [];
+
+ var matchIdx = -queryLen;
+ while (true) {
+ matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
+ if (matchIdx === -1) {
+ break;
+ }
+
+ matches.push(matchIdx);
+ }
+ this.pageMatches[pageIndex] = matches;
+ this.updatePage(pageIndex);
+ if (this.resumePageIdx === pageIndex) {
+ var callback = this.resumeCallback;
+ this.resumePageIdx = null;
+ this.resumeCallback = null;
+ callback();
+ }
+ },
+
+ extractText: function() {
+ if (this.startedTextExtraction) {
+ return;
+ }
+ this.startedTextExtraction = true;
+
+ this.pageContents = [];
+ for (var i = 0, ii = PDFView.pdfDocument.numPages; i < ii; i++) {
+ this.extractTextPromises.push(new PDFJS.Promise());
+ }
+
+ var self = this;
+ function extractPageText(pageIndex) {
+ PDFView.pages[pageIndex].getTextContent().then(
+ function textContentResolved(data) {
+ // Build the find string.
+ var bidiTexts = data.bidiTexts;
+ var str = '';
+
+ for (var i = 0; i < bidiTexts.length; i++) {
+ str += bidiTexts[i].str;
+ }
+
+ // Store the pageContent as a string.
+ self.pageContents.push(str);
+
+ self.extractTextPromises[pageIndex].resolve(pageIndex);
+ if ((pageIndex + 1) < PDFView.pages.length)
+ extractPageText(pageIndex + 1);
+ }
+ );
+ }
+ extractPageText(0);
+ return this.extractTextPromise;
+ },
+
+ handleEvent: function(e) {
+ if (this.state === null || e.type !== 'findagain') {
+ this.dirtyMatch = true;
+ }
+ this.state = e.detail;
+ this.updateUIState(FindStates.FIND_PENDING);
+
+ this.extractText();
+
+ clearTimeout(this.findTimeout);
+ if (e.type === 'find') {
+ // Only trigger the find action after 250ms of silence.
+ this.findTimeout = setTimeout(this.nextMatch.bind(this), 250);
+ } else {
+ this.nextMatch();
+ }
+ },
+
+ updatePage: function(idx) {
+ var page = PDFView.pages[idx];
+
+ if (this.selected.pageIdx === idx) {
+ // If the page is selected, scroll the page into view, which triggers
+ // rendering the page, which adds the textLayer. Once the textLayer is
+ // build, it will scroll onto the selected match.
+ page.scrollIntoView();
+ }
+
+ if (page.textLayer) {
+ page.textLayer.updateMatches();
+ }
+ },
+
+ nextMatch: function() {
+ var pages = PDFView.pages;
+ var previous = this.state.findPrevious;
+ var numPages = PDFView.pages.length;
+
+ this.active = true;
+
+ if (this.dirtyMatch) {
+ // Need to recalculate the matches, reset everything.
+ this.dirtyMatch = false;
+ this.selected.pageIdx = this.selected.matchIdx = -1;
+ this.offset.pageIdx = previous ? numPages - 1 : 0;
+ this.offset.matchIdx = null;
+ this.hadMatch = false;
+ this.resumeCallback = null;
+ this.resumePageIdx = null;
+ this.pageMatches = [];
+ var self = this;
+
+ for (var i = 0; i < numPages; i++) {
+ // Wipe out any previous highlighted matches.
+ this.updatePage(i);
+
+ // As soon as the text is extracted start finding the matches.
+ this.extractTextPromises[i].onData(function(pageIdx) {
+ // Use a timeout since all the pages may already be extracted and we
+ // want to start highlighting before finding all the matches.
+ setTimeout(function() {
+ self.calcFindMatch(pageIdx);
+ });
+ });
+ }
+ }
+
+ // If there's no query there's no point in searching.
+ if (this.state.query === '') {
+ this.updateUIState(FindStates.FIND_FOUND);
+ return;
+ }
+
+ // If we're waiting on a page, we return since we can't do anything else.
+ if (this.resumeCallback) {
+ return;
+ }
+
+ var offset = this.offset;
+ // If there's already a matchIdx that means we are iterating through a
+ // page's matches.
+ if (offset.matchIdx !== null) {
+ var numPageMatches = this.pageMatches[offset.pageIdx].length;
+ if ((!previous && offset.matchIdx + 1 < numPageMatches) ||
+ (previous && offset.matchIdx > 0)) {
+ // The simple case, we just have advance the matchIdx to select the next
+ // match on the page.
+ this.hadMatch = true;
+ offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1;
+ this.updateMatch(true);
+ return;
+ }
+ // We went beyond the current page's matches, so we advance to the next
+ // page.
+ this.advanceOffsetPage(previous);
+ }
+ // Start searching through the page.
+ this.nextPageMatch();
+ },
+
+ nextPageMatch: function() {
+ if (this.resumePageIdx !== null)
+ console.error('There can only be one pending page.');
+
+ var matchesReady = function(matches) {
+ var offset = this.offset;
+ var numMatches = matches.length;
+ var previous = this.state.findPrevious;
+ if (numMatches) {
+ // There were matches for the page, so initialize the matchIdx.
+ this.hadMatch = true;
+ offset.matchIdx = previous ? numMatches - 1 : 0;
+ this.updateMatch(true);
+ } else {
+ // No matches attempt to search the next page.
+ this.advanceOffsetPage(previous);
+ if (offset.wrapped) {
+ offset.matchIdx = null;
+ if (!this.hadMatch) {
+ // No point in wrapping there were no matches.
+ this.updateMatch(false);
+ return;
+ }
+ }
+ // Search the next page.
+ this.nextPageMatch();
+ }
+ }.bind(this);
+
+ var pageIdx = this.offset.pageIdx;
+ var pageMatches = this.pageMatches;
+ if (!pageMatches[pageIdx]) {
+ // The matches aren't ready setup a callback so we can be notified,
+ // when they are ready.
+ this.resumeCallback = function() {
+ matchesReady(pageMatches[pageIdx]);
+ };
+ this.resumePageIdx = pageIdx;
+ return;
+ }
+ // The matches are finished already.
+ matchesReady(pageMatches[pageIdx]);
+ },
+
+ advanceOffsetPage: function(previous) {
+ var offset = this.offset;
+ var numPages = this.extractTextPromises.length;
+ offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1;
+ offset.matchIdx = null;
+ if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
+ offset.pageIdx = previous ? numPages - 1 : 0;
+ offset.wrapped = true;
+ return;
+ }
+ },
+
+ updateMatch: function(found) {
+ var state = FindStates.FIND_NOTFOUND;
+ var wrapped = this.offset.wrapped;
+ this.offset.wrapped = false;
+ if (found) {
+ var previousPage = this.selected.pageIdx;
+ this.selected.pageIdx = this.offset.pageIdx;
+ this.selected.matchIdx = this.offset.matchIdx;
+ state = wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND;
+ // Update the currently selected page to wipe out any selected matches.
+ if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {
+ this.updatePage(previousPage);
+ }
+ }
+ this.updateUIState(state, this.state.findPrevious);
+ if (this.selected.pageIdx !== -1) {
+ this.updatePage(this.selected.pageIdx, true);
+ }
+ },
+
+ updateUIState: function(state, previous) {
+ if (PDFView.supportsIntegratedFind) {
+ FirefoxCom.request('updateFindControlState',
+ {result: state, findPrevious: previous});
+ return;
+ }
+ PDFFindBar.updateUIState(state, previous);
+ }
+};
+
+var PDFFindBar = {
+ // TODO: Enable the FindBar *AFTER* the pagesPromise in the load function
+ // got resolved
+
+ opened: false,
+
+ initialize: function() {
+ this.bar = document.getElementById('findbar');
+ this.toggleButton = document.getElementById('viewFind');
+ this.findField = document.getElementById('findInput');
+ this.highlightAll = document.getElementById('findHighlightAll');
+ this.caseSensitive = document.getElementById('findMatchCase');
+ this.findMsg = document.getElementById('findMsg');
+ this.findStatusIcon = document.getElementById('findStatusIcon');
+
+ var self = this;
+ this.toggleButton.addEventListener('click', function() {
+ self.toggle();
+ });
+
+ this.findField.addEventListener('input', function() {
+ self.dispatchEvent('');
+ });
+
+ this.bar.addEventListener('keydown', function(evt) {
+ switch (evt.keyCode) {
+ case 13: // Enter
+ if (evt.target === self.findField) {
+ self.dispatchEvent('again', evt.shiftKey);
+ }
+ break;
+ case 27: // Escape
+ self.close();
+ break;
+ }
+ });
+
+ document.getElementById('findPrevious').addEventListener('click',
+ function() { self.dispatchEvent('again', true); }
+ );
+
+ document.getElementById('findNext').addEventListener('click', function() {
+ self.dispatchEvent('again', false);
+ });
+
+ this.highlightAll.addEventListener('click', function() {
+ self.dispatchEvent('highlightallchange');
+ });
+
+ this.caseSensitive.addEventListener('click', function() {
+ self.dispatchEvent('casesensitivitychange');
+ });
+ },
+
+ dispatchEvent: function(aType, aFindPrevious) {
+ var event = document.createEvent('CustomEvent');
+ event.initCustomEvent('find' + aType, true, true, {
+ query: this.findField.value,
+ caseSensitive: this.caseSensitive.checked,
+ highlightAll: this.highlightAll.checked,
+ findPrevious: aFindPrevious
+ });
+ return window.dispatchEvent(event);
+ },
+
+ updateUIState: function(state, previous) {
+ var notFound = false;
+ var findMsg = '';
+ var status = '';
+
+ switch (state) {
+ case FindStates.FIND_FOUND:
+ break;
+
+ case FindStates.FIND_PENDING:
+ status = 'pending';
+ break;
+
+ case FindStates.FIND_NOTFOUND:
+ findMsg = mozL10n.get('find_not_found', null, 'Phrase not found');
+ notFound = true;
+ break;
+
+ case FindStates.FIND_WRAPPED:
+ if (previous) {
+ findMsg = mozL10n.get('find_reached_top', null,
+ 'Reached top of document, continued from bottom');
+ } else {
+ findMsg = mozL10n.get('find_reached_bottom', null,
+ 'Reached end of document, continued from top');
+ }
+ break;
+ }
+
+ if (notFound) {
+ this.findField.classList.add('notFound');
+ } else {
+ this.findField.classList.remove('notFound');
+ }
+
+ this.findField.setAttribute('data-status', status);
+ this.findMsg.textContent = findMsg;
+ },
+
+ open: function() {
+ if (this.opened) return;
+
+ this.opened = true;
+ this.toggleButton.classList.add('toggled');
+ this.bar.classList.remove('hidden');
+ this.findField.select();
+ this.findField.focus();
+ },
+
+ close: function() {
+ if (!this.opened) return;
+
+ this.opened = false;
+ this.toggleButton.classList.remove('toggled');
+ this.bar.classList.add('hidden');
+
+ PDFFindController.active = false;
+ },
+
+ toggle: function() {
+ if (this.opened) {
+ this.close();
+ } else {
+ this.open();
+ }
+ }
+};
+
+var PDFView = {
+ pages: [],
+ thumbnails: [],
+ currentScale: UNKNOWN_SCALE,
+ currentScaleValue: null,
+ initialBookmark: document.location.hash.substring(1),
+ startedTextExtraction: false,
+ pageText: [],
+ container: null,
+ thumbnailContainer: null,
+ initialized: false,
+ fellback: false,
+ pdfDocument: null,
+ sidebarOpen: false,
+ pageViewScroll: null,
+ thumbnailViewScroll: null,
+ isFullscreen: false,
+ previousScale: null,
+ pageRotation: 0,
+ mouseScrollTimeStamp: 0,
+ mouseScrollDelta: 0,
+ lastScroll: 0,
+ previousPageNumber: 1,
+
+ // called once when the document is loaded
+ initialize: function pdfViewInitialize() {
+ var self = this;
+ var container = this.container = document.getElementById('viewerContainer');
+ this.pageViewScroll = {};
+ this.watchScroll(container, this.pageViewScroll, updateViewarea);
+
+ var thumbnailContainer = this.thumbnailContainer =
+ document.getElementById('thumbnailView');
+ this.thumbnailViewScroll = {};
+ this.watchScroll(thumbnailContainer, this.thumbnailViewScroll,
+ this.renderHighestPriority.bind(this));
+
+ PDFFindBar.initialize();
+ PDFFindController.initialize();
+
+ this.initialized = true;
+ container.addEventListener('scroll', function() {
+ self.lastScroll = Date.now();
+ }, false);
+ },
+
+ getPage: function pdfViewGetPage(n) {
+ return this.pdfDocument.getPage(n);
+ },
+
+ // Helper function to keep track whether a div was scrolled up or down and
+ // then call a callback.
+ watchScroll: function pdfViewWatchScroll(viewAreaElement, state, callback) {
+ state.down = true;
+ state.lastY = viewAreaElement.scrollTop;
+ viewAreaElement.addEventListener('scroll', function webViewerScroll(evt) {
+ var currentY = viewAreaElement.scrollTop;
+ var lastY = state.lastY;
+ if (currentY > lastY)
+ state.down = true;
+ else if (currentY < lastY)
+ state.down = false;
+ // else do nothing and use previous value
+ state.lastY = currentY;
+ callback();
+ }, true);
+ },
+
+ setScale: function pdfViewSetScale(val, resetAutoSettings, noScroll) {
+ if (val == this.currentScale)
+ return;
+
+ var pages = this.pages;
+ for (var i = 0; i < pages.length; i++)
+ pages[i].update(val * CSS_UNITS);
+
+ if (!noScroll && this.currentScale != val)
+ this.pages[this.page - 1].scrollIntoView();
+ this.currentScale = val;
+
+ var event = document.createEvent('UIEvents');
+ event.initUIEvent('scalechange', false, false, window, 0);
+ event.scale = val;
+ event.resetAutoSettings = resetAutoSettings;
+ window.dispatchEvent(event);
+ },
+
+ parseScale: function pdfViewParseScale(value, resetAutoSettings, noScroll) {
+ if ('custom' == value)
+ return;
+
+ var scale = parseFloat(value);
+ this.currentScaleValue = value;
+ if (scale) {
+ this.setScale(scale, true, noScroll);
+ return;
+ }
+
+ var container = this.container;
+ var currentPage = this.pages[this.page - 1];
+ if (!currentPage) {
+ return;
+ }
+
+ var pageWidthScale = (container.clientWidth - SCROLLBAR_PADDING) /
+ currentPage.width * currentPage.scale / CSS_UNITS;
+ var pageHeightScale = (container.clientHeight - VERTICAL_PADDING) /
+ currentPage.height * currentPage.scale / CSS_UNITS;
+ switch (value) {
+ case 'page-actual':
+ scale = 1;
+ break;
+ case 'page-width':
+ scale = pageWidthScale;
+ break;
+ case 'page-height':
+ scale = pageHeightScale;
+ break;
+ case 'page-fit':
+ scale = Math.min(pageWidthScale, pageHeightScale);
+ break;
+ case 'auto':
+ scale = Math.min(1.0, pageWidthScale);
+ break;
+ }
+ this.setScale(scale, resetAutoSettings, noScroll);
+
+ selectScaleOption(value);
+ },
+
+ zoomIn: function pdfViewZoomIn() {
+ var newScale = (this.currentScale * DEFAULT_SCALE_DELTA).toFixed(2);
+ newScale = Math.ceil(newScale * 10) / 10;
+ newScale = Math.min(MAX_SCALE, newScale);
+ this.parseScale(newScale, true);
+ },
+
+ zoomOut: function pdfViewZoomOut() {
+ var newScale = (this.currentScale / DEFAULT_SCALE_DELTA).toFixed(2);
+ newScale = Math.floor(newScale * 10) / 10;
+ newScale = Math.max(MIN_SCALE, newScale);
+ this.parseScale(newScale, true);
+ },
+
+ set page(val) {
+ var pages = this.pages;
+ var input = document.getElementById('pageNumber');
+ var event = document.createEvent('UIEvents');
+ event.initUIEvent('pagechange', false, false, window, 0);
+
+ if (!(0 < val && val <= pages.length)) {
+ this.previousPageNumber = val;
+ event.pageNumber = this.page;
+ window.dispatchEvent(event);
+ return;
+ }
+
+ pages[val - 1].updateStats();
+ this.previousPageNumber = currentPageNumber;
+ currentPageNumber = val;
+ event.pageNumber = val;
+ window.dispatchEvent(event);
+
+ // checking if the this.page was called from the updateViewarea function:
+ // avoiding the creation of two "set page" method (internal and public)
+ if (updateViewarea.inProgress)
+ return;
+
+ // Avoid scrolling the first page during loading
+ if (this.loading && val == 1)
+ return;
+
+ pages[val - 1].scrollIntoView();
+ },
+
+ get page() {
+ return currentPageNumber;
+ },
+
+ get supportsPrinting() {
+ var canvas = document.createElement('canvas');
+ var value = 'mozPrintCallback' in canvas;
+ // shadow
+ Object.defineProperty(this, 'supportsPrinting', { value: value,
+ enumerable: true,
+ configurable: true,
+ writable: false });
+ return value;
+ },
+
+ get supportsFullscreen() {
+ var doc = document.documentElement;
+ var support = doc.requestFullscreen || doc.mozRequestFullScreen ||
+ doc.webkitRequestFullScreen;
+
+ // Disable fullscreen button if we're in an iframe
+ if (!!window.frameElement)
+ support = false;
+
+ Object.defineProperty(this, 'supportsFullScreen', { value: support,
+ enumerable: true,
+ configurable: true,
+ writable: false });
+ return support;
+ },
+
+ get supportsIntegratedFind() {
+ var support = false;
+//#if !(FIREFOX || MOZCENTRAL)
+//#else
+// support = FirefoxCom.requestSync('supportsIntegratedFind');
+//#endif
+ Object.defineProperty(this, 'supportsIntegratedFind', { value: support,
+ enumerable: true,
+ configurable: true,
+ writable: false });
+ return support;
+ },
+
+ get supportsDocumentFonts() {
+ var support = true;
+//#if !(FIREFOX || MOZCENTRAL)
+//#else
+// support = FirefoxCom.requestSync('supportsDocumentFonts');
+//#endif
+ Object.defineProperty(this, 'supportsDocumentFonts', { value: support,
+ enumerable: true,
+ configurable: true,
+ writable: false });
+ return support;
+ },
+
+ get isHorizontalScrollbarEnabled() {
+ var div = document.getElementById('viewerContainer');
+ return div.scrollWidth > div.clientWidth;
+ },
+
+ initPassiveLoading: function pdfViewInitPassiveLoading() {
+ if (!PDFView.loadingBar) {
+ PDFView.loadingBar = new ProgressBar('#loadingBar', {});
+ }
+
+ window.addEventListener('message', function window_message(e) {
+ var args = e.data;
+
+ if (typeof args !== 'object' || !('pdfjsLoadAction' in args))
+ return;
+ switch (args.pdfjsLoadAction) {
+ case 'progress':
+ PDFView.progress(args.loaded / args.total);
+ break;
+ case 'complete':
+ if (!args.data) {
+ PDFView.error(mozL10n.get('loading_error', null,
+ 'An error occurred while loading the PDF.'), e);
+ break;
+ }
+ PDFView.open(args.data, 0);
+ break;
+ }
+ });
+ FirefoxCom.requestSync('initPassiveLoading', null);
+ },
+
+ setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
+ this.url = url;
+ try {
+ this.setTitle(decodeURIComponent(getFileName(url)) || url);
+ } catch (e) {
+ // decodeURIComponent may throw URIError,
+ // fall back to using the unprocessed url in that case
+ this.setTitle(url);
+ }
+ },
+
+ setTitle: function pdfViewSetTitle(title) {
+ document.title = title;
+//#if B2G
+// document.getElementById('activityTitle').textContent = title;
+//#endif
+ },
+
+ open: function pdfViewOpen(url, scale, password) {
+ var parameters = {password: password};
+ if (typeof url === 'string') { // URL
+ this.setTitleUsingUrl(url);
+ parameters.url = url;
+ } else if (url && 'byteLength' in url) { // ArrayBuffer
+ parameters.data = url;
+ }
+
+ if (!PDFView.loadingBar) {
+ PDFView.loadingBar = new ProgressBar('#loadingBar', {});
+ }
+
+ this.pdfDocument = null;
+ var self = this;
+ self.loading = true;
+ PDFJS.getDocument(parameters).then(
+ function getDocumentCallback(pdfDocument) {
+ self.load(pdfDocument, scale);
+ self.loading = false;
+ },
+ function getDocumentError(message, exception) {
+ if (exception && exception.name === 'PasswordException') {
+ if (exception.code === 'needpassword') {
+ var promptString = mozL10n.get('request_password', null,
+ 'PDF is protected by a password:');
+ password = prompt(promptString);
+ if (password && password.length > 0) {
+ return PDFView.open(url, scale, password);
+ }
+ }
+ }
+
+ var loadingErrorMessage = mozL10n.get('loading_error', null,
+ 'An error occurred while loading the PDF.');
+
+ if (exception && exception.name === 'InvalidPDFException') {
+ // change error message also for other builds
+ var loadingErrorMessage = mozL10n.get('invalid_file_error', null,
+ 'Invalid or corrupted PDF file.');
+//#if B2G
+// window.alert(loadingErrorMessage);
+// return window.close();
+//#endif
+ }
+
+ if (exception && exception.name === 'MissingPDFException') {
+ // special message for missing PDF's
+ var loadingErrorMessage = mozL10n.get('missing_file_error', null,
+ 'Missing PDF file.');
+
+//#if B2G
+// window.alert(loadingErrorMessage);
+// return window.close();
+//#endif
+ }
+
+ var loadingIndicator = document.getElementById('loading');
+ loadingIndicator.textContent = mozL10n.get('loading_error_indicator',
+ null, 'Error');
+ var moreInfo = {
+ message: message
+ };
+ self.error(loadingErrorMessage, moreInfo);
+ self.loading = false;
+ },
+ function getDocumentProgress(progressData) {
+ self.progress(progressData.loaded / progressData.total);
+ }
+ );
+ },
+
+ download: function pdfViewDownload() {
+ function noData() {
+ FirefoxCom.request('download', { originalUrl: url });
+ }
+ var url = this.url.split('#')[0];
+//#if !(FIREFOX || MOZCENTRAL)
+ url += '#pdfjs.action=download';
+ window.open(url, '_parent');
+//#else
+// // Document isn't ready just try to download with the url.
+// if (!this.pdfDocument) {
+// noData();
+// return;
+// }
+// this.pdfDocument.getData().then(
+// function getDataSuccess(data) {
+// var blob = PDFJS.createBlob(data.buffer, 'application/pdf');
+// var blobUrl = window.URL.createObjectURL(blob);
+//
+// FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url },
+// function response(err) {
+// if (err) {
+// // This error won't really be helpful because it's likely the
+// // fallback won't work either (or is already open).
+// PDFView.error('PDF failed to download.');
+// }
+// window.URL.revokeObjectURL(blobUrl);
+// }
+// );
+// },
+// noData // Error occurred try downloading with just the url.
+// );
+//#endif
+ },
+
+ fallback: function pdfViewFallback() {
+//#if !(FIREFOX || MOZCENTRAL)
+// return;
+//#else
+// // Only trigger the fallback once so we don't spam the user with messages
+// // for one PDF.
+// if (this.fellback)
+// return;
+// this.fellback = true;
+// var url = this.url.split('#')[0];
+// FirefoxCom.request('fallback', url, function response(download) {
+// if (!download)
+// return;
+// PDFView.download();
+// });
+//#endif
+ },
+
+ navigateTo: function pdfViewNavigateTo(dest) {
+ if (typeof dest === 'string')
+ dest = this.destinations[dest];
+ if (!(dest instanceof Array))
+ return; // invalid destination
+ // dest array looks like that: <page-ref> </XYZ|FitXXX> <args..>
+ var destRef = dest[0];
+ var pageNumber = destRef instanceof Object ?
+ this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : (destRef + 1);
+ if (pageNumber > this.pages.length)
+ pageNumber = this.pages.length;
+ if (pageNumber) {
+ this.page = pageNumber;
+ var currentPage = this.pages[pageNumber - 1];
+ if (!this.isFullscreen) { // Avoid breaking fullscreen mode.
+ currentPage.scrollIntoView(dest);
+ }
+ }
+ },
+
+ getDestinationHash: function pdfViewGetDestinationHash(dest) {
+ if (typeof dest === 'string')
+ return PDFView.getAnchorUrl('#' + escape(dest));
+ if (dest instanceof Array) {
+ var destRef = dest[0]; // see navigateTo method for dest format
+ var pageNumber = destRef instanceof Object ?
+ this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] :
+ (destRef + 1);
+ if (pageNumber) {
+ var pdfOpenParams = PDFView.getAnchorUrl('#page=' + pageNumber);
+ var destKind = dest[1];
+ if (typeof destKind === 'object' && 'name' in destKind &&
+ destKind.name == 'XYZ') {
+ var scale = (dest[4] || this.currentScale);
+ pdfOpenParams += '&zoom=' + (scale * 100);
+ if (dest[2] || dest[3]) {
+ pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0);
+ }
+ }
+ return pdfOpenParams;
+ }
+ }
+ return '';
+ },
+
+ /**
+ * For the firefox extension we prefix the full url on anchor links so they
+ * don't come up as resource:// urls and so open in new tab/window works.
+ * @param {String} anchor The anchor hash include the #.
+ */
+ getAnchorUrl: function getAnchorUrl(anchor) {
+//#if !(FIREFOX || MOZCENTRAL)
+ return anchor;
+//#else
+// return this.url.split('#')[0] + anchor;
+//#endif
+ },
+
+ /**
+ * Returns scale factor for the canvas. It makes sense for the HiDPI displays.
+ * @return {Object} The object with horizontal (sx) and vertical (sy)
+ scales. The scaled property is set to false if scaling is
+ not required, true otherwise.
+ */
+ getOutputScale: function pdfViewGetOutputDPI() {
+ var pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1;
+ return {
+ sx: pixelRatio,
+ sy: pixelRatio,
+ scaled: pixelRatio != 1
+ };
+ },
+
+ /**
+ * Show the error box.
+ * @param {String} message A message that is human readable.
+ * @param {Object} moreInfo (optional) Further information about the error
+ * that is more technical. Should have a 'message'
+ * and optionally a 'stack' property.
+ */
+ error: function pdfViewError(message, moreInfo) {
+ var moreInfoText = mozL10n.get('error_version_info',
+ {version: PDFJS.version || '?', build: PDFJS.build || '?'},
+ 'PDF.js v{{version}} (build: {{build}})') + '\n';
+ if (moreInfo) {
+ moreInfoText +=
+ mozL10n.get('error_message', {message: moreInfo.message},
+ 'Message: {{message}}');
+ if (moreInfo.stack) {
+ moreInfoText += '\n' +
+ mozL10n.get('error_stack', {stack: moreInfo.stack},
+ 'Stack: {{stack}}');
+ } else {
+ if (moreInfo.filename) {
+ moreInfoText += '\n' +
+ mozL10n.get('error_file', {file: moreInfo.filename},
+ 'File: {{file}}');
+ }
+ if (moreInfo.lineNumber) {
+ moreInfoText += '\n' +
+ mozL10n.get('error_line', {line: moreInfo.lineNumber},
+ 'Line: {{line}}');
+ }
+ }
+ }
+
+ var loadingBox = document.getElementById('loadingBox');
+ loadingBox.setAttribute('hidden', 'true');
+
+//#if !(FIREFOX || MOZCENTRAL)
+ var errorWrapper = document.getElementById('errorWrapper');
+ errorWrapper.removeAttribute('hidden');
+
+ var errorMessage = document.getElementById('errorMessage');
+ errorMessage.textContent = message;
+
+ var closeButton = document.getElementById('errorClose');
+ closeButton.onclick = function() {
+ errorWrapper.setAttribute('hidden', 'true');
+ };
+
+ var errorMoreInfo = document.getElementById('errorMoreInfo');
+ var moreInfoButton = document.getElementById('errorShowMore');
+ var lessInfoButton = document.getElementById('errorShowLess');
+ moreInfoButton.onclick = function() {
+ errorMoreInfo.removeAttribute('hidden');
+ moreInfoButton.setAttribute('hidden', 'true');
+ lessInfoButton.removeAttribute('hidden');
+ };
+ lessInfoButton.onclick = function() {
+ errorMoreInfo.setAttribute('hidden', 'true');
+ moreInfoButton.removeAttribute('hidden');
+ lessInfoButton.setAttribute('hidden', 'true');
+ };
+ moreInfoButton.removeAttribute('hidden');
+ lessInfoButton.setAttribute('hidden', 'true');
+ errorMoreInfo.value = moreInfoText;
+
+ errorMoreInfo.rows = moreInfoText.split('\n').length - 1;
+//#else
+// console.error(message + '\n' + moreInfoText);
+// this.fallback();
+//#endif
+ },
+
+ progress: function pdfViewProgress(level) {
+ var percent = Math.round(level * 100);
+ PDFView.loadingBar.percent = percent;
+ },
+
+ load: function pdfViewLoad(pdfDocument, scale) {
+ function bindOnAfterDraw(pageView, thumbnailView) {
+ // when page is painted, using the image as thumbnail base
+ pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() {
+ thumbnailView.setImage(pageView.canvas);
+ };
+ }
+
+ this.pdfDocument = pdfDocument;
+
+ var errorWrapper = document.getElementById('errorWrapper');
+ errorWrapper.setAttribute('hidden', 'true');
+
+ var loadingBox = document.getElementById('loadingBox');
+ loadingBox.setAttribute('hidden', 'true');
+ var loadingIndicator = document.getElementById('loading');
+ loadingIndicator.textContent = '';
+
+ var thumbsView = document.getElementById('thumbnailView');
+ thumbsView.parentNode.scrollTop = 0;
+
+ while (thumbsView.hasChildNodes())
+ thumbsView.removeChild(thumbsView.lastChild);
+
+ if ('_loadingInterval' in thumbsView)
+ clearInterval(thumbsView._loadingInterval);
+
+ var container = document.getElementById('viewer');
+ while (container.hasChildNodes())
+ container.removeChild(container.lastChild);
+
+ var pagesCount = pdfDocument.numPages;
+ var id = pdfDocument.fingerprint;
+ document.getElementById('numPages').textContent =
+ mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}');
+ document.getElementById('pageNumber').max = pagesCount;
+
+ PDFView.documentFingerprint = id;
+ var store = PDFView.store = new Settings(id);
+
+ this.pageRotation = 0;
+
+ var pages = this.pages = [];
+ this.pageText = [];
+ this.startedTextExtraction = false;
+ var pagesRefMap = this.pagesRefMap = {};
+ var thumbnails = this.thumbnails = [];
+
+ var pagesPromise = new PDFJS.Promise();
+ var self = this;
+
+ var firstPagePromise = pdfDocument.getPage(1);
+
+ // Fetch a single page so we can get a viewport that will be the default
+ // viewport for all pages
+ firstPagePromise.then(function(pdfPage) {
+ var viewport = pdfPage.getViewport(scale || 1.0);
+ var pagePromises = [];
+ for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
+ var viewportClone = viewport.clone();
+ var pageView = new PageView(container, pageNum, scale,
+ self.navigateTo.bind(self),
+ viewportClone);
+ var thumbnailView = new ThumbnailView(thumbsView, pageNum,
+ viewportClone);
+ bindOnAfterDraw(pageView, thumbnailView);
+ pages.push(pageView);
+ thumbnails.push(thumbnailView);
+ }
+
+ var event = document.createEvent('CustomEvent');
+ event.initCustomEvent('documentload', true, true, {});
+ window.dispatchEvent(event);
+
+ for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
+ var pagePromise = pdfDocument.getPage(pageNum);
+ pagePromise.then(function(pdfPage) {
+ var pageNum = pdfPage.pageNumber;
+ var pageView = pages[pageNum - 1];
+ if (!pageView.pdfPage) {
+ // The pdfPage might already be set if we've already entered
+ // pageView.draw()
+ pageView.setPdfPage(pdfPage);
+ }
+ var thumbnailView = thumbnails[pageNum - 1];
+ if (!thumbnailView.pdfPage) {
+ thumbnailView.setPdfPage(pdfPage);
+ }
+
+ var pageRef = pdfPage.ref;
+ var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
+ pagesRefMap[refStr] = pdfPage.pageNumber;
+ });
+ pagePromises.push(pagePromise);
+ }
+
+ PDFJS.Promise.all(pagePromises).then(function(pages) {
+ pagesPromise.resolve(pages);
+ });
+ });
+
+ var storePromise = store.initializedPromise;
+ PDFJS.Promise.all([firstPagePromise, storePromise]).then(function() {
+ var storedHash = null;
+ if (store.get('exists', false)) {
+ var pageNum = store.get('page', '1');
+ var zoom = store.get('zoom', PDFView.currentScale);
+ var left = store.get('scrollLeft', '0');
+ var top = store.get('scrollTop', '0');
+
+ storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' +
+ left + ',' + top;
+ }
+ self.setInitialView(storedHash, scale);
+ });
+
+ pagesPromise.then(function() {
+ if (PDFView.supportsPrinting) {
+ pdfDocument.getJavaScript().then(function(javaScript) {
+ if (javaScript.length) {
+ console.warn('Warning: JavaScript is not supported');
+ PDFView.fallback();
+ }
+ // Hack to support auto printing.
+ var regex = /\bprint\s*\(/g;
+ for (var i = 0, ii = javaScript.length; i < ii; i++) {
+ var js = javaScript[i];
+ if (js && regex.test(js)) {
+ setTimeout(function() {
+ window.print();
+ });
+ return;
+ }
+ }
+ });
+ }
+ });
+
+ var destinationsPromise = pdfDocument.getDestinations();
+ destinationsPromise.then(function(destinations) {
+ self.destinations = destinations;
+ });
+
+ // outline depends on destinations and pagesRefMap
+ var promises = [pagesPromise, destinationsPromise,
+ PDFView.animationStartedPromise];
+ PDFJS.Promise.all(promises).then(function() {
+ pdfDocument.getOutline().then(function(outline) {
+ self.outline = new DocumentOutlineView(outline);
+ });
+
+ // Make all navigation keys work on document load,
+ // unless the viewer is embedded in another page.
+ if (window.parent.location === window.location) {
+ PDFView.container.focus();
+ }
+ });
+
+ pdfDocument.getMetadata().then(function(data) {
+ var info = data.info, metadata = data.metadata;
+ self.documentInfo = info;
+ self.metadata = metadata;
+
+ // Provides some basic debug information
+ console.log('PDF ' + pdfDocument.fingerprint + ' [' +
+ info.PDFFormatVersion + ' ' + (info.Producer || '-') +
+ ' / ' + (info.Creator || '-') + ']' +
+ (PDFJS.version ? ' (PDF.js: ' + PDFJS.version + ')' : ''));
+
+ var pdfTitle;
+ if (metadata) {
+ if (metadata.has('dc:title'))
+ pdfTitle = metadata.get('dc:title');
+ }
+
+ if (!pdfTitle && info && info['Title'])
+ pdfTitle = info['Title'];
+
+ if (pdfTitle)
+ self.setTitle(pdfTitle + ' - ' + document.title);
+
+ if (info.IsAcroFormPresent) {
+ console.warn('Warning: AcroForm/XFA is not supported');
+ PDFView.fallback();
+ }
+ });
+ },
+
+ setInitialView: function pdfViewSetInitialView(storedHash, scale) {
+ // Reset the current scale, as otherwise the page's scale might not get
+ // updated if the zoom level stayed the same.
+ this.currentScale = 0;
+ this.currentScaleValue = null;
+ if (this.initialBookmark) {
+ this.setHash(this.initialBookmark);
+ this.initialBookmark = null;
+ }
+ else if (storedHash)
+ this.setHash(storedHash);
+ else if (scale) {
+ this.parseScale(scale, true);
+ this.page = 1;
+ }
+
+ if (PDFView.currentScale === UNKNOWN_SCALE) {
+ // Scale was not initialized: invalid bookmark or scale was not specified.
+ // Setting the default one.
+ this.parseScale(DEFAULT_SCALE, true);
+ }
+ },
+
+ renderHighestPriority: function pdfViewRenderHighestPriority() {
+ // Pages have a higher priority than thumbnails, so check them first.
+ var visiblePages = this.getVisiblePages();
+ var pageView = this.getHighestPriority(visiblePages, this.pages,
+ this.pageViewScroll.down);
+ if (pageView) {
+ this.renderView(pageView, 'page');
+ return;
+ }
+ // No pages needed rendering so check thumbnails.
+ if (this.sidebarOpen) {
+ var visibleThumbs = this.getVisibleThumbs();
+ var thumbView = this.getHighestPriority(visibleThumbs,
+ this.thumbnails,
+ this.thumbnailViewScroll.down);
+ if (thumbView)
+ this.renderView(thumbView, 'thumbnail');
+ }
+ },
+
+ getHighestPriority: function pdfViewGetHighestPriority(visible, views,
+ scrolledDown) {
+ // The state has changed figure out which page has the highest priority to
+ // render next (if any).
+ // Priority:
+ // 1 visible pages
+ // 2 if last scrolled down page after the visible pages
+ // 2 if last scrolled up page before the visible pages
+ var visibleViews = visible.views;
+
+ var numVisible = visibleViews.length;
+ if (numVisible === 0) {
+ return false;
+ }
+ for (var i = 0; i < numVisible; ++i) {
+ var view = visibleViews[i].view;
+ if (!this.isViewFinished(view))
+ return view;
+ }
+
+ // All the visible views have rendered, try to render next/previous pages.
+ if (scrolledDown) {
+ var nextPageIndex = visible.last.id;
+ // ID's start at 1 so no need to add 1.
+ if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex]))
+ return views[nextPageIndex];
+ } else {
+ var previousPageIndex = visible.first.id - 2;
+ if (views[previousPageIndex] &&
+ !this.isViewFinished(views[previousPageIndex]))
+ return views[previousPageIndex];
+ }
+ // Everything that needs to be rendered has been.
+ return false;
+ },
+
+ isViewFinished: function pdfViewNeedsRendering(view) {
+ return view.renderingState === RenderingStates.FINISHED;
+ },
+
+ // Render a page or thumbnail view. This calls the appropriate function based
+ // on the views state. If the view is already rendered it will return false.
+ renderView: function pdfViewRender(view, type) {
+ var state = view.renderingState;
+ switch (state) {
+ case RenderingStates.FINISHED:
+ return false;
+ case RenderingStates.PAUSED:
+ PDFView.highestPriorityPage = type + view.id;
+ view.resume();
+ break;
+ case RenderingStates.RUNNING:
+ PDFView.highestPriorityPage = type + view.id;
+ break;
+ case RenderingStates.INITIAL:
+ PDFView.highestPriorityPage = type + view.id;
+ view.draw(this.renderHighestPriority.bind(this));
+ break;
+ }
+ return true;
+ },
+
+ setHash: function pdfViewSetHash(hash) {
+ if (!hash)
+ return;
+
+ if (hash.indexOf('=') >= 0) {
+ var params = PDFView.parseQueryString(hash);
+ // borrowing syntax from "Parameters for Opening PDF Files"
+ if ('nameddest' in params) {
+ PDFView.navigateTo(params.nameddest);
+ return;
+ }
+ if ('page' in params) {
+ var pageNumber = (params.page | 0) || 1;
+ if ('zoom' in params) {
+ var zoomArgs = params.zoom.split(','); // scale,left,top
+ // building destination array
+
+ // If the zoom value, it has to get divided by 100. If it is a string,
+ // it should stay as it is.
+ var zoomArg = zoomArgs[0];
+ var zoomArgNumber = parseFloat(zoomArg);
+ if (zoomArgNumber)
+ zoomArg = zoomArgNumber / 100;
+
+ var dest = [null, {name: 'XYZ'},
+ zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null,
+ zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null,
+ zoomArg];
+ var currentPage = this.pages[pageNumber - 1];
+ currentPage.scrollIntoView(dest);
+ } else {
+ this.page = pageNumber; // simple page
+ }
+ }
+ if ('pagemode' in params) {
+ var toggle = document.getElementById('sidebarToggle');
+ if (params.pagemode === 'thumbs' || params.pagemode === 'bookmarks') {
+ if (!this.sidebarOpen) {
+ toggle.click();
+ }
+ this.switchSidebarView(params.pagemode === 'thumbs' ?
+ 'thumbs' : 'outline');
+ } else if (params.pagemode === 'none' && this.sidebarOpen) {
+ toggle.click();
+ }
+ }
+ } else if (/^\d+$/.test(hash)) // page number
+ this.page = hash;
+ else // named destination
+ PDFView.navigateTo(unescape(hash));
+ },
+
+ switchSidebarView: function pdfViewSwitchSidebarView(view) {
+ var thumbsView = document.getElementById('thumbnailView');
+ var outlineView = document.getElementById('outlineView');
+
+ var thumbsButton = document.getElementById('viewThumbnail');
+ var outlineButton = document.getElementById('viewOutline');
+
+ switch (view) {
+ case 'thumbs':
+ var wasOutlineViewVisible = thumbsView.classList.contains('hidden');
+
+ thumbsButton.classList.add('toggled');
+ outlineButton.classList.remove('toggled');
+ thumbsView.classList.remove('hidden');
+ outlineView.classList.add('hidden');
+
+ PDFView.renderHighestPriority();
+
+ if (wasOutlineViewVisible) {
+ // Ensure that the thumbnail of the current page is visible
+ // when switching from the outline view.
+ scrollIntoView(document.getElementById('thumbnailContainer' +
+ this.page));
+ }
+ break;
+
+ case 'outline':
+ thumbsButton.classList.remove('toggled');
+ outlineButton.classList.add('toggled');
+ thumbsView.classList.add('hidden');
+ outlineView.classList.remove('hidden');
+
+ if (outlineButton.getAttribute('disabled'))
+ return;
+ break;
+ }
+ },
+
+ getVisiblePages: function pdfViewGetVisiblePages() {
+ if (!this.isFullscreen) {
+ return this.getVisibleElements(this.container, this.pages, true);
+ } else {
+ // The algorithm in getVisibleElements is broken in fullscreen mode.
+ var visible = [], page = this.page;
+ var currentPage = this.pages[page - 1];
+ visible.push({ id: currentPage.id, view: currentPage });
+
+ return { first: currentPage, last: currentPage, views: visible};
+ }
+ },
+
+ getVisibleThumbs: function pdfViewGetVisibleThumbs() {
+ return this.getVisibleElements(this.thumbnailContainer, this.thumbnails);
+ },
+
+ // Generic helper to find out what elements are visible within a scroll pane.
+ getVisibleElements: function pdfViewGetVisibleElements(
+ scrollEl, views, sortByVisibility) {
+ var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;
+ var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;
+
+ var visible = [], view;
+ var currentHeight, viewHeight, hiddenHeight, percentHeight;
+ var currentWidth, viewWidth;
+ for (var i = 0, ii = views.length; i < ii; ++i) {
+ view = views[i];
+ currentHeight = view.el.offsetTop + view.el.clientTop;
+ viewHeight = view.el.clientHeight;
+ if ((currentHeight + viewHeight) < top) {
+ continue;
+ }
+ if (currentHeight > bottom) {
+ break;
+ }
+ currentWidth = view.el.offsetLeft + view.el.clientLeft;
+ viewWidth = view.el.clientWidth;
+ if ((currentWidth + viewWidth) < left || currentWidth > right) {
+ continue;
+ }
+ hiddenHeight = Math.max(0, top - currentHeight) +
+ Math.max(0, currentHeight + viewHeight - bottom);
+ percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;
+
+ visible.push({ id: view.id, y: currentHeight,
+ view: view, percent: percentHeight });
+ }
+
+ var first = visible[0];
+ var last = visible[visible.length - 1];
+
+ if (sortByVisibility) {
+ visible.sort(function(a, b) {
+ var pc = a.percent - b.percent;
+ if (Math.abs(pc) > 0.001) {
+ return -pc;
+ }
+ return a.id - b.id; // ensure stability
+ });
+ }
+ return {first: first, last: last, views: visible};
+ },
+
+ // Helper function to parse query string (e.g. ?param1=value&parm2=...).
+ parseQueryString: function pdfViewParseQueryString(query) {
+ var parts = query.split('&');
+ var params = {};
+ for (var i = 0, ii = parts.length; i < parts.length; ++i) {
+ var param = parts[i].split('=');
+ var key = param[0];
+ var value = param.length > 1 ? param[1] : null;
+ params[unescape(key)] = unescape(value);
+ }
+ return params;
+ },
+
+ beforePrint: function pdfViewSetupBeforePrint() {
+ if (!this.supportsPrinting) {
+ var printMessage = mozL10n.get('printing_not_supported', null,
+ 'Warning: Printing is not fully supported by this browser.');
+ this.error(printMessage);
+ return;
+ }
+
+ var alertNotReady = false;
+ if (!this.pages.length) {
+ alertNotReady = true;
+ } else {
+ for (var i = 0, ii = this.pages.length; i < ii; ++i) {
+ if (!this.pages[i].pdfPage) {
+ alertNotReady = true;
+ break;
+ }
+ }
+ }
+ if (alertNotReady) {
+ var notReadyMessage = mozL10n.get('printing_not_ready', null,
+ 'Warning: The PDF is not fully loaded for printing.');
+ window.alert(notReadyMessage);
+ return;
+ }
+
+ var body = document.querySelector('body');
+ body.setAttribute('data-mozPrintCallback', true);
+ for (var i = 0, ii = this.pages.length; i < ii; ++i) {
+ this.pages[i].beforePrint();
+ }
+ },
+
+ afterPrint: function pdfViewSetupAfterPrint() {
+ var div = document.getElementById('printContainer');
+ while (div.hasChildNodes())
+ div.removeChild(div.lastChild);
+ },
+
+ fullscreen: function pdfViewFullscreen() {
+ var isFullscreen = document.fullscreenElement || document.mozFullScreen ||
+ document.webkitIsFullScreen;
+
+ if (isFullscreen) {
+ return false;
+ }
+
+ var wrapper = document.getElementById('viewerContainer');
+ if (document.documentElement.requestFullscreen) {
+ wrapper.requestFullscreen();
+ } else if (document.documentElement.mozRequestFullScreen) {
+ wrapper.mozRequestFullScreen();
+ } else if (document.documentElement.webkitRequestFullScreen) {
+ wrapper.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
+ } else {
+ return false;
+ }
+
+ this.isFullscreen = true;
+ var currentPage = this.pages[this.page - 1];
+ this.previousScale = this.currentScaleValue;
+ this.parseScale('page-fit', true);
+
+ // Wait for fullscreen to take effect
+ setTimeout(function() {
+ currentPage.scrollIntoView();
+ }, 0);
+
+ this.showPresentationControls();
+ return true;
+ },
+
+ exitFullscreen: function pdfViewExitFullscreen() {
+ this.isFullscreen = false;
+ this.parseScale(this.previousScale);
+ this.page = this.page;
+ this.clearMouseScrollState();
+ this.hidePresentationControls();
+
+ // Ensure that the thumbnail of the current page is visible
+ // when exiting fullscreen mode.
+ scrollIntoView(document.getElementById('thumbnailContainer' + this.page));
+ },
+
+ showPresentationControls: function pdfViewShowPresentationControls() {
+ var DELAY_BEFORE_HIDING_CONTROLS = 3000;
+ var wrapper = document.getElementById('viewerContainer');
+ if (this.presentationControlsTimeout) {
+ clearTimeout(this.presentationControlsTimeout);
+ } else {
+ wrapper.classList.add('presentationControls');
+ }
+ this.presentationControlsTimeout = setTimeout(function hideControls() {
+ wrapper.classList.remove('presentationControls');
+ delete PDFView.presentationControlsTimeout;
+ }, DELAY_BEFORE_HIDING_CONTROLS);
+ },
+
+ hidePresentationControls: function pdfViewShowPresentationControls() {
+ if (!this.presentationControlsTimeout) {
+ return;
+ }
+ clearTimeout(this.presentationControlsTimeout);
+ delete this.presentationControlsTimeout;
+
+ var wrapper = document.getElementById('viewerContainer');
+ wrapper.classList.remove('presentationControls');
+ },
+
+ rotatePages: function pdfViewPageRotation(delta) {
+
+ this.pageRotation = (this.pageRotation + 360 + delta) % 360;
+
+ for (var i = 0, l = this.pages.length; i < l; i++) {
+ var page = this.pages[i];
+ page.update(page.scale, this.pageRotation);
+ }
+
+ for (var i = 0, l = this.thumbnails.length; i < l; i++) {
+ var thumb = this.thumbnails[i];
+ thumb.update(this.pageRotation);
+ }
+
+ this.parseScale(this.currentScaleValue, true);
+
+ this.renderHighestPriority();
+
+ var currentPage = this.pages[this.page - 1];
+ if (!currentPage) {
+ return;
+ }
+
+ // Wait for fullscreen to take effect
+ setTimeout(function() {
+ currentPage.scrollIntoView();
+ }, 0);
+ },
+
+ /**
+ * This function flips the page in presentation mode if the user scrolls up
+ * or down with large enough motion and prevents page flipping too often.
+ *
+ * @this {PDFView}
+ * @param {number} mouseScrollDelta The delta value from the mouse event.
+ */
+ mouseScroll: function pdfViewMouseScroll(mouseScrollDelta) {
+ var MOUSE_SCROLL_COOLDOWN_TIME = 50;
+
+ var currentTime = (new Date()).getTime();
+ var storedTime = this.mouseScrollTimeStamp;
+
+ // In case one page has already been flipped there is a cooldown time
+ // which has to expire before next page can be scrolled on to.
+ if (currentTime > storedTime &&
+ currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME)
+ return;
+
+ // In case the user decides to scroll to the opposite direction than before
+ // clear the accumulated delta.
+ if ((this.mouseScrollDelta > 0 && mouseScrollDelta < 0) ||
+ (this.mouseScrollDelta < 0 && mouseScrollDelta > 0))
+ this.clearMouseScrollState();
+
+ this.mouseScrollDelta += mouseScrollDelta;
+
+ var PAGE_FLIP_THRESHOLD = 120;
+ if (Math.abs(this.mouseScrollDelta) >= PAGE_FLIP_THRESHOLD) {
+
+ var PageFlipDirection = {
+ UP: -1,
+ DOWN: 1
+ };
+
+ // In fullscreen mode scroll one page at a time.
+ var pageFlipDirection = (this.mouseScrollDelta > 0) ?
+ PageFlipDirection.UP :
+ PageFlipDirection.DOWN;
+ this.clearMouseScrollState();
+ var currentPage = this.page;
+
+ // In case we are already on the first or the last page there is no need
+ // to do anything.
+ if ((currentPage == 1 && pageFlipDirection == PageFlipDirection.UP) ||
+ (currentPage == this.pages.length &&
+ pageFlipDirection == PageFlipDirection.DOWN))
+ return;
+
+ this.page += pageFlipDirection;
+ this.mouseScrollTimeStamp = currentTime;
+ }
+ },
+
+ /**
+ * This function clears the member attributes used with mouse scrolling in
+ * presentation mode.
+ *
+ * @this {PDFView}
+ */
+ clearMouseScrollState: function pdfViewClearMouseScrollState() {
+ this.mouseScrollTimeStamp = 0;
+ this.mouseScrollDelta = 0;
+ }
+};
+
+var PageView = function pageView(container, id, scale,
+ navigateTo, defaultViewport) {
+ this.id = id;
+
+ this.rotation = 0;
+ this.scale = scale || 1.0;
+ this.viewport = defaultViewport;
+ this.pdfPageRotate = defaultViewport.rotate;
+
+ this.renderingState = RenderingStates.INITIAL;
+ this.resume = null;
+
+ this.textContent = null;
+ this.textLayer = null;
+
+ var anchor = document.createElement('a');
+ anchor.name = '' + this.id;
+
+ var div = this.el = document.createElement('div');
+ div.id = 'pageContainer' + this.id;
+ div.className = 'page';
+ div.style.width = Math.floor(this.viewport.width) + 'px';
+ div.style.height = Math.floor(this.viewport.height) + 'px';
+
+ container.appendChild(anchor);
+ container.appendChild(div);
+
+ this.setPdfPage = function pageViewSetPdfPage(pdfPage) {
+ this.pdfPage = pdfPage;
+ this.pdfPageRotate = pdfPage.rotate;
+ this.viewport = pdfPage.getViewport(this.scale);
+ this.stats = pdfPage.stats;
+ this.update();
+ };
+
+ this.destroy = function pageViewDestroy() {
+ this.update();
+ if (this.pdfPage) {
+ this.pdfPage.destroy();
+ }
+ };
+
+ this.update = function pageViewUpdate(scale, rotation) {
+ this.renderingState = RenderingStates.INITIAL;
+ this.resume = null;
+
+ if (typeof rotation !== 'undefined') {
+ this.rotation = rotation;
+ }
+
+ this.scale = scale || this.scale;
+
+ var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+ this.viewport = this.viewport.clone({
+ scale: this.scale,
+ rotation: totalRotation
+ });
+
+ div.style.width = Math.floor(this.viewport.width) + 'px';
+ div.style.height = Math.floor(this.viewport.height) + 'px';
+
+ while (div.hasChildNodes())
+ div.removeChild(div.lastChild);
+ div.removeAttribute('data-loaded');
+
+ delete this.canvas;
+
+ this.loadingIconDiv = document.createElement('div');
+ this.loadingIconDiv.className = 'loadingIcon';
+ div.appendChild(this.loadingIconDiv);
+ };
+
+ Object.defineProperty(this, 'width', {
+ get: function PageView_getWidth() {
+ return this.viewport.width;
+ },
+ enumerable: true
+ });
+
+ Object.defineProperty(this, 'height', {
+ get: function PageView_getHeight() {
+ return this.viewport.height;
+ },
+ enumerable: true
+ });
+
+ function setupAnnotations(pdfPage, viewport) {
+ function bindLink(link, dest) {
+ link.href = PDFView.getDestinationHash(dest);
+ link.onclick = function pageViewSetupLinksOnclick() {
+ if (dest)
+ PDFView.navigateTo(dest);
+ return false;
+ };
+ }
+ function createElementWithStyle(tagName, item, rect) {
+ if (!rect) {
+ rect = viewport.convertToViewportRectangle(item.rect);
+ rect = PDFJS.Util.normalizeRect(rect);
+ }
+ var element = document.createElement(tagName);
+ element.style.left = Math.floor(rect[0]) + 'px';
+ element.style.top = Math.floor(rect[1]) + 'px';
+ element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
+ element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
+ return element;
+ }
+ function createTextAnnotation(item) {
+ var container = document.createElement('section');
+ container.className = 'annotText';
+
+ var rect = viewport.convertToViewportRectangle(item.rect);
+ rect = PDFJS.Util.normalizeRect(rect);
+ // sanity check because of OOo-generated PDFs
+ if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
+ rect[3] = rect[1] + ANNOT_MIN_SIZE;
+ }
+ if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
+ rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
+ }
+ var image = createElementWithStyle('img', item, rect);
+ var iconName = item.name;
+ image.src = IMAGE_DIR + 'annotation-' +
+ iconName.toLowerCase() + '.svg';
+ image.alt = mozL10n.get('text_annotation_type', {type: iconName},
+ '[{{type}} Annotation]');
+ var content = document.createElement('div');
+ content.setAttribute('hidden', true);
+ var title = document.createElement('h1');
+ var text = document.createElement('p');
+ content.style.left = Math.floor(rect[2]) + 'px';
+ content.style.top = Math.floor(rect[1]) + 'px';
+ title.textContent = item.title;
+
+ if (!item.content && !item.title) {
+ content.setAttribute('hidden', true);
+ } else {
+ var e = document.createElement('span');
+ var lines = item.content.split(/(?:\r\n?|\n)/);
+ for (var i = 0, ii = lines.length; i < ii; ++i) {
+ var line = lines[i];
+ e.appendChild(document.createTextNode(line));
+ if (i < (ii - 1))
+ e.appendChild(document.createElement('br'));
+ }
+ text.appendChild(e);
+ image.addEventListener('mouseover', function annotationImageOver() {
+ content.removeAttribute('hidden');
+ }, false);
+
+ image.addEventListener('mouseout', function annotationImageOut() {
+ content.setAttribute('hidden', true);
+ }, false);
+ }
+
+ content.appendChild(title);
+ content.appendChild(text);
+ container.appendChild(image);
+ container.appendChild(content);
+
+ return container;
+ }
+
+ pdfPage.getAnnotations().then(function(items) {
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ switch (item.type) {
+ case 'Link':
+ var link = createElementWithStyle('a', item);
+ link.href = item.url || '';
+ if (!item.url)
+ bindLink(link, ('dest' in item) ? item.dest : null);
+ div.appendChild(link);
+ break;
+ case 'Text':
+ var textAnnotation = createTextAnnotation(item);
+ if (textAnnotation)
+ div.appendChild(textAnnotation);
+ break;
+ }
+ }
+ });
+ }
+
+ this.getPagePoint = function pageViewGetPagePoint(x, y) {
+ return this.viewport.convertToPdfPoint(x, y);
+ };
+
+ this.scrollIntoView = function pageViewScrollIntoView(dest) {
+ if (!dest) {
+ scrollIntoView(div);
+ return;
+ }
+
+ var x = 0, y = 0;
+ var width = 0, height = 0, widthScale, heightScale;
+ var scale = 0;
+ switch (dest[1].name) {
+ case 'XYZ':
+ x = dest[2];
+ y = dest[3];
+ scale = dest[4];
+ // If x and/or y coordinates are not supplied, default to
+ // _top_ left of the page (not the obvious bottom left,
+ // since aligning the bottom of the intended page with the
+ // top of the window is rarely helpful).
+ x = x !== null ? x : 0;
+ y = y !== null ? y : this.height / this.scale;
+ break;
+ case 'Fit':
+ case 'FitB':
+ scale = 'page-fit';
+ break;
+ case 'FitH':
+ case 'FitBH':
+ y = dest[2];
+ scale = 'page-width';
+ break;
+ case 'FitV':
+ case 'FitBV':
+ x = dest[2];
+ scale = 'page-height';
+ break;
+ case 'FitR':
+ x = dest[2];
+ y = dest[3];
+ width = dest[4] - x;
+ height = dest[5] - y;
+ widthScale = (this.container.clientWidth - SCROLLBAR_PADDING) /
+ width / CSS_UNITS;
+ heightScale = (this.container.clientHeight - SCROLLBAR_PADDING) /
+ height / CSS_UNITS;
+ scale = Math.min(widthScale, heightScale);
+ break;
+ default:
+ return;
+ }
+
+ if (scale && scale !== PDFView.currentScale)
+ PDFView.parseScale(scale, true, true);
+ else if (PDFView.currentScale === UNKNOWN_SCALE)
+ PDFView.parseScale(DEFAULT_SCALE, true, true);
+
+ var boundingRect = [
+ this.viewport.convertToViewportPoint(x, y),
+ this.viewport.convertToViewportPoint(x + width, y + height)
+ ];
+ setTimeout(function pageViewScrollIntoViewRelayout() {
+ // letting page to re-layout before scrolling
+ var scale = PDFView.currentScale;
+ var x = Math.min(boundingRect[0][0], boundingRect[1][0]);
+ var y = Math.min(boundingRect[0][1], boundingRect[1][1]);
+ var width = Math.abs(boundingRect[0][0] - boundingRect[1][0]);
+ var height = Math.abs(boundingRect[0][1] - boundingRect[1][1]);
+
+ scrollIntoView(div, {left: x, top: y, width: width, height: height});
+ }, 0);
+ };
+
+ this.getTextContent = function pageviewGetTextContent() {
+ if (!this.textContent) {
+ this.textContent = this.pdfPage.getTextContent();
+ }
+ return this.textContent;
+ };
+
+ this.draw = function pageviewDraw(callback) {
+ var pdfPage = this.pdfPage;
+
+ if (!pdfPage) {
+ var promise = PDFView.getPage(this.id);
+ promise.then(function(pdfPage) {
+ this.setPdfPage(pdfPage);
+ this.draw(callback);
+ }.bind(this));
+ return;
+ }
+
+ if (this.renderingState !== RenderingStates.INITIAL) {
+ console.error('Must be in new state before drawing');
+ }
+
+ this.renderingState = RenderingStates.RUNNING;
+
+ var canvas = document.createElement('canvas');
+ canvas.id = 'page' + this.id;
+ div.appendChild(canvas);
+ this.canvas = canvas;
+
+ var scale = this.scale, viewport = this.viewport;
+ var outputScale = PDFView.getOutputScale();
+ canvas.width = Math.floor(viewport.width) * outputScale.sx;
+ canvas.height = Math.floor(viewport.height) * outputScale.sy;
+
+ var textLayerDiv = null;
+ if (!PDFJS.disableTextLayer) {
+ textLayerDiv = document.createElement('div');
+ textLayerDiv.className = 'textLayer';
+ textLayerDiv.style.width = canvas.width + 'px';
+ textLayerDiv.style.height = canvas.height + 'px';
+ div.appendChild(textLayerDiv);
+ }
+ var textLayer = this.textLayer =
+ textLayerDiv ? new TextLayerBuilder(textLayerDiv, this.id - 1) : null;
+
+ if (outputScale.scaled) {
+ var cssScale = 'scale(' + (1 / outputScale.sx) + ', ' +
+ (1 / outputScale.sy) + ')';
+ CustomStyle.setProp('transform' , canvas, cssScale);
+ CustomStyle.setProp('transformOrigin' , canvas, '0% 0%');
+ if (textLayerDiv) {
+ CustomStyle.setProp('transform' , textLayerDiv, cssScale);
+ CustomStyle.setProp('transformOrigin' , textLayerDiv, '0% 0%');
+ }
+ }
+
+ var ctx = canvas.getContext('2d');
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ // TODO(mack): use data attributes to store these
+ ctx._scaleX = outputScale.sx;
+ ctx._scaleY = outputScale.sy;
+ if (outputScale.scaled) {
+ ctx.scale(outputScale.sx, outputScale.sy);
+ }
+//#if (FIREFOX || MOZCENTRAL)
+// // Checking if document fonts are used only once
+// var checkIfDocumentFontsUsed = !PDFView.pdfDocument.embeddedFontsUsed;
+//#endif
+
+ // Rendering area
+
+ var self = this;
+ var renderingWasReset = false;
+ function pageViewDrawCallback(error) {
+ if (renderingWasReset) {
+ return;
+ }
+
+ self.renderingState = RenderingStates.FINISHED;
+
+ if (self.loadingIconDiv) {
+ div.removeChild(self.loadingIconDiv);
+ delete self.loadingIconDiv;
+ }
+
+//#if (FIREFOX || MOZCENTRAL)
+// if (checkIfDocumentFontsUsed && PDFView.pdfDocument.embeddedFontsUsed &&
+// !PDFView.supportsDocumentFonts) {
+// console.error(mozL10n.get('web_fonts_disabled', null,
+// 'Web fonts are disabled: unable to use embedded PDF fonts.'));
+// PDFView.fallback();
+// }
+//#endif
+ if (error) {
+ PDFView.error(mozL10n.get('rendering_error', null,
+ 'An error occurred while rendering the page.'), error);
+ }
+
+ self.stats = pdfPage.stats;
+ self.updateStats();
+ if (self.onAfterDraw)
+ self.onAfterDraw();
+
+ cache.push(self);
+
+ var event = document.createEvent('CustomEvent');
+ event.initCustomEvent('pagerender', true, true, {
+ pageNumber: pdfPage.pageNumber
+ });
+ div.dispatchEvent(event);
+
+ callback();
+ }
+
+ var renderContext = {
+ canvasContext: ctx,
+ viewport: this.viewport,
+ textLayer: textLayer,
+ continueCallback: function pdfViewcContinueCallback(cont) {
+ if (self.renderingState === RenderingStates.INITIAL) {
+ // The page update() was called, we just need to abort any rendering.
+ renderingWasReset = true;
+ return;
+ }
+
+ if (PDFView.highestPriorityPage !== 'page' + self.id) {
+ self.renderingState = RenderingStates.PAUSED;
+ self.resume = function resumeCallback() {
+ self.renderingState = RenderingStates.RUNNING;
+ cont();
+ };
+ return;
+ }
+ cont();
+ }
+ };
+ this.pdfPage.render(renderContext).then(
+ function pdfPageRenderCallback() {
+ pageViewDrawCallback(null);
+ },
+ function pdfPageRenderError(error) {
+ pageViewDrawCallback(error);
+ }
+ );
+
+ if (textLayer) {
+ this.getTextContent().then(
+ function textContentResolved(textContent) {
+ textLayer.setTextContent(textContent);
+ }
+ );
+ }
+
+ setupAnnotations(this.pdfPage, this.viewport);
+ div.setAttribute('data-loaded', true);
+ };
+
+ this.beforePrint = function pageViewBeforePrint() {
+ var pdfPage = this.pdfPage;
+
+ var viewport = pdfPage.getViewport(1);
+ // Use the same hack we use for high dpi displays for printing to get better
+ // output until bug 811002 is fixed in FF.
+ var PRINT_OUTPUT_SCALE = 2;
+ var canvas = this.canvas = document.createElement('canvas');
+ canvas.width = Math.floor(viewport.width) * PRINT_OUTPUT_SCALE;
+ canvas.height = Math.floor(viewport.height) * PRINT_OUTPUT_SCALE;
+ canvas.style.width = (PRINT_OUTPUT_SCALE * viewport.width) + 'pt';
+ canvas.style.height = (PRINT_OUTPUT_SCALE * viewport.height) + 'pt';
+ var cssScale = 'scale(' + (1 / PRINT_OUTPUT_SCALE) + ', ' +
+ (1 / PRINT_OUTPUT_SCALE) + ')';
+ CustomStyle.setProp('transform' , canvas, cssScale);
+ CustomStyle.setProp('transformOrigin' , canvas, '0% 0%');
+
+ var printContainer = document.getElementById('printContainer');
+ printContainer.appendChild(canvas);
+
+ var self = this;
+ canvas.mozPrintCallback = function(obj) {
+ var ctx = obj.context;
+
+ ctx.save();
+ ctx.fillStyle = 'rgb(255, 255, 255)';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ ctx.restore();
+ ctx.scale(PRINT_OUTPUT_SCALE, PRINT_OUTPUT_SCALE);
+
+ var renderContext = {
+ canvasContext: ctx,
+ viewport: viewport
+ };
+
+ pdfPage.render(renderContext).then(function() {
+ // Tell the printEngine that rendering this canvas/page has finished.
+ obj.done();
+ self.pdfPage.destroy();
+ }, function(error) {
+ console.error(error);
+ // Tell the printEngine that rendering this canvas/page has failed.
+ // This will make the print proces stop.
+ if ('abort' in obj)
+ obj.abort();
+ else
+ obj.done();
+ self.pdfPage.destroy();
+ });
+ };
+ };
+
+ this.updateStats = function pageViewUpdateStats() {
+ if (!this.stats) {
+ return;
+ }
+
+ if (PDFJS.pdfBug && Stats.enabled) {
+ var stats = this.stats;
+ Stats.add(this.id, stats);
+ }
+ };
+};
+
+var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
+ var anchor = document.createElement('a');
+ anchor.href = PDFView.getAnchorUrl('#page=' + id);
+ anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}');
+ anchor.onclick = function stopNavigation() {
+ PDFView.page = id;
+ return false;
+ };
+
+
+ this.pdfPage = undefined;
+ this.viewport = defaultViewport;
+ this.pdfPageRotate = defaultViewport.rotate;
+
+ this.rotation = 0;
+ this.pageWidth = this.viewport.width;
+ this.pageHeight = this.viewport.height;
+ this.pageRatio = this.pageWidth / this.pageHeight;
+ this.id = id;
+
+ this.canvasWidth = 98;
+ this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight;
+ this.scale = (this.canvasWidth / this.pageWidth);
+
+ var div = this.el = document.createElement('div');
+ div.id = 'thumbnailContainer' + id;
+ div.className = 'thumbnail';
+
+ if (id === 1) {
+ // Highlight the thumbnail of the first page when no page number is
+ // specified (or exists in cache) when the document is loaded.
+ div.classList.add('selected');
+ }
+
+ var ring = document.createElement('div');
+ ring.className = 'thumbnailSelectionRing';
+ ring.style.width = this.canvasWidth + 'px';
+ ring.style.height = this.canvasHeight + 'px';
+
+ div.appendChild(ring);
+ anchor.appendChild(div);
+ container.appendChild(anchor);
+
+ this.hasImage = false;
+ this.renderingState = RenderingStates.INITIAL;
+
+ this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) {
+ this.pdfPage = pdfPage;
+ this.pdfPageRotate = pdfPage.rotate;
+ this.viewport = pdfPage.getViewport(1);
+ this.update();
+ };
+
+ this.update = function thumbnailViewUpdate(rot) {
+ if (!this.pdfPage) {
+ return;
+ }
+
+ if (rot !== undefined) {
+ this.rotation = rot;
+ }
+
+ var totalRotation = (this.rotation + this.pdfPage.rotate) % 360;
+ this.viewport = this.viewport.clone({
+ scale: 1,
+ rotation: totalRotation
+ });
+ this.pageWidth = this.viewport.width;
+ this.pageHeight = this.viewport.height;
+ this.pageRatio = this.pageWidth / this.pageHeight;
+
+ this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight;
+ this.scale = (this.canvasWidth / this.pageWidth);
+
+ div.removeAttribute('data-loaded');
+ ring.textContent = '';
+ ring.style.width = this.canvasWidth + 'px';
+ ring.style.height = this.canvasHeight + 'px';
+
+ this.hasImage = false;
+ this.renderingState = RenderingStates.INITIAL;
+ this.resume = null;
+ };
+
+ this.getPageDrawContext = function thumbnailViewGetPageDrawContext() {
+ var canvas = document.createElement('canvas');
+ canvas.id = 'thumbnail' + id;
+
+ canvas.width = this.canvasWidth;
+ canvas.height = this.canvasHeight;
+ canvas.className = 'thumbnailImage';
+ canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas',
+ {page: id}, 'Thumbnail of Page {{page}}'));
+
+ div.setAttribute('data-loaded', true);
+
+ ring.appendChild(canvas);
+
+ var ctx = canvas.getContext('2d');
+ ctx.save();
+ ctx.fillStyle = 'rgb(255, 255, 255)';
+ ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
+ ctx.restore();
+ return ctx;
+ };
+
+ this.drawingRequired = function thumbnailViewDrawingRequired() {
+ return !this.hasImage;
+ };
+
+ this.draw = function thumbnailViewDraw(callback) {
+ if (!this.pdfPage) {
+ var promise = PDFView.getPage(this.id);
+ promise.then(function(pdfPage) {
+ this.setPdfPage(pdfPage);
+ this.draw(callback);
+ }.bind(this));
+ return;
+ }
+
+ if (this.renderingState !== RenderingStates.INITIAL) {
+ console.error('Must be in new state before drawing');
+ }
+
+ this.renderingState = RenderingStates.RUNNING;
+ if (this.hasImage) {
+ callback();
+ return;
+ }
+
+ var self = this;
+ var ctx = this.getPageDrawContext();
+ var drawViewport = this.viewport.clone({ scale: this.scale });
+ var renderContext = {
+ canvasContext: ctx,
+ viewport: drawViewport,
+ continueCallback: function(cont) {
+ if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) {
+ self.renderingState = RenderingStates.PAUSED;
+ self.resume = function() {
+ self.renderingState = RenderingStates.RUNNING;
+ cont();
+ };
+ return;
+ }
+ cont();
+ }
+ };
+ this.pdfPage.render(renderContext).then(
+ function pdfPageRenderCallback() {
+ self.renderingState = RenderingStates.FINISHED;
+ callback();
+ },
+ function pdfPageRenderError(error) {
+ self.renderingState = RenderingStates.FINISHED;
+ callback();
+ }
+ );
+ this.hasImage = true;
+ };
+
+ this.setImage = function thumbnailViewSetImage(img) {
+ if (this.hasImage || !img)
+ return;
+ this.renderingState = RenderingStates.FINISHED;
+ var ctx = this.getPageDrawContext();
+ ctx.drawImage(img, 0, 0, img.width, img.height,
+ 0, 0, ctx.canvas.width, ctx.canvas.height);
+
+ this.hasImage = true;
+ };
+};
+
+var DocumentOutlineView = function documentOutlineView(outline) {
+ var outlineView = document.getElementById('outlineView');
+ while (outlineView.firstChild)
+ outlineView.removeChild(outlineView.firstChild);
+
+ function bindItemLink(domObj, item) {
+ domObj.href = PDFView.getDestinationHash(item.dest);
+ domObj.onclick = function documentOutlineViewOnclick(e) {
+ PDFView.navigateTo(item.dest);
+ return false;
+ };
+ }
+
+ if (!outline) {
+ var noOutline = document.createElement('div');
+ noOutline.classList.add('noOutline');
+ noOutline.textContent = mozL10n.get('no_outline', null,
+ 'No Outline Available');
+ outlineView.appendChild(noOutline);
+ return;
+ }
+
+ var queue = [{parent: outlineView, items: outline}];
+ while (queue.length > 0) {
+ var levelData = queue.shift();
+ var i, n = levelData.items.length;
+ for (i = 0; i < n; i++) {
+ var item = levelData.items[i];
+ var div = document.createElement('div');
+ div.className = 'outlineItem';
+ var a = document.createElement('a');
+ bindItemLink(a, item);
+ a.textContent = item.title;
+ div.appendChild(a);
+
+ if (item.items.length > 0) {
+ var itemsDiv = document.createElement('div');
+ itemsDiv.className = 'outlineItems';
+ div.appendChild(itemsDiv);
+ queue.push({parent: itemsDiv, items: item.items});
+ }
+
+ levelData.parent.appendChild(div);
+ }
+ }
+};
+
+// optimised CSS custom property getter/setter
+var CustomStyle = (function CustomStyleClosure() {
+
+ // As noted on: http://www.zachstronaut.com/posts/2009/02/17/
+ // animate-css-transforms-firefox-webkit.html
+ // in some versions of IE9 it is critical that ms appear in this list
+ // before Moz
+ var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
+ var _cache = { };
+
+ function CustomStyle() {
+ }
+
+ CustomStyle.getProp = function get(propName, element) {
+ // check cache only when no element is given
+ if (arguments.length == 1 && typeof _cache[propName] == 'string') {
+ return _cache[propName];
+ }
+
+ element = element || document.documentElement;
+ var style = element.style, prefixed, uPropName;
+
+ // test standard property first
+ if (typeof style[propName] == 'string') {
+ return (_cache[propName] = propName);
+ }
+
+ // capitalize
+ uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
+
+ // test vendor specific properties
+ for (var i = 0, l = prefixes.length; i < l; i++) {
+ prefixed = prefixes[i] + uPropName;
+ if (typeof style[prefixed] == 'string') {
+ return (_cache[propName] = prefixed);
+ }
+ }
+
+ //if all fails then set to undefined
+ return (_cache[propName] = 'undefined');
+ };
+
+ CustomStyle.setProp = function set(propName, element, str) {
+ var prop = this.getProp(propName);
+ if (prop != 'undefined')
+ element.style[prop] = str;
+ };
+
+ return CustomStyle;
+})();
+
+var TextLayerBuilder = function textLayerBuilder(textLayerDiv, pageIdx) {
+ var textLayerFrag = document.createDocumentFragment();
+
+ this.textLayerDiv = textLayerDiv;
+ this.layoutDone = false;
+ this.divContentDone = false;
+ this.pageIdx = pageIdx;
+ this.matches = [];
+
+ this.beginLayout = function textLayerBuilderBeginLayout() {
+ this.textDivs = [];
+ this.textLayerQueue = [];
+ this.renderingDone = false;
+ };
+
+ this.endLayout = function textLayerBuilderEndLayout() {
+ this.layoutDone = true;
+ this.insertDivContent();
+ };
+
+ this.renderLayer = function textLayerBuilderRenderLayer() {
+ var self = this;
+ var textDivs = this.textDivs;
+ var bidiTexts = this.textContent.bidiTexts;
+ var textLayerDiv = this.textLayerDiv;
+ var canvas = document.createElement('canvas');
+ var ctx = canvas.getContext('2d');
+
+ // No point in rendering so many divs as it'd make the browser unusable
+ // even after the divs are rendered
+ var MAX_TEXT_DIVS_TO_RENDER = 100000;
+ if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER)
+ return;
+
+ for (var i = 0, ii = textDivs.length; i < ii; i++) {
+ var textDiv = textDivs[i];
+ if ('isWhitespace' in textDiv.dataset) {
+ continue;
+ }
+ textLayerFrag.appendChild(textDiv);
+
+ ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
+ var width = ctx.measureText(textDiv.textContent).width;
+
+ if (width > 0) {
+ var textScale = textDiv.dataset.canvasWidth / width;
+
+ var transform = 'scale(' + textScale + ', 1)';
+ if (bidiTexts[i].dir === 'ttb') {
+ transform = 'rotate(90deg) ' + transform;
+ }
+ CustomStyle.setProp('transform' , textDiv, transform);
+ CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
+
+ textLayerDiv.appendChild(textDiv);
+ }
+ }
+
+ this.renderingDone = true;
+ this.updateMatches();
+
+ textLayerDiv.appendChild(textLayerFrag);
+ };
+
+ this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() {
+ // Schedule renderLayout() if user has been scrolling, otherwise
+ // run it right away
+ var RENDER_DELAY = 200; // in ms
+ var self = this;
+ if (Date.now() - PDFView.lastScroll > RENDER_DELAY) {
+ // Render right away
+ this.renderLayer();
+ } else {
+ // Schedule
+ if (this.renderTimer)
+ clearTimeout(this.renderTimer);
+ this.renderTimer = setTimeout(function() {
+ self.setupRenderLayoutTimer();
+ }, RENDER_DELAY);
+ }
+ };
+
+ this.appendText = function textLayerBuilderAppendText(geom) {
+ var textDiv = document.createElement('div');
+
+ // vScale and hScale already contain the scaling to pixel units
+ var fontHeight = geom.fontSize * Math.abs(geom.vScale);
+ textDiv.dataset.canvasWidth = geom.canvasWidth * geom.hScale;
+ textDiv.dataset.fontName = geom.fontName;
+
+ textDiv.style.fontSize = fontHeight + 'px';
+ textDiv.style.fontFamily = geom.fontFamily;
+ textDiv.style.left = geom.x + 'px';
+ textDiv.style.top = (geom.y - fontHeight) + 'px';
+
+ // The content of the div is set in the `setTextContent` function.
+
+ this.textDivs.push(textDiv);
+ };
+
+ this.insertDivContent = function textLayerUpdateTextContent() {
+ // Only set the content of the divs once layout has finished, the content
+ // for the divs is available and content is not yet set on the divs.
+ if (!this.layoutDone || this.divContentDone || !this.textContent)
+ return;
+
+ this.divContentDone = true;
+
+ var textDivs = this.textDivs;
+ var bidiTexts = this.textContent.bidiTexts;
+
+ for (var i = 0; i < bidiTexts.length; i++) {
+ var bidiText = bidiTexts[i];
+ var textDiv = textDivs[i];
+ if (!/\S/.test(bidiText.str)) {
+ textDiv.dataset.isWhitespace = true;
+ continue;
+ }
+
+ textDiv.textContent = bidiText.str;
+ // bidiText.dir may be 'ttb' for vertical texts.
+ textDiv.dir = bidiText.dir === 'rtl' ? 'rtl' : 'ltr';
+ }
+
+ this.setupRenderLayoutTimer();
+ };
+
+ this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
+ this.textContent = textContent;
+ this.insertDivContent();
+ };
+
+ this.convertMatches = function textLayerBuilderConvertMatches(matches) {
+ var i = 0;
+ var iIndex = 0;
+ var bidiTexts = this.textContent.bidiTexts;
+ var end = bidiTexts.length - 1;
+ var queryLen = PDFFindController.state.query.length;
+
+ var lastDivIdx = -1;
+ var pos;
+
+ var ret = [];
+
+ // Loop over all the matches.
+ for (var m = 0; m < matches.length; m++) {
+ var matchIdx = matches[m];
+ // # Calculate the begin position.
+
+ // Loop over the divIdxs.
+ while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
+ iIndex += bidiTexts[i].str.length;
+ i++;
+ }
+
+ // TODO: Do proper handling here if something goes wrong.
+ if (i == bidiTexts.length) {
+ console.error('Could not find matching mapping');
+ }
+
+ var match = {
+ begin: {
+ divIdx: i,
+ offset: matchIdx - iIndex
+ }
+ };
+
+ // # Calculate the end position.
+ matchIdx += queryLen;
+
+ // Somewhat same array as above, but use a > instead of >= to get the end
+ // position right.
+ while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
+ iIndex += bidiTexts[i].str.length;
+ i++;
+ }
+
+ match.end = {
+ divIdx: i,
+ offset: matchIdx - iIndex
+ };
+ ret.push(match);
+ }
+
+ return ret;
+ };
+
+ this.renderMatches = function textLayerBuilder_renderMatches(matches) {
+ // Early exit if there is nothing to render.
+ if (matches.length === 0) {
+ return;
+ }
+
+ var bidiTexts = this.textContent.bidiTexts;
+ var textDivs = this.textDivs;
+ var prevEnd = null;
+ var isSelectedPage = this.pageIdx === PDFFindController.selected.pageIdx;
+ var selectedMatchIdx = PDFFindController.selected.matchIdx;
+ var highlightAll = PDFFindController.state.highlightAll;
+
+ var infty = {
+ divIdx: -1,
+ offset: undefined
+ };
+
+ function beginText(begin, className) {
+ var divIdx = begin.divIdx;
+ var div = textDivs[divIdx];
+ div.textContent = '';
+
+ var content = bidiTexts[divIdx].str.substring(0, begin.offset);
+ var node = document.createTextNode(content);
+ if (className) {
+ var isSelected = isSelectedPage &&
+ divIdx === selectedMatchIdx;
+ var span = document.createElement('span');
+ span.className = className + (isSelected ? ' selected' : '');
+ span.appendChild(node);
+ div.appendChild(span);
+ return;
+ }
+ div.appendChild(node);
+ }
+
+ function appendText(from, to, className) {
+ var divIdx = from.divIdx;
+ var div = textDivs[divIdx];
+
+ var content = bidiTexts[divIdx].str.substring(from.offset, to.offset);
+ var node = document.createTextNode(content);
+ if (className) {
+ var span = document.createElement('span');
+ span.className = className;
+ span.appendChild(node);
+ div.appendChild(span);
+ return;
+ }
+ div.appendChild(node);
+ }
+
+ function highlightDiv(divIdx, className) {
+ textDivs[divIdx].className = className;
+ }
+
+ var i0 = selectedMatchIdx, i1 = i0 + 1, i;
+
+ if (highlightAll) {
+ i0 = 0;
+ i1 = matches.length;
+ } else if (!isSelectedPage) {
+ // Not highlighting all and this isn't the selected page, so do nothing.
+ return;
+ }
+
+ for (i = i0; i < i1; i++) {
+ var match = matches[i];
+ var begin = match.begin;
+ var end = match.end;
+
+ var isSelected = isSelectedPage && i === selectedMatchIdx;
+ var highlightSuffix = (isSelected ? ' selected' : '');
+ if (isSelected)
+ scrollIntoView(textDivs[begin.divIdx], {top: -50});
+
+ // Match inside new div.
+ if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
+ // If there was a previous div, then add the text at the end
+ if (prevEnd !== null) {
+ appendText(prevEnd, infty);
+ }
+ // clears the divs and set the content until the begin point.
+ beginText(begin);
+ } else {
+ appendText(prevEnd, begin);
+ }
+
+ if (begin.divIdx === end.divIdx) {
+ appendText(begin, end, 'highlight' + highlightSuffix);
+ } else {
+ appendText(begin, infty, 'highlight begin' + highlightSuffix);
+ for (var n = begin.divIdx + 1; n < end.divIdx; n++) {
+ highlightDiv(n, 'highlight middle' + highlightSuffix);
+ }
+ beginText(end, 'highlight end' + highlightSuffix);
+ }
+ prevEnd = end;
+ }
+
+ if (prevEnd) {
+ appendText(prevEnd, infty);
+ }
+ };
+
+ this.updateMatches = function textLayerUpdateMatches() {
+ // Only show matches, once all rendering is done.
+ if (!this.renderingDone)
+ return;
+
+ // Clear out all matches.
+ var matches = this.matches;
+ var textDivs = this.textDivs;
+ var bidiTexts = this.textContent.bidiTexts;
+ var clearedUntilDivIdx = -1;
+
+ // Clear out all current matches.
+ for (var i = 0; i < matches.length; i++) {
+ var match = matches[i];
+ var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
+ for (var n = begin; n <= match.end.divIdx; n++) {
+ var div = textDivs[n];
+ div.textContent = bidiTexts[n].str;
+ div.className = '';
+ }
+ clearedUntilDivIdx = match.end.divIdx + 1;
+ }
+
+ if (!PDFFindController.active)
+ return;
+
+ // Convert the matches on the page controller into the match format used
+ // for the textLayer.
+ this.matches = matches =
+ this.convertMatches(PDFFindController.pageMatches[this.pageIdx] || []);
+
+ this.renderMatches(this.matches);
+ };
+};
+
+document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
+ PDFView.initialize();
+ var params = PDFView.parseQueryString(document.location.search.substring(1));
+
+//#if !(FIREFOX || MOZCENTRAL)
+ var file = params.file || DEFAULT_URL;
+//#else
+//var file = window.location.toString()
+//#endif
+
+//#if !(FIREFOX || MOZCENTRAL)
+ if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
+ document.getElementById('openFile').setAttribute('hidden', 'true');
+ } else {
+ document.getElementById('fileInput').value = null;
+ }
+//#else
+//document.getElementById('openFile').setAttribute('hidden', 'true');
+//#endif
+
+ // Special debugging flags in the hash section of the URL.
+ var hash = document.location.hash.substring(1);
+ var hashParams = PDFView.parseQueryString(hash);
+
+ if ('disableWorker' in hashParams)
+ PDFJS.disableWorker = (hashParams['disableWorker'] === 'true');
+
+//#if !(FIREFOX || MOZCENTRAL)
+ var locale = navigator.language;
+ if ('locale' in hashParams)
+ locale = hashParams['locale'];
+ mozL10n.setLanguage(locale);
+//#endif
+
+ if ('textLayer' in hashParams) {
+ switch (hashParams['textLayer']) {
+ case 'off':
+ PDFJS.disableTextLayer = true;
+ break;
+ case 'visible':
+ case 'shadow':
+ case 'hover':
+ var viewer = document.getElementById('viewer');
+ viewer.classList.add('textLayer-' + hashParams['textLayer']);
+ break;
+ }
+ }
+
+//#if !(FIREFOX || MOZCENTRAL)
+ if ('pdfBug' in hashParams) {
+//#else
+//if ('pdfBug' in hashParams && FirefoxCom.requestSync('pdfBugEnabled')) {
+//#endif
+ PDFJS.pdfBug = true;
+ var pdfBug = hashParams['pdfBug'];
+ var enabled = pdfBug.split(',');
+ PDFBug.enable(enabled);
+ PDFBug.init();
+ }
+
+ if (!PDFView.supportsPrinting) {
+ document.getElementById('print').classList.add('hidden');
+ }
+
+ if (!PDFView.supportsFullscreen) {
+ document.getElementById('fullscreen').classList.add('hidden');
+ }
+
+ if (PDFView.supportsIntegratedFind) {
+ document.querySelector('#viewFind').classList.add('hidden');
+ }
+
+ // Listen for warnings to trigger the fallback UI. Errors should be caught
+ // and call PDFView.error() so we don't need to listen for those.
+ PDFJS.LogManager.addLogger({
+ warn: function() {
+ PDFView.fallback();
+ }
+ });
+
+ var mainContainer = document.getElementById('mainContainer');
+ var outerContainer = document.getElementById('outerContainer');
+ mainContainer.addEventListener('transitionend', function(e) {
+ if (e.target == mainContainer) {
+ var event = document.createEvent('UIEvents');
+ event.initUIEvent('resize', false, false, window, 0);
+ window.dispatchEvent(event);
+ outerContainer.classList.remove('sidebarMoving');
+ }
+ }, true);
+
+ document.getElementById('sidebarToggle').addEventListener('click',
+ function() {
+ this.classList.toggle('toggled');
+ outerContainer.classList.add('sidebarMoving');
+ outerContainer.classList.toggle('sidebarOpen');
+ PDFView.sidebarOpen = outerContainer.classList.contains('sidebarOpen');
+ PDFView.renderHighestPriority();
+ });
+
+ document.getElementById('viewThumbnail').addEventListener('click',
+ function() {
+ PDFView.switchSidebarView('thumbs');
+ });
+
+ document.getElementById('viewOutline').addEventListener('click',
+ function() {
+ PDFView.switchSidebarView('outline');
+ });
+
+ document.getElementById('previous').addEventListener('click',
+ function() {
+ PDFView.page--;
+ });
+
+ document.getElementById('next').addEventListener('click',
+ function() {
+ PDFView.page++;
+ });
+
+ document.querySelector('.zoomIn').addEventListener('click',
+ function() {
+ PDFView.zoomIn();
+ });
+
+ document.querySelector('.zoomOut').addEventListener('click',
+ function() {
+ PDFView.zoomOut();
+ });
+
+ document.getElementById('fullscreen').addEventListener('click',
+ function() {
+ PDFView.fullscreen();
+ });
+
+ document.getElementById('openFile').addEventListener('click',
+ function() {
+ document.getElementById('fileInput').click();
+ });
+
+ document.getElementById('print').addEventListener('click',
+ function() {
+ window.print();
+ });
+
+ document.getElementById('download').addEventListener('click',
+ function() {
+ PDFView.download();
+ });
+
+ document.getElementById('pageNumber').addEventListener('click',
+ function() {
+ this.select();
+ });
+
+ document.getElementById('pageNumber').addEventListener('change',
+ function() {
+ // Handle the user inputting a floating point number.
+ PDFView.page = (this.value | 0);
+
+ if (this.value !== (this.value | 0).toString()) {
+ this.value = PDFView.page;
+ }
+ });
+
+ document.getElementById('scaleSelect').addEventListener('change',
+ function() {
+ PDFView.parseScale(this.value);
+ });
+
+ document.getElementById('first_page').addEventListener('click',
+ function() {
+ PDFView.page = 1;
+ });
+
+ document.getElementById('last_page').addEventListener('click',
+ function() {
+ PDFView.page = PDFView.pdfDocument.numPages;
+ });
+
+ document.getElementById('page_rotate_ccw').addEventListener('click',
+ function() {
+ PDFView.rotatePages(-90);
+ });
+
+ document.getElementById('page_rotate_cw').addEventListener('click',
+ function() {
+ PDFView.rotatePages(90);
+ });
+
+//#if (FIREFOX || MOZCENTRAL)
+//if (FirefoxCom.requestSync('getLoadingType') == 'passive') {
+// PDFView.setTitleUsingUrl(file);
+// PDFView.initPassiveLoading();
+// return;
+//}
+//#endif
+
+//#if !B2G
+ PDFView.open(file, 0);
+//#endif
+}, true);
+
+function updateViewarea() {
+
+ if (!PDFView.initialized)
+ return;
+ var visible = PDFView.getVisiblePages();
+ var visiblePages = visible.views;
+ if (visiblePages.length === 0) {
+ return;
+ }
+
+ PDFView.renderHighestPriority();
+
+ var currentId = PDFView.page;
+ var firstPage = visible.first;
+
+ for (var i = 0, ii = visiblePages.length, stillFullyVisible = false;
+ i < ii; ++i) {
+ var page = visiblePages[i];
+
+ if (page.percent < 100)
+ break;
+
+ if (page.id === PDFView.page) {
+ stillFullyVisible = true;
+ break;
+ }
+ }
+
+ if (!stillFullyVisible) {
+ currentId = visiblePages[0].id;
+ }
+
+ if (!PDFView.isFullscreen) {
+ updateViewarea.inProgress = true; // used in "set page"
+ PDFView.page = currentId;
+ updateViewarea.inProgress = false;
+ }
+
+ var currentScale = PDFView.currentScale;
+ var currentScaleValue = PDFView.currentScaleValue;
+ var normalizedScaleValue = currentScaleValue == currentScale ?
+ currentScale * 100 : currentScaleValue;
+
+ var pageNumber = firstPage.id;
+ var pdfOpenParams = '#page=' + pageNumber;
+ pdfOpenParams += '&zoom=' + normalizedScaleValue;
+ var currentPage = PDFView.pages[pageNumber - 1];
+ var topLeft = currentPage.getPagePoint(PDFView.container.scrollLeft,
+ (PDFView.container.scrollTop - firstPage.y));
+ pdfOpenParams += ',' + Math.round(topLeft[0]) + ',' + Math.round(topLeft[1]);
+
+ var store = PDFView.store;
+ store.initializedPromise.then(function() {
+ store.set('exists', true);
+ store.set('page', pageNumber);
+ store.set('zoom', normalizedScaleValue);
+ store.set('scrollLeft', Math.round(topLeft[0]));
+ store.set('scrollTop', Math.round(topLeft[1]));
+ });
+ var href = PDFView.getAnchorUrl(pdfOpenParams);
+ document.getElementById('viewBookmark').href = href;
+}
+
+window.addEventListener('resize', function webViewerResize(evt) {
+ if (PDFView.initialized &&
+ (document.getElementById('pageWidthOption').selected ||
+ document.getElementById('pageFitOption').selected ||
+ document.getElementById('pageAutoOption').selected))
+ PDFView.parseScale(document.getElementById('scaleSelect').value);
+ updateViewarea();
+});
+
+window.addEventListener('hashchange', function webViewerHashchange(evt) {
+ PDFView.setHash(document.location.hash.substring(1));
+});
+
+window.addEventListener('change', function webViewerChange(evt) {
+ var files = evt.target.files;
+ if (!files || files.length === 0)
+ return;
+
+ // Read the local file into a Uint8Array.
+ var fileReader = new FileReader();
+ fileReader.onload = function webViewerChangeFileReaderOnload(evt) {
+ var buffer = evt.target.result;
+ var uint8Array = new Uint8Array(buffer);
+ PDFView.open(uint8Array, 0);
+ };
+
+ var file = files[0];
+ fileReader.readAsArrayBuffer(file);
+ PDFView.setTitleUsingUrl(file.name);
+
+ // URL does not reflect proper document location - hiding some icons.
+ document.getElementById('viewBookmark').setAttribute('hidden', 'true');
+ document.getElementById('download').setAttribute('hidden', 'true');
+}, true);
+
+function selectScaleOption(value) {
+ var options = document.getElementById('scaleSelect').options;
+ var predefinedValueFound = false;
+ for (var i = 0; i < options.length; i++) {
+ var option = options[i];
+ if (option.value != value) {
+ option.selected = false;
+ continue;
+ }
+ option.selected = true;
+ predefinedValueFound = true;
+ }
+ return predefinedValueFound;
+}
+
+window.addEventListener('localized', function localized(evt) {
+ document.getElementsByTagName('html')[0].dir = mozL10n.getDirection();
+
+ // Adjust the width of the zoom box to fit the content.
+ PDFView.animationStartedPromise.then(
+ function() {
+ var container = document.getElementById('scaleSelectContainer');
+ var select = document.getElementById('scaleSelect');
+ select.setAttribute('style', 'min-width: inherit;');
+ var width = select.clientWidth + 8;
+ select.setAttribute('style', 'min-width: ' + (width + 20) + 'px;');
+ container.setAttribute('style', 'min-width: ' + width + 'px; ' +
+ 'max-width: ' + width + 'px;');
+ });
+}, true);
+
+window.addEventListener('scalechange', function scalechange(evt) {
+ var customScaleOption = document.getElementById('customScaleOption');
+ customScaleOption.selected = false;
+
+ if (!evt.resetAutoSettings &&
+ (document.getElementById('pageWidthOption').selected ||
+ document.getElementById('pageFitOption').selected ||
+ document.getElementById('pageAutoOption').selected)) {
+ updateViewarea();
+ return;
+ }
+
+ var predefinedValueFound = selectScaleOption('' + evt.scale);
+ if (!predefinedValueFound) {
+ customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%';
+ customScaleOption.selected = true;
+ }
+
+ document.getElementById('zoom_out').disabled = (evt.scale === MIN_SCALE);
+ document.getElementById('zoom_in').disabled = (evt.scale === MAX_SCALE);
+
+ updateViewarea();
+}, true);
+
+window.addEventListener('pagechange', function pagechange(evt) {
+ var page = evt.pageNumber;
+ if (PDFView.previousPageNumber !== page) {
+ document.getElementById('pageNumber').value = page;
+ var selected = document.querySelector('.thumbnail.selected');
+ if (selected)
+ selected.classList.remove('selected');
+ var thumbnail = document.getElementById('thumbnailContainer' + page);
+ thumbnail.classList.add('selected');
+ var visibleThumbs = PDFView.getVisibleThumbs();
+ var numVisibleThumbs = visibleThumbs.views.length;
+ // If the thumbnail isn't currently visible scroll it into view.
+ if (numVisibleThumbs > 0) {
+ var first = visibleThumbs.first.id;
+ // Account for only one thumbnail being visible.
+ var last = numVisibleThumbs > 1 ?
+ visibleThumbs.last.id : first;
+ if (page <= first || page >= last)
+ scrollIntoView(thumbnail);
+ }
+
+ }
+ document.getElementById('previous').disabled = (page <= 1);
+ document.getElementById('next').disabled = (page >= PDFView.pages.length);
+}, true);
+
+// Firefox specific event, so that we can prevent browser from zooming
+window.addEventListener('DOMMouseScroll', function(evt) {
+ if (evt.ctrlKey) {
+ evt.preventDefault();
+
+ var ticks = evt.detail;
+ var direction = (ticks > 0) ? 'zoomOut' : 'zoomIn';
+ for (var i = 0, length = Math.abs(ticks); i < length; i++)
+ PDFView[direction]();
+ } else if (PDFView.isFullscreen) {
+ var FIREFOX_DELTA_FACTOR = -40;
+ PDFView.mouseScroll(evt.detail * FIREFOX_DELTA_FACTOR);
+ }
+}, false);
+
+window.addEventListener('mousemove', function mousemove(evt) {
+ if (PDFView.isFullscreen) {
+ PDFView.showPresentationControls();
+ }
+}, false);
+
+window.addEventListener('mousedown', function mousedown(evt) {
+ if (PDFView.isFullscreen && evt.button === 0) {
+ // Enable clicking of links in fullscreen mode.
+ // Note: Only links that point to the currently loaded PDF document works.
+ var targetHref = evt.target.href;
+ var internalLink = targetHref && (targetHref.replace(/#.*$/, '') ===
+ window.location.href.replace(/#.*$/, ''));
+ if (!internalLink) {
+ // Unless an internal link was clicked, advance a page in fullscreen mode.
+ evt.preventDefault();
+ PDFView.page++;
+ }
+ }
+}, false);
+
+window.addEventListener('click', function click(evt) {
+ if (PDFView.isFullscreen && evt.button === 0) {
+ // Necessary since preventDefault() in 'mousedown' won't stop
+ // the event propagation in all circumstances.
+ evt.preventDefault();
+ }
+}, false);
+
+window.addEventListener('keydown', function keydown(evt) {
+ var handled = false;
+ var cmd = (evt.ctrlKey ? 1 : 0) |
+ (evt.altKey ? 2 : 0) |
+ (evt.shiftKey ? 4 : 0) |
+ (evt.metaKey ? 8 : 0);
+
+ // First, handle the key bindings that are independent whether an input
+ // control is selected or not.
+ if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {
+ // either CTRL or META key with optional SHIFT.
+ switch (evt.keyCode) {
+ case 70:
+ if (!PDFView.supportsIntegratedFind) {
+ PDFFindBar.toggle();
+ handled = true;
+ }
+ break;
+ case 61: // FF/Mac '='
+ case 107: // FF '+' and '='
+ case 187: // Chrome '+'
+ case 171: // FF with German keyboard
+ PDFView.zoomIn();
+ handled = true;
+ break;
+ case 173: // FF/Mac '-'
+ case 109: // FF '-'
+ case 189: // Chrome '-'
+ PDFView.zoomOut();
+ handled = true;
+ break;
+ case 48: // '0'
+ case 96: // '0' on Numpad of Swedish keyboard
+ PDFView.parseScale(DEFAULT_SCALE, true);
+ handled = false; // keeping it unhandled (to restore page zoom to 100%)
+ break;
+ }
+ }
+
+ // CTRL or META with or without SHIFT.
+ if (cmd == 1 || cmd == 8 || cmd == 5 || cmd == 12) {
+ switch (evt.keyCode) {
+ case 71: // g
+ if (!PDFView.supportsIntegratedFind) {
+ PDFFindBar.dispatchEvent('again', cmd == 5 || cmd == 12);
+ handled = true;
+ }
+ break;
+ }
+ }
+
+ if (handled) {
+ evt.preventDefault();
+ return;
+ }
+
+ // Some shortcuts should not get handled if a control/input element
+ // is selected.
+ var curElement = document.activeElement;
+ if (curElement && (curElement.tagName == 'INPUT' ||
+ curElement.tagName == 'SELECT')) {
+ return;
+ }
+ var controlsElement = document.getElementById('toolbar');
+ while (curElement) {
+ if (curElement === controlsElement && !PDFView.isFullscreen)
+ return; // ignoring if the 'toolbar' element is focused
+ curElement = curElement.parentNode;
+ }
+
+ if (cmd === 0) { // no control key pressed at all.
+ switch (evt.keyCode) {
+ case 38: // up arrow
+ case 33: // pg up
+ case 8: // backspace
+ if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') {
+ break;
+ }
+ /* in fullscreen mode */
+ /* falls through */
+ case 37: // left arrow
+ // horizontal scrolling using arrow keys
+ if (PDFView.isHorizontalScrollbarEnabled) {
+ break;
+ }
+ /* falls through */
+ case 75: // 'k'
+ case 80: // 'p'
+ PDFView.page--;
+ handled = true;
+ break;
+ case 27: // esc key
+ if (!PDFView.supportsIntegratedFind && PDFFindBar.opened) {
+ PDFFindBar.close();
+ handled = true;
+ }
+ break;
+ case 40: // down arrow
+ case 34: // pg down
+ case 32: // spacebar
+ if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') {
+ break;
+ }
+ /* falls through */
+ case 39: // right arrow
+ // horizontal scrolling using arrow keys
+ if (PDFView.isHorizontalScrollbarEnabled) {
+ break;
+ }
+ /* falls through */
+ case 74: // 'j'
+ case 78: // 'n'
+ PDFView.page++;
+ handled = true;
+ break;
+
+ case 36: // home
+ if (PDFView.isFullscreen) {
+ PDFView.page = 1;
+ handled = true;
+ }
+ break;
+ case 35: // end
+ if (PDFView.isFullscreen) {
+ PDFView.page = PDFView.pdfDocument.numPages;
+ handled = true;
+ }
+ break;
+
+ case 82: // 'r'
+ PDFView.rotatePages(90);
+ break;
+ }
+ }
+
+ if (cmd == 4) { // shift-key
+ switch (evt.keyCode) {
+ case 82: // 'r'
+ PDFView.rotatePages(-90);
+ break;
+ }
+ }
+
+ if (handled) {
+ evt.preventDefault();
+ PDFView.clearMouseScrollState();
+ }
+});
+
+window.addEventListener('beforeprint', function beforePrint(evt) {
+ PDFView.beforePrint();
+});
+
+window.addEventListener('afterprint', function afterPrint(evt) {
+ PDFView.afterPrint();
+});
+
+(function fullscreenClosure() {
+ function fullscreenChange(e) {
+ var isFullscreen = document.fullscreenElement || document.mozFullScreen ||
+ document.webkitIsFullScreen;
+
+ if (!isFullscreen) {
+ PDFView.exitFullscreen();
+ }
+ }
+
+ window.addEventListener('fullscreenchange', fullscreenChange, false);
+ window.addEventListener('mozfullscreenchange', fullscreenChange, false);
+ window.addEventListener('webkitfullscreenchange', fullscreenChange, false);
+})();
+
+(function animationStartedClosure() {
+ // The offsetParent is not set until the pdf.js iframe or object is visible.
+ // Waiting for first animation.
+ var requestAnimationFrame = window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function startAtOnce(callback) { callback(); };
+ PDFView.animationStartedPromise = new PDFJS.Promise();
+ requestAnimationFrame(function onAnimationFrame() {
+ PDFView.animationStartedPromise.resolve();
+ });
+})();
+
+//#if B2G
+//window.navigator.mozSetMessageHandler('activity', function(activity) {
+// var url = activity.source.data.url;
+// PDFView.open(url);
+// var cancelButton = document.getElementById('activityClose');
+// cancelButton.addEventListener('click', function() {
+// activity.postResult('close');
+// });
+//});
+//#endif