diff --git a/src/main/resources/includes/tiny_mce/jquery.tinymce.js b/src/main/resources/includes/tiny_mce/jquery.tinymce.js index 85104c3..41e9313 100644 --- a/src/main/resources/includes/tiny_mce/jquery.tinymce.js +++ b/src/main/resources/includes/tiny_mce/jquery.tinymce.js @@ -1 +1,341 @@ -(function(b){var e,d,a=[],c=window;b.fn.tinymce=function(j){var p=this,g,k,h,m,i,l="",n="";if(!p.length){return p}if(!j){return tinyMCE.get(p[0].id)}p.css("visibility","hidden");function o(){var r=[],q=0;if(f){f();f=null}p.each(function(t,u){var s,w=u.id,v=j.oninit;if(!w){u.id=w=tinymce.DOM.uniqueId()}s=new tinymce.Editor(w,j);r.push(s);s.onInit.add(function(){var x,y=v;p.css("visibility","");if(v){if(++q==r.length){if(tinymce.is(y,"string")){x=(y.indexOf(".")===-1)?null:tinymce.resolve(y.replace(/\.\w+$/,""));y=tinymce.resolve(y)}y.apply(x||tinymce,r)}}})});b.each(r,function(t,s){s.render()})}if(!c.tinymce&&!d&&(g=j.script_url)){d=1;h=g.substring(0,g.lastIndexOf("/"));if(/_(src|dev)\.js/g.test(g)){n="_src"}m=g.lastIndexOf("?");if(m!=-1){l=g.substring(m+1)}c.tinyMCEPreInit=c.tinyMCEPreInit||{base:h,suffix:n,query:l};if(g.indexOf("gzip")!=-1){i=j.language||"en";g=g+(/\?/.test(g)?"&":"?")+"js=true&core=true&suffix="+escape(n)+"&themes="+escape(j.theme)+"&plugins="+escape(j.plugins)+"&languages="+i;if(!c.tinyMCE_GZ){tinyMCE_GZ={start:function(){tinymce.suffix=n;function q(r){tinymce.ScriptLoader.markDone(tinyMCE.baseURI.toAbsolute(r))}q("langs/"+i+".js");q("themes/"+j.theme+"/editor_template"+n+".js");q("themes/"+j.theme+"/langs/"+i+".js");b.each(j.plugins.split(","),function(s,r){if(r){q("plugins/"+r+"/editor_plugin"+n+".js");q("plugins/"+r+"/langs/"+i+".js")}})},end:function(){}}}}b.ajax({type:"GET",url:g,dataType:"script",cache:true,success:function(){tinymce.dom.Event.domLoaded=1;d=2;if(j.script_loaded){j.script_loaded()}o();b.each(a,function(q,r){r()})}})}else{if(d===1){a.push(o)}else{o()}}return p};b.extend(b.expr[":"],{tinymce:function(g){return !!(g.id&&tinyMCE.get(g.id))}});function f(){function i(l){if(l==="remove"){this.each(function(n,o){var m=h(o);if(m){m.remove()}})}this.find("span.mceEditor,div.mceEditor").each(function(n,o){var m=tinyMCE.get(o.id.replace(/_parent$/,""));if(m){m.remove()}})}function k(n){var m=this,l;if(n!==e){i.call(m);m.each(function(p,q){var o;if(o=tinyMCE.get(q.id)){o.setContent(n)}})}else{if(m.length>0){if(l=tinyMCE.get(m[0].id)){return l.getContent()}}}}function h(m){var l=null;(m)&&(m.id)&&(c.tinymce)&&(l=tinyMCE.get(m.id));return l}function g(l){return !!((l)&&(l.length)&&(c.tinymce)&&(l.is(":tinymce")))}var j={};b.each(["text","html","val"],function(n,l){var o=j[l]=b.fn[l],m=(l==="text");b.fn[l]=function(s){var p=this;if(!g(p)){return o.apply(p,arguments)}if(s!==e){k.call(p.filter(":tinymce"),s);o.apply(p.not(":tinymce"),arguments);return p}else{var r="";var q=arguments;(m?p:p.eq(0)).each(function(u,v){var t=h(v);r+=t?(m?t.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):t.getContent()):o.apply(b(v),q)});return r}}});b.each(["append","prepend"],function(n,m){var o=j[m]=b.fn[m],l=(m==="prepend");b.fn[m]=function(q){var p=this;if(!g(p)){return o.apply(p,arguments)}if(q!==e){p.filter(":tinymce").each(function(s,t){var r=h(t);r&&r.setContent(l?q+r.getContent():r.getContent()+q)});o.apply(p.not(":tinymce"),arguments);return p}}});b.each(["remove","replaceWith","replaceAll","empty"],function(m,l){var n=j[l]=b.fn[l];b.fn[l]=function(){i.call(this,l);return n.apply(this,arguments)}});j.attr=b.fn.attr;b.fn.attr=function(n,q,o){var m=this;if((!n)||(n!=="value")||(!g(m))){return j.attr.call(m,n,q,o)}if(q!==e){k.call(m.filter(":tinymce"),q);j.attr.call(m.not(":tinymce"),n,q,o);return m}else{var p=m[0],l=h(p);return l?l.getContent():j.attr.call(b(p),n,q,o)}}}})(jQuery); \ No newline at end of file +/** + * jquery.tinymce.js + * + * Copyright, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://www.tinymce.com/license + * Contributing: http://www.tinymce.com/contributing + */ + +(function($) { + var undef, + lazyLoading, + delayedInits = [], + win = window; + + $.fn.tinymce = function(settings) { + var self = this, url, ed, base, pos, lang, query = "", suffix = ""; + + // No match then just ignore the call + if (!self.length) + return self; + + // Get editor instance + if (!settings) + return tinyMCE.get(self[0].id); + + self.css('visibility', 'hidden'); // Hide textarea to avoid flicker + + function init() { + var editors = [], initCount = 0; + + // Apply patches to the jQuery object, only once + if (applyPatch) { + applyPatch(); + applyPatch = null; + } + + // Create an editor instance for each matched node + self.each(function(i, node) { + var ed, id = node.id, oninit = settings.oninit; + + // Generate unique id for target element if needed + if (!id) + node.id = id = tinymce.DOM.uniqueId(); + + // Create editor instance and render it + ed = new tinymce.Editor(id, settings); + editors.push(ed); + + ed.onInit.add(function() { + var scope, func = oninit; + + self.css('visibility', ''); + + // Run this if the oninit setting is defined + // this logic will fire the oninit callback ones each + // matched editor instance is initialized + if (oninit) { + // Fire the oninit event ones each editor instance is initialized + if (++initCount == editors.length) { + if (tinymce.is(func, "string")) { + scope = (func.indexOf(".") === -1) ? null : tinymce.resolve(func.replace(/\.\w+$/, "")); + func = tinymce.resolve(func); + } + + // Call the oninit function with the object + func.apply(scope || tinymce, editors); + } + } + }); + }); + + // Render the editor instances in a separate loop since we + // need to have the full editors array used in the onInit calls + $.each(editors, function(i, ed) { + ed.render(); + }); + } + + // Load TinyMCE on demand, if we need to + if (!win.tinymce && !lazyLoading && (url = settings.script_url)) { + lazyLoading = 1; + base = url.substring(0, url.lastIndexOf("/")); + + // Check if it's a dev/src version they want to load then + // make sure that all plugins, themes etc are loaded in source mode aswell + if (/_(src|dev)\.js/g.test(url)) + suffix = "_src"; + + // Parse out query part, this will be appended to all scripts, css etc to clear browser cache + pos = url.lastIndexOf("?"); + if (pos != -1) + query = url.substring(pos + 1); + + // Setup tinyMCEPreInit object this will later be used by the TinyMCE + // core script to locate other resources like CSS files, dialogs etc + // You can also predefined a tinyMCEPreInit object and then it will use that instead + win.tinyMCEPreInit = win.tinyMCEPreInit || { + base : base, + suffix : suffix, + query : query + }; + + // url contains gzip then we assume it's a compressor + if (url.indexOf('gzip') != -1) { + lang = settings.language || "en"; + url = url + (/\?/.test(url) ? '&' : '?') + "js=true&core=true&suffix=" + escape(suffix) + "&themes=" + escape(settings.theme) + "&plugins=" + escape(settings.plugins) + "&languages=" + lang; + + // Check if compressor script is already loaded otherwise setup a basic one + if (!win.tinyMCE_GZ) { + tinyMCE_GZ = { + start : function() { + tinymce.suffix = suffix; + + function load(url) { + tinymce.ScriptLoader.markDone(tinyMCE.baseURI.toAbsolute(url)); + } + + // Add core languages + load("langs/" + lang + ".js"); + + // Add themes with languages + load("themes/" + settings.theme + "/editor_template" + suffix + ".js"); + load("themes/" + settings.theme + "/langs/" + lang + ".js"); + + // Add plugins with languages + $.each(settings.plugins.split(","), function(i, name) { + if (name) { + load("plugins/" + name + "/editor_plugin" + suffix + ".js"); + load("plugins/" + name + "/langs/" + lang + ".js"); + } + }); + }, + + end : function() { + } + } + } + } + + // Load the script cached and execute the inits once it's done + $.ajax({ + type : "GET", + url : url, + dataType : "script", + cache : true, + success : function() { + tinymce.dom.Event.domLoaded = 1; + lazyLoading = 2; + + // Execute callback after mainscript has been loaded and before the initialization occurs + if (settings.script_loaded) + settings.script_loaded(); + + init(); + + $.each(delayedInits, function(i, init) { + init(); + }); + } + }); + } else { + // Delay the init call until tinymce is loaded + if (lazyLoading === 1) + delayedInits.push(init); + else + init(); + } + + return self; + }; + + // Add :tinymce psuedo selector this will select elements that has been converted into editor instances + // it's now possible to use things like $('*:tinymce') to get all TinyMCE bound elements. + $.extend($.expr[":"], { + tinymce : function(e) { + return !!(e.id && tinyMCE.get(e.id)); + } + }); + + // This function patches internal jQuery functions so that if + // you for example remove an div element containing an editor it's + // automatically destroyed by the TinyMCE API + function applyPatch() { + // Removes any child editor instances by looking for editor wrapper elements + function removeEditors(name) { + // If the function is remove + if (name === "remove") { + this.each(function(i, node) { + var ed = tinyMCEInstance(node); + + if (ed) + ed.remove(); + }); + } + + this.find("span.mceEditor,div.mceEditor").each(function(i, node) { + var ed = tinyMCE.get(node.id.replace(/_parent$/, "")); + + if (ed) + ed.remove(); + }); + } + + // Loads or saves contents from/to textarea if the value + // argument is defined it will set the TinyMCE internal contents + function loadOrSave(value) { + var self = this, ed; + + // Handle set value + if (value !== undef) { + removeEditors.call(self); + + // Saves the contents before get/set value of textarea/div + self.each(function(i, node) { + var ed; + + if (ed = tinyMCE.get(node.id)) + ed.setContent(value); + }); + } else if (self.length > 0) { + // Handle get value + if (ed = tinyMCE.get(self[0].id)) + return ed.getContent(); + } + } + + // Returns tinymce instance for the specified element or null if it wasn't found + function tinyMCEInstance(element) { + var ed = null; + + (element) && (element.id) && (win.tinymce) && (ed = tinyMCE.get(element.id)); + + return ed; + } + + // Checks if the specified set contains tinymce instances + function containsTinyMCE(matchedSet) { + return !!((matchedSet) && (matchedSet.length) && (win.tinymce) && (matchedSet.is(":tinymce"))); + } + + // Patch various jQuery functions + var jQueryFn = {}; + + // Patch some setter/getter functions these will + // now be able to set/get the contents of editor instances for + // example $('#editorid').html('Content'); will update the TinyMCE iframe instance + $.each(["text", "html", "val"], function(i, name) { + var origFn = jQueryFn[name] = $.fn[name], + textProc = (name === "text"); + + $.fn[name] = function(value) { + var self = this; + + if (!containsTinyMCE(self)) + return origFn.apply(self, arguments); + + if (value !== undef) { + loadOrSave.call(self.filter(":tinymce"), value); + origFn.apply(self.not(":tinymce"), arguments); + + return self; // return original set for chaining + } else { + var ret = ""; + var args = arguments; + + (textProc ? self : self.eq(0)).each(function(i, node) { + var ed = tinyMCEInstance(node); + + ret += ed ? (textProc ? ed.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g, "") : ed.getContent()) : origFn.apply($(node), args); + }); + + return ret; + } + }; + }); + + // Makes it possible to use $('#id').append("content"); to append contents to the TinyMCE editor iframe + $.each(["append", "prepend"], function(i, name) { + var origFn = jQueryFn[name] = $.fn[name], + prepend = (name === "prepend"); + + $.fn[name] = function(value) { + var self = this; + + if (!containsTinyMCE(self)) + return origFn.apply(self, arguments); + + if (value !== undef) { + self.filter(":tinymce").each(function(i, node) { + var ed = tinyMCEInstance(node); + + ed && ed.setContent(prepend ? value + ed.getContent() : ed.getContent() + value); + }); + + origFn.apply(self.not(":tinymce"), arguments); + + return self; // return original set for chaining + } + }; + }); + + // Makes sure that the editor instance gets properly destroyed when the parent element is removed + $.each(["remove", "replaceWith", "replaceAll", "empty"], function(i, name) { + var origFn = jQueryFn[name] = $.fn[name]; + + $.fn[name] = function() { + removeEditors.call(this, name); + + return origFn.apply(this, arguments); + }; + }); + + jQueryFn.attr = $.fn.attr; + + // Makes sure that $('#tinymce_id').attr('value') gets the editors current HTML contents + $.fn.attr = function(name, value) { + var self = this; + + if ((!name) || (name !== "value") || (!containsTinyMCE(self))) { + if (value !== undef) { + return jQueryFn.attr.call(self, name, value); + } else { + return jQueryFn.attr.call(self, name); + } + } + + if (value !== undef) { + loadOrSave.call(self.filter(":tinymce"), value); + jQueryFn.attr.call(self.not(":tinymce"), name, value); + + return self; // return original set for chaining + } else { + var node = self[0], ed = tinyMCEInstance(node); + + return ed ? ed.getContent() : jQueryFn.attr.call($(node), name, value); + } + }; + } +})(jQuery); diff --git a/src/main/resources/includes/tinymcerenderer_listener.js b/src/main/resources/includes/tinymcerenderer_listener.js index b6f9056..144f906 100644 --- a/src/main/resources/includes/tinymcerenderer_listener.js +++ b/src/main/resources/includes/tinymcerenderer_listener.js @@ -66,7 +66,7 @@ jQuery(document).ready(function() { // the following hacks are to handle the fact the main issue page has two comment boxes (top, bottom) if (jQuery("#comment-issue").length != 0) { - jQuery("#comment-issue").click( function(){ + jQuery("body").delegate( "#comment-issue","click",function(){ setTimeout(function () { removeTinyMCEEditor() jQuery('textarea.myTinyMCETextArea').tinymce(tinyMCEConfigAdvanced); @@ -77,7 +77,7 @@ jQuery(document).ready(function() { } if (jQuery("#footer-comment-button").length != 0) { - jQuery("#footer-comment-button").click(function(){ + jQuery("body").delegate("#footer-comment-button","click",function(){ setTimeout(function () { removeTinyMCEEditor() jQuery('textarea.myTinyMCETextArea').tinymce(tinyMCEConfigAdvanced); @@ -99,4 +99,4 @@ jQuery(document).ready(function() { return "text" === type && ( attr === type || attr === null ); } } -}); \ No newline at end of file +});