Chrome Extension - 初探與實作 No MailTo

Introduction

在 HTML 的 anchor 中,我們可以在 href 屬性中加入 mailto 讓使用者點擊連結時自動開啟 Mail Agent(例如 Outlook),但對於不常使用的人來說,這常常使得使用者誤觸而相當惱人。因此在本篇文章中,我們將實作一個 Chrome 擴充元件,令使用者點擊到 mailto 連結時,改為複製電子郵件位置而不打開 Mail Agent。

Implementation

在實作前,我們先定義擴充元件的功能與流程:

  1. 尋遍網頁中的 anchor 標籤,並挑出 hrefmailto 開頭的。
  2. 當使用者按下 anchor 標籤後,會複製 Email Address 內容至剪貼簿中。
  3. 跳出 Tooltip 提示使用者已經複製 Email Address 至剪貼簿。

Script Content

Get Mailto Address

首先我們先觀察一個簡單的 mailto 的連結:

1
<a href="mailto:[email protected]">Send mail to [email protected]</a>

會發現到我們只需要將 href 屬性取出來,並將前面的 mailto: 去除掉即可:

1
2
3
4
5
6
$('a').each(function () {
const href = String($(this).attr('href')).trim();
if (typeof href !== 'undefined' && href.indexOf('mailto:') == 0) {
console.log(href.substr(href.indexOf(':') + 1).trim());
}
});

Copy to Clipboard

在以前,我們為了要做出點選自動複製(ZeroClipboard)得更能,通常是使用 Flash,繞過瀏覽器安全性限制,將網頁元素內容複製到剪貼簿。但由於 Flash 的安全性導致其在近年逐漸遭到瀏覽器捨棄,因此我們使用 Clipboard.js,純粹使用 JavaScript 便可以將內容複製到剪貼簿中。

Clipboard.js 的使用非常簡單,也提供了成功與失敗的事件,而取消選取的部分亦可以寫進成功的事件中,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- 引入 Clipboard.js -->
<script type="text/javascript" src="clipboard.min.js"></script>

<!-- HTML -->
<button id="copy-btn" data-clipboard-action="cut" data-clipboard-target="#data">
Click to Copy
</button>
<textarea id="data">
Here is data.
</textarea>

<!-- Script -->
<script type="text/javascript">
const clipboard = new ClipboardJS('#copy-btn');
clipboard.on('success', function(e) {
console.info('Action:', e.action);
console.info('Text:', e.text);
console.info('Trigger:', e.trigger);

/* Clear Selected */
e.clearSelection();
});
clipboard.on('error', function(e) {
console.error('Action:', e.action);
console.error('Trigger:', e.trigger);
});
</script>

Tooltip

雖然我們可以用簡單的 alert('Copied!') 來通知使用者已複製內容,但這樣的做法在呈現上顯得粗糙,為了美觀我們採用 popper.jstippy.js 來完成需求。

Build Chrome Extension

擴充元件 No Mailto 的檔案結構如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
./no-mailto                         (DIR)
├── _locales (DIR)
│ ├── en (DIR)
│ │ └── messages.json (FILE | json file)
│ └── zh_TW (DIR)
│ └── messages.json (FILE | json file)
├── clipboard.min.js.css (FILE | javascript file)
├── content.js (FILE | javascript file)
├── favicon-16x16.png (FILE | extension icon)
├── favicon-32x32.png (FILE | extension icon)
├── favicon-48x48.png (FILE | extension icon)
├── favicon-64x64.png (FILE | extension icon)
├── favicon-128x128.png (FILE | extension icon)
├── jquery.min.js (FILE | javascript file)
├── manifest.json (FILE | extension important information)
├── popper.min.js (FILE | javascript file)
├── tippy.min.css (FILE | css file)
├── tippy.min.js (FILE | javascript file)
└── tooltip.js (FILE | javascript file)

由於實作了多語系,因此會在目錄中多一個 _locales 的資料夾。關於多語系的說明可以參考官方文件,在此就不多做贅述。

Manifest Fire Format

