Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / chromeos / provided_file_systems.js
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
3 // found in the LICENSE file.
4
5 <include src="../../../../third_party/polymer_legacy/platform/platform.js">
6 <include src="../../../../third_party/polymer_legacy/polymer/polymer.js">
7
8 /**
9  * Formats size to a human readable form.
10  * @param {number} size Size in bytes.
11  * @return {string} Output string in a human-readable format.
12  */
13 function formatSizeCommon(size) {
14   if (size < 1024)
15     return size + ' B';
16   if (size < 1024 * 1024)
17     return Math.round(size / 1024) + ' KB';
18   return Math.round(size / 1024 / 1024) + ' MB';
19 }
20
21 // Defines the file-systems element.
22 Polymer('file-systems', {
23   /**
24    * Called when the element is created.
25    */
26   ready: function() {
27   },
28
29   /**
30    * Selects an active file system from the list.
31    * @param {Event} event Event.
32    * @param {number} detail Detail.
33    * @param {HTMLElement} sender Sender.
34    */
35   rowClicked: function(event, detail, sender) {
36     var requestEventsNode = document.querySelector('#request-events');
37     requestEventsNode.hidden = false;
38     requestEventsNode.model = [];
39
40     var requestTimelineNode = document.querySelector('#request-timeline');
41     requestTimelineNode.hidden = false;
42     requestTimelineNode.model = [];
43
44     chrome.send('selectFileSystem', [sender.dataset.extensionId,
45       sender.dataset.id]);
46   },
47
48   /**
49    * List of provided file system information maps.
50    * @type {Array.<Object>}
51    */
52   model: []
53 });
54
55 // Defines the request-log element.
56 Polymer('request-events', {
57   /**
58    * Called when the element is created.
59    */
60   ready: function() {
61   },
62
63   /**
64    * Formats time to a hh:mm:ss.xxxx format.
65    * @param {Date} time Input time.
66    * @return {string} Output string in a human-readable format.
67    */
68   formatTime: function(time) {
69     return ('0' + time.getHours()).slice(-2) + ':' +
70            ('0' + time.getMinutes()).slice(-2) + ':' +
71            ('0' + time.getSeconds()).slice(-2) + '.' +
72            ('000' + time.getMilliseconds()).slice(-3);
73   },
74
75   /**
76    * Formats size to a human readable form.
77    * @param {number} size Size in bytes.
78    * @return {string} Output string in a human-readable format.
79    */
80   formatSize: function(size) {
81     return formatSizeCommon(size);
82   },
83
84   /**
85    * Formats a boolean value to human-readable form.
86    * @param {boolean=} opt_hasMore Input value.
87    * @return {string} Output string in a human-readable format.
88    */
89   formatHasMore: function(opt_hasMore) {
90     if (opt_hasMore == undefined)
91       return '';
92
93     return opt_hasMore ? 'HAS_MORE' : 'LAST';
94   },
95
96   /**
97    * Formats execution time to human-readable form.
98    * @param {boolean=} opt_executionTime Input value.
99    * @return {string} Output string in a human-readable format.
100    */
101   formatExecutionTime: function(opt_executionTime) {
102     if (opt_executionTime == undefined)
103       return '';
104
105     return opt_executionTime + ' ms';
106   },
107
108   /**
109    * List of events.
110    * @type {Array.<Object>}
111    */
112   model: []
113 });
114
115 // Defines the request-timeline element.
116 Polymer('request-timeline', {
117   /**
118    * Step for zoomin in and out.
119    * @type {number}
120    * @const
121    */
122   SCALE_STEP: 1.5,
123
124   /**
125    * Height of each row in the chart in pixels.
126    * @type {number}
127    * @const
128    */
129   ROW_HEIGHT: 14,
130
131   /**
132    * Observes changes in the model.
133    * @type {Object.<string, string>}
134    */
135   observe: {
136     'model.length': 'chartUpdate'
137   },
138
139   /**
140    * Called when the element is created.
141    */
142   ready: function() {
143     // Update active requests in the background for nice animation.
144     var activeUpdateAnimation = function() {
145       this.activeUpdate();
146       requestAnimationFrame(activeUpdateAnimation);
147     }.bind(this);
148     activeUpdateAnimation();
149   },
150
151   /**
152    * Formats size to a human readable form.
153    * @param {number} size Size in bytes.
154    * @return {string} Output string in a human-readable format.
155    */
156   formatSize: function(size) {
157     return formatSizeCommon(size);
158   },
159
160   /**
161    * Zooms in the timeline.
162    * @param {Event} event Event.
163    * @param {number} detail Detail.
164    * @param {HTMLElement} sender Sender.
165    */
166   zoomInClicked: function(event, detail, sender) {
167     this.scale *= this.SCALE_STEP;
168   },
169
170   /**
171    * Zooms out the timeline.
172    * @param {Event} event Event.
173    * @param {number} detail Detail.
174    * @param {HTMLElement} sender Sender.
175    */
176   zoomOutClicked: function(event, detail, sender) {
177     this.scale /= this.SCALE_STEP;
178   },
179
180   /**
181    * Selects or deselects an element on the timeline.
182    * @param {Event} event Event.
183    * @param {number} detail Detail.
184    * @param {HTMLElement} sender Sender.
185    */
186   elementClicked: function(event, detail, sender) {
187     if (sender.dataset.id in this.selected) {
188       delete this.selected[sender.dataset.id];
189       sender.classList.remove('selected');
190     } else {
191       this.selected[sender.dataset.id] = true;
192       sender.classList.add('selected');
193     }
194
195     var requestEventsNode = document.querySelector('#request-events');
196     requestEventsNode.hidden = false;
197
198     requestEventsNode.model = [];
199     for (var i = 0; i < this.model.length; i++) {
200       if (this.model[i].id in this.selected)
201         requestEventsNode.model.push(this.model[i]);
202     }
203   },
204
205   /**
206    * Updates chart elements of active requests, so they grow with time.
207    */
208   activeUpdate: function() {
209     if (Object.keys(this.active).length == 0)
210       return;
211
212     for (var id in this.active) {
213       var index = this.active[id];
214       this.chart[index].length = Date.now() - this.chart[index].time;
215     }
216   },
217
218   /**
219    * Generates <code>chart</code> from the new <code>model</code> value.
220    */
221   chartUpdate: function(oldLength, newLength) {
222     // If the new value is empty, then clear the model.
223     if (!newLength) {
224       this.active = {};
225       this.rows = [];
226       this.chart = [];
227       this.timeStart = null;
228       this.idleStart = null;
229       this.idleTotal = 0;
230       this.selected = [];
231       return;
232     }
233
234     // Only adding new entries to the model is supported (or clearing).
235     console.assert(newLength >= oldLength);
236
237     for (var i = oldLength; i < newLength; i++) {
238       var event = this.model[i];
239       switch (event.eventType) {
240         case 'created':
241           // If this is the first creation event in the chart, then store its
242           // time as beginning time of the chart.
243           if (!this.timeStart)
244             this.timeStart = event.time;
245
246           // If this event terminates idling, then add the idling time to total
247           // idling time. This is used to avoid gaps in the chart while idling.
248           if (Object.keys(this.active).length == 0 && this.idleStart)
249             this.idleTotal += event.time.getTime() - this.idleStart.getTime();
250
251           // Find the appropriate row for this chart element.
252           var rowIndex = 0;
253           while (true) {
254             // Add to this row only if there is enough space, and if the row
255             // is of the same type.
256             var addToRow = (rowIndex >= this.rows.length) ||
257                 (this.rows[rowIndex].time.getTime() <= event.time.getTime() &&
258                  !this.rows[rowIndex].active &&
259                  (this.rows[rowIndex].requestType == event.requestType));
260
261             if (addToRow) {
262               this.chart.push({
263                 index: this.chart.length,
264                 id: event.id,
265                 time: event.time,
266                 executionTime: 0,
267                 length: 0,
268                 requestType: event.requestType,
269                 left: event.time - this.timeStart - this.idleTotal,
270                 row: rowIndex,
271                 modelIndexes: [i]
272               });
273
274               this.rows[rowIndex] = {
275                 requestType: event.requestType,
276                 time: event.time,
277                 active: true
278               };
279
280               this.active[event.id] = this.chart.length - 1;
281               break;
282             }
283
284             rowIndex++;
285           }
286           break;
287
288         case 'fulfilled':
289         case 'rejected':
290           if (!(event.id in this.active))
291             return;
292           var chartIndex = this.active[event.id];
293           this.chart[chartIndex].state = event.eventType;
294           this.chart[chartIndex].executionTime = event.executionTime;
295           this.chart[chartIndex].valueSize = event.valueSize;
296           this.chart[chartIndex].modelIndexes.push(i);
297           break;
298
299         case 'destroyed':
300           if (!(event.id in this.active))
301             return;
302
303           var chartIndex = this.active[event.id];
304           this.chart[chartIndex].length =
305               event.time - this.chart[chartIndex].time;
306           this.chart[chartIndex].modelIndexes.push(i);
307           this.rows[this.chart[chartIndex].row].time = event.time;
308           this.rows[this.chart[chartIndex].row].active = false;
309           delete this.active[event.id];
310
311           // If this was the last active request, then idling starts.
312           if (Object.keys(this.active).length == 0)
313             this.idleStart = event.time;
314           break;
315       }
316     }
317   },
318
319   /**
320    * Map of selected requests.
321    * @type {Object.<number, boolean>}
322    */
323   selected: {},
324
325   /**
326    * Map of requests which has started, but are not completed yet, from
327    * a request id to the chart element index.
328    * @type {Object.<number, number>}}
329    */
330   active: {},
331
332   /**
333    * List of chart elements, calculated from the model.
334    * @type {Array.<Object>}
335    */
336   chart: [],
337
338   /**
339    * List of rows in the chart, with the last endTime value on it.
340    * @type {Array.<Object>}
341    */
342   rows: [],
343
344   /**
345    * Scale of the chart.
346    * @type {number}
347    */
348   scale: 1,
349
350   /**
351    * Time of the first created request.
352    * @type {Date}
353    */
354   timeStart: null,
355
356   /**
357    * Time of the last idling started.
358    * @type {Date}
359    */
360   idleStart: null,
361
362   /**
363    * Total idling time since chart generation started. Used to avoid
364    * generating gaps in the chart when there is no activity. In milliseconds.
365    * @type {number}
366    */
367   idleTotal: 0,
368
369   /**
370    * List of requests information maps.
371    * @type {Array.<Object>}
372    */
373   model: []
374 });
375
376 /*
377  * Updates the mounted file system list.
378  * @param {Array.<Object>} fileSystems Array containing provided file system
379  *     information.
380  */
381 function updateFileSystems(fileSystems) {
382   var fileSystemsNode = document.querySelector('#file-systems');
383   fileSystemsNode.model = fileSystems;
384 }
385
386 /**
387  * Called when a request is created.
388  * @param {Object} event Event.
389  */
390 function onRequestEvent(event) {
391   event.time = new Date(event.time);  // Convert to a real Date object.
392   var requestTimelineNode = document.querySelector('#request-timeline');
393   requestTimelineNode.model.push(event);
394 }
395
396 document.addEventListener('DOMContentLoaded', function() {
397   var context = document.getCSSCanvasContext('2d', 'dashedPattern', 4, 4);
398   context.beginPath();
399   context.strokeStyle = '#ffffff';
400   context.moveTo(0, 0);
401   context.lineTo(4, 4);
402   context.stroke();
403
404   chrome.send('updateFileSystems');
405
406   // Refresh periodically.
407   setInterval(function() {
408     chrome.send('updateFileSystems');
409   }, 1000);
410 });