Last active
May 30, 2017 01:12
-
-
Save oshybystyi/8cf882bc8b0c9a95a116 to your computer and use it in GitHub Desktop.
Load default preferences for firefox bootstrap (restartless) addons
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Default addon bootstrap file | |
* full example can be found here https://github.com/oshybystyi/FireX-Pixel-Perfect/blob/issue-5-make-addon-restartless/bootstrap.js | |
*/ | |
const defaultPreferencesLoaderLink = 'chrome://<addon-alias/<path-to>/defaultPreferencesLoader.jsm'; | |
function startup(data) { | |
/** some code here ... **/ | |
loadDefaultPreferences(data.installPath); | |
/** some code here ... **/ | |
} | |
function shutdown(data, reason) { | |
if (reason == APP_SHUTDOWN) | |
return; | |
/** Remove default preferences on extension being uninstalled **/ | |
unloadDefaultPreferences(); | |
/** some code here ... **/ | |
} | |
function loadDefaultPreferences(installPath) { | |
Cu.import(defaultPreferencesLoaderLink); | |
this.defaultPreferencesLoader = new DefaultPreferencesLoader(installPath); | |
this.defaultPreferencesLoader.parseDirectory(); | |
} | |
function unloadDefaultPreferences() { | |
this.defaultPreferencesLoader.clearDefaultPrefs(); | |
Cu.unload(defaultPreferencesLoaderLink); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Working example can be found here | |
* https://github.com/oshybystyi/FireX-Pixel-Perfect/blob/issue-5-make-addon-restartless/content/lib/defaultPreferencesLoader.jsm | |
* | |
* Important this module was tested only with <em:unpack>true</em:unpack>, most | |
* likely it won't work with false value | |
* | |
* A lot of stuff was borrowed from https://github.com/firebug/firebug/blob/master/extension/modules/prefLoader.js | |
*/ | |
const { utils: Cu, classes: Cc, interfaces: Ci } = Components; | |
Cu.import('resource://gre/modules/Services.jsm'); | |
var EXPORTED_SYMBOLS = ['DefaultPreferencesLoader']; | |
/** | |
* Read defaults/preferences/* and set Services.pref default branch | |
*/ | |
function DefaultPreferencesLoader(installPath) { | |
let readFrom = installPath.clone(); // don't modify the original object | |
['defaults', 'preferences'].forEach(function(dir) { | |
readFrom.append(dir); | |
}); | |
this.baseURI = Services.io.newFileURI(readFrom); | |
if (readFrom.exists() !== true) { | |
throw new DefaultsDirectoryMissingError(readFrom); | |
} | |
this.readFrom = readFrom; | |
this.defaultBranch = Services.prefs.getDefaultBranch(""); | |
} | |
DefaultPreferencesLoader.prototype = { | |
/** | |
* Iterate over files in the default/preferences/* | |
* | |
* @param {function} prefFunc the function that should be used instead of | |
* pref | |
*/ | |
parseDirectory: function(prefFunc) { | |
prefFunc = prefFunc || this.pref.bind(this); | |
let entries = this.readFrom.directoryEntries; | |
while (entries.hasMoreElements()) { | |
let fileURI = Services.io.newFileURI(entries.getNext()); | |
Services.scriptloader.loadSubScript(fileURI.spec, { pref: prefFunc }); | |
} | |
}, | |
/** | |
* Emulates firefox pref function to load default preferences | |
*/ | |
pref: function(key, value) { | |
switch (typeof value) { | |
case 'boolean': | |
this.defaultBranch.setBoolPref(key, value); | |
break; | |
case 'number': | |
this.defaultBranch.setIntPref(key, value); | |
break; | |
case 'string': | |
/** | |
* Using setComplexValue instead of setCharPref because of | |
* unicode support | |
*/ | |
let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); | |
str.value = value; | |
this.defaultBranch.setComplexValue(key, Ci.nsISupportsString, str); | |
break; | |
default: | |
throw new NotSupportedValueTypeError(key); | |
break; | |
} | |
}, | |
/** | |
* Clears default preferences according to AMO reviewers reccommendation | |
* This should be invoked on bootstrap::shutdown | |
* @see https://github.com/firebug/firebug/blob/master/extension/modules/prefLoader.js | |
*/ | |
clearDefaultPrefs: function() { | |
this.parseDirectory(this.prefUnload.bind(this)); | |
}, | |
prefUnload: function(key) { | |
let branch = this.defaultBranch; | |
if (branch.prefHasUserValue(key) !== true) { | |
branch.deleteBranch(key); | |
} | |
} | |
}; | |
/** | |
* Exception type on missing defaults/preferences folder | |
*/ | |
function DefaultsDirectoryMissingError(installPath) { | |
this.name = 'DefaultsDirectoryMissingError'; | |
this.message = '\'' + installPath.path + '\' does no exist'; | |
} | |
/** Inherit from Error for error stack and pretty output in terminal **/ | |
DefaultsDirectoryMissingError.prototype = new Error(); | |
/** | |
* Not supported value type to store by pref | |
*/ | |
function NotSupportedValueTypeError(key) { | |
this.name = 'NotSupportedValueType'; | |
this.message = 'Value type for key \'' + key + '\' is not supported'; | |
} | |
NotSupportedValueTypeError.prototype = new Error(); |
After review on bugzilla I found similar firebug extension.
So I borrowed and modified some code in prefLoader (d2dd3ea6e6a93b98bacee5b5276a64fd7895c6ca)
Among changes:
- instead of parsing file data with regex - use loadSubScript with pref function.
- replaced setCharPref with setComplexValue to support unicode.
Why should you use this component instead of firebug prefLoader?
- it is easier to deploy into bootstrap.js (because I have example in this gist)
Other benefits from this gist?
- when I started porting extension I didn't know about prefLoader, but now additional info introduced here https://developer.mozilla.org/en-US/Add-ons/How_to_convert_an_overlay_extension_to_restartless#Step_4a.3A_Another_way_to_handle_default_preferences . So if anybody will got into similar problem he will know about current solution.
It appears that str.value
on line 76 should be str.data
?
This doesn't appear to work for a packed extension. The code in function DefaultPreferencesLoader
is trying to append the path "defaults/preferences" to the path of the XPI file, which doesn't work. I think you need to implement alternative code using nsIZipReader
or something.
Something like this seems to work (the rest of the code other than the section shown here remains unchanged):
/**
* Read defaults/preferences/* and set Services.pref default branch
*/
function DefaultPreferencesLoader(installPath) {
var readFrom = [];
// Maybe instead just test if it's a file rather than a directory?
// Not sure.
if (/\.xpi$/i.test(installPath.path)) {
let baseURI = Services.io.newFileURI(installPath);
// Packed extension, need to read ZIP to get list of preference files
// and then use "jar:" URIs to access them.
let zr = Cc['@mozilla.org/libjar/zip-reader;1'].createInstance(
Ci.nsIZipReader);
zr.open(installPath);
let entries = zr.findEntries('defaults/preferences/?*');
while (entries.hasMore()) {
let entry = entries.getNext();
readFrom.push('jar:' + baseURI.spec + "!/" + entry);
}
}
else {
let dirPath = installPath.clone(); // don't modify the original object
['defaults', 'preferences'].forEach(function(dir) {
dirPath.append(dir);
});
if (dirPath.exists() !== true) {
throw new DefaultsDirectoryMissingError(dirPath);
}
let entries = dirPath.directoryEntries;
while (entries.hasMoreElements()) {
let fileURI = Services.io.newFileURI(entries.getNext());
readFrom.push(fileURI.spec);
}
}
this.readFrom = readFrom;
this.defaultBranch = Services.prefs.getDefaultBranch("");
}
DefaultPreferencesLoader.prototype = {
/**
* Iterate over files in the default/preferences/*
*
* @param {function} prefFunc the function that should be used instead of
* pref
*/
parseDirectory: function(prefFunc) {
prefFunc = prefFunc || this.pref.bind(this);
this.readFrom.forEach(function(uri) {
Services.scriptloader.loadSubScript(uri, { pref: prefFunc });
});
},
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This module allows automatic loading files from default/preferences/* with pref('...', ...) instructions for restartless firefox addons (a hack against firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=564675)
Examples of usage can be found on https://github.com/oshybystyi/FireX-Pixel-Perfect/tree/issue-5-make-addon-restartless (here I ported FireX-Pixel-Perfect from overlay based into bootstrap one)