// packager build Form-Placeholder/*
/*
---

name: Class.Binds

description: A clean Class.Binds Implementation

authors: Scott Kyle (@appden), Christoph Pojer (@cpojer)

license: MIT-style license.

requires: [Core/Class, Core/Function]

provides: Class.Binds

...
*/

Class.Binds = new Class({

	$bound: {},

	bound: function(name){
		return this.$bound[name] ? this.$bound[name] : this.$bound[name] = this[name].bind(this);
	}

});

/*
---

name: Class.Singleton

description: Beautiful Singleton Implementation that is per-context or per-object/element

authors: Christoph Pojer (@cpojer)

license: MIT-style license.

requires: [Core/Class]

provides: Class.Singleton

...
*/

(function(){

var storage = {

	storage: {},

	store: function(key, value){
		this.storage[key] = value;
	},

	retrieve: function(key){
		return this.storage[key] || null;
	}

};

Class.Singleton = function(){
	this.$className = String.uniqueID();
};

Class.Singleton.prototype.check = function(item){
	if (!item) item = storage;

	var instance = item.retrieve('single:' + this.$className);
	if (!instance) item.store('single:' + this.$className, this);
	
	return instance;
};

var gIO = function(klass){

	var name = klass.prototype.$className;

	return name ? this.retrieve('single:' + name) : null;

};

if (('Element' in this) && Element.implement) Element.implement({getInstanceOf: gIO});

Class.getInstanceOf = gIO.bind(storage);

}).call(this);

/*
---

name: Form.Placeholder

description: Provides a fallback for the placeholder property on input elements for older browsers.

authors: Christoph Pojer (@cpojer)

license: MIT-style license.

requires: [Core/Class.Extras, Core/Element, Core/Element.Event, Core/Element.Style, Class-Extras/Class.Binds, Class-Extras/Class.Singleton]

provides: Form.Placeholder

...
*/

(function(){

if (!this.Form) this.Form = {};

var supportsPlaceholder = ('placeholder' in document.createElement('input'));
if (!('supportsPlaceholder' in this) && this.supportsPlaceholder !== false && supportsPlaceholder) return;

var wrapSet = function(set, self){
	return function(key, value){
		if (key == 'value' && !value){
			self.reset();
			return this;
		}

		return set.apply(this, arguments);
	};
};

var wrapGet = function(get, self){
	return function(key){
		if (key == 'value' && !self.hasValue())
			return '';

		return get.apply(this, arguments);
	};
};

this.Form.Placeholder = new Class({

	Implements: [Class.Singleton, Class.Binds, Options],

	options: {
		color: '#777'
	},

	initialize: function(element, options){
		this.setOptions(options);
		element = this.element = document.id(element);

		return this.check(element) || this.setup();
	},

	setup: function(){
		var element = this.element;
		
		this.defaultValue = element.get('placeholder') || element.value;
		this.color = element.getStyle('color');

		element.erase('placeholder');
		element.set = wrapSet(element.set, this);
		element.get = wrapGet(element.get, this);
		
		this.attach();

		if (!this.hasValue()) this.reset();
	},

	attach: function(){
		this.element.addEvents({
			focus: this.bound('focus'),
			blur: this.bound('blur')
		});
		
		return this;
	},

	detach: function(){
		this.element.removeEvents({
			focus: this.bound('focus'),
			blur: this.bound('blur')
		});

		return this;
	},

	clear: function(){
		var element = this.element;
		element.setStyle('color', this.color);
		if (element.value == this.defaultValue) element.value = '';
		
		return this;
	},

	reset: function(){
		this.element.setStyle('color', this.options.color).value = this.defaultValue;

		return this;
	},
	
	focus: function(){
		this.clear();
	},
	
	blur: function(){
		if (!this.element.value) this.reset();
	},

	hasValue: function(){
		var value = this.element.value;
		return (value && value != this.defaultValue);
	}

});

}).call(this);


