Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / resources / service_worker / serviceworker_internals.js
blobff382dd75ad43c3fc5134341763638534a5b6a77
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     update();
10   }
12   function update() {
13       chrome.send('GetOptions');
14       chrome.send('getAllRegistrations');
15   }
17   function onOptions(options) {
18     var template;
19     var container = $('serviceworker-options');
20     if (container.childNodes) {
21       template = container.childNodes[0];
22     }
23     if (!template) {
24       template = jstGetTemplate('serviceworker-options-template');
25       container.appendChild(template);
26     }
27     jstProcess(new JsEvalContext(options), template);
28     var inputs = container.querySelectorAll('input[type=\'checkbox\']');
29     for (var i = 0; i < inputs.length; ++i) {
30       if (!inputs[i].hasClickEvent) {
31         inputs[i].addEventListener('click', (function(event) {
32           chrome.send('SetOption',
33                       [event.target.className, event.target.checked]);
34         }).bind(this), false);
35         inputs[i].hasClickEvent = true;
36       }
37     }
38   }
40   function progressNodeFor(link) {
41     return link.parentNode.querySelector('.operation-status');
42   }
44   // All commands are completed with 'onOperationComplete'.
45   var COMMANDS = ['stop', 'push', 'inspect', 'unregister', 'start'];
46   function commandHandler(command) {
47     return function(event) {
48       var link = event.target;
49       progressNodeFor(link).style.display = 'inline';
50       sendCommand(command, link.cmdArgs, (function(status) {
51         progressNodeFor(link).style.display = 'none';
52       }).bind(null, link));
53       return false;
54     };
55   };
57   var commandCallbacks = [];
58   function sendCommand(command, args, callback) {
59     var callbackId = 0;
60     while (callbackId in commandCallbacks) {
61       callbackId++;
62     }
63     commandCallbacks[callbackId] = callback;
64     chrome.send(command, [callbackId, args]);
65   }
67   // Fired from the backend after the command call has completed.
68   function onOperationComplete(status, callbackId) {
69     var callback = commandCallbacks[callbackId];
70     delete commandCallbacks[callbackId];
71     if (callback) {
72       callback(status);
73     }
74     update();
75   }
77   var allLogMessages = {};
78   // Set log for a worker version.
79   function fillLogForVersion(container, partition_id, version) {
80     if (!version) {
81       return;
82     }
83     if (!(partition_id in allLogMessages)) {
84       allLogMessages[partition_id] = {};
85     }
86     var logMessages = allLogMessages[partition_id];
87     if (version.version_id in logMessages) {
88       version.log = logMessages[version.version_id];
89     } else {
90       version.log = '';
91     }
92     var logAreas = container.querySelectorAll('textarea.serviceworker-log');
93     for (var i = 0; i < logAreas.length; ++i) {
94       var logArea = logAreas[i];
95       if (logArea.partition_id == partition_id &&
96           logArea.version_id == version.version_id) {
97         logArea.value = version.log;
98       }
99     }
100   }
102   // Get the unregistered workers.
103   // |unregistered_registrations| will be filled with the registrations which
104   // are in |live_registrations| but not in |stored_registrations|.
105   // |unregistered_versions| will be filled with the versions which
106   // are in |live_versions| but not in |stored_registrations| nor in
107   // |live_registrations|.
108   function getUnregisteredWorkers(stored_registrations,
109                                   live_registrations,
110                                   live_versions,
111                                   unregistered_registrations,
112                                   unregistered_versions) {
113     var registration_id_set = {};
114     var version_id_set = {};
115     stored_registrations.forEach(function(registration) {
116       registration_id_set[registration.registration_id] = true;
117     });
118     [stored_registrations, live_registrations].forEach(function(registrations) {
119       registrations.forEach(function(registration) {
120         [registration.active, registration.waiting].forEach(function(version) {
121           if (version) {
122             version_id_set[version.version_id] = true;
123           }
124         });
125       });
126     });
127     live_registrations.forEach(function(registration) {
128       if (!registration_id_set[registration.registration_id]) {
129         registration.unregistered = true;
130         unregistered_registrations.push(registration);
131       }
132     });
133     live_versions.forEach(function(version) {
134       if (!version_id_set[version.version_id]) {
135         unregistered_versions.push(version);
136       }
137     });
138   }
140   // Fired once per partition from the backend.
141   function onPartitionData(live_registrations,
142                            live_versions,
143                            stored_registrations,
144                            partition_id,
145                            partition_path) {
146     var unregistered_registrations = [];
147     var unregistered_versions = [];
148     getUnregisteredWorkers(stored_registrations,
149                            live_registrations,
150                            live_versions,
151                            unregistered_registrations,
152                            unregistered_versions);
153     var template;
154     var container = $('serviceworker-list');
155     // Existing templates are keyed by partition_id. This allows
156     // the UI to be updated in-place rather than refreshing the
157     // whole page.
158     for (var i = 0; i < container.childNodes.length; ++i) {
159       if (container.childNodes[i].partition_id == partition_id) {
160         template = container.childNodes[i];
161       }
162     }
163     // This is probably the first time we're loading.
164     if (!template) {
165       template = jstGetTemplate('serviceworker-list-template');
166       container.appendChild(template);
167     }
168     var fillLogFunc = fillLogForVersion.bind(this, container, partition_id);
169     stored_registrations.forEach(function(registration) {
170       [registration.active, registration.waiting].forEach(fillLogFunc);
171     });
172     unregistered_registrations.forEach(function(registration) {
173       [registration.active, registration.waiting].forEach(fillLogFunc);
174     });
175     unregistered_versions.forEach(fillLogFunc);
176     jstProcess(new JsEvalContext({
177                  stored_registrations: stored_registrations,
178                  unregistered_registrations: unregistered_registrations,
179                  unregistered_versions: unregistered_versions,
180                  partition_id: partition_id,
181                  partition_path: partition_path}),
182                template);
183     for (var i = 0; i < COMMANDS.length; ++i) {
184       var handler = commandHandler(COMMANDS[i]);
185       var links = container.querySelectorAll('button.' + COMMANDS[i]);
186       for (var j = 0; j < links.length; ++j) {
187         if (!links[j].hasClickEvent) {
188           links[j].addEventListener('click', handler, false);
189           links[j].hasClickEvent = true;
190         }
191       }
192     }
193   }
195   function onRunningStateChanged(partition_id, version_id) {
196     update();
197   }
199   function onErrorReported(partition_id,
200                            version_id,
201                            process_id,
202                            thread_id,
203                            error_info) {
204     outputLogMessage(partition_id,
205                      version_id,
206                      'Error: ' + JSON.stringify(error_info) + '\n');
207   }
209   function onConsoleMessageReported(partition_id,
210                                     version_id,
211                                     process_id,
212                                     thread_id,
213                                     message) {
214     outputLogMessage(partition_id,
215                      version_id,
216                      'Console: ' + JSON.stringify(message) + '\n');
217   }
219   function onVersionStateChanged(partition_id, version_id) {
220     update();
221   }
223   function onRegistrationStored(scope) {
224     update();
225   }
227   function onRegistrationDeleted(scope) {
228     update();
229   }
231   function outputLogMessage(partition_id, version_id, message) {
232     if (!(partition_id in allLogMessages)) {
233       allLogMessages[partition_id] = {};
234     }
235     var logMessages = allLogMessages[partition_id];
236     if (version_id in logMessages) {
237       logMessages[version_id] += message;
238     } else {
239       logMessages[version_id] = message;
240     }
242     var logAreas = document.querySelectorAll('textarea.serviceworker-log');
243     for (var i = 0; i < logAreas.length; ++i) {
244       var logArea = logAreas[i];
245       if (logArea.partition_id == partition_id &&
246           logArea.version_id == version_id) {
247         logArea.value += message;
248       }
249     }
250   }
252   return {
253     initialize: initialize,
254     onOptions: onOptions,
255     onOperationComplete: onOperationComplete,
256     onPartitionData: onPartitionData,
257     onRunningStateChanged: onRunningStateChanged,
258     onErrorReported: onErrorReported,
259     onConsoleMessageReported: onConsoleMessageReported,
260     onVersionStateChanged: onVersionStateChanged,
261     onRegistrationStored: onRegistrationStored,
262     onRegistrationDeleted: onRegistrationDeleted,
263   };
266 document.addEventListener('DOMContentLoaded', serviceworker.initialize);