| Index: chrome/browser/resources/policy.js
 | 
| diff --git a/chrome/browser/resources/policy.js b/chrome/browser/resources/policy.js
 | 
| index 064a6c5fc774f39a5d6f218ad742fdb4aac46cc4..2c52c616df0a8bdd2f65ce6209243f31ebc0ec81 100644
 | 
| --- a/chrome/browser/resources/policy.js
 | 
| +++ b/chrome/browser/resources/policy.js
 | 
| @@ -1,277 +1,422 @@
 | 
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
 | 
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
 | 
|  // Use of this source code is governed by a BSD-style license that can be
 | 
|  // found in the LICENSE file.
 | 
|  
 | 
| -/**
 | 
| - * This variable structure is here to document the structure that the template
 | 
| - * expects to correctly populate the page.
 | 
| - */
 | 
| -var policyDataFormat = {
 | 
| -  // Whether any of the policies in 'policies' have a value.
 | 
| -  'anyPoliciesSet': true,
 | 
| -
 | 
| -  'policies': [
 | 
| -    {
 | 
| -      'level': 'managed',
 | 
| -      'name': 'AllowXYZ',
 | 
| -      'set': true,
 | 
| -      'scope': 'Machine',
 | 
| -      'status': 'ok',
 | 
| -      'value': true
 | 
| -    }
 | 
| -  ],
 | 
| -  'status': {
 | 
| -    'deviceFetchInterval': '8min',
 | 
| -    'deviceId': 'D2AC39A2-3C8FC-E2C0-E45D2DC3782C',
 | 
| -    'deviceLastFetchTime': '9:50 PM',
 | 
| -    'devicePolicyDomain': 'google.com',
 | 
| -    'deviceStatusMessage': 'OK',
 | 
| -    'displayDeviceStatus': true,
 | 
| -    'displayStatusSection': true,
 | 
| -    'displayUserStatus': true,
 | 
| -    'user': 'simo@google.com',
 | 
| -    'userFetchInterval': '8min',
 | 
| -    'userId': 'D2AC39A2-3C8FC-E2C0-E45D2DC3782C',
 | 
| -    'userLastFetchTime': '9:50 PM',
 | 
| -    'userStatusMessage': 'OK'
 | 
| -  }
 | 
| -};
 | 
| -
 | 
