/*
 * Edytor WYSIWYG, działający pod przeglądarkami Microsoft Internet Explorer, Firefox, Mozilla.
 * Poprawianie działa tylko _jeden_ edytor na stronie (ze względu na globalne tablice buttons oraz cmdButtons).
 * Edytor powstał na potrzeby artykułu opublikowanego w Magazynie Internet.
 *
 * Edytor można swobodnie wykorzystywać do wszelkich celów, nie ponoszę jednak odpowiedzialności za jego błędne działanie, oraz za szkody wynikłe z jego funkcjonowania.
 *
 * Autor: Marcin Staniszczak
 * e-mail: marcin@staniszczak.pl
 *
 * Kodowanie: UTF-8
 */

var UserAgent = navigator.userAgent.toLowerCase();
isIE = ((UserAgent.indexOf("msie") != -1) && (UserAgent.indexOf("opera") == -1)); 
isGecko = (UserAgent.indexOf("gecko") != -1);
isSafari = (UserAgent.indexOf("safari") != -1);
isKonqueror = (UserAgent.indexOf("konqueror") != -1);


var buttons = new Array();
var cmdButtons = new Array();

/**
 * Konstruktor
 *
 * @access public
 * @param string nazwa edytora (id textarea)
 */
function JSEdit(name) {
	//zapamiętujemy nazwę edytora
	this.name = name;
	
	this.textArea = null;
	
	
	//editMode ustawiamy na tryb tekstowy
	this.editMode = 0;
	
	//inicjujemy klasę odpowiedzialną za wyświetlenie paska narzędzi
	this._ToolBar = new JSEdit.ToolBar(this);
}

/**
 * Uruchomienie edytora - zastępuje textarea polem iframe
 *
 * @access public
 */
JSEdit.prototype.write = function() {
	if(!isIE && !isGecko)
		return;

	/*
	 * Pobieramy obiekt textarea oraz jego wymiary
	 */
	this.textArea = document.getElementById(this.name);
	
	var width = this.textArea.offsetWidth;
	var height = this.textArea.offsetHeight;
		
	var DIVContainer = document.createElement('div');
	DIVContainer.className = 'WebEdit';
	this.DIVContainer = DIVContainer;
	
	//ustalamy szerokość edytora
	this.DIVContainer.style.width = width+4+'px'
	
	this._ToolBar.write();	 
	
	this.textArea.parentNode.insertBefore(this.DIVContainer, this.textArea);	 	
	this.textArea.style.display = 'none';
	
	/*
	 * Tworzymy iframe-a który będzie pracował jako edytorek WYSIWYG
	 */
	var ifRame = document.createElement('iframe');
	DIVContainer.appendChild(ifRame);
	ifRame.id = this.name+'_ifr'
	this.ifRame = ifRame;
		
	ifRame.style.width = width+'px';
	ifRame.style.height = height+'px';
	

	this.ifRame.contentWindow.document.open();
	
	//wpisujemy standardowe ramy edytowanego dokumentu w iframe-a. To w body będzie wpisywana już konkretna zawartość
	this.ifRame.contentWindow.document.write('<body></body>');
	this.ifRame.contentWindow.document.close();
	
	/*
	 * Dodanie eventów
	 */
	var edit = this;
	JSEdit.addEvent(this.ifRame.contentWindow.document, 'keydown',  
		function(event) {
			return edit.editEvent(isIE?edit.ifRame.contentWindow.event:event)
		}
	);
	JSEdit.addEvent(this.ifRame.contentWindow.document, 'keypress',  function(event) {
			return edit.editEvent(isIE?edit.ifRame.contentWindow.event:event)
		}
	);
	JSEdit.addEvent(this.ifRame.contentWindow.document, 'mousedown',  function(event) {
			return edit.editEvent(isIE?edit.ifRame.contentWindow.event:event)
		}
	);
	JSEdit.addEvent(this.ifRame.contentWindow.document, 'drag',  function(event) {
			return edit.editEvent(isIE?edit.ifRame.contentWindow.event:event)
		}
	);
	
	
	/*
	 * Przechodzimy w tryb WYSIWYG
	 */
	this.setMode(1);
}


