// ==UserScript==
// @name Textarea resizer
// @author Joćo Eiras
// @description This script provides extra accessibility by allowing easy resizing of textareas
// @version 1.1
// @include *
// @exclude http://docs.google.com/*
// ==/UserScript==

/*
	Copyright © 2005 by Joćo Eiras 

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/


(function( opera ){
	//event to listen and modifiers
	var shortcut = { eventType:'mousemove', shiftKey:true, ctrlKey:false, altKey:false };
	//leave blank for auto-detect, else write 'en','fr','de','nl','pt','en-US' ....
	var preferedLanguage = '';
	
	var langs = {
		en:{
			resize:'resize',
			width:'width',
			height:'height',
			unit:'unit',
			increase:'increase',
			decrease:'decrease',
			column:'column',
			columns:'columns',
			line:'line',
			lines:'lines',
			auto:'auto',
			reset:'reset',
			custom:'custom'
		},
		pt:{
			resize:'redimensionar',
			width:'largura',
			height:'altura',
			unit:'unidade',
			increase:'aumentar',
			decrease:'diminuir',
			column:'coluna',
			columns:'colunas',
			line:'linha',
			lines:'linhas',
			auto:'autom&aacute;tico',
			reset:'reset',
			custom:'definir'
		}
	};
	
	var lang = langs.en;
	if( preferedLanguage && langs[preferedLanguage] ){
		lang = langs[preferedLanguage];
	}
	else{
		for(var prop in langs){
			if( navigator.userLanguage.substring(0,prop.length)==prop ){
				lang = langs[prop];
				break;
			}
		}
	}
	
	function addCssToDocument(document,cssText){
		with(document){
			var elId = "userjs-styles";
			var styles = getElementById(elId);
			if(!styles){
				var ns = "http://www.w3.org/xhtml/1999";
				var head = getElementsByTagName("head")[0]||getElementsByTagNameNS(ns,"head")[0];
				if( !head ){
					var docEl = getElementsByTagName("html")[0]||getElementsByTagNameNS(ns,"html")[0]||documentElement;
					if(!docEl){ return false; }// :S this shouldn't happen
					head = createElement("head");
					if(head) docEl.insertBefore(head,docEl.firstChild);
					else head = docEl;
				}
				styles = createElement("style");
				styles.setAttribute("type","text/css");	
				styles.setAttribute("id",elId);
				styles.appendChild(createTextNode(' '));
				head.appendChild(styles)
			}
			styles.firstChild.nodeValue += cssText+"\n";
		}
		return true;
	};
	
	function isNodeChildOf(node,parent){
		if( !node || !parent ) return false;
		if( node.parentNode == parent ) return true;
		return arguments.callee(node.parentNode,parent);
	};
	
	var textAreaResizeMenu = null;
	var textAreaResizeMenuMarkup = 
		'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'+
		'<ujs_ul xmlns="http://www.w3.org/1999/xhtml" class="ujs_ta_menu"><ujs_li class="ujs_hdr"><ujs_strong>'+lang.resize+
		'</ujs_strong></ujs_li><ujs_li class="ujs_sep"><hr/></ujs_li><ujs_li><ujs_span>&rsaquo;</ujs_span>'+lang.width+''+
		'<ujs_ul><ujs_li>'+lang.increase+' 1 '+lang.column+'</ujs_li><ujs_li>'+lang.increase+' 5 '+lang.columns+'</ujs_li>'+
		'<ujs_li>'+lang.increase+' 20 '+lang.columns+'</ujs_li><ujs_li class="ujs_sep"><hr/></ujs_li><ujs_li>'+lang.decrease+
		' 1 '+lang.column+'</ujs_li><ujs_li>'+lang.decrease+' 5 '+lang.columns+'</ujs_li><ujs_li>'+lang.decrease+' 20 '+
		lang.columns+'</ujs_li><ujs_li class="ujs_sep"><hr/></ujs_li><ujs_li><ujs_span><input type="checkbox"/></ujs_span>'+
		lang.auto+'</ujs_li><ujs_li>'+lang.reset+'</ujs_li></ujs_ul></ujs_li><ujs_li><ujs_span>&rsaquo;</ujs_span>'+lang.height+
		'<ujs_ul><ujs_li>'+lang.increase+' 1 '+lang.line+'</ujs_li><ujs_li>'+lang.increase+' 5 '+lang.lines+
		'</ujs_li><ujs_li>'+lang.increase+' 20 '+lang.lines+'</ujs_li><ujs_li class="ujs_sep"><hr/></ujs_li><ujs_li>'+lang.decrease+
		' 1 '+lang.line+'</ujs_li><ujs_li>'+lang.decrease+' 5 '+lang.lines+'</ujs_li><ujs_li>'+lang.decrease+' 20 '+lang.lines+
		'</ujs_li><ujs_li class="ujs_sep"><hr/></ujs_li><ujs_li><ujs_span><input type="checkbox"/></ujs_span>'+lang.auto+'</ujs_li>'+
		'<ujs_li>'+lang.reset+'</ujs_li></ujs_ul></ujs_li><ujs_li class="ujs_sep"><hr/></ujs_li><ujs_li>'+lang.custom+'<ujs_ul>'+
		'<ujs_li class="ujs_hdr">'+lang.width+' <b>x</b> '+lang.height+' <b>x</b> '+lang.unit+'</ujs_li><ujs_li class="ujs_sep"><hr/>'+
		'</ujs_li><ujs_li><input size="3" maxlength="3"/> <input size="3" maxlength="3"/> <button style="width:3em!important">em'+
		'</button></ujs_li></ujs_ul></ujs_li><ujs_li class="ujs_sep"><hr/></ujs_li><ujs_li><ujs_span><input type="checkbox"/>'+
		'</ujs_span>'+lang.auto+'</ujs_li><ujs_li>'+lang.reset+'</ujs_li></ujs_ul>';
			
	var cssStyles = 
		"ujs_ul.ujs_ta_menu,ujs_ul.ujs_ta_menu ujs_ul{display:block;position:absolute!important;"+
		"color:MenuText!important;font-size:.8em!important;border:thin solid ActiveBorder!important;"+
		"padding:0!important;margin:0!important;min-width:10em!important;"+
		"background-color:Menu!important;font-size:10pt!important;padding:2px!important}"+
		"ujs_ul.ujs_ta_menu ujs_strong{font-weight:bold!important}"+
		"ujs_ul.ujs_ta_menu ujs_ul{width:12.5em!important;left:10em!important;margin-top:-1.5em!important}"+
		"ujs_ul.ujs_ta_menu ujs_li{margin:0!important;list-style:none!important;padding-left:1em!important;"+
		"width:100%!important;box-sizing:border-box;border:thin solid transparent!important;padding-right:.3em!important;"+
		"text-align:left!important;display:list-item!important;font:menu!important}"+
		"ujs_ul.ujs_ta_menu ujs_li:first-letter,ujs_ul.ujs_ta_menu ujs_li :first-letter,ujs_ul.ujs_ta_menu ujs_li.ujs_hdr{text-transform:capitalize!important}"+
		"ujs_ul.ujs_ta_menu ujs_li ujs_span{display:inline-block!important;float:right!important}"+
		"ujs_ul.ujs_ta_menu ujs_li.ujs_sep{height:.5em!important;padding:0!important}"+
		"ujs_ul.ujs_ta_menu ujs_li.ujs_sep hr{margin-top:.15em!important;}"+
		"ujs_ul.ujs_ta_menu ujs_li:hover{background-color:Highlight!important;color:HighlightText!important}"+
		"ujs_ul.ujs_ta_menu ujs_li.ujs_sep:hover,ujs_ul.ujs_ta_menu ujs_li.ujs_hdr:hover{background-color:inherit!important;color:inherit!important}"+
		"ujs_ul.ujs_ta_menu>ujs_li>ujs_ul{display:none!important}"+
		"ujs_ul.ujs_ta_menu>ujs_li:hover> ujs_ul{display:block!important}"+
		"ujs_ul.ujs_ta_menu input{display:inline-block;margin-right:0.3em}"+
		"ujs_ul.ujs_ta_menu button{display:inline-block;width:3em!important}"+
		"ujs_ul.ujs_ta_menu hr{height:0px;border:0;border-top:1px solid ActiveBorder;}"+
		"";
		
	function oneEm(){
		return arguments.callee.answer || 
		      (arguments.callee.answer = parseInt(getComputedStyle(document.documentElement,'').fontSize) );
	}
	
	var DIR_INCREASE = 1, DIR_DECREASE = 2, DIR_RESET = 3, DIR_ABS = 4;
	function changeElementDimension(elem,dimension,direction,howmuch){
		
		if( !elem )
			return;
			
		if( !elem.defaultDimensions ){
			setDefaultDimensionsForElement(elem);
			if ( direction == DIR_RESET )
				return;
		}
		else if ( direction == DIR_RESET ) {
			elem.style[dimension] = elem.defaultDimensions[dimension];
			return ;
		}
		
		//computed lengths are always in pixels
		howmuch = Math.abs(howmuch*oneEm());
		
		var currSize = getComputedStyle(elem,'')[dimension];
		var newSize = 0;
		if ( direction == DIR_DECREASE ) {
			newSize = Math.max(parseInt(currSize)-parseInt(howmuch),oneEm() * (dimension=='width'?4:3) );
		}
		else if ( direction == DIR_INCREASE ) {
			newSize = parseInt(currSize)+parseInt(howmuch);
		}
		else if ( direction == DIR_ABS ) {
			newSize = parseInt(howmuch);
		}
		else{
			throw "WRONG_ARGUMENTS_ERR";
		}
		elem.style[dimension] = newSize+'px';
	}
	
	var RSTA_HEIGHT = 2, RSTA_WIDTH = 4;
	function resizeTextAreaAuto(ta,direction){
		var lines = ta.value.replace(/\t/g,'        ').split('\n');
		
		if( direction & RSTA_HEIGHT){
			var newHeight = lines.length+2;
			if( !(direction & RSTA_WIDTH) ){
				var actualTAWidth = parseInt(getComputedStyle(ta,'').width)/oneEm()*2-2;
				for(var k=0;k<lines.length;k++)
					if( actualTAWidth < lines[k].length )
						newHeight++;
			}
			changeElementDimension(ta,'height',DIR_ABS,newHeight);
		}
		
		if( direction & RSTA_WIDTH){
			var longest = '';
			for(var k=0;k<lines.length;k++)
				if( longest.length < lines[k].length )
					longest = lines[k];
			changeElementDimension(ta,'width',DIR_ABS,Math.max(longest.length*0.5+2,3));
		}
	}
	
	function setDefaultDimensionsForElement(elem){
		var compStyles = getComputedStyle(elem,'');
		return elem.defaultDimensions = {width:compStyles.width,height:compStyles.height};
	}
	
	var activeTextArea = null;
	function makeMenu(document){
		if( textAreaResizeMenu )
			return;
			
		addCssToDocument(document,cssStyles);
			
		textAreaResizeMenu = new DOMParser().parseFromString(textAreaResizeMenuMarkup, 'text/xml').documentElement;
		if( opera && opera.version()<9 )
			textAreaResizeMenu = document.importNode(textAreaResizeMenu,true);
			
		(document.body||document.documentElement).appendChild(textAreaResizeMenu);
		
		textAreaResizeMenu.addEventListener('mousemove',function(e){
			e.preventDefault();
		},false);
		textAreaResizeMenu.addEventListener('dblclick',function(e){
			e.preventDefault();
		},false);
		
		var allLIs = textAreaResizeMenu.getElementsByTagName('ujs_li');
		
		function getListener(dim,action,howmuch){
			return function(){ changeElementDimension(activeTextArea,dim,action,howmuch); }
		}
		
		for(var k=0,dim='width';k<12;k+=11,dim='height'){
			allLIs[k + 3].addEventListener('mouseup',getListener(dim,DIR_INCREASE,1),false);
			allLIs[k + 4].addEventListener('mouseup',getListener(dim,DIR_INCREASE,5),false);
			allLIs[k + 5].addEventListener('mouseup',getListener(dim,DIR_INCREASE,20),false);
			
			allLIs[k + 7].addEventListener('mouseup',getListener(dim,DIR_DECREASE,1),false);
			allLIs[k + 8].addEventListener('mouseup',getListener(dim,DIR_DECREASE,5),false);
			allLIs[k + 9].addEventListener('mouseup',getListener(dim,DIR_DECREASE,20),false);
			
			allLIs[k +12].addEventListener('mouseup',getListener(dim,DIR_RESET,0),false);
		}
		
		allLIs[11].addEventListener('mouseup',function(e){
			//if( e.target instanceof HTMLLIElement )
				resizeTextAreaAuto(activeTextArea,RSTA_WIDTH);
		},false);
		allLIs[22].addEventListener('mouseup',function(e){
			//if( e.target instanceof HTMLLIElement )
				resizeTextAreaAuto(activeTextArea,RSTA_HEIGHT);
		},false);
		
		allLIs[25].addEventListener('mouseover',(function(realTarget){ return function(e){
			if( e.target == realTarget && !isNodeChildOf(e.relatedTarget,e.target) )
				placeDimensionsInCustomForm();
		};})(allLIs[25]),false);
		
		allLIs[30].addEventListener('mouseup',function(e){
			//if( e.target instanceof HTMLLIElement )
				resizeTextAreaAuto(activeTextArea,RSTA_WIDTH|RSTA_HEIGHT);
		},false);
		allLIs[31].addEventListener('mouseup',function(e){
			changeElementDimension(activeTextArea,'height',DIR_RESET,0);
			changeElementDimension(activeTextArea,'width',DIR_RESET,0);
		},false);
		
		
		var allInps = textAreaResizeMenu.getElementsByTagName('input');
		textAreaResizeMenu.w_inp  = allInps[0];
		textAreaResizeMenu.h_inp  = allInps[1];
		textAreaResizeMenu.wh_inp = allInps[4];
		
		textAreaResizeMenu.w_inp.addEventListener('click',function(e){
			textAreaResizeMenu.wh_inp.checked = textAreaResizeMenu.w_inp.checked && textAreaResizeMenu.h_inp.checked;
			//if( textAreaResizeMenu.w_inp.checked )
			//	resizeTextAreaAuto(activeTextArea,RSTA_WIDTH);
		},false);
		textAreaResizeMenu.h_inp.addEventListener('click',function(e){
			textAreaResizeMenu.wh_inp.checked = textAreaResizeMenu.w_inp.checked && textAreaResizeMenu.h_inp.checked;
			//if( textAreaResizeMenu.h_inp.checked )
			//	resizeTextAreaAuto(activeTextArea,RSTA_HEIGHT);
		},false);
		textAreaResizeMenu.wh_inp.addEventListener('click',function(e){
			textAreaResizeMenu.w_inp.checked = textAreaResizeMenu.h_inp.checked = textAreaResizeMenu.wh_inp.checked;
			//if( textAreaResizeMenu.wh_inp.checked )
			//	resizeTextAreaAuto(activeTextArea,RSTA_WIDTH|RSTA_HEIGHT);
		},false);
		
		textAreaResizeMenu.cw_inp = allInps[2];
		textAreaResizeMenu.ch_inp = allInps[3];
		textAreaResizeMenu.unitButton = textAreaResizeMenu.getElementsByTagName('button')[0];
		
		textAreaResizeMenu.cw_inp.addEventListener('keyup',function(e){	
			if( e.keyCode == 13 ){
				flushCustomFormData();
				textAreaResizeMenu.ch_inp.focus();
				textAreaResizeMenu.ch_inp.select();
			}
			e.preventDefault();
		},false);
		textAreaResizeMenu.ch_inp.addEventListener('keyup',function(e){	
			if( e.keyCode == 13 ){
				flushCustomFormData();
			}
			e.preventDefault();
		},false);
		textAreaResizeMenu.unitButton.addEventListener('click',function(e){
			var text = e.target.firstChild.nodeValue;
			if( text == 'em' ){
				text = 'px';
				textAreaResizeMenu.cw_inp.value = Math.round(parseFloat(textAreaResizeMenu.cw_inp.value)*oneEm());
				textAreaResizeMenu.ch_inp.value = Math.round(parseFloat(textAreaResizeMenu.ch_inp.value)*oneEm());
			}
			else{
				text = 'em';
				textAreaResizeMenu.cw_inp.value = Math.round(parseInt(textAreaResizeMenu.cw_inp.value)/oneEm()*10)/10;
				textAreaResizeMenu.ch_inp.value = Math.round(parseInt(textAreaResizeMenu.ch_inp.value)/oneEm()*10)/10;
			}
			e.target.firstChild.nodeValue = text;
		},false);
	}
	
	function placeDimensionsInCustomForm(){
		var compSz = getComputedStyle(activeTextArea,'');
		if( textAreaResizeMenu.unitButton.firstChild.nodeValue == 'em' ){
			textAreaResizeMenu.cw_inp.value = Math.round( parseInt(compSz.width) / oneEm() * 10 ) / 10;
			textAreaResizeMenu.ch_inp.value = Math.round( parseInt(compSz.height) / oneEm() * 10 ) / 10;
		}
		else{
			textAreaResizeMenu.cw_inp.value = parseInt(compSz.width);
			textAreaResizeMenu.ch_inp.value = parseInt(compSz.height);
		}
	};
	
	function flushCustomFormData(){
		var newWidth = parseFloat(textAreaResizeMenu.cw_inp.value), newHeight = parseFloat(textAreaResizeMenu.ch_inp.value);
		if(textAreaResizeMenu.unitButton.firstChild.nodeValue == 'px' ){
			newWidth = newWidth/oneEm();
			newHeight = newHeight/oneEm();
		}
		changeElementDimension(activeTextArea,'height',DIR_ABS,newHeight);
		changeElementDimension(activeTextArea,'width',DIR_ABS,newWidth);
	};
	
	function textAreaChangeListener(e){
		if( !textAreaResizeMenu || !(e.target instanceof HTMLTextAreaElement) )
			return;
		if( typeof e.target.sPrevValue == 'undefined' ){
			e.target.sPrevValue = e.target.value;
		}
		else if( e.target.sPrevValue != e.target.value ){
			e.target.sPrevValue = e.target.value;
			
			if ( textAreaResizeMenu.w_inp.checked )
				resizeTextAreaAuto(e.target,RSTA_WIDTH);
				
			if ( textAreaResizeMenu.h_inp.checked )
				resizeTextAreaAuto(e.target,RSTA_HEIGHT);
		}
	}
	addEventListener('click',function(e){
		if( textAreaResizeMenu && !isNodeChildOf(e.target,textAreaResizeMenu) && e.target!=textAreaResizeMenu )
			textAreaResizeMenu.style.display='none';
	},true);
	
	addEventListener(shortcut.eventType,function(e){
		if( textAreaResizeMenu && textAreaResizeMenu.style.display != 'none' ){ return; }
		
		if( !e ){ return; }
		
		var keys = (e.altKey   == (shortcut.altKey  &&true)) && 
				   (e.ctrlKey  == (shortcut.ctrlKey &&true)) &&
		           (e.shiftKey == (shortcut.shiftKey&&true));
			
		if( !(e.target instanceof HTMLTextAreaElement) || !keys )
			return;
		
		if( activeTextArea && activeTextArea != e.target ){
			activeTextArea.removeEventListener('change',textAreaChangeListener,false);
			activeTextArea.removeEventListener('keyup',textAreaChangeListener,false);
		}
		activeTextArea = e.target;
		activeTextArea.addEventListener('change',textAreaChangeListener,false);
		activeTextArea.addEventListener('keyup',textAreaChangeListener,false);
		
		makeMenu(e.target.ownerDocument);
		textAreaResizeMenu.style.top = (window.pageYOffset+e.clientY-oneEm())+'px';
		textAreaResizeMenu.style.left = (window.pageXOffset+e.clientX-oneEm())+'px';
		textAreaResizeMenu.style.display='';
		
		e.preventDefault();
		
	},false);
	
	
})( window.opera );