| -cr.define('policies', function() {
 | 
| +cr.define('policy', function() {
 | 
| +  /**
 | 
| +   * A box that shows the status of cloud policy for a device or user.
 | 
| +   * @constructor
 | 
| +   * @extends {HTMLFieldSetElement}
 | 
| +   */
 | 
| +  var StatusBox = cr.ui.define(function() {
 | 
| +    var node = $('status-box-template').cloneNode(true);
 | 
| +    node.removeAttribute('id');
 | 
| +    return node;
 | 
| +  });
 | 
|  
 | 
| -  function Policy() {
 | 
| -  }
 | 
| +  StatusBox.prototype = {
 | 
| +    // Set up the prototype chain.
 | 
| +    __proto__: HTMLFieldSetElement.prototype,
 | 
|  
 | 
| -  cr.addSingletonGetter(Policy);
 | 
| +    /**
 | 
| +     * Initialization function for the cr.ui framework.
 | 
| +     */
 | 
| +    decorate: function() {
 | 
| +    },
 | 
|  
 | 
| -  Policy.prototype = {
 | 
|      /**
 | 
| -     * True if none of the received policies are actually set, false otherwise.
 | 
| -     * @type {boolean}
 | 
| +     * Populate the box with the given cloud policy status.
 | 
| +     * @param {string} scope The policy scope, either "device" or "user".
 | 
| +     * @param {Object} status Dictionary with information about the status.
 | 
|       */
 | 
| -    noActivePolicies_: false,
 | 
| +    initialize: function(scope, status) {
 | 
| +      if (scope == 'device') {
 | 
| +        // For device policy, set the appropriate title and populate the topmost
 | 
| +        // status item with the domain the device is enrolled into.
 | 
| +        this.querySelector('.legend').textContent =
 | 
| +            loadTimeData.getString('statusDevice');
 | 
| +        var domain = this.querySelector('.domain');
 | 
| +        domain.textContent = status.domain;
 | 
| +        domain.parentElement.hidden = false;
 | 
| +      } else {
 | 
| +        // For user policy, set the appropriate title and populate the topmost
 | 
| +        // status item with the username that policies apply to.
 | 
| +        this.querySelector('.legend').textContent =
 | 
| +            loadTimeData.getString('statusUser');
 | 
| +        // Populate the topmost item with the username.
 | 
| +        var username = this.querySelector('.username');
 | 
| +        username.textContent = status.username;
 | 
| +        username.parentElement.hidden = false;
 | 
| +      }
 | 
| +      // Populate all remaining items.
 | 
| +      this.querySelector('.client-id').textContent = status.clientId || '';
 | 
| +      this.querySelector('.time-since-last-refresh').textContent =
 | 
| +          status.timeSinceLastRefresh || '';
 | 
| +      this.querySelector('.refresh-interval').textContent =
 | 
| +          status.refreshInterval || '';
 | 
| +      this.querySelector('.status').textContent = status.status || '';
 | 
| +    },
 | 
| +  };
 | 
| +
 | 
| +  /**
 | 
| +   * A single policy's entry in the policy table.
 | 
| +   * @constructor
 | 
| +   * @extends {HTMLTableSectionElement}
 | 
| +   */
 | 
| +  var Policy = cr.ui.define(function() {
 | 
| +    var node = $('policy-template').cloneNode(true);
 | 
| +    node.removeAttribute('id');
 | 
| +    return node;
 | 
| +  });
 | 
| +
 | 
| +  Policy.prototype = {
 | 
| +    // Set up the prototype chain.
 | 
| +    __proto__: HTMLTableSectionElement.prototype,
 | 
|  
 | 
|      /**
 | 
| -     * The current search term for filtering of the policy table.
 | 
| -     * @type {string}
 | 
| -     * @private
 | 
| +     * Initialization function for the cr.ui framework.
 | 
|       */
 | 
| -    searchTerm_: '',
 | 
| +    decorate: function() {
 | 
| +      this.updateToggleExpandedValueText_();
 | 
| +      this.querySelector('.toggle-expanded-value').addEventListener(
 | 
| +          'click', this.toggleExpandedValue_.bind(this));
 | 
| +    },
 | 
|  
 | 
|      /**
 | 
| -     * Takes the |policyData| argument and populates the page with this data. It
 | 
| -     * expects an object structure like the policyDataFormat above.
 | 
| -     * @param {Object} policyData Detailed info about policies.
 | 
| +     * Populate the table columns with information about the policy name, value
 | 
| +     * and status.
 | 
| +     * @param {string} name The policy name.
 | 
| +     * @param {Object} value Dictionary with information about the policy value.
 | 
| +     * @param {boolean} unknown Whether the policy name is not recognized.
 | 
|       */
 | 
| -    renderTemplate: function(policyData) {
 | 
| -      this.noActivePolicies_ = !policyData.anyPoliciesSet;
 | 
| -
 | 
| -      if (this.noActivePolicies_)
 | 
| -        $('no-policies').hidden = false;
 | 
| -      if (policyData.status.displayStatusSection)
 | 
| -        $('status-section').hidden = false;
 | 
| -
 | 
| -      // This is the javascript code that processes the template:
 | 
| -      var input = new JsEvalContext(policyData);
 | 
| -      var output = $('data-template');
 | 
| -      jstProcess(input, output);
 | 
| -
 | 
| -      var toggles = document.querySelectorAll('.policy-set * .toggler');
 | 
| -      for (var i = 0; i < toggles.length; i++) {
 | 
| -        toggles[i].hidden = true;
 | 
| -        toggles[i].onclick = function() {
 | 
| -          Policy.getInstance().toggleCellExpand_(this);
 | 
| -        };
 | 
| +    initialize: function(name, value, unknown) {
 | 
| +      this.name = name;
 | 
| +      this.unset = !value;
 | 
| +
 | 
| +      // Populate the name column.
 | 
| +      this.querySelector('.name').textContent = name;
 | 
| +
 | 
| +      // Populate the remaining columns with policy scope, level and value if a
 | 
| +      // value has been set. Otherwise, leave them blank.
 | 
| +      if (value) {
 | 
| +        this.querySelector('.scope').textContent =
 | 
| +            loadTimeData.getString(value.scope == 'user' ?
 | 
| +                'scopeUser' : 'scopeDevice');
 | 
| +        this.querySelector('.level').textContent =
 | 
| +            loadTimeData.getString(value.level == 'recommended' ?
 | 
| +                'levelRecommended' : 'levelMandatory');
 | 
| +        this.querySelector('.value').textContent = value.value;
 | 
| +        this.querySelector('.expanded-value').textContent = value.value;
 | 
|        }
 | 
|  
 | 
| -      var containers = document.querySelectorAll('.text-container');
 | 
| -      for (var i = 0; i < containers.length; i++)
 | 
| -        this.initTextContainer_(containers[i]);
 | 
| +      // Populate the status column.
 | 
| +      var status;
 | 
| +      if (!value) {
 | 
| +        // If the policy value has not been set, show an error message.
 | 
| +        status = loadTimeData.getString('unset');
 | 
| +      } else if (unknown) {
 | 
| +        // If the policy name is not recognized, show an error message.
 | 
| +        status = loadTimeData.getString('unknown');
 | 
| +      } else if (value.error) {
 | 
| +        // If an error occurred while parsing the policy value, show the error
 | 
| +        // message.
 | 
| +        status = value.error;
 | 
| +      } else {
 | 
| +        // Otherwise, indicate that the policy value was parsed correctly.
 | 
| +        status = loadTimeData.getString('ok');
 | 
| +      }
 | 
| +      this.querySelector('.status').textContent = status;
 | 
|      },
 | 
|  
 | 
|      /**
 | 
| -     * Filters the table of policies by name.
 | 
| -     * @param {string} term The search string.
 | 
| +     * Check the table columns for overflow. Most columns are automatically
 | 
| +     * elided when overflow occurs. The only action required is to add a tooltip
 | 
| +     * that shows the complete content. The value column is an exception. If
 | 
| +     * overflow occurs here, the contents is replaced with a link that toggles
 | 
| +     * the visibility of an additional row containing the complete value.
 | 
|       */
 | 
| -    filterTable: function(term) {
 | 
| -      this.searchTerm_ = term.toLowerCase();
 | 
| -      var table = $('policy-table');
 | 
| -      var showUnsent = $('toggle-unsent-policies').checked;
 | 
| -      for (var r = 1; r < table.rows.length; r++) {
 | 
| -        var row = table.rows[r];
 | 
| -
 | 
| -        // Don't change visibility of policies that aren't set if the checkbox
 | 
| -        // isn't checked.
 | 
| -        if (!showUnsent && row.className == 'policy-unset')
 | 
| -          continue;
 | 
| -
 | 
| -        var nameCell = row.querySelector('.policy-name');
 | 
| -        var cellContents = nameCell.textContent;
 | 
| -        row.hidden =
 | 
| -            !(cellContents.toLowerCase().indexOf(this.searchTerm_) >= 0);
 | 
| +    checkOverflow: function() {
 | 
| +      // Set a tooltip on all overflowed columns except the value column.
 | 
| +      var divs = this.querySelectorAll('div.elide');
 | 
| +      for (var i = 0; i < divs.length; i++) {
 | 
| +        var div = divs[i];
 | 
| +        div.title = div.offsetWidth < div.scrollWidth ? div.textContent : '';
 | 
|        }
 | 
| +
 | 
| +      // Cache the width of the value column's contents when it is first shown.
 | 
| +      // This is required to be able to check whether the contents would still
 | 
| +      // overflow the column once it has been hidden and replaced by a link.
 | 
| +      var valueContainer = this.querySelector('.value-container');
 | 
| +      if (valueContainer.valueWidth == undefined) {
 | 
| +        valueContainer.valueWidth =
 | 
| +            valueContainer.querySelector('.value').offsetWidth;
 | 
| +      }
 | 
| +
 | 
| +      // Determine whether the contents of the value column overflows. The
 | 
| +      // visibility of the contents, replacement link and additional row
 | 
| +      // containing the complete value that depend on this are handled by CSS.
 | 
| +      this.classList.toggle(
 | 
| +          'has-overflowed-value',
 | 
| +          valueContainer.offsetWidth < valueContainer.valueWidth);
 | 
|      },
 | 
|  
 | 
|      /**
 | 
| -     * Updates the visibility of the policies depending on the state of the
 | 
| -     * 'toggle-unsent-policies' checkbox.
 | 
| +     * Update the text of the link that toggles the visibility of an additional
 | 
| +     * row containing the complete policy value, depending on the toggle state.
 | 
| +     * @private
 | 
|       */
 | 
| -    updatePolicyVisibility: function() {
 | 
| -      if ($('toggle-unsent-policies').checked)
 | 
| -        $('policies').style.display = '';
 | 
| -      else if (this.noActivePolicies_)
 | 
| -        $('policies').style.display = 'none';
 | 
| -
 | 
| -      var tableRows = document.getElementsByClassName('policy-unset');
 | 
| -      for (var i = 0; i < tableRows.length; i++)
 | 
| -        tableRows[i].hidden = !($('toggle-unsent-policies').checked);
 | 
| -
 | 
| -      // Filter table again in case a search was active.
 | 
| -      this.filterTable(this.searchTerm_);
 | 
| +    updateToggleExpandedValueText_: function(event) {
 | 
| +      this.querySelector('.toggle-expanded-value').textContent =
 | 
| +          loadTimeData.getString(
 | 
| +              this.classList.contains('show-overflowed-value') ?
 | 
| +                  'hideExpandedValue' : 'showExpandedValue');
 | 
|      },
 | 
|  
 | 
|      /**
 | 
| -     * Expands or collapses a table cell that has overflowing text.
 | 
| -     * @param {Object} toggler The toggler that was clicked on.
 | 
| +     * Toggle the visibility of an additional row containing the complete policy
 | 
| +     * value.
 | 
|       * @private
 | 
|       */
 | 
| -    toggleCellExpand_: function(toggler) {
 | 
| -      var textContainer = toggler.parentElement;
 | 
| -      textContainer.collapsed = !textContainer.collapsed;
 | 
| -
 | 
| -      if (textContainer.collapsed)
 | 
| -        this.collapseCell_(textContainer);
 | 
| -      else
 | 
| -        this.expandCell_(textContainer);
 | 
| +    toggleExpandedValue_: function() {
 | 
| +      this.classList.toggle('show-overflowed-value');
 | 
| +      this.updateToggleExpandedValueText_();
 | 
|      },
 | 
| +  };
 | 
| +
 | 
| +  /**
 | 
| +   * A table of policies and their values.
 | 
| +   * @constructor
 | 
| +   * @extends {HTMLTableSectionElement}
 | 
| +   */
 | 
| +  var PolicyTable = cr.ui.define('tbody');
 | 
| +
 | 
| +  PolicyTable.prototype = {
 | 
| +    // Set up the prototype chain.
 | 
| +    __proto__: HTMLTableSectionElement.prototype,
 | 
|  
 | 
|      /**
 | 
| -     * Collapses all expanded table cells and updates the visibility of the
 | 
| -     * toggles accordingly. Should be called before the policy information in
 | 
| -     * the table is updated.
 | 
| +     * Initialization function for the cr.ui framework.
 | 
|       */
 | 
| -    collapseExpandedCells: function() {
 | 
| -      var textContainers = document.querySelectorAll('.text-expanded');
 | 
| -      for (var i = 0; i < textContainers.length; i++)
 | 
| -        this.collapseCell_(textContainers[i]);
 | 
| +    decorate: function() {
 | 
| +      this.policies_ = {};
 | 
| +      this.filterPattern_ = '';
 | 
| +      window.addEventListener('resize', this.checkOverflow_.bind(this));
 | 
|      },
 | 
|  
 | 
|      /**
 | 
| -     * Expands a table cell so that all the text it contains is visible.
 | 
| -     * @param {Object} textContainer The cell's div element that contains the
 | 
| -     * text.
 | 
| -     * @private
 | 
| +     * Initialize the list of all known policies.
 | 
| +     * @param {Object} names Dictionary containing all known policy names.
 | 
|       */
 | 
| -    expandCell_: function(textContainer) {
 | 
| -      textContainer.classList.remove('text-collapsed');
 | 
| -      textContainer.classList.add('text-expanded');
 | 
| -      textContainer.querySelector('.expand').hidden = true;
 | 
| -      textContainer.querySelector('.collapse').hidden = false;
 | 
| +    setPolicyNames: function(names) {
 | 
| +      this.policies_ = names;
 | 
| +      this.setPolicyValues({});
 | 
|      },
 | 
|  
 | 
|      /**
 | 
| -     * Collapses a table cell so that overflowing text is hidden.
 | 
| -     * @param {Object} textContainer The cell's div element that contains the
 | 
| -     * text.
 | 
| -     * @private
 | 
| +     * Populate the table with the currently set policy values and any errors
 | 
| +     * detected while parsing these.
 | 
| +     * @param {Object} values Dictionary containing the current policy values.
 | 
| +     */
 | 
| +    setPolicyValues: function(values) {
 | 
| +      // Remove all policies from the table.
 | 
| +      var policies = this.getElementsByTagName('tbody');
 | 
| +      while (policies.length > 0)
 | 
| +        this.removeChild(policies.item(0));
 | 
| +
 | 
| +      // First, add known policies whose value is currently set.
 | 
| +      var unset = [];
 | 
| +      for (var name in this.policies_) {
 | 
| +        if (name in values)
 | 
| +          this.setPolicyValue_(name, values[name], false);
 | 
| +        else
 | 
| +          unset.push(name);
 | 
| +      }
 | 
| +
 | 
| +      // Second, add policies whose value is currently set but whose name is not
 | 
| +      // recognized.
 | 
| +      for (var name in values) {
 | 
| +        if (!(name in this.policies_))
 | 
| +          this.setPolicyValue_(name, values[name], true);
 | 
| +      }
 | 
| +
 | 
| +      // Finally, add known policies whose value is not currently set.
 | 
| +      for (var i = 0; i < unset.length; i++)
 | 
| +        this.setPolicyValue_(unset[i], undefined, false);
 | 
| +
 | 
| +      // Filter the policies.
 | 
| +      this.filter();
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Set the filter pattern. Only policies whose name contains |pattern| are
 | 
| +     * shown in the policy table. The filter is case insensitive. It can be
 | 
| +     * disabled by setting |pattern| to an empty string.
 | 
| +     * @param {string} pattern The filter pattern.
 | 
| +     */
 | 
| +    setFilterPattern: function(pattern) {
 | 
| +      this.filterPattern_ = pattern.toLowerCase();
 | 
| +      this.filter();
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Filter policies. Only policies whose name contains the filter pattern are
 | 
| +     * shown in the table. Furthermore, policies whose value is not currently
 | 
| +     * set are only shown if the corresponding checkbox is checked.
 | 
|       */
 | 
| -    collapseCell_: function(textContainer) {
 | 
| -      textContainer.classList.remove('text-expanded');
 | 
| -      textContainer.classList.add('text-collapsed');
 | 
| -      textContainer.querySelector('.expand').hidden = false;
 | 
| -      textContainer.querySelector('.collapse').hidden = true;
 | 
| +    filter: function() {
 | 
| +      var showUnset = $('show-unset').checked;
 | 
| +      var policies = this.getElementsByTagName('tbody');
 | 
| +      for (var i = 0; i < policies.length; i++) {
 | 
| +        var policy = policies[i];
 | 
| +        policy.hidden =
 | 
| +            policy.unset && !showUnset ||
 | 
| +            policy.name.toLowerCase().indexOf(this.filterPattern_) == -1;
 | 
| +      }
 | 
| +      this.parentElement.classList.toggle(
 | 
| +          'empty', !this.querySelector('tbody:not([hidden])'));
 | 
| +      setTimeout(this.checkOverflow_.bind(this), 0);
 | 
|      },
 | 
|  
 | 
|      /**
 | 
| -     * Initializes a text container, showing the expand toggle if necessary.
 | 
| -     * @param {Object} textContainer The text container element.
 | 
| +     * Check the table columns for overflow.
 | 
| +     * @private
 | 
|       */
 | 
| -    initTextContainer_: function(textContainer) {
 | 
| -      textContainer.collapsed = true;
 | 
| -      var textValue = textContainer.querySelector('.text-value');
 | 
| -
 | 
| -      // If the text is wider than the text container, the expand toggler should
 | 
| -      // appear.
 | 
| -      if (textContainer.offsetWidth < textValue.offsetWidth ||
 | 
| -          textContainer.offsetHeight < textValue.offsetHeight) {
 | 
| -        this.collapseCell_(textContainer);
 | 
| +    checkOverflow_: function() {
 | 
| +      var policies = this.getElementsByTagName('tbody');
 | 
| +      for (var i = 0; i < policies.length; i++) {
 | 
| +        if (!policies[i].hidden)
 | 
| +          policies[i].checkOverflow();
 | 
|        }
 | 
| -    }
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Add a policy with the given |name| and |value| to the table.
 | 
| +     * @param {string} name The policy name.
 | 
| +     * @param {Object} value Dictionary with information about the policy value.
 | 
| +     * @param {boolean} unknown Whether the policy name is not recoginzed.
 | 
| +     * @private
 | 
| +     */
 | 
| +    setPolicyValue_: function(name, value, unknown) {
 | 
| +      var policy = new Policy;
 | 
| +      policy.initialize(name, value, unknown);
 | 
| +      this.appendChild(policy);
 | 
| +    },
 | 
|    };
 | 
|  
 | 
|    /**
 | 
| -   * Asks the C++ PolicyUIHandler to get details about policies and status
 | 
| -   * information. The PolicyUIHandler should reply to returnData() (below).
 | 
| +   * A singelton object that handles communication between browser and WebUI.
 | 
| +   * @constructor
 | 
|     */
 | 
| -  Policy.requestData = function() {
 | 
| -    chrome.send('requestData');
 | 
| -  };
 | 
| +  function Page() {
 | 
| +  }
 | 
| +
 | 
| +  // Make Page a singleton.
 | 
| +  cr.addSingletonGetter(Page);
 | 
|  
 | 
|    /**
 | 
| -   * Called by the C++ PolicyUIHandler when it has the requested data.
 | 
| -   * @param {Object} policyData The policy information in the format described
 | 
| -   * by the policyDataFormat.
 | 
| +   * Provide a list of all known policies to the UI. Called by the browser on
 | 
| +   * page load.
 | 
| +   * @param {Object} names Dictionary containing all known policy names.
 | 
|     */
 | 
| -  Policy.returnData = function(policyData) {
 | 
| -    var policy = Policy.getInstance();
 | 
| -    policy.collapseExpandedCells();
 | 
| -    policy.renderTemplate(policyData);
 | 
| -    policy.updatePolicyVisibility();
 | 
| +  Page.setPolicyNames = function(names) {
 | 
| +    this.getInstance().policyTable.setPolicyNames(names);
 | 
|    };
 | 
|  
 | 
|    /**
 | 
| -   * Called by the C++ PolicyUIHandler when a requested policy refresh has
 | 
| -   * completed.
 | 
| +   * Provide a list of the currently set policy values and any errors detected
 | 
| +   * while parsing these to the UI. Called by the browser on page load and
 | 
| +   * whenever policy values change.
 | 
| +   * @param {Object} values Dictionary containing the current policy values.
 | 
|     */
 | 
| -  Policy.refreshDone = function() {
 | 
| -    $('fetch-policies-button').disabled = false;
 | 
| +  Page.setPolicyValues = function(values) {
 | 
| +    this.getInstance().policyTable.setPolicyValues(values);
 | 
|    };
 | 
|  
 | 
|    /**
 | 
| -   * Asks the C++ PolicyUIHandler to re-fetch policy information.
 | 
| +   * Provide the current cloud policy status to the UI. Called by the browser on
 | 
| +   * page load if cloud policy is present and whenever the status changes.
 | 
| +   * @param {Object} status Dictionary containing the current policy status.
 | 
|     */
 | 
| -  Policy.triggerPolicyFetch = function() {
 | 
| -    chrome.send('fetchPolicy');
 | 
| +  Page.setStatus = function(status) {
 | 
| +    this.getInstance().setStatus(status);
 | 
|    };
 | 
|  
 | 
|    /**
 | 
| -   * Determines whether a policy should be visible or not.
 | 
| -   * @param {Object} policy An entry in the 'policies' array given by the above
 | 
| -   * PolicyDataFormat.
 | 
| +   * Notify the UI that a request to reload policy values has completed. Called
 | 
| +   * by the browser after a request to reload policy has been sent by the UI.
 | 
|     */
 | 
| -  Policy.shouldDisplayPolicy = function(policy) {
 | 
| -    return $('toggle-unsent-policies').checked || policy.set;
 | 
| +  Page.reloadPoliciesDone = function() {
 | 
| +    this.getInstance().reloadPoliciesDone();
 | 
|    };
 | 
|  
 | 
| -  /**
 | 
| -   * Initializes the page and loads the list of policies and the policy
 | 
| -   * status data.
 | 
| -   */
 | 
| -  Policy.initialize = function() {
 | 
| -    Policy.requestData();
 | 
| -
 | 
| -    // Set HTML event handlers.
 | 
| -    $('fetch-policies-button').onclick = function(event) {
 | 
| -      this.disabled = true;
 | 
| -      Policy.triggerPolicyFetch();
 | 
| -    };
 | 
| -
 | 
| -    $('toggle-unsent-policies').onchange = function(event) {
 | 
| -      Policy.getInstance().updatePolicyVisibility();
 | 
| -    };
 | 
| -
 | 
| -    $('search-field').onsearch = function(event) {
 | 
| -      Policy.getInstance().filterTable(this.value);
 | 
| -    };
 | 
| +  Page.prototype = {
 | 
| +    /**
 | 
| +     * Main initialization function. Called by the browser on page load.
 | 
| +     */
 | 
| +    initialize: function() {
 | 
| +      uber.onContentFrameLoaded();
 | 
| +      this.policyTable = $('policy-table');
 | 
| +      cr.ui.decorate(this.policyTable, PolicyTable);
 | 
| +
 | 
| +      // Place the initial focus on the filter input field.
 | 
| +      $('filter').focus();
 | 
| +
 | 
| +      var self = this;
 | 
| +      $('filter').onsearch = function(event) {
 | 
| +        self.policyTable.setFilterPattern(this.value);
 | 
| +      };
 | 
| +      $('reload-policies').onclick = function(event) {
 | 
| +        this.disabled = true;
 | 
| +        chrome.send('reloadPolicies');
 | 
| +      };
 | 
| +      $('show-unset').onchange = this.policyTable.filter.bind(this.policyTable);
 | 
| +
 | 
| +      // Notify the browser that the page has loaded, causing it to send the
 | 
| +      // list of all known policies, the current policy values and the cloud
 | 
| +      // policy status.
 | 
| +      chrome.send('initialized');
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Update the status section of the page to show the current cloud policy
 | 
| +     * status.
 | 
| +     * @param {Object} status Dictionary containing the current policy status.
 | 
| +     */
 | 
| +    setStatus: function(status) {
 | 
| +      // Remove any existing status boxes.
 | 
| +      var container = $('status-box-container');
 | 
| +      while (container.firstChild)
 | 
| +        container.removeChild(container.firstChild);
 | 
| +      // Hide the status section.
 | 
| +      var section = $('status');
 | 
| +      section.hidden = true;
 | 
| +
 | 
| +      // Add a status box for each scope that has a cloud policy status.
 | 
| +      for (var scope in status) {
 | 
| +        var box = new StatusBox;
 | 
| +        box.initialize(scope, status[scope]);
 | 
| +        container.appendChild(box);
 | 
| +        // Show the status section.
 | 
| +        section.hidden = false;
 | 
| +      }
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Re-enable the reload policies button when the previous request to reload
 | 
| +     * policies values has completed.
 | 
| +     */
 | 
| +    reloadPoliciesDone: function() {
 | 
| +      $('reload-policies').disabled = false;
 | 
| +    },
 | 
|    };
 | 
|  
 | 
| -  // Export
 | 
|    return {
 | 
| -    Policy: Policy
 | 
| +    Page: Page
 | 
|    };
 | 
|  });
 | 
|  
 | 
| -var Policy = policies.Policy;
 | 
| -
 | 
| -// Get data and have it displayed upon loading.
 | 
| -document.addEventListener('DOMContentLoaded', policies.Policy.initialize);
 | 
| +// Have the main initialization function be called when the page finishes
 | 
| +// loading.
 | 
| +document.addEventListener(
 | 
| +    'DOMContentLoaded',
 | 
| +    policy.Page.getInstance().initialize.bind(policy.Page.getInstance()));
 | 
| 
 |