/*
Script: MooEditable.js
MooEditable class for contentEditable-capable browsers

License:
MIT-style license.

Author:
Lim Chee Aun <cheeaun@gmail.com>

Contributor:
Marc Fowler <marc.fowler@defraction.net>

Changelog:
0.3 (20 Nov 2007)
- Fixed formatting bugs with Internet Explorer 7
- Fixed IE bug with inherited margins on form elements
- Fixed error when cancelling hyperlink prompt dialog
- Fixed button hover for Internet Explorer 6
- Tweaked the PNG images to be a little friendlier for Internet Explorer 6
- Fixed <label> event to focus on iframe instead of textarea in design mode
0.2 (15 Nov 2007)
- Fixed padding of textareas and iframe's doc for Safari 3 beta
- Added instant update of content to textareas
- Added compatibility for Internet Explorer 7
- Better compatibility with Adobe AIR's webkit
- More regex to cleanup the messy code made by Internet Explorer
- Removed 'mode' option, not very useful anyway
0.1 (12 Nov 2007)
- first initial release

Credits:
- Most code is based on Stefan's work "Safari Supports Content Editing!" <http://www.xs4all.nl/~hhijdra/stefan/ContentEditable.html>
- Main reference from Peter-Paul Koch's "execCommand compatibility" research <http://www.quirksmode.org/dom/execCommand.html>
- Some ideas inspired by TinyMCE <http://tinymce.moxiecode.com/>
- Some functions inspired by Inviz's "Most tiny wysiwyg you ever seen" <http://forum.mootools.net/viewtopic.php?id=746>, <http://forum.mootools.net/viewtopic.php?id=5740>
- Some regex from Cameron Adams's widgEditor <http://themaninblue.com/experiment/widgEditor/>
- IE support referring Robert Bredlau's "Rich Text Editing" part 1 and 2 articles <http://www.rbredlau.com/drupal/node/6>
- Tango icons from the Tango Desktop Project <http://tango.freedesktop.org/>
- Additional tango icons from Tango OpenOffice set by Jimmacs <http://www.gnome-look.org/content/show.php/Tango+OpenOffice?content=54799>
*/

