Mar 19 2010

JS Call Later

Taki prosty skrypcik, umozliwiajacy wywolanie metody JavaScript z czasowym opoznieniem. Przydatne gdy chcemy na przyklad wyswietlic plywajacego diva 5 sekund po zaladowaniu strony, albo ukryc elementy widoku po 5 sekundach :)

Utworzmy klase obiektu dbajacego o wywolanie okreslonej metody po zadanym czasie a nastepnie sie zniszczy

loCallTimer = function(id, func, args, time)
{
	if (typeof(id) == "undefined") {
		return;
	}
	this.id = id;
	this.func = func || null;
	this.args = args || null;
	this.time = time || 1500;
	this.timer = null;
};
 
loCallTimer.prototype.suicide = function()
{
	this.stopTimer();
	eval("window.ct_" + this.id + " = null;");
};
 
loCallTimer.prototype.onTime = function()
{
	if (typeof(this.args) == "undefined" || this.args == null || this.args.length == 0) {
		this.func();
	} else {
		this.func.apply(this.func, this.args);
	}
	this.suicide();
};
 
loCallTimer.prototype.runTimer = function()
{
	this.stopTimer();
	this.timer = window.setTimeout("window.ct_" + this.id + ".onTime();", this.time);
};
 
loCallTimer.prototype.stopTimer = function()
{
	if (this.timer != null) {
		window.clearTimeout(this.timer);
		this.timer = null;
	}
};

Wyzwalacz

function callLater(func, args, time) {
    var id = (new Date()).getTime();
    var ct = eval("window.ct_" + id + " = new loCallTimer(" + id + ");");
    ct.func = func;
    ct.args = args;
    ct.time = time;
    ct.runTimer();
    return ct;
};

Testujemy
czytaj dalej


Mar 6 2010

JS dziedziczenie i override’y

Niby nie ma formalnie klas w JS, jednak mozemy stworzyc cos co mimo braku podzialu na obiekty prywatne, publiczne itd, bedzie wygladalo na klasy.

Na poczatek stworzmy nasza “klase” bazowa

// konstruktor klasy
BaseClass = function(name)
{
	this.name = name || "obj_" + (new Date()).getTime();
};
 
BaseClass.prototype.className = "BaseClass";
 
// instancja klasy BaseClass
var instanceOfBaseClass = new BaseClass();

w ten sposob mamy obiekt posiadajacy dwie wlasnosci name i className. Ta druga nie bedzie dziedziczona bezposrednio.

A teraz dziedziczenie.

DerivativeClass = function(name)
{
	this.super = BaseClass;
	this.super(name);
};
 
DerivativeClass.prototype = new BaseClass();
DerivativeClass.prototype.className = "DerivativeClass";
 
var instanceOfDerivativeClass = new DerivativeClass();

Po tym zabiegu instancja klasy DerivativeClass bedzie wygladac mniej wiecej tak

instanceOfDerivativeClass
	className = "DerivativeClass"
	name = "obj_1267912571913"
		super
			prototype
				className = "BaseClass"

Dzidziczenie? Jak najbardziej ;)

Teraz sprobujmy nadpisac funkcje bazowa init, na poczatek dodajmy ja
czytaj dalej


Feb 28 2010

Przerejestrowanie obiektow JS po zaladowaniu kontentu AJAX’em

Niewielka sprawa, jednak zabrala mi troche czasu. Ten przypadek wymagal dociagania skryptow JS w zaleznosci od zaladowanego kontentu (On Demand JS) lecz dostarczane obiekty mialy nazywac sie identycznie. Wazne bylo, aby metoda getAnswer obiektu Question zwracala odpowiednio sformatowane dane, w zaleznosci od wyswietlonego kontentu. Silnik ladowany byl po wejsciu na strone wraz z zawartoscia zawierajaca obiekty JS, logiczne wiec, ze parser je wczytal i zarejestrowal. Wymienny kontent zawieral override’y zaladowanych obiektow, ktore niestety nie rejestrowaly sie automatycznie.

Mamy wiec cos podobnego

Question = function()
{
	this.answer = null;
	{ body }
};
 
Question.prototype.getAnswer = function()
{
	if (this.answer != null) {
		return this.answer;
	} else {
		{ body }
	}
};

w kazdej dynamicznie dostarczanej zawartosci z ta roznica, ze { body } roznie formatowalo dane

Aby dzialalo to poprawnie, nalezy po wczytaniu kontentu AJAX’em zarejestrowac wczytane obiekty, a mozna to zrobic tak

