

/*

user_pref("capability.policy.policynames", "allowclipboard");
user_pref("capability.policy.allowclipboard.sites", "http://www.example.com");
user_pref("capability.policy.allowclipboard.Clipboard.cutcopy", "allAccess");
user_pref("capability.policy.allowclipboard.Clipboard.paste", "allAccess");


https://addons.mozilla.org/extensions/moreinfo.php?application=firefox&id=852


http://www.mozilla.org/editor/midasdemo/securityprefs.html

*/


	// inclusioni richieste

$().ready(function () {

	FlexJS.Loader.LoadJS('js/jq/jDimensions.js');
});

	// definizione del NS FlexJS

FlexJS = window.FlexJS || {};

FlexJS.isIE = jQuery.browser.msie;
FlexJS.isGecko = jQuery.browser.mozilla;

FlexJS.AreaLite = function(el) {

		// inizializza i membri statici

	if (typeof FlexJS.AreaLite.sCSSRule === 'undefined') {

			// estrae dal CSS di pagina le regole che servono

		var styles = ['.userFormat1', '.userFormat2', '.userFormat3', '.editPar'];

		var ss = FlexJS.CSSUtils.GetCSS(document, 'BlobEdit');

		FlexJS.AreaLite.sCSSRule = [];
		for (var i = 0, m = styles.length; i < m; i++) {

			var r = FlexJS.CSSUtils.GetCSSRule(document, ss, styles[ i ]);

				// gli stili potrebbero non essere stati definiti

			if (r !== false)
				FlexJS.AreaLite.sCSSRule[ FlexJS.AreaLite.sCSSRule.length ] = r;
		}

			// un array che contiene gli ID degli oggetti su cui
			// è stata attivata l'area

		FlexJS.AreaLite.sIDs = [];

			// imposta una funzione globale, handle per
			// l'abilitazione delle textarea lite che sono
			// nascoste al momento dell'istanziazione

		window.onToggleDIV = FlexJS.AreaLite.onToggleDIV;

			// inizializza la clipboard solamente se ho almeno
			// una TA editabile nel documento

		FlexJS.Clipboard.Init();
	}

	this.el = el;

		// inserisce l'elemento nell'array per tenere
		// traccia degli oggetti su cui è stata creata la TA

	FlexJS.AreaLite.sIDs[ el.id ] = this;

	this.Attach();
}

	// funzione per l'abilitazione deferred delle aree
	// editabili (*)

FlexJS.AreaLite.onToggleDIV = function (el) {

	for (var id in FlexJS.AreaLite.sIDs) {

		// TBD: un metodo per l'attivazione del designmode
		// con curryng quando ha successo	
		var o = FlexJS.AreaLite.sIDs[ id ];
		if (o.el.contentDocument.designMode !== 'on') {

			// il codice di abilitazione è duplicato nella FlexJS.AreaLite.prototype.Attach
			try {
				
				o.el.contentDocument.designMode = 'on';
	
					// disabilita gli stili inline
	
				o.el.contentDocument.execCommand('styleWithCSS', false, false);

			} catch (err) {
		
				// l'abilitazione può fallire se l'elemento non è visibile
				// in questo caso l'attivazione viene ritardata al primo focus
				// dell'elemento (*)
			}
		}
		
		o.AdjustHeight()
	}

/*
	// TBD: iterare sugli elementi di FlexJS.AreaLite.sIDs
	var els = $('iframe.editorLite', el).each(function() {

		if (this.contentDocument.designMode !== 'on') {

			this.contentDocument.designMode = 'on';

				// disabilita gli stili inline

			this.contentDocument.execCommand('styleWithCSS', false, false);
//			this.contentDocument.execCommand('useCSS', false, false);
		}

//		FlexJS.AreaLite.sIDs[ this.id ].AdjustHeight();
	});
*/
}