var MooEditable = new Class({

	//	Implements: [Events, Options],

	options:{
		toolbar: true,
		styleWithCSS: true,
		buttons: 'bold,italic,underline,size, removeformat,separator,color,separator,imgalbum,img,youtube,smile,separator,left,center,right,separator,insertunorderedlist,insertorderedlist,indent,outdent,separator,undo,redo,separator,createlink,unlink,toggleview',
		text: {
		'headline': 'headline',
		'bold': 'Bold',
		'italic': 'Italic',
		'underline': 'underline',
		'color': 'Color',
		'size':'Size',
		'left': 'Left',
		'quote': 'Quote',
		'imgalbum': 'imgalbum',
		'removeformat': 'removeformat',
		'center': 'Center',
		'right': 'right',
		'insertunorderedlist': 'Unordered List',
		'insertorderedlist': 'Ordered List',
		'indent': 'Indent',
		'outdent': 'Outdent',
		'undo': 'Undo',
		'img': 'Image',
		'smile': 'Smile',
		'youtube': 'Youtube',
		'redo': 'Redo',
		'createlink': 'Add Hyperlink',
		'unlink': 'Remove Hyperlink',
		'separator': '|',
		'toggleview': 'Toggle View'
		}
	},
	initialize: function(elements,options){
		this.setOptions(options);
		$$(elements).each(this.build, this);
	},
	// Initialize wrapper
	prompt: function (text,value,obj, func) {
		if (window.ie) { // Loosing the focus we loose the marker too :(
			value = prompt(text,value);
			return eval('this.' + func + '("' + value + '");');
		}
		if ($('prompt')) $('prompt').remove();
		var div  = new Element('div')
		/*.setStyles({
		'width':'200px',
		'padding': '1em',
		'opacity': '0',
		'position': 'absolute',
		'color':'black',
		'border': '1px solid gray',
		'z-index': '99',
		'background': '#EEEEEE'
		})*/
		.setProperty('id','prompt')
		.addClass('wtoolbar')
		.setHTML('<strong>' + text + '</strong>')
		.injectAfter(obj);

		var input  = new Element('input')
		.setProperty('id','prompt_input')
		.injectInside(div);

		var localthis = this;
		var button = new Element('input')
		.setProperties({'type':'button','value':'Ok'})
		.addClass('small')
		.addEvent('click', function () {
			value = $('prompt_input').value;
			eval('localthis.'+func +'(\''+value+'\')');
			$('editablec').contentWindow.focus();
			$('prompt').remove();
		})
		.injectAfter(input);

		
		var close = new Element('input')
		.setProperties({'type':'button','value':'Cancel'})
		.addClass('small')
		.addEvent('click', function () {
			$('prompt').remove();
		})
		.injectAfter(button);
		var ef = new Fx.Style(div, 'opacity', {
			duration: 500,
			transition: Fx.Transitions.quartInOut
		})
		ef.start(0,1);
		(function () { $('prompt_input').focus();}).delay(500);
	},
	link: function (url) {
		if (url) {
			var win = $('editablec').contentWindow;
			var doc = win.document;
			if (window.ie) win.focus();
			doc.execCommand('createlink','',url);
		}
	},
	image: function (url) {
		if (url) {
			var win = $('editablec').contentWindow;
			var doc = win.document;
			win.focus();
			doc.execCommand('InsertImage','',url);
		}
	},
	insertimg: function (src) {
			var win = $('editablec').contentWindow;
			var doc = win.document;
			var html = "<img src="+(this.cleanup(src)).trim()+">";
			doc.getElementById('editable').innerHTML = this.cleanup(doc.getElementById('editable').innerHTML + html);
			this.el.value = this.cleanup(doc.getElementById('editable').innerHTML);
			$('album').remove();
	},
	insert_html: function (html) {
			var win = $('editablec').contentWindow;
			var doc = win.document;
			doc.getElementById('editable').innerHTML = this.cleanup(doc.getElementById('editable').innerHTML + html);
			// Build the content of iframe
			var content = $('editablec').contentWindow.document;
			// Turn on Design Mode
			content.designMode = 'On';
			win.focus();
	} ,
	empty: function () {
			var win = $('editablec').contentWindow;
			var doc = win.document;
			doc.getElementById('editable').innerHTML = '';
	} ,
	wrapText: function(Start, End) 
	{
		var win = $('editablec').contentWindow;
		var doc = win.document;		
		
		if (doc.selection) {
			var selectedText = doc.selection
			selectedText = selectedText.createRange().text;
		} else {
			var selectedText = doc.getSelection();
		}
		selectionPos = doc.body.innerHTML.indexOf(selectedText);
		if (selectionPos <= 0)
			return false;
		newInnerHTML = doc.body.innerHTML.substr(0, selectionPos);
		newInnerHTML+= Start;
		newInnerHTML+= selectedText;
		newInnerHTML+= End;
		newInnerHTML+= doc.body.innerHTML.substr(selectionPos + selectedText.length); 
		doc.body.innerHTML = newInnerHTML;
	} ,
	quote: function (textS, textE) {
		if (document.selection) {
			var selectedText = document.selection
			selectedText = selectedText.createRange().text;
		} else {
			var selectedText = document.getSelection();
		}
		if (selectedText) {
			var win = $('editablec').contentWindow;
			var doc = win.document;
			doc.getElementById('editable').innerHTML = doc.getElementById('editable').innerHTML + textS + this.cleanup(selectedText) + textE;			
		} else {
			alert('Alert: Select The text in the textarea then click on this button');
		}
	},
	youtube: function (url) {

		var code;
		var matches0 = url.match (/http:\/\/(www.)*youtube\.com\/watch\?.*?v=([^&]+)/);
		// the other way round
		var matches1 = url.match (/http:\/\/(www.)*youtube\.com\/v\/([^\/&]+)/);

		if (matches0 != null && matches0[2] != null)
		{
			code = matches0[2];
		}
		else if (matches1 != null && matches1[2] != null)
		{
			code = matches1[2];
		}
		else {	code = ""; }


		if (code) {
			code = '/thm/images/youtubevideo.png?url='+code;
			var win = $('editablec').contentWindow;
			var doc = win.document;
			if (window.ie) win.focus();
			doc.execCommand('InsertImage','',code);
			//doc.execCommand('InsertImage','',);
		} else {
			alert("Invalid Youtube Link");
		}


	},
	build: function(el){
		var id = el.className ? el.className : el.id ? el.id : 'mooeditable';
		var elStyles = el.getStyles('width','height','padding','margin','border','border-width');
		var sides = ['top','right','bottom','left'];
		for (var i = 0; i < sides.length; i++) {
			elStyles['padding-' + sides[i]] = elStyles['padding'].split(' ')[i];
			elStyles['border-' + sides[i] + '-width'] = elStyles['border-width'].split(' ')[i];
		}
		this.el = el;
		// Build the container
		var container = new Element('div',{
		'class': id + '-container',
		'id': id + '-container',
		'styles': {
		'width': elStyles['width'].toInt() + elStyles['padding-right'].toInt() + elStyles['padding-left'].toInt() + elStyles['border-right-width'].toInt() + elStyles['border-left-width'].toInt(),
		'margin': elStyles['margin']
		}
		});

		// Put textarea inside container
		container.inject(el, 'before');
		el.setStyles({
		'margin': 0,
		'display': 'none',
		'resize': 'none', // disable resizable textareas in Safari
		'outline': 'none' // disable focus ring in Safari
		});
		//		if(Browser.Engine.trident){
		if(window.ie){
			// Fix IE bug, refer "IE/Win Inherited Margins on Form Elements" <http://positioniseverything.net/explorer/inherited_margin.html>
			var span = new Element('span');
			span.inject(container, 'bottom');
			el.inject(span, 'bottom');
		}
		else el.inject(container, 'bottom');
		// Build the iframe
		var iframe = new Element('iframe',{
		'class': id + '-iframe',
		'styles':{
		'width': elStyles['width'].toInt() + elStyles['padding-right'].toInt() + elStyles['padding-left'].toInt(),
		'height': elStyles['height'].toInt() + elStyles['padding-top'].toInt() + elStyles['padding-bottom'].toInt()
		}
		})
		.setProperty('id','editablec');
		iframe.inject(container, 'top');

		// Build the content of iframe
		var doc = iframe.contentWindow.document;
		// Update the event for textarea's corresponding labels
		if(el.id) $$('label[for="'+el.id+'"]').addEvent('click', function(e){
			if(iframe.getStyle('display') != 'none'){
				e = new Event(e).stop();
				iframe.contentWindow.focus();
			}
		});


		if(this.options.toolbar) this.buildToolbar(el,iframe,id);
/*
		doc.open();
		doc.write('<html style="cursor: text; height: 100%">');
		doc.write('<body id="editable" style="background:white;font-family: helvetica, arial, sans-serif; border: 0; margin: 1px; padding: '+ elStyles['padding'] +'">');
		doc.write(el.value);
		doc.write('</body></html>');
		doc.close();	
		doc.designMode = 'On';
*/
		// Turn on Design Mode
		doc.designMode = 'On';
		doc.open();
		doc.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
		doc.write('<html>');
		doc.write('<head></head>');
		doc.write('<body style="height: 500px"><div style="margin-top: 5px">');
		
		if (el.value)
			doc.write(el.value);		
		/*
		else
			doc.write('<p>&nbsp;</p>');
		*/
			
		doc.write('<div></body>');
		doc.write('</html>');
		doc.close();
		$(doc.body).setProperty('id', 'editable');
		doc.body.setStyle('border', 0);		
		doc.body.setStyle('font-family', 'helvetica, arial, sans-serif');
		doc.body.setStyle('background-color', '#ffffff');		
		doc.body.setStyle('padding', '5px');
		doc.body.setStyle('font-size', '14px');		
		if ($('editablep'))
			$('editablep').setFocus();

		/*
		doc.body.setStyle('font-family', 'helvetica, arial, sans-serif');
		doc.body.setStyle('background-color', '#ffffff');
		doc.body.setStyle('font-size', '16px');
		doc.body.setStyle('padding', '1px');
		*/
		// Ensures textarea content is always updated
		var events = ['mousedown', 'mouseup', 'mouseout', 'mouseover', 'click', 'keydown', 'keyup', 'keypress', 'change', 'focus', 'blur'];
		for(var i = 0; i < events.length; i++){
			if($type(document.addEventListener) == 'function'){
				doc.addEventListener(events[i], function(oEvent){
					el.value = this.cleanup(doc.getElementById('editable').innerHTML);
				}.bind(this), false);
			}
			else{
				doc.attachEvent('on' + events[i], function(){
					el.value = this.cleanup(doc.getElementById('editable').innerHTML);
				}.bind(this));
			}
		}
	},
	buildToolbar: function(el,iframe,id) {
		var toolbar = new Element('div',{
		'class': id + '-toolbar'
		});
		toolbar.inject(iframe, 'before');

		var toolbarButtons = this.options.buttons.split(',');

		for (var i=0 ; i<toolbarButtons.length ; i++){
			var command = toolbarButtons[i];
			var b;
			if (command == 'separator'){
				b = new Element('span',{
				'class': 'toolbar-separator'
				});
			} else{
				b = new Element('button',{
				'class': command+'-button toolbar-button',
				'title': this.options.text[command]
				});
			}
			if (command !=  'headline') {
				//			b.set('text', this.options.text[command]);
				b.setText(this.options.text[command]);
			}
			b.inject(toolbar, 'bottom');
		}
		toolbar.getElements('.toolbar-button').each(function(item){
			item.addEvent('click', function(e){
				e = new Event(e).stop();
				if (!item.hasClass('disabled')){
					var command = item.className.split(' ')[0].split('-')[0];
					this.action(command, el, iframe, toolbar);
				}
				//iframe.contentWindow.focus();
			}.bind(this));

			// remove focus rings off the buttons in Firefox
			item.addEvent('mousedown', function(e){ new Event(e).stop(); });

			// add hover effect for IE6
			//			if(Browser.Engine.trident4) item.addEvents({
			if(window.ie) item.addEvents({
				'mouseenter': function(e){ this.addClass('hover'); },
				'mouseleave': function(e){ this.removeClass('hover'); }
			});
		}.bind(this));
	},
	
	action: function(command, el, iframe, toolbar){
		var win = iframe.contentWindow;
		var doc = win.document;
		var selection = '';
		
		$$('div.wtoolbar').each(function (el) {
			el.remove();
		});
		
		switch(command){

			case 'quote':
				this.quote();
			break;
			case 'strikethrough':
				doc.execCommand('strikethrough',false,'');
			break;
			case 'big':
			doc.execCommand('fontsize',false,'8');
			break;
			case 'medium':
			doc.execCommand('fontsize',false,'6');
			break;
			case 'normal':
			doc.execCommand('fontsize',false,'3');
			break;
			case 'small':
			doc.execCommand('fontsize',false,'2');
			break;
			case 'center':
			doc.execCommand('justifycenter',false,'');
			break;
			case 'left':
				doc.execCommand('justifyleft',false,'');
			break;
					
			case 'size':
				
				
				var localthis = this;
				var div = new Element('div')
				.setProperty('id','formatsize')
				.injectAfter(toolbar)
				.addClass('wtoolbar')
				.setStyle('position','absolute');
			
				var img = new Element('img')
				.setProperty('src','/thm/images/mooeditable/size_small.gif')
				.addEvent('click', function (e) {localthis.action('small',el,iframe,toolbar);})
				.injectInside(div);
								
				var img = new Element('img')
				.setProperty('src','/thm/images/mooeditable/size_normal.gif')
				.injectInside(div)
				.addEvent('click', function (e) {localthis.action('normal',el,iframe,toolbar);});
				
				var img = new Element('img')
				.setProperty('src','/thm/images/mooeditable/size_medium.gif')
				.injectInside(div)
				.addEvent('click', function (e) {localthis.action('medium',el,iframe,toolbar);});
				
				var img = new Element('img')
				.setProperty('src','/thm/images/mooeditable/size_big.gif')
				.injectInside(div)
				.addEvent('click', function (e) {localthis.action('big',el,iframe,toolbar);});

			

			
			break;
			
			case 'right':
			doc.execCommand('justifyright',false,'');
			break;
			case 'createlink':
			if (doc.selection){
				selection = doc.selection.createRange().text;
				if (selection == ''){
					alert("Please select the text you wish to hyperlink.");
					break;
				}
			}
			else{
				selection = win.getSelection();
				if (selection == ''){
					alert("Please select the text you wish to hyperlink.");
					break;
				}
			}
			var url  = this.prompt('Enter URL', 'http://', toolbar, 'link');
			
			break;
			case 'imgalbum':
				loadUrl('/administration/ajax/album', 'editablec', '', '570' , '545','','album');
			break;
			case 'img':
				var url  = this.prompt('Enter Image URL', 'http://', toolbar, 'image');
			break;

			case 'youtube':

			this.prompt('Enter Youtube URL', 'http://www.youtube.com/',toolbar, 'youtube');

			break;

			case 'color':

			var div = new Element('div')
			.setProperty('id','colors')
			.injectAfter(toolbar)
			.addClass('wtoolbar')
			.setStyle('position','absolute');
			div.addEvent('mouseleave', function(e) { this.remove() } );
			if (window.ie6 && false)
			{
				r = g = b = ["00","66","FF"];
			} else {
				r = g = b = ["00","33","66","99","CC","FF"];
			}
			/*
			var g = new Array("00","33","66","99","CC","FF");
			var b = new Array("00","33","66","99","CC","FF");
			*/
			var r_length = r.length;
			var g_length = g.length;
			var b_length = b.length;
			
			while(r_length--)
			{
				g_length = g.length;
				while(g_length--)
				{
					b_length = b.length;
					while(b_length--)
					{
						var nuevoc = "#" + r[r_length] + g[g_length] + b[b_length];
						var div2 = new Element('img');						
						div2.setProperty('id',nuevoc)
						.addEvent('click', function () {
							doc.execCommand('forecolor',false,this.id);
							$('colors').remove();
						})
						.setStyles({
						'background': nuevoc,
						'cursor':'pointer',
						'float': 'left',
						'width': '10px'})
						.injectInside(div);
						if (!window.ie) {
							div2.setProperty('src','/thm/images/xim.gif');
						}
						else
						{
							div2.src = '/thm/images/xim.gif';
						}
						
						if (window.ie6)
						{
							div2.setStyles({'width': '30px', 'padding': '2px 2px 2px 2px'});
						}
					}
				}
			}
			break;

			case 'smile':
			var smiles =
			[
			'/thm/images/mooeditable/msn/angel_smile.gif',
			'/thm/images/mooeditable/msn/angry_smile.gif',
			'/thm/images/mooeditable/msn/broken_heart.gif',
			'/thm/images/mooeditable/msn/cake.gif',
			'/thm/images/mooeditable/msn/confused_smile.gif',
			'/thm/images/mooeditable/msn/cry_smile.gif',
			'/thm/images/mooeditable/msn/devil_smile.gif',
			'/thm/images/mooeditable/msn/embaressed_smile.gif',
			'/thm/images/mooeditable/msn/envelope.gif',
			'/thm/images/mooeditable/msn/heart.gif',
			'/thm/images/mooeditable/msn/kiss.gif',
			'/thm/images/mooeditable/msn/lightbulb.gif',
			'/thm/images/mooeditable/msn/omg_smile.gif',
			'/thm/images/mooeditable/msn/regular_smile.gif',
			'/thm/images/mooeditable/msn/sad_smile.gif',
			'/thm/images/mooeditable/msn/shades_smile.gif',
			'/thm/images/mooeditable/msn/teeth_smile.gif',
			'/thm/images/mooeditable/msn/thumbs_down.gif',
			'/thm/images/mooeditable/msn/thumbs_up.gif',
			'/thm/images/mooeditable/msn/tounge_smile.gif',
			'/thm/images/mooeditable/msn/whatchutalkingabout_smile.gif',
			'/thm/images/mooeditable/msn/wink_smile.gif'
			];

			var ul = new Element('ul').addClass('smiles');

			smiles.each(function(el){

				var li = new Element('li')
				.injectInside(ul);

				var src = el;

				var img = new Element('img')
				.setProperty('src',el)
				.setStyles({'width':'22px', 'height':'22px'})
				.addEvent('click', function (e) {
					var win = $('editablec').contentWindow;
					var doc = win.document;
					win.focus();
					doc.execCommand('InsertImage','',src);
					$('smiles').remove();
				})
				.injectInside(li);

			});


			var div = new Element('div')
			.setProperty('id','smiles')
			.injectAfter(toolbar)
			.addClass('wtoolbar')
			.setStyle('position','absolute');

			ul.injectInside(div);

			break;

			case 'toggleview':
			this.toggle(el,iframe,toolbar);
			break;
			default:
			//if (!Browser.Engine.trident) this.execute(el, doc, 'styleWithCSS', false, this.options.styleWithCSS);
			if (!window.ie) this.execute(el, doc, 'styleWithCSS', false, this.options.styleWithCSS);
			this.execute(el, doc, command, false, '');
		}
	},

	execute: function(el, doc, command, param1, param2){
		if (!this.busy){

			this.busy = true;
			doc.execCommand(command, param1, param2);
			el.value = this.cleanup(doc.getElementById('editable').innerHTML);
			this.busy = false;
		}
		return false;
	},

	toggle: function(el,iframe,toolbar) {
		if (iframe.getStyle('display') == 'none') {
			iframe.setStyle('display', '');
			var doc = iframe.contentWindow.document;
			(function(){
				doc.getElementById('editable').innerHTML = el.value;

			}).delay(1); // dealing with Adobe AIR's webkit bug
			toolbar.getElements('.toolbar-button').each(function(item){
				item.removeClass('disabled');
				//				item.set('opacity', 1);
				item.setOpacity(1);
			});
			el.setStyle('display', 'none');
		} else {
			el.setStyle('display', '');
			var doc = iframe.contentWindow.document;
			el.value = this.cleanup(doc.getElementById('editable').innerHTML);
			toolbar.getElements('.toolbar-button').each(function(item){
				if (!item.hasClass('toggleview-button')) {
					item.addClass('disabled');
					//					item.set('opacity', 0.4);
					item.setOpacity(0.4);
				}
			});
			iframe.setStyle('display', 'none');
		}
	},

	cleanup: function(source){
		return source;
		
		// Remove leading and trailing whitespace
		source = source.replace(/^\s+/, '');
		source = source.replace(/\s+$/, '');

		// Remove trailing BRs
		source = source.replace(/<br>$/, '');

		// Remove BRs right before the end of blocks
		source = source.replace(/<br>\s*<\/(h1|h2|h3|h4|h5|h6|li|p|fieldset|legend)/gi, '</$1');

		// Remove empty tags
		source = source.replace(/(<[^\/]>|<[^\/][^>]*[^\/]>)\s*<\/[^>]*>/gi, '');

		// Webkit cleanup
		source = source.replace(/ class=\"Apple-style-span\"/gi, '');
		source = source.replace(/<SPAN style=\"\">/gi, '');

		// Replace uppercase element names with lowercase
		source = source.replace(/<[^> ]*/g, function(match){return match.toLowerCase();});

		// Replace uppercase attribute names with lowercase
		source = source.replace(/<[^>]*>/g, function(match){
			match = match.replace(/ [^=]+=/g, function(match2){return match2.toLowerCase();});
			return match;
		});

		// Put quotes around unquoted attributes
		source = source.replace(/<[^>]*>/g, function(match){
			match = match.replace(/( [^=]+=)([^"][^ >]*)/g, "$1\"$2\"");
			return match;
		});

		return source;
	}
    // insert HTML content into control
});

