Букмарклет: разбор существенных моментов, часть вторая, подгружаемая

  • Tutorial
Напомним, что букмарклет это небольшой javascript-код, сохраняемый в закладках браузера, и предназначенный для выполнения каких либо задач на текущей веб-странице.

Как было отмечено в предыдущем посте букмарклет можно разделить на 3 взаимодействующие части:
  1. Первая часть, небольшой, до 2000 символов javascript-код, который сохраняется в закладках браузера и, в простейшем случае может выполнять всю работу, но обычно служит для инициации работы букмарклета.
  2. Вторая, подгружаемая часть букмарклета: javascript-код подгружаемый в текущий документ в процессе инициации букмарклета и обеспечивающий основную функциональность.
  3. Третья, резервная часть букмарклета которая срабатывает если подгрузить javascript в текущий документ не удалось.

Первая часть букмарклета была досконально разобрана в предыдущем посте на живом примере букмарклета веб-сервиса TheOnlyPage (сервис хранения закладок, заметок и html-фрагментов)

На этот раз остановимся на подгружаемой части букмарклета.

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

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

  1. Обертка – изоляция кода букмарклета от внешней среды
  2. Включение и отмена индикатора загрузки / выключение
  3. Сброс CSS стилей
  4. Загрузка библиотек

Для наглядности будем иллюстрировать рассматриваемый материал, обращаясь к работе букмарклета веб-сервиса TheOnlyPage. Подробную информацию о том как установить этот букмарклет можно получить в справочной системе веб-сервиса

Обертка – изоляция букмарклета от внешней среды


В предыдущей публикации мы уже говорили о том, что javascript-код букмарклета необходимо разместить внутри анонимной функции. Тоже справедливо и для кода второй, подгружаемой части букмарклета. Этот код должен быть обернут в анонимную функцию приблизительно следующим образом:

(function (window, undefined) {
// здесь весь код букмарклета
})(window);

Анонимная функция содержит 2 параметра window и undefined, что сделано для того, чтобы вместо многократно используемых глобальных переменных window и undefined в теле функции использовались локальные переменные window и undefined, которые легко ужимаются при помощи минификаторов javascript-кода.
Вызов анонимной функции передает только один параметр: window. Второй параметр автоматически принимает требуемое значение undefined, не будучи переданным в функцию.

Включение и отмена индикатора загрузки / выключение


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

//  id индикатора загрузки: theonlypageAjaxLoaderGif
var image = window.document.getElementById('theonlypageAjaxLoaderGif');
// удаляем картинку
image.parentNode.removeChild(image);

При добавлении в текущий документ дополнительных визуальных элементов, имеет смысл обернуть их в общий контейнер. В букмарклете веб-сервиса TheOnlyPage это реализовано так:

// создаем элемент div
var veil = window.document.createElement('div');
// назначаем ему уникальный id
veil.id = 'theonlypageContainer';
// далее, обычно,  еще ряд действий… 
// …по наполнению контейнера содержимым 
// … и установки атрибутов
// встраиваем созданные элементы в текущий документ
window.document.body.appendChild(veil);

Как уже говорилось в предыдущей публикации важным моментом является использование на чужой веб-страничке гарантировано уникальных id. Для этого в id можно использовать название веб-сервиса. В нашем случае это theonlypageContainer.

Если элементы разметки, добавляемые букмарклетом помещаются в контейнер, отмеченный определенным id, то при повторной загрузке можно реализовать механизм выключения букмарклета:

var veil = window.document.getElementById('theonlypageContainer');
if(veil){
// если  в текущем документе уже присутствует контейнер
// удаляем его из текущего документа
	veil.parentNode.removeChild(veil);
	// и завершаем работу букмарклета
	return;
}

Удаляются все визуальные элементы с текущей странички и букмарклет отключается. Таким образом реализуется механиз включения / выключения букмарклета при последовательном клике по ссылке букмарклета в панели закладок браузера.

Сброс CSS стилей


При внедрении своих элементов разметки в чужой документ, надо иметь ввиду, что эти элементы могут наследовать CSS свойства текущего документа. И, в результате, наш div будет, к примеру, иметь совершенно ненужные отступы, а наш iframe внутри него, к примеру, совершенно неуместные тени.

Чтобы избавиться от возможных закруглений, цветов, отступов, анимационных эффектов и прочих ненужных нам свойств, необходимо сбрасывать стили каждого создаваемого элемента следующим образом:

