こんにちは、
Extensionsの開発の下準備
まずは開発環境を整理します。といっても、
ただ、
[パス省略]\chrome.exe --user-data-dir="C:\chrome_profile\test1"
このようにして、
また、
起動オプションは不要に
Extensionsを開発/
開発関連以外でも、
Extensionsのひな形とmanifest
まず、
{
"name": "sample",
"description": "Google Chrome Sample Extension",
"version": "0.0.0.1",
"permissions": [
"http://*/*",
"https://*/*",
"tabs"
],
"update_url": "http://example.com/updates.xml",
"options_page": "options_page.html",
"background_page": "background.html",
"chrome_url_overrides": {
"newtab": "newtab.html"
},
"icons": {
"16": "icon16.png",
"32": "icon32.png",
"64": "icon64.png",
"128": "icon128.png"
},
"content_scripts": [
{
"js": [
"sample.js"
],
"css": [
"sample.css"
],
"matches": [
"http://*/*"
]
}
],
"page_action": {
"default_icon": "icon16.png",
"default_title": "Sample",
"popup": "popup.html"
}
}
nameとdescriptionはそのままExtensionの名前と説明です。versionはドット区切りの数字で、
permissionsは拡張のアクセス権限を決定します。クロスオリジン通信を行う場合はアクセス先のオリジンを、
update_
options_
iconsはインストール時や拡張の一覧ページなどで使用されるアイコンを指定できます。サイズは16px、
content_
page_
manifest.
Extensionsの開発手順
では実際にmanifest.
{
"name": "SBM Counter",
"description": "Social Bookmark Counter Extension",
"version": "4.2.1",
"permissions": [
"tabs",
"http://*/",
"https://*/"
],
"update_url": "http://ss-o.net/chrome_extension/sbm_counter/updates.xml",
"options_page": "options_page.html",
"background_page": "background.html",
"icons": {
"128": "sbm_icon_128.png",
"64": "sbm_icon_64.png",
"32": "sbm_icon_32.png",
"16": "sbm_icon.png"
},
"browser_action": {
"default_icon": "sbm_icon.png",
"default_title": "SBM Counter",
"popup" : "popup.html"
}
}
Tabs APIとexecuteScriptをすべてのサイトで使用するので、
このmanifestに対応したHTML、
Background Page
では、
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="Services.js"></script>
<script type="text/javascript" src="md5.js"></script>
<script type="text/javascript" src="background.js"></script>
</head>
<body>
</body>
</html>
DOCTYPEやhtml要素などを省略せずに書きましたが、
scriptはサービスの定義を記述したServices.
このbackground.
var SBMConf = {
disable_sites:[
"^http://localhost(:\\d+)?/",
"^https://",
"^http://b\\.hatena\\.ne\\.jp/entry"
],
isInlineCount:true,
usageServiceConfig:[
{id:'hatena', enable:true},
{id:'delicious', enable:true}
]
}
if (!localStorage.disable_sites) {
localStorage.disable_sites = JSON.stringify(SBMConf.disable_sites);
} else {
SBMConf.disable_sites = JSON.parse(localStorage.disable_sites);
}
if (!localStorage.isInlineCount) {
localStorage.isInlineCount = Boolean(SBMConf.isInlineCount);
} else {
SBMConf.isInlineCount = Boolean(localStorage.isInlineCount);
}
if (!localStorage.usageServiceConfig) {
localStorage.usageServiceConfig = JSON.stringify(SBMConf.usageServiceConfig);
} else {
SBMConf.usageServiceConfig = JSON.parse(localStorage.usageServiceConfig);
}
SBMConf.usageServiceConfig.forEach(function(opt){
Services[opt.id].enable = opt.enable;
});
最初のSBMConfはインストール直後用のデフォルトの設定です。localStorageに値が存在すればその値をJSON.
最後のusageServiceConfigの処理は、
function SBM(tab){
if (tab) {
this.init(tab);
}
}
SBM.prototype = {
init:function _sbm_init(tab){
var tabid = tab.id, url = tab.url;
this.count = 0;
this.title = new Array(Services.length);
this.tabid = tabid;
this.title = tab.title;
this.url = url.replace('#','%23');
this.encoded_url = encodeURIComponent(url);
Services.forEach(function(service, index){
this.request(service, index);
},this);
},
request:function _sbm_request(service, index){
if (!service.enable) return;
var self = this, xhr = new XMLHttpRequest();
var api_url = fill(service.api_get, this);
xhr.open('GET', api_url, true);
xhr.onload = function(){
var count = service.responceFilter(xhr.responseText);
self.update(count,service,index);
};
xhr.send();
},
update:function _sbm_update(count, service, i){
this.count += parseInt(count, 10) || 0;
this.title[i] = count + ' count(' + service.name + ')';
chrome.browserAction.setBadgeText({
tabId:this.tabid,
text:this.count
});
chrome.browserAction.setTitle({
tabId:this.tabid,
title:this.title.join('\n')
});
}
};
続いて、
chrome.tabs.onUpdated.addListener(function(tabid, inf){
if (inf && inf.status === 'loading') {
chrome.tabs.get(tabid, function(tab){
if (!site_check(tab.url)) {
new SBM(tab);
}
});
}
});
function site_check(url){
if (url.indexOf('http') !== 0 || url.length > 255) return true;
return SBMConf.disable_sites.some(function(site){
return new RegExp(site).test(url);
});
}
仕上げにchrome.
Options Page
オプションページは chrome://
BrowserActionのPopup
Popupもやはり基本はHTMLですが、
さて、
var BackGround = chrome.extension.getBackgroundPage();
var log = BackGround.console;
var SBMConf = BackGround.SBMConf;
function PSBM(tab){
if (tab) {
this.init(tab);
}
}
PSBM.prototype = new BackGround.SBM();
var _request = PSBM.prototype.request;
PSBM.prototype.request = function(service, index){
if (service.enable) {
_request.call(this, service, index);
} else {
document.querySelector('#sbm_' + service.id).style.display = 'none';
}
};
PSBM.prototype.update = function(count, service, index){
document.querySelector('#add_' + service.id).href = fill(service.api_add, this, service);
var link = document.querySelector('#text_' + service.id);
link.href = fill(service.api_link, this, service);
link.textContent = count;
};
BackgroundPageのSBMクラスは引数に何も渡さなければinitメソッドを呼ばないようにしてあるので、
PSBMクラスでは継承元のrequestの前に無効なサービスであればその表示を隠す処理を入れ、
chrome.tabs.getSelected(null,function(tab){
if (BackGround.site_check(tab.url)) {
window.close();
return;
}
new PSBM(tab, BackGround.Services);
});
後はpopupがクリックされた際のタブを取得して、
まとめ
現在のSBMカウンタのすべてを説明したわけではありませんが、
次回はまだ紹介していないAPI