Michał Wachowski programista php & webdeveloper

Blog

Prototype.js - własne selektory

Zainspirowany wpisem na blogu Kamila B., a dokładniej fanboy'owskimi komentarzami, postanowiłem sprawdzić jak się ma sprawa z własnymi selektorami dla prototype.js. W końcu oba (jQuery i prototype) mają wspólny silnik - Sizzle.Toteż wpis będzie porównaniem tego jak wygląda sytuacja w jQuery i w mojej ulubionej bibliotece.

By dodać własny selektor w jQuery autorzy jak zwykle poszli na rękę (wg mnie porządnie na nią nadepneli) i dali do tego specjalną metodę. Cztery argumenty, z czego dwa są tablicami... po co?

$.expr[':'].mySelector = function(objNode, intStackIndex, arrProperties, arrNodeStack) {
		// implementacja selektora
};

W prototypie implementacja jest prostsza i można z powodzeniem korzystać z dokumentacji Sizzle, z tą różnicą, że w dokumentacji piszą Sizzle.foo, a w prototype pisać pełną ścieżkę gdzie Sizzle się znajduje Prototype.Selector.engine.selectors.foo. Dla jasności - dotyczy nas Extension Api.

Kamil na swoim blogu w ramach przykładu tworzył pseudoselektor :external, wykonującego co następuje:

  • Tylko obiekty a lub link
  • z atrybutem rel="external"
  • z wpisanym atrybutem href
  • prowadzące do zewnętrznej domeny

Więc, by stworzyć dla prototype taki pseudoselektor trzeba dodać do Sizzle filtr sprawdzający czy element spełnia nasze warunki.

Prototype.Selector.engine.selectors.filters.external = function(elem) {
	return elem.tagName.match(/^a|link$/i) && elem.href && elem.rel.match(/external/i) && elem.href.search(window.location.hostname) === -1;
};

Była definicja i wywołanie mające wykonać usuń wszystkie linki zewnętrzne, które prowadzą do Twittera lub Google+:

$$('a:external[href*=plus.google.com]', 'a:external[href*=twitter.com]').invoke('remove');

Jeśli trzeba zrobić selektor bardziej rozbudowany, można z powodzeniem korzystać z normalnej składni prototype, obiekt przekazywany do filtra jest już rozszerzony.
Przykładowo, pseudoselektor :visible, który zwraca widoczne elementy. Gdzie widoczne należy rozumieć jako znajdujące się obecnie w oknie przeglądarki i nie będące w jakiś sposób ukryte.

Prototype.Selector.engine.selectors.filters.visible = function(elem) {
	if(elem.style.display == 'none' || elem.style.visibility == 'hidden' || elem.style.opacity == 0) {
		return false;
	}

	var view = [document.viewport.getDimensions ['width'], document.viewport.getDimensions ['height']];
	var offsets = document.viewport.getScrollOffsets ;
	var pos = elem.viewportOffset ;

	if(pos[0] >= offsets[0] && pos[0] <= offsets[0]+view[0] && pos[1] >= offsets[1] && pos[1] <= offsets[1]+view[1]) {
		return true;
	}

	return false;
};

I na koniec ciekawostka - jeśli nie podoba ci się Sizzle w prototype.js - można bez problemu wymienić mechanizm selektorów na inny.

Komentarze

  1. Piotrek Reinmar Koszuliński Piotrek Reinmar Koszuliński

    > I na koniec ciekawostka - jeśli nie podoba ci się Sizzle w prototype.js - można bez problemu wymienić mechanizm selektorów na inny.
    Ciekawsza opcja, to w ogóle wywalenie tego silnika. Korzystanie w JS z zaawansowanych selektorów, to mocny bezsens, podstawowe da się wesprzeć w 50 liniach JS, a jakoś nie powstała wciąż żadna lekka biblioteka (D|B)OM-owa. Ciągle tylko (poza Zepto) te toporne, wszystko robiące potwory. Jeden większy od drugiego. A ja przez ponad 4 lata skorzystałem może z 50% API Prototype'a. W jQuery wyszłoby pewnie jeszcze mniej. I jeszcze to bezsensowne wsparcie dla archaicznych przeglądarek. Oczywiście czasami jest potrzeba ich wspierania. Ale coraz więcej projektów nie ma takiej potrzeby, a ciągle widzę "IE6+" i mnie skręca.

    Odpowiedz
  2. Piotrek Reinmar Koszuliński Piotrek Reinmar Koszuliński

    BTW. przeraźliwie małego fonta tu użyłeś. Tak ze 2px do góry by się przydały, bo musiałem dwa razy dać ctrl++

    Odpowiedz
  3. wachowski.michal@

    Arial 12px mały? ;) (wcześniej była 11)

    Odpowiedz
  4. Kamil Kamil

    @Piotrek
    Na dobrą sprawę to można całkowicie olać jakąkolwiek bibliotekę, jeśli nie potrzebujemy wspierać starszych przeglądarek i chcemy korzystać wyłącznie z selektorów zaproponowanych przez W3C (http://www.w3.org/TR/selectors-api/) - wystarczy querySelectorAll, o czym pewnie wiesz. Choć nawet i tutaj można wykrywać querySelectorAll i w razie potrzeby dynamicznie ładować Sizzle, więc nie dziwię się, że jeszcze nie powstała dodatkowa biblioteka :P
    Michał, już to chyba pisałem - ładnie to rozwiązali w Prototype. Niemniej jQuery, mimo brzydkiego API w tym przypadku, nadrabia w innych miejscach :-) Poza tym kwestia przyzwyczajenia - jeden woli jQuery, inny Prototype. Nie widzę jakichś szczególnie powodów, dla których miałbym przerzucać się na Prototype - co oferuje Prototype, czego nie ma jQuery? :)

    Odpowiedz
  5. wachowski.michal@

    Odpowiem niegrzecznie - co ma jQuery czego nie ma prototype.
    Bo czego nie ma jQuery, można zobaczyć choćby w dokumentacji.

    Odpowiedz
  6. Kamil Kamil

    Musiałbym znać obie biblioteki w doskonałym stopniu, a niestety na prototype nigdy nie starcza mi czasu - mówiąc więc najogólniej, nie mam co się wypowiadać w temacie :) Mi jednak jQuery wystarcza w zupełności.

    Odpowiedz

Dodaj komentarz