「キーワードの追加・削除」機能の実装
今回も、Thunderbird用アドオンのSubjectHelperの改造をする。
実装後のファイル構成はこんな感じ。
subjecthelper
├ install.rdf
┠ chrome.manifest
┠ defaults
│ └ preferences
│ └ preferences.js
└ content
┠ overlay.xul
┠ subjectHelper.css
┠ subjectHelper.xml
┠ subjectHelper.js
└ img
└ icon.png
defaults配下を追加、contentのsubjectHelper.js、overlay.xulを変更した。
キーワードの保持方法
今回は、キーワードを保持するために、Mozilla設定システムを利用した。Mozilla設定システムとは、FireFoxのアドレスバーに「about:config」を入力した際に、表示されるアレのこと。
今回追加したdefaults配下のpreferences.jsは、初回起動時に、初期値を設定するための定義が記述されている。
設定した初期値はこんな感じ。
pref( "extensions.subjecthelper.keyword.list", "要返信,年休連絡,時間外" );
※これは、[編集]->[設定]->[詳細]->「設定エディタ] から確認できる。
この「extensions.subjecthelper.keyword.list」の値を書き換えることで、キーワードの追加・削除を行う。
overlay.xulの修正
修正後のoverlay.xulは以下のような感じ。<?xml version="1.0"?> <overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/x-javascript" src="chrome://subjecthelper/content/subjectHelper.js"/> <textbox id="msgSubject"> <button popup="_child" type="menu" id="subject-helper-button" style="-moz-binding: url('chrome://subjecthelper/content/subjectHelper.xml#subjectHelper');"> <menupopup> <menuitem label="設定" accesskey="0" oncommand="SubjectHelper.setMenu();"/> </menupopup> </button> </textbox> </overlay>
Mozilla設定システムにキーワードを保持しているため、予めmenuitem要素で記述していた既存のキーワードを除去した。
そのかわりに、Mozilla設定システムのキーワードを操作するための関数をcommandイベントに付加したmenuitem要素を追加した。
subjectHelper.jsの修正
今回の実装では、SubjectHelperオブジェクトに以下の関数を追加した。・createMenu
・createMenuItem
・getKeywordList
・init
・setKeywordList
・setMenu
まず、取得したキーワードでメニューを新しく作成するcreateMenu。
createMenu: function( keywordList ) { const delimiter = ","; var button = document.getElementById( "subject-helper-button" ); var menu = button.firstChild; // メニューの削除 for( var index = menu.childNodes.length - 1; index >= 1; index-- ) { menu.removeChild( menu.childNodes[index] ); } // メニューの追加 var keywords = keywordList.split( delimiter ); for( index in keywords ) { // 前後の空白を削除 keywords[index] = keywords[index].replace( /^\s+|\s+$/g, "" ); if( keywords[index].length > 0 ) { var menuItem = this.createMenuItem( keywords[index] ); menu.appendChild( menuItem ); } } }
メニューの削除部分は、わざわざ後ろから順番に消去しているが、これはコードの可読性を考慮している。
これを前から順番に消していく処理にすると、
for( var index = 1; index <= menu.childNodes.length - 1; index++ ) { menu.removeChild( menu.childNodes[1] ); }
となり、一目ではmenu.childNodes[1]あたり何をしているかわかりにくい。
JavaScriptにあまり慣れていないせいかもしれないが、removeChildによるダルマ落とし的な削除では、forをインクリメントで回す場合、どうしてもこういう書き方になる。
インデックスが1の要素を消していくより、後ろから順に消していく方が、自分としてはわかりやすかったので、そうした。
次は、menuitem要素を作成するcreateMenuItem関数。
createMenuItem: function( keyword ) { var menuItem = document.createElement( "menuitem" ); menuItem.setAttribute( "label", keyword ); menuItem.setAttribute( "oncommand", "SubjectHelper.insert( this );" ); return menuItem; }
これは、名前のまんま、引数で与えられたキーワードをラベルとしてmenuitem要素を作成する。
次、getKeywordListはMozilla設定システムからキーワードを取得する関数で中身はこんな感じ。
getKeywordList: function() { var prefs = Components.classes["@mozilla.org/preferences-service;1"] .getService( Components.interfaces.nsIPrefService ); prefs = prefs.getBranch( "extensions.subjecthelper." ); var keywordList = prefs.getComplexValue( "keyword.list", Components.interfaces.nsISupportsString ).data; return keywordList; }
initは、メール作成画面起動時にメニューを作成するための関数。
init: function() { var keywordList = this.getKeywordList(); this.createMenu( keywordList ); }
setKeywordListは、Mozilla設定システムにキーワードを設定するための関数。
setKeywordList: function( keywordList ) { var prefs = Components.classes["@mozilla.org/preferences-service;1"] .getService( Components.interfaces.nsIPrefService ); prefs = prefs.getBranch( "extensions.subjecthelper." ); var str = Components.classes["@mozilla.org/supports-string;1"] .createInstance( Components.interfaces.nsISupportsString ); str.data = keywordList; prefs.setComplexValue( "keyword.list" , Components.interfaces.nsISupportsString, str ); }
setMenuは、メニューの「設定」を押した場合に、キーワードを入力するダイアログを表示させる関数。
setMenu: function() { var keywordList = this.getKeywordList(); keywordList = prompt( "プロジェクト名をカンマ区切りで設定", keywordList ); this.createMenu( keywordList ); this.setKeywordList( keywordList ); }
以上、6つの関数を追加した。
ソースをgithubに公開しようと思ったけど、フォークやらライセンスやら、わからないことがあるので、やめとく。
前よりは、コードをきれいにかけた気がする・・・気のせいかもしれない。
addEventListenerの引数の部分で、「function(){SubjectHelper.init();}」と書く場合と、「SubjectHelper.init」と書く場合で、挙動が違い、なぜ違うのかイマイチわからない。なんでだろ?
JavaScript難しい><