До того, как мы будем выполнять запросы к внешним ресурсам, надо внести изменения в 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'; }); }
Вот, что получилось:
— Работает:
На этом разработку всплывающего окна можно считать завершенной.