На чем пишут расширения для браузера. Пишем расширение для браузера Google Chrome. Давайте же внесём свой вклад в развитие web

Все элементы в магазине Chrome Web Store делятся на приложения и расширения. Мы сделаем и то, и другое. Созданное нами приложение будет отображаться в виде значка на новой вкладке браузера и даст возможность быстро запустить ваш сайт. Расширение представляет собой специальную кнопку на панели инструментов, щелчок по которой вызовет появление панели с последними обновлениями сайта.

Собираем приложение для Google Chrome

1. Скачиваем архив с шаблоном расширения по этой ссылке .

2. Разархивируем в любое удобное вам место. Внутри находится файл manifest.json и иконка icon.png .

3. Открываем файл manifest.json в блокноте и редактируем его содержимое. Вам необходимо в строке 2 ввести имя своего сайта, в строке 3 — его описание (до 132 символов), в строке 5 и 7 — адрес сайта. Сохраняем сделанные изменения.

4. Меняем иконку из архива на свое изображение в формате PNG, размером 128*128.

Собираем расширение для Google Chrome

Хотя расширение функционально существенно отличается от приложения, алгоритм его сборки не намного сложнее.

1. Получаем заготовку расширения по этой ссылке .

2. Разархивируем. Открываем в блокноте файл manifest.json и вставляем название своего сайта, его краткое описание и заголовок окна расширения (строки 2, 3 и 8).

3. Открываем файл labnol.js и указываем адрес RSS потока своего сайта.

4. Заменяем иконку из архива на свое изображение в формате PNG размером 128*128.

Публикация

Сделанные нами расширение и приложение можно использовать двумя способами. Если вы владелец сайта и хотите привлечь на него дополнительных пользователей, то можно опубликовать свои работы в Chrome Web Store. Для этого запаковываем файлы расширения и дополнения каждое в свой архив, идем на страницу Chrome Dashboard и загружаем свои работы в магазин Google. Здесь вас попросят загрузить скриншот, дать расширенное описание и указать некоторые другие параметры. Страница на русском языке, так что вы без труда разберетесь. Обратите только внимание, что для публикации расширения вы должны быть подтвержденным владельцем сайта, для которого сделали расширение. Кроме этого, от вас потребуется вступительный взнос в размере 5$ за публикацию.

Если вы собрали расширения только для личного использования, например чтобы удобно следить за обновлениями любимого сайта, то просто откройте в браузере страницу расширений и включите Режим разработчика. Затем нажмите кнопку Загрузить распакованное расширение и укажите путь к папке с файлами.

С помощью предложенного метода любой владелец сайта или блога сможет создать и разместить в каталоге расширений браузера Google Chrome фирменное расширение для своего ресурса. Это поможет посетителям быть всегда в курсе последних обновлений, что приведет дополнительных посетителей на ваш сайт и увеличит его популярность.

Наиболее авторитетные люди в этой области - Wladimir Palant (он написал AdBlock Plus), ... Расширения для Chrome писать проще, чем для Firefox . Что интересно, самое популярное расширение для Chrome - это "Тюряга ВКонтакте" (по статистике Яндекса).

Задача состоит в разработке расширения, которое будет реагировать на открытие определенных HTML-страниц в браузере. Например, модифицировать HTML-код страницы сайта для более удобного использования этого сайта.
Решение опробовано на Google Chrome 24.x и Chromium 6.x (Debian 6.0.6, amd64).

Решение задачи

