﻿/*
 @Ajax类，主要目的是完成前台和后台页的交互
 @作者: samfeng
 @日期: 2008-06-06 09:59:02.983
*/


/*
Script: Fx.Base.js
	Contains <Fx.Base>, the foundamentals of the MooTools Effects.

License:
	MIT-style license.
*/

var Fx = {};

/*
Class: Fx.Base
	Base class for the Effects.

Options:
	transition - the equation to use for the effect see <Fx.Transitions>; default is <Fx.Transitions.Sine.easeInOut>
	duration - the duration of the effect in ms; 500 is the default.
	unit - the unit is 'px' by default (other values include things like 'em' for fonts or '%').
	wait - boolean: to wait or not to wait for a current transition to end before running another of the same instance. defaults to true.
	fps - the frames per second for the transition; default is 50
	
Events:
	onStart - the function to execute as the effect begins; nothing (<Class.empty>) by default.
	onComplete - the function to execute after the effect has processed; nothing (<Class.empty>) by default.
	onCancel - the function to execute when you manually stop the effect.
*/

Fx.Base = new Class({

	options: {
		onStart: Class.empty,
		onComplete: Class.empty,
		onCancel: Class.empty,
		transition: function(p){
			return -(Math.cos(Math.PI * p) - 1) / 2;
		},
		duration: 500,
		unit: 'px',
		wait: true,
		fps: 50
	},

	initialize: function(options){
		this.element = this.element || null;
		this.setOptions(options);
		if (this.options.initialize) this.options.initialize.call(this);
	},

	step: function(){
		var time = $time();
		if (time < this.time + this.options.duration){
			this.delta = this.options.transition((time - this.time) / this.options.duration);
			this.setNow();
			this.increase();
		} else {
			this.stop(true);
			this.set(this.to);
			this.fireEvent('onComplete', this.element, 10);
			this.callChain();
		}
	},

	/*
	Property: set
		Immediately sets the value with no transition.

	Arguments:
		to - the point to jump to

	Example:
		>var myFx = new Fx.Style('myElement', 'opacity').set(0); //will make it immediately transparent
	*/

	set: function(to){
		this.now = to;
		this.increase();
		return this;
	},

	setNow: function(){
		this.now = this.compute(this.from, this.to);
	},

	compute: function(from, to){
		return (to - from) * this.delta + from;
	},

	/*
	Property: start
		Executes an effect from one position to the other.

	Arguments:
		from - integer: staring value
		to - integer: the ending value

	Examples:
		>var myFx = new Fx.Style('myElement', 'opacity').start(0,1); //display a transition from transparent to opaque.
	*/

	start: function(from, to){
		if (!this.options.wait) this.stop();
		else if (this.timer) return this;
		this.from = from;
		this.to = to;
		this.change = this.to - this.from;
		this.time = $time();
		this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
		this.fireEvent('onStart', this.element);
		return this;
	},

	/*
	Property: stop
		Stops the transition.
	*/

	stop: function(end){
		if (!this.timer) return this;
		this.timer = $clear(this.timer);
		if (!end) this.fireEvent('onCancel', this.element);
		return this;
	}/*compatibility*/,
	
	custom: function(from, to){
		return this.start(from, to);
	},

	clearTimer: function(end){
		return this.stop(end);
	}

	/*end compatibility*/

});

Fx.Base.implement(new Chain, new Events, new Options);

/*
Script: Fx.CSS.js
	Css parsing class for effects. Required by <Fx.Style>, <Fx.Styles>, <Fx.Elements>. No documentation needed, as its used internally.

License:
	MIT-style license.
*/

Fx.CSS = {

	select: function(property, to){
		if (property.test(/color/i)) return this.Color;
		var type = $type(to);
		if ((type == 'array') || (type == 'string' && to.contains(' '))) return this.Multi;
		return this.Single;
	},

	parse: function(el, property, fromTo){
		if (!fromTo.push) fromTo = [fromTo];
		var from = fromTo[0], to = fromTo[1];
		if (!$chk(to)){
			to = from;
			from = el.getStyle(property);
		}
		var css = this.select(property, to);
		return {'from': css.parse(from), 'to': css.parse(to), 'css': css};
	}

};

Fx.CSS.Single = {

	parse: function(value){
		return parseFloat(value);
	},

	getNow: function(from, to, fx){
		return fx.compute(from, to);
	},

	getValue: function(value, unit, property){
		if (unit == 'px' && property != 'opacity') value = Math.round(value);
		return value + unit;
	}

};

Fx.CSS.Multi = {

	parse: function(value){
		return value.push ? value : value.split(' ').map(function(v){
			return parseFloat(v);
		});
	},

	getNow: function(from, to, fx){
		var now = [];
		for (var i = 0; i < from.length; i++) now[i] = fx.compute(from[i], to[i]);
		return now;
	},

	getValue: function(value, unit, property){
		if (unit == 'px' && property != 'opacity') value = value.map(Math.round);
		return value.join(unit + ' ') + unit;
	}

};

Fx.CSS.Color = {

	parse: function(value){
		return value.push ? value : value.hexToRgb(true);
	},

	getNow: function(from, to, fx){
		var now = [];
		for (var i = 0; i < from.length; i++) now[i] = Math.round(fx.compute(from[i], to[i]));
		return now;
	},

	getValue: function(value){
		return 'rgb(' + value.join(',') + ')';
	}

};

/*
Script: Fx.Style.js
	Contains <Fx.Style>

License:
	MIT-style license.
*/

