Index: /trunk/themes/default/js/rating.js
===================================================================
--- /trunk/themes/default/js/rating.js	(revision 7956)
+++ /trunk/themes/default/js/rating.js	(revision 7957)
@@ -3,5 +3,5 @@
 function makeNiceRatingForm(options)
 {
-	gRatingOptions = options || {};
+	gRatingOptions = options;
 	var form = document.getElementById('rateForm');
 	if (!form) return; //? template changed
@@ -37,12 +37,9 @@
 
 		pwgAddEventListener(rateButton, "click", updateRating);
-		pwgAddEventListener(rateButton, "mouseout", resetRatingStarDisplay);
-		pwgAddEventListener(rateButton, "mouseover", updateRatingStarDisplayEvt);
+		pwgAddEventListener(rateButton, "mouseout", function() {updateRatingStarDisplay( gUserRating );});
+		pwgAddEventListener(rateButton, "mouseover", function(e) {
+			updateRatingStarDisplay( e.target ? e.target.initialRateValue : e.srcElement.initialRateValue);
+			});
 	}
-	resetRatingStarDisplay();
-}
-
-function resetRatingStarDisplay()
-{
 	updateRatingStarDisplay( gUserRating );
 }
@@ -52,10 +49,4 @@
 	for (var i=0; i<gRatingButtons.length; i++)
 		gRatingButtons[i].className = (userRating!=="" && userRating>=gRatingButtons[i].initialRateValue ) ? "rateButtonStarFull" : "rateButtonStarEmpty";
-}
-
-function updateRatingStarDisplayEvt(e)
-{
-	updateRatingStarDisplay(
-		e.target ? e.target.initialRateValue : e.srcElement.initialRateValue);
 }
 
@@ -91,2 +82,15 @@
 	return false;
 }
+
+(function() {
+if (typeof _pwgRatingAutoQueue!="undefined" && _pwgRatingAutoQueue.length)
+{
+    for (var i=0; i<_pwgRatingAutoQueue.length; i++)
+        makeNiceRatingForm(_pwgRatingAutoQueue[i]);
+}
+_pwgRatingAutoQueue = {
+	push: function(opts) {
+		makeNiceRatingForm(opts);
+	}
+}
+})();
Index: /trunk/themes/default/js/scripts.js
===================================================================
--- /trunk/themes/default/js/scripts.js	(revision 7956)
+++ /trunk/themes/default/js/scripts.js	(revision 7957)
@@ -22,10 +22,11 @@
 }
 
