Как то вечером, уходя с работы, наткнулся здесь на интересную статью, так как я люблю читать печатный вариант, та и время было уже позднее, хотелось дамой но и хотелось прочесть, решил распечатать и почитать в дороге.
Ну и полез я печатать, браузер мне предложил распечатать более 35 страниц, но откуда там может быть 20 страниц? Дело в том что печать шла вместе со всеми элементами, что делает пост узким, соответственно длинным, та и еще и комментарии ту да же.
Начал искать другие варианты, на habrahabr я новенький, мог и не найти, но искал что то вроде версии для печати, так и не нашел, решил пойти другим путем, сохранил статью в evernote, и затем распечатать ее, страниц для печати уменьшилось, но не на много, та и комментарии остались, и еще текст был узким, в конце концов пришел к тому что нужно что то, что бы можно было в один клик распечатать статью с данного сайта.
Так родилось расширение для браузера Google Chrome — HabraPrint.
Все что от вас требуется нажать на одну кнопку и распечатать.
Это мое первое расширения, как и первый пост, надеюсь меня исправят там где я ошибся.
И так что мы имеем внутри:
Создаем папку с названием нашего расширения, куда будем сохранять последующие файлы.
Далее первым делом создаем файл manifest:
Здесь указываем браузеру, что он и с какими разрешениями ставит.
{ "name": "HabraPrint", "version": "0.1", "description": "Печать в один клик поста с сайта habrahabr.ru", "icons": { "128": "img/icon_128.png", "64": "img/icon_64.png", "48": "img/icon_48.png", "32": "img/icon_32.png", "16": "img/icon_16.png" }, "minimum_chrome_version":"6.0", "permissions": [ "tabs","http://habrahabr.ru/*", "https://habrahabr.ru/*"], "background_page": "background.html", "content_scripts": [ { "js": [ "js/jquery-1.7.1.min.js","js/content.js" ], "css": ["css/content.css"], "run_at": "document_end", "matches": [ "http://habrahabr.ru/*", "https://habrahabr.ru/*" ] } ], "page_action": { "default_icon": "img/icon_19.png", "default_title": "HabrPrint" }, "options_page": "options.html" }
Указываем:
name — Имя расширения
version — текущая версия
description — описания вашего расширения
icons — указываем пути к иконкам расширения <key/размер>:<value/путь к изображению>
minimum_chrome_version-указываем минимальную версию браузера
permissions — здесь указываем к чему вам потребуется доступ
background_page — указываем путь к странице которая будет выполнятся в фоне
content_scripts — указываем пути к файлам которые будут внедрены в страницу
page_action — данное свойство указывает на то что кнопка расширения будет размещена в адресной строке браузера, указываем путь к иконке и название
options_page — путь к странице настроек
с подробным описанием файла можно ознакомится в документации
Данный файл является обязательным для каждого расширения, как и все файлы указанные в нем.
Теперь будем двигаться по списку.
Я разнес файлы относительно их типа по папкам для удобства использования.
Следующим файлом создаем background_page:
<!DOCTYPE html> <html> <head> <script src="js/background.js"></script> </head> </html>
Как видите здесь имеется только каркас страницы, и подключение javascript скрипта который отвечает за действия в фоновом режиме
background.js
chrome.tabs.onCreated.addListener(function(tab){ urlDetected(tab.id, null, tab); }); chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab){ if(changeInfo.status=='complete'){ urlDetected(tabId, changeInfo, tab); } }); function urlDetected(tabId, changeInfo, tab){ chrome.tabs.getSelected(null,function(tab) { var re=/.+habrahabr.+/(d+)//; if(re.test(tab.url)){ chrome.pageAction.show(tabId); }else{ chrome.pageAction.hide(tabId); } }); } chrome.pageAction.onClicked.addListener(function(tabId) { //узнаем какие настройки и выполняем действия if(!localStorage["radio"]||localStorage["radio"]=='popup'){ PrintIt(); }else if(localStorage["radio"]=='same'){ chrome.tabs.getSelected(null, function(tab) { chrome.tabs.sendRequest(tab.id, { type:'print-same' }); }); } });
В данном файле вешаем обработчики события на создание, и обновление вкладок, проверяем url на наличие нашего домена и цифр (использую проверку для того что бы теоретически определить находится ли пользователь на странице с постом или нет), на основе чего отображаю или скрываю значок расширения. Таким образом расширение отображается теоретически только на странице с постом.
Далее вешаем обработчик на клик по кнопке нашего приложения и на основе настроек, нашего расширения выполняем действие.
В настройках можно выбрать печатать в том же окне или в всплывающем, но об этом позднее.
Так как вызов всплывающего окна мне разрешил выполнить только данный файл(background_page), здесь разместилась функция отвечающая за показ того самого окна.
function PrintIt(){ if(wnd){ wnd.close(); } stext=''; chrome.tabs.getSelected(null, function(tab) { chrome.tabs.sendRequest(tab.id, { type:'returnHtml' }, function(response) { stext=response.html; wnd=window.open("", "habrPrint", 'statusbar=no,toolbar=no,scrollbars=yes,resizable=yes''); wnd.document.write("<!DOCTYPE html> <html lang='ru'> <head> <meta content='text/html; charset=utf-8' http-equiv='Content-Type'> <meta content='ru' name='language'> <title>"+response.title+"</title> <link href="/css/print.css"rel="stylesheet"type="text/css" media="all"/></style> </head> <body onclick="window.close()"> <div class='post'>"); wnd.document.write(stext); wnd.document.write("</div><body></html>"); wnd.document.close(); setTimeout(function(){ wnd.print(); wnd.close(); }, 100) }); }); }
Тут я укоротил немного функцию бы было нагляднее. Как видите используется обычный window.open и в него передается html со страницы с текстом поста. Для получения текста отправляем запрос, с названием действия, в content script, в ответ получаем innerHTML поста и записываем в окно wnd.document.write().
Далее напишем наш content script:
var getElementsByClassName = function(getClass){ if(document.querySelectorAll) { return document.querySelectorAll("." + getClass); } else if(document.getElementsByClassName) { return document.getElementsByClassName(getClass); } else { var list = document.getElementsByTagName('*'), i = list.length, classArray = getClass.split(/s+/), result = []; while(i--) { if(list[i].className.search('\b' + classArray + '\b') != -1) { result.push(list[i]); } } return result; } }; function pageCleaner(){ $('body *').removeClass('habrNoPrint').removeClass('habrPrint'); } function printSame(){ $('body *').addClass('habrNoPrint'); $('#layout, .content_left, .company_post, .post, .post *').removeClass('habrNoPrint'); $('.content_left').addClass('habrPrint'); window.print(); window.setTimeout(pageCleaner, 0); } chrome.extension.onRequest.addListener(function(request, sender, sendResponse) { if(request.type == 'print-same'){ printSame(); } if(request.type == 'returnHtml'){ var elem=getElementsByClassName('post')[0]; var title=document.getElementsByTagName('title')[0]; sendResponse({'html':elem.innerHTML,'title':title.innerHTML}); } });
Здесь размещаем слушатель запросов, и при получении его выполняем действие указанное в параметрах.
Здесь всего два действия либо отдать html поста, предыдущему скрипту, либо выполнить функции, которая отвечает за выполнение печати. В данной функции использую стили для печати, то есть указываю стилями что выводить на печать а что скрыть.
И в конце напишем страницу настроек.
В options.html делаем каркас страницы
<!DOCTYPE html> <html lang='ru' xml:lang='ru' xmlns='http://www.w3.org/1999/xhtml'> <head> <meta content='text/html; charset=utf-8' http-equiv='Content-Type'> <meta content='ru' name='language'> <style>@import "css/options.css";</style> <script src="js/options.js"></script> </head> <body> <header> <h3>Настройки:</h3><span id="options_callback"></span> </header> <div id='habrPrint_options'> <form name="habr_options_form"> <div class='options_form'> <div> <input id="radio_popup" type="radio" name="window" value='popup' checked="checked"/> <label id="append-label">В сплывающем окне</label> <p>Данный режим открывает всплывающее окно с печатью страницы</p> </div> <div> <input id="radio_same" type="radio" name="window" value='same' /> <label id="append-label">В том же окне</label> <p>Данный режим работает с ограничение, браузер ограничивает количество вызовов, не более одного вызова раза в 5-ть секунд</p> </div> </div> </form> <div class="button"> <div class="button_blue"> <button id="save">Сохранить</button> </div> </div> </div> </body> </html>
Здесь всего пару радио кнопок которые устанавливают режим печати и кнопка сохранения, стили указаны в css/options.css, здесь описывать не стану.
Итого вышла вот такая страница:
В файле options.js пишем javascript который будет отвечать за сохранение настроек.
function getRadioGroupValue(radioGroupObj) { for (var i=0; i < radioGroupObj.length; i++) if (radioGroupObj[i].checked) return radioGroupObj[i].value; return null; } function readProperty(property, defValue) { if(localStorage[property] == null) { return defValue; } return localStorage[property]; } window.addEventListener("load", function(){ chrome.tabs.getSelected(null, function(tab) { var save = document.getElementById("save"); if(localStorage["radio"]){ document.getElementById("radio_"+localStorage["radio"]).checked =readProperty("radio", false); } save.addEventListener("click", function(){ var radio_value = getRadioGroupValue(document.habr_options_form.window); localStorage["radio"] = radio_value; if(localStorage["radio"]){ var sum=document.getElementById('options_callback'); sum.innerHTML='Настройки сохранены' } }); }); });
Вешаем обработчик на клик кнопки сохранения и по нему заносим значение в объект localStorage.
localStorage является ассоциативным массивом хранящий пары «название», «значение». Для сохранения значения достаточно написать:
localStorage["radio"] = radio_value;
Вот, в принципе, и все осталось загрузить наше расширение в браузер.
Переходим на вкладку «Управление расширениями» (Инструменты->Расширения), включаем «Режим разработчика», и загружаем распакованное расширение.
Для того что бы воспользоваться расширениям, откройте любой пост на habrahabr и нажмите на появившейся иконке расширения, в адресной строке браузера.
Проблемы:
У себя заметил что при первой загрузке расширения, появляется ошибка что то вроде «Вам не разрешено использовать функции для tabs проверьте манифест», с чем это связанно я так и не разобрался, если что объяснит буду признателен.
Источники:
Google Chrome Extension FAQ
Создание расширения для Google Chrome
Расширение:
Скачать
P.S. К сожалению мои скудные познания в написании расширений не позволяют мне описать более детальнее процесс создания, но я надеюсь что кому то пригодится данное расширение.
Так же хотел бы услышать предложения, правки и замечания. Всем заранее спасибо.
Автор: Bookin