1 // Copyright (c) 2011 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.
6 // require cr/event_target.js
8 // require cr/ui/tabs.js
9 // require cr/ui/tree.js
16 * @param {Object} object Object to be checked.
17 * @return {boolean} true if |object| is {}.
20 function isEmptyObject_(object
) {
27 * Copy properties from |source| to |destination|.
28 * @param {Object} source Source of the copy.
29 * @param {Object} destination Destination of the copy.
30 * @return {Object} |destination|.
33 function copyAttributes_(source
, destination
) {
35 destination
[i
] = source
[i
];
40 * Apply localization to |element| with i18n_template.js if available.
41 * @param {Element} element Element to be localized.
44 function localize_(element
) {
45 if (window
.i18nTemplate
&& window
.loadTimeData
)
46 i18nTemplate
.process(element
, loadTimeData
);
50 * Returns 'N/A' (Not Available) text if |value| is undefined.
51 * @param {Object} value Object to print.
52 * @return {string} 'N/A' or ''.
55 function checkIfAvailable_(value
) {
56 return value
=== undefined ? 'N/A' : '';
60 * Returns |value| itself if |value| is not undefined,
61 * else returns 'N/A' text.
62 * @param {?string} value String to print.
63 * @return {string} 'N/A' or |value|.
66 function stringToText_(value
) {
67 return checkIfAvailable_(value
) || value
;
71 * Separates |value| into segments.
72 * The length of first segment is at most |maxLength|.
73 * Length of other following segments are just |maxLength|.
74 * e.g. separateBackward_('abcdefghijk', 4) == ['abc','defg','hijk'];
75 * @param {string} value String to be separated.
76 * @param {number} maxLength Max length of segments.
77 * @return {Array<string>} Array of segments.
80 function separateBackward_(value
, maxLength
) {
82 while (value
.length
> maxLength
) {
83 result
.unshift(value
.slice(-3));
84 value
= value
.slice(0, -3);
86 result
.unshift(value
);
91 * Returns formatted string from number as number of bytes.
92 * e.g. numBytesToText(123456789) = '123.45 MB (123,456,789 B)'.
93 * If |value| is undefined, this function returns 'N/A'.
94 * @param {?number} value Number to print.
95 * @return {string} 'N/A' or formatted |value|.
98 function numBytesToText_(value
) {
99 var result
= checkIfAvailable_(value
);
103 var segments
= separateBackward_(value
.toString(), 3);
104 result
= segments
.join(',') + ' B';
106 if (segments
.length
> 1) {
107 var UNIT
= [' B', ' KB', ' MB', ' GB', ' TB', ' PB'];
108 result
= segments
[0] + '.' + segments
[1].slice(0, 2) +
109 UNIT
[Math
.min(segments
.length
, UNIT
.length
) - 1] +
117 * Return formatted date |value| if |value| is not undefined.
118 * If |value| is undefined, this function returns 'N/A'.
119 * @param {?number} value Number of milliseconds since
120 * UNIX epoch time (0:00, Jan 1, 1970, UTC).
121 * @return {string} Formatted text of date or 'N/A'.
124 function dateToText(value
) {
125 var result
= checkIfAvailable_(value
);
129 var time
= new Date(value
);
130 var now
= new Date();
131 var delta
= Date
.now() - value
;
134 var MINUTE
= 60 * SECOND
;
135 var HOUR
= 60 * MINUTE
;
139 var SHOW_SECOND
= 5 * MINUTE
;
140 var SHOW_MINUTE
= 5 * HOUR
;
141 var SHOW_HOUR
= 3 * DAY
;
142 var SHOW_DAY
= 2 * WEEK
;
143 var SHOW_WEEK
= 3 * 30 * DAY
;
146 result
= 'access from future ';
147 } else if (delta
< SHOW_SECOND
) {
148 result
= Math
.ceil(delta
/ SECOND
) + ' sec ago ';
149 } else if (delta
< SHOW_MINUTE
) {
150 result
= Math
.ceil(delta
/ MINUTE
) + ' min ago ';
151 } else if (delta
< SHOW_HOUR
) {
152 result
= Math
.ceil(delta
/ HOUR
) + ' hr ago ';
153 } else if (delta
< SHOW_WEEK
) {
154 result
= Math
.ceil(delta
/ DAY
) + ' day ago ';
157 result
+= '(' + time
.toString() + ')';
162 * Available disk space.
163 * @type {number|undefined}
165 var availableSpace
= undefined;
168 * Root of the quota data tree,
169 * holding userdata as |treeViewObject.detail|.
172 var treeViewObject
= undefined;
175 * Key-value styled statistics data.
176 * This WebUI does not touch contents, just show.
177 * The value is hold as |statistics[key].detail|.
178 * @type {Object<string,Element>}
183 * Initialize and return |treeViewObject|.
184 * @return {cr.ui.Tree} Initialized |treeViewObject|.
186 function getTreeViewObject() {
187 if (!treeViewObject
) {
188 treeViewObject
= $('tree-view');
189 cr
.ui
.decorate(treeViewObject
, cr
.ui
.Tree
);
190 treeViewObject
.detail
= {payload
: {}, children
: {}};
191 treeViewObject
.addEventListener('change', updateDescription
);
193 return treeViewObject
;
197 * Initialize and return a tree item, that represents specified storage type.
198 * @param {!string} type Storage type.
199 * @return {cr.ui.TreeItem} Initialized |storageObject|.
201 function getStorageObject(type
) {
202 var treeViewObject
= getTreeViewObject();
203 var storageObject
= treeViewObject
.detail
.children
[type
];
204 if (!storageObject
) {
205 storageObject
= new cr
.ui
.TreeItem({
207 detail
: {payload
: {}, children
: {}}
209 storageObject
.mayHaveChildren_
= true;
210 treeViewObject
.detail
.children
[type
] = storageObject
;
211 treeViewObject
.add(storageObject
);
213 return storageObject
;
217 * Initialize and return a tree item, that represents specified
218 * storage type and hostname.
219 * @param {!string} type Storage type.
220 * @param {!string} host Hostname.
221 * @return {cr.ui.TreeItem} Initialized |hostObject|.
223 function getHostObject(type
, host
) {
224 var storageObject
= getStorageObject(type
);
225 var hostObject
= storageObject
.detail
.children
[host
];
227 hostObject
= new cr
.ui
.TreeItem({
229 detail
: {payload
: {}, children
: {}}
231 hostObject
.mayHaveChildren_
= true;
232 storageObject
.detail
.children
[host
] = hostObject
;
233 storageObject
.add(hostObject
);
239 * Initialize and return a tree item, that represents specified
240 * storage type, hostname and origin url.
241 * @param {!string} type Storage type.
242 * @param {!string} host Hostname.
243 * @param {!string} origin Origin URL.
244 * @return {cr.ui.TreeItem} Initialized |originObject|.
246 function getOriginObject(type
, host
, origin
) {
247 var hostObject
= getHostObject(type
, host
);
248 var originObject
= hostObject
.detail
.children
[origin
];
250 originObject
= new cr
.ui
.TreeItem({
252 detail
: {payload
: {}, children
: {}}
254 originObject
.mayHaveChildren_
= false;
255 hostObject
.detail
.children
[origin
] = originObject
;
256 hostObject
.add(originObject
);
262 * Event Handler for |cr.quota.onAvailableSpaceUpdated|.
263 * |event.detail| contains |availableSpace|.
264 * |availableSpace| represents total available disk space.
265 * @param {CustomEvent} event AvailableSpaceUpdated event.
267 function handleAvailableSpace(event
) {
271 availableSpace
= event
.detail
;
272 $('diskspace-entry').innerHTML
= numBytesToText_(availableSpace
);
276 * Event Handler for |cr.quota.onGlobalInfoUpdated|.
277 * |event.detail| contains a record which has:
279 * Storage type, that is either 'temporary' or 'persistent'.
281 * Total storage usage of all hosts.
283 * Total storage usage of unlimited-quota origins.
285 * Total quota of the storage.
287 * |usage|, |unlimitedUsage| and |quota| can be missing,
288 * and some additional fields can be included.
289 * @param {CustomEvent} event GlobalInfoUpdated event.
291 function handleGlobalInfo(event
) {
296 * unlimitedUsage: {?number}
300 var data
= event
.detail
;
301 var storageObject
= getStorageObject(data
.type
);
302 copyAttributes_(data
, storageObject
.detail
.payload
);
303 storageObject
.reveal();
304 if (getTreeViewObject().selectedItem
== storageObject
)
310 * Event Handler for |cr.quota.onPerHostInfoUpdated|.
311 * |event.detail| contains records which have:
313 * Hostname of the entry. (e.g. 'example.com')
315 * Storage type. 'temporary' or 'persistent'
317 * Total storage usage of the host.
321 * |usage| and |quota| can be missing,
322 * and some additional fields can be included.
323 * @param {CustomEvent} event PerHostInfoUpdated event.
325 function handlePerHostInfo(event
) {
334 var dataArray
= event
.detail
;
336 for (var i
= 0; i
< dataArray
.length
; ++i
) {
337 var data
= dataArray
[i
];
338 var hostObject
= getHostObject(data
.type
, data
.host
);
339 copyAttributes_(data
, hostObject
.detail
.payload
);
341 if (getTreeViewObject().selectedItem
== hostObject
)
348 * Event Handler for |cr.quota.onPerOriginInfoUpdated|.
349 * |event.detail| contains records which have:
351 * Origin URL of the entry.
353 * Storage type of the entry. 'temporary' or 'persistent'.
355 * Hostname of the entry.
357 * true if the origin is in use.
359 * Used count of the storage from the origin.
361 * Last storage access time from the origin.
362 * Number of milliseconds since UNIX epoch (Jan 1, 1970, 0:00:00 UTC).
363 * |lastModifiedTime|:
364 * Last modified time of the storage from the origin.
365 * Number of milliseconds since UNIX epoch.
367 * |inUse|, |usedCount|, |lastAccessTime| and |lastModifiedTime| can be missing,
368 * and some additional fields can be included.
369 * @param {CustomEvent} event PerOriginInfoUpdated event.
371 function handlePerOriginInfo(event
) {
378 * usedCount: {?number},
379 * lastAccessTime: {?number}
380 * lastModifiedTime: {?number}
383 var dataArray
= event
.detail
;
385 for (var i
= 0; i
< dataArray
.length
; ++i
) {
386 var data
= dataArray
[i
];
387 var originObject
= getOriginObject(data
.type
, data
.host
, data
.origin
);
388 copyAttributes_(data
, originObject
.detail
.payload
);
389 originObject
.reveal();
390 if (getTreeViewObject().selectedItem
== originObject
)
396 * Event Handler for |cr.quota.onStatisticsUpdated|.
397 * |event.detail| contains misc statistics data as dictionary.
398 * @param {CustomEvent} event StatisticsUpdated event.
400 function handleStatistics(event
) {
402 * @type {Object<string>}
404 var data
= event
.detail
;
405 for (var key
in data
) {
406 var entry
= statistics
[key
];
408 entry
= cr
.doc
.createElement('tr');
409 $('stat-entries').appendChild(entry
);
410 statistics
[key
] = entry
;
412 entry
.detail
= data
[key
];
414 '<td>' + stringToText_(key
) + '</td>' +
415 '<td>' + stringToText_(entry
.detail
) + '</td>';
421 * Update description on 'tree-item-description' field with
422 * selected item in tree view.
424 function updateDescription() {
425 var item
= getTreeViewObject().selectedItem
;
426 var tbody
= $('tree-item-description');
427 tbody
.innerHTML
= '';
430 var keyAndLabel
= [['type', 'Storage Type'],
431 ['host', 'Host Name'],
432 ['origin', 'Origin URL'],
433 ['usage', 'Total Storage Usage', numBytesToText_
],
434 ['unlimitedUsage', 'Usage of Unlimited Origins',
436 ['quota', 'Quota', numBytesToText_
],
437 ['inUse', 'Origin is in use?'],
438 ['usedCount', 'Used count'],
439 ['lastAccessTime', 'Last Access Time',
441 ['lastModifiedTime', 'Last Modified Time',
444 for (var i
= 0; i
< keyAndLabel
.length
; ++i
) {
445 var key
= keyAndLabel
[i
][0];
446 var label
= keyAndLabel
[i
][1];
447 var entry
= item
.detail
.payload
[key
];
448 if (entry
=== undefined)
451 var normalize
= keyAndLabel
[i
][2] || stringToText_
;
453 var row
= cr
.doc
.createElement('tr');
455 '<td>' + label
+ '</td>' +
456 '<td>' + normalize(entry
) + '</td>';
458 tbody
.appendChild(row
);
464 * Dump |treeViewObject| or subtree to a object.
465 * @param {?{cr.ui.Tree|cr.ui.TreeItem}} opt_treeitem
466 * @return {Object} Dump result object from |treeViewObject|.
468 function dumpTreeToObj(opt_treeitem
) {
469 var treeitem
= opt_treeitem
|| getTreeViewObject();
471 res
.payload
= treeitem
.detail
.payload
;
473 for (var i
in treeitem
.detail
.children
) {
474 var child
= treeitem
.detail
.children
[i
];
475 res
.children
.push(dumpTreeToObj(child
));
478 if (isEmptyObject_(res
.payload
))
481 if (res
.children
.length
== 0)
487 * Dump |statistics| to a object.
488 * @return {Object} Dump result object from |statistics|.
490 function dumpStatisticsToObj() {
492 for (var key
in statistics
)
493 result
[key
] = statistics
[key
].detail
;
498 * Event handler for 'dump-button' 'click'ed.
499 * Dump and show all data from WebUI page to 'dump-field' element.
502 var separator
= '========\n';
504 $('dump-field').textContent
=
508 JSON
.stringify({availableSpace
: availableSpace
}, null, 2) + '\n' +
510 'Usage And Quota\n' +
512 JSON
.stringify(dumpTreeToObj(), null, 2) + '\n' +
514 'Misc Statistics\n' +
516 JSON
.stringify(dumpStatisticsToObj(), null, 2);
520 cr
.ui
.decorate('tabbox', cr
.ui
.TabBox
);
522 cr
.quota
.onAvailableSpaceUpdated
.addEventListener('update',
523 handleAvailableSpace
);
524 cr
.quota
.onGlobalInfoUpdated
.addEventListener('update', handleGlobalInfo
);
525 cr
.quota
.onPerHostInfoUpdated
.addEventListener('update', handlePerHostInfo
);
526 cr
.quota
.onPerOriginInfoUpdated
.addEventListener('update',
527 handlePerOriginInfo
);
528 cr
.quota
.onStatisticsUpdated
.addEventListener('update', handleStatistics
);
529 cr
.quota
.requestInfo();
531 $('refresh-button').addEventListener('click', cr
.quota
.requestInfo
, false);
532 $('dump-button').addEventListener('click', dump
, false);
535 cr
.doc
.addEventListener('DOMContentLoaded', onLoad
, false);