| /* |
| * elRTE - WSWING editor for web |
| * |
| * Usage: |
| * var opts = { |
| * .... // see elRTE.options.js |
| * } |
| * var editor = new elRTE($('#my-id').get(0), opts) |
| * or |
| * $('#my-id').elrte(opts) |
| * |
| * $('#my-id) may be textarea or any DOM Element with text |
| * |
| * @author: Dmitry Levashov (dio) dio@std42.ru |
| * Copyright: Studio 42, http://www.std42.ru |
| */ |
| (function($) { |
| |
| elRTE = function(target, opts) { |
| if (!target || !target.nodeName) { |
| return alert('elRTE: argument "target" is not DOM Element'); |
| } |
| var self = this, html; |
| this.version = '1.3'; |
| this.build = '2011-06-23'; |
| this.options = $.extend(true, {}, this.options, opts); |
| this.browser = $.browser; |
| this.target = $(target); |
| |
| this.lang = (''+this.options.lang); |
| this._i18n = new eli18n({textdomain : 'rte', messages : { rte : this.i18Messages[this.lang] || {}} }); |
| this.rtl = !!(/^(ar|fa|he)$/.test(this.lang) && this.i18Messages[this.lang]); |
| |
| if (this.rtl) { |
| this.options.cssClass += ' el-rte-rtl'; |
| } |
| this.toolbar = $('<div class="toolbar"/>'); |
| this.iframe = document.createElement('iframe'); |
| this.iframe.setAttribute('frameborder', 0); // fixes IE border |
| |
| // this.source = $('<textarea />').hide(); |
| this.workzone = $('<div class="workzone"/>').append(this.iframe).append(this.source); |
| this.statusbar = $('<div class="statusbar"/>'); |
| this.tabsbar = $('<div class="tabsbar"/>'); |
| this.editor = $('<div class="'+this.options.cssClass+'" />').append(this.toolbar).append(this.workzone).append(this.statusbar).append(this.tabsbar); |
| |
| this.doc = null; |
| this.$doc = null; |
| this.window = null; |
| |
| this.utils = new this.utils(this); |
| this.dom = new this.dom(this); |
| this.filter = new this.filter(this) |
| |
| /** |
| * Sync iframes/textareas height with workzone height |
| * |
| * @return void |
| */ |
| this.updateHeight = function() { |
| self.workzone.add(self.iframe).add(self.source).height(self.workzone.height()); |
| } |
| |
| /** |
| * Turn editor resizable on/off if allowed |
| * |
| * @param Boolean |
| * @return void |
| **/ |
| this.resizable = function(r) { |
| var self = this; |
| if (this.options.resizable && $.fn.resizable) { |
| if (r) { |
| this.editor.resizable({handles : 'se', alsoResize : this.workzone, minWidth :300, minHeight : 200 }).bind('resize', self.updateHeight); |
| } else { |
| this.editor.resizable('destroy').unbind('resize', self.updateHeight); |
| } |
| } |
| } |
| |
| /* attach editor to document */ |
| this.editor.insertAfter(target); |
| /* init editor textarea */ |
| var content = ''; |
| if (target.nodeName == 'TEXTAREA') { |
| this.source = this.target; |
| this.source.insertAfter(this.iframe).hide(); |
| content = this.target.val(); |
| } else { |
| this.source = $('<textarea />').insertAfter(this.iframe).hide(); |
| content = this.target.hide().html(); |
| } |
| this.source.attr('name', this.target.attr('name')||this.target.attr('id')); |
| content = $.trim(content); |
| if (!content) { |
| content = ' '; |
| } |
| |
| /* add tabs */ |
| if (this.options.allowSource) { |
| this.tabsbar.append('<div class="tab editor rounded-bottom-7 active">'+self.i18n('Editor')+'</div><div class="tab source rounded-bottom-7">'+self.i18n('Source')+'</div><div class="clearfix" style="clear:both"/>') |
| .children('.tab').click(function(e) { |
| if (!$(this).hasClass('active')) { |
| self.tabsbar.children('.tab').toggleClass('active'); |
| self.workzone.children().toggle(); |
| |
| if ($(this).hasClass('editor')) { |
| self.updateEditor(); |
| self.window.focus(); |
| self.ui.update(true); |
| } else { |
| self.updateSource(); |
| self.source.focus(); |
| if ($.browser.msie) { |
| // @todo |
| } else { |
| self.source[0].setSelectionRange(0, 0); |
| } |
| self.ui.disable(); |
| self.statusbar.empty(); |
| |
| } |
| } |
| |
| }); |
| } |
| |
| this.window = this.iframe.contentWindow; |
| this.doc = this.iframe.contentWindow.document; |
| this.$doc = $(this.doc); |
| |
| /* put content into iframe */ |
| html = '<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />'; |
| $.each(self.options.cssfiles, function() { |
| html += '<link rel="stylesheet" type="text/css" href="'+this+'" />'; |
| }); |
| this.doc.open(); |
| var s = this.filter.wysiwyg(content), |
| cl = this.rtl ? ' class="el-rte-rtl"' : ''; |
| this.doc.write(self.options.doctype+html+'</head><body'+cl+'>'+(s)+'</body></html>'); |
| this.doc.close(); |
| |
| /* make iframe editable */ |
| if ($.browser.msie) { |
| this.doc.body.contentEditable = true; |
| } else { |
| try { this.doc.designMode = "on"; } |
| catch(e) { } |
| this.doc.execCommand('styleWithCSS', false, this.options.styleWithCSS); |
| } |
| |
| if (this.options.height>0) { |
| this.workzone.height(this.options.height); |
| } |
| if (this.options.width>0) { |
| this.editor.width(this.options.width); |
| } |
| |
| this.updateHeight(); |
| this.resizable(true); |
| this.window.focus(); |
| |
| this.history = new this.history(this); |
| |
| /* init selection object */ |
| this.selection = new this.selection(this); |
| /* init buttons */ |
| this.ui = new this.ui(this); |
| |
| |
| /* bind updateSource to parent form submit */ |
| this.target.parents('form').bind('submit.elfinder', function(e) { |
| self.source.parents('form').find('[name="el-select"]').remove() |
| self.beforeSave(); |
| }); |
| |
| // on tab press - insert \t and prevent move focus |
| this.source.bind('keydown', function(e) { |
| if (e.keyCode == 9) { |
| e.preventDefault(); |
| |
| if ($.browser.msie) { |
| var r = document.selection.createRange(); |
| r.text = "\t"+r.text; |
| this.focus(); |
| } else { |
| var before = this.value.substr(0, this.selectionStart), |
| after = this.value.substr(this.selectionEnd); |
| this.value = before+"\t"+after; |
| this.setSelectionRange(before.length+1, before.length+1); |
| } |
| } |
| }); |
| |
| $(this.doc.body).bind('dragend', function(e) { |
| setTimeout(function() { |
| try { |
| self.window.focus(); |
| var bm = self.selection.getBookmark(); |
| self.selection.moveToBookmark(bm); |
| self.ui.update(); |
| } catch(e) { } |
| |
| |
| }, 200); |
| |
| }); |
| |
| this.typing = false; |
| this.lastKey = null; |
| /* update buttons on click and keyup */ |
| this.$doc.bind('mouseup', function() { |
| self.typing = false; |
| self.lastKey = null; |
| self.ui.update(); |
| }) |
| .bind('keyup', function(e) { |
| if ((e.keyCode >= 8 && e.keyCode <= 13) || (e.keyCode>=32 && e.keyCode<= 40) || e.keyCode == 46 || (e.keyCode >=96 && e.keyCode <= 111)) { |
| self.ui.update(); |
| } |
| }) |
| .bind('keydown', function(e) { |
| if ((e.metaKey || e.ctrlKey) && e.keyCode == 65) { |
| self.ui.update(); |
| } else if (e.keyCode == 13) { |
| var n = self.selection.getNode(); |
| // self.log(n) |
| if (self.dom.selfOrParent(n, /^PRE$/)) { |
| self.selection.insertNode(self.doc.createTextNode("\r\n")); |
| return false; |
| } else if ($.browser.safari && e.shiftKey) { |
| self.selection.insertNode(self.doc.createElement('br')) |
| return false; |
| } |
| } |
| |
| if ((e.keyCode>=48 && e.keyCode <=57) || e.keyCode==61 || e.keyCode == 109 || (e.keyCode>=65 && e.keyCode<=90) || e.keyCode==188 ||e.keyCode==190 || e.keyCode==191 || (e.keyCode>=219 && e.keyCode<=222)) { |
| if (!self.typing) { |
| self.history.add(true); |
| } |
| self.typing = true; |
| self.lastKey = null; |
| } else if (e.keyCode == 8 || e.keyCode == 46 || e.keyCode == 32 || e.keyCode == 13) { |
| if (e.keyCode != self.lastKey) { |
| self.history.add(true); |
| } |
| self.lastKey = e.keyCode; |
| self.typing = false; |
| } |
| |
| if (e.keyCode == 32 && $.browser.opera) { |
| self.selection.insertNode(self.doc.createTextNode(" ")); |
| return false |
| } |
| }) |
| .bind('paste', function(e) { |
| if (!self.options.allowPaste) { |
| // paste denied |
| e.stopPropagation(); |
| e.preventDefault(); |
| } else { |
| var n = $(self.dom.create('div'))[0], |
| r = self.doc.createTextNode('_'); |
| self.history.add(true); |
| self.typing = true; |
| self.lastKey = null; |
| n.appendChild(r); |
| self.selection.deleteContents().insertNode(n); |
| self.selection.select(r); |
| setTimeout(function() { |
| if (n.parentNode) { |
| // clean sandbox content |
| $(n).html(self.filter.proccess('paste', $(n).html())); |
| r = n.lastChild; |
| self.dom.unwrap(n); |
| if (r) { |
| self.selection.select(r); |
| self.selection.collapse(false); |
| } |
| } else { |
| // smth wrong - clean all doc |
| n.parentNode && n.parentNode.removeChild(n); |
| self.val(self.filter.proccess('paste', self.filter.wysiwyg2wysiwyg($(self.doc.body).html()))); |
| self.selection.select(self.doc.body.firstChild); |
| self.selection.collapse(true); |
| } |
| $(self.doc.body).mouseup(); // to activate history buutons |
| }, 15); |
| } |
| }); |
| |
| if ($.browser.msie) { |
| this.$doc.bind('keyup', function(e) { |
| if (e.keyCode == 86 && (e.metaKey||e.ctrlKey)) { |
| self.history.add(true); |
| self.typing = true; |
| self.lastKey = null; |
| self.selection.saveIERange(); |
| self.val(self.filter.proccess('paste', self.filter.wysiwyg2wysiwyg($(self.doc.body).html()))); |
| self.selection.restoreIERange(); |
| $(self.doc.body).mouseup(); |
| this.ui.update(); |
| } |
| }); |
| } |
| |
| if ($.browser.safari) { |
| this.$doc.bind('click', function(e) { |
| $(self.doc.body).find('.elrte-webkit-hl').removeClass('elrte-webkit-hl'); |
| if (e.target.nodeName == 'IMG') { |
| $(e.target).addClass('elrte-webkit-hl'); |
| } |
| }).bind('keyup', function(e) { |
| $(self.doc.body).find('.elrte-webkit-hl').removeClass('elrte-webkit-hl'); |
| }) |
| } |
| |
| this.window.focus(); |
| |
| this.destroy = function() { |
| this.updateSource(); |
| this.target.is('textarea') |
| ? this.target.val($.trim(this.source.val())) |
| : this.target.html($.trim(this.source.val())); |
| this.editor.remove(); |
| this.target.show().parents('form').unbind('submit.elfinder'); |
| } |
| |
| } |
| |
| /** |
| * Return message translated to selected language |
| * |
| * @param string msg message text in english |
| * @return string |
| **/ |
| elRTE.prototype.i18n = function(msg) { |
| return this._i18n.translate(msg); |
| } |
| |
| |
| |
| /** |
| * Display editor |
| * |
| * @return void |
| **/ |
| elRTE.prototype.open = function() { |
| this.editor.show(); |
| } |
| |
| /** |
| * Hide editor and display elements on wich editor was created |
| * |
| * @return void |
| **/ |
| elRTE.prototype.close = function() { |
| this.editor.hide(); |
| } |
| |
| elRTE.prototype.updateEditor = function() { |
| this.val(this.source.val()); |
| } |
| |
| elRTE.prototype.updateSource = function() { |
| this.source.val(this.filter.source($(this.doc.body).html())); |
| } |
| |
| /** |
| * Return edited text |
| * |
| * @return String |
| **/ |
| elRTE.prototype.val = function(v) { |
| if (typeof(v) == 'string') { |
| v = ''+v; |
| if (this.source.is(':visible')) { |
| this.source.val(this.filter.source2source(v)); |
| } else { |
| if ($.browser.msie) { |
| this.doc.body.innerHTML = '<br />'+this.filter.wysiwyg(v); |
| this.doc.body.removeChild(this.doc.body.firstChild); |
| } else { |
| this.doc.body.innerHTML = this.filter.wysiwyg(v); |
| } |
| |
| } |
| } else { |
| if (this.source.is(':visible')) { |
| return this.filter.source2source(this.source.val()).trim(); |
| } else { |
| return this.filter.source($(this.doc.body).html()).trim(); |
| } |
| } |
| } |
| |
| elRTE.prototype.beforeSave = function() { |
| this.source.val($.trim(this.val())||''); |
| } |
| |
| /** |
| * Submit form |
| * |
| * @return void |
| **/ |
| elRTE.prototype.save = function() { |
| this.beforeSave(); |
| this.editor.parents('form').submit(); |
| } |
| |
| elRTE.prototype.log = function(msg) { |
| if (window.console && window.console.log) { |
| window.console.log(msg); |
| } |
| |
| } |
| |
| elRTE.prototype.i18Messages = {}; |
| |
| $.fn.elrte = function(o, v) { |
| var cmd = typeof(o) == 'string' ? o : '', ret; |
| |
| this.each(function() { |
| if (!this.elrte) { |
| this.elrte = new elRTE(this, typeof(o) == 'object' ? o : {}); |
| } |
| switch (cmd) { |
| case 'open': |
| case 'show': |
| this.elrte.open(); |
| break; |
| case 'close': |
| case 'hide': |
| this.elrte.close(); |
| break; |
| case 'updateSource': |
| this.elrte.updateSource(); |
| break; |
| case 'destroy': |
| this.elrte.destroy(); |
| } |
| }); |
| |
| if (cmd == 'val') { |
| if (!this.length) { |
| return ''; |
| } else if (this.length == 1) { |
| return v ? this[0].elrte.val(v) : this[0].elrte.val(); |
| } else { |
| ret = {} |
| this.each(function() { |
| ret[this.elrte.source.attr('name')] = this.elrte.val(); |
| }); |
| return ret; |
| } |
| } |
| return this; |
| } |
| |
| })(jQuery); |