/**
 * Ustawia tryb pracy edytora
 *
 * @ccess public
 * @param integer 0-tryb tekstowy, 1-tryb WYSIWYG
 */
JSEdit.prototype.setMode = function(mode) {
	switch(mode) {
		case 0: //tryb tekstowy
			this.ifRame.style.display = 'none';
			this.textArea.value = this.getContent();
			this.textArea.style.display = 'block';
		break;
		case 1: //tryb WYSIWYG
			this.textArea.style.display = 'none';
			this.ifRame.style.display = 'block';
			
			/*
			 * Przechodzimy w tryb WYSIWYG - robi się to inaczej w Internet Explorerze i inaczej w Gecko
			 */
			if(isGecko) {
				try {
					this.ifRame.contentDocument.designMode = 'On';
				} catch(e) {
				}
			} else {
				this.ifRame.contentWindow.document.body.contentEditable = true;
			}
			
			// wypełniamy body iframe-a treścią
			this.ifRame.contentWindow.document.body.innerHTML = this.getContent();
		break;
	}
	this.editMode = mode;
	this.focusEditor();
}


/**
 * Pobiera treść z edytora
 *
 * @access public
 * @return string pobrany kod HTML edytowanego dokumentu
 */
JSEdit.prototype.getContent = function() {
	switch(this.editMode) {
		case 1:		
			return this.ifRame.contentWindow.document.body.innerHTML;
		break;
		case 0:
			return this.textArea.value;
		break;
	}	
}


/**
 * Ustawia focus na aktywnym polu edytora
 *
 * @access public
 */
JSEdit.prototype.focusEditor = function() {
	
	// sprawdzamy w jakim trybie znajduje się edytor
	switch(this.editMode) {
		//i w zależności od trybu ustawiamy focus albo na pole iframe albo na textarea
		case 1:
			this.ifRame.contentWindow.focus();
		break;
		case 0:
			this.textArea.focus();
		break;
	}
}

/**
 * Eventy edytora - odpowiedzialne za odświeżanie paska narzędzi
 *
 * @access public
 * @param Event
 */
JSEdit.prototype.editEvent = function(e) {
	this.refreshToolBar();
}

/**
 * Odświerzanie paska narzędzi
 *
 * @access public
 */
JSEdit.prototype.refreshToolBar = function() {
	var objDoc = this.ifRame.contentWindow.document;
	
	/*
	 * przechodzimy w pętli tablicę cmdButtons otrzymując 
	 * po kolei wszystkie komendy obsługiwane przez pasek narzędzi
	 */	 
	for(i=cmdButtons.length-1; i>=0; i--) {
		// sprawdzamy czy dana komenda jest aktywna w miejscu znajdowania  się kursora
		if(objDoc.queryCommandState(cmdButtons[i])) {
			buttons[cmdButtons[i]]['active'] = false;
			buttons[cmdButtons[i]]['obj'].className = 'JSEditMenuIcon_pressed';
		} else {
			buttons[cmdButtons[i]]['active'] = true;
			buttons[cmdButtons[i]]['obj'].className = 'JSEditMenuIcon';
		}
	}
}

/**
 * Wykonuje komendę, odświeża pasek narzędzi, oraz ustawia focus na polu edycyjnym
 *
 * @access public
 */
JSEdit.prototype.execCommand = function(command, settings) {	
	this.ifRame.contentWindow.document.execCommand(command, false, settings);
	this.refreshToolBar();
	this.focusEditor();
}

/**
 * Konstruktor paska narzędzi
 *
 * @access public
 * @param JSEdit obiekt edytora
 */
JSEdit.ToolBar = function(edit) {
	this.edit = edit;
	
	//tworzymy ramy paska narzędzi
	var ToolBarDiv = document.createElement('div');
	this.ToolBarDiv = ToolBarDiv;
	this.ToolBarDiv.className = 'JSEditMenu';
	this.ToolBarDiv.unselectable = '1';	
}

/**
 * Wpisujemy pasek narzędzi nad pole edycyjne
 *
 * @access public
 */
