Как-то вечером, уходя с работы, наткнулся здесь на интересную статью. Так как я люблю читать печатный вариант, да и время было уже позднее — хотелось домой, но и хотелось прочесть — решил распечатать и почитать в дороге.
Ну и полез я печатать, браузер мне предложил распечатать более 35 страниц, но откуда там может быть 20 страниц? Дело в том что печать шла вместе со всеми элементами, что делает пост узким, соответственно длинным, та и еще и комментарии ту да же.
Начал искать другие варианты, на habrahabr я новенький, мог и не найти, но искал что то вроде версии для печати, так и не нашел, решил пойти другим путем, сохранил статью в evernote, и затем распечатать ее, страниц для печати уменьшилось, но не на много, та и комментарии остались, и еще текст был узким, в конце концов пришел к тому что нужно что то, что бы можно было в один клик распечатать статью с данного сайта.
Так родилось расширение для браузера Google Chrome — HabraPrint.
Все что от вас требуется нажать на одну кнопку и распечатать.
Это мое первое расширения, как и первый пост, надеюсь меня исправят там где я ошибся.
И так что мы имеем внутри:
Создаем папку с названием нашего расширения, куда будем сохранять последующие файлы.
Далее первым делом создаем файл manifest:
Здесь указываем браузеру, что он и с какими разрешениями ставит.
Указываем:
name — Имя расширения
version — текущая версия
description — описания вашего расширения
icons — указываем пути к иконкам расширения <key/размер>:<value/путь к изображению>
minimum_chrome_version-указываем минимальную версию браузера
permissions — здесь указываем к чему вам потребуется доступ
background_page — указываем путь к странице которая будет выполнятся в фоне
content_scripts — указываем пути к файлам которые будут внедрены в страницу
page_action — данное свойство указывает на то что кнопка расширения будет размещена в адресной строке браузера, указываем путь к иконке и название
options_page — путь к странице настроек
с подробным описанием файла можно ознакомится в документации
Данный файл является обязательным для каждого расширения, как и все файлы указанные в нем.
Теперь будем двигаться по списку.
Я разнес файлы относительно их типа по папкам для удобства использования.
Следующим файлом создаем background_page:
Как видите здесь имеется только каркас страницы, и подключение javascript скрипта который отвечает за действия в фоновом режиме
background.js
В данном файле вешаем обработчики события на создание, и обновление вкладок, проверяем url на наличие нашего домена и цифр (использую проверку для того что бытеоретически определить находится ли пользователь на странице с постом или нет), на основе чего отображаю или скрываю значок расширения. Таким образом расширение отображается теоретически только на странице с постом.
Далее вешаем обработчик на клик по кнопке нашего приложения и на основе настроек, нашего расширения выполняем действие.
В настройках можно выбрать печатать в том же окне или в всплывающем, но об этом позднее.
Так как вызов всплывающего окна мне разрешил выполнить только данный файл(background_page), здесь разместилась функция отвечающая за показ того самого окна.
Тут я укоротил немного функцию бы было нагляднее. Как видите используется обычный window.open и в него передается html со страницы с текстом поста. Для получения текста отправляем запрос, с названием действия, в content script, в ответ получаем innerHTML поста и записываем в окно wnd.document.write().
Далее напишем наш content script:
Здесь размещаем слушатель запросов, и при получении его выполняем действие указанное в параметрах.
Здесь всего два действия либо отдать html поста, предыдущему скрипту, либо выполнить функции, которая отвечает за выполнение печати. В данной функции использую стили для печати, то есть указываю стилями что выводить на печать а что скрыть.
И в конце напишем страницу настроек.
В options.html делаем каркас страницы
Здесь всего пару радио кнопок которые устанавливают режим печати и кнопка сохранения, стили указаны в css/options.css, здесь описывать не стану.
Итого вышла вот такая страница:
В файле options.js пишем javascript который будет отвечать за сохранение настроек.
Вешаем обработчик на клик кнопки сохранения и по нему заносим значение в объект localStorage.
localStorage является ассоциативным массивом хранящий пары «название», «значение». Для сохранения значения достаточно написать:
Вот, в принципе, и все осталось загрузить наше расширение в браузер.
Переходим на вкладку «Управление расширениями» (Инструменты->Расширения), включаем «Режим разработчика», и загружаем распакованное расширение.
Для того что бы воспользоваться расширениям, откройте любой пост на habrahabr и нажмите на появившейся иконке расширения, в адресной строке браузера.
Проблемы:
У себя заметил что при первой загрузке расширения, появляется ошибка что то вроде «Вам не разрешено использовать функции для tabs проверьте манифест», с чем это связанно я так и не разобрался, если что объяснит буду признателен.
Источники:
Google Chrome Extension FAQ
Создание расширения для Google Chrome
Расширение:
Скачать
P.S. К сожалению мои скудные познания в написании расширений не позволяют мне описать более детальнее процесс создания, но я надеюсь что кому то пригодится данное расширение.
Так же хотел бы услышать предложения, правки и замечания. Всем заранее спасибо.
UPD: по просьбе bo883, добавил подсветку синтаксиса, и добавил подложку под код (пока что работает только в «В всплывающем окне», в скором времени добавлю и при печати в том же окне). При реализации столкнулся с проблемой что фон, добавленный через css, не печатает Chrome, но зато прекрасно печатает картинки (<img ...>), основываясь на этом добавляем картинку к блоку с кодом устанавливаем ей ширину и высоту равную размерам блока кода, тем самим растягивая ее на весь блок, и меняем им z-index, что бы подложить под код картинки, в итоге при печати у нас область кода имеет подложку. (расширение обновил)
Ну и полез я печатать, браузер мне предложил распечатать более 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. К сожалению мои скудные познания в написании расширений не позволяют мне описать более детальнее процесс создания, но я надеюсь что кому то пригодится данное расширение.
Так же хотел бы услышать предложения, правки и замечания. Всем заранее спасибо.
UPD: по просьбе bo883, добавил подсветку синтаксиса, и добавил подложку под код (пока что работает только в «В всплывающем окне», в скором времени добавлю и при печати в том же окне). При реализации столкнулся с проблемой что фон, добавленный через css, не печатает Chrome, но зато прекрасно печатает картинки (<img ...>), основываясь на этом добавляем картинку к блоку с кодом устанавливаем ей ширину и высоту равную размерам блока кода, тем самим растягивая ее на весь блок, и меняем им z-index, что бы подложить под код картинки, в итоге при печати у нас область кода имеет подложку. (расширение обновил)