Делаем свое расширение для Firefox. Часть III. Работа с запросами.
До того, как мы будем выполнять запросы к внешним ресурсам, надо внести изменения в
manifest.json
, дав соответствующее разрешение "<all_urls>"
в permissions
. Все разрешения для нашего аддона:
"permissions": [
"activeTab",
"tabs",
"storage",
"<all_urls>"
]
Внимание! Если разрешение
"<all_urls>"
не дать, то при попытке обращения к внешнему ресурсу произойдет ошибка:Запрос из постороннего источника заблокирован: Политика одного источника запрещает чтение удаленного ресурса на https://api.myip.com/. (Причина: отсутствует заголовок CORS «Access-Control-Allow-Origin»).
Почему-то ссылка на пояснение к ошибке на сайте Мозиллы ведет не совсем на то, что нужно, а в поиске, тоже неизвестно почему, информация о том, что нужно просто дать разрешение
"<all_urls>"
в manifest.json
не всплывает. Сам еле догадался, практически методом научного тыка устранил данный глюк.После долгого ковыряния в отладке и интернете я решил немного отдохнуть, и дополнить дизайн расширения.
Фактически, у запроса есть три состояния:
- запрос выполняется
- запрос выполнен успешно
- запрос завершен с ошибкой
Обо всем этом можно и нужно сообщать пользователю, и симпатичнее всего это сделать, меняя иконку. Нарисовал и сохранил в каталог
flags
.- запрос выполняется (
1working.png
)
- запрос завершен с ошибкой (
2error.png
)
- если запрос выполнен успешно, то будем показывать флаг страны, как и планировалось изначально. Но, на всякий случай, можно предусмотреть ситуацию, когда страну определить не удалось (с api.myip.com это вряд ли случится, но с другим скриптом, выдающим данные в том же формате может быть).
- страна неизвестна (
3unknow.png
)
GET-запрос к сайту оказалось проще всего сделать с помощью библиотеки JQuery.
Скачиваем библиотеку и сохраняем ее в каталог с
ip_popup.html
. В самом ip_popup.html
подключаем ее (перед скриптом ip_popup.js
):<script src="jquery-3.4.1.min.js"></script>
Правим
ip_popup.js
. Понятно, что пока мы не получим адрес сайта из хранилища, запрос мы сделать не сможем, а функция
browser.storage.local.get
работает асинхронно и возвращает промис (gettingItem
), на который мы навесили обработчики onGot
и onGotError
, но прикол в том, что then
в gettingItem.then(onGot, onGotError)
тоже возвращает промис! К которому, в свою очередь, можно подцепится с помощью then. И пока первый промис в цепочке не завершит работу, второй работу не начнет.Подробности: Использование промисов
Поэтому, модифицируем функцию
loadSettings
так, чтобы она возвращала промис, просто добавив return
:Было:
function loadSettings()
{
var gettingItem = browser.storage.local.get('server_settings');
gettingItem.then(onGot, onGotError);
}
Стало:
function loadSettings()
{
var gettingItem = browser.storage.local.get('server_settings');
return gettingItem.then(onGot, onGotError);
}
Далее модифицируем функцию
bodyLoad
добавив после loadSettings
следующее звено цепочки:function bodyLoad()
{
loadSettings()
.then(doRequest);
}
В функции
doRequest
будем выполнять GET-запрос и обрабатывать результат.До самого запроса меняем иконку во всплывающем окне:
document.getElementById("flag").src = 'flags/1working.png';
document.getElementById("flag").alt = 'Working';
document.getElementById("flag").title = 'working...';
Далее, выполняем запрос и обрабатываем результат, так, как сказано в мануале JQuery. Функции JQuery вызываются через
$.<функция>
$.get(curAddr)
.done (function (data) {
//запрос успешно завершен, тут будет код обработки данных
})
.fail(function () {
// ошибка запроса, обрабатываем ошибку
});
Подробности: jQuery.get()
.done
передаем функцию-коллбэк со следующим кодом:var json = $.parseJSON(data);
document.getElementById("ip").value = json.ip;
document.getElementById("country").value = json.country;
if (json.cc.trim() == '') //no country code
{
document.getElementById("flag").src = 'flags/3unknow.png';
document.getElementById("flag").alt = 'Unknow';
document.getElementById("flag").title = 'Unknow country code';
}
else //country code exist
{
document.getElementById("flag").src = 'flags/'+json.cc.trim()+'.png';
document.getElementById("flag").alt = json.cc;
document.getElementById("flag").title = json.cc;
}
1. Распарсим, опять же, средствами JQuery (
$.parseJSON(data)
) полученные от сайта данные.2. Присвоим полям с id
ip
и id country
значения, соответственно, IP-адреса и названия страны.3. Если поле
cc
, объекта json
пустое, значит не удалось определить код страны. Присваиваем изображению флага картинку неопознанной страны, а свойствам изображения alt
и title
(всплывающая подсказка), соответствующие значения.4. Если код страны не пустой, т.е. страна определена, присваиваем изображению соответствующую картинку с флагом (файлы флагов названы в соответствии с кодом страны) и сам код в качестве описания и всплывающей подсказки.
Функция
doRequest()
целиком:function doRequest() //main request function
{
document.getElementById("flag").src = 'flags/1working.png';
document.getElementById("flag").alt = 'Working';
document.getElementById("flag").title = 'working...';
$.get(curAddr)
.done (function (data) {
//data processing code here
var json = $.parseJSON(data);
document.getElementById("ip").value = json.ip;
document.getElementById("country").value = json.country;
if (json.cc.trim() == '') //no country code
{
document.getElementById("flag").src = 'flags/3unknow.png';
document.getElementById("flag").alt = 'Unknow';
document.getElementById("flag").title = 'Unknow country code';
}
else //country code exist
{
document.getElementById("flag").src = 'flags/'+json.cc.trim()+'.png';
document.getElementById("flag").alt = json.cc;
document.getElementById("flag").title = json.cc;
}
})
.fail(function () {
//error processing code here
document.getElementById("flag").src = 'flags/2error.png';
document.getElementById("flag").alt = 'Error';
document.getElementById("flag").title = 'Error';
});
}
Вот, что получилось:
- Работает:



На этом разработку всплывающего окна можно считать завершенной.
ip_popup.html
ip_popup.css
ip_popup.js
Предыдущая часть
Продолжение
Это репост с сайта http://tolik-punkoff.com
Оригинал: http://tolik-punkoff.com/2019/10/02/dela