Конспект основных вопросов, возникающих по ходу написания crx-расширения.

  • Как оформить расширение?
  • Как установить таймер?
  • Как оформить расширение?

    Для минимального расширения достаточно 4-х файлов:

    128.png background.js content.js manifest.json

    Где manifest.json:

    { "manifest_version": 2, "name": "DomainCheck extension", "version": "0.1", "background": { "scripts": ["background.js"] }, "content_scripts": [ { "matches": [ "*://*/*" ], "js": [ "content..png" } // no web_accessible_resources }

    Файл background.js содержит код, исполняемый при старте браузера. В этом скрипте можно "повесить" обработчик загрузки контента документа (document.location.href).

    Chrome самостоятельно генерирует _generated_background_page.html:

    Для взаимодействия между background.js и content script, можно использовать сообщения (request/message) и chrome.extension.getBackgroundPage(). См. также описание архитектуры расширений Chrome (the architecture overview). Там сказано, что "A content script is some JavaScript that executes in the context of a page that"s been loaded into the browser".

    Примечание: в Chromium сложно отлаживать background page (background.js), так как нет соотв. вкладки на странице "Extensions" в developer mode.

    Как проверять текущий URL, обрезать его и вычислять хэш?

    Как устанавливать обработчик на DOMContentLoaded, рассказано на developer.chrome.com. См. также документацию про Background Pages (background.js).

    Для внедрения HTML-кода в страницу, можно использовать совет из статьи на Хабре (см. там упоминание глобальной переменной document), но нам нужно ещё и сравнивать текущий URL со списком.

    Is document.location.href deprecated?

    Пример со stackoverflow.com получения полного имени домена:

    var url = "http://www.domain.ru/tmp/file.txt?abc=1&cde=2#123" var getLocation = function(href) { var l = document.createElement("a"); l.href = href; return l; }; var l = getLocation(url); alert(l.hostname)

    Выделить поддомен 2-го уровня можно так:

    var l = getLocation(url); var d = l.hostname; function cutd(str) { var re = /.*?\.([\w\d-\u0100-\uffff-\.]+\.[\w\d-\u0100-\uffff-\.]+)/; return str.replace(re,"$1"); } alert(cutd(d));

    (см. подсказку на stackoverflow.com).

    sha1.js injection ...

    Как установить таймер? См. Sample Extensions: Event Page Example, background.js:

    chrome.alarms.create({delayInMinutes: 0.1}); chrome.alarms.onAlarm.addListener(function() { alert("Time"s up!"); });

    Этот баг в Chromium закрыт 9 января 2013 года, но ещё не появился в свежих сборках для Windows.

    Если всё-же решили использовать "современный" alarms, то как правильно устанавливать alarm-таймер произвольной длительности/периода, рассказано на stackoverflow.com.

    Для совместимости со старыми браузерами, лучше использовать window.setInterval() в background.js:

    var i = 0; window.setInterval(function() { alert(i); i++ }, 2*1000); // in milliseconds

    Функция setTimeout() - это одиночный "будильник".

    Disable-Enable chrome-расширения запускает по-новой background.js. *) надо проверить тоже самое для ухода в режим? и sleep.

    Как скачивать config.xml/time.txt, и как их парсить?

    Если скачать просто через XMLHttpRequest, то может вывалиться сообщение: "XMLHttpRequest cannot load http://сайт/config.xml. Origin http://www.google.ru is not allowed by Access-Control-Allow-Origin.". Это означает, что выполняя кросс-доменный запрос, вы не включили опцию для CORS, .htaccess:

    Header set Access-Control-Allow-Origin "*"

    Можно разрешить кросс-доменные запросы в расширении Chrome и через permissions в manifest.json:

    { "manifest_version": 2, ... "permissions": [ "http://сайт/" ],

    Впрочем, оба этих случая не работают для распакованных расширений Chromium . Для запакованных расширений, Chromium версий 6.0-7.0 иногда выдаёт "Bad magic number" (для чистого Chrome такая ошибка не наблюдается).
    Примечание: защиту CORS можно обойти в Chromium через опцию --disable-web-security:

    $ chromium-browser --disable-web-security http://domain/path

    Дополнение: для Chromium нужно подравить строки в manifest.json на следующие (указав явно домен и добавив звёздочку в пути):

    { "permissions": [ "http://сайт/*" ],

    Чтобы web inspector(?) в chrome не ругался при отключенном Интернете на XMLHttpRequest(), можно сделать так:

    var req = null; try { req = new XMLHttpRequest(); } catch(err) {} // see advice at stackoverflow.com

    (это написано по совету со stackoverflow.com). ...

    Для отладки парсинга, можно использовать console.log("строка"). Строки допускают переводы каретки с помощью "\n".

    Парсинг XML на JavaScript в chrome extension делается так:

    var xml = req.responseXML.documentElement; var ts = xml.getElementsByTagName("timeout"); var timeout = ts.textContent; if (ts) {console.log("timeout="+timeout);} var ds = xml.getElementsByTagName("domain"); if (ds) { for (var i = 0; i < ds.length; i++) { console.log("domain: "+ds[i].textContent); } }

    Как использовать глобальные атомарные переменные и табличные данные в chrome extension?

    Чтобы синхронизировать данные расширений при помощи Storage API, нужен Chrome версии >= 20. В манифесте (manifest.json) нужно написать следующее:

    "premissions": [ "storage" ]

    Как пишут в google group "Chromium HTML5", "I turned my attention to Web SQL Database but it seems Web SQL is no longer in "active maintenance" which leads me to believe that it will be dropped from HTML spec". См. подробнее W3C Web SQL Database, note. Можно попробовать использовать Basic concepts - для расширения места под базу можно использовать permissions: unlimitedStorage в manifest.json. Для использования "Unlimited storage" есть следующие Offline APIs: 1) App Cache; 2) File System; 3) IndexedDB; 4) WebSQL (deprecated). Пример использования IndexedDB в Chrome см. . Пример работы с IndexedDB см. на gist.github.com:

    window.indexedDB = window.indexedDB || window.webkitIndexedDB; var req = indexedDB.open("my db") req.onerror = function() { console.log("error"); }

    Расположение файлов IndexedDB,
    Windows: C:\Users\\AppData\Local\Google\Chrome\User Data\Default\IndexedDB,
    Linux: /home//.config/google-chrome/Default/IndexedDB/chrome-xxx.indexeddb.leveldb/:

    $ sudo ls -la /home/anonymous/.config/google-chrome/Default/IndexedDB/chrome-extension_ojeihbjghbabiocoglbfhdebhhckdnol_0.indexeddb.leveldb/ total 24 drwx------ 2 anonymous anonymous 4096 Фев 7 03:08 . drwx------ 3 anonymous anonymous 4096 Фев 7 03:08 .. -rw-r--r-- 1 anonymous anonymous 285 Фев 7 03:08 000003.log -rw-r--r-- 1 anonymous anonymous 16 Фев 7 03:08 CURRENT -rw------- 1 anonymous anonymous 0 Фев 7 03:08 LOCK -rw-r--r-- 1 anonymous anonymous 46 Фев 7 03:08 LOG -rw-r--r-- 1 anonymous anonymous 32 Фев 7 03:08 MANIFEST-000002

    Можно посмотреть на примеры использования IndexedDB в Mozilla Developer Network.

    Вставка большого числа записей в IndexedDB рассмотрена на stackoverflow.com.

    Для добавления элементов в IndexedDB, надо использовать

    indexedDB.db.transaction().objectStore().put({})

    В папке базы IndexedDB-данных старые базы хранятся как.sst-файлы, а новые (текущие) - как.log-файлы.

    setVersion() is Deprecated. Но тут есть одна хитрость [про onupgradeneeded()]: ...

    Как сказано в блоге Parashuram Narasimhan, "For Chrome: In case of chrome, the onupgradeneeded function is not called. The database"s onsuccess function is called. Here, the existence of the setVersion method is checked. If the method exists, and the specified version is greater than the database version, a the setVersion method is called. The onsuccess of the setVersion"s request call invokes the user"s onupgradeneeded method with the version transaction. Once the method completes, the versionTrasnaction is committed by closing the database. The database is opened again with the latest version and this is passed to the onsuccess defined by the user." (поэтому для вызова onupgradeneeded(), я делаю db.setVersion("3")).

    Как делать выборку данных в content.js:

    dbreq.onupgradeneeded = function(event) { console.log("dbreq.onupgradeneeded"); var db = event.target.result; var tx = db.transaction(["test_db"], "readonly"); var store = tx.objectStore("todo");

    Для открытия базы, используйте код от axemclion+jepp (функцию openReqShim).

    Когда открываем IndexedDB-базу, которая не существует, она создаётся (will be created) с номером версии, version = 0. При этом, вызываются onupgradeneeded() и onsuccess() последовательно. При первом вызове onupgradeneeded(), version уже = 1. Когда открываем второй раз [существующую базу], onupgradeneeded() уже не вызывается, а номер версии = 1. (?не увеличивается) Вызывается только dbreq.onsuccess().

    Ещё один момент. Тут сказано, что "With Chrome prior to 23 you need to create such a transaction manually by calling setVersion() - an API that has been removed from the spec. The older spec can be found at: http://www.w3.org/TR/2011/WD-IndexedDB-20110419/", то есть для того чтобы не было ошибки "NotFoundError: DOM IDBDatabase Exception 8" в логах хрома, требуется вызвать setVersion().

    В Chromium 6.0.472.63 (59945) реализация IndexedDB не является stable, поэтому отключена и не работает =)

    В общем, надо использовать background.js + iframe + обмен с контент-скриптами через messages

    Как отрабатывать событие об открытии страницы?

    "content_scripts": [ { "matches": [ "*://*/*" ], "js": [ "content.js" ], "run_at": "document_start" } ], ...

    Content.js:

    document.addEventListener("DOMContentLoaded", function () { alert("Abc "+document.location.href); });

    Как оформлять HTML-код страницы? См. написание расширений Firefox . Как упаковать расширение, и где его расположить?

    Чтобы расположить расширение на Chrome WebStore, нужно заплатить гуглю вступительный взнос 5$ (затем можно будет помещать любое количество расширений). Заплатить можно через VISA, MasterCard, AMEX или DISCOVER (дополнительно, при оплате, надо указать свой полный почтовый адрес и Имя-Фамилию).

    Для размещения расширения нужен Google-аккаунт, и далее. Там понадобятся скриншот и рекламная картинка. Обновлять код расширения надо будет вручную, через тот же Chrome WebStore (как я понял, тут нет автоматического обновления по URL, как в Firefox). В файле manifest.json нужно обновить версию расширения. Спустя несколько минут после добавления, расширение будет доступно в поиске по расширениям Chrome.

    Упаковка расширения под Linux:

    #!/bin/bash 7z a -tzip ../domainck-chromium.zip ./* mv ../domainck-chromium.zip ../domainck-chromium.crx

    Ключевые слова: Chromium builds for windows HOWTO, Google Chrome download page, Google Chrome sample extensions.

    iMacros - расширение, которое помогает в тестировании веб-страниц. Вместо того, чтобы самостоятельно проделывать одни и те же действия на странице, разработчику нужно лишь записать требуемую последовательность действий в iMacros и запускать расширение тогда, когда это необходимо.

    Расширение способно работать с сайтами, реализованными при помощи технологий Java, Flash, Flex, Ajax и Silverlight.

    2. Font Playground

    Расширение для тех, кто любит «поиграть со шрифтами» - позволяет экспериментировать со всем спектром шрифтов из библиотеки Google Fonts, не внося изменений в код страницы. Можно менять не только сам шрифт, но и его размер, стиль написания и так далее.

    3. Project Naptha

    Расширение для Google Chrome, которое позволяет выделять и копировать текст даже с картинок - будет полезным, по мнению Cretive Bloq, всем, кому хоть раз в своей работе приходилось иметь дело со встроенным текстом.

    4. What Font

    Расширение, которое позволяет мгновенно определить, какой шрифт использован на той или иной странице, не производя почти никаких дополнительных действий - наведя курсор мыши на надпись.

    5. YSlow

    YSlow - инструмент, который не только проверяет скорость загрузки той или иной веб-страницы, но и подсказывает разработчику, что её тормозит. Для этого расширение проверяет сайт на соответствие 23 из 34 правил производительности , сформулированных командой компании Yahoo.

    6. Web Developer

    Целый набор полезных инструментов для управления элементами сайта - например, для анализа веб-ресурсов и макетов, тестирования кода и мгновенного изменения параметров и внешнего вида страницы.

    7. Web Developer checklist

    Расширение для автоматической проверки, удовлетворяет ли сайт основным принципам SEO, достаточно ли он производителен и удобен для пользователя. Результаты проверки представляются в виде своеобразного чек-листа - можно посмотреть более подробную информацию и рекомендации по каждому из невыполненных пунктов, а также моментально исправить ошибки.

    8. DevTools Autosave

    Позволяет в автоматическом режиме сохранять любые изменения, внесённые в код страницы при помощи инструментов Chrome DevTools. Как отмечает автор материала, инструмент помогает разработчикам сэкономить большое количество времени.

    9. Instant Wireframe

    Расширение, при помощи которого можно «превратить» любую страницу в структурную схему компоновки материала - wireframe. Позволяет разработчикам и веб-дизайнерам не выходя из браузера ознакомиться с компоновкой любой страницы в сети.

    10. Ripple Emulator

    Ripple Emulator - расширение-эмулятор для Google Chrome, которое позволяет тестировать веб-сайты на различных мобильных платформах с различными разрешениями экрана. Может быть использовано в сочетании с другими расширениями для тестирования и отладки ресурсов.

    11. Streak

    Streak - расширение, которое позволяет превратить почтовый ящик на Gmail в CRM-систему. Можно отслеживать статус сделок и переговоров, которые ведутся в электронной почте с контрагентами, использовать Streak для обработки запросов пользователей продукта и отслеживания исправлений присланных ошибок и так далее.

    12. Search Stackoverflow

    Расширение для быстрого поиска по популярному ресурсу для разработчиков Stack Overflow.

    13. PHP Ninja Manual

    Позволяет получить мгновенный доступ к документации по PHP 5.5 из браузера.

    14. PerfectPixel

    PerfectPixel - расширение для Google Chrome. Оно позволяет «наложить» на веб-страницу полупрозрачную сетку и сверять по ней заданные расстояния. Можно накладывать и другие изображения - например, первоначальный макет - чтобы убедиться, что получившаяся страница в точности ему соответствует:

    15. Code Cola

    Инструмент для просмотра исходного кода страниц и редактирования CSS-кода.

    Можно менять тени, окружности бокса и так далее с помощью перетаскивания ползунка. После внесения изменений можно скопировать получившийся код и заменить его в коде сайта.

    16. Chrome Sniffer

    Расширение для браузера, которое определяет, какие JavaScript-библиотеки, фреймворк или CMS используются на ресурсе.

    17. User-Agent Switcher

    User-Agent Switcher - это расширение, которое позволяет «маскировать» браузер Google Chrome под Internet Explorer, Opera или любой другой браузер.

    18. IE Tab

    Встроенный эмулятор Internet Explorer для Chrome.

    19. PicMonkey

    Простой и бесплатный онлайн-редактор изображений. Позволяет «захватывать» изображения или делать скриншоты браузера - и сразу же редактировать их при помощи расширения для Chrome.

    20. Chrome Daltonize

    Расширение, которое помогает адаптировать веб-сервисы для тех пользователей, которые страдают дальтонизмом - демонстрируя разработчику, как сайт видят те, кто страдает этим заболеванием. Позволяет веб-дизайнерам и разработчикам создавать более доступные сервисы.

    21. Page Ruler

    Простой инструмент, который помогает определить высоту, ширину и положение любого элемента на странице.

    22. Check My Links

    Расширение, которое проверяет веб-страницу на наличие «битых» или неправильных ссылок.

    23. Flickr Tab

    Расширение, которое помогает не столько в разработке, сколько в поиске вдохновения и хороших фотографий. Показывает на каждой новой вкладке в Google Chrome одно изображение с сервиса Flickr. При нажатии на него пользователь переходит на страницу автора, где может ознакомиться с другими его работами.

    24. Google Art Project

    Расширение для браузера, похожее на предыдущий плагин в этом списке - только вместо фотографий из Flickr в новой вкладке пользователь видит признанные произведения искусства - например, полотна кисти Ван Гога или Мане.

    25. Data Saver

    Официальное расширение от Google для сжатия трафика, которое включает экономию трафика в браузере Google Chrome.

    Написать расширение для google chrome несложно. Но при написании первого раширения могут возникнуть (и возникают) вопросы. Большинство мануалов по написанию первого расширения расчитаны на использования манифеста первой версии, поддержка которого в скором будущем прекратится.

    В этой статье будет рассмотрено:

    • Как составлять манифест v.2
    • Как работать с удаленными ресурсами
    • Как работать с cookies
    • Как работать с local storage
    • Как работать с уведомлениями
    Введение

    К концу статьи у нас будет готово расширение-органайзер, в котором будет поле для добавления новой задачи, а так же список задач на текущий день. Обозначим все требования к органайзеру:

    • Должен иметь поле для добавления события (дата, время, событие)
    • Должен отображать все задачи на текущий день, отсортированные по времени
    • Все прошедшие события должен отображать зачеркнутыми
    • Должен иметь поле для ввода времени, за сколько надо показывать уведомление, а так же чекбокс разрешающий и запрещающий показывать уведомления
    • За указанное время до события должен отображать уведомление о приближающемся событии
    Манифест

    Начнем создавать расширение с самого начала, то есть с манифеста. Манифест – это тот самый файл, в котром прописываются все параметры расширения. Название, описание, версия, разрешение на доступ к сайтам, разрешение на использование кук, уведомлений, локального хранилища. В общем, манифест – это мозг расширения. Создаем файл manifest.json. Манифест – единственный файл, который должен иметь заранее предопределенное имя, все остальные файлы можно будет называть как угодно. В этом файле есть три обязательных поля:

    manifest.json

    { “name”: “Organizer extension”, // Название расширения “version”: “1.0”, // Версия расширения. “manifest_version”: 2 // Версия манифеста }

    Тут есть пара правил:

    • Версия манифеста должна быть целочисленной, то есть должна писаться как 2, а не “2”.
    • Версия расширения должна быть строковой, но содержать только числа и точки, то есть “1.0” - хорошо, а 1.0 и “0.9 beta” - плохо.

    С обязательными полями – все, перейдем к созданию всплывающего окна расширения. Для того, чтобы по нажатию на пиктограмму, открывалось окно, необходимо добавить в манифест поле “browser_action”

    manifest.json

    { … "browser_action": { "default_title": "Open organizer", // Заголовок. Его видно если навести курсор на иконку в браузере "default_icon": "icon_small.png", // Путь к иконке расширения "default_popup": "popup.html" // Путь к странице с попапом } }

    Теперь создадим всплывающее окно. Это обычная html страница, которая может быть любого размера и цвета, никаких фокусов. Назовем файл “popup.html”. Создать этот файл мало – его надо указать в манифесте. Так мы и сделали: «default_popup»: «popup.html».

    popup.html

    It works!

    Добавление расширения в браузер

    Теперь пришло время проверить работоспособность нашего расширния. Для этого загрузим расширение в браузер. Открываем в хроме меню расширений. Ставим птицу на “Developer mode”.

    После этого появятся три кнопки. Нажимаем “Load unpacked extension...”. Выбираем папку с файлами расширения. После этого появится наше расширение. Если все правильно, то по нажатию на иконку – повится окно:

    Подключение скриптов

    Теперь можно приступить к интересному. Подключим два javascript файла. Первый – popup.js, второй – jquery. С первым проблем не возникнет, но jquery будем подключать не локальный, а удаленный, взятый по адресу ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js . Проблемы возникнут от того, что по умолчанию расширение не имеет доступа к сторонним ресурсам. Чтобы получить доступ, надо его указать в манифесте. Доступ к чему-либо указывается в поле “permissions”. Так же, для удаленных скриптов и css надо указывать доступные удаленные ресурсы.

    manifest.json

    { … "permissions": [ "https://ajax.googleapis.com/*" ], "content_security_policy": "script-src "self" https://ajax.googleapis.com; object-src "self"" }

    Теперь подключим эти скрипты в popup.html

    popup.html

    Storage

    При помощи storage в хроме можно хранить пользовательские данные. И именно в storage наше расширение и будет хранить грядущие события. На то есть две причины. Во-первых, данные, хранищиеся в storage можно синхронизировать, если залогиниться в браузере. А во-вторых, данные можно хранить не только в виде строки, как в cookies, а в любом виде, то есть можно хранить и массивы и объекты. Чтобы это заработало, откроем доступ к storage в манифесте.

    manifest.json

    { ... "permissions": [ … "storage" ] ... }

    Теперь переделаем всплавающее окно. Во всплывающем окне будет поле с сегодняшней датой, три инпута для даты, времени и описания нового события, кнопка для добавления нового события, а так же список всех событий на сегодня.

    popup.html

    Date

    Дата Время Задача

    И сразу же добавим отображение даты в блоке #today_date.

    popup.js

    $(function(){ var today = new Date(); $("#today_date").html(today.getDate()+"."+(parseInt(today.getMonth())+1)+"." + today.getFullYear()); }

    Выглядеть должно так:

    Итак, при нажатии на кнопку “+” у нас должно добавляться событие. Вначале файла объявим глобальную переменную storage – объект для работы с storage, а так же глобальный массив tasks для хранения событий.

    popup.js

    Var storage = chrome.storage.sync; var tasks = new Array(); $(function(){ … $("#add_task").click(function(){ var new_task = new Object(); new_task.date = validateField($("#new_date").val(), "date"); new_task.time = validateField($("#new_time").val(), "time"); new_task.task = $("#new_task").val(); if(!new_task.task || !new_task.date || !new_task.task){ return false; } tasks = new_task; storage.set({ tasks:tasks }); }); });

    Функция валидации проверяет, что дата записана в формате d.m.yyyy, а время в формате hh:mm, а так же, что в описании события не меньше трех символов.

    popup.js

    Var validateField = function(val, type){ if(type == "date"){ var date = val.split("."); var year = new Date(); year = year.getFullYear(); if(date.length == 3 && parseInt(date) == date && date = 3){ return val; } return null; }

    С добавлением разобрались, переходим к получению событий на сегодня. Для этого надо получить все события из базы, выбираем из всех только сегодняшние события и сортируем их по времени по возрастанию.

    popup.js

    $(function(){ … var now_hours = today.getHours() < 10 ? "0" + today.getHours() : today.getHours(); var now_minutes = today.getMinutes() < 10 ? "0" + today.getMinutes() : today.getMinutes(); var now_time = now_hours + "" + now_minutes; storage.get("tasks",function(items){ if(items.tasks){ tasks = items.tasks; var today_tasks = getTodayTasks(tasks); if(today_tasks.length >0){ for(var i in today_tasks){ var this_time = today_tasks[i].time.replace(":", ""); var add = this_time > now_time ? "" : " class="done""; var add_html = ""+today_tasks[i].time+" "+today_tasks[i].task+""; $("ul").append(add_html); } } } }); … });

    Функция getTodayTasks() возвращает из общего списка только события с сегодняшней датой.

    popup.js

    Var getTodayTasks = function(tasks){ var today_tasks = new Array(); var today = new Date(); var today_date = today.getDate()+"."+(today.getMonth() + 1)+ "." + today.getFullYear(); for(var i in tasks){ if(tasks[i].date == today_date){ today_tasks = tasks[i]; } } if(today_tasks.length > 0){ today_tasks = sortTasks(today_tasks); } return today_tasks; }

    Функция sortTasks() сортирует события по возрастанию времени.

    popup.js

    Var sortTasks = function(tasks){ if(tasks.length > 0){ var swapped = true; while (swapped) { swapped = false; for (var i=0; i < tasks.length-1; i++) { var this_time = tasks[i].time.replace(":", ""); var next_time = tasks.time.replace(":", ""); if (this_time > next_time) { var temp = tasks[i]; tasks[i] = tasks; tasks = temp; swapped = true; } } } } return tasks; }

    Уведомления

    Пришло время настроить отображение уведомлений на экране. Добавим во всплывающее окно специальный чекбокс. Если этот чекбокс будет отмечен – уведомлениея будут показываться, если не будет отмечен – не будут. Так же добавим текстовый инпут. Цифра в этом инпуте будет показывать, за какое время до событя будет показываться уведомление. То есть если у нас событие назначено на 19:00, в этом текстовом инпуте будет 5, значит в 18:55 появится уведомление. Добавим в popup.html код с этими инпутами

    popup.html

    Показывать уведомления

    Теперь давайте разберемся с тем, как это будет работать. При нажатии на чекбокс, будет проверяться его атрибут checked, значение атрибута будет записываться в cookie “show_notifications”. Перейдем к текстовому инпуту. По изменению его значения, новое значение будет валидироваться, если оно целочисленное и не больше 120, записываем новое значение в cookie “when_to_notify”.

    Но для того, чтобы у нас это заработало, надо открыть доступ к cookies. Для этого заходим в manifest.json и добавляем в “permissions”

    manifest.json

    { ... "permissions": [ … “cookies” ] ... }

    Теперь можно приступать к скрипту. Заходим в popup.js. Для начала установим первоначальные значения в инпутах. По-умолчанию чекбокс не отмечен, то есть уведомления не показываются, а время равно 0. При клике на чекбокс, будет меняться значение cookie “show_notifications”. При изменении значения в тектовом поле, будет меняться значение cookie “when_to_notify”.

    popup.js

    $(function(){ setCheckbox(); setWhenToNotify(getCookie("when_to_notify")); ... $("#show_notifications").click(function(){ setCookie("show_notifications", document.getElementById("show_notifications").checked); }); $("#when_to_notify").change(function(){ setWhenToNotify($(this).val()); }); });

    Рассмотрим подробнее функции. Начнем с функций работы с cookies. В данном случае были взяты готовые функции с w3schools.com.

    popup.js

    Var setCookie = function(c_name,value,exdays){ /* *Взято с http://www.w3schools.com/js/js_cookies.asp */ var exdate=new Date(); exdate.setDate(exdate.getDate() + exdays); var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString()); document.cookie=c_name + "=" + c_value; } var getCookie = function(c_name){Позвонить Васе П. /* *Взято с http://www.w3schools.com/js/js_cookies.asp */ var i,x,y,ARRcookies=document.cookie.split(";"); for (i=0;i