JSEdit.ToolBar.prototype.write = function() {
	this.writeButton('Bold', 'bold', 'Pictures/bold.gif');
	
	this.writeButton('Italic', 'italic', 'Pictures/italic.gif');
	this.writeButton('Underline', 'underline', 'Pictures/underline.gif');

	this.writeButton('Justify left', 'justifyleft', 'Pictures/justifyleft.gif');
	this.writeButton('Justify right', 'justifyright', 'Pictures/justifyright.gif');
	this.writeButton('Justify center', 'justifycenter', 'Pictures/justifycenter.gif');
	this.writeButton('Justify full', 'justifyfull', 'Pictures/justifyfull.gif');

	this.writeButton('Insert ordered list', 'insertorderedlist', 'Pictures/numlist.gif');
	this.writeButton('Insert unordered list', 'insertunorderedlist', 'Pictures/bullist.gif');

	//dodanie paska narzędzi do elementu div zawierającego pole edycyjne
	this.edit.DIVContainer.appendChild(this.ToolBarDiv);
}

/**
 * Stworzenie przycisku
 *
 * @access public
 * @param string nazwa przycisku
 * @param string komenda do wykonania po kliknięciu na przycisku
 * @param string ścieżka do obrazka wyświetlanego na przycisku
 */
JSEdit.ToolBar.prototype.writeButton = function(name, cmd, img) {		
	
	//tworzymy element <img...>
	var ButtonImg = document.createElement('img');
	ButtonImg.src = img;
	ButtonImg.alt = name;
	ButtonImg.title = name;
	ButtonImg.className = 'JSEditMenuIcon';
	ButtonImg.id = 'jsedit_icon_'+cmd;

	//tablica przechowująca komendy
	cmdButtons[cmdButtons.length] = cmd;
	
	
	//tablica przechowująca obiekt przycisku, oraz jego stan
	buttons[cmd] = new Array();
	buttons[cmd]['obj'] = ButtonImg;
	buttons[cmd]['active'] = true;
	
	//ustalenie eventów odpowiedzialnych za poruszanie się przycisku gdy przejeżdża się nad nim myszką
	ButtonImg.onmouseover = this.raiseButton;
	ButtonImg.onmouseout = this.normalButton;
	ButtonImg.onmousedown = this.lowerButton;
	ButtonImg.onmouseup = this.raiseButton;
	
	//dodanie przycisku do paska narzędzi
	this.ToolBarDiv.appendChild(ButtonImg);
	
	var menu = this;
	
	//dodanie eventu wykonującego komendę
	JSEdit.addEvent(ButtonImg, 'click', function() {
			menu.edit.execCommand(ButtonImg.id.substr(12), false);
		}
	);
	
	return ButtonImg;
}

JSEdit.ToolBar.prototype.raiseButton = function(e) {
	if (isIE)
		var el = window.event.srcElement;
	else
		var el= e.target;
	
	cmd = el.id.substr(12);
	className = el.className;
		
	if((className == 'JSEditMenuIcon' || className == 'JSEditMenuIcon_pressed') && buttons[cmd]['active'])
		el.className = 'JSEditMenuIcon_over';
}

JSEdit.ToolBar.prototype.normalButton = function(e) {
	if (isIE)
		var el = window.event.srcElement;
	else
		var el= e.target;
	
	className = el.className;
	if((className == 'JSEditMenuIcon_pressed' || className == 'JSEditMenuIcon_over') && buttons[cmd]['active'])
		el.className = 'JSEditMenuIcon';
}

JSEdit.ToolBar.prototype.lowerButton = function(e) {
	if (isIE)
		var el = window.event.srcElement;
	else
		var el= e.target;
	
	className = el.className;
	if ((className == 'JSEditMenuIcon_over' || className == 'JSEditMenuIcon') && buttons[cmd]['active'])
		el.className = 'JSEditMenuIcon_pressed';
}



JSEdit.addEvent = function(obj, name, handler) {
	if (isIE) {
		obj.attachEvent("on" + name, handler);
	} else
		obj.addEventListener(name, handler, false);
};

