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