Weboldal "AJAX"-osítása egyszerűen 2
Tovább gondolkodtam a Weboldal “AJAX”-osítása egyszerűen bejegyzéssel kapcsolatban, és rájöttem, hogy maradt pár hiányosság, amit nem kezeltem le. Az egyik ilyen az, hogy mi van akkor ha a linkek nem a gyökértől indulnak, a másik pedig az, hogy mi van, ha <base>
elemet használnak az oldalon. Most ezeket is megoldom, és szerintem egy eléggé szép, ugyanakkor majd minden problémára kiterjedő megoldást találtam.
Az egyik probléma, ha <a href="blog.html">Blog</a>
jellegű linkeket használnak az oldalon, azaz az linkelt oldal URL-je a mostanihoz képest relatív. Ezt úgy küszöbölhetjük ki, hogy ha ilyen linkekkel találkozunk, akkor azokat átalakítjuk a megfelelő formára. És ha már itt vagyunk, akkor az abszolút URL-lel megadott linkeket is átalakítjuk, így később már csak egyetlen esetet kell kezelni. Ezzel nem csorbul a használhatóság, csupán közös formára hoztuk az összeset.
Ezzel kapcsolatban eszembe jutott, hogy mi van akkor, ha az oldalon <base>
elemmel befolyásolják ezen URL-eket. A <base href="http://example.com/blog/">
elem annyit tesz, hogy a <a href="blog.html">Blog</a>
formában megadott linkek a <base>
által megszabott URLhez képest relatívak, míg <base>
nélkül pedig az aktuális oldalhoz képest lennének relatívak. Ami még előjött probléma ezzel kapcsolatban, hogy mit tekintünk aktuális oldalnak.
Amennyiben még nem volt AJAX eseményünk, akkor az aktuális oldal a tényleges aktuális oldal, míg ha volt, akkor a tárolónkon belüli a tároló maga lesz az. Mint látszik ez eléggé megbonyolította a kód működését, ezért majdnem az egészet teljesen újra kellett építeni. Készítettem is két segédfüggvényt. Az egyik megnézi, hogy van-e <base>
elem a megadott elemben, és ha igen, akkor annak visszaadja a belső részét. Ebből csinálhattam volna egyszerűen egy jQuery kiegészítőt, de nem éreztem szükségét. A másik pedig az átadott elemben átalakítja a linkeket, hogy azok a gyökérhez képest relatívak legyenek.
Igazából csak ezek változtak, többi működés nagyjából maradt a régi, de kód szintjén így is nagyok a változások.
jQuery(function ($) {
var reInternal = $.urlInternalRegExp(),
id = '#main',
tag = 'a',
title = document.title,
l = window.location,
baseRe = /[^\/]+$/,
body = $(document.body),
// Az alap URL lekérdezése, amennyiben van <base> elem.
getBase = function (elem) {
var docBase = elem.find('head > base[href]'),
match = docBase.length && docBase.attr('href').match(reInternal);
if (match) {
return match[1];
}
},
base = getBase(body) || l.pathname.replace(baseRe, ''), // Relatív URN
containerBase = base, // A tároló relatív URNje
container = $(id), // A tároló
defaultValue = container.html(), // Eltároljuk az eredetit
// Az elem összes linkjét relativvá tesszük a gyökértől.
makeRelative = function (elem) {
elem.find(tag + ':urlInternal(href)').attr('href', function (index, href) {
var match, urn, link = this;
// jQuery 1.3 támogatás
if (typeof href === 'undefined') {
href = $(this).attr('href');
}
// Megnézzük hogy abszolút URI-nek van-e álcázva,
// ha igen, akkor leszedjük róla az abszolút részt.
match = href.match(reInternal);
if (match) {
urn = href.substring(match[0].length - 1);
}
else if (href.charAt(0) === '/') {
// A domainhez képest abszolút
urn = href;
}
else {
// Az aktuális oldalhoz képest relativ
urn = (container.find(tag).filter(function () {
return this === link;
}).length ? containerBase : base) + href;
}
return urn;
});
};
// Bármilyen linkre kattintunk, lekezeljük
$(tag).live('click', function (event) {
var link = $(this),
href = link.attr('href');
// Ha a link belső URL, akkor ahelyett hogy odaugranánk,
// csak megváltoztatjuk a hash-t.
if ($.isUrlInternal(href)) {
// Megváltoztatjuk a hash-t az URI-re
l.hash = '!' + href.replace(/#.*/, '');
// Megakadályozzuk az eseményt.
event.preventDefault();
}
});
// Kezeljük a megváltozott hash eseményt, és kiváltjuk is, hátha már van hash.
$(window).hashchange(function (e) {
var hash = l.hash,
match = hash && hash.match(/^#?!(\/.*)/),
urn = match && match[1];
// Ha megfelelő formátumú a hash, akkor betöltjük a tartalmat a tárolóba.
if (urn) {
// A gyermekekre van csak szükségünk.
$.get(urn, function (data) {
var rscript = /<script(.|\s)*?\/script>/gi, // Script elemek nem maradnak
page = jQuery("<div />").append(data.replace(rscript, "")),
// Betöltődött a tartalom, megnézzük van-e cím, és frissítjük az oldal címét
containerBase = getBase(page) || urn.replace(baseRe, '');
document.title = page.find('head > title').text() ||
page.find('h1:first').text() || title;
makeRelative(container.html(page.find(id).html()));
});
}
else if (!hash || hash === '#') {
// Visszaállítjuk az eredeti tartalmat
container.html(defaultValue);
}
}).hashchange();
// Módosítjuk a linkeket, hogy relatívok legyenek
makeRelative(body);
});
A működés megtekinthető a tesztoldalon.
comments powered by Disqus