/*
Class: Fx.Style
	The Style effect, used to transition any css property from one value to another. Includes colors.
	Colors must be in hex format.
	Inherits methods, properties, options and events from <Fx.Base>.

Arguments:
	el - the $(element) to apply the style transition to
	property - the property to transition
	options - the Fx.Base options (see: <Fx.Base>)

Example:
	>var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
	>marginChange.start(10, 100);
*/

Fx.Style = Fx.Base.extend({

	initialize: function(el, property, options){
		this.element = $(el);
		this.property = property;
		this.parent(options);
	},

	/*
	Property: hide
		Same as <Fx.Base.set> (0); hides the element immediately without transition.
	*/

	hide: function(){
		return this.set(0);
	},

	setNow: function(){
		this.now = this.css.getNow(this.from, this.to, this);
	},

	/*
	Property: set
		Sets the element's css property (specified at instantiation) to the specified value immediately.

	Example:
		(start code)
		var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
		marginChange.set(10); //margin-top is set to 10px immediately
		(end)
	*/

	set: function(to){
		this.css = Fx.CSS.select(this.property, to);
		return this.parent(this.css.parse(to));
	},

	/*
	Property: start
		Displays the transition to the value/values passed in

	Arguments:
		from - (integer; optional) the starting position for the transition
		to - (integer) the ending position for the transition

	Note:
		If you provide only one argument, the transition will use the current css value for its starting value.

	Example:
		(start code)
		var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
		marginChange.start(10); //tries to read current margin top value and goes from current to 10
		(end)
	*/

	start: function(from, to){
		if (this.timer && this.options.wait) return this;
		var parsed = Fx.CSS.parse(this.element, this.property, [from, to]);
		this.css = parsed.css;
		return this.parent(parsed.from, parsed.to);
	},

	increase: function(){
		this.element.setStyle(this.property, this.css.getValue(this.now, this.options.unit, this.property));
	}

});

/*
Class: Element
	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
*/

Element.extend({

	/*
	Property: effect
		Applies an <Fx.Style> to the Element; This a shortcut for <Fx.Style>.

	Arguments:
		property - (string) the css property to alter
		options - (object; optional) key/value set of options (see <Fx.Style>)

	Example:
		>var myEffect = $('myElement').effect('height', {duration: 1000, transition: Fx.Transitions.linear});
		>myEffect.start(10, 100);
		>//OR
		>$('myElement').effect('height', {duration: 1000, transition: Fx.Transitions.linear}).start(10,100);
	*/

	effect: function(property, options){
		return new Fx.Style(this, property, options);
	}

});


/*
Script: Fx.Styles.js
	Contains <Fx.Styles>

License:
	MIT-style license.
*/

/*
Class: Fx.Styles
	Allows you to animate multiple css properties at once;
	Colors must be in hex format.
	Inherits methods, properties, options and events from <Fx.Base>.

Arguments:
	el - the $(element) to apply the styles transition to
	options - the fx options (see: <Fx.Base>)

Example:
	(start code)
	var myEffects = new Fx.Styles('myElement', {duration: 1000, transition: Fx.Transitions.linear});

	//height from 10 to 100 and width from 900 to 300
	myEffects.start({
		'height': [10, 100],
		'width': [900, 300]
	});

	//or height from current height to 100 and width from current width to 300
	myEffects.start({
		'height': 100,
		'width': 300
	});
	(end)
*/

Fx.Styles = Fx.Base.extend({

	initialize: function(el, options){
		this.element = $(el);
		this.parent(options);
	},

	setNow: function(){
		for (var p in this.from) this.now[p] = this.css[p].getNow(this.from[p], this.to[p], this);
	},

	set: function(to){
		var parsed = {};
		this.css = {};
		for (var p in to){
			this.css[p] = Fx.CSS.select(p, to[p]);
			parsed[p] = this.css[p].parse(to[p]);
		}
		return this.parent(parsed);
	},

	/*
	Property: start
		Executes a transition for any number of css properties in tandem.

	Arguments:
		obj - an object containing keys that specify css properties to alter and values that specify either the from/to values (as an array) or just the end value (an integer).

	Example:
		see <Fx.Styles>
	*/

	start: function(obj){
		if (this.timer && this.options.wait) return this;
		this.now = {};
		this.css = {};
		var from = {}, to = {};
		for (var p in obj){
			var parsed = Fx.CSS.parse(this.element, p, obj[p]);
			from[p] = parsed.from;
			to[p] = parsed.to;
			this.css[p] = parsed.css;
		}
		return this.parent(from, to);
	},

	increase: function(){
		for (var p in this.now) this.element.setStyle(p, this.css[p].getValue(this.now[p], this.options.unit, p));
	}

});

/*
Class: Element
	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
*/

Element.extend({

	/*
	Property: effects
		Applies an <Fx.Styles> to the Element; This a shortcut for <Fx.Styles>.

	Example:
		>var myEffects = $(myElement).effects({duration: 1000, transition: Fx.Transitions.Sine.easeInOut});
 		>myEffects.start({'height': [10, 100], 'width': [900, 300]});
	*/

	effects: function(options){
		return new Fx.Styles(this, options);
	}

});


/*
Script: Fx.Transitions.js
	Effects transitions, to be used with all the effects.

License:
	MIT-style license.

Credits:
	Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified & optimized to be used with mootools.
*/

