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

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: 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.
mtomasz 2014/05/29 13:44:12 nit: Can we make it private?
yoshiki 2014/05/29 14:45:19 Done.
64 */
65 FullWindowVideoControls.prototype.showErrorMessage = function(message) {
66 var errorBanner = document.querySelector('#error');
67 errorBanner.textContent =
68 loadTimeData.getString(message);
69 errorBanner.setAttribute('visible', 'true');
70
71 // The window is hidden if the video has not loaded yet.
72 chrome.app.window.current().show();
73 }
mtomasz 2014/05/29 13:44:12 nit: ; missing.
yoshiki 2014/05/29 14:45:19 Done.
74
75 /**
76 * Handles playback (decoder) errors.
mtomasz 2014/05/29 13:44:12 nit: @private missing.
yoshiki 2014/05/29 14:45:19 Done.
77 */
78 FullWindowVideoControls.prototype.onPlaybackError_ = function() {
79 this.showErrorMessage('GALLERY_VIDEO_DECODING_ERROR');
80 this.decodeErrorOccured = true;
81
82 // Disable inactivity watcher, and disable the ui, by hiding tools manually.
83 this.inactivityWatcher.disabled = true;
84 document.querySelector('#video-player').setAttribute('disabled', 'true');
85
86 // Detach the video element, since it may be unreliable and reset stored
87 // current playback time.
88 this.cleanup();
89 this.clearState();
90
91 // Avoid reusing a video element.
92 player.unloadVideo();
93 };
94
95 /**
97 * Toggles the full screen mode. 96 * Toggles the full screen mode.
98 * @private 97 * @private
99 */ 98 */
100 FullWindowVideoControls.prototype.toggleFullScreen_ = function() { 99 FullWindowVideoControls.prototype.toggleFullScreen_ = function() {
101 var appWindow = chrome.app.window.current(); 100 var appWindow = chrome.app.window.current();
102 util.toggleFullScreen(appWindow, !util.isFullScreen(appWindow)); 101 util.toggleFullScreen(appWindow, !util.isFullScreen(appWindow));
103 }; 102 };
104 103
105 // TODO(mtomasz): Convert it to class members: crbug.com/171191. 104 // TODO(mtomasz): Convert it to class members: crbug.com/171191.
106 var decodeErrorOccured; 105 var player = new VideoPlayer();
107 var video;
108 var controls;
109 106
110 /** 107 /**
111 * Initializes the video player window. 108 * @constructor
112 */ 109 */
113 function loadVideoPlayer() { 110 function VideoPlayer() {
111 this.controls = null;
mtomasz 2014/05/29 13:44:12 nit: Can we make them private?
yoshiki 2014/05/29 14:45:19 Done.
112 this.videoElement = null;
113 this.videos = null;
114
115 Object.seal(this);
116 }
117
118 /**
119 * Initializes the video player window. This method must be called after DOM
120 * initialization.
121 * @param {Array.<Object.<string, Object>>} videos List of video to play.
mtomasz 2014/05/29 13:44:12 nit: ... -> List of videos.
yoshiki 2014/05/29 14:45:19 Done.
122 */
123 VideoPlayer.prototype.prepare = function(videos) {
114 document.ondragstart = function(e) { e.preventDefault() }; 124 document.ondragstart = function(e) { e.preventDefault() };
115 125
116 chrome.fileBrowserPrivate.getStrings(function(strings) { 126 this.videos = videos;
117 loadTimeData.data = strings;
118 127
119 var url = window.videoUrl; 128 this.controls = new FullWindowVideoControls(
120 document.title = window.videoTitle; 129 document.querySelector('#video-player'),
130 document.querySelector('#video-container'),
131 document.querySelector('#controls'));
121 132
122 controls = new FullWindowVideoControls( 133 var reloadVideo = function(e) {
123 document.querySelector('#video-player'), 134 if (this.controls.decodeErrorOccured &&
124 document.querySelector('#video-container'), 135 // Ignore shortcut keys
125 document.querySelector('#controls')); 136 !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) {
137 this.playVideo_();
138 e.preventDefault();
139 }
140 }.wrap(this);
126 141
127 var reloadVideo = function(e) { 142 document.addEventListener('keydown', reloadVideo, true);
128 if (decodeErrorOccured && 143 document.addEventListener('click', reloadVideo, true);
129 // Ignore shortcut keys 144 };
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 145
142 /** 146 /**
143 * Unloads the player. 147 * Unloads the player.
144 */ 148 */
145 function unload() { 149 function unload() {
146 if (!controls.getMedia()) 150 if (!player.controls || !player.controls.getMedia())
147 return; 151 return;
148 152
149 controls.savePosition(true /* exiting */); 153 player.controls.savePosition(true /* exiting */);
150 controls.cleanup(); 154 player.controls.cleanup();
151 } 155 }
152 156
153 /** 157 /**
154 * Reloads the player. 158 * Loads the video file.
155 * @param {string} url URL of the video file. 159 * @param {string} url URL of the video file.
160 * @param {string} title Title of the video file.
161 * @param {function(number, number)=} callback Callback
mtomasz 2014/05/29 13:44:12 nit: callback -> opt_callback
mtomasz 2014/05/29 13:44:12 nit: Callback -> Completion callback.
yoshiki 2014/05/29 14:45:19 Done.
yoshiki 2014/05/29 14:45:19 Done.
162 * @private
156 */ 163 */
157 function loadVideo(url) { 164 VideoPlayer.prototype.loadVideo_ = function(url, title, opt_callback) {
165 this.unloadVideo();
166
167 document.title = title;
168
158 // Re-enable ui and hide error message if already displayed. 169 // Re-enable ui and hide error message if already displayed.
159 document.querySelector('#video-player').removeAttribute('disabled'); 170 document.querySelector('#video-player').removeAttribute('disabled');
160 document.querySelector('#error').removeAttribute('visible'); 171 document.querySelector('#error').removeAttribute('visible');
161 controls.inactivityWatcher.disabled = false; 172 this.controls.inactivityWatcher.disabled = false;
162 decodeErrorOccured = false; 173 this.controls.decodeErrorOccured = false;
163 174
175 this.videoElement = document.createElement('video');
176 document.querySelector('#video-container').appendChild(this.videoElement);
177 this.controls.attachMedia(this.videoElement);
178
179 this.videoElement.src = url;
180 this.videoElement.load();
181 if (opt_callback)
182 this.videoElement.addEventListener('loadedmetadata', opt_callback);
183 };
184
185 /**
186 * Plays the video.
187 * @private
188 */
189 VideoPlayer.prototype.playVideo_ = function() {
190 var currentVideo = this.videos[0];
191 this.loadVideo_(currentVideo.fileUrl,
192 currentVideo.entry.name,
193 this.onVideoReady_.wrap(this));
194 };
195
196 /**
197 * Unlaods the current video.
mtomasz 2014/05/29 13:44:12 typo: Unloads.
yoshiki 2014/05/29 14:45:19 Done.
198 * @private
199 */
200 VideoPlayer.prototype.unloadVideo = function() {
164 // Detach the previous video element, if exists. 201 // Detach the previous video element, if exists.
165 if (video) 202 if (this.videoElement)
166 video.parentNode.removeChild(video); 203 this.videoElement.parentNode.removeChild(this.videoElement);
204 this.videoElement = null;
205 };
167 206
168 video = document.createElement('video'); 207 /**
169 document.querySelector('#video-container').appendChild(video); 208 * Called when the video is ready after starting to load.
170 controls.attachMedia(video); 209 * @private
210 */
211 VideoPlayer.prototype.onVideoReady_ = function() {
212 // TODO: chrome.app.window soon will be able to resize the content area.
mtomasz 2014/05/29 13:44:12 FYI: From M36, we can finally do that. https://de
yoshiki 2014/05/29 14:45:19 Thanks for guidance. I'll change it in a separated
213 // Until then use approximate title bar height.
214 var TITLE_HEIGHT = 33;
171 215
172 video.src = url; 216 var videoWidth = this.videoElement.videoWidth;
173 video.load(); 217 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 218
179 var aspect = video.videoWidth / video.videoHeight; 219 var aspect = videoWidth / videoHeight;
180 var newWidth = video.videoWidth; 220 var newWidth = videoWidth;
181 var newHeight = video.videoHeight + TITLE_HEIGHT; 221 var newHeight = videoHeight + TITLE_HEIGHT;
182 222
183 var shrinkX = newWidth / window.screen.availWidth; 223 var shrinkX = newWidth / window.screen.availWidth;
184 var shrinkY = newHeight / window.screen.availHeight; 224 var shrinkY = newHeight / window.screen.availHeight;
185 if (shrinkX > 1 || shrinkY > 1) { 225 if (shrinkX > 1 || shrinkY > 1) {
186 if (shrinkY > shrinkX) { 226 if (shrinkY > shrinkX) {
187 newHeight = newHeight / shrinkY; 227 newHeight = newHeight / shrinkY;
188 newWidth = (newHeight - TITLE_HEIGHT) * aspect; 228 newWidth = (newHeight - TITLE_HEIGHT) * aspect;
189 } else { 229 } else {
190 newWidth = newWidth / shrinkX; 230 newWidth = newWidth / shrinkX;
191 newHeight = newWidth / aspect + TITLE_HEIGHT; 231 newHeight = newWidth / aspect + TITLE_HEIGHT;
192 }
193 } 232 }
233 }
194 234
195 var oldLeft = window.screenX; 235 var oldLeft = window.screenX;
196 var oldTop = window.screenY; 236 var oldTop = window.screenY;
197 var oldWidth = window.outerWidth; 237 var oldWidth = window.outerWidth;
198 var oldHeight = window.outerHeight; 238 var oldHeight = window.outerHeight;
199 239
200 if (!oldWidth && !oldHeight) { 240 if (!oldWidth && !oldHeight) {
201 oldLeft = window.screen.availWidth / 2; 241 oldLeft = window.screen.availWidth / 2;
202 oldTop = window.screen.availHeight / 2; 242 oldTop = window.screen.availHeight / 2;
203 } 243 }
204 244
205 var appWindow = chrome.app.window.current(); 245 var appWindow = chrome.app.window.current();
206 appWindow.resizeTo(newWidth, newHeight); 246 appWindow.resizeTo(newWidth, newHeight);
207 appWindow.moveTo(oldLeft - (newWidth - oldWidth) / 2, 247 appWindow.moveTo(oldLeft - (newWidth - oldWidth) / 2,
208 oldTop - (newHeight - oldHeight) / 2); 248 oldTop - (newHeight - oldHeight) / 2);
209 appWindow.show(); 249 appWindow.show();
210 250
211 video.play(); 251 this.videoElement.play();
252 };
253
254 /**
255 * Initialize the list of videos.
256 * @param {function(Array.<Object>)} callback Called with the video list when
257 * it is ready.
258 **/
259 function initVideos(callback) {
260 if (window.videos) {
261 var videos = window.videos;
262 window.videos = null;
263 callback(videos);
264 return;
265 }
266
267 chrome.runtime.onMessage.addListener(
268 function(request, sender, sendResponse) {
269 var videos = window.videos;
270 window.videos = null;
271 callback(videos);
272 });
273 }
274
275 /**
276 * Initializes the strings.
277 * @param {function()} callback Called when the sting data is ready.
278 **/
279 function initStrings(callback) {
280 chrome.fileBrowserPrivate.getStrings(function(strings) {
281 loadTimeData.data = strings;
282 callback();
212 }); 283 });
213 } 284 }
214 285
215 util.addPageLoadHandler(loadVideoPlayer); 286 var initPhase1 = Promise.all([new Promise(initVideos.wrap(null)),
mtomasz 2014/05/29 13:44:12 nit: initPhase1 and initPhase2 naming is not helpf
yoshiki 2014/05/29 14:45:19 Done #2. Thanks.
287 new Promise(initStrings.wrap(null)),
288 new Promise(util.addPageLoadHandler.wrap(null))]);
289
290 var initPhase2 = initPhase1.then(function(results) {
291 var videos = results;
292 player.prepare(videos);
293 return new Promise(player.playVideo_.wrap(player));
294 });
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