Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: chrome/browser/resources/policy.js

Issue 12084065: Convert chrome://policy to new WebUI style (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Move string to the correct position. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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()));
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698