
/*===============================================================================
	AutoSaver.js
	John Larson
	1/27/08
	
	Component for listening to a collection of form inputs and autosaving
	on a regular basis.
	
	Example:    
<form>
  <div class="mySavers"></div>
  <textarea name="value1" class="myInputs">autosave </textarea><br />
  <textarea name="value2" class="myInputs">does not suck</textarea><br />
  <textarea name="value3" class="myInputs">I swear!</textarea><br />
  <div class="mySavers"></div>
</form>
	
	new AutoSaver($$('.myInputs'), $$('.mySavers'), 'AJAXAction.asp?a=save', 
		{inveral: 30, buttonTextLive: 'Save Now.', 
		 buttonTextSaved: 'Saved.', buttonTextAutoSaved: 'Autosaved.'});
	
===============================================================================*/


var AutoSaver = new Class({
	
	options: {
		interval:				10,
		buttonTextLive:			'Save',
		buttonTextSaved:		'Saved',
		buttonTextAutoSaved:	'Saved',
		autosavedNoticeText:	' Autosaved at %time%'
	},

	initialize: function(formElements, saveElements, saveURL, options){
		this.setOptions(options);
		
		this.formElements = [];
		var saveAction = this.performSave.bind(this);
		
		
		formElements = $$(formElements);
		// If we were given one or more forms we will replace them with the inputs within:
		formElements.each(function(element) {
			element = $(element);
			if (element.tagName == 'FORM') {
				element.addEvent('submit', saveAction);
				this.formElements.merge(element.getFormElements());
			}
			else
				this.formElements.merge(element);
		}, this);
		
		
		this.saveElements = $$(saveElements);
		
		this.saveEnabled = false;
		this.saveURL = saveURL;
		
		
		
		// Build our save inputs:
		this.saveElements.each(function(saveRegion) {
			
			saveRegion.myButton = new Element('input',
				{type: 'button', value: this.options.buttonTextSaved});
			saveRegion.myButton.disabled = true;
			
			saveRegion.myMessageSpan = new Element('span');
			
			saveRegion.adopt(saveRegion.myButton);
			saveRegion.adopt(saveRegion.myMessageSpan);
			
			saveRegion.myButton.addEvent('click', function() {
				saveAction();
			});
		}, this);
		
		
		
		// Let's set up listening to our inputs:
		var enableSaveButtonAction = this.enableSaveButtons.bind(this);
		
		this.formElements.each(function(formElement) {
			formElement.addEvents({
				'keyup': function() {
					enableSaveButtonAction();
				}, 
				'change': function() {
					enableSaveButtonAction();
				}
			}, this);
		}, this);
		
		// Let's set ourselves up to autosave at the prescribed interval:
		this.timer = function(){
			this.performAutoSave();
		}.periodical(this.options.interval * 1000, this, {});
		
		
	},
	
	addFormElement: function(formElement) {
		this.addFormElements([formElement]);
	},
	
	addFormElements: function(formElements) {
		
		var enableSaveButtonAction = this.enableSaveButtons.bind(this);
		
		formElements.each(function(formElement) {
			this.formElements.include(formElement);
			formElement.addEvents({
				'keyup': function() {
					enableSaveButtonAction();
				}, 
				'change': function() {
					enableSaveButtonAction();
				}
			}, this);
		}, this);
	},
	
	performSave: function(event) {
		
		// No need to do this again for now:
		this.saveEnabled = false;
		
		var saveData = this.getSaveData();
		var completeSaveAction = this.completeSave.bind(this)
		
		new Ajax(this.saveURL, {
			method: 'post',
			data: saveData,
			evalScripts: true,
			onComplete: function() { completeSaveAction(); }
		}).request();
	},
	
	performAutoSave: function() {
		
		if (this.saveEnabled) {
			dbug.log('let us autosave...');
			this.saveEnabled = false;
			
			var saveData = this.getSaveData();
			var completeAutoSaveAction = this.completeAutoSave.bind(this)
			
			new Ajax(this.saveURL, {
				method: 'post',
				data: saveData,
				evalScripts: true,
				onComplete: function() { completeAutoSaveAction(); }
			}).request();
		}
	},
	
	
	completeSave: function() {
		
		// Update our save inputs:
		this.saveElements.each(function(saveRegion) {
			
			saveRegion.myButton.value = this.options.buttonTextSaved;
			saveRegion.myButton.disabled = true;
			
			saveRegion.myMessageSpan.setText('');
		}, this);
		
		this.saveEnabled = false;
	},
	
	
	completeAutoSave: function() {
		
		// Update our save inputs:
		this.saveElements.each(function(saveRegion) {
			
			saveRegion.myButton.value = this.options.buttonTextAutoSaved;
			saveRegion.myButton.disabled = true;
			
			saveRegion.myMessageSpan.setText(
				this.options.autosavedNoticeText.replace('%time%', new Date().format("%X")));
		}, this);
		
		this.saveEnabled = false;
	},
	
	
	getSaveData: function() {
		
		var queryString = [];
		this.formElements.each(function(el){
			var name = el.name;
			var value = el.getValue();
			if (value === false || !name || el.disabled) return;
			var qs = function(val){
				queryString.push(name + '=' + encodeURIComponent(val));
			};
			if ($type(value) == 'array') value.each(qs);
			else qs(value);
		});
		return queryString.join('&');
	},
	
	enableSaveButtons: function() {
		
		if(!this.saveEnabled) {
			this.saveElements.each(function(saveRegion) {
				saveRegion.myButton.value = this.options.buttonTextLive;
				saveRegion.myButton.disabled = false;
			}, this);
			
			this.saveEnabled = true;
		}
	}
	
});


AutoSaver.implement(new Options, new Events);