Делаем свое расширение для 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)

Подключение JQuery

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-запрос и обрабатывать результат.

Выполняем 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';
		});
}

Вот, что получилось:

— Работает:


— Запрос завершился успешно:

— Ошибка запроса:


На этом разработку всплывающего окна можно считать завершенной.

Код целиком (текущая версия) на PasteBin

ip_popup.html
ip_popup.css
ip_popup.js

Предыдущая часть
Продолжение

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *