svn commit: r1036195 [3/4] - in /ofbiz/branches/jquery: applications/content/webapp/content/content/ applications/content/webapp/content/website/ applications/content/widget/ applications/content/widget/content/ framework/common/webcommon/includes/ fra...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1036195 [3/4] - in /ofbiz/branches/jquery: applications/content/webapp/content/content/ applications/content/webapp/content/website/ applications/content/widget/ applications/content/widget/content/ framework/common/webcommon/includes/ fra...

jleroux@apache.org
Added: ofbiz/branches/jquery/framework/images/webapp/images/jquery/plugins/elrteEditor/elrte.full.js
URL: http://svn.apache.org/viewvc/ofbiz/branches/jquery/framework/images/webapp/images/jquery/plugins/elrteEditor/elrte.full.js?rev=1036195&view=auto
==============================================================================
--- ofbiz/branches/jquery/framework/images/webapp/images/jquery/plugins/elrteEditor/elrte.full.js (added)
+++ ofbiz/branches/jquery/framework/images/webapp/images/jquery/plugins/elrteEditor/elrte.full.js Wed Nov 17 20:13:57 2010
@@ -0,0 +1,8647 @@
+/*!
+ * elRTE WYSIWYG HTML-editor
+ * Version 1.1 (2010-09-20)
+ * http://elrte.org
+ *
+ * Copyright 2010, Studio 42 Ltd.
+ * Licensed under a 3 clauses BSD license
+ */
+
+/**
+ * @class eli18n
+ * Javascript applications localization
+ *
+ * @param Object o - class options. Object. {textdomain : 'имя_группы_сообщений', messages : {textdomain1 : {}[, textdomain2 : {}]...}}
+ *
+ * Usage:
+ *
+ * var msgs = { Hello : 'Превэд', 'Hello %user' : 'Превед %user' };
+ * //load messages and set default textdomain
+ * var translator = new eli18n( {textdomain : 'test', messages : {test : msgs}} )
+ * window.console.log(translator.translate('Hello'));
+ * window.console.log(translator.format('Hello %user', {user : 'David Blain'}))
+ * // create new textdomain
+ * translator.load({test2 : {'Goodbye' : 'Ja, deva mata!'} })
+ * // and use it, without changing default one
+ * window.console.log(translator.translate('Goodbye', 'test2'));
+ *
+ * @author:    Dmitry (dio) Levashov [hidden email]
+ * license:   BSD license
+ **/
+function eli18n(o) {
+
+ /**
+ * Get/set default textdomain
+ *
+ * @param String d new textdomain name
+ * @return String  default textdomain
+ **/
+ this.textdomain = function(d) {
+ return this.messages[d] ? this._domain = d : this._domain;
+ }
+
+ o && o.messages   && this.load(o.messages);
+ o && o.textdomain && this.textdomain(o.textdomain);
+}
+
+eli18n.prototype = new function() {
+
+ /**
+ * @var Object messages (key - messages in English or message handler, value - message in selected language)
+ **/
+ this.messages = {};
+ /**
+ * @var String default textdomain
+ **/
+ this._domain   = '';
+
+ /**
+ * Load new messages
+ *
+ * @param Object msgs - messages (key - textdomain name, value - messages Object)
+ * @return Object this
+ **/
+ this.load = function(msgs) {
+ if (typeof(msgs) == 'object') {
+ for (var d in msgs) {
+ var _msgs = msgs[d];
+ if (typeof(_msgs) == 'object') {
+ if (!this.messages[d]) {
+ this.messages[d] = {};
+ }
+ for (var k in _msgs) {
+ if (typeof(_msgs[k]) == 'string') {
+ this.messages[d][k] = _msgs[k];
+ }
+ }
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Return translated message, if message exists in required or default textdomain, otherwise returns original message
+ *
+ * @param  String msg - message
+ * @param  String d - textdomain. If empty, default textdomain will be used
+ * @return String translated message
+ **/
+ this.translate = function(msg, d) {
+ var d = d && this.messages[d] ? d : this._domain;
+ return this.messages[d] && this.messages[d][msg] ? this.messages[d][msg] : msg;
+
+ }
+
+ /**
+ * Translate message and replace placeholders (%placeholder)
+ *
+ * @param  String  msg - message
+ * @param  Object  replacement for placeholders (keys - placeholders name without leading %, values - replacements)
+ * @param  String  d - textdomain. If empty, default textdomain will be used
+ * @return String  translated message
+ **/
+ this.format = function(msg, data, d) {
+ msg = this.translate(msg, d);
+ if (typeof(data) == 'object') {
+ for (var i in data) {
+ msg = msg.replace('%'+i, this.translate(data[i], d));
+ }
+ }
+ return msg;
+ }
+}
+/**
+ * @class elDialogForm
+ * Wraper for jquery.ui.dialog and jquery.ui.tabs
+ *  Create form in dialog. You can decorate it as you wish - with tabs or/and tables
+ *
+ * Usage:
+ *   var d = new elDialogForm(opts)
+ *   d.append(['Field name: ', $('<input type="text" name="f1" />')])
+ * .separator()
+ * .append(['Another field name: ', $('<input type="text" name="f2" />')])
+ *      .open()
+ * will create dialog with pair text field separated by horizontal rule
+ * Calling append() with 2 additional arguments ( d.append([..], null, true))
+ *  - will create table in dialog and put text inputs and labels in table cells
+ *
+ * Dialog with tabs:
+ *   var d = new elDialogForm(opts)
+ *   d.tab('first', 'First tab label)
+ *  .tab('second', 'Second tab label)
+ *    .append(['Field name: ', $('<input type="text" name="f1" />')], 'first', true)  - add label and input to first tab in table (table will create automagicaly)
+ *    .append(['Field name 2: ', $('<input type="text" name="f2" />')], 'second', true)  - same in secon tab
+ *
+ * Options:
+ *   class     - css class for dialog
+ *   submit    - form submit event callback. Accept 2 args - event and this object
+ *   ajaxForm  - arguments for ajaxForm, if needed (dont forget include jquery.form.js)
+ *   tabs      - arguments for ui.tabs
+ *   dialog    - arguments for ui.dialog
+ *   name      - hidden text field in wich selected value will saved
+ *
+ * Notice!
+ * When close dialog, it will destroing insead of dialog('close'). Reason - strange bug with tabs in dialog on secondary opening.
+ *
+ * @author:    Dmitry Levashov (dio) [hidden email]
+ *
+ **/
+
+function elDialogForm(o) {
+ var self = this;
+
+ var defaults = {
+ 'class'   : 'el-dialogform',
+ submit    : function(e, d) { window.console && window.console.log && window.console.log('submit called'); d.close(); },
+ form      : { action : window.location.href, method : 'post' },
+ ajaxForm  : null,
+ validate  : null,
+ spinner   : 'Loading',
+ tabs      : { active: 0 },
+ tabPrefix : 'el-df-tab-',
+ dialog    : {
+ title     : 'dialog',
+ autoOpen  : false,
+ modal     : true,
+ resizable : false,
+ buttons  : {
+ Cancel : function() { self.close(); },
+ Ok     : function() { self.form.trigger('submit'); }
+ }
+ }
+ };
+
+ this.opts = jQuery.extend(true, defaults, o, {dialog : { autoOpen : false, close : function() { self.close(); } }});
+
+ if (this.opts.rtl) {
+ this.opts['class'] += ' el-dialogform-rtl';
+ }
+
+ if (o && o.dialog && o.dialog.buttons && typeof(o.dialog.buttons) == 'object') {
+ this.opts.dialog.buttons = o.dialog.buttons;
+ }
+ this.ul     = null;
+ this.tabs   = {};
+ this._table = null;
+ this.dialog = jQuery('<div />').addClass(this.opts['class']).dialog(this.opts.dialog);
+ this.message = jQuery('<div class="el-dialogform-message rounded-5" />').hide().appendTo(this.dialog);
+ this.error   = jQuery('<div class="el-dialogform-error rounded-5" />').hide().appendTo(this.dialog);
+ this.spinner = jQuery('<div class="spinner" />').hide().appendTo(this.dialog);
+ this.content = jQuery('<div class="el-dialogform-content" />').appendTo(this.dialog)
+ this.form   = jQuery('<form />').attr(this.opts.form).appendTo(this.content);
+
+ if (this.opts.submit) {
+ this.form.bind('submit', function(e) { self.opts.submit(e, self) })
+ }
+ if (this.opts.ajaxForm && jQuery.fn.ajaxForm) {
+ this.form.ajaxForm(this.opts.ajaxForm);
+ }
+ if (this.opts.validate) {
+ this.form.validate(this.opts.validate);
+ }
+
+ this.option = function(name, value) {
+ return this.dialog.dialog('option', name, value)
+ }
+
+ this.showError = function(msg, hideContent) {
+ this.hideMessage();
+ this.hideSpinner();
+ this.error.html(msg).show();
+ hideContent && this.content.hide();
+ return this;
+ }
+
+ this.hideError= function() {
+ this.error.text('').hide();
+ this.content.show();
+ return this;
+ }
+
+ this.showSpinner = function(txt) {
+ this.error.hide();
+ this.message.hide();
+ this.content.hide();
+ this.spinner.text(txt||this.opts.spinner).show();
+ this.option('buttons', {});
+ return this;
+ }
+
+ this.hideSpinner = function() {
+ this.content.show();
+ this.spinner.hide();
+ return this;
+ }
+
+ this.showMessage = function(txt, hideContent) {
+ this.hideError();
+ this.hideSpinner();
+ this.message.html(txt||'').show();
+ hideContent && this.content.hide();
+ return this;
+ }
+
+ this.hideMessage = function() {
+ this.message.hide();
+ this.content.show();
+ return this;
+ }
+
+ /**
+ * Create new tab
+ * @param string id    - tab id
+ * @param string title - tab name
+ * @return elDialogForm
+ **/
+ this.tab = function(id, title) {
+ id = this.opts.tabPrefix+id;
+
+ if (!this.ul) {
+ this.ul = jQuery('<ul />').prependTo(this.form);
+ }
+ jQuery('<li />').append(jQuery('<a />').attr('href', '#'+id).html(title)).appendTo(this.ul);
+ this.tabs[id] = {tab : jQuery('<div />').attr('id', id).addClass('tab').appendTo(this.form), table : null};
+ return this;
+ }
+
+ /**
+ * Create new table
+ * @param string id  tab id, if set - table will create in tab, otherwise - in dialog
+ * @return elDialogForm
+ **/
+ this.table = function(id) {
+ id = id && id.indexOf(this.opts.tabPrefix) == -1 ? this.opts.tabPrefix+id : id;
+ if (id && this.tabs && this.tabs[id]) {
+ this.tabs[id].table = jQuery('<table />').appendTo(this.tabs[id].tab);
+ } else {
+ this._table = jQuery('<table />').appendTo(this.form);
+ }
+ return this;
+ }
+
+ /**
+ * Append html, dom nodes or jQuery objects to dialog or tab
+ * @param array|object|string  data object(s) to append to dialog
+ * @param string               tid  tab id, if adding to tab
+ * @param bool                 t    if true - data will added in table (creating automagicaly)
+ * @return elDialogForm
+ **/
+ this.append = function(data, tid, t) {
+ tid = tid ? 'el-df-tab-'+tid : '';
+
+ if (!data) {
+ return this;
+ }
+
+ if (tid && this.tabs[tid]) {
+ if (t) {
+ !this.tabs[tid].table && this.table(tid);
+ var tr = jQuery('<tr />').appendTo(this.tabs[tid].table);
+ if (!jQuery.isArray(data)) {
+ tr.append(jQuery('<td />').append(data));
+ } else {
+ for (var i=0; i < data.length; i++) {
+ tr.append(jQuery('<td />').append(data[i]));
+ };
+ }
+ } else {
+ if (!jQuery.isArray(data)) {
+ this.tabs[tid].tab.append(data)
+ } else {
+ for (var i=0; i < data.length; i++) {
+ this.tabs[tid].tab.append(data[i]);
+ };
+ }
+ }
+
+ } else {
+ if (!t) {
+ if (!jQuery.isArray(data)) {
+ this.form.append(data);
+ } else {
+ for (var i=0; i < data.length; i++) {
+ this.form.append(data[i]);
+ };
+ }
+ } else {
+ if (!this._table) {
+ this.table();
+ }
+ var tr = jQuery('<tr />').appendTo(this._table);
+ if (!jQuery.isArray(data)) {
+ tr.append(jQuery('<td />').append(data));
+ } else {
+ for (var i=0; i < data.length; i++) {
+ tr.append(jQuery('<td />').append(data[i]));
+ };
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Append separator (div class="separator") to dialog or tab
+ * @param  string tid  tab id, if adding to tab
+ * @return elDialogForm
+ **/
+ this.separator = function(tid) {
+ tid = 'el-df-tab-'+tid;
+ if (this.tabs && this.tabs[tid]) {
+ this.tabs[tid].tab.append(jQuery('<div />').addClass('separator'));
+ this.tabs[tid].table && this.table(tid);
+ } else {
+ this.form.append(jQuery('<div />').addClass('separator'));
+ }
+ return this;
+ }
+
+ /**
+ * Open dialog window
+ * @return elDialogForm
+ **/
+ this.open = function() {
+ this.ul && this.form.tabs(this.opts.tabs);
+ this.form.find(':text').keyup(function(e) {
+ if (e.keyCode == 13) {
+ self.form.submit();
+ }
+ });
+
+ this.dialog.attr('unselectable', 'on').dialog('open');
+ var self = this;
+ if (this.form && this.form.find(':text').length) {
+ setTimeout(function() { self.form.find(':text')[0].focus(); }, 20);
+ }
+
+ return this;
+ }
+
+ /**
+ * Close dialog window and destroy content
+ * @return void
+ **/
+ this.close = function() {
+ if (typeof(this.opts.close) == 'function') {
+ this.opts.close();
+ }
+ this.dialog.dialog('destroy').remove();
+ }
+
+}
+
+/**
+ * elColorPicker. JQuery plugin
+ * Create drop-down colors palette.
+ *
+ * Usage:
+ * $(selector).elColorPicker(opts)
+ *
+ * set color after init:
+ * var c = $(selector).elColorPicker(opts)
+ * c.val('#ffff99)
+ *
+ * Get selected color:
+ * var color = c.val();
+ *
+ * Notice!
+ *   Palette created only after first click on element (lazzy loading)
+ *
+ * Options:
+ *   colors - colors array (by default display 256 web safe colors)
+ *   color  - current (selected) color
+ *   class - css class for display "button" (element on wich plugin was called)
+ *   paletteClass - css class for colors palette
+ *   palettePosition - string indicate where palette will created:
+ *      'inner' - palette will attach to element (acceptable in most cases)
+ *      'outer' - palette will attach to document.body.
+ *                Use, when create color picker inside element with overflow == 'hidden', for example in ui.dialog
+ *   update - function wich update button view on select color (by default set selected color as background)
+ *   change - callback, called when color was selected (by default write color to console.log)
+ *   name   - hidden text field in wich selected color value will saved
+ *
+ * @author:    Dmitry Levashov (dio) [hidden email]
+ *
+ **/
+(function($) {
+
+ $.fn.elColorPicker = function(o) {
+ var self     = this;
+ var opts     = $.extend({}, $.fn.elColorPicker.defaults, o);
+ this.hidden  = $('<input type="hidden" />').attr('name', opts.name).val(opts.color||'').appendTo(this);
+ this.palette = null;
+ this.preview = null;
+ this.input   = null;
+
+ function setColor(c) {
+ self.val(c);
+ opts.change && opts.change(self.val());
+ self.palette.slideUp();
+ }
+
+ function init() {
+ self.palette  = $('<div />').addClass(opts.paletteClass+' rounded-3');
+ for (var i=0; i < opts.colors.length; i++) {
+ $('<div />')
+ .addClass('color')
+ .css('background-color', opts.colors[i])
+ .attr({title : opts.colors[i], unselectable : 'on'})
+ .appendTo(self.palette)
+ .mouseenter(function() {
+ var v = $(this).attr('title');
+ self.input.val(v);
+ self.preview.css('background-color', v);
+ })
+ .click(function(e) {
+ e.stopPropagation();
+ setColor($(this).attr('title'));
+ });
+ };
+ self.input = $('<input type="text" />')
+ .addClass('rounded-3')
+ .attr('size', 8)
+ .click(function(e) {
+ e.stopPropagation();
+ })
+ .keydown(function(e) {
+ if (e.ctrlKey || e.metaKey) {
+ return true;
+ }
+ var k = e.keyCode;
+ // on esc - close palette
+ if (k == 27) {
+ return self.mouseleave();
+ }
+ // allow input only hex color value
+ if (k!=8 && k != 13 && k!=46 && k!=37 && k != 39 && (k<48 || k>57) && (k<65 || k > 70)) {
+ return false;
+ }
+ var c = $(this).val();
+ if (c.length == 7 || c.length == 0) {
+ if (k == 13) {
+ e.stopPropagation();
+ e.preventDefault();
+ setColor(c);
+ self.palette.slideUp();
+ }
+ if (e.keyCode != 8 && e.keyCode != 46 && k!=37 && k != 39) {
+ return false;
+ }
+ }
+ })
+ .keyup(function(e) {
+ var c = $(this).val();
+ c.length == 7 && /^#[0-9abcdef]{6}$/i.test(c) && self.val(c);
+ });
+
+ self.preview = $('<div />')
+ .addClass('preview rounded-3')
+ .click(function(e) {
+ e.stopPropagation();
+ setColor(self.input.val());
+ });
+
+ self.palette
+ .append($('<div />').addClass('clearfix'))
+ .append($('<div />').addClass('panel').append(self.input).append(self.preview));
+
+ if (opts.palettePosition == 'outer') {
+ self.palette.hide()
+ .appendTo(self.parents('body').eq(0))
+ .mouseleave(function() {
+ $(this).slideUp();
+ self.val(self.val());
+ })
+ self.mouseleave(function(e) {
+ if (e.relatedTarget != self.palette.get(0)) {
+ self.palette.slideUp();
+ self.val(self.val());
+ }
+ })
+ } else {
+ self.append(self.palette.hide())
+ .mouseleave(function(e) {
+ self.palette.slideUp();
+ self.val(self.val());
+ });
+ }
+ self.val(self.val());
+ }
+
+ this.empty().addClass(opts['class']+' rounded-3')
+ .css({'position' : 'relative', 'background-color' : opts.color||''})
+ .click(function(e) {
+ if (!self.hasClass('disabled')) {
+ !self.palette && init();
+ if (opts.palettePosition == 'outer' && self.palette.css('display') == 'none') {
+ var o = $(this).offset();
+ var w = self.palette.width();
+ var l = self.parents('body').width() - o.left >= w ? o.left : o.left + $(this).outerWidth() - w;
+ self.palette.css({left : l+'px', top : o.top+$(this).height()+1+'px'});
+ }
+ self.palette.slideToggle();
+ }
+ });
+
+ this.val = function(v) {
+ if (!v && v!=='') {
+ return this.hidden.val();
+ } else {
+ this.hidden.val(v);
+ if (opts.update) {
+ opts.update(this.hidden.val());
+ } else {
+ this.css('background-color', v);
+ }
+
+ if (self.palette) {
+ self.preview.css('background-color', v);
+ self.input.val(v);
+ }
+ }
+ return this;
+ }
+
+ return this;
+ }
+
+ $.fn.elColorPicker.defaults = {
+ 'class'         : 'el-colorpicker',
+ paletteClass    : 'el-palette',
+ palettePosition : 'inner',
+ name            : 'color',
+ color           : '',
+ update          : null,
+ change          : function(c) {  },
+ colors          : [
+ '#ffffff', '#cccccc', '#999999', '#666666', '#333333', '#000000',
+ '#ffcccc', '#cc9999', '#996666', '#663333', '#330000',
+ '#ff9999', '#cc6666', '#cc3333', '#993333', '#660000',
+ '#ff6666', '#ff3333', '#ff0000', '#cc0000', '#990000',
+ '#ff9966', '#ff6633', '#ff3300', '#cc3300', '#993300',
+ '#ffcc99', '#cc9966', '#cc6633', '#996633', '#663300',
+ '#ff9933', '#ff6600', '#ff9900', '#cc6600', '#cc9933',
+ '#ffcc66', '#ffcc33', '#ffcc00', '#cc9900', '#996600',
+ '#ffffcc', '#cccc99', '#999966', '#666633', '#333300',
+ '#ffff99', '#cccc66', '#cccc33', '#999933', '#666600',
+ '#ffff66', '#ffff33', '#ffff00', '#cccc00', '#999900',
+ '#ccff66', '#ccff33', '#ccff00', '#99cc00', '#669900',
+ '#ccff99', '#99cc66', '#99cc33', '#669933', '#336600',
+ '#99ff33', '#99ff00', '#66ff00', '#66cc00', '#66cc33',
+ '#99ff66', '#66ff33', '#33ff00', '#33cc00', '#339900',
+ '#ccffcc', '#99cc99', '#669966', '#336633', '#003300',
+ '#99ff99', '#66cc66', '#33cc33', '#339933', '#006600',
+ '#66ff66', '#33ff33', '#00ff00', '#00cc00', '#009900',
+ '#66ff99', '#33ff66', '#00ff33', '#00cc33', '#009933',
+ '#99ffcc', '#66cc99', '#33cc66', '#339966', '#006633',
+ '#33ff99', '#00ff66', '#00ff99', '#00cc66', '#33cc99',
+ '#66ffcc', '#33ffcc', '#00ffcc', '#00cc99', '#009966',
+ '#ccffff', '#99cccc', '#669999', '#336666', '#003333',
+ '#99ffff', '#66cccc', '#33cccc', '#339999', '#006666',
+ '#66cccc', '#33ffff', '#00ffff', '#00cccc', '#009999',
+ '#66ccff', '#33ccff', '#00ccff', '#0099cc', '#006699',
+ '#99ccff', '#6699cc', '#3399cc', '#336699', '#003366',
+ '#3399ff', '#0099ff', '#0066ff', '#066ccc', '#3366cc',
+ '#6699ff', '#3366ff', '#0033ff', '#0033cc', '#003399',
+ '#ccccff', '#9999cc', '#666699', '#333366', '#000033',
+ '#9999ff', '#6666cc', '#3333cc', '#333399', '#000066',
+ '#6666ff', '#3333ff', '#0000ff', '#0000cc', '#009999',
+ '#9966ff', '#6633ff', '#3300ff', '#3300cc', '#330099',
+ '#cc99ff', '#9966cc', '#6633cc', '#663399', '#330066',
+ '#9933ff', '#6600ff', '#9900ff', '#6600cc', '#9933cc',
+ '#cc66ff', '#cc33ff', '#cc00ff', '#9900cc', '#660099',
+ '#ffccff', '#cc99cc', '#996699', '#663366', '#330033',
+ '#ff99ff', '#cc66cc', '#cc33cc', '#993399', '#660066',
+ '#ff66ff', '#ff33ff', '#ff00ff', '#cc00cc', '#990099',
+ '#ff66cc', '#ff33cc', '#ff00cc', '#cc0099', '#990066',
+ '#ff99cc', '#cc6699', '#cc3399', '#993366', '#660033',
+ '#ff3399', '#ff0099', '#ff0066', '#cc0066', '#cc3366',
+ '#ff6699', '#ff3366', '#ff0033', '#cc0033', '#990033'
+ ]
+ };
+
+})(jQuery);
+/**
+ * jQuery plugin. Create group of text input, elSelect and elColorPicker.
+ * Allow input border-width, border-style and border-color. Used in elRTE
+ *
+ * @author:    Dmitry Levashov (dio) [hidden email]
+ **/
+(function($) {
+
+ $.fn.elBorderSelect = function(o) {
+
+ var $self = this;
+ var self  = this.eq(0);
+ var opts  = $.extend({}, $.fn.elBorderSelect.defaults, o);
+ var width = $('<input type="text" />')
+ .attr({'name' : opts.name+'[width]', size : 3}).css('text-align', 'right')
+ .change(function() { $self.change(); });
+
+ var color = $('<div />').css('position', 'relative')
+ .elColorPicker({
+ 'class'         : 'el-colorpicker ui-icon ui-icon-pencil',
+ name            : opts.name+'[color]',
+ palettePosition : 'outer',
+ change          : function() { $self.change(); }
+ });
+
+
+ var style = $('<div />').elSelect({
+ tpl       : '<div style="border-bottom:4px %val #000;width:100%;margin:7px 0"> </div>',
+ tpls      : { '' : '%label'},
+ maxHeight : opts.styleHeight || null,
+ select    : function() { $self.change(); },
+ src       : {
+ ''       : 'none',
+ solid    : 'solid',
+ dashed   : 'dashed',
+ dotted   : 'dotted',
+ 'double' : 'double',
+ groove   : 'groove',
+ ridge    : 'ridge',
+ inset    : 'inset',
+ outset   : 'outset'
+ }
+ });
+
+ self.empty()
+ .addClass(opts['class'])
+ .attr('name', opts.name||'')
+ .append(
+ $('<table />').attr('cellspacing', 0).append(
+ $('<tr />')
+ .append($('<td />').append(width).append(' px'))
+ .append($('<td />').append(style))
+ .append($('<td />').append(color))
+ )
+ );
+
+ function rgb2hex(str) {
+    function hex(x)  {
+     hexDigits = ["0", "1", "2", "3", "4", "5", "6", "7", "8","9", "a", "b", "c", "d", "e", "f"];
+        return !x  ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x% 16];
+    }
+ var rgb = (str||'').match(/\(([0-9]{1,3}),\s*([0-9]{1,3}),\s*([0-9]{1,3})\)/);
+ return rgb ? "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]) : '';
+ }
+
+ function toPixels(num) {
+ if (!num) {
+ return num;
+ }
+ var m = num.match(/([0-9]+\.?[0-9]*)\s*(px|pt|em|%)/);
+ if (m) {
+ num  = m[1];
+ unit = m[2];
+ }
+ if (num[0] == '.') {
+ num = '0'+num;
+ }
+ num = parseFloat(num);
+
+ if (isNaN(num)) {
+ return '';
+ }
+ var base = parseInt($(document.body).css('font-size')) || 16;
+ switch (unit) {
+ case 'em': return parseInt(num*base);
+ case 'pt': return parseInt(num*base/12);
+ case '%' : return parseInt(num*base/100);
+ }
+ return num;
+ }
+
+ this.change = function() {
+ opts.change && opts.change(this.val());
+ }
+
+ this.val = function(v) {
+ if (!v && v !== '') {
+ var w = parseInt(width.val());
+ return {width : !isNaN(w) ? w+'px' : '', style : style.val(), color : color.val()};
+ } else {
+ var m, w, s, c, b = '';
+ if (v.nodeName || v.css) {
+ if (!v.css) {
+ v = $(v);
+ }
+ var b = v.css('border')
+ if ((b = v.css('border'))) {
+ w = s = c = b;
+ } else {
+ w = v.css('border-width');
+ s = v.css('border-style');
+ c = v.css('border-color');
+ }
+
+ } else {
+ w = v.width||'';
+ s = v.style||'';
+ c = v.color||'';
+ }
+
+ width.val(toPixels(w));
+ var m = s ? s.match(/(solid|dashed|dotted|double|groove|ridge|inset|outset)/i) :'';
+ style.val(m ? m[1] : '');
+ color.val(rgb2hex(c));
+ return this;
+ }
+ }
+
+ this.val(opts.value);
+ return this;
+ }
+
+ $.fn.elBorderSelect.defaults = {
+ name      : 'el-borderselect',
+ 'class'   : 'el-borderselect',
+ value     : {},
+ change    : null
+ }
+
+})(jQuery);
+/**
+ * jQuery plugin. Create group of text input fields and selects for setting padding/margin. Used in elRTE
+ *
+ * @author:    Dmitry Levashov (dio) [hidden email]
+ **/
+(function($) {
+
+ $.fn.elPaddingInput = function(o) {
+ var self = this;
+ var opts = $.extend({}, $.fn.elPaddingInput.defaults, {name : this.attr('name')}, o);
+ this.regexps = {
+ main   : new RegExp(opts.type == 'padding' ? 'padding\s*:\s*([^;"]+)'        : 'margin\s*:\s*([^;"]+)',       'im'),
+ left   : new RegExp(opts.type == 'padding' ? 'padding-left\s*:\s*([^;"]+)'   : 'margin-left\s*:\s*([^;"]+)',  'im'),
+ top    : new RegExp(opts.type == 'padding' ? 'padding-top\s*:\s*([^;"]+)'    : 'margin-top\s*:\s*([^;"]+)',    'im'),
+ right  : new RegExp(opts.type == 'padding' ? 'padding-right\s*:\s*([^;"]+)'  : 'margin-right\s*:\s*([^;"]+)',  'im'),
+ bottom : new RegExp(opts.type == 'padding' ? 'padding-bottom\s*:\s*([^;"]+)' : 'margin-bottom\s*:\s*([^;"]+)', 'im')
+ };
+
+ $.each(['left', 'top', 'right', 'bottom'], function() {
+
+ self[this] = $('<input type="text" />')
+ .attr('size', 3)
+ .css('text-align', 'right')
+ .css('border-'+this, '2px solid red')
+ .bind('change', function() { $(this).val(parseNum($(this).val())); change(); })
+ .attr('name', opts.name+'['+this+']');
+ });
+ $.each(['uleft', 'utop', 'uright', 'ubottom'], function() {
+ self[this] = $('<select />')
+ .append('<option value="px">px</option>')
+ .append('<option value="em">em</option>')
+ .append('<option value="pt">pt</option>')
+ .bind('change', function() { change(); })
+ .attr('name', opts.name+'['+this+']');
+ if (opts.percents) {
+ self[this].append('<option value="%">%</option>');
+ }
+ });
+
+ this.empty().addClass(opts['class'])
+ .append(this.left).append(this.uleft).append(' x ')
+ .append(this.top).append(this.utop).append(' x ')
+ .append(this.right).append(this.uright).append(' x ')
+ .append(this.bottom).append(this.ubottom);
+
+ this.val = function(v) {
+ if (!v && v!=='') {
+ var l = parseNum(this.left.val());
+ var t = parseNum(this.top.val());
+ var r = parseNum(this.right.val());
+ var b = parseNum(this.bottom.val());
+ var ret = {
+ left   : l=='auto' || l==0 ? l : (l!=='' ? l+this.uleft.val()   : ''),
+ top    : t=='auto' || t==0 ? t : (t!=='' ? t+this.utop.val()    : ''),
+ right  : r=='auto' || r==0 ? r : (r!=='' ? r+this.uright.val()  : ''),
+ bottom : b=='auto' || b==0 ? b : (b!=='' ? b+this.ubottom.val() : ''),
+ css    : ''
+ };
+ if (ret.left!=='' && ret.right!=='' && ret.top!=='' && ret.bottom!=='') {
+ if (ret.left == ret.right && ret.top == ret.bottom) {
+ ret.css = ret.top+' '+ret.left;
+ } else{
+ ret.css = ret.top+' '+ret.right+' '+ret.bottom+' '+ret.left;
+ }
+ }
+
+ return ret;
+ } else {
+
+ if (v.nodeName || v.css) {
+ if (!v.css) {
+ v = $(v);
+ }
+ var val   = {left : '', top : '', right: '', bottom : ''};
+ var style = (v.attr('style')||'').toLowerCase();
+
+ if (style) {
+ style   = $.trim(style);
+ var m = style.match(this.regexps.main);
+ if (m) {
+ var tmp    = $.trim(m[1]).replace(/\s+/g, ' ').split(' ', 4);
+ val.top    = tmp[0];
+ val.right  = tmp[1] && tmp[1]!=='' ? tmp[1] : val.top;
+ val.bottom = tmp[2] && tmp[2]!=='' ? tmp[2] : val.top;
+ val.left   = tmp[3] && tmp[3]!=='' ? tmp[3] : val.right;
+ } else {
+ $.each(['left', 'top', 'right', 'bottom'], function() {
+ var name = this.toString();
+ m = style.match(self.regexps[name]);
+ if (m) {
+ val[name] = m[1];
+ }
+ });
+ }
+ }
+ var v = val;
+ }
+
+ $.each(['left', 'top', 'right', 'bottom'], function() {
+ var name = this.toString();
+ if (typeof(v[name]) != 'undefined' && v[name] !== null) {
+ v[name] = v[name].toString();
+ var _v = parseNum(v[name]);
+ self[name].val(_v);
+ var m = v[name].match(/(px|em|pt|%)/i);
+ self['u'+name].val(m ? m[1] : 'px');
+ }
+ });
+ return this;
+ }
+ }
+
+ function parseNum(num) {
+ num = $.trim(num.toString());
+ if (num[0] == '.') {
+ num = '0'+num;
+ }
+ n = parseFloat(num);
+ return !isNaN(n) ? n : (num == 'auto' ? num : '');
+ }
+
+ function change() {
+ opts.change && opts.change(self);
+ }
+
+ this.val(opts.value);
+
+ return this;
+ }
+
+ $.fn.elPaddingInput.defaults = {
+ name     : 'el-paddinginput',
+ 'class'  : 'el-paddinginput',
+ type     : 'padding',
+ value    : {},
+ percents : true,
+ change   : null
+ }
+
+})(jQuery);
+/**
+ * elSelect JQuery plugin
+ * Replacement for select input
+ * Allow to put any html and css decoration in drop-down list
+ *
+ * Usage:
+ *   $(selector).elSelect(opts)
+ *
+ * set value after init:
+ *   var c = $(selector).elSelect(opts)
+ *   c.val('some value')
+ *
+ * Get selected value:
+ *   var val = c.val();
+ *
+ * Notice!
+ *   1. When called on multiply elements, elSelect create drop-down list only for fist element
+ *   2. Elements list created only after first click on element (lazzy loading)
+ *
+ * Options:
+ *   src       - object with pairs value:label to create drop-down list
+ *   value     - current (selected) value
+ *   class     - css class for display "button" (element on wich plugin was called)
+ *   listClass - css class for drop down elements list
+ *   select    - callback, called when value was selected (by default write value to console.log)
+ *   name      - hidden text field in wich selected value will saved
+ *   maxHeight - elements list max height (if height greater - scroll will appear)
+ *   tpl       - template for element in list (contains 2 vars: %var - for src key, %label - for src[val] )
+ *   labelTpl  - template for label (current selected element) (contains 2 placeholders: %var - for src key, %label - for src[val] )
+ *
+ * @author:    Dmitry Levashov (dio) [hidden email]
+ **/
+(function($) {
+
+ $.fn.elSelect = function(o) {
+ var $self    = this;
+ var self     = this.eq(0);
+ var opts     = $.extend({}, $.fn.elSelect.defaults, o);
+ var hidden   = $('<input type="hidden" />').attr('name', opts.name);
+ var label    = $('<label />').attr({unselectable : 'on'}).addClass('rounded-left-3');
+ var list     = null;
+ var ieWidth  = null;
+
+ if (self.get(0).nodeName == 'SELECT') {
+ opts.src = {};
+ self.children('option').each(function() {
+ opts.src[$(this).val()] = $(this).text();
+ });
+ opts.value = self.val();
+ opts.name  = self.attr('name');
+ self.replaceWith((self = $('<div />')));
+ }
+
+ if (!opts.value || !opts.src[opts.val]) {
+ opts.value = null;
+ var i = 0;
+ for (var v in opts.src) {
+ if (i++ == 0) {
+ opts.value = v;
+ }
+ }
+ }
+
+ this.val = function(v) {
+ if (!v && v!=='') {
+ return hidden.val();
+ } else {
+ if (opts.src[v]) {
+ hidden.val(v);
+ updateLabel(v);
+ if (list) {
+ list.children().each(function() {
+ if ($(this).attr('name') == v) {
+ $(this).addClass('active');
+ } else {
+ $(this).removeClass('active');
+ }
+ });
+ }
+ }
+ return this;
+ }
+ }
+
+ // update label content
+ function updateLabel(v) {
+ var tpl = opts.labelTpl || opts.tpls[v] || opts.tpl;
+ label.html(tpl.replace(/%val/g, v).replace(/%label/, opts.src[v])).children().attr({unselectable : 'on'});
+ }
+
+ // init "select"
+ self.empty()
+ .addClass(opts['class']+' rounded-3')
+ .attr({unselectable : 'on'})
+ .append(hidden)
+ .append(label)
+ .hover(
+ function() { $(this).addClass('hover') },
+ function() { $(this).removeClass('hover') }
+ )
+ .click(function(e) {
+ !list && init();
+ list.slideToggle();
+ // stupid ie inherit width from parent
+ if ($.browser.msie && !ieWidth) {
+ list.children().each(function() {
+ ieWidth = Math.max(ieWidth, $(this).width());
+ });
+ if (ieWidth > list.width()) {
+ list.width(ieWidth+40);
+ }
+ }
+ });
+
+ this.val(opts.value);
+
+ // create drop-down list
+ function init() {
+ // not ul because of ie is stupid with mouseleave in it :(
+ list = $('<div />')
+ .addClass(opts.listClass+' rounded-3')
+ .hide()
+ .appendTo(self.mouseleave(function(e) { list.slideUp(); }));
+
+ for (var v in opts.src) {
+ var tpl = opts.tpls[v] || opts.tpl;
+ $('<div />')
+ .attr('name', v)
+ .append( $(tpl.replace(/%val/g, v).replace(/%label/g, opts.src[v])).attr({unselectable : 'on'}) )
+ .appendTo(list)
+ .hover(
+ function() { $(this).addClass('hover') },
+ function() { $(this).removeClass('hover') }
+ )
+ .click(function(e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ var v = $(this).attr('name');
+ $self.val(v);
+ opts.select(v);
+ list.slideUp();
+ });
+ };
+
+ var w = self.outerWidth();
+ if (list.width() < w) {
+ list.width(w);
+ }
+
+ var h = list.height();
+ if (opts.maxHeight>0 && h>opts.maxHeight) {
+ list.height(opts.maxHeight);
+ }
+
+ $self.val(hidden.val());
+ }
+
+ return this;
+ }
+
+ $.fn.elSelect.defaults = {
+ name      : 'el-select',
+ 'class'   : 'el-select',
+ listClass : 'list',
+ labelTpl  : null,
+ tpl       : '<%val>%label</%val>',
+ tpls      : {},
+ value     : null,
+ src       : {},
+ select    : function(v) {  window.console &&  window.console.log && window.console.log('selected: '+v); },
+ maxHeight : 410
+ }
+
+})(jQuery);
+/*
+ * 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) [hidden email]
+ * 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.1';
+ this.build   = '2010-09-20';
+ this.options = $.extend(true, {}, this.options, opts);
+ this.browser = $.browser;
+ this.target  = $(target);
+
+ this.lang      = (''+this.options.lang).toLowerCase();
+ 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.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);
+
+ }
+ 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', 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);
+ }
+ }
+ });
+
+ /* update buttons on click and keyup */
+ this.$doc.bind('mouseup', function() {
+ self.ui.update();
+ })
+ .bind('dragstart', function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ })
+ .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.log('keyup '+e.keyCode)
+ 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;
+ }
+ }
+ })
+
+ this.typing = false;
+ this.lastKey = null;
+
+ this.$doc.bind('keydown', function(e) {
+ 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;
+ }
+
+ })
+ .bind('mouseup', function() {
+ self.typing = false;
+ self.lastKey = null;
+ })
+ .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.resizable(true)
+ this.window.focus();
+ // this.log(this.editor.parents('form').find('[name="el-select"]'))
+
+
+}
+
+/**
+ * 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());
+ } else {
+ return this.filter.source($(this.doc.body).html());
+ }
+ }
+}
+
+elRTE.prototype.beforeSave = function() {
+ this.source.val(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;
+ }
+ });
+
+ 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);
+/*
+ * DOM utilites for elRTE
+ *
+ * @author:    Dmitry Levashov (dio) [hidden email]
+ */
+(function($) {
+elRTE.prototype.dom = function(rte) {
+ this.rte = rte;
+ var self = this;
+ this.regExp = {
+ textNodes         : /^(A|ABBR|ACRONYM|ADDRESS|B|BDO|BIG|BLOCKQUOTE|CAPTION|CENTER|CITE|CODE|DD|DEL|DFN|DIV|DT|EM|FIELDSET|FONT|H[1-6]|I|INS|KBD|LABEL|LEGEND|LI|MARQUEE|NOBR|NOEMBED|P|PRE|Q|SAMP|SMALL|SPAN|STRIKE|STRONG|SUB|SUP|TD|TH|TT|VAR)$/,
+ textContainsNodes : /^(A|ABBR|ACRONYM|ADDRESS|B|BDO|BIG|BLOCKQUOTE|CAPTION|CENTER|CITE|CODE|DD|DEL|DFN|DIV|DL|DT|EM|FIELDSET|FONT|H[1-6]|I|INS|KBD|LABEL|LEGEND|LI|MARQUEE|NOBR|NOEMBED|OL|P|PRE|Q|SAMP|SMALL|SPAN|STRIKE|STRONG|SUB|SUP|TABLE|THEAD|TBODY|TFOOT|TD|TH|TR|TT|UL|VAR)$/,
+ block             : /^(APPLET|BLOCKQUOTE|BR|CAPTION|CENTER|COL|COLGROUP|DD|DIV|DL|DT|H[1-6]|EMBED|FIELDSET|LI|MARQUEE|NOBR|OBJECT|OL|P|PRE|TABLE|THEAD|TBODY|TFOOT|TD|TH|TR|UL)$/,
+ selectionBlock    : /^(APPLET|BLOCKQUOTE|BR|CAPTION|CENTER|COL|COLGROUP|DD|DIV|DL|DT|H[1-6]|EMBED|FIELDSET|LI|MARQUEE|NOBR|OBJECT|OL|P|PRE|TD|TH|TR|UL)$/,
+ header            : /^H[1-6]$/,
+ formElement       : /^(FORM|INPUT|HIDDEN|TEXTAREA|SELECT|BUTTON)$/
+ };
+
+ /********************************************************/
+ /*                      Ð£Ñ‚илиты                         */
+ /********************************************************/
+
+ /**
+ * Возвращает body редактируемого документа
+ *
+ * @return Element
+ **/
+ this.root = function() {
+ return this.rte.body;
+ }
+
+ this.create = function(t) {
+ return this.rte.doc.createElement(t);
+ }
+
+ /**
+ * Return node for bookmark with unique ID
+ *
+ * @return DOMElement
+ **/
+ this.createBookmark = function() {
+ var b = this.rte.doc.createElement('span');
+ b.id = 'elrte-bm-'+Math.random().toString().substr(2);
+ $(b).addClass('elrtebm');
+ return b;
+ }
+
+ /**
+ * Вовращает индекс элемента внутри родителя
+ *
+ * @param  Element n  Ð½Ð¾Ð´Ð°
+ * @return integer
+ **/
+ this.indexOf = function(n) {
+ var ndx = 0;
+ n = $(n);
+ while ((n = n.prev()) && n.length) {
+ ndx++;
+ }
+ return ndx;
+ }
+
+ /**
+ * Вовращает значение аттрибута в нижнем регистре (ох уж этот IE)
+ *
+ * @param  Element n  Ð½Ð¾Ð´Ð°
+ * @param  String  attr имя аттрибута
+ * @return string
+ **/
+ this.attr = function(n, attr) {
+ var v = '';
+ if (n.nodeType == 1) {
+ v = $(n).attr(attr);
+ if (v && attr != 'src' && attr != 'href') {
+ v = v.toString().toLowerCase();
+ }
+ }
+ return v||'';
+ }
+
+ /**
+ * Вовращает ближайший общий контейнер для 2-х эл-тов
+ *
+ * @param  Element n  Ð½Ð¾Ð´Ð°1
+ * @param  Element n  Ð½Ð¾Ð´Ð°2
+ * @return Element
+ **/
+ this.findCommonAncestor = function(n1, n2) {
+ if (!n1 || !n2) {
+ return this.rte.log('dom.findCommonAncestor invalid arguments');
+ }
+ if (n1 == n2) {
+ return n1;
+ } else if (n1.nodeName == 'BODY' || n2.nodeName == 'BODY') {
+ return this.rte.doc.body;
+ }
+ var p1 = $(n1).parents(), p2 = $(n2).parents(), l  = p2.length-1, c  = p2[l];
+ for (var i = p1.length - 1; i >= 0; i--, l--){
+ if (p1[i] == p2[l]) {
+ c = p1[i];
+ } else {
+ break;
+ }
+ };
+ return c;
+ }
+ /**
+ * Вовращает TRUE, если нода пустая
+ * пустой считаем ноды:
+ *  - текстовые эл-ты, содержащие пустую строку или тег br
+ *  - текстовые ноды с пустой строкой
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return bool
+ **/
+ this.isEmpty = function(n) {
+ if (n.nodeType == 1) {
+ return this.regExp.textNodes.test(n.nodeName) ? $.trim($(n).text()).length == 0 : false;
+ } else if (n.nodeType == 3) {
+ return /^(TABLE|THEAD|TFOOT|TBODY|TR|UL|OL|DL)$/.test(n.parentNode.nodeName)
+ || n.nodeValue == ''
+ || ($.trim(n.nodeValue).length== 0 && !(n.nextSibling && n.previousSibling && n.nextSibling.nodeType==1 && n.previousSibling.nodeType==1 && !this.regExp.block.test(n.nextSibling.nodeName) && !this.regExp.block.test(n.previousSibling.nodeName) ));
+ }
+ return true;
+ }
+
+ /********************************************************/
+ /*                  ÐŸÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ðµ по DOM                  */
+ /********************************************************/
+
+ /**
+ * Вовращает следующую соседнюю ноду (не включаются текстовые ноды не создающие значимые пробелы между инлайн элементами)
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return DOMElement
+ **/
+ this.next = function(n) {
+ while (n.nextSibling && (n = n.nextSibling)) {
+ if (n.nodeType == 1 || (n.nodeType == 3 && !this.isEmpty(n))) {
+ return n;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Вовращает предыдующую соседнюю ноду (не включаются текстовые ноды не создающие значимые пробелы между инлайн элементами)
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return DOMElement
+ **/
+ this.prev = function(n) {
+ while (n.previousSibling && (n = n.previousSibling)) {
+ if (n.nodeType == 1 || (n.nodeType ==3 && !this.isEmpty(n))) {
+ return n;
+ }
+ }
+ return null;
+ }
+
+ this.isPrev = function(n, prev) {
+ while ((n = this.prev(n))) {
+ if (n == prev) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Вовращает все следующие соседнии ноды (не включаются текстовые ноды не создающие значимые пробелы между инлайн элементами)
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return Array
+ **/
+ this.nextAll = function(n) {
+ var ret = [];
+ while ((n = this.next(n))) {
+ ret.push(n);
+ }
+ return ret;
+ }
+
+ /**
+ * Вовращает все предыдующие соседнии ноды (не включаются текстовые ноды не создающие значимые пробелы между инлайн элементами)
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return Array
+ **/
+ this.prevAll = function(n) {
+ var ret = [];
+ while ((n = this.prev(n))) {
+ ret.push(n);
+ }
+ return ret;
+ }
+
+ /**
+ * Вовращает все следующие соседнии inline ноды (не включаются текстовые ноды не создающие значимые пробелы между инлайн элементами)
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return Array
+ **/
+ this.toLineEnd = function(n) {
+ var ret = [];
+ while ((n = this.next(n)) && n.nodeName != 'BR' && n.nodeName != 'HR' && this.isInline(n)) {
+ ret.push(n);
+ }
+ return ret;
+ }
+
+ /**
+ * Вовращает все предыдующие соседнии inline ноды (не включаются текстовые ноды не создающие значимые пробелы между инлайн элементами)
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return Array
+ **/
+ this.toLineStart = function(n) {
+ var ret = [];
+ while ((n = this.prev(n)) && n.nodeName != 'BR' && n.nodeName != 'HR' && this.isInline(n) ) {
+ ret.unshift(n);
+ }
+ return ret;
+ }
+
+ /**
+ * Вовращает TRUE, если нода - первый непустой эл-т внутри родителя
+ *
+ * @param  Element n  Ð½Ð¾Ð´Ð°
+ * @return bool
+ **/
+ this.isFirstNotEmpty = function(n) {
+ while ((n = this.prev(n))) {
+ if (n.nodeType == 1 || (n.nodeType == 3 && $.trim(n.nodeValue)!='' ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Вовращает TRUE, если нода - последний непустой эл-т внутри родителя
+ *
+ * @param  Element n  Ð½Ð¾Ð´Ð°
+ * @return bool
+ **/
+ this.isLastNotEmpty = function(n) {
+ while ((n = this.next(n))) {
+ if (!this.isEmpty(n)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Вовращает TRUE, если нода - единственный непустой эл-т внутри родителя
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return bool
+ **/
+ this.isOnlyNotEmpty = function(n) {
+ return this.isFirstNotEmpty(n) && this.isLastNotEmpty(n);
+ }
+
+ /**
+ * Вовращает последний непустой дочерний эл-т ноды или FALSE
+ *
+ * @param  Element n  Ð½Ð¾Ð´Ð°
+ * @return Element
+ **/
+ this.findLastNotEmpty = function(n) {
+ this.rte.log('findLastNotEmpty Who is here 0_o');
+ if (n.nodeType == 1 && (l = n.lastChild)) {
+ if (!this.isEmpty(l)) {
+ return l;
+ }
+ while (l.previousSibling && (l = l.previousSibling)) {
+ if (!this.isEmpty(l)) {
+ return l;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Возвращает TRUE, если нода "inline"
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return bool
+ **/
+ this.isInline = function(n) {
+ if (n.nodeType == 3) {
+ return true;
+ } else if (n.nodeType == 1) {
+ n = $(n);
+ var d = n.css('display');
+ var f = n.css('float');
+ return d == 'inline' || d == 'inline-block' || f == 'left' || f == 'right';
+ }
+ return true;
+ }
+
+
+ /********************************************************/
+ /*                  ÐŸÐ¾Ð¸ÑÐº элементов                     */
+ /********************************************************/
+
+ this.is = function(n, f) {
+ if (n && n.nodeName) {
+ if (typeof(f) == 'string') {
+ f = this.regExp[f]||/.?/;
+ }
+ if (f instanceof RegExp && n.nodeName) {
+ return f.test(n.nodeName);
+ } else if (typeof(f) == 'function') {
+ return f(n);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Вовращает элемент(ы) отвечающие условиям поиска
+ *
+ * @param  DOMElement||Array  n       нода
+ * @param  RegExp||String     filter  Ñ„ильтр условия поиска (RegExp или имя ключа this.regExp или *)
+ * @return DOMElement||Array
+ **/
+ this.filter = function(n, filter) {
+ var ret = [], i;
+ if (!n.push) {
+ return this.is(n, filter) ? n : null;
+ }
+ for (i=0; i < n.length; i++) {
+ if (this.is(n[i], filter)) {
+ ret.push(n[i]);
+ }
+ };
+ return ret;
+ }
+
+
+ /**
+ * Вовращает массив родительских элементов, отвечающих условиям поиска
+ *
+ * @param  DOMElement      n  Ð½Ð¾Ð´Ð°, родителей, которой ищем
+ * @param  RegExp||String  filter   фильтр условия поиска (RegExp или имя ключа this.regExp или *)
+ * @return Array
+ **/
+ this.parents = function(n, filter) {
+ var ret = [];
+
+ while (n && (n = n.parentNode) && n.nodeName != 'BODY' && n.nodeName != 'HTML') {
+ if (this.is(n, filter)) {
+ ret.push(n);
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Вовращает ближайший родительский эл-т, отвечающий условиям поиска
+ *
+ * @param  DOMElement     n  Ð½Ð¾Ð´Ð°, родителя, которой ищем
+ * @param  RegExp||String f   фильтр условия поиска (RegExp или имя ключа this.regExp или *)
+ * @return DOMElement
+ **/
+ this.parent = function(n, f) {
+ return this.parents(n, f)[0] || null;
+ }
+
+ /**
+ * Вовращает или саму ноду или ее ближайшего родителя, если выполняются условия sf для самой ноды или pf для родителя
+ *
+ * @param  DOMElement     n  Ð½Ð¾Ð´Ð°, родителя, которой ищем
+ * @param  RegExp||String sf   фильтр условия для самой ноды
+ * @param  RegExp||String  pf   фильтр условия для родителя
+ * @return DOMElement
+ **/
+ this.selfOrParent = function(n, sf, pf) {
+ return this.is(n, sf) ? n : this.parent(n, pf||sf);
+ }
+
+ /**
+ * Вовращает родительскую ноду - ссылку
+ *
+ * @param  Element n  Ð½Ð¾Ð´Ð°
+ * @return Element
+ **/
+ this.selfOrParentLink = function(n) {
+ n = this.selfOrParent(n, /^A$/);
+ return n && n.href ? n : null;
+ }
+
+ /**
+ * Вовращает TRUE, если нода -  anchor
+ *
+ * @param  Element n  Ð½Ð¾Ð´Ð°
+ * @return bool
+ **/
+ this.selfOrParentAnchor = function(n) {
+ n = this.selfOrParent(n, /^A$/);
+ return n && !n.href && n.name ? n : null;
+ }
+
+ /**
+ * Вовращает массив дочерних ссылок
+ *
+ * @param  DOMElement n  Ð½Ð¾Ð´Ð°
+ * @return Array
+ **/
+ this.childLinks = function(n) {
+ var res = [];
+ $('a[href]', n).each(function() { res.push(this); });
+ return res;
+ }
+
+ this.selectionHas = function(f) {
+ var n = this.rte.selection.cloneContents(), i;
+ if (n && n.childNodes && n.childNodes.length) {
+ for (i=0; i < n.childNodes.length; i++) {
+ if (typeof(f) == 'function') {
+ if (f(n.childNodes[i])) {
+ return true;
+ }
+ } else if (n instanceof RegExp) {
+ if (f.test(n.childNodes[i].nodeName)) {
+ return true;
+ }
+ }
+ };
+ }
+
+ return false;
+ }
+ /********************************************************/
+ /*                    Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ DOM                     */
+ /********************************************************/
+
+ /**
+ * Оборачивает одну ноду другой
+ *
+ * @param  DOMElement n  Ð¾Ð±Ð¾Ñ€Ð°Ñ‡Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ нода
+ * @param  DOMElement w  Ð½Ð¾Ð´Ð° обертка или имя тега
+ * @return DOMElement
+ **/
+ this.wrap = function(n, w) {
+ n = $.isArray(n) ? n : [n];
+ w = w.nodeName ? w : this.create(w);
+
+ if (n[0] && n[0].nodeType && n[0].parentNode) {
+ w = n[0].parentNode.insertBefore(w, n[0]);
+ $(n).each(function() {
+ if (this!=w) {
+ w.appendChild(this);
+ }
+ });
+ }
+
+ return w;
+ }
+
+ /**
+ * Replace node with its contents
+ *
+ * @param  DOMElement n node
+ * @return void
+ **/
+ this.unwrap = function(n) {
+ while (n.firstChild) {
+ n.parentNode.insertBefore(n.firstChild, n);
+ }
+ n.parentNode.removeChild(n);
+ }
+
+ /**
+ * Оборачивает все содержимое ноды
+ *
+ * @param  DOMElement n  Ð¾Ð±Ð¾Ñ€Ð°Ñ‡Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ нода
+ * @param  DOMElement w  Ð½Ð¾Ð´Ð° обертка или имя тега
+ * @return DOMElement
+ **/
+ this.wrapContents = function(n, w) {
+ w = w.nodeName ? w : this.create(w);
+ for (var i=0; i < n.childNodes.length; i++) {
+ w.appendChild(n.childNodes[i]);
+ };
+ n.appendChild(w);
+ return w;
+ }
+
+ this.cleanNode = function(n) {
+
+ if (n.nodeType != 1) {
+ return;
+ }
+ if (/^(P|LI)$/.test(n.nodeName) && (l = this.findLastNotEmpty(n)) && l.nodeName == 'BR') {
+ $(l).remove();
+ }
+ $n = $(n);
+ $n.children().each(function() {
+ this.cleanNode(this);
+ });
+ if (n.nodeName != 'BODY' && !/^(TABLE|TR|TD)$/.test(n) && this.isEmpty(n)) {
+ return $n.remove();
+ }
+ if ($n.attr('style') === '') {
+ $n.removeAttr('style');
+ }
+ if (this.rte.browser.safari && $n.hasClass('Apple-span')) {
+ $n.removeClass('Apple-span');
+ }
+ if (n.nodeName == 'SPAN' && !$n.attr('style') && !$n.attr('class') && !$n.attr('id')) {
+ $n.replaceWith($n.html());
+ }
+ }
+
+ this.cleanChildNodes = function(n) {
+ var cmd = this.cleanNode;
+ $(n).children().each(function() { cmd(this); });
+ }
+
+ /********************************************************/
+ /*                       Таблицы                        */
+ /********************************************************/
+
+ this.tableMatrix = function(n) {
+ var mx = [];
+ if (n && n.nodeName == 'TABLE') {
+ var max = 0;
+ function _pos(r) {
+ for (var i=0; i<=max; i++) {
+ if (!mx[r][i]) {
+ return i;
+ }
+ };
+ }
+
+ $(n).find('tr').each(function(r) {
+ if (!$.isArray(mx[r])) {
+ mx[r] = [];
+ }
+
+ $(this).children('td,th').each(function() {
+ var w = parseInt($(this).attr('colspan')||1);
+ var h = parseInt($(this).attr('rowspan')||1);
+ var i = _pos(r);
+ for (var y=0; y<h; y++) {
+ for (var x=0; x<w; x++) {
+ var _y = r+y;
+ if (!$.isArray(mx[_y])) {
+ mx[_y] = [];
+ }
+ var d = x==0 && y==0 ? this : (y==0 ? x : "-");
+ mx[_y][i+x] = d;
+ }
+ };
+ max= Math.max(max, mx[r].length);
+ });
+ });
+ }
+ return mx;
+ }
+
+ this.indexesOfCell = function(n, tbm) {
+ for (var rnum=0; rnum < tbm.length; rnum++) {
+ for (var cnum=0; cnum < tbm[rnum].length; cnum++) {
+ if (tbm[rnum][cnum] == n) {
+ return [rnum, cnum];
+ }
+
+ };
+ };
+ }
+
+ this.fixTable = function(n) {
+ if (n && n.nodeName == 'TABLE') {
+ var tb = $(n);
+ //tb.find('tr:empty').remove();
+ var mx = this.tableMatrix(n);
+ var x  = 0;
+ $.each(mx, function() {
+ x = Math.max(x, this.length);
+ });
+ if (x==0) {
+ return tb.remove();
+ }
+ // for (var i=0; i<mx.length; i++) {
+ // this.rte.log(mx[i]);
+ // }
+
+ for (var r=0; r<mx.length; r++) {
+ var l = mx[r].length;
+ //this.rte.log(r+' : '+l)
+
+ if (l==0) {
+ //this.rte.log('remove: '+tb.find('tr').eq(r))
+ tb.find('tr').eq(r).remove();
+// tb.find('tr').eq(r).append('<td>remove</td>')
+ } else if (l<x) {
+ var cnt = x-l;
+ var row = tb.find('tr').eq(r);
+ for (i=0; i<cnt; i++) {
+ row.append('<td>&nbsp;</td>');
+ }
+ }
+ }
+
+ }
+ }
+
+ this.tableColumn = function(n, ext, fix) {
+ n      = this.selfOrParent(n, /^TD|TH$/);
+ var tb = this.selfOrParent(n, /^TABLE$/);
+ ret    = [];
+ info   = {offset : [], delta : []};
+ if (n && tb) {
+ fix && this.fixTable(tb);
+ var mx = this.tableMatrix(tb);
+ var _s = false;
+ var x;
+ for (var r=0; r<mx.length; r++) {
+ for (var _x=0; _x<mx[r].length; _x++) {
+ if (mx[r][_x] == n) {
+ x = _x;
+ _s = true;
+ break;
+ }
+ }
+ if (_s) {
+ break;
+ }
+ }
+
+ // this.rte.log('matrix');
+ // for (var i=0; i<mx.length; i++) {
+ // this.rte.log(mx[i]);
+ // }
+ if (x>=0) {
+ for(var r=0; r<mx.length; r++) {
+ var tmp = mx[r][x]||null;
+ if (tmp) {
+ if (tmp.nodeName) {
+ ret.push(tmp);
+ if (ext) {
+ info.delta.push(0);
+ info.offset.push(x);
+ }
+ } else {
+ var d = parseInt(tmp);
+ if (!isNaN(d) && mx[r][x-d] && mx[r][x-d].nodeName) {
+ ret.push(mx[r][x-d]);
+ if (ext) {
+ info.delta.push(d);
+ info.offset.push(x);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return !ext ? ret : {column : ret, info : info};
+ }
+}
+
+})(jQuery);
+(function($) {
+ /**
+ * @class Filter - clean editor content
+ * @param elRTE editor instance
+ * @author Dmitry (dio) Levashov, [hidden email]
+ */
+ elRTE.prototype.filter = function(rte) {
+ var self = this,
+ n = $('<span/>').addClass('elrtetesturl').appendTo(document.body)[0];
+ // media replacement image base url
+ this.url = (typeof(n.currentStyle )!= "undefined" ? n.currentStyle['backgroundImage'] : document.defaultView.getComputedStyle(n, null)['backgroundImage']).replace(/^url\((['"]?)([\s\S]+\/)[\s\S]+\1\)$/i, "$2");
+ $(n).remove();
+
+ this.rte = rte;
+ // flag - return xhtml tags?
+ this.xhtml = /xhtml/i.test(rte.options.doctype);
+ // boolean attributes
+ this.boolAttrs = rte.utils.makeObject('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'.split(','));
+ // tag regexp
+ this.tagRegExp = /<(\/?)([\w:]+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*\/?>/g;
+ // opened tag regexp
+ this.openTagRegExp = /<([\w:]+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*\/?>/g;
+ // attributes regexp
+ this.attrRegExp = /(\w+)(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^\s]+))?/g;
+ // script tag regexp
+ this.scriptRegExp = /<script([^>]*)>([\s\S]*?)<\/script>/gi;
+ // style tag regexp
+ this.styleRegExp = /(<style([^>]*)>[\s\S]*?<\/style>)/gi;
+ // link tag regexp
+ this.linkRegExp = /(<link([^>]+)>)/gi;
+ // cdata regexp
+ this.cdataRegExp = /<!\[CDATA\[([\s\S]+)\]\]>/g;
+ // object tag regexp
+ this.objRegExp = /<object([^>]*)>([\s\S]*?)<\/object>/gi;
+ // embed tag regexp
+ this.embRegExp = /<(embed)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*>/gi;
+ // param tag regexp
+ this.paramRegExp = /<(param)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*>/gi;
+ this.vimeoRegExp = /<(iframe)\s+([^>]*src\s*=\s*"http:\/\/[^"]+vimeo\.com\/\w+[^>]*)>([\s\S]*?)<\/iframe>/gi;
+ // yandex maps regexp
+ this.yMapsRegExp = /<div\s+([^>]*id\s*=\s*('|")?YMapsID[^>]*)>/gi;
+ // google maps regexp
+ this.gMapsRegExp = /<iframe\s+([^>]*src\s*=\s*"http:\/\/maps\.google\.\w+[^>]*)>([\s\S]*?)<\/iframe>/gi;
+ // video hostings url regexp
+ this.videoHostRegExp = /^(http:\/\/[\w\.]*)?(youtube|vimeo|rutube).*/i;
+ // elrte services classes regexp
+ this.serviceClassRegExp = /<(\w+)([^>]*class\s*=\s*"[^>]*elrte-[^>]*)>\s*(<\/\1>)?/gi;
+ this.pagebreakRegExp = /<(\w+)([^>]*style\s*=\s*"[^>]*page-break[^>]*)>\s*(<\/\1>)?/gi;
+
+ this.pbRegExp = new RegExp('<!-- pagebreak -->', 'gi');
+ // allowed tags
+ this.allowTags = rte.options.allowTags.length ? rte.utils.makeObject(rte.options.allowTags) : null;
+ // denied tags
+ this.denyTags = rte.options.denyTags.length ? rte.utils.makeObject(rte.options.denyTags) : null;
+ // deny attributes
+ this.denyAttr = rte.options.denyAttr ? rte.utils.makeObject(rte.options.denyAttr) : null;
+ // deny attributes for pasted html
+ this.pasteDenyAttr = rte.options.pasteDenyAttr ? rte.utils.makeObject(rte.options.pasteDenyAttr) : null;
+ // font sizes to convert size attr into css property
+ this.fontSize = ['medium', 'xx-small', 'small', 'medium','large','x-large','xx-large' ];
+ // font families regexp to detect family by font name
+ this.fontFamily = {
+ 'sans-serif' : /^(arial|tahoma|verdana)$/i,
+ 'serif'      : /^(times|times new roman)$/i,
+ 'monospace'  : /^courier$/i
+ }
+ // scripts storage
+ this.scripts = {};
+ // cached chains of rules
+ this._chains = {};
+
+ // cache chains
+ $.each(this.chains, function(n) {
+ self._chains[n] = [];
+ $.each(this, function(i, r) {
+ typeof(self.rules[r]) == 'function' && self._chains[n].push(self.rules[r]);
+ });
+ });
+
+ /**
+ * filtering through required chain
+ *
+ * @param  String  chain name
+ * @param  String  html-code
+ * @return String
+ **/
+ this.proccess = function(chain, html) {
+ // remove whitespace at the begin and end
+ html = $.trim(html).replace(/^\s*(&nbsp;)+/gi, '').replace(/(&nbsp;|<br[^>]*>)+\s*$/gi, '');
+ // pass html through chain
+ $.each(this._chains[chain]||[], function() {
+ html = this.call(self, html);
+ });
+ return html.replace(/\t/g, '  ').replace(/\r/g, '').replace(/\s*\n\s*\n+/g, "\n")+'  ';
+ }
+
+ /**
+ * wrapper for "wysiwyg" chain filtering
+ *
+ * @param  String  
+ * @return String
+ **/
+ this.wysiwyg = function(html) {
+ return this.proccess('wysiwyg', html);
+ }
+
+ /**
+ * wrapper for "source" chain filtering
+ *
+ * @param  String  
+ * @return String
+ **/
+ this.source = function(html) {
+ return this.proccess('source', html);
+ }
+
+ /**
+ * wrapper for "source2source" chain filtering
+ *
+ * @param  String  
+ * @return String
+ **/
+ this.source2source = function(html) {
+ return this.proccess('source2source', html);
+ }
+
+ /**
+ * wrapper for "wysiwyg2wysiwyg" chain filtering
+ *
+ * @param  String  
+ * @return String
+ **/
+ this.wysiwyg2wysiwyg = function(html) {
+ return this.proccess('wysiwyg2wysiwyg', html);
+ }
+
+ /**
+ * Parse attributes from string into object
+ *
+ * @param  String  string of attributes  
+ * @return Object
+ **/
+ this.parseAttrs = function(s) {
+ var a = {},
+ b = this.boolAttrs,
+ m = s.match(this.attrRegExp),
+ t, n, v;
+
+ m && $.each(m, function(i, s) {
+ t = s.split('=');
+ n = $.trim(t[0]).toLowerCase();
+
+ if (t.length>2) {
+ t.shift();
+ v = t.join('=');
+ } else {
+ v = b[n] ||t[1]||'';
+ }
+ a[n] = $.trim(v).replace(/^('|")(.*)(\1)$/, "$2");
+ });
+
+ a.style = this.rte.utils.parseStyle(a.style);
+ a['class'] = this.rte.utils.parseClass(a['class']||'')
+ return a;
+ }
+
+ /**
+ * Restore attributes string from hash
+ *
+ * @param  Object  attributes hash
+ * @return String
+ **/
+ this.serializeAttrs = function(a, c) {
+ var s = [], self = this;
+
+ $.each(a, function(n, v) {
+ if (n=='style') {
+ v = self.rte.utils.serializeStyle(v, c);
+ } else if (n=='class') {
+ v = self.rte.utils.serializeClass(v);
+ }
+ v && s.push(n+'="'+v+'"');
+ });
+ return s.join(' ');
+ }
+
+ /**
+ * Remove/replace denied attributes/style properties
+ *
+ * @param  Object  attributes hash
+ * @param  String  tag name to wich attrs belongs
+ * @return Object
+ **/
+ this.cleanAttrs = function(a, t) {
+ var self = this, ra = this.replaceAttrs;
+
+ // remove safari and mso classes
+ $.each(a['class'], function(n) {
+ /^(Apple-style-span|mso\w+)$/i.test(n) && delete a['class'][n];
+ });
+
+ function value(v) {
+ return v+(/\d$/.test(v) ? 'px' : '');
+ }
+
+ $.each(a, function(n, v) {
+ // replace required attrs with css
+ ra[n] && ra[n].call(self, a, t);
+ // remove/fix mso styles
+ if (n == 'style') {
+ $.each(v, function(sn, sv) {
+ switch (sn) {
+ case "mso-padding-alt":
+ case "mso-padding-top-alt":
+ case "mso-padding-right-alt":
+ case "mso-padding-bottom-alt":
+ case "mso-padding-left-alt":
+ case "mso-margin-alt":
+ case "mso-margin-top-alt":
+ case "mso-margin-right-alt":
+ case "mso-margin-bottom-alt":
+ case "mso-margin-left-alt":
+ case "mso-table-layout-alt":
+ case "mso-height":
+ case "mso-width":
+ case "mso-vertical-align-alt":
+ a.style[sn.replace(/^mso-|-alt$/g, '')] = value(sv);
+ delete a.style[sn];
+ break;
+
+ case "horiz-align":
+ a.style['text-align'] = sv;
+ delete a.style[sn];
+ break;
+
+ case "vert-align":
+ a.style['vertical-align'] = sv;
+ delete a.style[sn];
+ break;
+
+ case "font-color":
+ case "mso-foreground":
+ a.style.color = sv;
+ delete a.style[sn];
+ break;
+
+ case "mso-background":
+ case "mso-highlight":
+ a.style.background = sv;
+ delete a.style[sn];
+ break;
+
+ case "mso-default-height":
+ a.style['min-height'] = value(sv);
+ delete a.style[sn];
+ break;
+
+ case "mso-default-width":
+ a.style['min-width'] = value(sv);
+ delete a.style[sn];
+ break;
+
+ case "mso-padding-between-alt":
+ a.style['border-collapse'] = 'separate';
+ a.style['border-spacing'] = value(sv);
+ delete a.style[sn];
+ break;
+
+ case "text-line-through":
+ if (sv.match(/(single|double)/i)) {
+ a.style['text-decoration'] = 'line-through';
+ }
+ delete a.style[sn];
+ break;
+
+ case "mso-zero-height":
+ if (sv == 'yes') {
+ a.style.display = 'none';
+ }
+ delete a.style[sn];
+ break;
+
+ case 'font-weight':
+ if (sv == 700) {
+ a.style['font-weight'] = 'bold';
+ }
+ break;
+
+ default:
+ if (sn.match(/^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?!align|decor|indent|trans)|top-bar|version|vnd|word-break)/)) {
+ delete a.style[sn]
+ }
+ }
+ });
+ }
+ });
+ return a;
+ }
+
+ }
+
+ // rules to replace tags
+ elRTE.prototype.filter.prototype.replaceTags = {
+ b         : { tag : 'strong' },
+ big       : { tag : 'span', style : {'font-size' : 'large'} },
+ center    : { tag : 'div',  style : {'text-align' : 'center'} },
+ i         : { tag : 'em' },
+ font      : { tag : 'span' },
+ nobr      : { tag : 'span', style : {'white-space' : 'nowrap'} },
+ menu      : { tag : 'ul' },
+ plaintext : { tag : 'pre' },
+ s         : { tag : 'strike' },
+ small     : { tag : 'span', style : {'font-size' : 'small'}},
+ u         : { tag : 'span', style : {'text-decoration' : 'underline'} },
+ xmp       : { tag : 'pre' }
+ }
+
+ // rules to replace attributes
+ elRTE.prototype.filter.prototype.replaceAttrs = {
+ align : function(a, n) {
+ switch (n) {
+ case 'img':
+ a.style[a.align.match(/(left|right)/) ? 'float' : 'vertical-align'] = a.align;
+ break;
+
+ case 'table':
+ if (a.align == 'center') {
+ a.style['margin-left'] = a.style['margin-right'] = 'auto';
+ } else {
+ a.style['float'] = a.align;
+ }
+ break;
+
+ default:
+ a.style['text-align'] = a.align;
+ }
+ delete a.align;
+ },
+ border : function(a) {
+ !a.style['border-width'] && (a.style['border-width'] = (parseInt(a.border)||1)+'px');
+ !a.style['border-style'] && (a.style['border-style'] = 'solid');
+ delete a.border;
+ },
+ bordercolor : function(a) {
+ !a.style['border-color'] && (a.style['border-color'] = a.bordercolor);
+ delete a.bordercolor;
+ },
+ background : function(a) {
+ !a.style['background-image'] && (a.style['background-image'] = 'url('+a.background+')');
+ delete a.background;
+ },
+ bgcolor : function(a) {
+ !a.style['background-color'] && (a.style['background-color'] = a.bgcolor);
+ delete a.bgcolor;
+ },
+ clear : function(a) {
+ a.style.clear = a.clear == 'all' ? 'both' : a.clear;
+ delete a.clear;
+ },
+ color : function(a) {
+ !a.style.color && (a.style.color = a.color);
+ delete a.color;
+ },
+ face : function(a) {
+ var f = a.face.toLowerCase();
+ $.each(this.fontFamily, function(n, r) {
+ if (f.match(r)) {
+ a.style['font-family'] = f+','+n;
+ }
+ });
+ delete a.face;
+ },
+ hspace : function(a, n) {
+ if (n == 'img') {
+ var v = parseInt(a.hspace)||0;
+ !a.style['margin-left'] && (a.style['margin-left'] = v+'px');
+ !a.style['margin-right'] && (a.style['margin-right'] = v+'px')
+ delete a.hspace;
+ }
+ },
+ size : function(a, n) {
+ if (n != 'input') {
+ a.style['font-size'] = this.fontSize[parseInt(a.size)||0]||'medium';
+ delete a.size;
+ }
+ },
+ valign : function(a) {
+ if (!a.style['vertical-align']) {
+ a.style['vertical-align'] = a.valign;
+ }
+ delete a.valign;
+ },
+ vspace : function(a, n) {
+ if (n == 'img') {
+ var v = parseInt(a.vspace)||0;
+ !a.style['margin-top'] && (a.style['margin-top'] = v+'px');
+ !a.style['margin-bottom'] && (a.style['margin-bottom'] = v+'px')
+ delete a.hspace;
+ }
+ }
+ }
+
+ // rules collection
+ elRTE.prototype.filter.prototype.rules = {
+ /**
+ * If this.rte.options.allowTags is set - remove all except this ones
+ *
+ * @param String  html code
+ * @return String
+ **/
+ allowedTags : function(html) {
+ var a = this.allowTags;
+ return a ? html.replace(this.tagRegExp, function(t, c, n) { return a[n.toLowerCase()] ? t : ''; }) : html;
+ },
+ /**
+ * If this.rte.options.denyTags is set - remove all deny tags
+ *
+ * @param String  html code
+ * @return String
+ **/
+ deniedTags : function(html) {
+ var d = this.denyTags;
+ return d ? html.replace(this.tagRegExp, function(t, c, n) { return d[n.toLowerCase()] ? '' : t }) : html;
+ },
+
+ /**
+ * Replace not allowed tags/attributes
+ *
+ * @param String  html code
+ * @return String
+ **/
+ clean : function(html) {
+ var self = this,
+ rt   = this.replaceTags,
+ ra   = this.replaceAttrs,
+ da   = this.denyAttr,
+ n;
+
+ return html.replace(/<!DOCTYPE([\s\S]*)>/gi, '')
+ .replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>")
+ .replace(/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s&nbsp;]*)<\/span>/gi, "$1")
+ .replace(/(<p[^>]*>\s*<\/p>|<p[^>]*\/>)/gi, '<br>')
+ .replace(this.tagRegExp, function(t, c, n, a) {
+ n = n.toLowerCase();
+
+ if (c) {
+ return '</'+(rt[n] ? rt[n].tag : n)+'>';
+ }
+
+ // create attributes hash and clean it
+ a = self.cleanAttrs(self.parseAttrs(a||''), n);
+
+ if (rt[n]) {
+ rt[n].style && $.extend(a.style, rt[n].style);
+ n = rt[n].tag;
+ }
+
+ da && $.each(a, function(na) {
+ if (da[na]) {
+ delete a[na];
+ }
+ });
+ a = self.serializeAttrs(a);
+ return '<'+n+(a?' ':'')+a+'>';
+ });
+ },
+
+ /**
+ * Clean pasted html
+ *
+ * @param String  html code
+ * @return String
+ **/
+ cleanPaste : function(html) {
+ var self = this, d = this.pasteDenyAttr;
+
+ html = html
+ .replace(this.scriptRegExp, '')
+ .replace(this.styleRegExp, '')
+ .replace(this.linkRegExp, '')
+ .replace(this.cdataRegExp, '')
+ .replace(/\<\!--[\s\S]*?--\>/g, '');
+
+ if (this.rte.options.pasteOnlyText) {
+ html = html.replace(this.tagRegExp, function(t, c, n) {
+ return /br/i.test(n) || (c && /h[1-6]|p|ol|ul|li|div|blockquote|tr/i) ? '<br>' : '';
+ }).replace(/(&nbsp;|<br[^>]*>)+\s*$/gi, '');
+ } else if (d) {
+ html = html.replace(this.openTagRegExp, function(t, n, a) {
+ a = self.parseAttrs(a);
+ $.each(a, function(an) {
+ if (d[an]) {
+ delete a[an];
+ }
+ });
+ a = self.serializeAttrs(a, true);
+ return '<'+n+(a?' ':'')+a+'>';
+ });
+ }
+ return html;
+ },
+
+ /**
+ * Replace script/style/media etc with placeholders
+ *
+ * @param String  html code
+ * @return String
+ **/
+ replace : function(html) {
+ var self = this, r = this.rte.options.replace||[], n;
+
+ // custom replaces if set
+ if (r.length) {
+ $.each(r, function(i, f) {
+ if (typeof(f) == 'function') {
+ html = f.call(self, html);
+ }
+ });
+ }
+
+ /**
+ * Return media replacement - img html code
+ *
+ * @param Object  object to store in rel attr
+ * @param String  media mime-type
+ * @return String
+ **/
+ function img(o, t) {
+ var s = src(),
+ c = s && self.videoHostRegExp.test(s) ? s.replace(self.videoHostRegExp, "$2") : t.replace(/^\w+\/(.+)/, "$1"),
+ w = parseInt((o.obj ? o.obj.width || o.obj.style.width : 0)||(o.embed ? o.embed.width || o.embed.style.width : 0))||150,
+ h = parseInt((o.obj ? o.obj.height || o.obj.style.height : 0)||(o.embed ? o.embed.height || o.embed.style.height : 0))||100,
+ id = 'media'+Math.random().toString().substring(2),
+ style ='',
+ l;
+
+ // find media src
+ function src() {
+ if (o.embed && o.embed.src) {
+ return o.embed.src;
+ }
+ if (o.params && o.params.length) {
+ l = o.params.length;
+ while (l--) {
+ if (o.params[l].name == 'src' || o.params[l].name == 'movie') {
+ return o.params[l].value;
+ }
+ }
+ }
+ }
+ if (o.obj && o.obj.style && o.obj.style['float']) {
+ style = ' style="float:'+o.obj.style['float']+'"';
+ }
+ self.scripts[id] = o;
+ return '<img src="'+self.url+'pixel.gif" class="elrte-media elrte-media-'+c+' elrte-protected" title="'+(s ? self.rte.utils.encode(s) : '')+'" rel="'+id+'" width="'+w+'" height="'+h+'"'+style+'>';
+ }
+
+ html = html
+ .replace(this.styleRegExp, "<!-- ELRTE_COMMENT$1 -->")
+ .replace(this.linkRegExp,  "<!-- ELRTE_COMMENT$1-->")
+ .replace(this.cdataRegExp, "<!--[CDATA[$1]]-->")
+ .replace(this.scriptRegExp, function(t, a, s) {
+ var id;
+ if (self.denyTags.script) {
+ return '';
+ }
+ id = 'script'+Math.random().toString().substring(2);
+ a = self.parseAttrs(a);
+ !a.type && (a.type = 'text/javascript');
+ self.scripts[id] = '<script '+self.serializeAttrs(a)+">"+s+"</script>";
+ return '<!-- ELRTE_SCRIPT:'+(id)+' -->';
+ })
+ .replace(this.yMapsRegExp, function(t, a) {
+ a = self.parseAttrs(a);
+ a['class']['elrte-yandex-maps'] = 'elrte-yandex-maps';
+ a['class']['elrte-protected'] = 'elrte-protected';
+ return '<div '+self.serializeAttrs(a)+'>';
+ })
+ .replace(this.gMapsRegExp, function(t, a) {
+ var id = 'gmaps'+Math.random().toString().substring(2), w, h;
+ a = self.parseAttrs(a);
+ w = parseInt(a.width||a.style.width||100);
+ h = parseInt(a.height||a.style.height||100);
+ self.scripts[id] = t;
+ return '<img src="'+self.url+'pixel.gif" class="elrte-google-maps elrte-protected" id="'+id+'" style="width:'+w+'px;height:'+h+'px">';
+ })
+ .replace(this.objRegExp, function(t, a, c) {
+ var m = c.match(self.embRegExp),
+ o = { obj : self.parseAttrs(a), embed : m && m.length ? self.parseAttrs(m[0].substring(7)) : null, params : [] },
+ i = self.rte.utils.mediaInfo(o.embed ? o.embed.type||'' : '', o.obj.classid||'');
+
+ if (i) {
+ if ((m = c.match(self.paramRegExp))) {
+ $.each(m, function(i, p) {
+ o.params.push(self.parseAttrs(p.substring(6)));
+ });
+ }
+ !o.obj.classid  && (o.obj.classid  = i.classid[0]);
+ !o.obj.codebase && (o.obj.codebase = i.codebase);
+ o.embed && !o.embed.type && (o.embed.type = i.type);
+ // ie bug with empty attrs
+ o.obj.width == '1' && delete o.obj.width;
+ o.obj.height == '1' && delete o.obj.height;
+ if (o.embed) {
+ o.embed.width == '1' && delete o.embed.width;
+ o.embed.height == '1' && delete o.embed.height;
+ }
+ return img(o, i.type);
+ }
+ return t;
+ })
+ .replace(this.embRegExp, function(t, n, a) {
+ var a = self.parseAttrs(a),
+ i = self.rte.utils.mediaInfo(a.type||'');
+ // ie bug with empty attrs
+ a.width == '1' && delete a.width;
+ a.height == '1' && delete a.height;
+ return i ? img({ embed : a }, i.type) : t;
+ })
+ .replace(this.vimeoRegExp, function(t, n, a) {
+ a = self.parseAttrs(a);
+ delete a.frameborder;
+ a.width == '1' && delete a.width;
+ a.height == '1' && delete a.height;
+ a.type = 'application/x-shockwave-flash';
+ return img({ embed : a }, 'application/x-shockwave-flash');
+ })
+ .replace(/<\/(embed|param)>/gi, '')
+ .replace(this.pbRegExp, function() {
+ return '<img src="'+self.url+'pixel.gif" class="elrte-protected elrte-pagebreak">';
+ });
+
+
+ n = $('<div>'+html+'</div>');
+ // remove empty spans and merge nested spans
+ n.find('span:not([id]):not([class])').each(function() {
+ var t = $(this);
+
+ if (!t.attr('style')) {
+ t.children().length ? self.rte.dom.unwrap(this) : t.remove();
+ }
+ }).end().find('span span:only-child').each(function() {
+ var t   = $(this),
+ p   = t.parent().eq(0),
+ tid = t.attr('id'),
+ pid = p.attr('id'), id, s, c;
+
+ if (self.rte.dom.is(this, 'onlyChild') && (!tid || !pid)) {
+ c = $.trim(p.attr('class')+' '+t.attr('class'))
+ c && p.attr('class', c);
+ s = self.rte.utils.serializeStyle($.extend(self.rte.utils.parseStyle($(this).attr('style')||''), self.rte.utils.parseStyle($(p).attr('style')||'')));
+ s && p.attr('style', s);
+ id = tid||pid;
+ id && p.attr('id', id);
+ this.firstChild ? $(this.firstChild).unwrap() : t.remove();
+ }
+ });
+
+
+
+ if (!this.rte.options.allowTextNodes) {
+ // wrap inline nodes with p
+ var dom = this.rte.dom,
+ nodes = [],
+ w = [];
+
+ if ($.browser.msie) {
+ for (var i = 0; i<n[0].childNodes.length; i++) {

[... 5792 lines stripped ...]