1/*
2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
3 * Copyright (C) 2003-2007 Frederico Caldeira Knabben
4 * Copyright (C) 2008-2013 Myron Turner
5 * Copyright (C) 2013 Kamil Demecki [kodstark@gmail.com]
6 *
7 * == BEGIN LICENSE ==
8 *
9 * Licensed under the terms of any of the following licenses at your
10 * choice:
11 *
12 *  - GNU General Public License Version 2 or later (the "GPL")
13 *    http://www.gnu.org/licenses/gpl.html
14 *
15 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
16 *    http://www.gnu.org/licenses/lgpl.html
17 *
18 *  - Mozilla Public License Version 1.1 or later (the "MPL")
19 *    http://www.mozilla.org/MPL/MPL-1.1.html
20 *
21 * == END LICENSE ==
22 *
23 */
24
25// Register the related commands.
26var gdialog_dim = FCKBrowserInfo.IsIE ? 500: 600;
27FCKCommands.RegisterCommand( 'geshi',
28   new FCKDialogCommand( FCKLang['GeshiDlgTitle'], FCKLang['GeshiDlgTitle'],
29   FCKConfig.PluginsPath + 'geshi/geshi.html',  gdialog_dim, gdialog_dim ) ) ;
30
31
32var oGeshiTool		= new FCKToolbarButton( 'geshi',  FCKLang['GeshiToolTip'] ) ;
33oGeshiTool.IconPath	= FCKPlugins.Items['geshi'].Path  + 'images/geshi.gif' ;
34
35FCKToolbarItems.RegisterItem( 'geshi', oGeshiTool ) ;
36
37// The object used for all Geshi operations.
38var FCKGeshi = new Object() ;
39FCKGeshi.isIE = FCKBrowserInfo.IsIE;
40FCKGeshi.CheckForText = function() {
41     var isSafari = false;
42    if(!FCKBrowserInfo.IsIE && !FCKBrowserInfo.IsGecko) isSafari = true;
43    var	mySelection = ( FCKBrowserInfo.IsIE) ? FCKSelection.GetSelectedHTML(isSafari) : removeBR(FCKSelection.GetSelectedHTML(isSafari));
44
45    return FCKGeshi.StripHtmlDom(mySelection);
46}
47
48FCKGeshi.InsertText = function(code_type, lang, snip_fname, mySelection) {
49
50
51    var pre_class = code_type + ' ' + lang;
52	var hrefStartHtml	=  '<pre class="' + pre_class + '">';
53	var hrefEndHtml		=  '</pre>';
54
55    var  isSafari = false;
56    if(!FCKBrowserInfo.IsIE && !FCKBrowserInfo.IsGecko) isSafari = true;
57    mySelection = mySelection.replace(/^\s+/,"");
58    mySelection = mySelection.replace(/\s+$/,"");
59    if(!mySelection) mySelection = "<br /><br />";
60
61    hrefHtml = hrefStartHtml+mySelection+hrefEndHtml;
62    if(snip_fname) {
63        hrefHtml=downloadable_snippet(hrefHtml, snip_fname) ;
64    }
65
66
67
68    hrefHtml += '<span class="np_break">&nbsp;</span>';
69    if(isSafari) {
70          hrefHtml = '<span class="np_break">&nbsp;</span>' + hrefHtml;
71    }
72	FCK.InsertHtml(hrefHtml);
73}
74
75FCKGeshi.Insert = function(code_type, lang, snip_fname) {
76
77
78    var pre_class = code_type + ' ' + lang;
79	var hrefStartHtml	=  '<pre class="' + pre_class + '">';
80	var hrefEndHtml		=  '</pre>';
81    var isSafari = false;
82    var reset = false;
83    if(!FCKBrowserInfo.IsIE && !FCKBrowserInfo.IsGecko) isSafari = true;
84	mySelection = ( FCKBrowserInfo.IsIE) ? FCKSelection.GetSelectedHTML(isSafari) : removeBR(FCKSelection.GetSelectedHTML(isSafari));
85
86    mySelection = mySelection.replace(/^\s+/,"");
87    mySelection = mySelection.replace(/\s+$/,"");
88    if(!mySelection) mySelection = "<br /><br />";
89
90    hrefHtml = hrefStartHtml+mySelection+hrefEndHtml;
91    if(snip_fname) {
92        hrefHtml=downloadable_snippet(hrefHtml, snip_fname) ;
93    }
94
95
96
97    hrefHtml += '<span class="np_break">&nbsp;</span>';
98    if(isSafari) {
99          hrefHtml = '<span class="np_break">&nbsp;</span>' + hrefHtml;
100    }
101	FCK.InsertHtml(hrefHtml);
102}
103
104FCKGeshi.InsertEdited = function(val) {
105
106//	mySelection = ( FCKBrowserInfo.IsIE) ? FCKSelection.GetSelectedHTML() : removeBR(FCKSelection.GetSelectedHTML());
107
108	hrefHtml = val;
109
110
111	FCK.InsertHtml(hrefHtml);
112}
113
114FCKSelection.GetSelectedHTML = function(isSafari) {
115
116							// see http://www.quirksmode.org/js/selected.html for other browsers
117	if( FCKBrowserInfo.IsIE) {												// IE
118		var oRange = FCK.EditorDocument.selection.createRange() ;
119		//if an object like a table is deleted, the call to GetType before getting again a range returns Control
120		switch ( this.GetType() ) {
121			case 'Control' :
122			return oRange.item(0).outerHTML;
123
124			case 'None' :
125			return '' ;
126
127			default :
128			return oRange.htmlText ;
129		}
130	}
131	else if ( FCKBrowserInfo.IsGecko || isSafari ) {									// Mozilla, Safari
132
133									// Mozilla, Safari
134		var oSelection = FCK.EditorWindow.getSelection();
135		//Gecko doesn't provide a function to get the innerHTML of a selection,
136		//so we must clone the selection to a temporary element and check that innerHTML
137		var e = FCK.EditorDocument.createElement( 'DIV' );
138		for ( var i = 0 ; i < oSelection.rangeCount ; i++ ) {
139			e.appendChild( oSelection.getRangeAt(i).cloneContents() );
140		}
141		return e.innerHTML;
142	}
143}
144
145function removeBR(input) {							/* Used with Gecko */
146	var output = "";
147	for (var i = 0; i < input.length; i++) {
148		if ((input.charCodeAt(i) == 13) && (input.charCodeAt(i + 1) == 10)) {
149			i++;
150			output += " ";
151		}
152		else {
153			output += input.charAt(i);
154   		}
155	}
156	return output;
157}
158
159function downloadable_snippet(mySelection, fname) {
160
161
162matches = fname.match(/\.(\w+)$/);
163var ext = matches ? matches[1] : 'php';
164
165var media_file = 'mediafile mf_' + ext;
166
167var selection = '<dl class="file">' +
168    '<dt><a href="doku.php?do=export_code&id=start&codeblock=0"'
169          + 'title="Download Snippet" class="' + media_file + '">' + fname +'</a></dt>'
170    + '<dd>'
171    + mySelection
172   + ' </dd> </dl>';
173
174 return selection;
175}
176
177// originally from Club AJAX General Purpose Code
178// author of original: Mike Wilcox http://clubajax.org
179// Returns a line-break, properly spaced, normailized plain text
180// representation of multiple child nodes which can't be done via
181// textContent or innerText because those two methods are vastly
182// different, and even innerText works differently across browsers.
183FCKGeshi.StripHtmlDom = function(htmlText){
184    var node = document.createElement("div");
185    node.innerHTML = htmlText;
186
187	// used for testing:
188	// return node.innerText || node.textContent;
189
190	var normalize = function(a){
191		// clean up double line breaks and spaces
192		if(!a) return "";
193		return a.replace(/ +/g, " ")
194				.replace(/[\t]+/gm, "")
195				.replace(/[ ]+$/gm, "")
196				.replace(/^[ ]+/gm, "")
197				.replace(/\n+/g, "\n")
198				.replace(/\n+$/, "")
199				.replace(/^\n+/, "")
200				.replace(/\nNEWLINE\n/g, "\n\n")
201				.replace(/NEWLINE\n/g, "\n\n"); // IE
202	}
203	var removeWhiteSpace = function(node){
204		// getting rid of empty text nodes
205		var isWhite = function(node) {
206			return !(/[^\t\n\r ]/.test(node.nodeValue));
207		}
208		var ws = [];
209		var findWhite = function(node){
210			for(var i=0; i<node.childNodes.length;i++){
211				var n = node.childNodes[i];
212				if (n.nodeType==3 && isWhite(n)){
213					ws.push(n)
214				}else if(n.hasChildNodes()){
215					findWhite(n);
216				}
217			}
218		}
219		findWhite(node);
220		for(var i=0;i<ws.length;i++){
221			ws[i].parentNode.removeChild(ws[i])
222		}
223
224	}
225	var sty = function(n, prop){
226		// Get the style of the node.
227		// Assumptions are made here based on tagName.
228		if(n.style[prop]) return n.style[prop];
229		var s = n.currentStyle || n.ownerDocument.defaultView.getComputedStyle(n, null);
230		if(n.tagName == "SCRIPT") return "none";
231		if(!s[prop]) return "LI,P,TR".indexOf(n.tagName) > -1 ? "block" : n.style[prop];
232		if(s[prop] =="block" && n.tagName=="TD") return "feaux-inline";
233		return s[prop];
234	}
235
236	var blockTypeNodes = "table-row,block,list-item";
237	var isBlock = function(n){
238		// diaply:block or something else
239		var s = sty(n, "display") || "feaux-inline";
240		if(blockTypeNodes.indexOf(s) > -1) return true;
241		return false;
242	}
243	var recurse = function(n){
244		// Loop through all the child nodes
245		// and collect the text, noting whether
246		// spaces or line breaks are needed.
247		if(/pre/.test(sty(n, "whiteSpace"))) {
248			t += n.innerHTML
249				.replace(/\t/g, " ")
250				.replace(/\n/g, " "); // to match IE
251			return "";
252		}
253		var s = sty(n, "display");
254		if(s == "none") return "";
255		var gap = isBlock(n) ? "\n" : " ";
256		t += gap;
257		for(var i=0; i<n.childNodes.length;i++){
258			var c = n.childNodes[i];
259			if(c.nodeType == 3) t += c.nodeValue;
260			if(c.childNodes.length) recurse(c);
261		}
262		t += gap;
263		return t;
264	}
265	// Use a copy because stuff gets changed
266	node = node.cloneNode(true);
267	// Line breaks aren't picked up by textContent
268	node.innerHTML = node.innerHTML.replace(/<br>/g, "\n");
269
270	// Double line breaks after P tags are desired, but would get
271	// stripped by the final RegExp. Using placeholder text.
272	var paras = node.getElementsByTagName("p");
273	for(var i=0; i<paras.length;i++){
274		paras[i].innerHTML += "NEWLINE";
275	}
276
277	var t = "";
278	removeWhiteSpace(node);
279	return normalize(recurse(node));
280}
281