Sharing knowledge

by Oleg Atamanenko

Расширение Delicious Bookmarks для Google Chrome/Chromium

Введение


Решил научиться писать собственные расширения для Google Chrome/Chromium.

За идею взял официальное расширение от Yahoo! для Firefox - Delicious Bookmarks.

Структура расширения


Расширение - файл с расширением .crx. На самом деле это просто ZIP-архив с файлом манифеста внутри.

Файл манифеста

{
“name”: “Delicious plugin”, // 1
“version”: “0.2”, // 2
“background_page”: “background.html”, // 3
“permissions”: [ // 4
“bookmarks”,
“tabs”
],

“browser_action”: { // 5 “name”: “Save bookmark to delicious.com”, “default_title”: “Save bookmark to delicious.com”, “default_icon”: “delicious.20.gif” // optional },

“content_scripts”: [ // 6 { “matches”: [“http:///”, “https:///”], “js”: [“getDocumentSelection.js”] } ],

“options_page”: “options.html” // 7 }


Манифест - файл в формате JSON.

Манифест состоит из следующих частей:

1. name - Имя расширения
2. version - Версия расширения
3. background_page - основной файл с расширением. Это обычный HTML-файл с разметкой.
4. permissions - разрешения для расширения. Указываем, что нам нужен доступ к вкладкам (tabs) и закладкам (bookmarks).
5. browser_action - указываем, что нужно отобразить на панели инструментов браузера.
6. content_scripts - Для доступа к DOM отображаемой страницы необходимы content scripts, данный блок регистрирует скрипт getDocumentSelection.js для всех http и https страниц.
7. options_page - страница с настройками.

Подробное описание файла манифеста есть на официальном сайте.

Описание работы расширения



Расширение работает следующим образом:
1. При клике на значок расширения вызывается обработчик addBookmark
2. Обработчик открывает коммуникационный порт и отправляет сообщение скрипту содержимого.
3. Скрипт содержимого забирает выделенный текст и отправляет назад расширению выделенный текст.
4. Расширение забирает выделенный текст, определяет настройки сохранения (Private/Public) и вызывает окно сохранения Delicious.

Реализация расширения



background.html:
<html>
<head>
<script type="text/javascript">
    function saveBookmark() {
        // Send our password to the current tab when clicked.
        chrome.tabs.getSelected(null, function(tab) {
            var port = chrome.tabs.connect(tab.id, {
                name : "deliciousBookmark"
            });
            port.postMessage( {
                action : ‘getSelection’
            });
        });
    }

    function addBookmark(id, bookmark) {         console.log("added bookmark:  " + bookmark);         saveBookmark();     }

    chrome.bookmarks.onCreated.addListener(addBookmark);     console.log("Registered listener");

    function getShareStatus() {         var markPrivate = localStorage["markPrivate"];         var share = "yes";         if (markPrivate == "true") {             share = "no";         }         return share;     }

    chrome.extension.onConnect.addListener(function(port) {         console.assert(port.name == "deliciousBookmark");         port.onMessage.addListener(function(msg) {             var selection = msg.selection;             chrome.tabs.getSelected(null, function(tab) {

                var url = encodeURIComponent(tab.url);

                if (!url || url === "") {                     return;                 }

                var title = encodeURIComponent(tab.title);                 var description = encodeURIComponent(selection);

                var share = getShareStatus();

                var f = ‘http://delicious.com/save?url=' + url + '&title=' + title + '&notes=' + description                         + ‘&share=’ + share + ‘&v=5&’;                 window.open(f + ‘noui=1&jump=doclose’, ‘deliciousuiv5’,                         ‘location=yes,links=no,scrollbars=no,toolbar=no,width=550,height=550’);

            });         });     });

    chrome.browserAction.onClicked.addListener(saveBookmark); </script> </head> </html>



getDocumentSelection.js

var port = chrome.extension.connect( {
name : “deliciousBookmark”
});

// Also listen for new channels from the extension for when the button is // pressed. chrome.extension.onConnect.addListener(function(port) { console.assert(port.name == “deliciousBookmark”); port.onMessage.addListener(function(msg) { if (msg.action == ‘getSelection’) { var responsePort = chrome.extension.connect( { name : “deliciousBookmark” }); var description = document.getSelection() ? “ + document.getSelection() : “; responsePort.postMessage( { selection : description }); } }); });



options.html

<html>
<html>
<head>
<title>Delicious Bookmarks Options</title>
</head>
<script type="text/javascript">
    // Saves options to localStorage.
    function saveOptions() {
        var share = document.getElementById("share");
        localStorage["markPrivate"] = share.checked;

    // Update status to let user know options were saved.
    var status = document.getElementById(&quot;status&quot;);
    status.innerHTML = &quot;Options Saved.&quot;;
    setTimeout(function() {
        status.innerHTML = &quot;&quot;;
    }, 1500);
}

// Restores select box state to saved value from localStorage.
function restoreOptions() {
    var share = localStorage[&quot;markPrivate&quot;];

    if (!share) {
        return;
    }
    var shareCheckbox = document.getElementById(&quot;share&quot;);

    shareCheckbox.checked = share;

}

</script>

<body onload="restoreOptions()">

<label for="share">Mark as Private</label> <input type="checkbox" class="checkbox" name="share" id="share" />

<br> <button onclick="saveOptions();">Save</button> <div id="status">&nbsp;</div> </body> </html>



Сборка расширения


В Chromium есть возможность собрать расширение.
1. Открываем адрес chrome://extensions/
2. В правом верхнем углу нажимаем Developer Mode.
3. На появившейся панели инструментов кликаем Pack Extension
4. Выбираем каталог, в котором находится расширение
5. Chromium автоматически собирает расширение в каталоге с исходниками расширения.

Заключение


Писать расширения для Google Chrome не просто, а очень просто.

Готовое и собранное расширение можно скачать здесь.

Дополнительная информация


  1. Google Chrome Extensions Developer’s Guide
  2. Manifest file description
  3. Chrome Extensions API
  4. Extension Packaging


В следующей заметке опишу работу messaging для коммуникации расширения со скриптами содержимого.