function reloadScripts(id) {
	// pobieramy obiekt zawierajacy override'y
	var obj = document.getElementById(id);
	if (obj) {
		// wyciagamy tagi potencjalnie zawierajace skrypty JS
		var scripts = obj.getElementsByTagName("script");
		for (var i = 0; i < scripts.length; i++) {
			script = scripts[i].innerHTML;
			// rejestrujemy JS'y
			eval(script);
		}
	}
};

lub tak, jezeli dostarczamy jedynie JS’y

eval(ajax.xmlHttp.responseText);

Jak masz inny pomysl na rozwiazanie tego problemu … nie krepuj sie, daj komentsa :)


Nov 8 2009

Raportowanie bledow strony klienta

Back-end aplikacji webowej, mozna kontrolowac przegladajac raporty i logi, lecz nijak ma sie to do front-endu wyswietlanego po stronie klienta. Nie dowiemy sie czy i kiedy wystapi blad, dopoki jakis nawiedzony klient nie zwymysla nam do sluchawki, chyba, ze mamy 105 srodowisk testowych, na ktorych mozemy sprawdzic kazda funkcjonalnosc aplikacji.

I tutaj nasuwa sie pytanie, czy nie ma innej mozliwosci?
Sa, a to jedna z nich, dzieki asynchronicznym zapytaniom, raport o bledzie klienta trafi do back-endu, i zapisany zostanie, do bazki czy pliku logow.

Przechwytywanie bledow

1. Dodajemy wymagane pliki bibliotek

<script type="text/javascript" src="http://www.losoft.org/blog/download/ajax/loajax_v1.1.js"></script>

plik mozna pobrac z dzialu Download, albo zamiast klasy loAJAX, linkujemy wlasnego wrappera ajax.

2. Tworzymy metode akcyjna zdarzenia window.onerror

// on/off powiadomienie klienta o bledzie
var suppressErrors = true;
// nowy obiekt ajax
var ajax = new loAJAX(this, "http://www.losoft.org/blog/examples/ajax/errorreport.php", null, AJAX_POST);
// akcja zdarzenia onerror
function errorReport(msg, url, lineNumber)
{
	ajax.reset();
	ajax.addParam("msg", msg);
	ajax.addParam("url", url);
	ajax.addParam("lineNumber", lineNumber);
	ajax.request();
 
	if (suppressErrors) {
		return true;
	}
	alert("Error occurred: " + msg + "\nURL: " + url + "\nLine Number: " + lineNumber);
};

3. Podpiecie akcji

window.onerror = errorReport;

Jak mamy juz gotowa metode, to teraz … czytaj dalej


Oct 13 2009

Blokada wyjscia ze strony

Wyobrazmy sobie pania Jole, ktora plodzi cos przez godzine, nastepnie klika przycisk Odswiez i cala jej prace szlag trafia. Znajoma sytuacja? Dlatego tez czasem musimy zabezpieczyc dane uzytkownikow, przed nimi samymi.

Najlepsza metoda na zabezpieczenie wiekszosci takich przypadkow, tzn. wywolanie funkcji Wstecz, Dalej, Odswiez czy Strona domowa, jest podpiecie sie pod zdarzenie onbeforeunload i wyswietlenie stosownego komunikatu, aby user mial czas zastanowic sie czy na pewno chce zrobic to co robi.

Ustawiamy zmienna isChanged, okreslajaca czy dane, np. na formularzach, sa zmienione.

var isChanged = false;
function setIsChanged(value)
{
	isChanged = value;
};

Tworzymy metode wyladowania strony

function preventLostData(event)
{
	if (!event) event = window.event;
	if (isChanged) {
		if (window.navigator.appName == "Microsoft Internet Explorer") {
			event.cancelBubble = true;
		}
		event.returnValue = "Nacisnij \"Zapisz zmiany\", aby uchronic sie przed utrata danych.";
		if (event.stopPropagation) {
			event.stopPropagation();
			event.preventDefault();
		}
	}
};

Podlaczamy nasza metode pod zdarzenie wyladowania strony

window.onbeforeunload = preventLostData;

Aby zasymulowac zmiane danych utworzymy modyfikatory, umozliwiajace zmiane wartosci zmiennej isChanged.

<input type="button" value="Symuluj zmiany" onclick="setIsChanged(true);" />
<input type="button" value="Zapisz zmiany" onclick="setIsChanged(false);" />

Powyzszy przyklad chroni przed zmiana strony, zamknieciem zakladki a nawet calej przegladarki (Nie testowane w ie < 7, ale oL4c ten $h|t, 8).

Tutaj mozna potestowac:
czytaj dalej