/*
Class: Fx.Transitions
	A collection of tweening transitions for use with the <Fx.Base> classes.

Example:
	>//Elastic.easeOut with default values:
	>new Fx.Style('margin', {transition: Fx.Transitions.Elastic.easeOut});
	>//Elastic.easeOut with user-defined value for elasticity.
	> var myTransition = new Fx.Transition(Fx.Transitions.Elastic, 3);
	>new Fx.Style('margin', {transition: myTransition.easeOut});

See also:
	http://www.robertpenner.com/easing/
*/

Fx.Transition = function(transition, params){
	params = params || [];
	if ($type(params) != 'array') params = [params];
	return $extend(transition, {
		easeIn: function(pos){
			return transition(pos, params);
		},
		easeOut: function(pos){
			return 1 - transition(1 - pos, params);
		},
		easeInOut: function(pos){
			return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
		}
	});
};

Fx.Transitions = new Abstract({

	/*
	Property: linear
		displays a linear transition.

	Graph:
		(see Linear.png)
	*/

	linear: function(p){
		return p;
	}

});

Fx.Transitions.extend = function(transitions){
	for (var transition in transitions){
		Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
		/*compatibility*/
		Fx.Transitions.compat(transition);
		/*end compatibility*/
	}
};

/*compatibility*/

Fx.Transitions.compat = function(transition){
	['In', 'Out', 'InOut'].each(function(easeType){
		Fx.Transitions[transition.toLowerCase() + easeType] = Fx.Transitions[transition]['ease' + easeType];
	});
};

/*end compatibility*/

Fx.Transitions.extend({

	/*
	Property: Quad
		displays a quadratic transition. Must be used as Quad.easeIn or Quad.easeOut or Quad.easeInOut

	Graph:
		(see Quad.png)
	*/

	//auto generated

	/*
	Property: Cubic
		displays a cubicular transition. Must be used as Cubic.easeIn or Cubic.easeOut or Cubic.easeInOut

	Graph:
		(see Cubic.png)
	*/

	//auto generated

	/*
	Property: Quart
		displays a quartetic transition. Must be used as Quart.easeIn or Quart.easeOut or Quart.easeInOut

	Graph:
		(see Quart.png)
	*/

	//auto generated

	/*
	Property: Quint
		displays a quintic transition. Must be used as Quint.easeIn or Quint.easeOut or Quint.easeInOut

	Graph:
		(see Quint.png)
	*/

	//auto generated

	/*
	Property: Pow
		Used to generate Quad, Cubic, Quart and Quint.
		By default is p^6.

	Graph:
		(see Pow.png)
	*/

	Pow: function(p, x){
		return Math.pow(p, x[0] || 6);
	},

	/*
	Property: Expo
		displays a exponential transition. Must be used as Expo.easeIn or Expo.easeOut or Expo.easeInOut

	Graph:
		(see Expo.png)
	*/

	Expo: function(p){
		return Math.pow(2, 8 * (p - 1));
	},

	/*
	Property: Circ
		displays a circular transition. Must be used as Circ.easeIn or Circ.easeOut or Circ.easeInOut

	Graph:
		(see Circ.png)
	*/

	Circ: function(p){
		return 1 - Math.sin(Math.acos(p));
	},


	/*
	Property: Sine
		displays a sineousidal transition. Must be used as Sine.easeIn or Sine.easeOut or Sine.easeInOut

	Graph:
		(see Sine.png)
	*/

	Sine: function(p){
		return 1 - Math.sin((1 - p) * Math.PI / 2);
	},

	/*
	Property: Back
		makes the transition go back, then all forth. Must be used as Back.easeIn or Back.easeOut or Back.easeInOut

	Graph:
		(see Back.png)
	*/

	Back: function(p, x){
		x = x[0] || 1.618;
		return Math.pow(p, 2) * ((x + 1) * p - x);
	},

	/*
	Property: Bounce
		makes the transition bouncy. Must be used as Bounce.easeIn or Bounce.easeOut or Bounce.easeInOut

	Graph:
		(see Bounce.png)
	*/

	Bounce: function(p){
		var value;
		for (var a = 0, b = 1; 1; a += b, b /= 2){
			if (p >= (7 - 4 * a) / 11){
				value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b;
				break;
			}
		}
		return value;
	},

	/*
	Property: Elastic
		Elastic curve. Must be used as Elastic.easeIn or Elastic.easeOut or Elastic.easeInOut

	Graph:
		(see Elastic.png)
	*/

	Elastic: function(p, x){
		return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
	}

});

['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
	Fx.Transitions[transition] = new Fx.Transition(function(p){
		return Math.pow(p, [i + 2]);
	});
	
	/*compatibility*/
	Fx.Transitions.compat(transition);
	/*end compatibility*/
});


/*
Script: XHR.js
	Contains the basic XMLHttpRequest Class Wrapper.

License:
	MIT-style license.
*/

/*
Class: XHR
	Basic XMLHttpRequest Wrapper.

Arguments:
	options - an object with options names as keys. See options below.

Options:
	method - 'post' or 'get' - the protocol for the request; optional, defaults to 'post'.
	async - boolean: asynchronous option; true uses asynchronous requests. Defaults to true.
	encoding - the encoding, defaults to utf-8.
	autoCancel - cancels the already running request if another one is sent. defaults to false.
	headers - accepts an object, that will be set to request headers.
	
Events:
	onRequest - function to execute when the XHR request is fired.
	onSuccess - function to execute when the XHR request completes.
	onStateChange - function to execute when the state of the XMLHttpRequest changes.
	onFailure - function to execute when the state of the XMLHttpRequest changes.

Properties:
	running - true if the request is running.
	response - object, text and xml as keys. You can access this property in the onSuccess event.

Example:
	>var myXHR = new XHR({method: 'get'}).send('http://site.com/requestHandler.php', 'name=john&lastname=dorian');
*/