-Function.prototype.pwgBind = function() {
-		var __method = this, object = arguments[0], args = Array.prototype.slice.call(arguments,1);
-		return function() {
-				return __method.apply(object, args.concat(arguments) );
-		}
+function pwgBind(object, method) {
+	var args = Array.prototype.slice.call(arguments,2);
+	return function() {
+			return method.apply(object, args.concat(Array.prototype.slice.call(arguments,0)) );
+	}
 }
+
 function PwgWS(urlRoot)
 {
@@ -40,23 +41,23 @@
 
 PwgWS.prototype = {
-
 	callService : function(method, parameters, options)
 	{
 		if (options)
 		{
-			for (var property in options)
-				this.options[property] = options[property];
+			for (var prop in options)
+				this.options[prop] = options[prop];
 		}
-		try { this.transport = new XMLHttpRequest();}
+		try { this.xhr = new XMLHttpRequest();}
 		catch(e) {
-			try { this.transport = new ActiveXObject('Msxml2.XMLHTTP'); }
+			try { this.xhr = new ActiveXObject('Msxml2.XMLHTTP'); }
 			catch(e) {
-				try { this.transport = new ActiveXObject('Microsoft.XMLHTTP'); }
+				try { this.xhr = new ActiveXObject('Microsoft.XMLHTTP'); }
 				catch (e){
-					dispatchError(0, "Cannot create request object");
+					this.error(0, "Cannot create request object");
+					return;
 				}
 			}
 		}
-		this.transport.onreadystatechange = this.onStateChange.pwgBind(this);
+		this.xhr.onreadystatechange = pwgBind(this, this.onStateChange);
 
 		var url = this.urlRoot+"ws.php?format=json";
@@ -65,80 +66,90 @@
 		if (parameters)
 		{
-			for (var property in parameters)
+			for (var prop in parameters)
 			{
-				if ( typeof parameters[property] == 'object' && parameters[property])
+				if ( typeof parameters[prop] == 'object' && parameters[prop])
 				{
-					for (var i=0; i<parameters[property].length; i++)
-						body += "&"+property+"[]="+encodeURIComponent(parameters[property][i]);
+					for (var i=0; i<parameters[prop].length; i++)
+						body += "&"+prop+"[]="+encodeURIComponent(parameters[prop][i]);
 				}
 				else
-					body += "&"+property+"="+encodeURIComponent(parameters[property]);
+					body += "&"+prop+"="+encodeURIComponent(parameters[prop]);
 			}
 		}
 
 		if (this.options.method == "POST" )
-		{
-			this.transport.open(this.options.method, url, this.options.async);
-			this.transport.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-			this.transport.send(body);
-		}
+			this.xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 		else
 		{
 			url += "&"+body;
-			this.transport.open(this.options.method, url, this.options.async);
-			this.transport.send(null);
+			body = null;
+		}
+		this.xhr.open(this.options.method, url, this.options.async);
+		try {
+			this.xhr.send(body);
+		} catch(e) {
+			this.error(0, e.message);
 		}
 	},
 
 	onStateChange: function() {
-		var readyState = this.transport.readyState;
+		var readyState = this.xhr.readyState;
 		if (readyState==4)
-			this.respondToReadyState(readyState);
+		{
+			try {
+				this.respondToReadyState(readyState);
+			} finally {
+				this.cleanup();
+			}
+		}
 	},
 
-	dispatchError: function( httpCode, text )
+	error: function( httpCode, text )
 	{
 		!this.options.onFailure || this.options.onFailure( httpCode, text);
+		this.cleanup();
 	},
 
 	respondToReadyState: function(readyState)
 	{
-		var transport = this.transport;
-		if (readyState==4 && transport.status == 200)
+		var xhr = this.xhr;
+		if (readyState==4 && xhr.status == 200)
 		{
 			var resp;
 			try {
-				eval('resp = ' + transport.responseText);
+				resp = window.JSON && window.JSON.parse ? window.JSON.parse( xhr.responseText ) : (new Function("return " + xhr.responseText))();
 			}
 			catch (e) {
-				this.dispatchError( 200, e.message + '\n' + transport.responseText.substr(0,512) );
+				this.error( 200, e.message + '\n' + xhr.responseText.substr(0,512) );
 			}
 			if (resp!=null)
 			{
 				if (resp.stat==null)
-					this.dispatchError( 200, "Invalid response" );
+					this.error( 200, "Invalid response" );
 				else if (resp.stat=='ok')
-				{
-					if (this.options.onSuccess) this.options.onSuccess( resp.result );
-				}
+					!this.options.onSuccess || this.options.onSuccess( resp.result );
 				else
-					this.dispatchError( 200, resp.err + " " + resp.message);
+					this.error( 200, resp.err + " " + resp.message);
 			}
 		}
-		if (readyState==4 && transport.status != 200)
-			this.dispatchError( transport.status, transport.statusText );
+		if (readyState==4 && xhr.status != 200)
+			this.error( xhr.status, xhr.statusText );
 	},
 
+	cleanup: function()
+	{
+		if (this.xhr) this.xhr.onreadystatechange = null;
+		this.xhr = null;
+		this.options.onFailure = this.options.onSuccess = null;
+	},
 
-	transport: null,
-	urlRoot: null,
-	options: {}
+	xhr: null
 }
 
 function pwgAddEventListener(elem, evt, fn)
 {
-	if (window.attachEvent)
-		elem.attachEvent('on'+evt, fn);
+	if (window.addEventListener)
+		elem.addEventListener(evt, fn, false);
 	else
-		elem.addEventListener(evt, fn, false);
+		elem.attachEvent('on'+evt, fn);		
 }
Index: /trunk/themes/default/template/picture.tpl
===================================================================
--- /trunk/themes/default/template/picture.tpl	(revision 7956)
+++ /trunk/themes/default/template/picture.tpl	(revision 7957)
@@ -209,9 +209,13 @@
 			{/if}
 			{/foreach}
-			<script type="text/javascript" src="{$ROOT_URL}themes/default/js/rating.js"></script>
 			<script type="text/javascript">
-			makeNiceRatingForm( {ldelim}rootUrl: '{$ROOT_URL|@escape:"javascript"}', image_id: {$current.id},
-			updateRateText: "{'Update your rating'|@translate|@escape:'javascript'}", updateRateElement: document.getElementById("updateRate"),
-			ratingSummaryText: "{'%.2f (rated %d times)'|@translate|@escape:'javascript'}", ratingSummaryElement: document.getElementById("ratingSummary") {rdelim} );
+				var _pwgRatingAutoQueue = _pwgRatingAutoQueue || [];
+				_pwgRatingAutoQueue.push(  {ldelim}rootUrl: '{$ROOT_URL|@escape:"javascript"}', image_id: {$current.id},
+					updateRateText: "{'Update your rating'|@translate|@escape:'javascript'}", updateRateElement: document.getElementById("updateRate"),
+					ratingSummaryText: "{'%.2f (rated %d times)'|@translate|@escape:'javascript'}", ratingSummaryElement: document.getElementById("ratingSummary") {rdelim} );
+				(function () {ldelim}
+				var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true; s.src = '{$ROOT_URL}themes/default/js/rating.js';
+				var s0 = document.getElementsByTagName('script')[0]; s0.parentNode.insertBefore(s, s0);
+				})();
 			</script>
 			</div>
