Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 (function() { | 5 (function() { |
| 6 'use strict'; | 6 'use strict'; |
| 7 | 7 |
| 8 <include src="../../../../ui/webui/resources/js/util.js"></include> | 8 <include src="../../../../ui/webui/resources/js/util.js"></include> |
| 9 <include src="viewport.js"></include> | 9 <include src="viewport.js"></include> |
| 10 | 10 |
| 11 // The plugin element is sized to fill the entire window and is set to be fixed | 11 /** |
| 12 // positioning, acting as a viewport. The plugin renders into this viewport | 12 * Creates a new PDFViewer. |
| 13 // according to the scroll position of the window. | 13 */ |
| 14 var plugin; | 14 function PDFViewer() { |
| 15 | 15 // The sizer element is placed behind the plugin element to cause scrollbars |
| 16 // This element is placed behind the plugin element to cause scrollbars to be | 16 // to be displayed in the window. It is sized according to the document size |
| 17 // displayed in the window. It is sized according to the document size of the | 17 // of the pdf and zoom level. |
| 18 // pdf and zoom level. | 18 this.sizer_ = $('sizer'); |
|
arv (Not doing code reviews)
2014/04/07 21:01:44
This pattern is a bit strange. You are creating a
raymes
2014/04/08 01:44:06
It is a bit weird. It would be less weird if the d
arv (Not doing code reviews)
2014/04/08 16:36:22
Now that I look at it. Why is everything private?
| |
| 19 var sizer; | 19 this.toolbar_ = $('toolbar'); |
| 20 | 20 this.pageIndicator_ = $('page-indicator'); |
| 21 // The toolbar element. | 21 this.progressBar_ = $('progress-bar'); |
| 22 var viewerToolbar; | 22 this.passwordScreen_ = $('password-screen'); |
| 23 | 23 this.passwordScreen_.addEventListener('password-submitted', |
| 24 // The page indicator element. | 24 this.onPasswordSubmitted_.bind(this)); |
| 25 var viewerPageIndicator; | 25 this.errorScreen_ = $('error-screen'); |
| 26 | 26 this.errorScreen_.text = 'Failed to load PDF document'; |
| 27 // The progress bar element. | |
| 28 var viewerProgressBar; | |
| 29 | |
| 30 // The element indicating there was an error loading the document. | |
| 31 var viewerErrorScreen; | |
| 32 | |
| 33 // The viewport object. | |
| 34 var viewport; | |
| 35 | |
| 36 // The element displaying the password screen. | |
| 37 var viewerPasswordScreen; | |
| 38 | |
| 39 // The document dimensions. | |
| 40 var documentDimensions; | |
| 41 | |
| 42 // Notify the plugin to print. | |
| 43 function print() { | |
| 44 plugin.postMessage({ | |
| 45 type: 'print', | |
| 46 }); | |
| 47 } | |
| 48 | |
| 49 // Returns true if the fit-to-page button is enabled. | |
| 50 function isFitToPageEnabled() { | |
| 51 return $('fit-to-page-button').classList.contains('polymer-selected'); | |
| 52 } | |
| 53 | |
| 54 function updateProgress(progress) { | |
| 55 viewerProgressBar.progress = progress; | |
| 56 if (progress == -1) { | |
| 57 // Document load failed. | |
| 58 viewerErrorScreen.style.visibility = 'visible'; | |
| 59 sizer.style.display = 'none'; | |
| 60 viewerToolbar.style.visibility = 'hidden'; | |
| 61 if (viewerPasswordScreen.active) { | |
| 62 viewerPasswordScreen.deny(); | |
| 63 viewerPasswordScreen.active = false; | |
| 64 } | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 function onPasswordSubmitted(event) { | |
| 69 plugin.postMessage({ | |
| 70 type: 'getPasswordComplete', | |
| 71 password: event.detail.password | |
| 72 }); | |
| 73 } | |
| 74 | |
| 75 // Called when a message is received from the plugin. | |
| 76 function handleMessage(message) { | |
| 77 switch (message.data.type.toString()) { | |
| 78 case 'documentDimensions': | |
| 79 documentDimensions = message.data; | |
| 80 viewport.setDocumentDimensions(documentDimensions); | |
| 81 viewerToolbar.style.visibility = 'visible'; | |
| 82 // If we received the document dimensions, the password was good so we can | |
| 83 // dismiss the password screen. | |
| 84 if (viewerPasswordScreen.active) | |
| 85 viewerPasswordScreen.accept(); | |
| 86 | |
| 87 viewerPageIndicator.initialFadeIn(); | |
| 88 viewerToolbar.initialFadeIn(); | |
| 89 break; | |
| 90 case 'loadProgress': | |
| 91 updateProgress(message.data.progress); | |
| 92 break; | |
| 93 case 'goToPage': | |
| 94 viewport.goToPage(message.data.page); | |
| 95 break; | |
| 96 case 'getPassword': | |
| 97 // If the password screen isn't up, put it up. Otherwise we're responding | |
| 98 // to an incorrect password so deny it. | |
| 99 if (!viewerPasswordScreen.active) | |
| 100 viewerPasswordScreen.active = true; | |
| 101 else | |
| 102 viewerPasswordScreen.deny(); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 // Callback that's called when the viewport changes. | |
| 107 function viewportChangedCallback(zoom, | |
| 108 x, | |
| 109 y, | |
| 110 scrollbarWidth, | |
| 111 hasScrollbars, | |
| 112 page) { | |
| 113 // Offset the toolbar position so that it doesn't move if scrollbars appear. | |
| 114 var toolbarRight = hasScrollbars.y ? 0 : scrollbarWidth; | |
| 115 var toolbarBottom = hasScrollbars.x ? 0 : scrollbarWidth; | |
| 116 viewerToolbar.style.right = toolbarRight + 'px'; | |
| 117 viewerToolbar.style.bottom = toolbarBottom + 'px'; | |
| 118 | |
| 119 // Show or hide the page indicator. | |
| 120 if (documentDimensions.pageDimensions.length > 1 && hasScrollbars.y) | |
| 121 viewerPageIndicator.style.visibility = 'visible'; | |
| 122 else | |
| 123 viewerPageIndicator.style.visibility = 'hidden'; | |
| 124 | |
| 125 // Update the most visible page. | |
| 126 viewerPageIndicator.text = page + 1; | |
| 127 | |
| 128 // Notify the plugin of the viewport change. | |
| 129 plugin.postMessage({ | |
| 130 type: 'viewport', | |
| 131 zoom: zoom, | |
| 132 xOffset: x, | |
| 133 yOffset: y | |
| 134 }); | |
| 135 } | |
| 136 | |
| 137 function load() { | |
| 138 sizer = $('sizer'); | |
| 139 viewerToolbar = $('toolbar'); | |
| 140 viewerPageIndicator = $('page-indicator'); | |
| 141 viewerProgressBar = $('progress-bar'); | |
| 142 viewerPasswordScreen = $('password-screen'); | |
| 143 viewerPasswordScreen.addEventListener('password-submitted', | |
| 144 onPasswordSubmitted); | |
| 145 viewerErrorScreen = $('error-screen'); | |
| 146 viewerErrorScreen.text = 'Failed to load PDF document'; | |
| 147 | 27 |
| 148 // Create the viewport. | 28 // Create the viewport. |
| 149 viewport = new Viewport(window, | 29 this.viewport_ = new Viewport(window, |
| 150 sizer, | 30 this.sizer_, |
| 151 isFitToPageEnabled, | 31 this.isFitToPageEnabled_.bind(this), |
| 152 viewportChangedCallback); | 32 this.viewportChangedCallback_.bind(this)); |
| 153 | 33 |
| 154 // Create the plugin object dynamically so we can set its src. | 34 // Create the plugin object dynamically so we can set its src. The plugin |
| 155 plugin = document.createElement('object'); | 35 // element is sized to fill the entire window and is set to be fixed |
| 156 plugin.id = 'plugin'; | 36 // positioning, acting as a viewport. The plugin renders into this viewport |
| 157 plugin.type = 'application/x-google-chrome-pdf'; | 37 // according to the scroll position of the window. |
| 158 plugin.addEventListener('message', handleMessage, false); | 38 this.plugin_ = document.createElement('object'); |
| 39 this.plugin_.id = 'plugin'; | |
| 40 this.plugin_.type = 'application/x-google-chrome-pdf'; | |
| 41 this.plugin_.addEventListener('message', this.handleMessage_.bind(this), | |
| 42 false); | |
| 159 // The pdf location is passed in stream details in the background page. | 43 // The pdf location is passed in stream details in the background page. |
| 160 var streamDetails = chrome.extension.getBackgroundPage().popStreamDetails(); | 44 var streamDetails = chrome.extension.getBackgroundPage().popStreamDetails(); |
| 161 plugin.setAttribute('src', streamDetails.streamUrl); | 45 this.plugin_.setAttribute('src', streamDetails.streamUrl); |
| 162 document.body.appendChild(plugin); | 46 document.body.appendChild(this.plugin_); |
| 163 | 47 |
| 164 // Setup the button event listeners. | 48 this.setupEventListeners_(streamDetails); |
| 165 $('fit-to-width-button').addEventListener('click', | 49 } |
| 166 viewport.fitToWidth.bind(viewport)); | 50 |
| 167 $('fit-to-page-button').addEventListener('click', | 51 PDFViewer.prototype = { |
| 168 viewport.fitToPage.bind(viewport)); | 52 /** |
| 169 $('zoom-in-button').addEventListener('click', | 53 * @private |
| 170 viewport.zoomIn.bind(viewport)); | 54 * Sets up event listeners for key shortcuts and also the UI buttons. |
| 171 $('zoom-out-button').addEventListener('click', | 55 * @param {Object} streamDetails the details of the original HTTP request for |
| 172 viewport.zoomOut.bind(viewport)); | 56 * the PDF. |
| 173 $('save-button-link').href = streamDetails.originalUrl; | 57 */ |
| 174 $('print-button').addEventListener('click', print); | 58 setupEventListeners_: function(streamDetails) { |
| 175 | 59 // Setup the button event listeners. |
| 176 | 60 $('fit-to-width-button').addEventListener('click', |
| 177 // Setup keyboard event listeners. | 61 this.viewport_.fitToWidth.bind(this.viewport_)); |
| 178 document.onkeydown = function(e) { | 62 $('fit-to-page-button').addEventListener('click', |
| 179 switch (e.keyCode) { | 63 this.viewport_.fitToPage.bind(this.viewport_)); |
| 180 case 37: // Left arrow key. | 64 $('zoom-in-button').addEventListener('click', |
| 181 // Go to the previous page if there are no horizontal scrollbars. | 65 this.viewport_.zoomIn.bind(this.viewport_)); |
| 182 if (!viewport.documentHasScrollbars().x) { | 66 $('zoom-out-button').addEventListener('click', |
| 183 viewport.goToPage(viewport.getMostVisiblePage() - 1); | 67 this.viewport_.zoomOut.bind(this.viewport_)); |
| 184 // Since we do the movement of the page. | 68 $('save-button-link').href = streamDetails.originalUrl; |
| 185 e.preventDefault(); | 69 $('print-button').addEventListener('click', this.print_.bind(this)); |
| 186 } | 70 |
| 187 return; | 71 // Setup keyboard event listeners. |
| 188 case 33: // Page up key. | 72 document.onkeydown = function(e) { |
| 189 // Go to the previous page if we are fit-to-page. | 73 switch (e.keyCode) { |
| 190 if (isFitToPageEnabled()) { | 74 case 37: // Left arrow key. |
| 191 viewport.goToPage(viewport.getMostVisiblePage() - 1); | 75 // Go to the previous page if there are no horizontal scrollbars. |
| 192 // Since we do the movement of the page. | 76 if (!this.viewport_.documentHasScrollbars().x) { |
|
arv (Not doing code reviews)
2014/04/07 21:01:44
this is not lexically bound but dynamically bound.
raymes
2014/04/08 01:44:06
Good catch :) I bound the function.
| |
| 193 e.preventDefault(); | 77 this.viewport_.goToPage(this.viewport_.getMostVisiblePage() - 1); |
| 194 } | 78 // Since we do the movement of the page. |
| 195 return; | 79 e.preventDefault(); |
| 196 case 39: // Right arrow key. | 80 } |
| 197 // Go to the next page if there are no horizontal scrollbars. | 81 return; |
| 198 if (!viewport.documentHasScrollbars().x) { | 82 case 33: // Page up key. |
| 199 viewport.goToPage(viewport.getMostVisiblePage() + 1); | 83 // Go to the previous page if we are fit-to-page. |
| 200 // Since we do the movement of the page. | 84 if (isFitToPageEnabled()) { |
| 201 e.preventDefault(); | 85 this.viewport_.goToPage(this.viewport_.getMostVisiblePage() - 1); |
| 202 } | 86 // Since we do the movement of the page. |
| 203 return; | 87 e.preventDefault(); |
| 204 case 34: // Page down key. | 88 } |
| 205 // Go to the next page if we are fit-to-page. | 89 return; |
| 206 if (isFitToPageEnabled()) { | 90 case 39: // Right arrow key. |
| 207 viewport.goToPage(viewport.getMostVisiblePage() + 1); | 91 // Go to the next page if there are no horizontal scrollbars. |
| 208 // Since we do the movement of the page. | 92 if (!this.viewport_.documentHasScrollbars().x) { |
| 209 e.preventDefault(); | 93 this.viewport_.goToPage(this.viewport_.getMostVisiblePage() + 1); |
| 210 } | 94 // Since we do the movement of the page. |
| 211 return; | 95 e.preventDefault(); |
| 212 case 187: // +/= key. | 96 } |
| 213 case 107: // Numpad + key. | 97 return; |
| 214 if (e.ctrlKey || e.metaKey) { | 98 case 34: // Page down key. |
| 215 viewport.zoomIn(); | 99 // Go to the next page if we are fit-to-page. |
| 216 // Since we do the zooming of the page. | 100 if (isFitToPageEnabled()) { |
| 217 e.preventDefault(); | 101 this.viewport_.goToPage(this.viewport_.getMostVisiblePage() + 1); |
| 218 } | 102 // Since we do the movement of the page. |
| 219 return; | 103 e.preventDefault(); |
| 220 case 189: // -/_ key. | 104 } |
| 221 case 109: // Numpad - key. | 105 return; |
| 222 if (e.ctrlKey || e.metaKey) { | 106 case 187: // +/= key. |
| 223 viewport.zoomOut(); | 107 case 107: // Numpad + key. |
| 224 // Since we do the zooming of the page. | 108 if (e.ctrlKey || e.metaKey) { |
| 225 e.preventDefault(); | 109 this.viewport_.zoomIn(); |
| 226 } | 110 // Since we do the zooming of the page. |
| 227 return; | 111 e.preventDefault(); |
| 228 case 83: // s key. | 112 } |
| 229 if (e.ctrlKey || e.metaKey) { | 113 return; |
| 230 // Simulate a click on the button so that the <a download ...> | 114 case 189: // -/_ key. |
| 231 // attribute is used. | 115 case 109: // Numpad - key. |
| 232 $('save-button-link').click(); | 116 if (e.ctrlKey || e.metaKey) { |
| 233 // Since we do the saving of the page. | 117 this.viewport_.zoomOut(); |
| 234 e.preventDefault(); | 118 // Since we do the zooming of the page. |
| 235 } | 119 e.preventDefault(); |
| 236 return; | 120 } |
| 237 case 80: // p key. | 121 return; |
| 238 if (e.ctrlKey || e.metaKey) { | 122 case 83: // s key. |
| 239 print(); | 123 if (e.ctrlKey || e.metaKey) { |
| 240 // Since we do the printing of the page. | 124 // Simulate a click on the button so that the <a download ...> |
| 241 e.preventDefault(); | 125 // attribute is used. |
| 242 } | 126 $('save-button-link').click(); |
| 243 return; | 127 // Since we do the saving of the page. |
| 128 e.preventDefault(); | |
| 129 } | |
| 130 return; | |
| 131 case 80: // p key. | |
| 132 if (e.ctrlKey || e.metaKey) { | |
| 133 this.print_(); | |
| 134 // Since we do the printing of the page. | |
| 135 e.preventDefault(); | |
| 136 } | |
| 137 return; | |
| 138 } | |
| 139 }; | |
| 140 }, | |
| 141 | |
| 142 | |
| 143 /** | |
| 144 * @private | |
| 145 * Notify the plugin to print. | |
| 146 */ | |
| 147 print_: function() { | |
| 148 this.plugin_.postMessage({ | |
| 149 type: 'print', | |
| 150 }); | |
| 151 }, | |
| 152 | |
| 153 /** | |
| 154 * @private | |
| 155 * @return {boolean} true if the fit-to-page button is enabled. | |
| 156 */ | |
| 157 isFitToPageEnabled_: function() { | |
| 158 return $('fit-to-page-button').classList.contains('polymer-selected'); | |
| 159 }, | |
| 160 | |
| 161 /** | |
| 162 * @private | |
| 163 * Update the loading progress of the document in response to a progress | |
| 164 * message being received from the plugin. | |
| 165 * @param {number} progress the progress as a percentage. | |
| 166 */ | |
| 167 updateProgress_: function(progress) { | |
| 168 this.progressBar_.progress = progress; | |
| 169 if (progress == -1) { | |
| 170 // Document load failed. | |
| 171 this.errorScreen_.style.visibility = 'visible'; | |
| 172 this.sizer_.style.display = 'none'; | |
| 173 this.toolbar_.style.visibility = 'hidden'; | |
| 174 if (this.passwordScreen_.active) { | |
| 175 this.passwordScreen_.deny(); | |
| 176 this.passwordScreen_.active = false; | |
| 177 } | |
| 244 } | 178 } |
| 245 }; | 179 }, |
| 180 | |
| 181 /** | |
| 182 * @private | |
| 183 * An event handler for handling password-submitted events. These are fired | |
| 184 * when an event is entered into the password screen. | |
| 185 * @param {Object} event a password-submitted event. | |
| 186 */ | |
| 187 onPasswordSubmitted_: function(event) { | |
| 188 this.plugin_.postMessage({ | |
| 189 type: 'getPasswordComplete', | |
| 190 password: event.detail.password | |
| 191 }); | |
| 192 }, | |
| 193 | |
| 194 /** | |
| 195 * @private | |
| 196 * An event handler for handling message events received from the plugin. | |
| 197 * @param {Object} message a message event. | |
|
arv (Not doing code reviews)
2014/04/07 21:01:44
Maybe use {MessageEvent} as the type?
raymes
2014/04/08 01:44:06
Done.
| |
| 198 */ | |
| 199 handleMessage_: function(message) { | |
| 200 switch (message.data.type.toString()) { | |
| 201 case 'documentDimensions': | |
| 202 this.documentDimensions_ = message.data; | |
| 203 this.viewport_.setDocumentDimensions(this.documentDimensions_); | |
| 204 this.toolbar_.style.visibility = 'visible'; | |
| 205 // If we received the document dimensions, the password was good so we | |
| 206 // can dismiss the password screen. | |
| 207 if (this.passwordScreen_.active) | |
| 208 this.passwordScreen_.accept(); | |
| 209 | |
| 210 this.pageIndicator_.initialFadeIn(); | |
| 211 this.toolbar_.initialFadeIn(); | |
| 212 break; | |
| 213 case 'loadProgress': | |
| 214 this.updateProgress_(message.data.progress); | |
| 215 break; | |
| 216 case 'goToPage': | |
| 217 this.viewport_.goToPage(message.data.page); | |
| 218 break; | |
| 219 case 'getPassword': | |
| 220 // If the password screen isn't up, put it up. Otherwise we're | |
| 221 // responding to an incorrect password so deny it. | |
| 222 if (!this.passwordScreen_.active) | |
| 223 this.passwordScreen_.active = true; | |
| 224 else | |
| 225 this.passwordScreen_.deny(); | |
| 226 } | |
| 227 }, | |
| 228 | |
| 229 /** | |
| 230 * @private | |
| 231 * A callback that's called when the viewport changes. | |
| 232 * @param {number} zoom the zoom level. | |
| 233 * @param {number} x the x scroll coordinate. | |
| 234 * @param {number} y the y scroll coordinate. | |
| 235 * @param {number} scrollbarWidth the width of scrollbars on the page. | |
| 236 * @param {Object} hasScrollbars whether the viewport has a | |
| 237 * horizontal/vertical scrollbar. | |
| 238 * @param {number} page the index of the most visible page in the viewport. | |
| 239 */ | |
| 240 viewportChangedCallback_: function(zoom, | |
| 241 x, | |
| 242 y, | |
| 243 scrollbarWidth, | |
| 244 hasScrollbars, | |
| 245 page) { | |
| 246 // Offset the toolbar position so that it doesn't move if scrollbars appear. | |
| 247 var toolbarRight = hasScrollbars.y ? 0 : scrollbarWidth; | |
| 248 var toolbarBottom = hasScrollbars.x ? 0 : scrollbarWidth; | |
| 249 this.toolbar_.style.right = toolbarRight + 'px'; | |
| 250 this.toolbar_.style.bottom = toolbarBottom + 'px'; | |
| 251 | |
| 252 // Show or hide the page indicator. | |
| 253 if (this.documentDimensions_.pageDimensions.length > 1 && hasScrollbars.y) | |
| 254 this.pageIndicator_.style.visibility = 'visible'; | |
| 255 else | |
| 256 this.pageIndicator_.style.visibility = 'hidden'; | |
| 257 | |
| 258 // Update the most visible page. | |
| 259 this.pageIndicator_.text = page + 1; | |
| 260 | |
| 261 // Notify the plugin of the viewport change. | |
| 262 this.plugin_.postMessage({ | |
| 263 type: 'viewport', | |
| 264 zoom: zoom, | |
| 265 xOffset: x, | |
| 266 yOffset: y | |
| 267 }); | |
| 268 }, | |
| 246 } | 269 } |
| 247 | 270 |
| 248 load(); | 271 new PDFViewer(); |
| 249 | 272 |
| 250 })(); | 273 })(); |
| OLD | NEW |