var XHR = new Class({

	options: {
		method: 'post',
		async: true,
		onRequest: Class.empty,
		onSuccess: Class.empty,
		onFailure: Class.empty,
		urlEncoded: true,
		encoding: 'utf-8',
		autoCancel: false,
		headers: {}
	},

	setTransport: function(){
		this.transport = (window.XMLHttpRequest) ? new XMLHttpRequest() : (window.ie ? new ActiveXObject('Microsoft.XMLHTTP') : false);
		return this;
	},

	initialize: function(options){
		this.setTransport().setOptions(options);
		this.options.isSuccess = this.options.isSuccess || this.isSuccess;
		this.headers = {};
		if (this.options.urlEncoded && this.options.method == 'post'){
			var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
			this.setHeader('Content-type', 'application/x-www-form-urlencoded' + encoding);
		}
		if (this.options.initialize) this.options.initialize.call(this);
	},

	onStateChange: function(){
		if (this.transport.readyState != 4 || !this.running) return;
		this.running = false;
		var status = 0;
		try {status = this.transport.status;} catch(e){};
		if (this.options.isSuccess.call(this, status)) this.onSuccess();
		else this.onFailure();
		this.transport.onreadystatechange = Class.empty;
	},

	isSuccess: function(status){
		return ((status >= 200) && (status < 300));
	},

	onSuccess: function(){
		this.response = {
			'text': this.transport.responseText,
			'xml': this.transport.responseXML
		};
		this.fireEvent('onSuccess', [this.response.text, this.response.xml]);
		this.callChain();
	},

	onFailure: function(){
		this.fireEvent('onFailure', this.transport);
	},

	/*
	Property: setHeader
		Add/modify an header for the request. It will not override headers from the options.

	Example:
		>var myXhr = new XHR(url, {method: 'get', headers: {'X-Request': 'JSON'}});
		>myXhr.setHeader('Last-Modified','Sat, 1 Jan 2005 05:00:00 GMT');
	*/

	setHeader: function(name, value){
		this.headers[name] = value;
		return this;
	},

	/*
	Property: send
		Opens the XHR connection and sends the data. Data has to be null or a string.

	Example:
		>var myXhr = new XHR({method: 'post'});
		>myXhr.send(url, querystring);
		>
		>var syncXhr = new XHR({async: false, method: 'post'});
		>syncXhr.send(url, null);
		>
	*/

	send: function(url, data){
		if (this.options.autoCancel) this.cancel();
		else if (this.running) return this;
		this.running = true;
		if (data && this.options.method == 'get'){
			url = url + (url.contains('?') ? '&' : '?') + data;
			data = null;
		}
		this.transport.open(this.options.method.toUpperCase(), url, this.options.async);
		this.transport.onreadystatechange = this.onStateChange.bind(this);
		if ((this.options.method == 'post') && this.transport.overrideMimeType) this.setHeader('Connection', 'close');
		$extend(this.headers, this.options.headers);
		for (var type in this.headers) try {this.transport.setRequestHeader(type, this.headers[type]);} catch(e){};
		this.fireEvent('onRequest');
		this.transport.send($pick(data, null));
		return this;
	},

	/*
	Property: cancel
		Cancels the running request. No effect if the request is not running.

	Example:
		>var myXhr = new XHR({method: 'get'}).send(url);
		>myXhr.cancel();
	*/

	cancel: function(){
		if (!this.running) return this;
		this.running = false;
		this.transport.abort();
		this.transport.onreadystatechange = Class.empty;
		this.setTransport();
		this.fireEvent('onCancel');
		return this;
	}

});

XHR.implement(new Chain, new Events, new Options);

/*
Script: Ajax.js
	Contains the <Ajax> class. Also contains methods to generate querystings from forms and Objects.

Credits:
	Loosely based on the version from prototype.js <http://prototype.conio.net>

License:
	MIT-style license.
*/

/*
Class: Ajax
	An Ajax class, For all your asynchronous needs.
	Inherits methods, properties, options and events from <XHR>.

Arguments:
	url - the url pointing to the server-side script.
	options - optional, an object containing options.

Options:
	data - you can write parameters here. Can be a querystring, an object or a Form element.
	update - $(element) to insert the response text of the XHR into, upon completion of the request.
	evalScripts - boolean; default is false. Execute scripts in the response text onComplete. When the response is javascript the whole response is evaluated.
	evalResponse - boolean; default is false. Force global evalulation of the whole response, no matter what content-type it is.
	
Events:
	onComplete - function to execute when the ajax request completes.

Example:
	>var myAjax = new Ajax(url, {method: 'get'}).request();
*/

