/* * Lightweight RTE - jQuery Plugin, version 1.2 * Copyright (c) 2009 Andrey Gayvoronsky - http://www.gayvoronsky.com */ jQuery.fn.rte = function(options, editors) { if(!editors || editors.constructor != Array) editors = new Array(); $(this).each(function(i) { var id = (this.id) ? this.id : editors.length; editors[id] = new lwRTE (this, options || {}); }); return editors; } var lwRTE_resizer = function(textarea) { this.drag = false; this.rte_zone = $(textarea).parents('.rte-zone'); } lwRTE_resizer.mousedown = function(resizer, e) { resizer.drag = true; resizer.event = (typeof(e) == "undefined") ? window.event : e; resizer.rte_obj = $(".rte-resizer", resizer.rte_zone).prev().eq(0); $('body', document).css('cursor', 'se-resize'); return false; } lwRTE_resizer.mouseup = function(resizer, e) { resizer.drag = false; $('body', document).css('cursor', 'auto'); return false; } lwRTE_resizer.mousemove = function(resizer, e) { if(resizer.drag) { e = (typeof(e) == "undefined") ? window.event : e; var w = Math.max(1, resizer.rte_zone.width() + e.screenX - resizer.event.screenX); var h = Math.max(1, resizer.rte_obj.height() + e.screenY - resizer.event.screenY); resizer.rte_zone.width(w); resizer.rte_obj.height(h); resizer.event = e; } return false; } var lwRTE = function (textarea, options) { this.css = []; this.css_class = options.frame_class || ''; this.base_url = options.base_url || ''; this.width = options.width || $(textarea).width() || '100%'; this.height = options.height || $(textarea).height() || 350; this.iframe = null; this.iframe_doc = null; this.textarea = null; this.event = null; this.range = null; this.toolbars = {rte: '', html : ''}; this.controls = {rte: {disable: {hint: 'Source editor'}}, html: {enable: {hint: 'Visual editor'}}}; $.extend(this.controls.rte, options.controls_rte || {}); $.extend(this.controls.html, options.controls_html || {}); $.extend(this.css, options.css || {}); if(document.designMode || document.contentEditable) { $(textarea).wrap($('
').addClass('rte-zone').width(this.width)); $('
').insertAfter(textarea); var resizer = new lwRTE_resizer(textarea); $(".rte-resizer a", $(textarea).parents('.rte-zone')).mousedown(function(e) { $(document).mousemove(function(e) { return lwRTE_resizer.mousemove(resizer, e); }); $(document).mouseup(function(e) { return lwRTE_resizer.mouseup(resizer, e) }); return lwRTE_resizer.mousedown(resizer, e); }); this.textarea = textarea; this.enable_design_mode(); } } lwRTE.prototype.editor_cmd = function(command, args) { this.iframe.contentWindow.focus(); try { this.iframe_doc.execCommand(command, false, args); } catch(e) { } this.iframe.contentWindow.focus(); } lwRTE.prototype.get_toolbar = function() { var editor = (this.iframe) ? $(this.iframe) : $(this.textarea); return (editor.prev().hasClass('rte-toolbar')) ? editor.prev() : null; } lwRTE.prototype.activate_toolbar = function(editor, tb) { var old_tb = this.get_toolbar(); if(old_tb) old_tb.remove(); $(editor).before($(tb).clone(true)); } lwRTE.prototype.enable_design_mode = function() { var self = this; // need to be created this way self.iframe = document.createElement("iframe"); self.iframe.frameBorder = 0; self.iframe.frameMargin = 0; self.iframe.framePadding = 0; self.iframe.width = '100%'; self.iframe.height = self.height || '100%'; self.iframe.src = "javascript:void(0);"; if($(self.textarea).attr('class')) self.iframe.className = $(self.textarea).attr('class'); if($(self.textarea).attr('id')) self.iframe.id = $(self.textarea).attr('id'); if($(self.textarea).attr('name')) self.iframe.title = $(self.textarea).attr('name'); var content = $(self.textarea).val(); $(self.textarea).hide().after(self.iframe).remove(); self.textarea = null; var css = ''; for(var i in self.css) css += ""; var base = (self.base_url) ? "" : ''; var style = (self.css_class) ? "class='" + self.css_class + "'" : ''; // Mozilla need this to display caret /*if($.trim(content) == '') content = '
';*/ var doc = "" + base + css + "" + content + ""; self.iframe_doc = self.iframe.contentWindow.document; try { self.iframe_doc.designMode = 'on'; } catch ( e ) { // Will fail on Gecko if the editor is placed in an hidden container element // The design mode will be set ones the editor is focused $(self.iframe_doc).focus(function() { self.iframe_doc.designMode(); } ); } self.iframe_doc.open(); self.iframe_doc.write(doc); self.iframe_doc.close(); if(!self.toolbars.rte) self.toolbars.rte = self.create_toolbar(self.controls.rte); self.activate_toolbar(self.iframe, self.toolbars.rte); $(self.iframe).parents('form').submit( function() { self.disable_design_mode(true); } ); $(self.iframe_doc).mouseup(function(event) { if(self.iframe_doc.selection) self.range = self.iframe_doc.selection.createRange(); //store to restore later(IE fix) self.set_selected_controls( (event.target) ? event.target : event.srcElement, self.controls.rte); }); $(self.iframe_doc).blur(function(event){ if(self.iframe_doc.selection) self.range = self.iframe_doc.selection.createRange(); // same fix for IE as above }); $(self.iframe_doc).keyup(function(event) { self.set_selected_controls( self.get_selected_element(), self.controls.rte); }); // Mozilla CSS styling off if(!$.browser.msie) self.editor_cmd('styleWithCSS', false); } lwRTE.prototype.disable_design_mode = function(submit) { var self = this; self.textarea = (submit) ? $('').get(0) : $('').width('100%').height(self.height).get(0); if(self.iframe.className) self.textarea.className = self.iframe.className; if(self.iframe.id) self.textarea.id = self.iframe.id; if(self.iframe.title) self.textarea.name = self.iframe.title; $(self.textarea).val($('body', self.iframe_doc).html()); $(self.iframe).before(self.textarea); if(!self.toolbars.html) self.toolbars.html = self.create_toolbar(self.controls.html); if(submit != true) { $(self.iframe_doc).remove(); //fix 'permission denied' bug in IE7 (jquery cache) $(self.iframe).remove(); self.iframe = self.iframe_doc = null; self.activate_toolbar(self.textarea, self.toolbars.html); } } lwRTE.prototype.toolbar_click = function(obj, control) { var fn = control.exec; var args = control.args || []; var is_select = (obj.tagName.toUpperCase() == 'SELECT'); $('.rte-panel', this.get_toolbar()).remove(); if(fn) { if(is_select) args.push(obj); try { fn.apply(this, args); } catch(e) { } } else if(this.iframe && control.command) { if(is_select) { args = obj.options[obj.selectedIndex].value; if(args.length <= 0) return; } this.editor_cmd(control.command, args); } } lwRTE.prototype.create_toolbar = function(controls) { var self = this; var tb = $("
").addClass('rte-toolbar').width('100%').append($("")).append($("
").addClass('clear')); var obj, li; for (var key in controls){ if(controls[key].separator) { li = $("
  • ").addClass('separator'); } else { if(controls[key].init) { try { controls[key].init.apply(controls[key], [this]); } catch(e) { } } if(controls[key].select) { obj = $(controls[key].select) .change( function(e) { self.event = e; self.toolbar_click(this, controls[this.className]); return false; }); } else { obj = $("") .attr('title', (controls[key].hint) ? controls[key].hint : key) .attr('rel', key) .click( function(e) { self.event = e; self.toolbar_click(this, controls[this.rel]); return false; }) } li = $("
  • ").append(obj.addClass(key)); } $("ul",tb).append(li); } $('.enable', tb).click(function() { self.enable_design_mode(); return false; }); $('.disable', tb).click(function() { self.disable_design_mode(); return false; }); return tb.get(0); } lwRTE.prototype.create_panel = function(title, width) { var self = this; var tb = self.get_toolbar(); if(!tb) return false; $('.rte-panel', tb).remove(); var drag, event; var left = self.event.pageX; var top = self.event.pageY; var panel = $('
    ').hide().addClass('rte-panel').css({left: left, top: top}); $('
    ') .addClass('rte-panel-title') .html(title) .append($("X") .click( function() { panel.remove(); return false; })) .mousedown( function() { drag = true; return false; }) .mouseup( function() { drag = false; return false; }) .mousemove( function(e) { if(drag && event) { left -= event.pageX - e.pageX; top -= event.pageY - e.pageY; panel.css( {left: left, top: top} ); } event = e; return false; } ) .appendTo(panel); if(width) panel.width(width); tb.append(panel); return panel; } lwRTE.prototype.get_content = function() { return (this.iframe) ? $('body', this.iframe_doc).html() : $(this.textarea).val(); } lwRTE.prototype.autoUpdate = function(el) { var scope = this; window.setInterval(function() { el.val(scope.get_content()); }, 1000); } lwRTE.prototype.set_content = function(content) { (this.iframe) ? $('body', this.iframe_doc).html(content) : $(this.textarea).val(content); } lwRTE.prototype.set_selected_controls = function(node, controls) { var toolbar = this.get_toolbar(); if(!toolbar) return false; var key, i_node, obj, control, tag, i, value; try { for (key in controls) { control = controls[key]; obj = $('.' + key, toolbar); obj.removeClass('active'); if(!control.tags) continue; i_node = node; do { if(i_node.nodeType != 1) continue; tag = i_node.nodeName.toLowerCase(); if($.inArray(tag, control.tags) < 0 ) continue; if(control.select) { obj = obj.get(0); if(obj.tagName.toUpperCase() == 'SELECT') { obj.selectedIndex = 0; for(i = 0; i < obj.options.length; i++) { value = obj.options[i].value; if(value && ((control.tag_cmp && control.tag_cmp(i_node, value)) || tag == value)) { obj.selectedIndex = i; break; } } } } else obj.addClass('active'); } while(i_node = i_node.parentNode) } } catch(e) { } return true; } lwRTE.prototype.get_selected_element = function () { var node, selection, range; var iframe_win = this.iframe.contentWindow; if (iframe_win.getSelection) { try { selection = iframe_win.getSelection(); range = selection.getRangeAt(0); node = range.commonAncestorContainer; } catch(e){ return false; } } else { try { selection = iframe_win.document.selection; range = selection.createRange(); node = range.parentElement(); } catch (e) { return false; } } return node; } lwRTE.prototype.get_selection_range = function() { var rng = null; var iframe_window = this.iframe.contentWindow; this.iframe.focus(); if(iframe_window.getSelection) { rng = iframe_window.getSelection().getRangeAt(0); if($.browser.opera) { //v9.63 tested only var s = rng.startContainer; if(s.nodeType === Node.TEXT_NODE) rng.setStartBefore(s.parentNode); } } else { this.range.select(); //Restore selection, if IE lost focus. rng = this.iframe_doc.selection.createRange(); } return rng; } lwRTE.prototype.get_selected_text = function() { var iframe_win = this.iframe.contentWindow; if(iframe_win.getSelection) return iframe_win.getSelection().toString(); this.range.select(); //Restore selection, if IE lost focus. return iframe_win.document.selection.createRange().text; }; lwRTE.prototype.get_selected_html = function() { var html = null; var iframe_window = this.iframe.contentWindow; var rng = this.get_selection_range(); if(rng) { if(iframe_window.getSelection) { var e = document.createElement('div'); e.appendChild(rng.cloneContents()); html = e.innerHTML; } else { html = rng.htmlText; } } return html; }; lwRTE.prototype.selection_replace_with = function(html) { var rng = this.get_selection_range(); var iframe_window = this.iframe.contentWindow; if(!rng) return; this.editor_cmd('removeFormat'); // we must remove formating or we will get empty format tags! if(iframe_window.getSelection) { rng.deleteContents(); rng.insertNode(rng.createContextualFragment(html)); this.editor_cmd('delete'); } else { this.editor_cmd('delete'); rng.pasteHTML(html); } }