FlexJS.AreaLite.prototype.Attach = function() {

	var el = this.el;

		// abilita la modalità di editing

	try {

		el.contentDocument.designMode = 'on';

			// disabilita gli stili inline
			// per qualche motivo non documentato è necessario impostare
			// il comando con un po' di ritardo ...
		
		setTimeout(function () { el.contentDocument.execCommand('styleWithCSS', false, false); }, 1000);
//		el.contentDocument.execCommand('useCSS', false, false);

	} catch (err) {

		// l'abilitazione può fallire se l'elemento non è visibile
		// in questo caso l'attivazione viene ritardata al primo focus
		// dell'elemento (*)
	}

		// trova i bottoni sapendo che il loro ID
		// è costruito come AL_<function>_<name>
		// con <function> che vale 'B', 'I', 'U', 'X'

		// TBD: produrre dinamicamente il DOM dei bottoni

		// uso 'me' in modo da creare una closure e poter
		// far chiamare alla lambda function il metodo di
		// questo oggetto

	var me = this;

	$('#AL_' + 'B' + '_' + el.id).click(function(e) { return me.onBold(e); });
	$('#AL_' + 'I' + '_' + el.id).click(function(e) { return me.onItalic(e); });
	$('#AL_' + 'U' + '_' + el.id).click(function(e) { return me.onUnderline(e); });
	$('#AL_' + 'X' + '_' + el.id).click(function(e) { return me.onCancelFormat(e); });
	$('#AL_' + 'L' + '_' + el.id).click(function(e) { return me.onLink(e); });

		// aggiunge due gestori per il get/set di un link

	el.FlexAddLink = function(url, desc) { return me.onAddLink(url, desc); };
	el.FlexGetLink = function(url, desc) { return me.onGetLink(url, desc); };

		// operazioni sul documento

	var elCD = this.el.contentDocument;

		// disabilita lo spell checking

	elCD.body.spellcheck = false;

		// aggiunge handler per la gestione del cut/paste

	elCD.addEventListener('keydown', function(e) { return me.onKeyDown(e); }, false);
	elCD.addEventListener('keyup', function(e) { return me.onKeyUp(e); }, false);
	elCD.addEventListener('keypress', function(e) { return me.onKeyPress(e); }, false);

		// aggiunge alle classi del body la editPar

	$('body', elCD).addClass('editPar').css({margin: 1});
	$(el).css({overflow: 'hidden'});

/*
	elCD.addEventListener('focus', function(e) { $('body', this.contentDocument).addClass('editPar').css({margin: 5}); }, false);
	elCD.addEventListener('blur', function(e) { $('body', this.contentDocument).addClass('editPar').css({margin: 0}); }, false);

	var sn = elCD.createElement('style');
	sn.setAttribute('type', 'text/css');
	sn.setAttribute('media', 'screen'); 
//	sn.appendChild(document.createTextNode(selector + ' {' + declaration + '}'));
	sn.appendChild(elCD.createTextNode('body::-moz-selection' + ' {' + 'background-color: black; color: yellow; ' + '}'));
	sn.appendChild(elCD.createTextNode('body:focus::-moz-selection' + ' {' + 'background-color: red; color: yellow; ' + '}'));

	elCD.getElementsByTagName('head')[0].appendChild(sn);
*/

		// disabilita il menu contestuale per evitare
		// il paste

	elCD.addEventListener('contextmenu', function(e) { return me.onMouseDown(e); }, false);

		// aggiunge un CSS per la definizione degli stili custom

	var css = FlexJS.CSSUtils.AddCSS(elCD, 'FlexDynamicCSS');
	for (var i = 0, m = FlexJS.AreaLite.sCSSRule.length; i < m; i++)
		FlexJS.CSSUtils.AddCSSRule(elCD, css, FlexJS.AreaLite.sCSSRule[i]);

	this.AdjustHeight();
}

FlexJS.AreaLite.prototype.AdjustHeight = function() {

		// adatta la dimensione dell'iframe al contenuto
		// ma con un minimo di 15 pt, in questo modo se il paragrafo
		// è vuoto non collassa

	var h = Math.max(this.el.contentDocument.body.offsetHeight, 15);

		// siccome questo codice viene eseguito alla pressione di ogni tasto,
		// per evitare di modificare l'altezza troppo frequentemente tengo
		// traccia del suo valore attuale e la modifico solo se cambiata
		// effettivamente

	if (h != this.mCurHeight) {
		
		this.mCurHeight = h;
		$(this.el).height(h);
	}
}

FlexJS.AreaLite.prototype.onBold = function(e) {

	this.el.contentDocument.execCommand('bold', false, null);

	this.el.contentWindow.focus();

	return false;
}

FlexJS.AreaLite.prototype.onItalic = function(e) {

	this.el.contentDocument.execCommand('italic', false, null);

	this.el.contentWindow.focus();

	return false;
}

FlexJS.AreaLite.prototype.onUnderline = function(e) {

	var elCD = this.el.contentDocument;
	var styleName = 'userFormat3';

		// usa l'editor per assegnare un tag FONT alla selezione ...

	elCD.execCommand('fontsize', false, styleName);

		// ... poi lo cerca per cambiare stile all'elemento

	var innerEls = elCD.getElementsByTagName('font');
	for (var idx = 0; (innerEl = innerEls[idx]); idx++) {

/*
		if (innerEl.style.fontFamily === styleName) {
		
			innerEl.className = innerEl.style.fontFamily;
			innerEl.removeAttribute('style', 0);
		}
*/

		if (innerEl.size === styleName) {
		
//			innerEl.size = '+0';

			innerEl.className = styleName;
			innerEl.removeAttribute('size', 0);
		}
	}

	this.el.contentWindow.focus();

	return false;
}

FlexJS.AreaLite.prototype.onCancelFormat = function(e) {

	this.el.contentDocument.execCommand('unlink', false, null);
	this.el.contentDocument.execCommand('removeformat', false, null);

	this.el.contentWindow.focus();

	return false;
}

FlexJS.AreaLite.prototype.onLink = function(e) {

		// apre il popup per la selezione della pagina

	PageSelectorTextArea(this.el.id, FlexJS.AppConfigure.Get('kBaseURL') + 'pages/PopupPageSelector.php', this.el.id);

	e.preventDefault();

	return false;
}

FlexJS.AreaLite.prototype.onAddLink = function(url, desc) {

 	var s = this.el.contentWindow.getSelection();
	var r = s.getRangeAt(0);

		// se è un nodo interno, davanti viene messo un finto
		// protocollo, altrimenti non si riesce ad inserire il nodo

	url = 'link:' + url;

	if (r.collapsed) {

		this.el.contentDocument.execCommand('inserthtml', false, "<a href='" + url + "'>" + desc + "</a>");

	} else
		this.el.contentDocument.execCommand('createlink', false, url);

	return false;
}

FlexJS.AreaLite.prototype.onGetLink = function() {

	var s = this.el.contentWindow.getSelection();
	var r = s.getRangeAt(0);

	if (r.collapsed)
		return false;

	var selNode = null;

    if ( s.anchorNode.childNodes.length > s.anchorOffset && s.anchorNode.childNodes[s.anchorOffset].nodeType === 1 ) {

      selNode = s.anchorNode.childNodes[ s.anchorOffset ];

    } else if ( s.anchorNode.nodeType === 1 ) {

      selNode = s.anchorNode;
    }

	if (selNode !== null && selNode.nodeType === 1 && selNode.tagName === 'A') {

			// se è un nodo interno, davanti viene messo un finto
			// protocollo, altrimenti non si riesce ad inserire il nodo

		return selNode.href.replace(/^link:/, '');
	}

	return false;
}

	// per adesso keydown e keyup non sono usati

FlexJS.AreaLite.prototype.onKeyDown = function(e) {}
FlexJS.AreaLite.prototype.onKeyUp = function(e) {}