var Ajax = XHR.extend({

	options: {
		data: null,
		update: null,
		onComplete: Class.empty,
		evalScripts: false,
		evalResponse: false
	},

	initialize: function(url, options){
		this.addEvent('onSuccess', this.onComplete);
		this.setOptions(options);
		/*compatibility*/
		this.options.data = this.options.data || this.options.postBody;
		/*end compatibility*/
		if (!['post', 'get'].contains(this.options.method)){
			this._method = '_method=' + this.options.method;
			this.options.method = 'post';
		}
		this.parent();
		this.setHeader('X-Requested-With', 'XMLHttpRequest');
		this.setHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
		this.url = url;
	},

	onComplete: function(){
		if (this.options.update) $(this.options.update).empty().setHTML(this.response.text);
		if (this.options.evalScripts || this.options.evalResponse) this.evalScripts();
		this.fireEvent('onComplete', [this.response.text, this.response.xml], 20);
	},

	/*
	Property: request
		Executes the ajax request.

	Example:
		>var myAjax = new Ajax(url, {method: 'get'});
		>myAjax.request();

		OR

		>new Ajax(url, {method: 'get'}).request();
	*/

	request: function(data){
		data = data || this.options.data;
		switch($type(data)){
			case 'element': data = $(data).toQueryString(); break;
			case 'object': data = Object.toQueryString(data);
		}
		if (this._method) data = (data) ? [this._method, data].join('&') : this._method;
		return this.send(this.url, data);
	},

	/*
	Property: evalScripts
		Executes scripts in the response text
	*/

	evalScripts: function(){
		var script, scripts;
		if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) scripts = this.response.text;
		else {
			scripts = [];
			var regexp = /<script[^>]*>([\s\S]*?)<\/script>/gi;
			while ((script = regexp.exec(this.response.text))) scripts.push(script[1]);
			scripts = scripts.join('\n');
		}
		if (scripts) (window.execScript) ? window.execScript(scripts) : window.setTimeout(scripts, 0);
	},

	/*
	Property: getHeader
		Returns the given response header or null
	*/

	getHeader: function(name){
		try {return this.transport.getResponseHeader(name);} catch(e){};
		return null;
	}

});

/* Section: Object related Functions */

/*
Function: Object.toQueryString
	Generates a querystring from key/pair values in an object

Arguments:
	source - the object to generate the querystring from.

Returns:
	the query string.

Example:
	>Object.toQueryString({apple: "red", lemon: "yellow"}); //returns "apple=red&lemon=yellow"
*/

Object.toQueryString = function(source){
	var queryString = [];
	for (var property in source) queryString.push(encodeURIComponent(property) + '=' + encodeURIComponent(source[property]));
	return queryString.join('&');
};

/*
Class: Element
	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
*/

Element.extend({

	/*
	Property: send
		Sends a form with an ajax post request

	Arguments:
		options - option collection for ajax request. See <Ajax> for the options list.

	Returns:
		The Ajax Class Instance

	Example:
		(start code)
		<form id="myForm" action="submit.php">
		<input name="email" value="bob@bob.com">
		<input name="zipCode" value="90210">
		</form>
		<script>
		$('myForm').send()
		</script>
		(end)
	*/

	send: function(options){
		return new Ajax(this.getProperty('action'), $merge({data: this.toQueryString()}, options, {method: 'post'})).request();
	}

});

/*
Script: Hash.js
	Contains the class Hash.

License:
	MIT-style license.
*/

/*
Class: Hash
	It wraps an object that it uses internally as a map. The user must use set(), get(), and remove() to add/change, retrieve and remove values, it must not access the internal object directly. null/undefined values are allowed.

Note:
	Each hash instance has the length property.

Arguments:
	obj - an object to convert into a Hash instance.

Example:
	(start code)
	var hash = new Hash({a: 'hi', b: 'world', c: 'howdy'});
	hash.remove('b'); // b is removed.
	hash.set('c', 'hello');
	hash.get('c'); // returns 'hello'
	hash.length // returns 2 (a and c)
	(end)
*/

var Hash = new Class({

	length: 0,

	initialize: function(object){
		this.obj = object || {};
		this.setLength();
	},

	/*
	Property: get
		Retrieves a value from the hash.

	Arguments:
		key - The key

	Returns:
		The value
	*/

	get: function(key){
		return (this.hasKey(key)) ? this.obj[key] : null;
	},

	/*
	Property: hasKey
		Check the presence of a specified key-value pair in the hash.

	Arguments:
		key - The key

	Returns:
		True if the Hash contains a value for the specified key, otherwise false
	*/

	hasKey: function(key){
		return (key in this.obj);
	},

	/*
	Property: set
		Adds a key-value pair to the hash or replaces a previous value associated with the key.

	Arguments:
		key - The key
		value - The value
	*/

	set: function(key, value){
		if (!this.hasKey(key)) this.length++;
		this.obj[key] = value;
		return this;
	},

	setLength: function(){
		this.length = 0;
		for (var p in this.obj) this.length++;
		return this;
	},

	/*
	Property: remove
		Removes a key-value pair from the hash.

	Arguments:
		key - The key
	*/

	remove: function(key){
		if (this.hasKey(key)){
			delete this.obj[key];
			this.length--;
		}
		return this;
	},

	/*
	Property: each
		Calls a function for each key-value pair. The first argument passed to the function will be the value, the second one will be the key, like $each.

	Arguments:
		fn - The function to call for each key-value pair
		bind - Optional, the object that will be referred to as "this" in the function
	*/

	each: function(fn, bind){
		$each(this.obj, fn, bind);
	},

	/*
	Property: extend
		Extends the current hash with an object containing key-value pairs. Values for duplicate keys will be replaced by the new ones.

	Arguments:
		obj - An object containing key-value pairs
	*/

	extend: function(obj){
		$extend(this.obj, obj);
		return this.setLength();
	},

	/*
	Property: merge
		Merges the current hash with multiple objects.
	*/

	merge: function(){
		this.obj = $merge.apply(null, [this.obj].extend(arguments));
		return this.setLength();
	},

	/*
	Property: empty
		Empties all hash values properties and values.
	*/

	empty: function(){
		this.obj = {};
		this.length = 0;
		return this;
	},

	/*
	Property: keys
		Returns an array containing all the keys, in the same order as the values returned by <Hash.values>.

	Returns:
		An array containing all the keys of the hash
	*/

	keys: function(){
		var keys = [];
		for (var property in this.obj) keys.push(property);
		return keys;
	},

	/*
	Property: values
		Returns an array containing all the values, in the same order as the keys returned by <Hash.keys>.

	Returns:
		An array containing all the values of the hash
	*/

	values: function(){
		var values = [];
		for (var property in this.obj) values.push(this.obj[property]);
		return values;
	}

});