// задаем переменную содержащую весь CSS код сброса параметров
var ResetCSS = "animation:none;animation-delay:0;animation-direction:normal;animation-duration:0;animation-fill-mode:none;animation-iteration-count:1;animation-name:none;animation-play-state:running;animation-timing-function:ease;backface-visibility:visible;background:0;background-attachment:scroll;background-clip:border-box;background-color:transparent;background-image:none;background-origin:padding-box;background-position:0 0;background-position-x:0;background-position-y:0;background-repeat:repeat;background-size:auto auto;border:0;border-style:none;border-width:medium;border-color:inherit;border-bottom:0;border-bottom-color:inherit;border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom-style:none;border-bottom-width:medium;border-collapse:separate;border-image:none;border-left:0;border-left-color:inherit;border-left-style:none;border-left-width:medium;border-radius:0;border-right:0;border-right-color:inherit;border-right-style:none;border-right-width:medium;border-spacing:0;border-top:0;border-top-color:inherit;border-top-left-radius:0;border-top-right-radius:0;border-top-style:none;border-top-width:medium;bottom:auto;box-shadow:none;box-sizing:content-box;caption-side:top;clear:none;clip:auto;color:inherit;columns:auto;column-count:auto;column-fill:balance;column-gap:normal;column-rule:medium none currentColor;column-rule-color:currentColor;column-rule-style:none;column-rule-width:none;column-span:1;column-width:auto;content:normal;counter-increment:none;counter-reset:none;cursor:auto;direction:ltr;display:inline;empty-cells:show;float:none;font:normal;font-family:inherit;font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;height:auto;hyphens:none;left:auto;letter-spacing:normal;line-height:normal;list-style:none;list-style-image:none;list-style-position:outside;list-style-type:disc;margin:0;margin-bottom:0;margin-left:0;margin-right:0;margin-top:0;max-height:none;max-width:none;min-height:0;min-width:0;opacity:1;orphans:0;outline:0;outline-color:invert;outline-style:none;outline-width:medium;overflow:visible;overflow-x:visible;overflow-y:visible;padding:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;page-break-after:auto;page-break-before:auto;page-break-inside:auto;perspective:none;perspective-origin:50% 50%;position:static;right:auto;tab-size:8;table-layout:auto;text-align:inherit;text-align-last:auto;text-decoration:none;text-decoration-color:inherit;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-shadow:none;text-transform:none;top:auto;transform:none;transform-style:flat;transition:none;transition-delay:0s;transition-duration:0s;transition-property:none;transition-timing-function:ease;unicode-bidi:normal;vertical-align:baseline;visibility:visible;white-space:normal;widows:0;width:auto;word-spacing:normal;z-index:auto;";
// и далее, при назначении свойств создаваемому элементу …
// … всегда используем CSS код сброса параметров …
// … при необходимости добавив CSS код специфический для данного элемента
veil.style.cssText = ResetCSS + 'position:absolute ;background-color:rgba(0,0,0,.2); cursor:pointer; '; 


Загрузка библиотек


Подгружаемая часть букмарклета TheOnlyPage не использует дополнительные библиотеки, однако, при необходимости, воспользоваться дополнительными библиотеками несложно.

Рассмотрим наиболее широко востребованный вариант — загрузку библиотеки jQuery

// минимально подходящая версия jQuery
var v = "1.11.1";
if (window.jQuery===undefined||window.jQuery.fn.jquery<v){
// если библиотека jQuery не загружена или версия jQuery слишкмо старая
// загружаем библиотеку
	// создаем элемент который будет загружать библиотеку
	var script=document.createElement('script');
	// указываем адрес по которому скачивается библиотека
	script.src="https://ajax.googleapis.com/ajax/libs/jquery/"+v+"/jquery.min.js";
	script.async=true;
	// внедряем скрипт в дом 
	var entry=document.getElementsByTagName('script')[0];
	entry.parentNode.insertBefore(script,entry);
	script.onload=script.onreadystatechange=function(){
		var readyState=script.readyState;
		if (!readyState||/complete|loaded/.test(script.readyState)){
			// если библиотека загружена
			// переходим к выполнению основной части кода букмарклета
			main();
			// отменяем обработчик чтобы не допустить... 
			// ...возможную в некоторых случаях утечку памяти
			script.onload = null;
			script.onreadystatechange = null;
		}
	};
}else{
	main();
}
var main=function(){
	// здесь весь оставшийся основной код букмарклета
}


Важный момент, на который уже обращали внимание в предыдущей публикации если у загружаемого javascript-кода протокол адреса: http:// то будут возникать ошибки, при работе на текущей странице, протокол адреса которой: https://. Причина этого: ограничения, накладываемые на смешанный активный контент (mixed active content), которые запрещают загружать код с незащищенных адресов в документ, защищенный по протоколу TLS (SSL). Есть 2 способа обеспечить, чтобы javascript-код всегда нормально загружался:
  1. либо размещать его по адресу с протоколом https://
  2. либо использовать специальную нотацию //, например:
    script.src='//ajax.googleapis.com/ajax/libs/jquery/v.1.11.1/jquery.min.js'
    что означает использование того же протокола что и у родительского документа. Тогда, в зависимости от протокола самой текущей веб-странички http:// или https:// будет использоваться соответствующий адрес:
    ajax.googleapis.com/ajax/libs/jquery/v.1.11.1/jquery.min.js
    или
    ajax.googleapis.com/ajax/libs/jquery/v.1.11.1/jquery.min.js

Кстати, если предполагается использовать библиотеку jQuery, то стоит обратить внимание на следующий важный момент: чтобы избежать возможные конфликты недопустимо использовать сокращение $ глобальной переменной jQuery, так как глобальная переменная $, с большой вероятностью, может уже использоваться в скриптах текущего документа, не как псевдоним для jQuery, а как другая глобальная переменная, например из библиотеки Prototype.JS. Поэтому используем только jQuery, без сокращений.

Мы рассмотрели все базовые элементы загружаемой части букмарклета, но имеются еще две темы для обсуждения:
  1. кросс-доменный обмен сообщениями с сервером;
  2. аутентификация пользователей веб-сервиса при работе с букмарклетом.

Однако эти темы требуют отдельного места и времени и им будут посвящены отдельные публикации.
TheOnlyPage
10.40
Company
Share post

Comments 0

Only users with full accounts can post comments. Log in, please.