/* Redactor v9.1.4 Updated: Sep 10, 2013 http://imperavi.com/redactor/ Copyright (c) 2009-2013, Imperavi LLC. License: http://imperavi.com/redactor/license/ Usage: $('#content').redactor(); */ (function($) { var uuid = 0; var rtePaste = false; "use strict"; var Range = function(range) { this[0] = range.startOffset; this[1] = range.endOffset; this.range = range; return this; }; Range.prototype.equals = function() { return this[0] === this[1]; }; // Plugin $.fn.redactor = function(options) { var val = []; var args = Array.prototype.slice.call(arguments, 1); if (typeof options === 'string') { this.each(function() { var instance = $.data(this, 'redactor'); if (typeof instance !== 'undefined' && $.isFunction(instance[options])) { var methodVal = instance[options].apply(instance, args); if (methodVal !== undefined && methodVal !== instance) val.push(methodVal); } else return $.error('No such method "' + options + '" for Redactor'); }); } else { this.each(function() { if (!$.data(this, 'redactor')) $.data(this, 'redactor', Redactor(this, options)); }); } if (val.length === 0) return this; else if (val.length === 1) return val[0]; else return val; }; // Initialization function Redactor(el, options) { return new Redactor.prototype.init(el, options); } $.Redactor = Redactor; $.Redactor.VERSION = '9.1.4'; $.Redactor.opts = { // settings rangy: false, iframe: false, fullpage: false, css: false, // url lang: 'en', direction: 'ltr', // ltr or rtl placeholder: false, wym: false, mobile: true, cleanup: true, tidyHtml: true, pastePlainText: false, removeEmptyTags: true, templateVars: false, visual: true, focus: false, tabindex: false, autoresize: true, minHeight: false, shortcuts: true, autosave: false, // false or url autosaveInterval: 60, // seconds plugins: false, // array linkAnchor: false, linkEmail: false, linkProtocol: 'http://', linkNofollow: false, imageFloatMargin: '10px', imageGetJson: false, // url (ex. /folder/images.json ) or false imageUpload: false, // url fileUpload: false, // url clipboardUpload: true, // or false clipboardUploadUrl: false, // url dragUpload: true, // false dnbImageTypes: ['image/png', 'image/jpeg', 'image/gif'], // or false s3: false, uploadFields: false, observeImages: true, observeLinks: true, modalOverlay: true, tabSpaces: false, // true or number of spaces tabFocus: true, air: false, airButtons: ['formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent'], toolbar: true, toolbarFixed: false, toolbarFixedTarget: document, toolbarFixedTopOffset: 0, // pixels toolbarFixedBox: false, toolbarExternal: false, // ID selector buttonSource: true, buttonSeparator: '
', buttonsCustom: {}, buttonsAdd: [], buttons: ['html', '|', 'formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 'image', 'video', 'file', 'table', 'link', '|', 'alignment', '|', 'horizontalrule'], // 'underline', 'alignleft', 'aligncenter', 'alignright', 'justify' activeButtons: ['deleted', 'italic', 'bold', 'underline', 'unorderedlist', 'orderedlist', 'alignleft', 'aligncenter', 'alignright', 'justify', 'table'], activeButtonsStates: { b: 'bold', strong: 'bold', i: 'italic', em: 'italic', del: 'deleted', strike: 'deleted', ul: 'unorderedlist', ol: 'orderedlist', u: 'underline', tr: 'table', td: 'table', table: 'table' }, activeButtonsAdd: false, // object, ex.: { tag: 'buttonName' } formattingTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], linebreaks: false, paragraphy: true, convertDivs: true, convertLinks: true, convertImageLinks: false, convertVideoLinks: false, formattingPre: false, phpTags: false, allowedTags: false, deniedTags: ['html', 'head', 'link', 'body', 'meta', 'script', 'style', 'applet'], boldTag: 'strong', italicTag: 'em', // private indentValue: 20, buffer: [], rebuffer: [], textareamode: false, emptyHtml: '
', invisibleSpace: '', rBlockTest: /^(P|H[1-6]|LI|ADDRESS|SECTION|HEADER|FOOTER|ASIDE|ARTICLE)$/i, alignmentTags: ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DD', 'DL', 'DT', 'DIV', 'TD', 'BLOCKQUOTE', 'OUTPUT', 'FIGCAPTION', 'ADDRESS', 'SECTION', 'HEADER', 'FOOTER', 'ASIDE', 'ARTICLE'], ownLine: ['area', 'body', 'head', 'hr', 'i?frame', 'link', 'meta', 'noscript', 'style', 'script', 'table', 'tbody', 'thead', 'tfoot'], contOwnLine: ['li', 'dt', 'dt', 'h[1-6]', 'option', 'script'], newLevel: ['blockquote', 'div', 'dl', 'fieldset', 'form', 'frameset', 'map', 'ol', 'p', 'pre', 'select', 'td', 'th', 'tr', 'ul'], blockLevelElements: ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DD', 'DL', 'DT', 'DIV', 'LI', 'BLOCKQUOTE', 'OUTPUT', 'FIGCAPTION', 'PRE', 'ADDRESS', 'SECTION', 'HEADER', 'FOOTER', 'ASIDE', 'ARTICLE', 'TD'], // lang langs: { en: { html: 'HTML', video: 'Insert Video', image: 'Insert Image', table: 'Table', link: 'Link', link_insert: 'Insert link', link_edit: 'Edit link', unlink: 'Unlink', formatting: 'Formatting', paragraph: 'Normal text', quote: 'Quote', code: 'Code', header1: 'Header 1', header2: 'Header 2', header3: 'Header 3', header4: 'Header 4', header5: 'Header 5', bold: 'Bold', italic: 'Italic', fontcolor: 'Font Color', backcolor: 'Back Color', unorderedlist: 'Unordered List', orderedlist: 'Ordered List', outdent: 'Outdent', indent: 'Indent', cancel: 'Cancel', insert: 'Insert', save: 'Save', _delete: 'Delete', insert_table: 'Insert Table', insert_row_above: 'Add Row Above', insert_row_below: 'Add Row Below', insert_column_left: 'Add Column Left', insert_column_right: 'Add Column Right', delete_column: 'Delete Column', delete_row: 'Delete Row', delete_table: 'Delete Table', rows: 'Rows', columns: 'Columns', add_head: 'Add Head', delete_head: 'Delete Head', title: 'Title', image_position: 'Position', none: 'None', left: 'Left', right: 'Right', image_web_link: 'Image Web Link', text: 'Text', mailto: 'Email', web: 'URL', video_html_code: 'Video Embed Code', file: 'Insert File', upload: 'Upload', download: 'Download', choose: 'Choose', or_choose: 'Or choose', drop_file_here: 'Drop file here', align_left: 'Align text to the left', align_center: 'Center text', align_right: 'Align text to the right', align_justify: 'Justify text', horizontalrule: 'Insert Horizontal Rule', deleted: 'Deleted', anchor: 'Anchor', link_new_tab: 'Open link in new tab', underline: 'Underline', alignment: 'Alignment', filename: 'Name (optional)', edit: 'Edit' } } }; // Functionality Redactor.fn = $.Redactor.prototype = { keyCode: { BACKSPACE: 8, DELETE: 46, DOWN: 40, ENTER: 13, ESC: 27, TAB: 9, CTRL: 17, META: 91, LEFT: 37, LEFT_WIN: 91 }, // Initialization init: function(el, options) { this.$element = this.$source = $(el); this.uuid = uuid++; // clonning options var opts = $.extend(true, {}, $.Redactor.opts); // current settings this.opts = $.extend( {}, opts, this.$element.data(), options ); this.start = true; this.dropdowns = []; // get sizes this.sourceHeight = this.$source.css('height'); this.sourceWidth = this.$source.css('width'); // dependency of the editor modes if (this.opts.fullpage) this.opts.iframe = true; if (this.opts.linebreaks) this.opts.paragraphy = false; if (this.opts.paragraphy) this.opts.linebreaks = false; if (this.opts.toolbarFixedBox) this.opts.toolbarFixed = true; // the alias for iframe mode this.document = document; this.window = window; // selection saved this.savedSel = false; // clean setup this.cleanlineBefore = new RegExp('^<(/?' + this.opts.ownLine.join('|/?' ) + '|' + this.opts.contOwnLine.join('|') + ')[ >]'); this.cleanlineAfter = new RegExp('^<(br|/?' + this.opts.ownLine.join('|/?' ) + '|/' + this.opts.contOwnLine.join('|/') + ')[ >]'); this.cleannewLevel = new RegExp('^?(' + this.opts.newLevel.join('|' ) + ')[ >]'); // block level this.rTestBlock = new RegExp('^(' + this.opts.blockLevelElements.join('|' ) + ')$', 'i'); // setup formatting permissions if (this.opts.linebreaks === false) { if (this.opts.allowedTags !== false && $.inArray('p', this.opts.allowedTags) === '-1') this.opts.allowedTags.push('p'); if (this.opts.deniedTags !== false) { var pos = $.inArray('p', this.opts.deniedTags); if (pos !== '-1') this.opts.deniedTags.splice(pos, pos); } } // ie & opera if (this.browser('msie') || this.browser('opera')) { this.opts.buttons = this.removeFromArrayByValue(this.opts.buttons, 'horizontalrule'); } // load lang this.opts.curLang = this.opts.langs[this.opts.lang]; // Build this.buildStart(); }, initToolbar: function(lang) { return { html: { title: lang.html, func: 'toggle' }, formatting: { title: lang.formatting, func: 'show', dropdown: { p: { title: lang.paragraph, func: 'formatBlocks' }, blockquote: { title: lang.quote, func: 'formatQuote', className: 'redactor_format_blockquote' }, pre: { title: lang.code, func: 'formatBlocks', className: 'redactor_format_pre' }, h1: { title: lang.header1, func: 'formatBlocks', className: 'redactor_format_h1' }, h2: { title: lang.header2, func: 'formatBlocks', className: 'redactor_format_h2' }, h3: { title: lang.header3, func: 'formatBlocks', className: 'redactor_format_h3' }, h4: { title: lang.header4, func: 'formatBlocks', className: 'redactor_format_h4' }, h5: { title: lang.header5, func: 'formatBlocks', className: 'redactor_format_h5' } } }, bold: { title: lang.bold, exec: 'bold' }, italic: { title: lang.italic, exec: 'italic' }, deleted: { title: lang.deleted, exec: 'strikethrough' }, underline: { title: lang.underline, exec: 'underline' }, unorderedlist: { title: '• ' + lang.unorderedlist, exec: 'insertunorderedlist' }, orderedlist: { title: '1. ' + lang.orderedlist, exec: 'insertorderedlist' }, outdent: { title: '< ' + lang.outdent, func: 'indentingOutdent' }, indent: { title: '> ' + lang.indent, func: 'indentingIndent' }, image: { title: lang.image, func: 'imageShow' }, video: { title: lang.video, func: 'videoShow' }, file: { title: lang.file, func: 'fileShow' }, table: { title: lang.table, func: 'show', dropdown: { insert_table: { title: lang.insert_table, func: 'tableShow' }, separator_drop1: { name: 'separator' }, insert_row_above: { title: lang.insert_row_above, func: 'tableAddRowAbove' }, insert_row_below: { title: lang.insert_row_below, func: 'tableAddRowBelow' }, insert_column_left: { title: lang.insert_column_left, func: 'tableAddColumnLeft' }, insert_column_right: { title: lang.insert_column_right, func: 'tableAddColumnRight' }, separator_drop2: { name: 'separator' }, add_head: { title: lang.add_head, func: 'tableAddHead' }, delete_head: { title: lang.delete_head, func: 'tableDeleteHead' }, separator_drop3: { name: 'separator' }, delete_column: { title: lang.delete_column, func: 'tableDeleteColumn' }, delete_row: { title: lang.delete_row, func: 'tableDeleteRow' }, delete_table: { title: lang.delete_table, func: 'tableDeleteTable' } } }, link: { title: lang.link, func: 'show', dropdown: { link: { title: lang.link_insert, func: 'linkShow' }, unlink: { title: lang.unlink, exec: 'unlink' } } }, fontcolor: { title: lang.fontcolor, func: 'show' }, backcolor: { title: lang.backcolor, func: 'show' }, alignment: { title: lang.alignment, func: 'show', dropdown: { alignleft: { title: lang.align_left, func: 'alignmentLeft' }, aligncenter: { title: lang.align_center, func: 'alignmentCenter' }, alignright: { title: lang.align_right, func: 'alignmentRight' }, justify: { title: lang.align_justify, func: 'alignmentJustify' } } }, alignleft: { title: lang.align_left, func: 'alignmentLeft' }, aligncenter: { title: lang.align_center, func: 'alignmentCenter' }, alignright: { title: lang.align_right, func: 'alignmentRight' }, justify: { title: lang.align_justify, func: 'alignmentJustify' }, horizontalrule: { exec: 'inserthorizontalrule', title: lang.horizontalrule } } }, // CALLBACKS callback: function(type, event, data) { var callback = this.opts[ type + 'Callback' ]; if ($.isFunction(callback)) { if (event === false) return callback.call(this, data); else return callback.call(this, event, data); } else return data; }, // DESTROY destroy: function() { clearInterval(this.autosaveInterval); $(window).off('.redactor'); this.$source.off('redactor-textarea'); this.$element.off('.redactor').removeData('redactor'); var html = this.get(); if (this.opts.textareamode) { this.$box.after(this.$source); this.$box.remove(); this.$source.val(html).show(); } else { var $elem = this.$editor; if (this.opts.iframe) $elem = this.$element; this.$box.after($elem); this.$box.remove(); $elem.removeClass('redactor_editor').removeClass('redactor_editor_wym').removeAttr('contenteditable').html(html).show(); } if (this.opts.air) { $('.redactor_air').remove(); } }, // API GET getObject: function() { return $.extend({}, this); }, getEditor: function() { return this.$editor; }, getBox: function() { return this.$box; }, getIframe: function() { return (this.opts.iframe) ? this.$frame : false; }, getToolbar: function() { return this.$toolbar; }, // CODE GET & SET get: function() { return this.$source.val(); }, getCodeIframe: function() { this.$editor.removeAttr('contenteditable').removeAttr('dir'); var html = this.outerHtml(this.$frame.contents().children()); this.$editor.attr({ 'contenteditable': true, 'dir': this.opts.direction }); return html; }, set: function(html, strip, placeholderRemove) { html = html.toString(); if (this.opts.fullpage) this.setCodeIframe(html); else this.setEditor(html, strip); if (placeholderRemove !== false) this.placeholderRemove(); }, setEditor: function(html, strip) { if (strip !== false) { html = this.cleanSavePreCode(html); html = this.cleanStripTags(html); html = this.cleanConvertProtected(html); html = this.cleanConvertInlineTags(html); if (this.opts.linebreaks === false) html = this.cleanConverters(html); else html = html.replace(/([\w\W]*?)<\/p>/gi, '$2 ' + this.opts.invisibleSpace + ' ' + this.opts.invisibleSpace + ' ' + this.opts.invisibleSpace + ' ').append($(current).clone());
$(current).replaceWith(node);
var next = $(node).next();
if (typeof(next[0]) !== 'undefined' && next[0].tagName == 'BR')
{
next.remove();
}
this.selectionEnd(node);
}
// convert links
if ((this.opts.convertLinks || this.opts.convertImageLinks || this.opts.convertVideoLinks) && key === this.keyCode.ENTER)
{
this.formatLinkify(this.opts.linkProtocol, this.opts.convertLinks, this.opts.convertImageLinks, this.opts.convertVideoLinks);
setTimeout($.proxy(function()
{
if (this.opts.convertImageLinks) this.observeImages();
if (this.opts.observeLinks) this.observeLinks();
}, this), 5);
}
// if empty
if (this.opts.linebreaks === false && (key === this.keyCode.DELETE || key === this.keyCode.BACKSPACE))
{
return this.formatEmpty(e);
}
this.callback('keyup', e);
this.sync();
},
buildPlugins: function()
{
if (!this.opts.plugins ) return;
$.each(this.opts.plugins, $.proxy(function(i, s)
{
if (RedactorPlugins[s])
{
$.extend(this, RedactorPlugins[s]);
if ($.isFunction( RedactorPlugins[ s ].init)) this.init();
}
}, this ));
},
// IFRAME
iframeStart: function()
{
this.iframeCreate();
if (this.opts.textareamode) this.iframeAppend(this.$source);
else
{
this.$sourceOld = this.$source.hide();
this.$source = this.buildCodearea(this.$sourceOld);
this.iframeAppend(this.$sourceOld);
}
},
iframeAppend: function(el)
{
this.$source.attr('dir', this.opts.direction).hide();
this.$box.insertAfter(el).append(this.$frame).append(this.$source);
},
iframeCreate: function()
{
this.$frame = $('').one('load', $.proxy(function()
{
if (this.opts.fullpage)
{
this.iframePage();
if (this.content === '') this.content = this.opts.invisibleSpace;
this.$frame.contents()[0].write(this.content);
this.$frame.contents()[0].close();
var timer = setInterval($.proxy(function()
{
if (this.$frame.contents().find('body').html())
{
clearInterval(timer);
this.iframeLoad();
}
}, this), 0);
}
else this.iframeLoad();
}, this));
},
iframeDoc: function()
{
return this.$frame[0].contentWindow.document;
},
iframePage: function()
{
var doc = this.iframeDoc();
if (doc.documentElement) doc.removeChild(doc.documentElement);
return doc;
},
iframeAddCss: function(css)
{
css = css || this.opts.css;
if (this.isString(css))
{
this.$frame.contents().find('head').append('');
}
if ($.isArray(css))
{
$.each(css, $.proxy(function(i, url)
{
this.iframeAddCss(url);
}, this));
}
},
iframeLoad: function()
{
this.$editor = this.$frame.contents().find('body').attr({ 'contenteditable': true, 'dir': this.opts.direction });
// set document & window
if (this.$editor[0])
{
this.document = this.$editor[0].ownerDocument;
this.window = this.document.defaultView || window;
}
// iframe css
this.iframeAddCss();
if (this.opts.fullpage) this.setFullpageOnInit(this.$editor.html());
else this.set(this.content, true, false);
this.buildOptions();
this.buildAfter();
},
// PLACEHOLDER
placeholderStart: function(html)
{
if (this.isEmpty(html))
{
if (this.$element.attr('placeholder')) this.opts.placeholder = this.$element.attr('placeholder');
if (this.opts.placeholder === '') this.opts.placeholder = false;
if (this.opts.placeholder !== false)
{
this.opts.focus = false;
this.$editor.one('focus.redactor_placeholder', $.proxy(this.placeholderFocus, this));
return $('').attr('contenteditable', false).text(this.opts.placeholder);
}
}
return false;
},
placeholderFocus: function()
{
this.$editor.find('span.redactor_placeholder').remove();
var html = '';
if (this.opts.linebreaks === false) html = this.opts.emptyHtml;
this.$editor.off('focus.redactor_placeholder');
this.$editor.html(html);
if (this.opts.linebreaks === false)
{
// place the cursor inside emptyHtml
this.selectionStart(this.$editor.children()[0]);
}
this.sync();
},
placeholderRemove: function()
{
this.opts.placeholder = false;
this.$editor.find('span.redactor_placeholder').remove();
this.$editor.off('focus.redactor_placeholder');
},
placeholderRemoveFromCode: function(html)
{
return html.replace(/(.*?)<\/span>/i, '');
},
// SHORTCUTS
shortcuts: function(e, key)
{
if (!this.opts.shortcuts) return;
if (!e.altKey)
{
if (key === 77) this.shortcutsLoad(e, 'removeFormat'); // Ctrl + m
else if (key === 66) this.shortcutsLoad(e, 'bold'); // Ctrl + b
else if (key === 73) this.shortcutsLoad(e, 'italic'); // Ctrl + i
else if (key === 74) this.shortcutsLoad(e, 'insertunorderedlist'); // Ctrl + j
else if (key === 75) this.shortcutsLoad(e, 'insertorderedlist'); // Ctrl + k
else if (key === 72) this.shortcutsLoad(e, 'superscript'); // Ctrl + h
else if (key === 76) this.shortcutsLoad(e, 'subscript'); // Ctrl + l
}
else
{
if (key === 48) this.shortcutsLoadFormat(e, 'p'); // ctrl + alt + 0
else if (key === 49) this.shortcutsLoadFormat(e, 'h1'); // ctrl + alt + 1
else if (key === 50) this.shortcutsLoadFormat(e, 'h2'); // ctrl + alt + 2
else if (key === 51) this.shortcutsLoadFormat(e, 'h3'); // ctrl + alt + 3
else if (key === 52) this.shortcutsLoadFormat(e, 'h4'); // ctrl + alt + 4
else if (key === 53) this.shortcutsLoadFormat(e, 'h5'); // ctrl + alt + 5
else if (key === 54) this.shortcutsLoadFormat(e, 'h6'); // ctrl + alt + 6
}
},
shortcutsLoad: function(e, cmd)
{
e.preventDefault();
this.execCommand(cmd, false);
},
shortcutsLoadFormat: function(e, cmd)
{
e.preventDefault();
this.formatBlocks(cmd);
},
// FOCUS
focus: function()
{
if (!this.browser('opera')) this.window.setTimeout($.proxy(this.focusSet, this, true), 1);
else this.$editor.focus();
},
focusEnd: function()
{
this.focusSet();
},
focusSet: function(collapse)
{
this.$editor.focus();
var range = this.getRange();
range.selectNodeContents(this.$editor[0]);
// collapse - controls the position of focus: the beginning (true), at the end (false).
range.collapse(collapse || false);
var sel = this.getSelection();
sel.removeAllRanges();
sel.addRange(range);
},
// TOGGLE
toggle: function(direct)
{
var html;
if (this.opts.visual)
{
if (direct !== false) this.selectionSave();
var height = null;
if (this.opts.iframe)
{
height = this.$frame.height();
if (this.opts.fullpage) this.$editor.removeAttr('contenteditable');
this.$frame.hide();
}
else
{
height = this.$editor.innerHeight();
this.$editor.hide();
}
html = this.$source.val();
this.modified = html;
this.$source.height(height).show().focus();
// textarea indenting
this.$source.on('keydown.redactor-textarea-indenting', function (e)
{
if (e.keyCode === 9)
{
var $el = $(this);
var start = $el.get(0).selectionStart;
$el.val($el.val().substring(0, start) + "\t" + $el.val().substring($el.get(0).selectionEnd));
$el.get(0).selectionStart = $el.get(0).selectionEnd = start + 1;
return false;
}
});
this.buttonInactiveVisual();
this.buttonActive('html');
this.opts.visual = false;
}
else
{
html = this.$source.hide().val();
if (typeof this.modified !== 'undefined')
{
this.modified = this.cleanRemoveSpaces(this.modified, false) !== this.cleanRemoveSpaces(html, false);
}
if (this.modified)
{
// don't remove the iframe even if cleared all.
if (this.opts.fullpage && html === '') this.setFullpageOnInit(html);
else
{
this.set(html);
if (this.opts.fullpage) this.buildBindKeyboard();
}
}
if (this.opts.iframe) this.$frame.show();
else this.$editor.show();
if (this.opts.fullpage ) this.$editor.attr('contenteditable', true );
this.$source.off('keydown.redactor-textarea-indenting');
this.$editor.focus();
this.selectionRestore();
this.observeStart();
this.buttonActiveVisual();
this.buttonInactive('html');
this.opts.visual = true;
}
},
// AUTOSAVE
autosave: function()
{
var savedHtml = false;
this.autosaveInterval = setInterval($.proxy(function()
{
var html = this.get();
if (savedHtml !== html)
{
$.ajax({
url: this.opts.autosave,
type: 'post',
data: this.$source.attr('name') + '=' + escape(encodeURIComponent(html)),
success: $.proxy(function(data)
{
this.callback('autosave', false, data);
savedHtml = html;
}, this)
});
}
}, this), this.opts.autosaveInterval*1000);
},
// TOOLBAR
toolbarBuild: function()
{
// extend buttons
if (this.opts.air)
{
this.opts.buttons = this.opts.airButtons;
}
else
{
if (!this.opts.buttonSource)
{
var index = this.opts.buttons.indexOf('html'), next = this.opts.buttons[index + 1];
this.opts.buttons.splice(index, 1);
if (next === '|') this.opts.buttons.splice(index, 1);
}
}
$.extend(this.opts.toolbar, this.opts.buttonsCustom);
$.each(this.opts.buttonsAdd, $.proxy(function(i, s)
{
this.opts.buttons.push(s);
}, this));
// formatting tags
if (this.opts.toolbar)
{
$.each(this.opts.toolbar.formatting.dropdown, $.proxy(function (i, s)
{
if ($.inArray(i, this.opts.formattingTags ) == '-1') delete this.opts.toolbar.formatting.dropdown[i];
}, this));
}
// if no buttons don't create a toolbar
if (this.opts.buttons.length === 0) return false;
// air enable
this.airEnable();
// toolbar build
this.$toolbar = $('
');
}
html = this.cleanEmpty(html);
this.$editor.html(html);
this.sync();
},
setCodeIframe: function(html)
{
var doc = this.iframePage();
this.$frame[0].src = "about:blank";
html = this.cleanConvertProtected(html);
html = this.cleanConvertInlineTags(html);
html = this.cleanRemoveSpaces(html);
doc.open();
doc.write(html);
doc.close();
// redefine editor for fullpage mode
if (this.opts.fullpage)
{
this.$editor = this.$frame.contents().find('body').attr({ 'contenteditable': true, 'dir': this.opts.direction });
}
this.sync();
},
setFullpageOnInit: function(html)
{
html = this.cleanSavePreCode(html, true);
html = this.cleanConverters(html);
html = this.cleanEmpty(html);
// set code
this.$editor.html(html);
this.sync();
},
// SYNC
sync: function()
{
var html = '';
this.cleanUnverified();
if (this.opts.fullpage) html = this.getCodeIframe();
else html = this.$editor.html();
html = this.syncClean(html);
html = this.cleanRemoveSpaces(html);
html = this.cleanRemoveEmptyTags(html);
// fix second level up ul, ol
html = html.replace(/<\/li><(ul|ol)>([\w\W]*?)<\/(ul|ol)>/gi, '<$1>$2$1>');
if ($.trim(html) === '
') html = '';
if (html !== '' && this.opts.tidyHtml) html = this.cleanHtml(html);
html = html.replace(/
/gi, '
');
// before callback
html = this.callback('syncBefore', false, html);
this.$source.val(html);
// onchange & after callback
this.callback('syncAfter', false, html);
if (this.start === false)
{
this.callback('change', false, html);
}
},
syncClean: function(html)
{
if (!this.opts.fullpage) html = this.cleanStripTags(html);
html = $.trim(html);
// removeplaceholder
html = this.placeholderRemoveFromCode(html);
// remove space
html = html.replace(//gi, '');
html = html.replace(//gi, '');
html = html.replace(/ /gi, ' ');
// link nofollow
if (this.opts.linkNofollow)
{
html = html.replace(//gi, '');
html = html.replace(//gi, '');
}
// php code fix
html = html.replace('', '?>');
html = html.replace(/ data-tagblock=""/gi, '');
html = html.replace(/
\n?<\/(P|H[1-6]|LI|ADDRESS|SECTION|HEADER|FOOTER|ASIDE|ARTICLE)>/gi, '$1>');
// remove image resize
html = html.replace(/([\w\W]*?)<\/span>/i, '$3');
html = html.replace(/(.*?)<\/span>/i, '');
html = html.replace(/(.*?)<\/span>/i, '');
// remove spans
html = html.replace(/([\w\W]*?)<\/span>/gi, '$1');
html = html.replace(/([\w\W]*?)<\/span>/gi, '$3');
html = html.replace(/([\w\W]*?)<\/span>/gi, '$3' );
html = html.replace(/([\w\W]*?)<\/span>/gi, '$1');
html = html.replace(/([\w\W]*?)<\/span>/gi, '');
html = html.replace(/([\w\W]*?)<\/span>/gi, '$1');
html = html.replace(/([\w\W]*?)<\/span>/gi, '$3');
html = html.replace(/([\w\W]*?)<\/span>/gi, '$3' );
html = html.replace(/([\w\W]*?)<\/span>/gi, '$1');
// amp fix
html = html.replace(/;amp;/gi, ';');
html = this.cleanReConvertProtected(html);
return html;
},
// BUILD
buildStart: function()
{
// content
this.content = '';
// container
this.$box = $('');
// textarea test
if (this.$source[0].tagName === 'TEXTAREA') this.opts.textareamode = true;
// mobile
if (this.opts.mobile === false && this.isMobile())
{
this.buildMobile();
}
else
{
// get the content at the start
this.buildContent();
if (this.opts.iframe)
{
// build as iframe
this.opts.autoresize = false;
this.iframeStart();
}
else if (this.opts.textareamode) this.buildFromTextarea();
else this.buildFromElement();
// options and final setup
if (!this.opts.iframe)
{
this.buildOptions();
this.buildAfter();
}
}
},
buildMobile: function()
{
if (!this.opts.textareamode)
{
this.$editor = this.$source;
this.$editor.hide();
this.$source = this.buildCodearea(this.$editor);
this.$source.val(this.content);
}
this.$box.insertAfter(this.$source).append(this.$source);
},
buildContent: function()
{
if (this.opts.textareamode) this.content = $.trim(this.$source.val());
else this.content = $.trim(this.$source.html());
},
buildFromTextarea: function()
{
this.$editor = $('');
this.$box.insertAfter(this.$source).append(this.$editor).append(this.$source);
// enable
this.buildAddClasses(this.$editor);
this.buildEnable();
},
buildFromElement: function()
{
this.$editor = this.$source;
this.$source = this.buildCodearea(this.$editor);
this.$box.insertAfter(this.$editor).append(this.$editor).append(this.$source);
// enable
this.buildEnable();
},
buildCodearea: function($source)
{
return $('').attr('name', $source.attr('id')).css('height', this.sourceHeight);
},
buildAddClasses: function(el)
{
// append textarea classes to editable layer
$.each(this.$source.get(0).className.split(/\s+/), function(i,s)
{
el.addClass('redactor_' + s);
});
},
buildEnable: function()
{
this.$editor.addClass('redactor_editor').attr({ 'contenteditable': true, 'dir': this.opts.direction });
this.$source.attr('dir', this.opts.direction).hide();
// set code
this.set(this.content, true, false);
},
buildOptions: function()
{
var $source = this.$editor;
if (this.opts.iframe) $source = this.$frame;
// options
if (this.opts.tabindex) $source.attr('tabindex', this.opts.tabindex);
if (this.opts.minHeight) $source.css('min-height', this.opts.minHeight + 'px');
if (this.opts.wym) this.$editor.addClass('redactor_editor_wym');
if (!this.opts.autoresize) $source.css('height', this.sourceHeight);
},
buildAfter: function()
{
this.start = false;
// load toolbar
if (this.opts.toolbar)
{
this.opts.toolbar = this.initToolbar(this.opts.curLang);
this.toolbarBuild();
}
// modal templates
this.modalTemplatesInit();
// plugins
this.buildPlugins();
// enter, tab, etc.
this.buildBindKeyboard();
// autosave
if (this.opts.autosave) this.autosave();
// observers
setTimeout($.proxy(this.observeStart, this), 4);
// FF fix
if (this.browser('mozilla'))
{
try {
this.document.execCommand('enableObjectResizing', false, false);
this.document.execCommand('enableInlineTableEditing', false, false);
} catch (e) {}
}
// focus
if (this.opts.focus) setTimeout($.proxy(this.focus, this), 100);
// code mode
if (!this.opts.visual)
{
setTimeout($.proxy(function()
{
this.opts.visual = true;
this.toggle(false);
}, this), 200);
}
// init callback
this.callback('init');
},
buildBindKeyboard: function()
{
if (this.opts.dragUpload)
{
this.$editor.on('drop.redactor', $.proxy(this.buildEventDrop, this));
}
this.$editor.on('paste.redactor', $.proxy(this.buildEventPaste, this));
this.$editor.on('keydown.redactor', $.proxy(this.buildEventKeydown, this));
this.$editor.on('keyup.redactor', $.proxy(this.buildEventKeyup, this));
// textarea callback
if ($.isFunction(this.opts.textareaKeydownCallback))
{
this.$source.on('keydown.redactor-textarea', $.proxy(this.opts.textareaKeydownCallback, this));
}
// focus callback
if ($.isFunction(this.opts.focusCallback))
{
this.$editor.on('focus.redactor', $.proxy(this.opts.focusCallback, this));
}
// blur callback
this.$editor.on('blur.redactor', $.proxy(function()
{
this.selectall = false;
}, this));
if ($.isFunction(this.opts.blurCallback))
{
this.$editor.on('blur.redactor', $.proxy(this.opts.blurCallback, this));
}
},
buildEventDrop: function(e)
{
e = e.originalEvent || e;
if (window.FormData === undefined) return true;
var length = e.dataTransfer.files.length;
if (length == 0) return true;
e.preventDefault();
var file = e.dataTransfer.files[0];
if (this.opts.dnbImageTypes !== false && this.opts.dnbImageTypes.indexOf(file.type) == -1)
{
return true;
}
this.bufferSet();
var progress = $('
' + this.opts.invisibleSpace);
$(current).replaceWith(node);
this.selectionStart(node);
}
if (typeof current.nodeValue !== 'undefined' && current.nodeValue !== null)
{
var value = $.trim(current.nodeValue.replace(/[^\u0000-\u1C7F]/g, ''));
if (current.remove && current.nodeType === 3 && current.nodeValue.charCodeAt(0) == 8203 && value == '')
{
current.remove();
}
}
}
},
buildEventKeydownInsertLineBreak: function(e)
{
this.bufferSet();
e.preventDefault();
this.insertLineBreak();
this.callback('enter', e);
return;
},
buildEventKeyup: function(e)
{
if (rtePaste) return false;
var key = e.which;
var parent = this.getParent();
var current = this.getCurrent();
// replace to p before / after the table or body
if (!this.opts.linebreaks && current.nodeType == 3 && (parent == false || parent.tagName == 'BODY'))
{
var node = $('').addClass('redactor_toolbar').attr('id', 'redactor_toolbar_' + this.uuid);
if (this.opts.air)
{
// air box
this.$air = $('