15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @fileoverview This file defines a singleton which provides access to all data
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * that is available as soon as the page's resources are loaded (before DOM
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * content has finished loading). This data includes both localized strings and
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * any data that is important to have ready from a very early stage (e.g. things
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * that must be displayed right away).
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var loadTimeData;
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Expose this type globally as a temporary work around until
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// https://github.com/google/closure-compiler/issues/544 is fixed.
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/** @constructor */
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)function LoadTimeData() {}
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(function() {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  'use strict';
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadTimeData.prototype = {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Sets the backing object.
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     *
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Note that there is no getter for |data_| to discourage abuse of the form:
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     *
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     *     var value = loadTimeData.data()['key'];
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     *
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Object} value The de-serialized page data.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set data(value) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expect(!this.data_, 'Re-setting data.');
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.data_ = value;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Returns a JsEvalContext for |data_|.
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * @returns {JsEvalContext}
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    createJsEvalContext: function() {
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return new JsEvalContext(this.data_);
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    },
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @param {string} id An ID of a value that might exist.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {boolean} True if |id| is a key in the dictionary.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    valueExists: function(id) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return id in this.data_;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Fetches a value, expecting that it exists.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} id The key that identifies the desired value.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {*} The corresponding value.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getValue: function(id) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expect(this.data_, 'No data. Did you remember to include strings.js?');
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var value = this.data_[id];
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expect(typeof value != 'undefined', 'Could not find value for ' + id);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return value;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * As above, but also makes sure that the value is a string.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} id The key that identifies the desired string.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {string} The corresponding string value.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getString: function(id) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var value = this.getValue(id);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expectIsType(id, value, 'string');
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return /** @type {string} */ (value);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Returns a formatted localized string where $1 to $9 are replaced by the
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * second to the tenth argument.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} id The ID of the string we want.
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @param {...string} var_args The extra values to include in the formatted
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     *     output.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {string} The formatted string.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    getStringF: function(id, var_args) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var value = this.getString(id);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!value)
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return '';
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var varArgs = arguments;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return value.replace(/\$[$1-9]/g, function(m) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return m == '$$' ? '$' : varArgs[m[1]];
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      });
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * As above, but also makes sure that the value is a boolean.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} id The key that identifies the desired boolean.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {boolean} The corresponding boolean value.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getBoolean: function(id) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var value = this.getValue(id);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expectIsType(id, value, 'boolean');
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return /** @type {boolean} */ (value);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * As above, but also makes sure that the value is an integer.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} id The key that identifies the desired number.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {number} The corresponding number value.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getInteger: function(id) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var value = this.getValue(id);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expectIsType(id, value, 'number');
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expect(value == Math.floor(value), 'Number isn\'t integer: ' + value);
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return /** @type {number} */ (value);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Override values in loadTimeData with the values found in |replacements|.
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @param {Object} replacements The dictionary object of keys to replace.
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    overrideValues: function(replacements) {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      expect(typeof replacements == 'object',
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             'Replacements must be a dictionary object.');
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (var key in replacements) {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this.data_[key] = replacements[key];
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /**
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * Checks condition, displays error message if expectation fails.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @param {*} condition The condition to check for truthiness.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @param {string} message The message to display if the check fails.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function expect(condition, message) {
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!condition) {
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      console.error('Unexpected condition on ' + document.location.href + ': ' +
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    message);
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /**
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * Checks that the given value has the given type.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @param {string} id The id of the value (only used for error message).
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @param {*} value The value to check the type on.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @param {string} type The type we expect |value| to be.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function expectIsType(id, value, type) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    expect(typeof value == type, '[' + value + '] (' + id +
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 ') is not a ' + type);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expect(!loadTimeData, 'should only include this file once');
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  loadTimeData = new LoadTimeData;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)})();
158