1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 'use strict'; 6 7 /** 8 * @fileoverview Provides the Settings class. 9 */ 10 base.exportTo('base', function() { 11 var alternativeStorageInstance = undefined; 12 13 /** 14 * Settings is a simple wrapper around local storage, to make it easier 15 * to test classes that have settings. 16 * 17 * @constructor 18 */ 19 function Settings() { 20 if (alternativeStorageInstance) { 21 this.storage_ = alternativeStorageInstance; 22 } else if ('G_testRunner' in global) { 23 /** 24 * In unit tests, use a mock object for storage so we don't change 25 * localStorage in tests. 26 */ 27 this.storage_ = new FakeLocalStorage(); 28 } else { 29 this.storage_ = localStorage; 30 } 31 } 32 33 Settings.setAlternativeStorageInstance = function(instance) { 34 alternativeStorageInstance = instance; 35 } 36 37 Settings.prototype = { 38 39 /** 40 * Get the setting with the given name. 41 * 42 * @param {string} key The name of the setting. 43 * @param {string} opt_default The default value to return if not set. 44 * @param {string} opt_namespace If set, the setting name will be prefixed 45 * with this namespace, e.g. "categories.settingName". This is useful for 46 * a set of related settings. 47 */ 48 get: function(key, opt_default, opt_namespace) { 49 key = this.namespace_(key, opt_namespace); 50 var val = this.storage_.getItem(key); 51 if (val === null || val === undefined) 52 return opt_default; 53 return String(val); 54 }, 55 56 /** 57 * Set the setting with the given name to the given value. 58 * 59 * @param {string} key The name of the setting. 60 * @param {string} value The value of the setting. 61 * @param {string} opt_namespace If set, the setting name will be prefixed 62 * with this namespace, e.g. "categories.settingName". This is useful for 63 * a set of related settings. 64 */ 65 set: function(key, value, opt_namespace) { 66 this.storage_.setItem(this.namespace_(key, opt_namespace), String(value)); 67 }, 68 69 /** 70 * Return a list of all the keys, or all the keys in the given namespace 71 * if one is provided. 72 * 73 * @param {string} opt_namespace If set, only return settings which 74 * begin with this prefix. 75 */ 76 keys: function(opt_namespace) { 77 var result = []; 78 opt_namespace = opt_namespace || ''; 79 for (var i = 0; i < this.storage_.length; i++) { 80 var key = this.storage_.key(i); 81 if (this.isnamespaced_(key, opt_namespace)) 82 result.push(this.unnamespace_(key, opt_namespace)); 83 } 84 return result; 85 }, 86 87 isnamespaced_: function(key, opt_namespace) { 88 return key.indexOf(this.normalize_(opt_namespace)) == 0; 89 }, 90 91 namespace_: function(key, opt_namespace) { 92 return this.normalize_(opt_namespace) + key; 93 }, 94 95 unnamespace_: function(key, opt_namespace) { 96 return key.replace(this.normalize_(opt_namespace), ''); 97 }, 98 99 /** 100 * All settings are prefixed with a global namespace to avoid collisions. 101 * Settings may also be namespaced with an additional prefix passed into 102 * the get, set, and keys methods in order to group related settings. 103 * This method makes sure the two namespaces are always set properly. 104 */ 105 normalize_: function(opt_namespace) { 106 return Settings.NAMESPACE + (opt_namespace ? opt_namespace + '.' : ''); 107 } 108 }; 109 110 Settings.NAMESPACE = 'trace-viewer'; 111 112 /** 113 * Create a Fake localStorage object which just stores to a dictionary 114 * instead of actually saving into localStorage. Only used in unit tests. 115 * @constructor 116 */ 117 function FakeLocalStorage() { 118 } 119 120 FakeLocalStorage.prototype = { 121 __proto__: Object.prototype, 122 123 getItem: function(key) { 124 // LocalStorage returns null if the key isn't found, not undefined. 125 if (this[key] === undefined || this[key] === null) 126 return null; 127 return this[key]; 128 }, 129 130 setItem: function(key, value) { 131 this[key] = value; 132 }, 133 134 key: function(i) { 135 return Object.keys(this).sort()[i]; 136 }, 137 get length() { 138 return Object.keys(this).length; 139 } 140 }; 141 142 return { 143 Settings: Settings 144 }; 145 }); 146