OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 cr.define('policy', function() { |
6 * This variable structure is here to document the structure that the template | 6 /** |
7 * expects to correctly populate the page. | 7 * A box that shows the status of cloud policy for a device or user. |
8 */ | 8 * @constructor |
9 var policyDataFormat = { | 9 * @extends {HTMLFieldSetElement} |
10 // Whether any of the policies in 'policies' have a value. | 10 */ |
11 'anyPoliciesSet': true, | 11 var StatusBox = cr.ui.define(function() { |
12 | 12 var node = $('status-box-template').cloneNode(true); |
13 'policies': [ | 13 node.removeAttribute('id'); |
14 { | 14 return node; |
15 'level': 'managed', | 15 }); |
16 'name': 'AllowXYZ', | 16 |
17 'set': true, | 17 StatusBox.prototype = { |
18 'scope': 'Machine', | 18 // Set up the prototype chain. |
19 'status': 'ok', | 19 __proto__: HTMLFieldSetElement.prototype, |
20 'value': true | 20 |
21 } | 21 /** |
22 ], | 22 * Initialization function for the cr.ui framework. |
23 'status': { | 23 */ |
24 'deviceFetchInterval': '8min', | 24 decorate: function() { |
25 'deviceId': 'D2AC39A2-3C8FC-E2C0-E45D2DC3782C', | 25 }, |
26 'deviceLastFetchTime': '9:50 PM', | 26 |
27 'devicePolicyDomain': 'google.com', | 27 /** |
28 'deviceStatusMessage': 'OK', | 28 * Populate the box with the given cloud policy status. |
29 'displayDeviceStatus': true, | 29 * @param {string} scope The policy scope, either "device" or "user". |
30 'displayStatusSection': true, | 30 * @param {Object} status Dictionary with information about the status. |
31 'displayUserStatus': true, | 31 */ |
32 'user': 'simo@google.com', | 32 initialize: function(scope, status) { |
33 'userFetchInterval': '8min', | 33 if (scope == 'device') { |
34 'userId': 'D2AC39A2-3C8FC-E2C0-E45D2DC3782C', | 34 // For device policy, set the appropriate title and populate the topmost |
35 'userLastFetchTime': '9:50 PM', | 35 // status item with the domain the device is enrolled into. |
36 'userStatusMessage': 'OK' | 36 this.querySelector('.legend').textContent = |
| 37 loadTimeData.getString('statusDevice'); |
| 38 var domain = this.querySelector('.domain'); |
| 39 domain.textContent = status.domain; |
| 40 domain.parentElement.hidden = false; |
| 41 } else { |
| 42 // For user policy, set the appropriate title and populate the topmost |
| 43 // status item with the username that policies apply to. |
| 44 this.querySelector('.legend').textContent = |
| 45 loadTimeData.getString('statusUser'); |
| 46 // Populate the topmost item with the username. |
| 47 var username = this.querySelector('.username'); |
| 48 username.textContent = status.username; |
| 49 username.parentElement.hidden = false; |
| 50 } |
| 51 // Populate all remaining items. |
| 52 this.querySelector('.client-id').textContent = status.clientId || ''; |
| 53 this.querySelector('.time-since-last-refresh').textContent = |
| 54 status.timeSinceLastRefresh || ''; |
| 55 this.querySelector('.refresh-interval').textContent = |
| 56 status.refreshInterval || ''; |
| 57 this.querySelector('.status').textContent = status.status || ''; |
| 58 }, |
| 59 }; |
| 60 |
| 61 /** |
| 62 * A single policy's entry in the policy table. |
| 63 * @constructor |
| 64 * @extends {HTMLTableSectionElement} |
| 65 */ |
| 66 var Policy = cr.ui.define(function() { |
| 67 var node = $('policy-template').cloneNode(true); |
| 68 node.removeAttribute('id'); |
| 69 return node; |
| 70 }); |
| 71 |
| 72 Policy.prototype = { |
| 73 // Set up the prototype chain. |
| 74 __proto__: HTMLTableSectionElement.prototype, |
| 75 |
| 76 /** |
| 77 * Initialization function for the cr.ui framework. |
| 78 */ |
| 79 decorate: function() { |
| 80 this.updateToggleExpandedValueText_(); |
| 81 this.querySelector('.toggle-expanded-value').addEventListener( |
| 82 'click', this.toggleExpandedValue_.bind(this)); |
| 83 }, |
| 84 |
| 85 /** |
| 86 * Populate the table columns with information about the policy name, value |
| 87 * and status. |
| 88 * @param {string} name The policy name. |
| 89 * @param {Object} value Dictionary with information about the policy value. |
| 90 * @param {boolean} unknown Whether the policy name is not recognized. |
| 91 */ |
| 92 initialize: function(name, value, unknown) { |
| 93 this.name = name; |
| 94 this.unset = !value; |
| 95 |
| 96 // Populate the name column. |
| 97 this.querySelector('.name').textContent = name; |
| 98 |
| 99 // Populate the remaining columns with policy scope, level and value if a |
| 100 // value has been set. Otherwise, leave them blank. |
| 101 if (value) { |
| 102 this.querySelector('.scope').textContent = |
| 103 loadTimeData.getString(value.device ? 'scopeDevice' : 'scopeUser'); |
| 104 this.querySelector('.level').textContent = |
| 105 loadTimeData.getString(value.recommended ? 'levelRecommended' : |
| 106 'levelMandatory'); |
| 107 this.querySelector('.value').textContent = value.value; |
| 108 this.querySelector('.expanded-value').textContent = value.value; |
| 109 } |
| 110 |
| 111 // Populate the status column. |
| 112 var status; |
| 113 if (!value) { |
| 114 // If the policy value has not been set, show an error message. |
| 115 status = loadTimeData.getString('unset'); |
| 116 } else if (unknown) { |
| 117 // If the policy name is not recognized, show an error message. |
| 118 status = loadTimeData.getString('unknown'); |
| 119 } else if (value.error) { |
| 120 // If an error occurred while parsing the policy value, show the error |
| 121 // message. |
| 122 status = value.error; |
| 123 } else { |
| 124 // Otherwise, indicate that the policy value was parsed correctly. |
| 125 status = loadTimeData.getString('ok'); |
| 126 } |
| 127 this.querySelector('.status').textContent = status; |
| 128 }, |
| 129 |
| 130 /** |
| 131 * Check the table columns for overflow. Most columns are automatically |
| 132 * elided when overflow occurs. The only action required is to add a tooltip |
| 133 * that shows the complete content. The value column is an exception. If |
| 134 * overflow occurs here, the contents is replaced with a link that toggles |
| 135 * the visibility of an additional row containing the complete value. |
| 136 */ |
| 137 checkOverflow: function() { |
| 138 // Set a tooltip on all overflowed columns except the value column. |
| 139 var divs = this.querySelectorAll('div.elide'); |
| 140 for (var i = 0; i < divs.length; ++i) { |
| 141 var div = divs[i]; |
| 142 div.title = div.offsetWidth < div.scrollWidth ? div.textContent : ''; |
| 143 } |
| 144 |
| 145 // Cache the width of the value column's contents when it is first shown. |
| 146 // This is required to be able to check whether the contents would still |
| 147 // overflow the column once it has been hidden and replaced by a link. |
| 148 var valueContainer = this.querySelector('.value-container'); |
| 149 if (valueContainer.valueWidth == undefined) { |
| 150 valueContainer.valueWidth = |
| 151 valueContainer.querySelector('.value').offsetWidth; |
| 152 } |
| 153 |
| 154 // Determine whether the contents of the value column overflows. The |
| 155 // visibility of the contents, replacement link and additional row |
| 156 // containing the complete value that depend on this are handled by CSS. |
| 157 this.classList.toggle( |
| 158 'has-overflowed-value', |
| 159 valueContainer.offsetWidth < valueContainer.valueWidth); |
| 160 }, |
| 161 |
| 162 /** |
| 163 * Update the text of the link that toggles the visibility of an additional |
| 164 * row containing the complete policy value, depending on the toggle state. |
| 165 * @private |
| 166 */ |
| 167 updateToggleExpandedValueText_: function(event) { |
| 168 this.querySelector('.toggle-expanded-value').textContent = |
| 169 loadTimeData.getString( |
| 170 this.classList.contains('show-overflowed-value') ? |
| 171 'hideExpandedValue' : 'showExpandedValue'); |
| 172 }, |
| 173 |
| 174 /** |
| 175 * Toggle the visibility of an additional row containing the complete policy |
| 176 * value. |
| 177 * @private |
| 178 */ |
| 179 toggleExpandedValue_: function() { |
| 180 this.classList.toggle('show-overflowed-value'); |
| 181 this.updateToggleExpandedValueText_(); |
| 182 }, |
| 183 }; |
| 184 |
| 185 /** |
| 186 * A table of policies and their values. |
| 187 * @constructor |
| 188 * @extends {HTMLTableSectionElement} |
| 189 */ |
| 190 var PolicyTable = cr.ui.define('tbody'); |
| 191 |
| 192 PolicyTable.prototype = { |
| 193 // Set up the prototype chain. |
| 194 __proto__: HTMLTableSectionElement.prototype, |
| 195 |
| 196 /** |
| 197 * Initialization function for the cr.ui framework. |
| 198 */ |
| 199 decorate: function() { |
| 200 this.policies_ = {}; |
| 201 this.filterPattern_ = ''; |
| 202 window.addEventListener('resize', this.checkOverflow_.bind(this)); |
| 203 }, |
| 204 |
| 205 /** |
| 206 * Initialize the list of all known policies. |
| 207 * @param {Object} definitions Dictionary containing all known policies. |
| 208 */ |
| 209 setDefinitions: function(definitions) { |
| 210 this.policies_ = definitions; |
| 211 this.setPolicyValues({}); |
| 212 }, |
| 213 |
| 214 /** |
| 215 * Populate the table with the currently set policy values and any errors |
| 216 * detected while parsing these. |
| 217 * @param {Object} values Dictionary containing the current policy values. |
| 218 */ |
| 219 setPolicyValues: function(values) { |
| 220 // Remove all policies from the table. |
| 221 var policies = this.getElementsByTagName('tbody'); |
| 222 while (policies.length > 0) |
| 223 this.removeChild(policies.item(0)); |
| 224 |
| 225 // First, add known policies whose value is currently set. |
| 226 var unset = []; |
| 227 for (var name in this.policies_) { |
| 228 if (name in values) |
| 229 this.setPolicyValue_(name, values[name], false); |
| 230 else |
| 231 unset.push(name); |
| 232 } |
| 233 |
| 234 // Second, add policies whose value is currently set but whose name is not |
| 235 // recognized. |
| 236 for (var name in values) { |
| 237 if (!(name in this.policies_)) |
| 238 this.setPolicyValue_(name, values[name], true); |
| 239 } |
| 240 |
| 241 // Finally, add known policies whose value is not currently set. |
| 242 for (var i = 0; i < unset.length; ++i) |
| 243 this.setPolicyValue_(unset[i], undefined, false); |
| 244 |
| 245 // Filter the policies. |
| 246 this.filter(); |
| 247 }, |
| 248 |
| 249 /** |
| 250 * Set the filter pattern. Only policies whose name contains |pattern| are |
| 251 * shown in the policy table. The filter is case insensitive. It can be |
| 252 * disabled by setting |pattern| to an empty string. |
| 253 * @param {string} pattern The filter pattern. |
| 254 */ |
| 255 setFilterPattern: function(pattern) { |
| 256 this.filterPattern_ = pattern.toLowerCase(); |
| 257 this.filter(); |
| 258 }, |
| 259 |
| 260 /** |
| 261 * Filter policies. Only policies whose name contains the filter pattern are |
| 262 * shown in the table. Furthermore, policies whose value is not currently |
| 263 * set are only shown if the corresponding checkbox is checked. |
| 264 */ |
| 265 filter: function() { |
| 266 var showUnset = $('show-unset').checked; |
| 267 var policies = this.getElementsByTagName('tbody'); |
| 268 for (var i = 0; i < policies.length; ++i) { |
| 269 var policy = policies[i]; |
| 270 policy.hidden = |
| 271 policy.unset && !showUnset || |
| 272 policy.name.toLowerCase().indexOf(this.filterPattern_) == -1; |
| 273 } |
| 274 this.parentElement.classList.toggle( |
| 275 'empty', !this.querySelector('tbody:not([hidden])')); |
| 276 setTimeout(this.checkOverflow_.bind(this), 0); |
| 277 }, |
| 278 |
| 279 /** |
| 280 * Check the table columns for overflow. |
| 281 * @private |
| 282 */ |
| 283 checkOverflow_: function() { |
| 284 var policies = this.getElementsByTagName('tbody'); |
| 285 for (var i = 0; i < policies.length; ++i) { |
| 286 if (!policies[i].hidden) |
| 287 policies[i].checkOverflow(); |
| 288 } |
| 289 }, |
| 290 |
| 291 /** |
| 292 * Add a policy with the given |name| and |value| to the table. |
| 293 * @param {string} name The policy name. |
| 294 * @param {Object} value Dictionary with information about the policy value. |
| 295 * @param {boolean} unknown Whether the policy name is not recoginzed. |
| 296 * @private |
| 297 */ |
| 298 setPolicyValue_: function(name, value, unknown) { |
| 299 var policy = new Policy; |
| 300 policy.initialize(name, value, unknown); |
| 301 this.appendChild(policy); |
| 302 }, |
| 303 }; |
| 304 |
| 305 /** |
| 306 * A singelton object that handles communication between browser and WebUI. |
| 307 * @constructor |
| 308 */ |
| 309 function Page() { |
37 } | 310 } |
38 }; | 311 |
39 | 312 // Make Page a singleton. |
40 cr.define('policies', function() { | 313 cr.addSingletonGetter(Page); |
41 | 314 |
42 function Policy() { | 315 /** |
43 } | 316 * Provide a list of all known policies to the UI. Called by the browser on |
44 | 317 * page load. |
45 cr.addSingletonGetter(Policy); | 318 * @param {Object} definitions Dictionary containing all known policies. |
46 | 319 */ |
47 Policy.prototype = { | 320 Page.setDefinitions = function(definitions) { |
48 /** | 321 this.getInstance().policyTable.setDefinitions(definitions); |
49 * True if none of the received policies are actually set, false otherwise. | 322 }; |
50 * @type {boolean} | 323 |
51 */ | 324 /** |
52 noActivePolicies_: false, | 325 * Provide a list of the currently set policy values and any errors detected |
53 | 326 * while parsing these to the UI. Called by the browser on page load and |
54 /** | 327 * whenever policy values change. |
55 * The current search term for filtering of the policy table. | 328 * @param {Object} values Dictionary containing the current policy values. |
56 * @type {string} | 329 */ |
57 * @private | 330 Page.setPolicyValues = function(values) { |
58 */ | 331 this.getInstance().policyTable.setPolicyValues(values); |
59 searchTerm_: '', | 332 }; |
60 | 333 |
61 /** | 334 /** |
62 * Takes the |policyData| argument and populates the page with this data. It | 335 * Provide the current cloud policy status to the UI. Called by the browser on |
63 * expects an object structure like the policyDataFormat above. | 336 * page load if cloud policy is present and whenever the status changes. |
64 * @param {Object} policyData Detailed info about policies. | 337 * @param {Object} status Dictionary containing the current policy status. |
65 */ | 338 */ |
66 renderTemplate: function(policyData) { | 339 Page.setStatus = function(status) { |
67 this.noActivePolicies_ = !policyData.anyPoliciesSet; | 340 this.getInstance().setStatus(status); |
68 | 341 }; |
69 if (this.noActivePolicies_) | 342 |
70 $('no-policies').hidden = false; | 343 /** |
71 if (policyData.status.displayStatusSection) | 344 * Notify the UI that a request to reload policy values has completed. Called |
72 $('status-section').hidden = false; | 345 * by the browser after a request to reload policy has been sent by the UI. |
73 | 346 */ |
74 // This is the javascript code that processes the template: | 347 Page.reloadPoliciesDone = function() { |
75 var input = new JsEvalContext(policyData); | 348 this.getInstance().reloadPoliciesDone(); |
76 var output = $('data-template'); | 349 }; |
77 jstProcess(input, output); | 350 |
78 | 351 Page.prototype = { |
79 var toggles = document.querySelectorAll('.policy-set * .toggler'); | 352 /** |
80 for (var i = 0; i < toggles.length; i++) { | 353 * Main initialization function. Called by the browser on page load. |
81 toggles[i].hidden = true; | 354 */ |
82 toggles[i].onclick = function() { | 355 initialize: function() { |
83 Policy.getInstance().toggleCellExpand_(this); | 356 uber.onContentFrameLoaded(); |
84 }; | 357 this.policyTable = $('policy-table'); |
85 } | 358 cr.ui.decorate(this.policyTable, PolicyTable); |
86 | 359 |
87 var containers = document.querySelectorAll('.text-container'); | 360 // Place the initial focus on the filter input field. |
88 for (var i = 0; i < containers.length; i++) | 361 $('filter').focus(); |
89 this.initTextContainer_(containers[i]); | 362 |
90 }, | 363 var self = this; |
91 | 364 $('filter').onsearch = function(event) { |
92 /** | 365 self.policyTable.setFilterPattern(this.value); |
93 * Filters the table of policies by name. | 366 }; |
94 * @param {string} term The search string. | 367 $('reload-policies').onclick = function(event) { |
95 */ | 368 this.disabled = true; |
96 filterTable: function(term) { | 369 chrome.send('reloadPolicies'); |
97 this.searchTerm_ = term.toLowerCase(); | 370 }; |
98 var table = $('policy-table'); | 371 $('show-unset').onchange = this.policyTable.filter.bind(this.policyTable); |
99 var showUnsent = $('toggle-unsent-policies').checked; | 372 |
100 for (var r = 1; r < table.rows.length; r++) { | 373 // Notify the browser that the page has loaded, causing it to send the |
101 var row = table.rows[r]; | 374 // list of all known policies, the current policy values and the cloud |
102 | 375 // policy status. |
103 // Don't change visibility of policies that aren't set if the checkbox | 376 chrome.send('initialized'); |
104 // isn't checked. | 377 }, |
105 if (!showUnsent && row.className == 'policy-unset') | 378 |
106 continue; | 379 /** |
107 | 380 * Update the status section of the page to show the current cloud policy |
108 var nameCell = row.querySelector('.policy-name'); | 381 * status. |
109 var cellContents = nameCell.textContent; | 382 * @param {Object} status Dictionary containing the current policy status. |
110 row.hidden = | 383 */ |
111 !(cellContents.toLowerCase().indexOf(this.searchTerm_) >= 0); | 384 setStatus: function(status) { |
112 } | 385 // Remove any existing status boxes. |
113 }, | 386 var container = $('status-box-container'); |
114 | 387 while (container.firstChild) |
115 /** | 388 container.removeChild(container.firstChild); |
116 * Updates the visibility of the policies depending on the state of the | 389 // Hide the status section. |
117 * 'toggle-unsent-policies' checkbox. | 390 var section = $('status'); |
118 */ | 391 section.hidden = true; |
119 updatePolicyVisibility: function() { | 392 |
120 if ($('toggle-unsent-policies').checked) | 393 // Add a status box for each scope that has a cloud policy status. |
121 $('policies').style.display = ''; | 394 for (var scope in status) { |
122 else if (this.noActivePolicies_) | 395 var box = new StatusBox; |
123 $('policies').style.display = 'none'; | 396 box.initialize(scope, status[scope]); |
124 | 397 container.appendChild(box); |
125 var tableRows = document.getElementsByClassName('policy-unset'); | 398 // Show the status section. |
126 for (var i = 0; i < tableRows.length; i++) | 399 section.hidden = false; |
127 tableRows[i].hidden = !($('toggle-unsent-policies').checked); | 400 } |
128 | 401 }, |
129 // Filter table again in case a search was active. | 402 |
130 this.filterTable(this.searchTerm_); | 403 /** |
131 }, | 404 * Re-enable the reload policies button when the previous request to reload |
132 | 405 * policies values has completed. |
133 /** | 406 */ |
134 * Expands or collapses a table cell that has overflowing text. | 407 reloadPoliciesDone: function() { |
135 * @param {Object} toggler The toggler that was clicked on. | 408 $('reload-policies').disabled = false; |
136 * @private | 409 }, |
137 */ | 410 }; |
138 toggleCellExpand_: function(toggler) { | 411 |
139 var textContainer = toggler.parentElement; | |
140 textContainer.collapsed = !textContainer.collapsed; | |
141 | |
142 if (textContainer.collapsed) | |
143 this.collapseCell_(textContainer); | |
144 else | |
145 this.expandCell_(textContainer); | |
146 }, | |
147 | |
148 /** | |
149 * Collapses all expanded table cells and updates the visibility of the | |
150 * toggles accordingly. Should be called before the policy information in | |
151 * the table is updated. | |
152 */ | |
153 collapseExpandedCells: function() { | |
154 var textContainers = document.querySelectorAll('.text-expanded'); | |
155 for (var i = 0; i < textContainers.length; i++) | |
156 this.collapseCell_(textContainers[i]); | |
157 }, | |
158 | |
159 /** | |
160 * Expands a table cell so that all the text it contains is visible. | |
161 * @param {Object} textContainer The cell's div element that contains the | |
162 * text. | |
163 * @private | |
164 */ | |
165 expandCell_: function(textContainer) { | |
166 textContainer.classList.remove('text-collapsed'); | |
167 textContainer.classList.add('text-expanded'); | |
168 textContainer.querySelector('.expand').hidden = true; | |
169 textContainer.querySelector('.collapse').hidden = false; | |
170 }, | |
171 | |
172 /** | |
173 * Collapses a table cell so that overflowing text is hidden. | |
174 * @param {Object} textContainer The cell's div element that contains the | |
175 * text. | |
176 * @private | |
177 */ | |
178 collapseCell_: function(textContainer) { | |
179 textContainer.classList.remove('text-expanded'); | |
180 textContainer.classList.add('text-collapsed'); | |
181 textContainer.querySelector('.expand').hidden = false; | |
182 textContainer.querySelector('.collapse').hidden = true; | |
183 }, | |
184 | |
185 /** | |
186 * Initializes a text container, showing the expand toggle if necessary. | |
187 * @param {Object} textContainer The text container element. | |
188 */ | |
189 initTextContainer_: function(textContainer) { | |
190 textContainer.collapsed = true; | |
191 var textValue = textContainer.querySelector('.text-value'); | |
192 | |
193 // If the text is wider than the text container, the expand toggler should | |
194 // appear. | |
195 if (textContainer.offsetWidth < textValue.offsetWidth || | |
196 textContainer.offsetHeight < textValue.offsetHeight) { | |
197 this.collapseCell_(textContainer); | |
198 } | |
199 } | |
200 }; | |
201 | |
202 /** | |
203 * Asks the C++ PolicyUIHandler to get details about policies and status | |
204 * information. The PolicyUIHandler should reply to returnData() (below). | |
205 */ | |
206 Policy.requestData = function() { | |
207 chrome.send('requestData'); | |
208 }; | |
209 | |
210 /** | |
211 * Called by the C++ PolicyUIHandler when it has the requested data. | |
212 * @param {Object} policyData The policy information in the format described | |
213 * by the policyDataFormat. | |
214 */ | |
215 Policy.returnData = function(policyData) { | |
216 var policy = Policy.getInstance(); | |
217 policy.collapseExpandedCells(); | |
218 policy.renderTemplate(policyData); | |
219 policy.updatePolicyVisibility(); | |
220 }; | |
221 | |
222 /** | |
223 * Called by the C++ PolicyUIHandler when a requested policy refresh has | |
224 * completed. | |
225 */ | |
226 Policy.refreshDone = function() { | |
227 $('fetch-policies-button').disabled = false; | |
228 }; | |
229 | |
230 /** | |
231 * Asks the C++ PolicyUIHandler to re-fetch policy information. | |
232 */ | |
233 Policy.triggerPolicyFetch = function() { | |
234 chrome.send('fetchPolicy'); | |
235 }; | |
236 | |
237 /** | |
238 * Determines whether a policy should be visible or not. | |
239 * @param {Object} policy An entry in the 'policies' array given by the above | |
240 * PolicyDataFormat. | |
241 */ | |
242 Policy.shouldDisplayPolicy = function(policy) { | |
243 return $('toggle-unsent-policies').checked || policy.set; | |
244 }; | |
245 | |
246 /** | |
247 * Initializes the page and loads the list of policies and the policy | |
248 * status data. | |
249 */ | |
250 Policy.initialize = function() { | |
251 Policy.requestData(); | |
252 | |
253 // Set HTML event handlers. | |
254 $('fetch-policies-button').onclick = function(event) { | |
255 this.disabled = true; | |
256 Policy.triggerPolicyFetch(); | |
257 }; | |
258 | |
259 $('toggle-unsent-policies').onchange = function(event) { | |
260 Policy.getInstance().updatePolicyVisibility(); | |
261 }; | |
262 | |
263 $('search-field').onsearch = function(event) { | |
264 Policy.getInstance().filterTable(this.value); | |
265 }; | |
266 }; | |
267 | |
268 // Export | |
269 return { | 412 return { |
270 Policy: Policy | 413 Page: Page |
271 }; | 414 }; |
272 }); | 415 }); |
273 | 416 |
274 var Policy = policies.Policy; | 417 // Have the main initialization function be called when the page finishes |
275 | 418 // loading. |
276 // Get data and have it displayed upon loading. | 419 document.addEventListener( |
277 document.addEventListener('DOMContentLoaded', policies.Policy.initialize); | 420 'DOMContentLoaded', |
| 421 policy.Page.getInstance().initialize.bind(policy.Page.getInstance())); |
OLD | NEW |