/* 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('^]'); // 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
    '); } 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'); 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, ''); // 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 $('' + '' + '' + '
    ' + '' + '' + '
    ' }); }, modalInit: function(title, content, width, callback) { var $redactorModalOverlay = $('#redactor_modal_overlay'); // modal overlay if (!$redactorModalOverlay.length) { this.$overlay = $redactorModalOverlay = $(''); $('body').prepend(this.$overlay); } if (this.opts.modalOverlay) { $redactorModalOverlay.show().on('click', $.proxy(this.modalClose, this)); } var $redactorModal = $('#redactor_modal'); if (!$redactorModal.length) { this.$modal = $redactorModal = $(''); $('body').append(this.$modal); } $('#redactor_modal_close').on('click', $.proxy(this.modalClose, this)); this.hdlModalClose = $.proxy(function(e) { if (e.keyCode === this.keyCode.ESC) { this.modalClose(); return false; } }, this); $(document).keyup(this.hdlModalClose); this.$editor.keyup(this.hdlModalClose); // set content this.modalcontent = false; if (content.indexOf('#') == 0) { this.modalcontent = $(content); $('#redactor_modal_inner').empty().append(this.modalcontent.html()); this.modalcontent.html(''); } else { $('#redactor_modal_inner').empty().append(content); } $redactorModal.find('#redactor_modal_header').html(title); // draggable if (typeof $.fn.draggable !== 'undefined') { $redactorModal.draggable({ handle: '#redactor_modal_header' }); $redactorModal.find('#redactor_modal_header').css('cursor', 'move'); } var $redactor_tabs = $('#redactor_tabs'); // tabs if ($redactor_tabs.length ) { var that = this; $redactor_tabs.find('a').each(function(i, s) { i++; $(s).on('click', function(e) { e.preventDefault(); $redactor_tabs.find('a').removeClass('redactor_tabs_act'); $(this).addClass('redactor_tabs_act'); $('.redactor_tab').hide(); $('#redactor_tab' + i ).show(); $('#redactor_tab_selected').val(i); if (that.isMobile() === false) { var height = $redactorModal.outerHeight(); $redactorModal.css('margin-top', '-' + (height + 10) / 2 + 'px'); } }); }); } $redactorModal.find('.redactor_btn_modal_close').on('click', $.proxy(this.modalClose, this)); // save scroll if (this.opts.autoresize === true) this.saveModalScroll = this.document.body.scrollTop; if (this.isMobile() === false) { $redactorModal.css({ position: 'fixed', top: '-2000px', left: '50%', width: width + 'px', marginLeft: '-' + (width + 60) / 2 + 'px' }).show(); this.modalSaveBodyOveflow = $(document.body).css('overflow'); $(document.body).css('overflow', 'hidden'); } else { $redactorModal.css({ position: 'fixed', width: '100%', height: '100%', top: '0', left: '0', margin: '0', minHeight: '300px' }).show(); } // callback if (typeof callback === 'function') callback(); if (this.isMobile() === false) { setTimeout(function() { var height = $redactorModal.outerHeight(); $redactorModal.css({ top: '50%', height: 'auto', minHeight: 'auto', marginTop: '-' + (height + 10) / 2 + 'px' }); }, 10); } }, modalClose: function() { $('#redactor_modal_close').off('click', this.modalClose ); $('#redactor_modal').fadeOut('fast', $.proxy(function() { var redactorModalInner = $('#redactor_modal_inner'); if (this.modalcontent !== false) { this.modalcontent.html(redactorModalInner.html()); this.modalcontent = false; } redactorModalInner.html(''); if (this.opts.modalOverlay) { $('#redactor_modal_overlay').hide().off('click', this.modalClose); } $(document).unbind('keyup', this.hdlModalClose); this.$editor.unbind('keyup', this.hdlModalClose); this.selectionRestore(); // restore scroll if (this.opts.autoresize && this.saveModalScroll) $(this.document.body).scrollTop(this.saveModalScroll); }, this)); if (this.isMobile() === false) { $(document.body).css('overflow', this.modalSaveBodyOveflow ? this.modalSaveBodyOveflow : 'visible'); } return false; }, modalSetTab: function(num) { $('.redactor_tab').hide(); $('#redactor_tabs').find('a').removeClass('redactor_tabs_act').eq(num - 1).addClass('redactor_tabs_act'); $('#redactor_tab' + num).show(); }, // S3 s3handleFileSelect: function(e) { var files = e.target.files; for (var i = 0, f; f = files[i]; i++) { this.s3uploadFile(f); } }, s3uploadFile: function(file) { this.s3executeOnSignedUrl(file, $.proxy(function(signedURL) { this.s3uploadToS3(file, signedURL); }, this)); }, s3executeOnSignedUrl: function(file, callback) { var xhr = new XMLHttpRequest(); xhr.open('GET', this.opts.s3 + '?name=' + file.name + '&type=' + file.type, true); // Hack to pass bytes through unprocessed. xhr.overrideMimeType('text/plain; charset=x-user-defined'); xhr.onreadystatechange = function(e) { if (this.readyState == 4 && this.status == 200) { $('#redactor-progress').fadeIn(); callback(decodeURIComponent(this.responseText)); } else if(this.readyState == 4 && this.status != 200) { //setProgress(0, 'Could not contact signing script. Status = ' + this.status); } }; xhr.send(); }, s3createCORSRequest: function(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { xhr = new XDomainRequest(); xhr.open(method, url); } else { xhr = null; } return xhr; }, s3uploadToS3: function(file, url) { var xhr = this.s3createCORSRequest('PUT', url); if (!xhr) { //setProgress(0, 'CORS not supported'); } else { xhr.onload = $.proxy(function() { if (xhr.status == 200) { //setProgress(100, 'Upload completed.'); $('#redactor-progress').hide(); var s3image = url.split('?'); if (!s3image[0]) { // url parsing is fail return false; } this.selectionRestore(); var html = ''; html = ''; if (this.opts.paragraphy) html = '

    ' + html + '

    '; this.execCommand('inserthtml', html, false); var image = $(this.$editor.find('img#image-marker')); if (image.length) image.removeAttr('id'); else image = false; this.sync(); // upload image callback this.callback('imageUpload', image, false); this.modalClose(); this.observeImages(); } else { //setProgress(0, 'Upload error: ' + xhr.status); } }, this); xhr.onerror = function() { //setProgress(0, 'XHR error.'); }; xhr.upload.onprogress = function(e) { /* if (e.lengthComputable) { var percentLoaded = Math.round((e.loaded / e.total) * 100); setProgress(percentLoaded, percentLoaded == 100 ? 'Finalizing.' : 'Uploading.'); } */ }; xhr.setRequestHeader('Content-Type', file.type); xhr.setRequestHeader('x-amz-acl', 'public-read'); xhr.send(file); } }, // UPLOAD uploadInit: function(el, options) { this.uploadOptions = { url: false, success: false, error: false, start: false, trigger: false, auto: false, input: false }; $.extend(this.uploadOptions, options); var $el = $('#' + el); // Test input or form if ($el.length && $el[0].tagName === 'INPUT') { this.uploadOptions.input = $el; this.el = $($el[0].form); } else this.el = $el; this.element_action = this.el.attr('action'); // Auto or trigger if (this.uploadOptions.auto) { $(this.uploadOptions.input).change($.proxy(function(e) { this.el.submit(function(e) { return false; }); this.uploadSubmit(e); }, this)); } else if (this.uploadOptions.trigger) { $('#' + this.uploadOptions.trigger).click($.proxy(this.uploadSubmit, this)); } }, uploadSubmit: function(e) { $('#redactor-progress').fadeIn(); this.uploadForm(this.element, this.uploadFrame()); }, uploadFrame: function() { this.id = 'f' + Math.floor(Math.random() * 99999); var d = this.document.createElement('div'); var iframe = ''; d.innerHTML = iframe; $(d).appendTo("body"); // Start if (this.uploadOptions.start) this.uploadOptions.start(); $( '#' + this.id ).load($.proxy(this.uploadLoaded, this)); return this.id; }, uploadForm: function(f, name) { if (this.uploadOptions.input) { var formId = 'redactorUploadForm' + this.id, fileId = 'redactorUploadFile' + this.id; this.form = $('
    '); // append hidden fields if (this.opts.uploadFields !== false && typeof this.opts.uploadFields === 'object') { $.each(this.opts.uploadFields, $.proxy(function(k, v) { if (v != null && v.toString().indexOf('#') === 0) v = $(v).val(); var hidden = $('', { 'type': "hidden", 'name': k, 'value': v }); $(this.form).append(hidden); }, this)); } var oldElement = this.uploadOptions.input; var newElement = $(oldElement).clone(); $(oldElement).attr('id', fileId).before(newElement).appendTo(this.form); $(this.form).css('position', 'absolute') .css('top', '-2000px') .css('left', '-2000px') .appendTo('body'); this.form.submit(); } else { f.attr('target', name) .attr('method', 'POST') .attr('enctype', 'multipart/form-data') .attr('action', this.uploadOptions.url); this.element.submit(); } }, uploadLoaded: function() { var i = $( '#' + this.id)[0], d; if (i.contentDocument) d = i.contentDocument; else if (i.contentWindow) d = i.contentWindow.document; else d = window.frames[this.id].document; // Success if (this.uploadOptions.success) { $('#redactor-progress').hide(); if (typeof d !== 'undefined') { // Remove bizarre
     tag wrappers around our json data:
    					var rawString = d.body.innerHTML;
    					var jsonString = rawString.match(/\{(.|\n)*\}/)[0];
    
    					jsonString = jsonString.replace(/^\[/, '');
    					jsonString = jsonString.replace(/\]$/, '');
    
    					var json = $.parseJSON(jsonString);
    
    					if (typeof json.error == 'undefined') this.uploadOptions.success(json);
    					else
    					{
    						this.uploadOptions.error(this, json);
    						this.modalClose();
    					}
    				}
    				else
    				{
    					this.modalClose();
    					alert('Upload failed!');
    				}
    			}
    
    			this.el.attr('action', this.element_action);
    			this.el.attr('target', '');
    		},
    
    		// DRAGUPLOAD
    		draguploadInit: function (el, options)
    		{
    			this.draguploadOptions = $.extend({
    				url: false,
    				success: false,
    				error: false,
    				preview: false,
    				uploadFields: false,
    				text: this.opts.curLang.drop_file_here,
    				atext: this.opts.curLang.or_choose
    			}, options);
    
    			if (window.FormData === undefined) return false;
    
    			this.droparea = $('
    '); this.dropareabox = $('
    ' + this.draguploadOptions.text + '
    '); this.dropalternative = $('
    ' + this.draguploadOptions.atext + '
    '); this.droparea.append(this.dropareabox); $(el).before(this.droparea); $(el).before(this.dropalternative); // drag over this.dropareabox.on('dragover', $.proxy(function() { return this.draguploadOndrag(); }, this)); // drag leave this.dropareabox.on('dragleave', $.proxy(function() { return this.draguploadOndragleave(); }, this)); // drop this.dropareabox.get(0).ondrop = $.proxy(function(e) { e.preventDefault(); this.dropareabox.removeClass('hover').addClass('drop'); this.dragUploadAjax(this.draguploadOptions.url, e.dataTransfer.files[0], false); }, this ); }, dragUploadAjax: function(url, file, directupload, progress, e) { if (!directupload) { var xhr = $.ajaxSettings.xhr(); if (xhr.upload) { xhr.upload.addEventListener('progress', $.proxy(this.uploadProgress, this), false); } $.ajaxSetup({ xhr: function () { return xhr; } }); } var fd = new FormData(); // append file data fd.append('file', file); // append hidden fields if (this.opts.uploadFields !== false && typeof this.opts.uploadFields === 'object') { $.each(this.opts.uploadFields, $.proxy(function(k, v) { if (v != null && v.toString().indexOf('#') === 0) v = $(v).val(); fd.append(k, v); }, this)); } $.ajax({ url: url, dataType: 'html', data: fd, cache: false, contentType: false, processData: false, type: 'POST', success: $.proxy(function(data) { data = data.replace(/^\[/, ''); data = data.replace(/\]$/, ''); var json = $.parseJSON(data); if (directupload) { progress.fadeOut('slow', function() { $(this).remove(); }); var $img = $(''); $img.attr('src', json.filelink).attr('id', 'drag-image-marker'); this.insertNodeToCaretPositionFromPoint(e, $img[0]); var image = $(this.$editor.find('img#drag-image-marker')); if (image.length) image.removeAttr('id'); else image = false; this.sync(); this.observeImages(); // upload callback if (image) this.callback('imageUpload', image, json); // error callback if (typeof json.error !== 'undefined') this.callback('imageUploadError', json); } else { if (typeof json.error == 'undefined') { this.draguploadOptions.success(json); } else { this.draguploadOptions.error(this, json); this.draguploadOptions.success(false); } } }, this) }); }, draguploadOndrag: function() { this.dropareabox.addClass('hover'); return false; }, draguploadOndragleave: function() { this.dropareabox.removeClass('hover'); return false; }, uploadProgress: function(e, text) { var percent = e.loaded ? parseInt(e.loaded / e.total * 100, 10) : e; this.dropareabox.text('Loading ' + percent + '% ' + (text || '')); }, // UTILS isMobile: function() { return /(iPhone|iPod|BlackBerry|Android)/.test(navigator.userAgent); }, normalize: function(str) { if (typeof(str) === 'undefined') return 0; return parseInt(str.replace('px',''), 10); }, outerHtml: function(el) { return $('
    ').append($(el).eq(0).clone()).html(); }, isString: function(obj) { return Object.prototype.toString.call(obj) == '[object String]'; }, isEmpty: function(html) { html = html.replace(/​|
    || /gi, ''); html = html.replace(/\s/g, ''); html = html.replace(/^

    [^\W\w\D\d]*?<\/p>$/i, ''); return html == ''; }, browser: function(browser) { var ua = navigator.userAgent.toLowerCase(); var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+)/.exec(ua) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; if (browser == 'version') return match[2]; if (browser == 'webkit') return (match[1] == 'chrome' || match[1] == 'webkit'); return match[1] == browser; }, oldIE: function() { if (this.browser('msie') && parseInt(this.browser('version'), 10) < 9) return true; return false; }, getFragmentHtml: function (fragment) { var cloned = fragment.cloneNode(true); var div = this.document.createElement('div'); div.appendChild(cloned); return div.innerHTML; }, extractContent: function() { var node = this.$editor[0]; var frag = this.document.createDocumentFragment(); var child; while ((child = node.firstChild)) { frag.appendChild(child); } return frag; }, isParentRedactor: function(el) { if (!el) return false; if (this.opts.iframe) return el; if ($(el).parents('div.redactor_editor').length == 0 || $(el).hasClass('redactor_editor')) return false; else return el; }, currentOrParentIs: function(tagName) { var parent = this.getParent(), current = this.getCurrent(); return parent && parent.tagName === tagName ? parent : current && current.tagName === tagName ? current : false; }, isEndOfElement: function() { var current = this.getBlock(); var offset = this.getCaretOffset(current); var text = $.trim($(current).text()).replace(/\n\r\n/g, ''); var len = text.length; if (offset == len) return true; else return false; }, isFocused: function() { var el, sel = this.getSelection(); if (sel && sel.rangeCount && sel.rangeCount > 0) el = sel.getRangeAt(0).startContainer; if (!el) return false; if (this.opts.iframe) { if (this.getCaretOffsetRange().equals()) return !this.$editor.is(el); else return true; } return $(el).closest('div.redactor_editor').length != 0; }, removeEmptyAttr: function (el, attr) { if ($(el).attr(attr) == '') $(el).removeAttr(attr); }, removeFromArrayByValue: function(array, value) { var index = null; while ((index = array.indexOf(value)) !== -1) { array.splice(index, 1); } return array; } }; // constructor Redactor.prototype.init.prototype = Redactor.prototype; // LINKIFY $.Redactor.fn.formatLinkify = function(protocol, convertLinks, convertImageLinks, convertVideoLinks) { var url1 = /(^|<|\s)(www\..+?\..+?)(\s|>|$)/g, url2 = /(^|<|\s)(((https?|ftp):\/\/|mailto:).+?)(\s|>|$)/g, urlImage = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif))/gi, urlYoutube = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/, urlVimeo = /http:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/; var childNodes = (this.$editor ? this.$editor.get(0) : this).childNodes, i = childNodes.length; while (i--) { var n = childNodes[i]; if (n.nodeType === 3) { var html = n.nodeValue; // youtube & vimeo if (convertVideoLinks && html) { var iframeStart = ''; if (html.match(urlYoutube)) { html = html.replace(urlYoutube, iframeStart + '//www.youtube.com/embed/$2' + iframeEnd); $(n).after(html).remove(); } else if (html.match(urlVimeo)) { html = html.replace(urlVimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd); $(n).after(html).remove(); } } // image if (convertImageLinks && html && html.match(urlImage)) { html = html.replace(urlImage, ''); $(n).after(html).remove(); } // link if (convertLinks && html && (html.match(url1) || html.match(url2))) { var href = (html.match(url1) || html.match(url2)); href = href[0]; if (href.length > 50) href = href.substring(0, 50) + '...'; html = html.replace(/&/g, '&') .replace(//g, '>') .replace(url1, '$1' + href + '$3') .replace(url2, '$1' + href + '$5'); $(n).after(html).remove(); } } else if (n.nodeType === 1 && !/^(a|button|textarea)$/i.test(n.tagName)) { $.Redactor.fn.formatLinkify.call(n, protocol, convertLinks, convertImageLinks, convertVideoLinks); } } }; })(jQuery);