Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / resources / service_worker / serviceworker_internals.js
blob3eda10f5acff08e628bd63fd1697401d86e8a608
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.
5 cr.define('serviceworker', function() {
6   'use strict';
8   function initialize() {
9     if (window.location.hash == "#iframe") {
10       // This page is loaded from chrome://inspect.
11       window.addEventListener('message', onMessage.bind(this), false);
12     }
13     update();
14   }
16   function onMessage(event) {
17     if (event.origin != 'chrome://inspect') {
18       return;
19     }
20     sendCommand(event.data.action, event.data.worker);
21   }
23   function update() {
24       chrome.send('GetOptions');
25       chrome.send('getAllRegistrations');
26   }
28   function onOptions(options) {
29     var template;
30     var container = $('serviceworker-options');
31     if (container.childNodes) {
32       template = container.childNodes[0];
33     }
34     if (!template) {
35       template = jstGetTemplate('serviceworker-options-template');
36       container.appendChild(template);
37     }
38     jstProcess(new JsEvalContext(options), template);
39     var inputs = container.querySelectorAll('input[type=\'checkbox\']');
40     for (var i = 0; i < inputs.length; ++i) {
41       if (!inputs[i].hasClickEvent) {
42         inputs[i].addEventListener('click', (function(event) {
43           chrome.send('SetOption',
44                       [event.target.className, event.target.checked]);
45         }).bind(this), false);
46         inputs[i].hasClickEvent = true;
47       }
48     }
49   }
51   function progressNodeFor(link) {
52     return link.parentNode.querySelector('.operation-status');
53   }
55   // All commands are completed with 'onOperationComplete'.
56   var COMMANDS = ['stop', 'sync', 'push', 'inspect', 'unregister', 'start'];
57   function commandHandler(command) {
58     return function(event) {
59       var link = event.target;
60       progressNodeFor(link).style.display = 'inline';
61       sendCommand(command, link.cmdArgs, (function(status) {
62         progressNodeFor(link).style.display = 'none';
63       }).bind(null, link));
64       return false;
65     };
66   };
68   var commandCallbacks = [];
69   function sendCommand(command, args, callback) {
70     var callbackId = 0;
71     while (callbackId in commandCallbacks) {
72       callbackId++;
73     }
74     commandCallbacks[callbackId] = callback;
75     chrome.send(command, [callbackId, args]);
76   }
78   // Fired from the backend after the command call has completed.
79   function onOperationComplete(status, callbackId) {
80     var callback = commandCallbacks[callbackId];
81     delete commandCallbacks[callbackId];
82     if (callback) {
83       callback(status);
84     }
85     update();
86   }
88   // Send the active ServiceWorker information to chrome://inspect.
89   function sendToInspectPage(live_registrations,
90                  partition_id) {
91     var workers = [];
92     live_registrations.forEach(function(registration) {
93       [registration.active, registration.waiting].forEach(function(version) {
94         if (!version || version.running_status != 'RUNNING') {
95           return;
96         }
97         workers.push({
98           'scope': registration.scope,
99           'url': version.script_url,
100           'partition_id': partition_id,
101           'version_id': version.version_id,
102           'process_id': version.process_id,
103           'devtools_agent_route_id':
104             version.devtools_agent_route_id
105         });
106       });
107     });
108     window.parent.postMessage(
109         {'partition_id': partition_id, 'workers': workers},
110         'chrome://inspect');
111   }
113   var allLogMessages = {};
114   // Set log for a worker version.
115   function fillLogForVersion(partition_id, version) {
116     if (!version) {
117       return;
118     }
119     if (!(partition_id in allLogMessages)) {
120       allLogMessages[partition_id] = {};
121     }
122     var logMessages = allLogMessages[partition_id];
123     if (version.version_id in logMessages) {
124       version.log = logMessages[version.version_id];
125     } else {
126       version.log = '';
127     }
128   }
130   // Get the unregistered workers.
131   // |unregistered_registrations| will be filled with the registrations which
132   // are in |live_registrations| but not in |stored_registrations|.
133   // |unregistered_versions| will be filled with the versions which
134   // are in |live_versions| but not in |stored_registrations| nor in
135   // |live_registrations|.
136   function getUnregisteredWorkers(stored_registrations,
137                                   live_registrations,
138                                   live_versions,
139                                   unregistered_registrations,
140                                   unregistered_versions) {
141     var registration_id_set = {};
142     var version_id_set = {};
143     stored_registrations.forEach(function(registration) {
144       registration_id_set[registration.registration_id] = true;
145     });
146     [stored_registrations, live_registrations].forEach(function(registrations) {
147       registrations.forEach(function(registration) {
148         [registration.active, registration.waiting].forEach(function(version) {
149           if (version) {
150             version_id_set[version.version_id] = true;
151           }
152         });
153       });
154     });
155     live_registrations.forEach(function(registration) {
156       if (!registration_id_set[registration.registration_id]) {
157         registration.unregistered = true;
158         unregistered_registrations.push(registration);
159       }
160     });
161     live_versions.forEach(function(version) {
162       if (!version_id_set[version.version_id]) {
163         unregistered_versions.push(version);
164       }
165     });
166   }
168   // Fired once per partition from the backend.
169   function onPartitionData(live_registrations,
170                            live_versions,
171                            stored_registrations,
172                            partition_id,
173                            partition_path) {
174     if (window.location.hash == "#iframe") {
175       // This page is loaded from chrome://inspect.
176       sendToInspectPage(live_registrations, partition_id);
177       return;
178     }
179     var unregistered_registrations = [];
180     var unregistered_versions = [];
181     getUnregisteredWorkers(stored_registrations,
182                            live_registrations,
183                            live_versions,
184                            unregistered_registrations,
185                            unregistered_versions);
186     var template;
187     var container = $('serviceworker-list');
188     // Existing templates are keyed by partition_id. This allows
189     // the UI to be updated in-place rather than refreshing the
190     // whole page.
191     for (var i = 0; i < container.childNodes.length; ++i) {
192       if (container.childNodes[i].partition_id == partition_id) {
193         template = container.childNodes[i];
194       }
195     }
196     // This is probably the first time we're loading.
197     if (!template) {
198       template = jstGetTemplate('serviceworker-list-template');
199       container.appendChild(template);
200     }
201     var fillLogFunc = fillLogForVersion.bind(this, partition_id);
202     stored_registrations.forEach(function(registration) {
203       [registration.active, registration.waiting].forEach(fillLogFunc);
204     });
205     unregistered_registrations.forEach(function(registration) {
206       [registration.active, registration.waiting].forEach(fillLogFunc);
207     });
208     unregistered_versions.forEach(fillLogFunc);
209     jstProcess(new JsEvalContext({
210                  stored_registrations: stored_registrations,
211                  unregistered_registrations: unregistered_registrations,
212                  unregistered_versions: unregistered_versions,
213                  partition_id: partition_id,
214                  partition_path: partition_path}),
215                template);
216     for (var i = 0; i < COMMANDS.length; ++i) {
217       var handler = commandHandler(COMMANDS[i]);
218       var links = container.querySelectorAll('button.' + COMMANDS[i]);
219       for (var j = 0; j < links.length; ++j) {
220         if (!links[j].hasClickEvent) {
221           links[j].addEventListener('click', handler, false);
222           links[j].hasClickEvent = true;
223         }
224       }
225     }
226   }
228   function onWorkerStarted(partition_id, version_id, process_id, thread_id) {
229     update();
230   }
232   function onWorkerStopped(partition_id, version_id, process_id, thread_id) {
233     update();
234   }
236   function onErrorReported(partition_id,
237                            version_id,
238                            process_id,
239                            thread_id,
240                            error_info) {
241     outputLogMessage(partition_id,
242                      version_id,
243                      'Error: ' + JSON.stringify(error_info) + '\n');
244   }
246   function onConsoleMessageReported(partition_id,
247                                     version_id,
248                                     process_id,
249                                     thread_id,
250                                     message) {
251     outputLogMessage(partition_id,
252                      version_id,
253                      'Console: ' + JSON.stringify(message) + '\n');
254   }
256   function onVersionStateChanged(partition_id, version_id) {
257     update();
258   }
260   function onRegistrationStored(scope) {
261     update();
262   }
264   function onRegistrationDeleted(scope) {
265     update();
266   }
268   function outputLogMessage(partition_id, version_id, message) {
269     if (!(partition_id in allLogMessages)) {
270       allLogMessages[partition_id] = {};
271     }
272     var logMessages = allLogMessages[partition_id];
273     if (version_id in logMessages) {
274       logMessages[version_id] += message;
275     } else {
276       logMessages[version_id] = message;
277     }
279     var logAreas = document.querySelectorAll('textarea.serviceworker-log');
280     for (var i = 0; i < logAreas.length; ++i) {
281       var logArea = logAreas[i];
282       if (logArea.partition_id == partition_id &&
283         logArea.version_id == version_id) {
284         logArea.value += message;
285       }
286     }
287   }
289   return {
290     initialize: initialize,
291     onOptions: onOptions,
292     onOperationComplete: onOperationComplete,
293     onPartitionData: onPartitionData,
294     onWorkerStarted: onWorkerStarted,
295     onWorkerStopped: onWorkerStopped,
296     onErrorReported: onErrorReported,
297     onConsoleMessageReported: onConsoleMessageReported,
298     onVersionStateChanged: onVersionStateChanged,
299     onRegistrationStored: onRegistrationStored,
300     onRegistrationDeleted: onRegistrationDeleted,
301   };
304 document.addEventListener('DOMContentLoaded', serviceworker.initialize);