FlexJS.AreaLite.prototype.onKeyPress = function(e) {

		// 118: v
		// 45: INS

     if ((e.ctrlKey && e.charCode === 118) || (e.shiftKey && e.keyCode === 45)) {

			// recupera il contenuto della clipboard

		var text = FlexJS.Clipboard.Get();
		if (text === false) {

				// si è verificato un errore al caricamento del clipboard
				// è probabile che l'utente non abbia le impostazioni corrette
				// per poter accedere

			FlexJS.Loader.LoadJS('js/jq/jDialog/jDialog.js', function () {

				new FlexJS.UI.Dialog('Attenzione',
						"Non &egrave; possibile effettuare azioni di copia e incolla nei paragrafi di testo "
						+ "poich&eacute; il browser &egrave; attualmente impostato per non "
						+ "consentire tali azioni.<br />"
						+ "Per maggiori informazioni sulle regole di sicurezza di utilizzo "
						+ "dell'editor visuale di Mozilla consultare questo documento:<br />"
						+ "<a href='http://www.mozilla.org/editor/midasdemo/securityprefs.html' xml:lang='en' onclick='TBHack.Open(this.href); return false;'>"
						+ "Setting Prefs for the Mozilla Rich Text Editing Demo"
						+ "</a>."
						+ "<br /><br />"
						+ "&Eacute; disponibile una "
						+ "<a href='https://addons.mozilla.org/en-US/firefox/addon/852' onclick='TBHack.Open(this.href); return false;'>estensione</a> "
						+ "che permette in modo rapido ed agevole di modificare le regole di "
						+ "sicurezza ed abilitare il copia e incolla."
					,
					470, 200);
			});

		} else {

			// text = text.replace(/\n/g, '<br />');
			this.el.contentDocument.execCommand('inserthtml', false, text);
		}

		return e.preventDefault();
    }

		// deve aspettare che il carattere sia inserito
		// il timeout di 1/1000 di secondo sfrutta il fatto che JS
		// non è multithread, quindi quest'azione sarà eseguita al termine
		// del servizio dell'evento

	var me = this;
	setTimeout(function () { me.AdjustHeight(); }, 1);

	return true;
}

FlexJS.AreaLite.prototype.onMouseDown = function(e) {

	e.stopPropagation(); 

	return false;
}

	// widget hide/show
	
FlexJS.HideShow = function(cnt, hdlo, hdlc) {

	this.mContent = $('#' + cnt)[0];
	this.mHandleOpen = $('#' + hdlo)[0];
	this.mHandleClose = $('#' + hdlc)[0];

	var me = this;
	$(this.mHandleOpen).click(function() { me.Open(); });
	$(this.mHandleClose).click(function() { me.Close(); });
	
	this.Close();
}

FlexJS.HideShow.prototype.Open = function() {

	$(this.mContent).show();

	$(this.mHandleOpen).hide();
	$(this.mHandleClose).show();
}

FlexJS.HideShow.prototype.Close = function() {

	$(this.mContent).hide();	

	$(this.mHandleOpen).show();
	$(this.mHandleClose).hide();
}

	//
	// stylesheet handling
	//

FlexJS.CSSUtils = window.FlexJS.CSSUtils || {}

FlexJS.CSSUtils.GetCSS = function(document, name) {

	var ss = null;
	for (var i = 0; i < document.styleSheets.length; i++) {

		if (document.styleSheets[i].href.indexOf(name) !== -1) {

			ss = document.styleSheets[i];
			break;
		}
	}

	return ss;
}

FlexJS.CSSUtils.AddCSS = function(document, title) {

	var node = document.createElement('style');

	node.type = 'text/css';
	node.rel = 'stylesheet';
	node.media = 'screen';
	node.title = title;
	
	document.getElementsByTagName('head')[0].appendChild(node);
	
	return node;
}

FlexJS.CSSUtils.GetCSSRule = function(document, ss, ruleName) {

	ruleName = ruleName.toLowerCase();

	var j = 0;
	var cssRule = false;
	do {

		cssRule = ss.cssRules[j];

		if (cssRule && cssRule.selectorText.toLowerCase() === ruleName)
			return cssRule;

		j++;

	} while (cssRule);

	return false;
}

FlexJS.CSSUtils.AddCSSRule = function(document, ss, rule) {

   document.styleSheets[0].insertRule(rule.cssText, 0);
}

FlexJS.CSSUtils.ClassNames = function(el) {

	return el.className.split(' ');
}

FlexJS.CSSUtils.HasClassName = function(el, sClassName) {

	var p = FlexJS.CSSUtils.ClassNames(el);

	for (var i = 0, l = p.length; i < l; i++)
		if (p[i] === sClassName)
			return true;
	
	return false;
}

	//
	// gestione del clipboadr per Mozilla
	//

FlexJS.Clipboard = window.FlexJS.Clipboard || function () {

		// quando ho il DOM creato, aggiungo l'iframe

	// $(document).ready(function () { FlexJS.Clipboard.Init(); });

	return {};
}();

