Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / front_end / components_lazy / FilmStripView.js
blob95dbfa1ae711b72ede9e1f718002f7b8bf630c3e
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6 * @constructor
7 * @extends {WebInspector.HBox}
8 */
9 WebInspector.FilmStripView = function()
11 WebInspector.HBox.call(this, true);
12 this.registerRequiredCSS("components_lazy/filmStripView.css");
13 this.contentElement.classList.add("film-strip-view");
14 this._statusLabel = this.contentElement.createChild("div", "label");
15 this.reset();
16 this.setMode(WebInspector.FilmStripView.Modes.TimeBased);
19 WebInspector.FilmStripView.Events = {
20 FrameSelected: "FrameSelected",
21 FrameEnter: "FrameEnter",
22 FrameExit: "FrameExit",
25 WebInspector.FilmStripView.Modes = {
26 TimeBased: "TimeBased",
27 FrameBased: "FrameBased"
30 WebInspector.FilmStripView.prototype = {
31 /**
32 * @param {string} mode
34 setMode: function(mode)
36 this._mode = mode;
37 this.contentElement.classList.toggle("time-based", mode === WebInspector.FilmStripView.Modes.TimeBased);
38 this.update();
41 /**
42 * @param {!WebInspector.FilmStripModel} filmStripModel
43 * @param {number} zeroTime
44 * @param {number} spanTime
46 setModel: function(filmStripModel, zeroTime, spanTime)
48 this._model = filmStripModel;
49 this._zeroTime = zeroTime;
50 this._spanTime = spanTime;
51 var frames = filmStripModel.frames();
52 if (!frames.length) {
53 this.reset();
54 return;
56 this.update();
59 /**
60 * @param {!WebInspector.FilmStripModel.Frame} frame
61 * @return {!Promise<!Element>}
63 createFrameElement: function(frame)
65 var time = frame.timestamp;
66 var element = createElementWithClass("div", "frame");
67 element.title = WebInspector.UIString("Doubleclick to zoom image. Click to view preceding requests.");
68 element.createChild("div", "time").textContent = Number.millisToString(time - this._zeroTime);
69 var imageElement = element.createChild("div", "thumbnail").createChild("img");
70 element.addEventListener("mousedown", this._onMouseEvent.bind(this, WebInspector.FilmStripView.Events.FrameSelected, time), false);
71 element.addEventListener("mouseenter", this._onMouseEvent.bind(this, WebInspector.FilmStripView.Events.FrameEnter, time), false);
72 element.addEventListener("mouseout", this._onMouseEvent.bind(this, WebInspector.FilmStripView.Events.FrameExit, time), false);
73 element.addEventListener("dblclick", this._onDoubleClick.bind(this, frame), false);
75 return frame.imageDataPromise().then(WebInspector.FilmStripView._setImageData.bind(null, imageElement)).then(returnElement);
76 /**
77 * @return {!Element}
79 function returnElement()
81 return element;
85 /**
86 * @param {number} time
87 * @return {!WebInspector.FilmStripModel.Frame}
89 frameByTime: function(time)
91 /**
92 * @param {number} time
93 * @param {!WebInspector.FilmStripModel.Frame} frame
94 * @return {number}
96 function comparator(time, frame)
98 return time - frame.timestamp;
100 // Using the first frame to fill the interval between recording start
101 // and a moment the frame is taken.
102 var frames = this._model.frames();
103 var index = Math.max(frames.upperBound(time, comparator) - 1, 0);
104 return frames[index];
107 update: function()
109 if (!this._model)
110 return;
111 var frames = this._model.frames();
112 if (!frames.length)
113 return;
115 if (this._mode === WebInspector.FilmStripView.Modes.FrameBased) {
116 Promise.all(frames.map(this.createFrameElement.bind(this))).then(appendElements.bind(this));
117 return;
120 var width = this.contentElement.clientWidth;
121 var scale = this._spanTime / width;
122 this.createFrameElement(frames[0]).then(continueWhenFrameImageLoaded.bind(this)); // Calculate frame width basing on the first frame.
125 * @this {WebInspector.FilmStripView}
126 * @param {!Element} element0
128 function continueWhenFrameImageLoaded(element0)
130 var frameWidth = Math.ceil(WebInspector.measurePreferredSize(element0, this.contentElement).width);
131 if (!frameWidth)
132 return;
134 var promises = [];
135 for (var pos = frameWidth; pos < width; pos += frameWidth) {
136 var time = pos * scale + this._zeroTime;
137 promises.push(this.createFrameElement(this.frameByTime(time)).then(fixWidth));
139 Promise.all(promises).then(appendElements.bind(this));
141 * @param {!Element} element
142 * @return {!Element}
144 function fixWidth(element)
146 element.style.width = frameWidth + "px";
147 return element;
152 * @param {!Array.<!Element>} elements
153 * @this {WebInspector.FilmStripView}
155 function appendElements(elements)
157 this.contentElement.removeChildren();
158 for (var i = 0; i < elements.length; ++i)
159 this.contentElement.appendChild(elements[i]);
164 * @override
166 onResize: function()
168 if (this._mode === WebInspector.FilmStripView.Modes.FrameBased)
169 return;
170 this.update();
174 * @param {string} eventName
175 * @param {number} timestamp
177 _onMouseEvent: function(eventName, timestamp)
179 this.dispatchEventToListeners(eventName, timestamp);
183 * @param {!WebInspector.FilmStripModel.Frame} filmStripFrame
185 _onDoubleClick: function(filmStripFrame)
187 new WebInspector.FilmStripView.DialogDelegate(filmStripFrame, this._zeroTime);
190 reset: function()
192 this._zeroTime = 0;
193 this.contentElement.removeChildren();
194 this.contentElement.appendChild(this._statusLabel);
198 * @param {string} text
200 setStatusText: function(text)
202 this._statusLabel.textContent = text;
205 __proto__: WebInspector.HBox.prototype
209 * @param {!Element} imageElement
210 * @param {?string} data
212 WebInspector.FilmStripView._setImageData = function(imageElement, data)
214 if (data)
215 imageElement.src = "data:image/jpg;base64," + data;
219 * @constructor
220 * @extends {WebInspector.DialogDelegate}
221 * @param {!WebInspector.FilmStripModel.Frame} filmStripFrame
222 * @param {number=} zeroTime
224 WebInspector.FilmStripView.DialogDelegate = function(filmStripFrame, zeroTime)
226 WebInspector.DialogDelegate.call(this);
227 var shadowRoot = WebInspector.createShadowRootWithCoreStyles(this.element);
228 shadowRoot.appendChild(WebInspector.Widget.createStyleElement("components_lazy/filmStripDialog.css"));
229 this._contentElement = shadowRoot.createChild("div", "filmstrip-dialog");
230 this._contentElement.tabIndex = 0;
232 this._frames = filmStripFrame.model().frames();
233 this._index = filmStripFrame.index;
234 this._zeroTime = zeroTime || filmStripFrame.model().zeroTime();
236 this._imageElement = this._contentElement.createChild("img");
237 var footerElement = this._contentElement.createChild("div", "filmstrip-dialog-footer");
238 footerElement.createChild("div", "flex-auto");
239 var prevButton = createTextButton("\u25C0", this._onPrevFrame.bind(this), undefined, WebInspector.UIString("Previous frame"));
240 footerElement.appendChild(prevButton);
241 this._timeLabel = footerElement.createChild("div", "filmstrip-dialog-label");
242 var nextButton = createTextButton("\u25B6", this._onNextFrame.bind(this), undefined, WebInspector.UIString("Next frame"));
243 footerElement.appendChild(nextButton);
244 footerElement.createChild("div", "flex-auto");
246 this._contentElement.addEventListener("keydown", this._keyDown.bind(this), false);
247 this._render().then(WebInspector.Dialog.show.bind(null, null, this));
250 WebInspector.FilmStripView.DialogDelegate.prototype = {
252 * @override
254 focus: function()
256 this._contentElement.focus();
260 * @param {!Event} event
262 _keyDown: function(event)
264 switch (event.keyIdentifier) {
265 case "Left":
266 if (WebInspector.isMac() && event.metaKey)
267 this._onFirstFrame();
268 else
269 this._onPrevFrame();
270 break;
272 case "Right":
273 if (WebInspector.isMac() && event.metaKey)
274 this._onLastFrame();
275 else
276 this._onNextFrame();
277 break;
279 case "Home":
280 this._onFirstFrame();
281 break;
283 case "End":
284 this._onLastFrame();
285 break;
289 _onPrevFrame: function()
291 if (this._index > 0)
292 --this._index;
293 this._render();
296 _onNextFrame: function()
298 if (this._index < this._frames.length - 1)
299 ++this._index;
300 this._render();
303 _onFirstFrame: function()
305 this._index = 0;
306 this._render();
309 _onLastFrame: function()
311 this._index = this._frames.length - 1;
312 this._render();
316 * @return {!Promise<undefined>}
318 _render: function()
320 var frame = this._frames[this._index];
321 this._timeLabel.textContent = Number.millisToString(frame.timestamp - this._zeroTime);
322 return frame.imageDataPromise().then(WebInspector.FilmStripView._setImageData.bind(null, this._imageElement));
325 __proto__: WebInspector.DialogDelegate.prototype