/* Section: Utility Functions */

/*
Function: $H
	Shortcut to create a Hash from an Object.
*/

function $H(obj){
	return new Hash(obj);
};






//Ajax的基类

var BaseAjax = new Class({
    /// <summary>
    /// 初始化类，并且对一些变量赋值

    /// </summary>
    /// <param name="_showID">要加载的DIV的ID</param>
	/// <param name="_funID">栏目ID</param>
	initialize: function(_showID, _funID){
		this.showID = _showID; 
		this.topNumber = -1; //显示条数, -1表示没有限制
		this.funID = _funID;         //栏目ID
		this.async = true;           //是否同步
		this.method = 'get';        //Ajax发送方法

		/*
		 * 加载进度图片采用那种方式
		 * small  用小图片的方式

		 * big    用大图片的方式

		 * custom 用自定义方式
		 */
		this.loadingMethod = 'small';
		this.requestUrl = "../ServerAspx/magServer.aspx";
		this.data = "maMethod="+escape(this.showID)+"&funID="+escape(this.funID)+"&topNumber="+escape(this.topNumber);	
		this.loadHtmlCode = '';
		this.xsltPath = '';	  //xslt文件的路径

	},
	
	getBaseData: function(){
	   this.data = "maMethod="+escape(this.showID)+"&funID="+escape(this.funID)+"&topNumber="+escape(this.topNumber)+"";
	},	
	

    /// <summary>
    /// 加载进度样式
    /// </summary>
	loadding: function(){
		switch(this.loadingMethod){
			case "small":
			   $(this.showID).empty().addClass('ajax-small-loading');
			   break;
		    case "big":
			   $(this.showID).empty().addClass('ajax-big-loading');
			   break;			   
		}		
		$(this.showID).setHTML(this.loadHtmlCode);
	},
	

    /// <summary>
    /// 清除进度样式
    /// </summary>	
	unloaded: function(){
		switch(this.loadingMethod){
			case "small":
			   $(this.showID).removeClass('ajax-small-loading');
			   $(this.showID).setHTML("");
			   break;
		    case "big":
			   $(this.showID).removeClass('ajax-big-loading');
			   break;			   
		}	
	},
	
    setNaviULVisibility: function(){ 
        if( typeof(mlddminit) == 'function'){
	        mlddminit();
	     }
    }
}
  
);

//Ajax的更新类，主要是用来处理返回值是text的数据

var UpReTextAjax = BaseAjax.extend({
    initilize: function(_showID, _funID){
        this.parent(_showID, _funID);
        this.magaID = '';
        this.picID = '';
        this.ifLoading = false;
        this.url = '';
    },
    
    /// <summary>
    /// 采用返回值为字符串的方式来进行Ajax方法交互
    /// </summary>		
	ajaxExecMethod: function(){
	　　this.requestUrl　+= "?"+this.data;
	　　if(this.ifLoading){
	　　 this.loadding();    
	　　}
	    var myAjax = new Ajax( this.requestUrl, {
	                                           method: this.method,
	                                           async:this.async,
											   onComplete: this.CallBack_Response.curry(this)
											   }
						 );
		myAjax.request();
		
	},
	
	CallBack_Response: function(value,requestText,requestXML){
		try{
		if(this.ifLoading){
			value.unloaded();
		 }	
			switch(value.showID){
			 case "maga_Submit_Comment": 
			     //new Asset.javascript('../../js/ui/dialog/dialog_box.js', 'dialog');
			     //$('').click();
			     var resultArray = requestText.split('|+|');
			     if( resultArray[0] == "0"){
			      ErrorInfo(resultArray[1],280,150,"错误提示",null,null);
			     } else {
			      SucceedInfo(resultArray[1],280,150,null,null,null);
			      //刷新用户留言
			      refrsh(10,1, 'refrsh', 'pagination01', $H({'magaID':value.magaID,'url':value.url}));  
			     //刷新验证码  
			      $(value.picID).onclick();
			     //把所有的input的值都清理掉

			     var inputs = $$('#'+value.showID+' input');
			     inputs.each(function(ip, i){
			         if(ip.type != 'hidden' && ip.type != 'submit'){
			            ip.value = '';
			         }
			      });
			      $('reviewContent').value = '';
//			      if(!(resultArray[2]==""&&resultArray[3]=="")){
//			        //如果引用了Head, 那么就要更新Head中isloginhy和LBuserOne的状态

//			        if($chk($("Head1_isloginhy"))&&$chk($("Head1_LBuserOne"))){
//			           var isloginhy = $("Head1_isloginhy");
//			           var LBuserOne = $("Head1_LBuserOne");
//			           isloginhy.setProperties({
//			                     href: 'javascript:__doPostBack(\'Head1$isloginhy\',\'\');',
//			                     onclick: 'ShowUser();LoginOut();' });
//			           isloginhy.setText('欢迎您：'+resultArray[2]+' |退出登录');
//			           LBuserOne.removeClass('hide');
//			           LBuserOne.setProperty('href','javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\'Head1$LBuserOne\', \'\', false, \'\', \'../UserPage/Default.aspx\', false, true));');
//			           LBuserOne.setText('|个人管理');
//			        }
//			      }
			     }
			   break;
			 default:
	         	$(value.showID).setHTML(requestText);
	          	value.setNaviULVisibility();			 
			   break;
			}
		} catch(e) {
			alert('数据处理失败!');
		}
	}
 });
 
  //Ajax的普通扩展类，主要是用来处理返回值是text的数据

