Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1260)

Side by Side Diff: ui/file_manager/video_player/js/video_player.js

Issue 307863004: [Video Player] Re-factoring the code (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed the comments Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/file_manager/video_player/js/background.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 'use strict'; 5 'use strict';
6 6
7 /** 7 /**
8 * Displays error message.
9 * @param {string} message Message id.
10 */
11 function showErrorMessage(message) {
12 var errorBanner = document.querySelector('#error');
13 errorBanner.textContent =
14 loadTimeData.getString(message);
15 errorBanner.setAttribute('visible', 'true');
16
17 // The window is hidden if the video has not loaded yet.
18 chrome.app.window.current().show();
19 }
20
21 /**
22 * Handles playback (decoder) errors.
23 */
24 function onPlaybackError() {
25 showErrorMessage('GALLERY_VIDEO_DECODING_ERROR');
26 decodeErrorOccured = true;
27
28 // Disable inactivity watcher, and disable the ui, by hiding tools manually.
29 controls.inactivityWatcher.disabled = true;
30 document.querySelector('#video-player').setAttribute('disabled', 'true');
31
32 // Detach the video element, since it may be unreliable and reset stored
33 // current playback time.
34 controls.cleanup();
35 controls.clearState();
36
37 // Avoid reusing a video element.
38 video.parentNode.removeChild(video);
39 video = null;
40 }
41
42 /**
43 * @param {Element} playerContainer Main container. 8 * @param {Element} playerContainer Main container.
44 * @param {Element} videoContainer Container for the video element. 9 * @param {Element} videoContainer Container for the video element.
45 * @param {Element} controlsContainer Container for video controls. 10 * @param {Element} controlsContainer Container for video controls.
46 * @constructor 11 * @constructor
47 */ 12 */
48 function FullWindowVideoControls( 13 function FullWindowVideoControls(
49 playerContainer, videoContainer, controlsContainer) { 14 playerContainer, videoContainer, controlsContainer) {
50 VideoControls.call(this, 15 VideoControls.call(this,
51 controlsContainer, 16 controlsContainer,
52 onPlaybackError, 17 this.onPlaybackError_.wrap(this),
53 loadTimeData.getString.wrap(loadTimeData), 18 loadTimeData.getString.wrap(loadTimeData),
54 this.toggleFullScreen_.wrap(this), 19 this.toggleFullScreen_.wrap(this),
55 videoContainer); 20 videoContainer);
56 21
57 this.playerContainer_ = playerContainer; 22 this.playerContainer_ = playerContainer;
23 this.decodeErrorOccured = false;
58 24
59 this.updateStyle(); 25 this.updateStyle();
60 window.addEventListener('resize', this.updateStyle.wrap(this)); 26 window.addEventListener('resize', this.updateStyle.wrap(this));
61
62 document.addEventListener('keydown', function(e) { 27 document.addEventListener('keydown', function(e) {
63 if (e.keyIdentifier == 'U+0020') { // Space 28 if (e.keyIdentifier == 'U+0020') { // Space
64 this.togglePlayStateWithFeedback(); 29 this.togglePlayStateWithFeedback();
65 e.preventDefault(); 30 e.preventDefault();
66 } 31 }
67 if (e.keyIdentifier == 'U+001B') { // Escape 32 if (e.keyIdentifier == 'U+001B') { // Escape
68 util.toggleFullScreen( 33 util.toggleFullScreen(
69 chrome.app.window.current(), 34 chrome.app.window.current(),
70 false); // Leave the full screen mode. 35 false); // Leave the full screen mode.
71 e.preventDefault(); 36 e.preventDefault();
(...skipping 15 matching lines...) Expand all
87 this.__defineGetter__('inactivityWatcher', function() { 52 this.__defineGetter__('inactivityWatcher', function() {
88 return this.inactivityWatcher_; 53 return this.inactivityWatcher_;
89 }); 54 });
90 55
91 this.inactivityWatcher_.check(); 56 this.inactivityWatcher_.check();
92 } 57 }
93 58
94 FullWindowVideoControls.prototype = { __proto__: VideoControls.prototype }; 59 FullWindowVideoControls.prototype = { __proto__: VideoControls.prototype };
95 60
96 /** 61 /**
62 * Displays error message.
63 * @param {string} message Message id.
64 * @private
65 */
66 FullWindowVideoControls.prototype.showErrorMessage_ = function(message) {
67 var errorBanner = document.querySelector('#error');
68 errorBanner.textContent =
69 loadTimeData.getString(message);
70 errorBanner.setAttribute('visible', 'true');
71
72 // The window is hidden if the video has not loaded yet.
73 chrome.app.window.current().show();
74 };
75
76 /**
77 * Handles playback (decoder) errors.
78 * @private
79 */
80 FullWindowVideoControls.prototype.onPlaybackError_ = function() {
81 this.showErrorMessage_('GALLERY_VIDEO_DECODING_ERROR');
82 this.decodeErrorOccured = true;
83
84 // Disable inactivity watcher, and disable the ui, by hiding tools manually.
85 this.inactivityWatcher.disabled = true;
86 document.querySelector('#video-player').setAttribute('disabled', 'true');
87
88 // Detach the video element, since it may be unreliable and reset stored
89 // current playback time.
90 this.cleanup();
91 this.clearState();
92
93 // Avoid reusing a video element.
94 player.unloadVideo();
95 };
96
97 /**
97 * Toggles the full screen mode. 98 * Toggles the full screen mode.
98 * @private 99 * @private
99 */ 100 */
100 FullWindowVideoControls.prototype.toggleFullScreen_ = function() { 101 FullWindowVideoControls.prototype.toggleFullScreen_ = function() {
101 var appWindow = chrome.app.window.current(); 102 var appWindow = chrome.app.window.current();
102 util.toggleFullScreen(appWindow, !util.isFullScreen(appWindow)); 103 util.toggleFullScreen(appWindow, !util.isFullScreen(appWindow));
103 }; 104 };
104 105
105 // TODO(mtomasz): Convert it to class members: crbug.com/171191. 106 // TODO(mtomasz): Convert it to class members: crbug.com/171191.
106 var decodeErrorOccured; 107 var player = new VideoPlayer();
107 var video;
108 var controls;
109 108
110 /** 109 /**
111 * Initializes the video player window. 110 * @constructor
112 */ 111 */
113 function loadVideoPlayer() { 112 function VideoPlayer() {
113 this.controls_ = null;
114 this.videoElement_ = null;
115 this.videos_ = null;
116
117 this.__defineGetter__('controls', function() {
mtomasz 2014/05/29 23:16:33 I think get {} is preferred over __defineGetter__.
yoshiki 2014/05/31 07:45:50 Done.
118 return this.controls_;
119 });
120
121 Object.seal(this);
122 }
123
124 /**
125 * Initializes the video player window. This method must be called after DOM
126 * initialization.
127 * @param {Array.<Object.<string, Object>>} videos List of videos.
128 */
129 VideoPlayer.prototype.prepare = function(videos) {
114 document.ondragstart = function(e) { e.preventDefault() }; 130 document.ondragstart = function(e) { e.preventDefault() };
115 131
116 chrome.fileBrowserPrivate.getStrings(function(strings) { 132 this.videos_ = videos;
117 loadTimeData.data = strings;
118 133
119 var url = window.videoUrl; 134 this.controls_ = new FullWindowVideoControls(
120 document.title = window.videoTitle; 135 document.querySelector('#video-player'),
136 document.querySelector('#video-container'),
137 document.querySelector('#controls'));
121 138
122 controls = new FullWindowVideoControls( 139 var reloadVideo = function(e) {
123 document.querySelector('#video-player'), 140 if (this.controls_.decodeErrorOccured &&
124 document.querySelector('#video-container'), 141 // Ignore shortcut keys
125 document.querySelector('#controls')); 142 !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) {
143 this.playVideo_();
144 e.preventDefault();
145 }
146 _}.wrap(this);
mtomasz 2014/05/29 23:16:33 nit: _ accidential change?
yoshiki 2014/05/31 07:45:50 Sorry, Removed.
126 147
127 var reloadVideo = function(e) { 148 document.addEventListener('keydown', reloadVideo, true);
128 if (decodeErrorOccured && 149 document.addEventListener('click', reloadVideo, true);
129 // Ignore shortcut keys 150 };
130 !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) {
131 loadVideo(url);
132 e.preventDefault();
133 }
134 };
135
136 loadVideo(url);
137 document.addEventListener('keydown', reloadVideo, true);
138 document.addEventListener('click', reloadVideo, true);
139 });
140 }
141 151
142 /** 152 /**
143 * Unloads the player. 153 * Unloads the player.
144 */ 154 */
145 function unload() { 155 function unload() {
146 if (!controls.getMedia()) 156 if (!player.controls || !player.controls.getMedia())
147 return; 157 return;
148 158
149 controls.savePosition(true /* exiting */); 159 player.controls.savePosition(true /* exiting */);
150 controls.cleanup(); 160 player.controls.cleanup();
151 } 161 }
152 162
153 /** 163 /**
154 * Reloads the player. 164 * Loads the video file.
155 * @param {string} url URL of the video file. 165 * @param {string} url URL of the video file.
166 * @param {string} title Title of the video file.
167 * @param {function(number, number)=} opt_callback Completion callback.
168 * @private
156 */ 169 */
157 function loadVideo(url) { 170 VideoPlayer.prototype.loadVideo_ = function(url, title, opt_callback) {
158 // Re-enable ui and hide error message if already displayed. 171 this.unloadVideo();
172
173 document.title = title;
174
175 // Re-enables ui and hide error message if already displayed.
159 document.querySelector('#video-player').removeAttribute('disabled'); 176 document.querySelector('#video-player').removeAttribute('disabled');
160 document.querySelector('#error').removeAttribute('visible'); 177 document.querySelector('#error').removeAttribute('visible');
161 controls.inactivityWatcher.disabled = false; 178 this.controls.inactivityWatcher.disabled = false;
162 decodeErrorOccured = false; 179 this.controls.decodeErrorOccured = false;
163 180
181 this.videoElement_ = document.createElement('video');
182 document.querySelector('#video-container').appendChild(this.videoElement_);
183 this.controls.attachMedia(this.videoElement_);
184
185 this.videoElement_.src = url;
186 this.videoElement_.load();
187 if (opt_callback)
188 this.videoElement_.addEventListener('loadedmetadata', opt_callback);
189 };
190
191 /**
192 * Plays the video.
193 * @private
194 */
195 VideoPlayer.prototype.playVideo_ = function() {
196 var currentVideo = this.videos_[0];
197 this.loadVideo_(currentVideo.fileUrl,
198 currentVideo.entry.name,
199 this.onVideoReady_.wrap(this));
200 };
201
202 /**
203 * Unloads the current video.
204 * @private
205 */
206 VideoPlayer.prototype.unloadVideo = function() {
mtomasz 2014/05/29 23:16:33 nit: unloadVideo -> unloadVideo_
yoshiki 2014/05/31 07:45:50 This method is public. Removed @private from JSDOC
164 // Detach the previous video element, if exists. 207 // Detach the previous video element, if exists.
165 if (video) 208 if (this.videoElement_)
166 video.parentNode.removeChild(video); 209 this.videoElement_.parentNode.removeChild(this.videoElement_);
210 this.videoElement_ = null;
211 };
167 212
168 video = document.createElement('video'); 213 /**
169 document.querySelector('#video-container').appendChild(video); 214 * Called when the video is ready after starting to load.
170 controls.attachMedia(video); 215 * @private
216 */
217 VideoPlayer.prototype.onVideoReady_ = function() {
218 // TODO: chrome.app.window soon will be able to resize the content area.
219 // Until then use approximate title bar height.
220 var TITLE_HEIGHT = 33;
171 221
172 video.src = url; 222 var videoWidth = this.videoElement_.videoWidth;
173 video.load(); 223 var videoHeight = this.videoElement_.videoHeight;
174 video.addEventListener('loadedmetadata', function() {
175 // TODO: chrome.app.window soon will be able to resize the content area.
176 // Until then use approximate title bar height.
177 var TITLE_HEIGHT = 33;
178 224
179 var aspect = video.videoWidth / video.videoHeight; 225 var aspect = videoWidth / videoHeight;
180 var newWidth = video.videoWidth; 226 var newWidth = videoWidth;
181 var newHeight = video.videoHeight + TITLE_HEIGHT; 227 var newHeight = videoHeight + TITLE_HEIGHT;
182 228
183 var shrinkX = newWidth / window.screen.availWidth; 229 var shrinkX = newWidth / window.screen.availWidth;
184 var shrinkY = newHeight / window.screen.availHeight; 230 var shrinkY = newHeight / window.screen.availHeight;
185 if (shrinkX > 1 || shrinkY > 1) { 231 if (shrinkX > 1 || shrinkY > 1) {
186 if (shrinkY > shrinkX) { 232 if (shrinkY > shrinkX) {
187 newHeight = newHeight / shrinkY; 233 newHeight = newHeight / shrinkY;
188 newWidth = (newHeight - TITLE_HEIGHT) * aspect; 234 newWidth = (newHeight - TITLE_HEIGHT) * aspect;
189 } else { 235 } else {
190 newWidth = newWidth / shrinkX; 236 newWidth = newWidth / shrinkX;
191 newHeight = newWidth / aspect + TITLE_HEIGHT; 237 newHeight = newWidth / aspect + TITLE_HEIGHT;
192 }
193 } 238 }
239 }
194 240
195 var oldLeft = window.screenX; 241 var oldLeft = window.screenX;
196 var oldTop = window.screenY; 242 var oldTop = window.screenY;
197 var oldWidth = window.outerWidth; 243 var oldWidth = window.outerWidth;
198 var oldHeight = window.outerHeight; 244 var oldHeight = window.outerHeight;
199 245
200 if (!oldWidth && !oldHeight) { 246 if (!oldWidth && !oldHeight) {
201 oldLeft = window.screen.availWidth / 2; 247 oldLeft = window.screen.availWidth / 2;
202 oldTop = window.screen.availHeight / 2; 248 oldTop = window.screen.availHeight / 2;
203 } 249 }
204 250
205 var appWindow = chrome.app.window.current(); 251 var appWindow = chrome.app.window.current();
206 appWindow.resizeTo(newWidth, newHeight); 252 appWindow.resizeTo(newWidth, newHeight);
207 appWindow.moveTo(oldLeft - (newWidth - oldWidth) / 2, 253 appWindow.moveTo(oldLeft - (newWidth - oldWidth) / 2,
208 oldTop - (newHeight - oldHeight) / 2); 254 oldTop - (newHeight - oldHeight) / 2);
209 appWindow.show(); 255 appWindow.show();
210 256
211 video.play(); 257 this.videoElement_.play();
258 };
259
260 /**
261 * Initialize the list of videos.
262 * @param {function(Array.<Object>)} callback Called with the video list when
263 * it is ready.
264 **/
265 function initVideos(callback) {
266 if (window.videos) {
267 var videos = window.videos;
268 window.videos = null;
269 callback(videos);
270 return;
271 }
272
273 chrome.runtime.onMessage.addListener(
274 function(request, sender, sendResponse) {
275 var videos = window.videos;
276 window.videos = null;
277 callback(videos);
278 });
279 }
280
281 /**
282 * Initializes the strings.
283 * @param {function()} callback Called when the sting data is ready.
284 **/
285 function initStrings(callback) {
286 chrome.fileBrowserPrivate.getStrings(function(strings) {
287 loadTimeData.data = strings;
288 callback();
212 }); 289 });
213 } 290 }
214 291
215 util.addPageLoadHandler(loadVideoPlayer); 292 var initPromise = Promise.all(
293 [new Promise(initVideos.wrap(null)),
294 new Promise(initStrings.wrap(null)),
295 new Promise(util.addPageLoadHandler.wrap(null))]);
296
297 initPromise.then(function(results) {
298 var videos = results[0];
299 player.prepare(videos);
300 return new Promise(player.playVideo_.wrap(player));
mtomasz 2014/05/29 23:16:33 nit: Accessing a private member. We should make it
yoshiki 2014/05/31 07:45:50 Good catch. DONE.
301 });
OLDNEW
« no previous file with comments | « ui/file_manager/video_player/js/background.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698