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) { | |
James Hawkins
2013/01/31 17:08:05
nit: i++
Here and elsewhere.
bartfab (slow)
2013/01/31 17:36:13
Done.
| |
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 |