任何擴充元件中都必須存在 manifest.json 檔案,用來提供重要資訊。關於 manifest.json 詳細資訊可以參考官方文件,在此就不多做贅述。

而 No Mailto 的 manifest.json 內容為:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
/* ===== 以下資訊必填 ===== */
"manifest_version": 2, /* manifest_version 版本 */
"name": "No MailTo", /* 擴充元件名稱 */
"version": "1.0", /* 擴充元件版本 */

/* ===== 以下資訊建議填寫 ===== */
"default_locale": "en", /* 擴充元件預設語系 */
/* 擴充元件說明 */
"description": "__MSG_app_description__",
"icons": { /* 擴充元件圖示 */
"16": "favicon-16x16.png",
"32": "favicon-32x32.png",
"48": "favicon-48x48.png",
"64": "favicon-64x64.png",
"128": "favicon-128x128.png"
},

/* ===== 以下資訊選填 ===== */
"browser_action": {
"default_title": "No MailTo", /* 瀏覽器上擴充元件的 ToolTip Title */
"default_icon": { /* 瀏覽器上擴充元件預設的圖示 */
"16": "favicon-16x16.png",
"32": "favicon-32x32.png",
"48": "favicon-48x48.png",
"64": "favicon-64x64.png",
"128": "favicon-128x128.png"
}
},
"content_scripts": [
{
"matches": [ "<all_urls>" ], /* 擴充元件適用的網址 */
"css": [
"tippy.min.css" /* 擴充元件使用者 CSS 樣式列表 */
],
"js": [
"jquery.min.js", /* 擴充元件使用者 JavaScript 程式碼 */
"clipboard.min.js", /* 擴充元件使用者 JavaScript 程式碼 */
"popper.min.js", /* 擴充元件使用者 JavaScript 程式碼 */
"tippy.min.js", /* 擴充元件使用者 JavaScript 程式碼 */
"tooltip.js", /* 擴充元件使用者 JavaScript 程式碼 */
"content.js" /* 擴充元件使用者 JavaScript 程式碼 */
]
}
],
"permissions": [ "activeTab" ], /* 擴充元件所使用的權限 */
"short_name": "No MailTo" /* 擴充元件的簡稱 */
}

Test Chrome Extension

在完成 No MailTo 的建構後,可以擴充元件中載入未封裝的擴充元件功能來先行測試:

  1. 開啟 Google Chrome。
  2. 開啟新頁面並進入網址 chrome://extensions/
  3. 按下 Load unpacked 並選擇 No MailTo 的資料夾
  4. 若未出現任何錯誤訊息,表示擴充元件已載入,可以立即開始測試。若出現錯誤訊息,則依照錯誤訊息提示修正。

Pack Extension

在測試完成後,可以從:

  1. 開啟 Google Chrome。
  2. 開啟新頁面並進入網址 chrome://extensions/
  3. 按下 Pack extension 將 AppleDaily Viewer 進行封裝。

封裝完畢後便可以將擴充元件散布出去。當然較正確的做法是將擴充元件上架至 Chrome 線上應用程式商店

Publish Chrome Extension

上架至 Chrome 線上應用程式商店除了程式碼之外,還需要準備:

  1. 5 元美金的一次性付費(可上傳 20 個 Extension)
  2. 擴充元件的詳細說明
  3. 擴充元件所使用的 Icon 檔案(96x96 in 128x128)
  4. 440x280 的小型宣傳圖塊(JPEG 或 24 位元 PNG,無 alpha 透明層)
  5. 螢幕擷取畫面(1280x800 或 640x400,JPEG 或 24 位元 PNG,無 alpha 透明層)

若是想宣傳擴充元件,建議產品詳細資訊內所有資料都要上傳,盡量越詳細越好。

若是未來要更新擴充元件,請記得在 manifest.json 中將 version 加一(不是 manifest_version)。

最後需要特別注意的是,上架後的產品是不能移除的,只能下架不讓其顯示在線上應用程式商店中,但仍然會占用 20 個 Extension 的的額度。

References