Миналата седмица един клиент ни препрати код от EasyAds, чрез който да се активират реклами върху ключови думи в текста на сайта. Като оставим настрана самата идея половината думи в текста да станат рекламни връзки и на всичкото отгоре със досадни блокчета, които изскачат като минете с мишката върху тях, въпросният код ме накара няколко пъти да изразя възмущението си в Twitter.
Ще започна с това, че JavaScript-ът разчиташе на document.write(). Това е една ужасно лоша практика, за съжаление в арсенала на всички рекламни мрежи. Освен, че методът е нодопустим в XHTML страници, използването му за добавяне на елемент script води до забавяне (или дори блокиране) на зареждането на страницата докато се изтегли скриптът и съответно влошаване на потребителското изживяване.
Оригиналният скрипт изглежда така:
<script type="text/javascript"><!--//<![CDATA[
var dd=et=dc=ur=rf=sc=scr="";
var cb=0;
scr=screen;
dd=new Date();
dc=document;
et=dd.getTimezoneOffset()+dd.getTime();
sc=scr.width+"x"+scr.height;
cb=Math.round(Math.random()*21474836);
rf=escape(dc.referrer);
ur="ht"+"tp://media.easyads.bg/intext.php?rid=XXX&scr="+sc+"&et="+et+"&cb="+cb+"&rf="+rf+"&md5checksum=ZZZ";
dc.writeln("<sc"+"ript src=\""+ur+"\" type=\"text/jav"+"ascr"+"ipt\"></scr"+"ipt>");
//]]>--></script>
Как да се освободим от document.write() методът? Естествено чрез DOM:
<script type="text/javascript"><!--//<![CDATA[
var dd=et=dc=ur=rf=sc=scr="";
var cb=0;
scr=screen;
dd=new Date();
dc=document;
et=dd.getTimezoneOffset()+dd.getTime();
sc=scr.width+"x"+scr.height;
cb=Math.round(Math.random()*21474836);
rf=escape(dc.referrer);
ur="ht"+"tp://media.easyads.bg/intext.php?rid=XXX&scr="+sc+"&et="+et+"&cb="+cb+"&rf="+rf+"&md5checksum=ZZZ";
var sc = dc.createElement('script');
sc.src = ur;
var head = dc.getElementsByTagName('head')[0];
head.appendChild(sc);
//]]>--></script>
Тъй като в сайта използваме така или иначе jQuery, горния пример придобива малко по-прост вид:
<script type="text/javascript"><!--//<![CDATA[
var dd=et=dc=ur=rf=sc=scr="";
var cb=0;
scr=screen;
dd=new Date();
dc=document;
et=dd.getTimezoneOffset()+dd.getTime();
sc=scr.width+"x"+scr.height;
cb=Math.round(Math.random()*21474836);
rf=escape(dc.referrer);
ur="ht"+"tp://media.easyads.bg/intext.php?rid=XXX&scr="+sc+"&et="+et+"&cb="+cb+"&rf="+rf+"&md5checksum=ZZZ";
$(window).load(function(){
$.getScript(ur);
});
//]]>--></script>
Както виждате, никак не е трудно въпросният скрипт с динамично генериран адрес да се добави към страницата така, че да не се блокира зареждането на страницата. Повече по въпроса можете да прочетете в тази статия на Стоян в YUIBlog.
Следващият проблем в рекламите на EasyAds беше с изискванията им за кода на страницата, за да работи техния скрипт. Според тях текстът, в който искаме да има реклами, трябва да бъде заграден от <div class="EasyadsIntext">
. Чудесно, при нас текстът е заграден от div
, който вече има клас, добавих и техния клас и… йок! За да работи чудото, елементът трябва да е изписан така, както е показано в техния пример – не може да има други класове. Естествено, че полудях! Толкова ли е трудно да намериш всички елементи в DOM, които имат даден клас? Естествено че не, не ставай смешен! Методът се нарича getElementsByClassName
и се поддържа от всички съвременни браузъри. За съжаление най-популярният браузър не е сред тях, но това не пречи за него да напишем малка функцийка, която да върши необходимата работа.
И така, в кода на EasyAds намирам следната функция:
function getElementsByStyleClass (className){
var all = document.all ? document.all : document.getElementsByTagName('*');
var elements = new Array();
for (var e = 0; e < all.length; e++)
if (all[e].className == className) elements[elements.length] = all[e];
return elements;
}
Доста първичен подход към задачата. Аз като мързелив човек се поразрових и естествено попаднах на статия на Робърт Нийман, в която той дава работещо решение. Неговата функция е доста по-пълна откъм функционалност, но по-важното е, че използва DOM методът, когато е наличен в браузъра и по този начин работи много по-бързо за повечето потребители. Задължително прочетете и коментарите под тази публикация на PPK, макар и стари, има доста полезна информация.
Третият проблем, който имах с EasyAds се дължеше на факта, че пробвах скрипта на тестовия ни сървър. Работата е там, че той е с адрес напълно различен от този на работещия сайт и явно EasyAds проверяват от къде правите заявката. Нищо лошо, обаче начинът да ви информира, че нещо не е наред, беше следния:
document.write('Error');
Веднага си спомних кое е първото нещо, което един уеб-разработчит трябва да може според Ники Бачийски. И ако не сте разбрали защо, това е един чудесен пример. След като на страницата нищо не се случи, първо проверих с Firebug дали има заявка към сървъра на EasyAds. Да, имаше заявка и всичко с нея беше наред, статус 200. Тогава проверих и съдържанието на отговора. Нямаше ли да е по-добре, ако при некоректна заявка сървърът връщаше подходящ статус? Например 400 или 403? Тогава браузърът ще знае, че заявката е неуспешна и няма да изпълни нищо, което от своя страна няма да доведе до промяна в съдържаниет на страницата. Ако не знаете какво означава кодовете за статус на HTTP протокола, описани са в RFC 2616.
Етикети: DOM, HTTP, javascript
Аз им се чудя на разхвърляния код, всичко може да се събере на 2 реда ;)
Е той кода беше на 1 ред, ама не се чете така, та го подредих малко. Докато им издиря функцията getElementsByStyleClass ква мъка беше…
Те естествено са го сложили на един ред, за да е трудно за четене разбира се. Стандартна техника. Статията е наистина добра… Може и аз да се възползвам скоро.
Аз да попитам рискуваме ли бан от мрежата, ако променяме кода.
Или няма проблеми, зашото се чудя
Просто си нямаш напредстава колко ми трябваше!А относно въпроса на георги?
@Георги, не виждам причина да те отрежат, тъй като промените по никакъв начин не променят начина на работа на системата. Промяната е единствено в начина на зареждане на скрипта. А и до сега сайтовете, в които работи променения код си показват рекламите без проблем.