FlexJS.Clipboard.Init = function () {

	if (typeof FlexJS.Clipboard.sFrameObj === 'undefined') {

		var iframe = document.createElement('iframe');

		iframe.setAttribute('id', 'FlexPasteFrame');
 		iframe.style.border = iframe.style.width = iframe.style.height
			= iframe.style.width = iframe.style.height = '0px';

		iframe.onload = FlexJS.Clipboard._InitCont;

		FlexJS.Clipboard.sFrameObj = document.body.appendChild(iframe);
	}
}

FlexJS.Clipboard._InitCont = function () {

	if (typeof FlexJS.Clipboard.sFrameObj !== 'undefined') {

			// abilita la modalità di editing

		try {

			FlexJS.Clipboard.sFrameObj.contentDocument.designMode = 'on';
			
		} catch (err) {}
	}
}

FlexJS.Clipboard.Put = function (text) {

	alert('TBD');

	return;
}

FlexJS.Clipboard.Get = function () {

	var elCD = FlexJS.Clipboard.sFrameObj.contentDocument;

	try {

			// prima di fare il paste, seleziona tutto: in questo modo
			// il nuovo contenuto sostituisce il vecchio

		elCD.execCommand('selectall', false, null);
		elCD.execCommand('paste', false, null);

		FlexJS.HTMLUtils.CleanMozDOM(elCD.body);

		var t = FlexJS.HTMLUtils.GetCleanHTML(elCD.body);

		return t;

	} catch (e) {

			// non ho i permessi per cut/paste
	
		return false;
	}
}

	//
	// pulizia di codice HTML
	//

FlexJS.HTMLUtils = window.FlexJS.HTMLUtils || {}

	// 'font' viene messo in fase di editing e trasformato in 'span'
	// 'b' ed 'i' vengono trasformati rispettivamente in 'strong' ed 'em'

FlexJS.HTMLUtils.sAllowedTags = ['br', 'b', 'strong', 'em', 'i', 'font', 'span', 'a'];

FlexJS.HTMLUtils.GetCleanHTML = function (el) {

	if (el.nodeType === 3)
		return el.nodeValue;
	else if (el.nodeType === 1) {

		var cnt = '';
		for (var i = 0, m = el.childNodes.length; i < m; i++)
			cnt += FlexJS.HTMLUtils.GetCleanHTML(el.childNodes[i]);

		var out = '';
		var tag = el.tagName.toLowerCase();
		if (FlexJS.Utils.InArray(tag, FlexJS.HTMLUtils.sAllowedTags)) {

				// converte alcuni tag

			switch (tag) {

				case 'b':		tag = 'strong'; break;
				case 'i':		tag = 'em'; break;
				case 'font':	tag = 'span'; break;
			}

			if (cnt !== '') {

				var cl = '';
				if (el.className != '')
					cl = " class='" + el.className + "'"

				var href = '';
				if (el.href && el.href != '')
					href = " href='" + el.href + "'"

				out = '<' + tag + cl + href + '>' + cnt + '</' + tag + '>';

			} else
				out = '<' + tag + ' />';

		} else
			out = cnt;

		return out;
	}

	return '';
}

FlexJS.HTMLUtils.CleanMozDOM = function (el) {

		// se è un 'p' al termine del quale ci sono <br> vuoti, li elimina

	if (el.nodeType === 1 && el.tagName.toLowerCase() === 'p' && el.childNodes.length > 1) {

		if (el.lastChild !== null && el.lastChild.nodeName.toLowerCase() === 'br')
			el.removeChild(el.lastChild);
	}

		// CleanMozHTML modifica il DOM

	for (var i = 0, m = el.childNodes.length; i < m; i++)
		FlexJS.HTMLUtils.CleanMozDOM(el.childNodes.item(i));
}

	//
	// utility generiche
	//

FlexJS.Utils = window.FlexJS.Utils || {}

FlexJS.Utils.InArray = function (needle, haystack) {

	for (var i = 0, m = haystack.length; i < m; i++)
		if (haystack[i] === needle)
			return true;

	return false;
}

FlexJS.Utils.Random = function (min, max) {

	if (! min) min = 0;
	if (! max) max = 10e10;

	return Math.round(max * Math.random() + min)
}

	// quoting di un valore XML
	// usa virgolette semplici o doppie se all'interno del
	// valore non ne compaiono, altrimenti procede all'escapeing
	// del contenuto

