В SitePoint мы широко используем Trello. Конечно, он имеет свои причуды и может использовать одно или два улучшения в различных областях, но по большей части он революционизировал совместный опыт не только сотрудников, но также авторов и их редакторов.
Недавно я обнаружил, что мне нужно экспортировать заголовки карточек из определенного списка для не членов. По умолчанию Trello поддерживает только полный пансионный экспорт в JSON, и это то, что ломает мою вкладку на доске из более чем 100 участников с сотнями карт. В магазине есть небольшая армия расширений Trello, и, что любопытно, ни одна из них не экспортирует списки каким-либо образом.
Давайте сделаем расширение Chrome, которое может сделать это для нас! Если вы спешите и просто хотите увидеть конечный результат, посмотрите репозиторий Github для окончательной версии кода этого урока.
Создание расширения Chrome
Я полагал, что лучшим подходом будет расширение, потому что отдельное приложение, выполняющее только этот экспорт, может быть слишком много Кроме того, у Trello есть отличный API, который мы можем использовать, чтобы получить все, что нам нужно. Я также подумал, что это будет хороший переход обратно к разработке расширений, чего я давно не делал.
Бутстрапирование
Я буду использовать мое верное хранилище ChromeSkel — скелетное расширение, которое я создал давно, чтобы упростить начало работы с Chrome Extension. Для справки, если вы хотите увидеть другие учебники по расширению Chrome, которые я написал в прошлом, смотрите здесь и здесь .
Начнем с клонирования репо в любую папку.
git clone https://github.com/Swader/ChromeSkel_a.git
Чтобы увидеть, работает ли он, загрузите его в Chrome. Перейдите на вкладку расширений и нажмите «Загрузить распакованное расширение». Если опция отсутствует, убедитесь, что вы отметили флажок «Режим разработчика» в правом верхнем углу.
После загрузки он должен появиться в вашем списке расширений.
Аутентификация
В то время как мы могли бы просто собирать данные на экране с помощью расширения Chrome и анализировать это, Trello иногда оказывался ненадежным и, как правило, приводил к сбоям на густонаселенных платах. Вот почему мы будем использовать только интеграцию расширения Chrome с доменом trello.com для создания новых опций контекстного меню в списках (опция «Экспорт карт»), и мы будем выполнять всю логику на фоновой странице, выбирая данные через API.
Ключ и Секрет
Чтобы создать ключ приложения для Trello, перейдите по адресу https://trello.com/1/appKey/generate при входе в систему. Это даст вам ключ и секрет, которые вы можете использовать в своей учетной записи. В оставшейся части этого учебного пособия рассмотрите {{KEY}} в качестве этого ключа и замените содержимое соответствующим образом.
Когда у вас есть ключ, в key.js
scripts
создайте файл key.js
:
// key.js var APP_KEY = '{{KEY}}';
Пока вы это делаете, вы можете удалять fragments
и папки с fancy-settings
. Нам они не понадобятся.
Рабочий процесс и манифест
Идея рабочего процесса расширения заключается в следующем:
- данный пользователь открывает доску Trello
- проверить, разрешил ли указанный пользователь добавочный номер использовать свою учетную запись Trello
- если да, продолжайте
- если нет, откройте страницу настроек с кнопкой авторизации, которая позволяет им завершить процедуру
- После авторизации закройте страницу настроек автоматически и оставьте добавочный номер авторизованным.
Чтобы расширение автоматически открывало новую вкладку с некоторым содержимым, мы должны пометить это содержимое как «доступный через Интернет ресурс» .
Для этого создайте папку с settings
, которая будет содержать нашу страницу настроек, и обновите манифест расширения так, чтобы он выглядел следующим образом:
{ "name": "Trello Helper", "version": "0.1", "manifest_version" : 2, "description": "Trello Helper adds some much needed functionality to Trello. The current version focuses on exporting card information from lists.", "background" : { "page" : "background.html", "persistent": false }, "page_action" : { "default_icon": { "19": "icons/19.png", "38": "icons/38.png" } }, "content_scripts": [ { "matches": ["https://trello.com/b/*"], "js": [ "lib/jquery-2.1.1.min.js", "scripts/main.js" ], "run_at": "document_idle" } ], "permissions": [ "tabs" ], "icons": { "16": "icons/16.png", "48": "icons/48.png", "128": "icons/128.png" }, "web_accessible_resources": [ "settings/index.html" ], "options_page": "settings/index.html" }
Большая часть этого должна быть знакомой. Мы устанавливаем версию, даем некоторые метаданные, определяем значки и объявляем страницу события , загружаем некоторые необходимые сценарии содержимого (нам нужен jQuery для клиентской библиотеки Trello JS ) и, наконец, определяем «web_accessible_resources», чтобы мы могли использовать страницу настроек, которую мы будем использовать строить Мы также ограничиваем влияние расширения на https://trello.com/b/*
, то есть только URL-адреса форума.
Настройки и авторизация
Чтобы создать нашу страницу настроек, мы пишем простую страницу HTML. В демонстрационных целях я буду в этом случае очень прост. Мы будем использовать Foundation для стилизации (прямо сейчас, только для кнопок, но мы будем работать над улучшением страницы настроек в будущих публикациях), поэтому загрузите пакет базовых компонентов Foundation и разархивируйте его содержимое в /settings
, чтобы index.html
попадает в эту папку. У вас должна быть такая структура папок:
Если у вас есть дополнительные папки, которые не видны на моем скриншоте, удалите их. Создайте файл settings/js/settings.js
, пока оставьте его пустым.
Хорошо, давайте приступим к делу. Таким образом, предполагается, что пользователь попадает на эту страницу, либо переходя к «Параметры» на вкладке «Расширения», либо пытаясь использовать расширение, когда его не аутентифицируют. Давайте создадим довольно простую HTML-страницу с двумя элементами div — одну для проверки подлинности пользователя с помощью кнопки «Выйти», а другую — для проверки подлинности, когда он еще не прошел проверку подлинности и ему необходимо нажать кнопку «Авторизовать». Замените содержимое index.html
следующим:
<!doctype html> <html class="no-js" lang="en"> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>Trello Helper Settings</title> <link rel="stylesheet" href="css/foundation.css"/> <script src="js/vendor/modernizr.js"></script> </head> <body> <div class="row"> <div class="large-12 columns"> <h1>Trello Helper Settings</h1> </div> </div> <div class="row"> <div class="large-12 columns"> <div class="panel" id="trello_helper_loggedout" style="display: none"> <p>To get going, you'll need to authorize the extension to use your Trello account.</p> <p>Do it by clicking the big Authorize button below.</p> <a href="#" class="medium success button" id="trello_helper_login">Authorize</a><br/> </div> <div class="panel" id="trello_helper_loggedin" style="display: none"> <p>You are already authorized. If something doesn't work, try logging out using the button below, and logging back in.</p> <a href="#" class="medium success button" id="trello_helper_logout">Log out</a><br/> </div> </div> </div> <script src="../scripts/key.js"></script> <script src="js/vendor/jquery.js"></script> <script src="js/settings.js"></script> </body> </html>
У нас есть два элемента div, кнопка входа и выхода, и мы подключаем JS, который нам понадобится. В этом случае мы используем включенный по умолчанию jQuery, но на самом деле не имеет значения, если вы решите использовать свой собственный загруженный файл в другом месте проекта, в случае, если вы выбрали более современный, как я (подробнее на что позже).
Теперь давайте добавим немного логики. Откройте settings.js
и предоставьте ему следующее содержимое:
function init() { // Message and button containers var lout = $("#trello_helper_loggedout"); var lin = $("#trello_helper_loggedin"); // Log in button $("#trello_helper_login").click(function () { }); // Log out button $("#trello_helper_logout").click(function () { }); if (!localStorage.trello_token) { $(lout).show(); $(lin).hide(); } else { $(lout).hide(); $(lin).show(); } } $(document).ready(init);
Читая документы , мы можем узнать, что trello_token
будет существовать в localStorage
когда клиентское приложение будет аутентифицировано. Это означает, что мы можем использовать его как индикатор того, когда показывать каждый из наших элементов. В функции init
мы берем div, добавляем обработчики нажатия на кнопки (там пока нет логики) и, наконец, мы скрываем соответствующий div в соответствии с trello_token
.
Например, когда пользователь проходит проверку подлинности, он получает такой экран:
Давайте сейчас получим клиент Trello JS.
Документация Trello на самом деле не написана с учетом расширений Chrome, и рекомендует подключать key
к URL при извлечении клиентской библиотеки JS из их домена, например так:
<script src="https://api.trello.com/1/client.js?key=substitutewithyourapplicationkey"></script>
На самом деле мы не можем этого сделать, поскольку имеем дело с закрытой средой расширения и видим, что было бы гораздо разумнее иметь его локально для повышения производительности. Поэтому мы посещаем вышеуказанный URL, но без ключевого параметра:
https://api.trello.com/1/client.js
Сохраните содержимое этого файла в lib/trello_client.js
, затем убедитесь, что наша страница настроек загружает его, добавив его в раздел сценариев рядом с конечным <body>
, например:
<script src="js/vendor/jquery.js"></script> <script src="../lib/trello_client.js"></script> <script src="js/settings.js"></script>
Это обеспечит доступность объекта Trello в нашем JavaScript, что позволит нам использовать его методы . Давайте сначала обработаем выход из системы. Измените обработчик нажатия кнопки выхода из системы следующим образом:
$("#trello_helper_logout").click(function () { Trello.deauthorize(); location.reload(); });
Это все, что нужно, чтобы деавторизовать с Trello. Мы вызываем метод и перезагружаем страницу, на которой мы находимся (то есть экран настроек).
Теперь давайте обработаем вход в систему, что немного сложнее.
// Log in button $("#trello_helper_login").click(function () { Trello.setKey(APP_KEY); Trello.authorize( { name: "Trello Helper Extension", type: "redirect", expiration: "never", interactive: true, scope: {read: true, write: false}, success: function () { // Can't do nothing, we've left the page }, error: function () { alert("Failed to authorize with Trello.") } }); });
Следуя логике онлайновых документов, мы видим, что у объекта Trello есть метод setKey
, который мы удачно используем для его установки. Затем мы вызываем в действие метод authorize
. Согласно документации, использование popup
типа вместо redirect
потребует от пользователя ручного вставления секретного ключа в приложение при его получении, что мы не ищем. Однако, если мы используем перенаправление, страница будет перенаправлена на аутентификацию и вернется обратно после завершения. interactive
поле, если установлено значение false, отменяет как всплывающее окно, так и перенаправление, и вместо этого проверяет только, существует ли значение localStorage.trello_token
. Согласно документам, нам нужно сначала вызвать обычную авторизацию с перенаправлением, а затем, после возврата на страницу настроек, нам нужно вызвать его снова, но с интерактивным значением false, что заставит его получить токен предыдущего перенаправления. при условии. Это все немного запутанно, но это работает.
Есть и другая проблема. Если мы вызываем неинтерактивную authorize
сразу после открытия страницы настроек, то мы вызовем ошибку на странице, потому что перенаправление после авторизации еще не произошло. В качестве альтернативы можно добавить еще одну кнопку «Подтвердить» или что-то подобное на нашей странице настроек, которая появляется после перенаправления из Trello обратно на нашу страницу настроек, позволяя пользователю инициировать неинтерактивную авторизацию вручную. Это похоже на кошмар UX. В итоге я выбрал третье решение.
Сохраните следующий код в lib/hashSearch.js
.
/* As found on: http://stackoverflow.com/questions/3729150/retrieve-specific-hash-tags-value-from-url */ var HashSearch = new function () { var params; this.set = function (key, value) { params[key] = value; this.push(); }; this.remove = function (key, value) { delete params[key]; this.push(); }; this.get = function (key, value) { return params[key]; }; this.keyExists = function (key) { return params.hasOwnProperty(key); }; this.push= function () { var hashBuilder = [], key, value; for(key in params) if (params.hasOwnProperty(key)) { key = escape(key), value = escape(params[key]); // escape(undefined) == "undefined" hashBuilder.push(key + ( (value !== "undefined") ? '=' + value : "" )); } window.location.hash = hashBuilder.join("&"); }; (this.load = function () { params = {} var hashStr = window.location.hash, hashArray, keyVal hashStr = hashStr.substring(1, hashStr.length); hashArray = hashStr.split('&'); for(var i = 0; i < hashArray.length; i++) { keyVal = hashArray[i].split('='); params[unescape(keyVal[0])] = (typeof keyVal[1] != "undefined") ? unescape(keyVal[1]) : keyVal[1]; } })(); }
Как видно из ответа StackOverflow , эта небольшая утилита помогает нам получить значение определенного хэша из URL.
Когда вы авторизуетесь с помощью Trello через режим redirect
, он будет перенаправлен обратно на страницу, с которой пришел, но с токеном в URL. Этот токен будет токеном аутентификации, который нужен клиенту Trello JS. Следовательно, само собой разумеется, что если мы сможем обнаружить присутствие этого токена в URL, мы можем заключить, что имеем дело с перенаправлением из Trello и, таким образом, можем автоматически и безопасно запускать неинтерактивный протокол authorize
.
После добавления hashSearch
на страницу настроек вот так …
<script src="../scripts/key.js"></script> <script src="js/vendor/jquery.js"></script> <script src="../lib/trello_client.js"></script> <script src="../lib/hashSearch.js"></script> <script src="js/settings.js"></script>
… Файл settings.js
должен, в конце концов, выглядеть так:
function init() { // Check if page load is a redirect back from the auth procedure if (HashSearch.keyExists('token')) { Trello.authorize( { name: "Trello Helper Extension", expiration: "never", interactive: false, scope: {read: true, write: false}, success: function () {}, error: function () { alert("Failed to authorize with Trello.") } }); } // Message and button containers var lout = $("#trello_helper_loggedout"); var lin = $("#trello_helper_loggedin"); // Log in button $("#trello_helper_login").click(function () { Trello.setKey(APP_KEY); Trello.authorize( { name: "Trello Helper Extension", type: "redirect", expiration: "never", interactive: true, scope: {read: true, write: false}, success: function () { // Can't do nothing, we've left the page }, error: function () { alert("Failed to authorize with Trello.") } }); }); // Log out button $("#trello_helper_logout").click(function () { Trello.deauthorize(); location.reload(); }); if (!localStorage.trello_token) { $(lout).show(); $(lin).hide(); } else { $(lout).hide(); $(lin).show(); } } $(document).ready(init);
Теперь вы можете попробовать расширение. Загрузите вкладку расширений, нажмите на ссылку «Параметры» и проверьте аутентификацию и выход из системы. Все должно работать нормально.
Вывод
В этой части мы создали основы нашего расширения, осуществив аутентификацию через пользовательский экран настроек на основе Foundation и используя клиентскую библиотеку Trello JavaScript.
В следующей части мы построим всю логику за расширением и завершим вещи.