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"> </span>'; 69 if(isSafari) { 70 hrefHtml = '<span class="np_break"> </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"> </span>'; 98 if(isSafari) { 99 hrefHtml = '<span class="np_break"> </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