4 * Copyright, Moxiecode Systems AB
5 * Released under LGPL License.
7 * License: http://www.tinymce.com/license
8 * Contributing: http://www.tinymce.com/contributing
11 /*global tinymce:true, jQuery */
19 $.fn.tinymce = function(settings) {
20 var self = this, url, base, lang, suffix = "";
22 // No match then just ignore the call
27 // Get editor instance
29 return tinymce.get(self[0].id);
32 self.css('visibility', 'hidden'); // Hide textarea to avoid flicker
35 var editors = [], initCount = 0;
37 // Apply patches to the jQuery object, only once
43 // Create an editor instance for each matched node
44 self.each(function(i, node) {
45 var ed, id = node.id, oninit = settings.oninit;
47 // Generate unique id for target element if needed
49 node.id = id = tinymce.DOM.uniqueId();
52 // Only init the editor once
53 if (tinymce.get(id)) {
57 // Create editor instance and render it
58 ed = new tinymce.Editor(id, settings, tinymce.EditorManager);
61 ed.on('init', function() {
62 var scope, func = oninit;
64 self.css('visibility', '');
66 // Run this if the oninit setting is defined
67 // this logic will fire the oninit callback ones each
68 // matched editor instance is initialized
70 // Fire the oninit event ones each editor instance is initialized
71 if (++initCount == editors.length) {
72 if (typeof(func) === "string") {
73 scope = (func.indexOf(".") === -1) ? null : tinymce.resolve(func.replace(/\.\w+$/, ""));
74 func = tinymce.resolve(func);
77 // Call the oninit function with the object
78 func.apply(scope || tinymce, editors);
84 // Render the editor instances in a separate loop since we
85 // need to have the full editors array used in the onInit calls
86 $.each(editors, function(i, ed) {
91 // Load TinyMCE on demand, if we need to
92 if (!win.tinymce && !lazyLoading && (url = settings.script_url)) {
94 base = url.substring(0, url.lastIndexOf("/"));
96 // Check if it's a dev/src version they want to load then
97 // make sure that all plugins, themes etc are loaded in source mode as well
98 if (url.indexOf('.min') != -1) {
102 // Setup tinyMCEPreInit object this will later be used by the TinyMCE
103 // core script to locate other resources like CSS files, dialogs etc
104 // You can also predefined a tinyMCEPreInit object and then it will use that instead
105 win.tinymce = win.tinyMCEPreInit || {
110 // url contains gzip then we assume it's a compressor
111 if (url.indexOf('gzip') != -1) {
112 lang = settings.language || "en";
113 url = url + (/\?/.test(url) ? '&' : '?') + "js=true&core=true&suffix=" + escape(suffix) +
114 "&themes=" + escape(settings.theme || '') + "&plugins=" + escape(settings.plugins || '') + "&languages=" + (lang || '');
116 // Check if compressor script is already loaded otherwise setup a basic one
117 if (!win.tinyMCE_GZ) {
121 tinymce.ScriptLoader.markDone(tinymce.baseURI.toAbsolute(url));
124 // Add core languages
125 load("langs/" + lang + ".js");
127 // Add themes with languages
128 load("themes/" + settings.theme + "/theme" + suffix + ".js");
129 load("themes/" + settings.theme + "/langs/" + lang + ".js");
131 // Add plugins with languages
132 $.each(settings.plugins.split(","), function(i, name) {
134 load("plugins/" + name + "/plugin" + suffix + ".js");
135 load("plugins/" + name + "/langs/" + lang + ".js");
146 var script = document.createElement('script');
147 script.type = 'text/javascript';
148 script.onload = script.onreadystatechange = function(e) {
151 if (e.type == 'load' || /complete|loaded/.test(script.readyState)) {
152 tinymce.dom.Event.domLoaded = 1;
155 // Execute callback after mainscript has been loaded and before the initialization occurs
156 if (settings.script_loaded) {
157 settings.script_loaded();
162 $.each(delayedInits, function(i, init) {
168 document.body.appendChild(script);
170 // Delay the init call until tinymce is loaded
171 if (lazyLoading === 1) {
172 delayedInits.push(init);
181 // Add :tinymce psuedo selector this will select elements that has been converted into editor instances
182 // it's now possible to use things like $('*:tinymce') to get all TinyMCE bound elements.
183 $.extend($.expr[":"], {
184 tinymce: function(e) {
185 return !!(e.id && "tinymce" in window && tinymce.get(e.id));
189 // This function patches internal jQuery functions so that if
190 // you for example remove an div element containing an editor it's
191 // automatically destroyed by the TinyMCE API
192 function applyPatch() {
193 // Removes any child editor instances by looking for editor wrapper elements
194 function removeEditors(name) {
195 // If the function is remove
196 if (name === "remove") {
197 this.each(function(i, node) {
198 var ed = tinyMCEInstance(node);
206 this.find("span.mceEditor,div.mceEditor").each(function(i, node) {
207 var ed = tinymce.get(node.id.replace(/_parent$/, ""));
215 // Loads or saves contents from/to textarea if the value
216 // argument is defined it will set the TinyMCE internal contents
217 function loadOrSave(value) {
221 /*jshint eqnull:true */
223 removeEditors.call(self);
225 // Saves the contents before get/set value of textarea/div
226 self.each(function(i, node) {
229 if ((ed = tinymce.get(node.id))) {
230 ed.setContent(value);
233 } else if (self.length > 0) {
235 if ((ed = tinymce.get(self[0].id))) {
236 return ed.getContent();
241 // Returns tinymce instance for the specified element or null if it wasn't found
242 function tinyMCEInstance(element) {
245 if (element && element.id && win.tinymce) {
246 ed = tinymce.get(element.id);
252 // Checks if the specified set contains tinymce instances
253 function containsTinyMCE(matchedSet) {
254 return !!((matchedSet) && (matchedSet.length) && (win.tinymce) && (matchedSet.is(":tinymce")));
257 // Patch various jQuery functions
260 // Patch some setter/getter functions these will
261 // now be able to set/get the contents of editor instances for
262 // example $('#editorid').html('Content'); will update the TinyMCE iframe instance
263 $.each(["text", "html", "val"], function(i, name) {
264 var origFn = jQueryFn[name] = $.fn[name],
265 textProc = (name === "text");
267 $.fn[name] = function(value) {
270 if (!containsTinyMCE(self)) {
271 return origFn.apply(self, arguments);
274 if (value !== undef) {
275 loadOrSave.call(self.filter(":tinymce"), value);
276 origFn.apply(self.not(":tinymce"), arguments);
278 return self; // return original set for chaining
281 var args = arguments;
283 (textProc ? self : self.eq(0)).each(function(i, node) {
284 var ed = tinyMCEInstance(node);
287 ret += textProc ? ed.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g, "") : ed.getContent({save: true});
289 ret += origFn.apply($(node), args);
298 // Makes it possible to use $('#id').append("content"); to append contents to the TinyMCE editor iframe
299 $.each(["append", "prepend"], function(i, name) {
300 var origFn = jQueryFn[name] = $.fn[name],
301 prepend = (name === "prepend");
303 $.fn[name] = function(value) {
306 if (!containsTinyMCE(self)) {
307 return origFn.apply(self, arguments);
310 if (value !== undef) {
311 self.filter(":tinymce").each(function(i, node) {
312 var ed = tinyMCEInstance(node);
315 ed.setContent(prepend ? value + ed.getContent() : ed.getContent() + value);
319 origFn.apply(self.not(":tinymce"), arguments);
321 return self; // return original set for chaining
326 // Makes sure that the editor instance gets properly destroyed when the parent element is removed
327 $.each(["remove", "replaceWith", "replaceAll", "empty"], function(i, name) {
328 var origFn = jQueryFn[name] = $.fn[name];
330 $.fn[name] = function() {
331 removeEditors.call(this, name);
333 return origFn.apply(this, arguments);
337 jQueryFn.attr = $.fn.attr;
339 // Makes sure that $('#tinymce_id').attr('value') gets the editors current HTML contents
340 $.fn.attr = function(name, value) {
341 var self = this, args = arguments;
343 if ((!name) || (name !== "value") || (!containsTinyMCE(self))) {
344 if (value !== undef) {
345 return jQueryFn.attr.apply(self, args);
347 return jQueryFn.attr.apply(self, args);
351 if (value !== undef) {
352 loadOrSave.call(self.filter(":tinymce"), value);
353 jQueryFn.attr.apply(self.not(":tinymce"), args);
355 return self; // return original set for chaining
357 var node = self[0], ed = tinyMCEInstance(node);
359 return ed ? ed.getContent({save: true}) : jQueryFn.attr.apply($(node), args);