mirror of
https://github.com/atom/atom.git
synced 2026-01-23 13:58:08 -05:00
331 lines
9.6 KiB
JavaScript
331 lines
9.6 KiB
JavaScript
/* vim:ts=4:sts=4:sw=4:
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla Skywriter.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Mozilla.
|
|
* Portions created by the Initial Developer are Copyright (C) 2009
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Joe Walker (jwalker@mozilla.com)
|
|
* Julian Viereck (jviereck@mozilla.com)
|
|
* Kevin Dangoor (kdangoor@mozilla.com)
|
|
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
define(function(require, exports, module) {
|
|
|
|
/**
|
|
* This plug-in manages settings.
|
|
*/
|
|
|
|
var console = require('pilot/console');
|
|
var oop = require('pilot/oop');
|
|
var types = require('pilot/types');
|
|
var EventEmitter = require('pilot/event_emitter').EventEmitter;
|
|
var catalog = require('pilot/catalog');
|
|
|
|
var settingExtensionSpec = {
|
|
name: 'setting',
|
|
description: 'A setting is something that the application offers as a ' +
|
|
'way to customize how it works',
|
|
register: 'env.settings.addSetting',
|
|
indexOn: 'name'
|
|
};
|
|
|
|
exports.startup = function(data, reason) {
|
|
catalog.addExtensionSpec(settingExtensionSpec);
|
|
};
|
|
|
|
exports.shutdown = function(data, reason) {
|
|
catalog.removeExtensionSpec(settingExtensionSpec);
|
|
};
|
|
|
|
|
|
/**
|
|
* Create a new setting.
|
|
* @param settingSpec An object literal that looks like this:
|
|
* {
|
|
* name: 'thing',
|
|
* description: 'Thing is an example setting',
|
|
* type: 'string',
|
|
* defaultValue: 'something'
|
|
* }
|
|
*/
|
|
function Setting(settingSpec, settings) {
|
|
this._settings = settings;
|
|
|
|
Object.keys(settingSpec).forEach(function(key) {
|
|
this[key] = settingSpec[key];
|
|
}, this);
|
|
|
|
this.type = types.getType(this.type);
|
|
if (this.type == null) {
|
|
throw new Error('In ' + this.name +
|
|
': can\'t find type for: ' + JSON.stringify(settingSpec.type));
|
|
}
|
|
|
|
if (!this.name) {
|
|
throw new Error('Setting.name == undefined. Ignoring.', this);
|
|
}
|
|
|
|
if (!this.defaultValue === undefined) {
|
|
throw new Error('Setting.defaultValue == undefined', this);
|
|
}
|
|
|
|
if (this.onChange) {
|
|
this.on('change', this.onChange.bind(this))
|
|
}
|
|
|
|
this.set(this.defaultValue);
|
|
}
|
|
Setting.prototype = {
|
|
get: function() {
|
|
return this.value;
|
|
},
|
|
|
|
set: function(value) {
|
|
if (this.value === value) {
|
|
return;
|
|
}
|
|
|
|
this.value = value;
|
|
if (this._settings.persister) {
|
|
this._settings.persister.persistValue(this._settings, this.name, value);
|
|
}
|
|
|
|
this._dispatchEvent('change', { setting: this, value: value });
|
|
},
|
|
|
|
/**
|
|
* Reset the value of the <code>key</code> setting to it's default
|
|
*/
|
|
resetValue: function() {
|
|
this.set(this.defaultValue);
|
|
},
|
|
toString: function () {
|
|
return this.name;
|
|
}
|
|
};
|
|
oop.implement(Setting.prototype, EventEmitter);
|
|
|
|
|
|
/**
|
|
* A base class for all the various methods of storing settings.
|
|
* <p>Usage:
|
|
* <pre>
|
|
* // Create manually, or require 'settings' from the container.
|
|
* // This is the manual version:
|
|
* var settings = plugins.catalog.getObject('settings');
|
|
* // Add a new setting
|
|
* settings.addSetting({ name:'foo', ... });
|
|
* // Display the default value
|
|
* alert(settings.get('foo'));
|
|
* // Alter the value, which also publishes the change etc.
|
|
* settings.set('foo', 'bar');
|
|
* // Reset the value to the default
|
|
* settings.resetValue('foo');
|
|
* </pre>
|
|
* @constructor
|
|
*/
|
|
function Settings(persister) {
|
|
// Storage for deactivated values
|
|
this._deactivated = {};
|
|
|
|
// Storage for the active settings
|
|
this._settings = {};
|
|
// We often want sorted setting names. Cache
|
|
this._settingNames = [];
|
|
|
|
if (persister) {
|
|
this.setPersister(persister);
|
|
}
|
|
};
|
|
|
|
Settings.prototype = {
|
|
/**
|
|
* Function to add to the list of available settings.
|
|
* <p>Example usage:
|
|
* <pre>
|
|
* var settings = plugins.catalog.getObject('settings');
|
|
* settings.addSetting({
|
|
* name: 'tabsize', // For use in settings.get('X')
|
|
* type: 'number', // To allow value checking.
|
|
* defaultValue: 4 // Default value for use when none is directly set
|
|
* });
|
|
* </pre>
|
|
* @param {object} settingSpec Object containing name/type/defaultValue members.
|
|
*/
|
|
addSetting: function(settingSpec) {
|
|
var setting = new Setting(settingSpec, this);
|
|
this._settings[setting.name] = setting;
|
|
this._settingNames.push(setting.name);
|
|
this._settingNames.sort();
|
|
},
|
|
|
|
addSettings: function addSettings(settings) {
|
|
Object.keys(settings).forEach(function (name) {
|
|
var setting = settings[name];
|
|
if (!('name' in setting)) setting.name = name;
|
|
this.addSetting(setting);
|
|
}, this);
|
|
},
|
|
|
|
removeSetting: function(setting) {
|
|
var name = (typeof setting === 'string' ? setting : setting.name);
|
|
setting = this._settings[name];
|
|
delete this._settings[name];
|
|
util.arrayRemove(this._settingNames, name);
|
|
settings.removeAllListeners('change');
|
|
},
|
|
|
|
removeSettings: function removeSettings(settings) {
|
|
Object.keys(settings).forEach(function(name) {
|
|
var setting = settings[name];
|
|
if (!('name' in setting)) setting.name = name;
|
|
this.removeSettings(setting);
|
|
}, this);
|
|
},
|
|
|
|
getSettingNames: function() {
|
|
return this._settingNames;
|
|
},
|
|
|
|
getSetting: function(name) {
|
|
return this._settings[name];
|
|
},
|
|
|
|
/**
|
|
* A Persister is able to store settings. It is an object that defines
|
|
* two functions:
|
|
* loadInitialValues(settings) and persistValue(settings, key, value).
|
|
*/
|
|
setPersister: function(persister) {
|
|
this._persister = persister;
|
|
if (persister) {
|
|
persister.loadInitialValues(this);
|
|
}
|
|
},
|
|
|
|
resetAll: function() {
|
|
this.getSettingNames().forEach(function(key) {
|
|
this.resetValue(key);
|
|
}, this);
|
|
},
|
|
|
|
/**
|
|
* Retrieve a list of the known settings and their values
|
|
*/
|
|
_list: function() {
|
|
var reply = [];
|
|
this.getSettingNames().forEach(function(setting) {
|
|
reply.push({
|
|
'key': setting,
|
|
'value': this.getSetting(setting).get()
|
|
});
|
|
}, this);
|
|
return reply;
|
|
},
|
|
|
|
/**
|
|
* Prime the local cache with the defaults.
|
|
*/
|
|
_loadDefaultValues: function() {
|
|
this._loadFromObject(this._getDefaultValues());
|
|
},
|
|
|
|
/**
|
|
* Utility to load settings from an object
|
|
*/
|
|
_loadFromObject: function(data) {
|
|
// We iterate over data rather than keys so we don't forget values
|
|
// which don't have a setting yet.
|
|
for (var key in data) {
|
|
if (data.hasOwnProperty(key)) {
|
|
var setting = this._settings[key];
|
|
if (setting) {
|
|
var value = setting.type.parse(data[key]);
|
|
this.set(key, value);
|
|
} else {
|
|
this.set(key, data[key]);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Utility to grab all the settings and export them into an object
|
|
*/
|
|
_saveToObject: function() {
|
|
return this.getSettingNames().map(function(key) {
|
|
return this._settings[key].type.stringify(this.get(key));
|
|
}.bind(this));
|
|
},
|
|
|
|
/**
|
|
* The default initial settings
|
|
*/
|
|
_getDefaultValues: function() {
|
|
return this.getSettingNames().map(function(key) {
|
|
return this._settings[key].spec.defaultValue;
|
|
}.bind(this));
|
|
}
|
|
};
|
|
exports.settings = new Settings();
|
|
|
|
/**
|
|
* Save the settings in a cookie
|
|
* This code has not been tested since reboot
|
|
* @constructor
|
|
*/
|
|
function CookiePersister() {
|
|
};
|
|
|
|
CookiePersister.prototype = {
|
|
loadInitialValues: function(settings) {
|
|
settings._loadDefaultValues();
|
|
var data = cookie.get('settings');
|
|
settings._loadFromObject(JSON.parse(data));
|
|
},
|
|
|
|
persistValue: function(settings, key, value) {
|
|
try {
|
|
var stringData = JSON.stringify(settings._saveToObject());
|
|
cookie.set('settings', stringData);
|
|
} catch (ex) {
|
|
console.error('Unable to JSONify the settings! ' + ex);
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.CookiePersister = CookiePersister;
|
|
|
|
});
|