var PaginationReTextAjax = BaseAjax.extend({
    initilize: function(_showID, _funID, _sName, _functionInfo, _pageViewDiv, _pageSize, _currentPage){
        this.parent(_showID, _funID);
        this.functionInfo = _functionInfo;
        this.pageViewDiv = _pageViewDiv;
        this.sName = _sName;
        this.pageSize = _pageSize;
        this.currentPage = _currentPage;
        this.data = "maMethod="+this.showID+"&funID="+this.funID+"&pageSize="+this.pageSize+"&currentPage="+this.currentPage;
        this.paras = null;
        this.magaID = "";
        
    },
    
    /// <summary>
    /// 采用返回值为字符串的方式来进行Ajax方法交互
    /// </summary>		
	ajaxExecMethod: function(){
	　　this.requestUrl　+= "?"+this.data;
	　　this.loadding();    
	    var myAjax = new Ajax( this.requestUrl, {
	                                           method: this.method,
	                                           async:this.async,
											   onComplete: this.CallBack_Response.curry(this)
											   }
						 );
		myAjax.request();
		
	},
	
	CallBack_Response: function(value,requestText,requestXML){
		try{
			value.unloaded();	
			var reArray = requestText.split('|+|');
	     	$(value.showID).setHTML(reArray[0]);
	     	if( reArray[1] > 0){
	        $(value.pageViewDiv).setStyle('visibility', 'visible');
	        switch(value.showID){
	          case "maga_user_guestbook_new":
	           var tst = $("maga_user_guestbook_new");
	           var pintable = $('pinluntable');
	           var pintableHeight = 0;
	           if(pintable.getStyle('height').toInt()>205){
	            pintableHeight = pintable.getStyle('height').toInt();
	           } else {
	            pintableHeight = 205;
	           }
	           var fx = new Fx.Styles(tst, {duration:200, wait:false, transition: Fx.Transitions.linear});
		            fx.start({
			            'height': [205, pintable.getStyle('height').toInt()]
		            });	   
	           SetPage(reArray[1],value.pageSize, value.currentPage,value.sName, value.functionInfo, value.pageViewDiv, value.paras);
	            break;
	          default:
	     	    SetPage(reArray[1],value.pageSize, value.currentPage,value.sName, value.functionInfo, value.pageViewDiv, value.paras);
	     	    break;
	     	 }
	     	} else {
	        switch(value.showID){
	          case "maga_user_guestbook_new":
	           var tst = $("maga_user_guestbook_new");
	           var pintable = $('pinluntable');
	           var pintableHeight = pintable.getStyle('height').toInt();
	           new Fx.Style('maga_user_guestbook_new','height').set(pintableHeight-10);
	            break;
	          default:
	     	    break;
	     	 }	     	  
	     	  $(value.pageViewDiv).setStyle('visibility', 'hidden');
	     	}
	     	//value.setNaviULVisibility();
		} catch(e) {
			alert('数据处理失败!');
		}
	}
 });
 
function downloadMagazine( rootUrl, magaID, url, isFree, FreeNum, isAddHitCount ){
    //判断是否安装了月桂阅读器
    CheckReader();
    var isAlert = false;
    if(typeof iDownClick == "undefined") iDownClick = 0;
    if(iDownClick!=1){
     if( isFree == 1){
         Alert('本书为收费图书，如没有购买只能免费看前'+FreeNum+'页!',null,null,"信息提示",function(){downloadExec(rootUrl, magaID, url,  isAddHitCount);},null);
//       ConfirmInfo('信息确认框功能测试',null,null,null,fun1,fun2);
       } else {
         downloadExec( rootUrl, magaID, url, isAddHitCount );  
       };
    } else {
      window.open(url,"download");
    }
    if(iDownClick==2) iDownClick = 1;
};

//判断是否安装了月桂阅读器
function CheckReader() 
{
//     alert('开始检查');
//     var  WshShell  =  new  ActiveXObject("WScript.Shell");
//     var keyValue="";
//     try
//     {
//        keyValue  =  WshShell.RegRead("HKEY_CLASSES_ROOT\\ZTDFILE\\shell\\open\\command\\"); 
//     } 
//     catch(e)
//     {
//     }
//     if(""==keyValue)//等于空则表示没有安装杂志阅读器

//     {
//        if   (confirm("需要安装阅读器才能阅读该杂志，您是否要下载阅读器？"))  location.href="http://www.yogui.com.cn/DownLoad/YoGui.exe";   
//     }
//     else
//     {
//        alert(keyValue);
//     }

    
//    var bl = true;
//    try
//    {
//       var comActiveX = new ActiveXObject("ZTDownCap.ZTDownCapClass.1"); 
//    }
//    catch(e)
//    {
////       alert(e.message);
//       bl =false;
//    }
//    
//    
////        var bl = detectPlugin("B9BFA00B-59E6-44AF-81C3-1995F17DEDDA","SetSite");
//		if( bl == true )
//		{
//			//
//		}
//		else
//		{
//			if   (confirm("需要安装阅读器才能阅读该杂志，您是否要下载阅读器？"))  
//			{
//			   window.open("http://www.yogui.com.cn/DownLoad/YoGui.exe","_blank");
////			   location.href="http://www.yogui.com.cn/DownLoad/YoGui.exe";
//			}
//		}
}


