Javascript  |  146行  |  4.22 KB

// Copyright (c) 2012 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.

'use strict';

/**
 * @fileoverview Provides the Settings class.
 */
base.exportTo('base', function() {
  var alternativeStorageInstance = undefined;

  /**
   * Settings is a simple wrapper around local storage, to make it easier
   * to test classes that have settings.
   *
   * @constructor
   */
  function Settings() {
    if (alternativeStorageInstance) {
      this.storage_ = alternativeStorageInstance;
    } else if ('G_testRunner' in global) {
      /**
       * In unit tests, use a mock object for storage so we don't change
       * localStorage in tests.
       */
      this.storage_ = new FakeLocalStorage();
    } else {
      this.storage_ = localStorage;
    }
  }

  Settings.setAlternativeStorageInstance = function(instance) {
    alternativeStorageInstance = instance;
  }

  Settings.prototype = {

    /**
     * Get the setting with the given name.
     *
     * @param {string} key The name of the setting.
     * @param {string} opt_default The default value to return if not set.
     * @param {string} opt_namespace If set, the setting name will be prefixed
     * with this namespace, e.g. "categories.settingName". This is useful for
     * a set of related settings.
     */
    get: function(key, opt_default, opt_namespace) {
      key = this.namespace_(key, opt_namespace);
      var val = this.storage_.getItem(key);
      if (val === null || val === undefined)
        return opt_default;
      return String(val);
    },

    /**
     * Set the setting with the given name to the given value.
     *
     * @param {string} key The name of the setting.
     * @param {string} value The value of the setting.
     * @param {string} opt_namespace If set, the setting name will be prefixed
     * with this namespace, e.g. "categories.settingName". This is useful for
     * a set of related settings.
     */
    set: function(key, value, opt_namespace) {
      this.storage_.setItem(this.namespace_(key, opt_namespace), String(value));
    },

    /**
     * Return a list of all the keys, or all the keys in the given namespace
     * if one is provided.
     *
     * @param {string} opt_namespace If set, only return settings which
     * begin with this prefix.
     */
    keys: function(opt_namespace) {
      var result = [];
      opt_namespace = opt_namespace || '';
      for (var i = 0; i < this.storage_.length; i++) {
        var key = this.storage_.key(i);
        if (this.isnamespaced_(key, opt_namespace))
          result.push(this.unnamespace_(key, opt_namespace));
      }
      return result;
    },

    isnamespaced_: function(key, opt_namespace) {
      return key.indexOf(this.normalize_(opt_namespace)) == 0;
    },

    namespace_: function(key, opt_namespace) {
      return this.normalize_(opt_namespace) + key;
    },

    unnamespace_: function(key, opt_namespace) {
      return key.replace(this.normalize_(opt_namespace), '');
    },

    /**
     * All settings are prefixed with a global namespace to avoid collisions.
     * Settings may also be namespaced with an additional prefix passed into
     * the get, set, and keys methods in order to group related settings.
     * This method makes sure the two namespaces are always set properly.
     */
    normalize_: function(opt_namespace) {
      return Settings.NAMESPACE + (opt_namespace ? opt_namespace + '.' : '');
    }
  };

  Settings.NAMESPACE = 'trace-viewer';

  /**
   * Create a Fake localStorage object which just stores to a dictionary
   * instead of actually saving into localStorage. Only used in unit tests.
   * @constructor
   */
  function FakeLocalStorage() {
  }

  FakeLocalStorage.prototype = {
    __proto__: Object.prototype,

    getItem: function(key) {
      // LocalStorage returns null if the key isn't found, not undefined.
      if (this[key] === undefined || this[key] === null)
        return null;
      return this[key];
    },

    setItem: function(key, value) {
      this[key] = value;
    },

    key: function(i) {
      return Object.keys(this).sort()[i];
    },
    get length() {
      return Object.keys(this).length;
    }
  };

  return {
    Settings: Settings
  };
});