FlexJS.Utils.QuoteXMLAttr = function (v) {

		// ottiene una rappresentazione stringa
		// del valore dell'oggetto

	v = '' + v;

	var apos_pos = v.indexOf("'");
	if (apos_pos === -1)
		return "'" + v + "'";

	var quot_pos = v.indexOf('"');
	if (quot_pos === -1)
		return '"' + v + '"';

	var re = new RegExp("'", 'g');

	return "'" + v.replace(re, '&apos;') + "'";
}

	//
	// accesso alla configurazione
	//

FlexJS.AppConfigure = window.FlexJS.AppConfigure || {};

FlexJS.AppConfigure.Get = function (pName) {

	return gAppConfigure[pName];
}

	//
	// AJAX query
	//

FlexJS.Ajax = window.FlexJS.Ajax || (function () {

		// inizializza le funzionalità ajax di jq
/*
	$.ajaxSetup( {
		url: FlexJS.AppConfigure.Get('kBaseURL') + 'pages/Lite/AS.php',
		global: false,
		type: 'POST'
	} );
*/
	return {};

})();

FlexJS.Ajax.Query = function(what, cb) {

	$.get(FlexJS.AppConfigure.Get('kBaseURL') + 'pages/Lite/AS.php', {H: what}, cb);
}


	//
	// loader dinamico
	//

/*

	FlexJS.Loader.LoadJS('path/to/file.js', function () { use JS });

*/

FlexJS.Loader = window.FlexJS.Loader || {};

FlexJS.Loader.sCache = [];
FlexJS.Loader.sImageCache = [];

	// carica un JS esterno
	// siccome JS non è multithread, uso la callback da posizionare sull'onload
	// dell'elemento script, in modo da creare una continuazione

FlexJS.Loader.LoadJS = function (path, cb, useUniqueID) {

	path = path instanceof Array ? path : [path];
	useUniqueID = useUniqueID || false;

		// se ho già caricato l'include mi limito ad eseguire la CB

	for (var i = 0, m = path.length; i < m; i++) {

		var fName = path[i];

//		if (FlexJS.Utils.InArray(fName, FlexJS.Loader.sCache)) {
		if (FlexJS.Loader.sCache[ fName ]) {

				// se siamo all'ultimo elemento

			if (i === m - 1) {

				if (cb) cb();

				return;
			}
		}

		var script = document.createElement('script');

			// aggiunge al nome del file un identificativo numerico univoco
			// per forzare il caricamento (no cache) per il debug

		script.type = 'text/javascript';
		script.src = FlexJS.AppConfigure.Get('kBaseURL') + fName + (useUniqueID ? ('?v=' + FlexJS.Utils.Random(1, 9999)) : '');

			// metto la callback solamente sull'ultimo elemento

		if (i === m - 1)
			script.onload = cb || function () {};

		document.getElementsByTagName('head')[0].appendChild(script);  

//		FlexJS.Loader.sCache[ FlexJS.Loader.sCache.length ] = fName;
		FlexJS.Loader.sCache[ fName ] = true;
	}
}

FlexJS.Loader.LoadCSS = function (path) {

//	if (FlexJS.Utils.InArray(path, FlexJS.Loader.sCache))
	if (FlexJS.Loader.sCache[path])
		return;

	var css = document.createElement('link');

	css.type = 'text/css';
	css.rel = 'stylesheet';
	css.href = FlexJS.AppConfigure.Get('kBaseURL') + path; //'js/jq/jDialog/jDialog.css';
	css.media = 'screen';

	document.getElementsByTagName('head')[0].appendChild(css);

//	FlexJS.Loader.sCache[ FlexJS.Loader.sCache.length ] = path;
	FlexJS.Loader.sCache[ path ] = true;
}

FlexJS.Loader.LoadImage = function (path) {

	if (FlexJS.Loader.sImageCache[path])
		return FlexJS.Loader.sImageCache[path].src;

	var img = FlexJS.Loader.sImageCache[path] = document.createElement('img');

	img.src = FlexJS.AppConfigure.Get('kBaseURL') + path;

	document.getElementsByTagName('head')[0].appendChild(img);

	return img.src;
}