function detectPlugin(CLSID,functionName) 
{ 
	var pluginDiv = document.createElement("<div id=\"pluginDiv\" style=\"display:none\"></div>");
	document.body.insertBefore(pluginDiv); 
	pluginDiv.innerHTML = '<object id="objectForDetectPlugin" classid="CLSID:'+ CLSID +'\"></object>'; 
	try 
	{ 
		if(eval("objectForDetectPlugin.SetSite('')") == undefined) 
		{ 
			pluginDiv.removeNode(true);//删除pluginDiv及其所有的子元素 
			return false; 
		} 
		else 
		{ 
			pluginDiv.removeNode(true);//删除pluginDiv及其所有的子元素 
			return true; 
		} 
	} 
	catch(e) 
	{ 
	    alert(e.message);
		return false; 
	}
}

function downloadExec(rootUrl ,magaID, url,  isAddHitCount){
    if(isAddHitCount==1){
      addHitCount(rootUrl,magaID);
    }
    var requestUrl = rootUrl+"/ServerAspx/magServer.aspx?maMethod="+encodeURIComponent("UP_DOWNCOUNT")+"&magaID="+encodeURIComponent(magaID)+"&url="+encodeURIComponent(url);	
	var myAjax = new Ajax( requestUrl, {
                                           method: "get",
                                           async:true,
									       onComplete: function(txt,xml){
									         if(isAddHitCount!=1){
									         setHitDownCount(txt);};
									       }
									   }
						 );
	myAjax.request();    
	
	window.open(url,"download");
};


function addHitCount( rootUrl, magaID ){
    var requestUrl = rootUrl+"/ServerAspx/magServer.aspx?maMethod="+encodeURIComponent("UP_HITCOUNT")+"&magaID="+encodeURIComponent(magaID);	
	var myAjax = new Ajax( requestUrl, {
                                           method: "get",
                                           async:true,
									       onComplete: function(txt,xml){
									         setHitDownCount(txt);
									       }
									   }
						 );
	myAjax.request();    
};

function setHitDownCount(str){
     if(!!str){	
         eval(str);								         
         if(reShowObj){
           for( var reShowObjProperty in reShowObj){
               if(document.getElementById(reShowObjProperty))
               document.getElementById(reShowObjProperty).innerHTML=reShowObj[reShowObjProperty] + ' 次';
           }
         }
     }
};

function showMagaUserInfo( rootUrl, magaID ){
    var requestUrl = rootUrl+"/ServerAspx/magServer.aspx?maMethod="+encodeURIComponent("S_MageUserInfo")+"&magaID="+encodeURIComponent(magaID);	
	var myAjax = new Ajax( requestUrl, 
	                                      {method: "get",
                                           async:true,
									       onComplete: function(txt,xml){
									         setHitDownCount(txt);
									       }
									   }
						 );
	myAjax.request();    
};

function showMagaUserInfo( rootUrl, mName, str ){
    var requestUrl = rootUrl+"/ServerAspx/magServer.aspx?maMethod="+encodeURIComponent(mName)+"&magaID="+encodeURIComponent(str);	
	var myAjax = new Ajax( requestUrl, 
	                                      {method: "get",
                                           async:true,
									       onComplete: function(txt,xml){
									         setHitDownCount(txt);
									       }
									   }
						 );
	myAjax.request();    
};



 //跳转到明细页
function GoToDetail(rootUrl, magaID, detailUrl){
    addHitCount(rootUrl,magaID);
    window.location = detailUrl;
};   
//跳转到作者作品页
function GoToWriterDetail(url, userID, userName){
  window.open(url+'/main/WriterList.aspx?userID='+encodeURIComponent(userID)+'&userName='+encodeURIComponent(userName),"_blank");
};  


 //截取指定类名的字符串，并且添加完整的tips信息
 function GetLengthString(divID, className, length, ExChar){
     	  //如果有该类名的元素，那么收缩到11长度
   	      if($chk($$('#'+divID+' .'+className+''))){
           $$('#'+divID+' .'+className+'').each(function(t,i){
               var temp = t.getText();
               t.setText(temp.toLengthChar(0,length,ExChar));
               t.setProperty('alt',temp);
               t.removeClass(className);
               t.addClass('cssTips');
              }
           );
          }       
 };


function CheckLength(source, length) 
{ 
    var len = source.replace(/[^\x00-\xff]/g,"**").length;

    if (len<=length){ 
       return true; 
    }
    else{
       return false; 
    }
};

/*--StringBuilder集合类--*/
 var StringBuilder = new Class({
 
	initialize: function(){
      this._strings = new Array();
      this._strings[0] = "";
	},   
	
	append: function(str, index){
	  this._strings[this._strings.length] = str;
	},
	
	toString: function(){
	   return this._strings.join("");
	}
 
 });
 
    function GetBgImage(type){
     var reValue = "";
     switch(type){
       case "0":
         reValue = htmlSR+"/Images/bluegray_columns_bl.gif";
        break;
       case "1":
         reValue = htmlSR+"/Images/bluegray_columns_bc.gif";
        break;
       case "2":
         reValue = htmlSR+"/Images/bluegray_columns_br.gif";
        break;                                                    
     }
     return reValue;
    };
