ユーザー設定とは、アドオンの設定を管理する機能です。
設定システムにアクセスするには、XPCOMを使用します。
nsIPrefBranchは、次のようにすることで取得できます。
var prefBranch = Components.classes[ '@mozilla.org/preferences-service;1' ] .getService( Components.interfaces.nsIPrefBranch );
またはnsIPrefServiceから、getBranch()でも取得できます。
メソッド | |
---|---|
void | addObserver( in string aDomain, in nsIObserver aObserver, in boolean aHoldWeak ) |
void | removeObserver( in string aDomain, in nsIObserver aObserver ) |
void | getChildList( in string aStartingAt, [optional] out unsigned long aCount, [array, size_is(aCount), retval] out string aChildArray ) |
void | deleteBranch( in string aStartingAt ) |
void | resetBranch( in string aStartingAt ) |
long | getPrefType( in string aPrefName ) |
boolean | prefHasUserValue( in string aPrefName ) |
void | clearUserPref( in string aPrefName ) |
void | lockPref( in string aPrefName ) |
void | unlockPref( in string aPrefName ) |
boolean | prefIsLocked( in string aPrefName ) |
区分 | メソッド | |
---|---|---|
取得 | long | getIntPref( in string aPrefName ) |
string | getCharPref( in string aPrefName ) | |
boolean | getBoolPref( in string aPrefName ) | |
設定 | void | setIntPref( in string aPrefName, in long aValue ) |
void | setCharPref( in string aPrefName, in string aValue ) | |
void | setBoolPref( in string aPrefName, in long aValue ) |
メソッド | |
---|---|
void | getComplexValue( in string aPrefName, in nsIIDRef aType, [iid_is(aType), retval] out nsQIResult aValue ) |
void | setComplexValue( in string aPrefName, in nsIIDRef aType, in nsISupports aValue ) |
nsIPrefServiceは、次のようにすることで取得できます。
var prefService = Components.classes[ '@mozilla.org/preferences-service;1' ] .getService( Components.interfaces.nsIPrefService );
メソッド | |
---|---|
nsIPrefBranch | getBranch( in string aPrefRoot ) |
nsIPrefBranch | getDefaultBranch( in string aPrefRoot ) |
void | resetPrefs() |
void | resetUserPrefs() |
void | savePrefFile( in nsIFile aFile ) |
void | readUserPrefs( in nsIFile aFile ) |
ユーザー設定へアクセスするためのnsIPrefBranchを取得します。
nsIPrefBranch getBranch( in string aPrefRoot );getBranch() - nsIPrefService - XPCOM Interface Reference | MDN
about:configで、既存のアドオンの設定を確認できます。設定値の使用方法は、これが参考になります。
設定値の名前は、
のいずれかの形式から始めるのが慣習のようです。しかしアドオンを配布することを考えるならば、1番目の書式とすべきです。
all preference names should begin with "extensions.", followed by the add-on name or some other unique identifier
Review Process :: Add-on Documentation :: Developer Hub :: Add-ons for Firefox
また設定名はドット区切りで記述されることが多いようですが、システム上はこのドットに意味はなく、文字列の一部とみなされます。設定 "木" についての詳細 - Preferences - Code snippets | MDN
型 | 取得 | 設定 |
---|---|---|
整数※1 | getIntPref() | setIntPref() |
文字列 | getCharPref() | setCharPref() |
論理値 | getBoolPref() | setBoolPref() |
※1 浮動小数点数は使用できません。よってその必要があるならば文字列として定義し、使用時に文字列と数値を変換します。
これらのメソッドは、設定値の型に応じて正しく使い分けなければなりません。さもなくば例外が発生します。
long getIntPref( in string aPrefName );getIntPref() - nsIPrefBranch - Mozilla | MDN
void setIntPref( in string aPrefName, in long aValue );setIntPref() - nsIPrefBranch - Mozilla | MDN
オブジェクトは、JSONに変換することで文字列として処理できます。また文字列に変換できる要素から構成される配列ならば、Array.join()でも同様です。
var prefService = Components.classes[ '@mozilla.org/preferences-service;1' ] .getService( Components.interfaces.nsIPrefService ); var branch = prefService.getBranch( 'extensions.MyAddon.' ); var value = branch.getIntPref( 'pref1' );
設定名のドット区切りに意味はないため、次のように指定しても同じです。
var branch = prefService.getBranch( '' ); var value = branch.getIntPref( 'extensions.MyAddon.pref1' );
またnsIPrefServiceではなくnsIPrefBranchを取得することで、
var prefBranch = Components.classes[ '@mozilla.org/preferences-service;1' ] .getService( Components.interfaces.nsIPrefBranch ); var value = prefBranch.getIntPref( 'extensions.MyAddon.pref1' );
のようにも記述できます。
有効な値が存在しない設定名から読み込もうとすると「NS_ERROR_UNEXPECTED: Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIPrefBranch.getIntPref]」として例外が発生します。その設定名で記録する処理が存在していても、既定の設定で初期値が指定されていないと、ユーザーのリセットの操作により設定値が削除されることがあります。
よって設定の取得時には例外に備えるか、さもなくば既定値を設定します。
書き込みも読み込みと同様で、nsIPrefBranchのメソッドを呼び出します。
var prefBranch = Components.classes[ '@mozilla.org/preferences-service;1' ] .getService( Components.interfaces.nsIPrefBranch ); prefBranch.setCharPref( 'extensions.MyAddon.pref1', 'abc' );
たとえば文字列として作成されたユーザー設定を、整数用のメソッドであるgetIntPref()で読もうとすると、「Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIPrefBranch.getIntPref]」として例外が発生します。
この問題には、ユーザー設定の型を事前に調べることで対処できます。それを行うのが次のgetPrefType()です。
long getPrefType( in string aPrefName )getPrefType() - nsIPrefBranch - XPCOM Interface Reference | MDN
branch.getPrefType( aPrefName )として設定名を指定して呼び出すと、その設定の型に応じて定数が返されます。このメソッドの用法は、以下のサンプルを参考にしてください。
var prefService = Components.classes[ '@mozilla.org/preferences-service;1' ] .getService( Components.interfaces.nsIPrefService ); var branch = prefService.getBranch( 'extensions.MyAddon.' ); var value = null; var prefName = 'pref1'; switch( branch.getPrefType( prefName ) ) { case branch.PREF_STRING: value = branch.getCharPref( prefName ); break; case branch.PREF_INT: value = branch.getIntPref( prefName ); break; case branch.PREF_BOOL: value = branch.getBoolPref( prefName ); break; case branch.PREF_INVALID: break; }
複合型では単純型の3つの型、つまり整数、文字列、論理値以外の型を扱えます。
取得 | 設定 |
---|---|
getComplexValue() | setComplexValue() |
void getComplexValue( in string aPrefName, in nsIIDRef aType, [iid_is(aType), retval] out nsQIResult aValue );getComplexValue() - nsIPrefBranch - XPCOM Interface Reference | MDN
void setComplexValue( in string aPrefName, in nsIIDRef aType, in nsISupports aValue );
aTypeには、次のいずれかの値を指定します。
about:configで、設定値の確認や編集を行えます。
作成した設定値は、直接削除することはできません。その設定値を作成しないようにコードを修正し、設定値が既定値であることを確認してからFirefoxを再起動することで、設定ファイル (prefs.js) から削除されます。
なお設定値を既定値に戻すには、対象の値を右クリックしコンテキストメニューから[リセット]を実行します。
設定値をブラウザのロード時に初期化している場合、ユーザーに設定ウィンドウで設定を変更されても、その設定はブラウザを再起動するまで反映されません。この問題に対処するには、設定の変更を監視するようにします。
addObserver()で、設定値の変更を監視 (オブザーブ) できます。このとき監視する対象は、他の拡張の設定でも、ブラウザの既定の設定でも構いません。
addObserver( in string aDomain, // 監視対象の設定値の名前 in nsIObserver aObserver, // 変更の通知を受け取るオブジェクト in boolean aHoldWeak // trueならばaObserverの弱い参照を、さもなくば強い参照を保持する )addObserver() - nsIPrefBranch - XPCOM Interface Reference | MDN
引数のaDomainには、getBranch()で指定した設定名に続く文字を指定します。たとえば、
という設定名があるとき、
var branch = prefService.getBranch( 'MyAddon.' ); branch.addObserver( 'a', this, false );
とすると、[MyAddon.a]から始まる「MyAddon.aa」と「MyAddon.ab」の2つが監視対象となります。一方で第1引数のaDomainを空文字とすると、[MyAddon.]から始まる「MyAddon.bb」も含めた3つが対象となります。
addObserver()でオブザーバを追加したならば、それが不要になったときにはremoveObserver()でそれを取り除く必要があります。さもなくば監視対象が変更されるたびに、observe()が呼ばれ続けることになります。
void removeObserver( in string aDomain, // 監視対象としてあった設定値の名前 in nsIObserver aObserver // 変更の通知を受け取るオブジェクト );removeObserver() - nsIPrefBranch - XPCOM Interface Reference | MDN
addObserver()で追加したオブザーバーを削除するならば、引数のaDomainとaObserverは、addObserver()で指定した同名の引数と同じものとします。
var prefObserver = { branch: null, register: function() { var prefService = Components.classes[ '@mozilla.org/preferences-service;1' ] .getService( Components.interfaces.nsIPrefService ); // ユーザー設定へアクセスするためのnsIPrefBranchを取得する this.branch = prefService.getBranch( 'extensions.MyAddon.' ); // … そのユーザー設定に、オブザーバーを追加する // … 第2引数にthisを渡すことで、通知をthis.observe()が受け取ることになる this.branch.addObserver( '', this, false ); }, unregister: function() { this.branch.removeObserver( '', this ); }, // 監視対象の設定が変更されると、呼び出されるメソッド observe: function( aSubject, aTopic, aData ) { switch( aData ) { case 'pref1': // 'extensions.MyAddon.pref1' が変更された break; case 'pref2': // 'extensions.MyAddon.pref2' が変更された break; } } }; window.addEventListener( 'load', function() { prefObserver.register(); }, false ); window.addEventListener( 'unload', function() { prefObserver.unregister(); }, false );
observe()は、addObserver()の第2引数で指定するオブジェクトにobserveの名前で定義することで、監視対象の設定が変更されるたびに呼び出されます。
void observe( in nsISupports aSubject, // 監視対象のnsIPrefBranch in string aTopic, // "nsPref:changed"などの値 in wstring aData // 変更された設定値の名前 );nsIObserver - XPCOM Interface Reference | MDN
引数のaSubjectには、オブザーバを設定したnsIPrefBranchが渡されます。つまり、
aSubject.getIntPref( aData );
のようにすることで、新しい設定値を取得できます。このとき引数のaDataには、getBranch()で指定した設定名に続く文字列が渡されます。たとえば「extensions.MyAddon.pref1」という設定名があるとして、
branch = prefService.getBranch( 'extensions.MyAddon.' ); branch.addObserver( 'p', this, false );
のようにオブザーバが追加されているとします。このとき「extensions.MyAddon.pref1」に変更があると、observe()の引数aDataには'pref1'という文字列が渡されます。一方で、もし
branch = prefService.getBranch( 'exten' ); branch.addObserver( '', this, false );
のようにオブザーバが追加されているとすると、'sions.MyAddon.pref1'が渡されます。
既定の設定は、defaults\preferences\フォルダに拡張子を「js」としてファイルを配置します。配置するフォルダと拡張子が重要であり、ファイル名は意味を持ちません。複数のファイルを配置した場合は、それらのすべてが読み込まれます。
値の設定は、pref()関数で行います。
pref('name', value);
この関数では設定名と値のみを指定し、型を指定する必要はありません。それはvalueの型に応じて適切に設定されます。設定値が複数ある場合には、セミコロンで区切ってこの関数を複数記述します。なお、このファイルに記述できるのはこの関数とコメントのみで、それは次のようにします。
/* comment */ pref( 'extensions.MyAddon.a', 1 ); // 整数値 pref( 'extensions.MyAddon.c', 'foo' ); // 文字列 pref( 'extensions.MyAddon.d', true ); // 真偽値
記述に誤りがあると、それ以降の設定が無効となります。
拡張子はjsでありJavaScript風に記述しますが、これはJavaScriptではありません。よって変数や式は記述できず、文末のセミコロンを省略できないなど文法も異なります。
about:configでリセットされたときは、この既定の設定の値が設定されます。もしこの既定の設定がなければその設定値は無効な状態となり、その値を読み込もうとすると「NS_ERROR_UNEXPECTED: Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIPrefBranch.getIntPref]」として例外が発生します。
値に文字列を指定する場合、文字列を「'」で囲った場合には、文字列中に「'」を直接記述することはできません。これは「"」で文字列を囲むか、「\'」のようにエスケープすることで解決できます。このような問題は、JavaScriptの文字列リテラルをエスケープすることと同じです。
設定用のウィンドウも他のUIと同様に、XULで定義します。そのときルート要素は<prefwindow>とし、その子要素に<prefpane>でペインを配置します。
設定項目は<preferences>のなかで<preference>で定義します。<preference>のname属性が設定値の名前となり、typeで下表のいずれかの型を指定します。
種類 | 設定値 | 意味 |
---|---|---|
単純型 | bool | 真偽値 |
int | 整数値 | |
string | 文字列 | |
複合型 | unichar | Unicode文字列 |
wstring | ローカライズされた文字列 | |
file | ファイル |
typeと異なる型の値が設定された場合は、typeの型に変換されて設定に格納されます。たとえばtypeをintとしたときに"12AB34"が設定されると、"12"が格納されます。
すでに存在する設定と同名で、しかし型が異なる設定値は設定できません。設定しようとしても無視されます。
<textbox>などの入力要素で、設定対象の<preference>のid属性をpreference属性で指定します。こうすることで設定ウィンドウに現在の設定値が自動で表示され、また設定を変更したときにはその値が保存されます。
<?xml version="1.0"?> <?xml-stylesheet type="text/css" href="chrome://global/skin/"?> <prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="pref"> <prefpane> <preferences> <preference type="bool" id="AAA" name="extensions.MyAddon.A" /> <preference type="int" id="BBB" name="extensions.MyAddon.B" /> </preferences> <checkbox preference="AAA" label="A" /> <textbox preference="BBB" /> </prefpane> </prefwindow>
このサンプルでの設定値は、about:configで次のように確認できます。
prefwindow要素のid属性は必須です。このことは開発者センターの検証で、「<prefwindow>` elements without `id` attributes cause errors to be reported in the error console and prevent persistence of certain properties of the dialog.」のように記されています。
またXULは、XUL Editorでプレビューを確認しながら記述すると簡単です。そのとき設定値は、about:configで確認できます。
prefpane要素を複数定義することで、設定項目をペインごとにまとめられます。ペインの名前をlabel属性で、ペインのIDはid属性で定義します。このid属性は必須で、これを定義しないとペインの切替が機能しません。Using multiple prefpanes - prefpane - XUL | MDN
<prefpane id="pane1" label="Pane1"> <preferences> <preference type="bool" id="AAA" name="aaa.A" /> </preferences> <checkbox preference="AAA" label="A" /> </prefpane> <prefpane id="pane2" label="Pane2"> ... </prefpane>
radioの値を記録するには、preferenceをradiogroupに設定します。そしてradioのそれぞれの値を、valueで指定しておきます。
<preferences> <preference type="int" id="AAA" name="extensions.MyAddon.A" /> </preferences> <radiogroup preference="AAA"> <radio label="A" value="0" /> <radio label="B" value="1" /> <radio label="C" value="2" /> </radiogroup>
アドオンマネージャ (Add-on Manager) のアドオンの項目に、
のような[設定]ボタンを追加するには、install.rdfのoptionsURLで
<em:optionsURL>chrome://myPackage/content/prefs.xul</em:optionsURL>Adding preferences to an extension | MDN
のように、設定ウィンドウのxulファイルを指定します。
拡張機能のルートにoptions.xulというファイルが置かれていると、この設定は無視され、そのファイルがインラインオプションとして開かれます。
プラットフォームによっては、アドオンマネージャから開くウィンドウはモーダル (他のウィンドウを操作できないウィンドウ) で表示されます。モードレスとするには、アドオンマネージャ以外からopenDialog()で開く必要があります。588720 – Addon preference dialog shouldn't be modal when opened from addon manager page
既定ではprefwindowの[OK]ボタンがクリックされたときに、preference要素のname属性で指定された設定に書き込まれます。
設定が変更されたタイミングでユーザー設定を更新したい場合には、その設定のpreference要素のinstantApply属性をtrueとします。
<preference instantApply="true" type="bool" id="A" name="extensions.MyAddon.A" />instantApply - Mozilla | MDN
設定画面を設定ウィンドウのようなウィンドウではなく、アドオンの詳細ページに埋め込む形で表示できます。
設定画面をインラインオプションとするには、
<em:optionsURL>chrome://myPackage/content/options.xul</em:optionsURL> <em:optionsType>2</em:optionsType>のように定義する
の2つの方法があります。UIとなるXULは、次のように定義します。
<?xml version="1.0"?> <vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <setting type="bool" pref="extensions.MyAddon.A" title="設定項目1" /> <setting type="string" pref="extensions.MyAddon.B" title="設定項目2" /> </vbox>
ここでは設定ウィンドウのような<prefwindow>や<preferences>は不要で、ただ<setting>のみで記述します。