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 |