diff --git a/app/assets/javascripts/admin.coffee b/app/assets/javascripts/admin.coffee index de53fc0..7f8ba3a 100644 --- a/app/assets/javascripts/admin.coffee +++ b/app/assets/javascripts/admin.coffee @@ -24,11 +24,34 @@ #= require redactor +#= require redactor_plugins/fontsize +#= require redactor_plugins/fontfamily +#= require redactor_plugins/fontcolor #= require nested_fields -#= require_tree ./note_files - +portlet_to_move = false +content_type_to_move =false +@open_collapse3 = -> + $("#collapse3 .panel").show() + $("#collapse3").show() + +@reset_edit_pane = -> + $("#element_form").html() + $("#collapse3").hide() + +@unselect_portlet = -> + $(".portlet.active").removeClass("active") + reset_edit_pane() + +@cancel_move_portlet = -> + $(".move_message").show() + $(".cancel_message").hide() + + $(".move").removeClass("move") + $(".portlet_placeholder").remove() + portlet_to_move = false + $(document).ready -> $(document).on 'click', 'input.datepicker', -> @@ -61,11 +84,14 @@ $(document).ready -> $(document).on "click", ".portlet", (event) -> - $(".portlet.active").removeClass("active") - $(this).addClass("active") + if !$(this).hasClass("active") and portlet_to_move == false + + $(".portlet.active").removeClass("active") + $(this).addClass("active") - $.ajax({url : $(this).data("edit-link"), type: "GET"}); - $("#collapse3 .trash").attr("href", $(this).data("show-link")); + + $.ajax({url : $(this).data("edit-link"), type: "GET"}); + $("#collapse3 .trash").attr("href", $(this).data("show-link")); event.stopPropagation(); @@ -73,26 +99,43 @@ $(document).ready -> portlet_to_move = false content_type_to_move = false $("#element_form").html("") - $("#collapse3").collapse('hide'); - $("#collapse2").collapse('show'); + $(".portlet.active").removeClass("active") - portlet_to_move = false - content_type_to_move =false + + + + $(document).on "click", "#content_types .content_type", -> - + cancel_move_portlet() + unselect_portlet() + reset_edit_pane() + + type = $(this).data("type") content_type_to_move = type init_portlets_place_holder() $(this).addClass("move") false + + $(document).on "click", ".portlet_handle", -> - id = $(this).data("portlet-id") - portlet_to_move = $("#portlet_"+id) - init_portlets_place_holder() - portlet_to_move.addClass("move") - false + if portlet_to_move == false + + $(".move_message").hide() + $(".cancel_message").show() + + + id = $(this).data("portlet-id") + portlet_to_move = $("#portlet_"+id) + init_portlets_place_holder() + portlet_to_move.addClass("move") + false + else + cancel_move_portlet() + + false $(document).on "click", ".portlet_placeholder", -> if portlet_to_move != false @@ -100,7 +143,7 @@ $(document).ready -> $(".move").removeClass("move") $(".portlet_placeholder").remove() update_block_portlet_order(portlet_to_move.closest(".block_portlets").data("block_id")) - portlet_to_move = false + cancel_move_portlet() else block_id = $(this).closest(".block_portlets").data("block_id") @@ -344,3 +387,14 @@ $(document).on "scroll", () -> $("#toolbar-text, #menu_item_informations").css top : top + +$(document).on "click", "#menu_item_informations .save", -> + $(this).closest(".panel").find("form").submit() + return false + +$(document).on "click", "#menu_item_informations h4", -> + $(this).next(".panel").toggle() + return false + + + diff --git a/app/assets/javascripts/redactor.js b/app/assets/javascripts/redactor.js index 8f6ec66..fe77a60 100755 --- a/app/assets/javascripts/redactor.js +++ b/app/assets/javascripts/redactor.js @@ -1,6 +1,6 @@ /* - Redactor v9.2.4 - Updated: May 15, 2014 + Redactor v10.0.1 + Updated: October 6, 2014 http://imperavi.com/redactor/ @@ -9,28 +9,26 @@ Usage: $('#content').redactor(); */ + (function($) { + 'use strict'; + + if (!Function.prototype.bind) + { + Function.prototype.bind = function(scope) + { + var fn = this; + return function() + { + return fn.apply(scope); + }; + }; + } + var uuid = 0; - "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]; - }; - - var reUrlYoutube = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig; + var reUrlYoutube = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig; var reUrlVimeo = /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/; // Plugin @@ -44,19 +42,41 @@ this.each(function() { var instance = $.data(this, 'redactor'); - if (typeof instance !== 'undefined' && $.isFunction(instance[options])) + var func; + + if (options.search(/\./) != '-1') { - var methodVal = instance[options].apply(instance, args); - if (methodVal !== undefined && methodVal !== instance) val.push(methodVal); + func = options.split('.'); + if (typeof instance[func[0]] != 'undefined') + { + func = instance[func[0]][func[1]]; + } + } + else + { + func = instance[options]; + } + + if (typeof instance !== 'undefined' && $.isFunction(func)) + { + var methodVal = func.apply(instance, args); + if (methodVal !== undefined && methodVal !== instance) + { + val.push(methodVal); + } + } + else + { + $.error('No such method "' + options + '" for Redactor'); } - else return $.error('No such method "' + options + '" for Redactor'); }); } else { this.each(function() { - if (!$.data(this, 'redactor')) $.data(this, 'redactor', Redactor(this, options)); + $.data(this, 'redactor', {}); + $.data(this, 'redactor', Redactor(this, options)); }); } @@ -72,239 +92,238 @@ return new Redactor.prototype.init(el, options); } + // Functionality $.Redactor = Redactor; - $.Redactor.VERSION = '9.2.4'; + $.Redactor.VERSION = '10.0.1'; + $.Redactor.modules = ['core', 'build', 'lang', 'toolbar', 'button', 'dropdown', 'code', + 'clean', 'tidy', 'paragraphize', 'tabifier', 'focus', 'placeholder', 'autosave', 'buffer', 'indent', 'alignment', 'paste', + 'keydown', 'keyup', 'shortcuts', 'line', 'list', 'block', 'inline', 'insert', 'caret', 'selection', 'observe', + 'link', 'image', 'file', 'modal', 'progress', 'upload', 'utils']; + $.Redactor.opts = { - // settings - rangy: false, + // settings + lang: 'en', + direction: 'ltr', // ltr or rtl - iframe: false, - fullpage: false, - css: false, // url + plugins: false, // array - lang: 'en', - direction: 'ltr', // ltr or rtl + focus: false, + focusEnd: false, - placeholder: false, + placeholder: false, - typewriter: false, - wym: false, - mobile: true, - cleanup: true, - tidyHtml: true, - pastePlainText: false, - removeEmptyTags: true, - cleanSpaces: true, - cleanFontTag: true, - templateVars: false, - xhtml: false, + visual: true, + tabindex: false, - visual: true, - focus: false, - tabindex: false, - autoresize: true, - minHeight: false, - maxHeight: false, - shortcuts: { - 'ctrl+m, meta+m': "this.execCommand('removeFormat', false)", - 'ctrl+b, meta+b': "this.execCommand('bold', false)", - 'ctrl+i, meta+i': "this.execCommand('italic', false)", - 'ctrl+h, meta+h': "this.execCommand('superscript', false)", - 'ctrl+l, meta+l': "this.execCommand('subscript', false)", - 'ctrl+k, meta+k': "this.linkShow()", - 'ctrl+shift+7': "this.execCommand('insertorderedlist', false)", - 'ctrl+shift+8': "this.execCommand('insertunorderedlist', false)" - }, - shortcutsAdd: { - 'ctrl+3': "this.execCommand('removeFormat', false)" + minHeight: false, + maxHeight: false, - }, + linebreaks: false, + replaceDivs: true, + paragraphize: true, + cleanStyleOnEnter: false, + enterKey: true, - autosave: false, // false or url - autosaveInterval: 60, // seconds + cleanOnPaste: true, + cleanSpaces: true, + pastePlainText: false, - plugins: false, // array + autosave: false, // false or url + autosaveName: false, + autosaveInterval: 60, // seconds + autosaveOnChange: false, - //linkAnchor: true, - //linkEmail: true, - linkProtocol: 'http://', - linkNofollow: false, - linkSize: 50, - predefinedLinks: false, // json url (ex. /some-url.json ) or false + linkTooltip: true, + linkProtocol: 'http', + linkNofollow: false, + linkSize: 50, - imageFloatMargin: '10px', - imageGetJson: false, // json url (ex. /some-images.json ) or false + imageEditable: true, + imageLink: true, + imagePosition: true, + imageFloatMargin: '10px', + imageResizable: true, - dragUpload: true, // false - imageTabLink: true, - imageUpload: false, // url - imageUploadParam: 'file', // input name - imageResizable: true, + imageUpload: false, + imageUploadParam: 'file', - fileUpload: false, // url - fileUploadParam: 'file', // input name - clipboardUpload: true, // or false - clipboardUploadUrl: false, // url + uploadImageField: false, - dnbImageTypes: ['image/png', 'image/jpeg', 'image/gif'], // or false + dragImageUpload: true, - s3: false, - uploadFields: false, + fileUpload: false, + fileUploadParam: 'file', - observeImages: true, - observeLinks: true, + dragFileUpload: true, - modalOverlay: true, + s3: false, - tabSpaces: false, // true or number of spaces - tabFocus: true, + convertLinks: true, + convertUrlLinks: true, + convertImageLinks: true, + convertVideoLinks: true, - air: false, - airButtons: ['formatting', 'bold', 'italic', 'deleted', 'unorderedlist', 'orderedlist', 'outdent', 'indent'], + preSpaces: 4, // or false + tabAsSpaces: false, // true or number of spaces + tabFocus: true, - toolbar: true, - toolbarFixed: false, - toolbarFixedTarget: document, - toolbarFixedTopOffset: 0, // pixels - toolbarFixedBox: false, - toolbarExternal: false, // ID selector - toolbarOverflow: false, - buttonSource: true, + scrollTarget: false, - buttons: ['html', 'formatting', 'bold', 'italic', 'deleted', 'unorderedlist', 'orderedlist', - 'outdent', 'indent', 'image', 'video', 'file', 'table', 'link', 'alignment', '|', - 'horizontalrule'], // 'underline', 'alignleft', 'aligncenter', 'alignright', 'justify' - buttonsHideOnMobile: [], + toolbar: true, + toolbarFixed: true, + toolbarFixedTarget: document, + toolbarFixedTopOffset: 0, // pixels + toolbarExternal: false, // ID selector + toolbarOverflow: false, - 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' - }, + buttonSource: false, + buttons: ['html', 'formatting', 'bold', 'italic', 'deleted', 'unorderedlist', 'orderedlist', + 'outdent', 'indent', 'image', 'file', 'link', 'alignment', 'horizontalrule'], // + 'underline' - formattingTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + buttonsHide: [], + buttonsHideOnMobile: [], - linebreaks: false, - paragraphy: true, - convertDivs: true, - convertLinks: true, - convertImageLinks: false, - convertVideoLinks: false, - formattingPre: false, - phpTags: false, + formatting: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + formattingAdd: false, - allowedTags: false, - deniedTags: ['html', 'head', 'link', 'body', 'meta', 'script', 'style', 'applet'], + tabifier: true, - boldTag: 'strong', - italicTag: 'em', + deniedTags: ['html', 'head', 'link', 'body', 'meta', 'script', 'style', 'applet'], + allowedTags: false, // or array - // 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'], + removeComments: false, + replaceTags: [ + ['strike', 'del'] + ], + replaceStyles: [ + ['font-weight:\\s?bold', "strong"], + ['font-style:\\s?italic', "em"], + ['text-decoration:\\s?underline', "u"], + ['text-decoration:\\s?line-through', 'del'] + ], + removeDataAttr: false, + + removeAttr: false, // or multi array + allowedAttr: false, // or multi array + + removeWithoutAttr: ['span'], // or false + removeEmpty: ['p'], // or false; + + activeButtons: ['deleted', 'italic', 'bold', 'underline', 'unorderedlist', 'orderedlist', + 'alignleft', 'aligncenter', 'alignright', 'justify'], + activeButtonsStates: { + b: 'bold', + strong: 'bold', + i: 'italic', + em: 'italic', + del: 'deleted', + strike: 'deleted', + ul: 'unorderedlist', + ol: 'orderedlist', + u: 'underline' + }, + + shortcuts: { + 'ctrl+shift+m, meta+shift+m': { func: 'inline.removeFormat' }, + 'ctrl+b, meta+b': { func: 'inline.format', params: ['bold'] }, + 'ctrl+i, meta+i': { func: 'inline.format', params: ['italic'] }, + 'ctrl+h, meta+h': { func: 'inline.format', params: ['superscript'] }, + 'ctrl+l, meta+l': { func: 'inline.format', params: ['subscript'] }, + 'ctrl+k, meta+k': { func: 'link.show' }, + 'ctrl+shift+7': { func: 'list.toggle', params: ['orderedlist'] }, + 'ctrl+shift+8': { func: 'list.toggle', params: ['unorderedlist'] } + }, + shortcutsAdd: false, + + // private + buffer: [], + rebuffer: [], + emptyHtml: '
', + invisibleSpace: '', + imageTypes: ['image/png', 'image/jpeg', 'image/gif'], + indentValue: 20, + verifiedTags: ['a', 'img', 'b', 'strong', 'sub', 'sup', 'i', 'em', 'u', 'small', 'strike', 'del', 'cite', 'ul', 'ol', 'li'], // and for span tag special rule + inlineTags: ['strong', 'b', 'u', 'em', 'i', 'code', 'del', 'ins', 'samp', 'kbd', 'sup', 'sub', 'mark', 'var', 'cite', 'small'], + alignmentTags: ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DL', 'DT', 'DD', 'DIV', 'TD', 'BLOCKQUOTE', 'OUTPUT', 'FIGCAPTION', 'ADDRESS', 'SECTION', 'HEADER', 'FOOTER', 'ASIDE', 'ARTICLE'], + blockLevelElements: ['PRE', 'UL', 'OL', 'LI'], - // 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', - center: 'Center', - 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' - } + // 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', + center: 'Center', + image_web_link: 'Image Web Link', + text: 'Text', + mailto: 'Email', + web: 'URL', + video_html_code: 'Video Embed Code or Youtube/Vimeo Link', + 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 @@ -315,10 +334,13 @@ DELETE: 46, DOWN: 40, ENTER: 13, + SPACE: 32, ESC: 27, TAB: 9, CTRL: 17, META: 91, + SHIFT: 16, + ALT: 18, LEFT: 37, LEFT_WIN: 91 }, @@ -326,2994 +348,2923 @@ // Initialization init: function(el, options) { - this.rtePaste = false; - this.$element = this.$source = $(el); + this.$element = $(el); this.uuid = uuid++; - // clonning options - var opts = $.extend(true, {}, $.Redactor.opts); + // if paste event detected = true + this.rtePaste = false; + this.$pasteBox = false; - // current settings - this.opts = $.extend( - {}, - opts, - this.$element.data(), - options - ); + this.loadOptions(options); + this.loadModules(); - this.start = true; - this.dropdowns = []; + // formatting storage + this.formatting = {}; - // get sizes - this.sourceHeight = this.$source.css('height'); - this.sourceWidth = this.$source.css('width'); + // block level tags + $.merge(this.opts.blockLevelElements, this.opts.alignmentTags); + this.reIsBlock = new RegExp('^(' + this.opts.blockLevelElements.join('|' ) + ')$', 'i'); - // 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) - { - var arrSearch = ['strong', 'em', 'del']; - var arrAdd = ['b', 'i', 'strike']; - - if ($.inArray('p', this.opts.allowedTags) === '-1') this.opts.allowedTags.push('p'); - - for (i in arrSearch) - { - if ($.inArray(arrSearch[i], this.opts.allowedTags) != '-1') this.opts.allowedTags.push(arrAdd[i]); - } - } - - 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'); - } + // setup allowed and denied tags + this.tidy.setupAllowed(); // load lang - this.opts.curLang = this.opts.langs[this.opts.lang]; + this.lang.load(); // extend shortcuts $.extend(this.opts.shortcuts, this.opts.shortcutsAdd); - // init placeholder - this.placeholderInit(); - - // Build - this.buildStart(); + // start callback + this.core.setCallback('start'); + // build + this.start = true; + this.build.run(); }, - toolbarInit: function(lang) + + loadOptions: function(options) + { + this.opts = $.extend( + {}, + $.extend(true, {}, $.Redactor.opts), + this.$element.data(), + options + ); + }, + getModuleMethods: function(object) + { + return Object.getOwnPropertyNames(object).filter(function(property) + { + return typeof object[property] == 'function'; + }); + }, + loadModules: function() + { + var len = $.Redactor.modules.length; + for (var i = 0; i < len; i++) + { + this.bindModuleMethods($.Redactor.modules[i]); + } + }, + bindModuleMethods: function(module) + { + if (typeof this[module] == 'undefined') return; + + // init module + this[module] = this[module](); + + var methods = this.getModuleMethods(this[module]); + var len = methods.length; + + // bind methods + for (var z = 0; z < len; z++) + { + this[module][methods[z]] = this[module][methods[z]].bind(this); + } + }, + + core: function() { return { - html: + getObject: function() { - title: lang.html, - func: 'toggle' + return $.extend({}, this); }, - formatting: + getEditor: function() { - title: lang.formatting, - func: 'show', - dropdown: + return this.$editor; + }, + getBox: function() + { + return this.$box; + }, + getElement: function() + { + return this.$element; + }, + getTextarea: function() + { + return this.$textarea; + }, + getToolbar: function() + { + return (this.$toolbar) ? this.$toolbar : false; + }, + addEvent: function(name) + { + this.core.event = name; + }, + getEvent: function() + { + return this.core.event; + }, + setCallback: function(type, e, data) + { + var callback = this.opts[type + 'Callback']; + if ($.isFunction(callback)) { - 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' - } - } - }, - 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' - }, - alignjustify: - { - 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.toolbarExternal) - { - $(this.opts.toolbarExternal).html(''); - } - - if (this.opts.air) - { - $('#redactor_air_' + this.uuid).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) ? this.$toolbar : false; - }, - - // 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(); - html = html.replace(/\$/g, '$'); - - if (this.opts.fullpage) this.setCodeIframe(html); - else this.setEditor(html, strip); - - if (html == '') placeholderRemove = false; - if (placeholderRemove !== false) this.placeholderRemoveFromEditor(); - }, - setEditor: function(html, strip) - { - - if (strip !== false) - { - html = this.cleanSavePreCode(html); - - html = this.cleanStripTags(html); - html = this.cleanConvertProtected(html); - html = this.cleanConvertInlineTags(html, true); - - 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 + ' ' + 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.buildEventKeyupConverters();
- }
-
- // if empty
- if (key === this.keyCode.DELETE || key === this.keyCode.BACKSPACE)
- {
- return this.formatEmpty(e);
- }
-
- this.callback('keyup', e);
- this.sync(e);
- },
- buildEventKeyupConverters: function()
- {
- this.formatLinkify(this.opts.linkProtocol, this.opts.convertLinks, this.opts.convertImageLinks, this.opts.convertVideoLinks, this.opts.linkSize);
-
- setTimeout($.proxy(function()
- {
- if (this.opts.convertImageLinks) this.observeImages();
- if (this.opts.observeLinks) this.observeLinks();
- }, this), 5);
- },
- 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();
+ if (this.opts.dragImageUpload || this.opts.dragFileUpload)
+ {
+ var files = e.dataTransfer.files;
+ this.upload.directUpload(files[0], e);
+ }
}
- }, this), 0);
- }
- else this.iframeLoad();
+ setTimeout($.proxy(this.clean.clearUnverified, this), 1);
- }, this));
- },
- iframeDoc: function()
- {
- return this.$frame[0].contentWindow.document;
- },
- iframePage: function()
- {
- var doc = this.iframeDoc();
- if (doc.documentElement) doc.removeChild(doc.documentElement);
+ this.core.setCallback('drop', e);
- return doc;
- },
- iframeAddCss: function(css)
- {
- css = css || this.opts.css;
+ }, this));
- 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.$source.val());
- }
- else this.set(this.content, true, false);
-
- this.buildOptions();
- this.buildAfter();
- },
-
- // PLACEHOLDER
- placeholderInit: function()
- {
- if (this.opts.placeholder !== false)
- {
- this.placeholderText = this.opts.placeholder;
- this.opts.placeholder = true;
- }
- else
- {
- if (typeof this.$element.attr('placeholder') == 'undefined' || this.$element.attr('placeholder') == '')
- {
- this.opts.placeholder = false;
- }
- else
- {
- this.placeholderText = this.$element.attr('placeholder');
- this.opts.placeholder = true;
- }
- }
- },
- placeholderStart: function(html)
- {
- if (this.opts.placeholder === false)
- {
- return false;
- }
-
- if (this.isEmpty(html))
- {
- this.opts.focus = false;
- this.placeholderOnFocus();
- this.placeholderOnBlur();
-
- return this.placeholderGet();
- }
- else
- {
- this.placeholderOnBlur();
- }
-
- return false;
- },
- placeholderOnFocus: function()
- {
- this.$editor.on('focus.redactor_placeholder', $.proxy(this.placeholderFocus, this));
- },
- placeholderOnBlur: function()
- {
- this.$editor.on('blur.redactor_placeholder', $.proxy(this.placeholderBlur, this));
- },
- placeholderGet: function()
- {
- var ph = $('').data('redactor', 'verified')
- .attr('contenteditable', false).text(this.placeholderText);
-
- if (this.opts.linebreaks === false)
- {
- return $(' ').append(ph);
- }
- else return ph;
- },
- placeholderBlur: function()
- {
- var html = this.get();
- if (this.isEmpty(html))
- {
- this.placeholderOnFocus();
- this.$editor.html(this.placeholderGet());
- }
- },
- 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]);
- }
- else
- {
- this.focus();
- }
-
- this.sync();
- },
- placeholderRemoveFromEditor: function()
- {
- 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)
- {
-
- // disable browser's hot keys for bold and italic
- if (!this.opts.shortcuts)
- {
- if ((e.ctrlKey || e.metaKey) && (key === 66 || key === 73))
- {
- e.preventDefault();
- }
-
- return false;
- }
-
- $.each(this.opts.shortcuts, $.proxy(function(str, command)
- {
- var keys = str.split(',');
- for (var i in keys)
- {
- if (typeof keys[i] === 'string')
+ // click
+ this.$editor.on('click.redactor', $.proxy(function(e)
{
- this.shortcutsHandler(e, $.trim(keys[i]), $.proxy(function()
+ var type = 'click';
+ if ((this.core.getEvent() == 'click' || this.core.getEvent() == 'arrow'))
{
- eval(command);
- }, this));
+ type = false;
+ }
+
+ this.core.addEvent(type);
+ this.utils.disableSelectAll();
+ this.core.setCallback('click', e);
+
+ }, this));
+
+ // paste
+ this.$editor.on('paste.redactor', $.proxy(this.paste.init, this));
+
+ // keydown
+ this.$editor.on('keydown.redactor', $.proxy(this.keydown.init, this));
+
+ // keyup
+ this.$editor.on('keyup.redactor', $.proxy(this.keyup.init, this));
+
+ // textarea keydown
+ if ($.isFunction(this.opts.codeKeydownCallback))
+ {
+ this.$textarea.on('keydown.redactor-textarea', $.proxy(this.opts.codeKeydownCallback, this));
}
- }
-
- }, this));
-
-
- },
- shortcutsHandler: function(e, keys, origHandler)
- {
- // based on https://github.com/jeresig/jquery.hotkeys
- var hotkeysSpecialKeys =
- {
- 8: "backspace", 9: "tab", 10: "return", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
- 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
- 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", 59: ";", 61: "=",
- 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
- 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
- 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
- 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 173: "-", 186: ";", 187: "=",
- 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'"
- };
-
-
- var hotkeysShiftNums =
- {
- "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
- "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
- ".": ">", "/": "?", "\\": "|"
- };
-
- keys = keys.toLowerCase().split(" ");
- var special = hotkeysSpecialKeys[e.keyCode],
- character = String.fromCharCode( e.which ).toLowerCase(),
- modif = "", possible = {};
-
- $.each([ "alt", "ctrl", "meta", "shift"], function(index, specialKey)
- {
- if (e[specialKey + 'Key'] && special !== specialKey)
- {
- modif += specialKey + '+';
- }
- });
-
-
- if (special)
- {
- possible[modif + special] = true;
- }
-
- if (character)
- {
- possible[modif + character] = true;
- possible[modif + hotkeysShiftNums[character]] = true;
-
- // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
- if (modif === "shift+")
- {
- possible[hotkeysShiftNums[character]] = true;
- }
- }
-
- for (var i = 0, l = keys.length; i < l; i++)
- {
- if (possible[keys[i]])
- {
- e.preventDefault();
- return origHandler.apply(this, arguments);
- }
- }
- },
-
- // FOCUS
- focus: function()
- {
- if (!this.browser('opera'))
- {
- this.window.setTimeout($.proxy(this.focusSet, this, true), 1);
- }
- else
- {
- this.$editor.focus();
- }
- },
- focusWithSaveScroll: function()
- {
- if (this.browser('msie'))
- {
- var top = this.document.documentElement.scrollTop;
- }
-
- this.$editor.focus();
-
- if (this.browser('msie'))
- {
- this.document.documentElement.scrollTop = top;
- }
- },
- focusEnd: function()
- {
- if (!this.browser('mozilla'))
- {
- this.focusSet();
- }
- else
- {
- if (this.opts.linebreaks === false)
- {
- var last = this.$editor.children().last();
-
- this.$editor.focus();
- this.selectionEnd(last);
- }
- else
- {
- this.focusSet();
- }
- }
- },
- focusSet: function(collapse, element)
- {
- this.$editor.focus();
-
- if (typeof element == 'undefined')
- {
- element = this.$editor[0];
- }
-
- var range = this.getRange();
- range.selectNodeContents(element);
-
- // 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)
- {
- if (this.opts.visual) this.toggleCode(direct);
- else this.toggleVisual();
- },
- toggleVisual: function()
- {
- var html = this.$source.hide().val();;
- if (typeof this.modified !== 'undefined')
- {
- var modified = this.modified.replace(/\n/g, '');
-
- var thtml = html.replace(/\n/g, '');
- thtml = this.cleanRemoveSpaces(thtml, false);
-
- this.modified = this.cleanRemoveSpaces(modified, false) !== thtml;
- }
-
- 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)
+ // textarea keyup
+ if ($.isFunction(this.opts.codeKeyupCallback))
{
- this.buildBindKeyboard();
+ this.$textarea.on('keyup.redactor-textarea', $.proxy(this.opts.codeKeyupCallback, this));
}
- }
- this.callback('change', false, html);
- }
+ // focus
+ if ($.isFunction(this.opts.focusCallback))
+ {
+ this.$editor.on('focus.redactor', $.proxy(this.opts.focusCallback, this));
+ }
- 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;
-
-
- },
- toggleCode: function(direct)
- {
- 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();
- }
-
- var html = this.$source.val();
-
- // tidy html
- if (html !== '' && this.opts.tidyHtml)
- {
- this.$source.val(this.cleanHtml(html));
- }
-
- this.modified = html;
-
- this.$source.height(height).show().focus();
-
- // textarea indenting
- this.$source.on('keydown.redactor-textarea-indenting', this.textareaIndenting);
-
- this.buttonInactiveVisual();
- this.buttonActive('html');
- this.opts.visual = false;
- },
- textareaIndenting: 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;
- }
- },
-
- // AUTOSAVE
- autosave: function()
- {
- var savedHtml = false;
- this.autosaveInterval = setInterval($.proxy(function()
- {
- var html = this.get();
- if (savedHtml !== html)
- {
- var name = this.$source.attr('name');
- $.ajax({
- url: this.opts.autosave,
- type: 'post',
- data: 'name=' + name + '&' + name + '=' + escape(encodeURIComponent(html)),
- success: $.proxy(function(data)
- {
- var json = $.parseJSON(data);
- if (typeof json.error == 'undefined')
- {
- // success
- this.callback('autosave', false, json);
- }
- else
- {
- // error
- this.callback('autosaveError', false, json);
- }
-
- savedHtml = html;
-
- }, this)
+ var clickedElement;
+ $(document).on('mousedown', function(e) {
+ clickedElement = $(e.target);
});
+
+ // blur
+ this.$editor.on('blur.redactor', $.proxy(function(e)
+ {
+ if (this.rtePaste) return;
+
+ var $el = $(clickedElement);
+ if (!$el.hasClass('redactor-toolbar, redactor-dropdown') && !$el.is('#redactor-modal') && $el.parents('.redactor-toolbar, .redactor-dropdown, #redactor-modal').size() === 0)
+ {
+ this.utils.disableSelectAll();
+ if ($.isFunction(this.opts.blurCallback)) this.core.setCallback('blur', e);
+ }
+ }, this));
+ },
+ setHelpers: function()
+ {
+ // autosave
+ this.autosave.enable();
+
+ // placeholder
+ this.placeholder.enable();
+
+ // focus
+ if (this.opts.focus) setTimeout($.proxy(this.focus.setStart, this), 100);
+ if (this.opts.focusEnd) setTimeout($.proxy(this.focus.setEnd, this), 100);
+
+ },
+ plugins: function()
+ {
+ if (!this.opts.plugins) return;
+ if (!RedactorPlugins) return;
+
+ $.each(this.opts.plugins, $.proxy(function(i, s)
+ {
+ if (RedactorPlugins[s])
+ {
+ if (!$.isFunction(RedactorPlugins[s])) return;
+
+ this[s] = RedactorPlugins[s]();
+
+ var methods = this.getModuleMethods(this[s]);
+ var len = methods.length;
+
+ // bind methods
+ for (var z = 0; z < len; z++)
+ {
+ this[s][methods[z]] = this[s][methods[z]].bind(this);
+ }
+
+ if ($.isFunction(this[s].init)) this[s].init();
+ }
+
+ }, this));
+
+
+ },
+ disableMozillaEditing: function()
+ {
+ if (!this.utils.browser('mozilla')) return;
+
+ // FF fix
+ try {
+ document.execCommand('enableObjectResizing', false, false);
+ document.execCommand('enableInlineTableEditing', false, false);
+ } catch (e) {}
}
- }, this), this.opts.autosaveInterval*1000);
+ };
},
-
- // TOOLBAR
- toolbarBuild: function()
+ lang: function()
{
- // hide on mobile
- if (this.isMobile() && this.opts.buttonsHideOnMobile.length > 0)
- {
- $.each(this.opts.buttonsHideOnMobile, $.proxy(function(i, s)
+ return {
+ load: function()
{
- var index = this.opts.buttons.indexOf(s);
- this.opts.buttons.splice(index, 1);
-
- }, this));
- }
-
- // extend buttons
- if (this.opts.air)
- {
- this.opts.buttons = this.opts.airButtons;
- }
- else
- {
- if (!this.opts.buttonSource)
+ this.opts.curLang = this.opts.langs[this.opts.lang];
+ },
+ get: function(name)
{
+ return (typeof this.opts.curLang[name] != 'undefined') ? this.opts.curLang[name] : '';
+ }
+ };
+ },
+ toolbar: function()
+ {
+ return {
+ init: function()
+ {
+ return {
+ html:
+ {
+ title: this.lang.get('html'),
+ func: 'code.toggle'
+ },
+ formatting:
+ {
+ title: this.lang.get('formatting'),
+ dropdown:
+ {
+ p:
+ {
+ title: this.lang.get('paragraph'),
+ func: 'block.format'
+ },
+ blockquote:
+ {
+ title: this.lang.get('quote'),
+ func: 'block.format'
+ },
+ pre:
+ {
+ title: this.lang.get('code'),
+ func: 'block.format'
+ },
+ h1:
+ {
+ title: this.lang.get('header1'),
+ func: 'block.format'
+ },
+ h2:
+ {
+ title: this.lang.get('header2'),
+ func: 'block.format'
+ },
+ h3:
+ {
+ title: this.lang.get('header3'),
+ func: 'block.format'
+ },
+ h4:
+ {
+ title: this.lang.get('header4'),
+ func: 'block.format'
+ },
+ h5:
+ {
+ title: this.lang.get('header5'),
+ func: 'block.format'
+ }
+ }
+ },
+ bold:
+ {
+ title: this.lang.get('bold'),
+ func: 'inline.format'
+ },
+ italic:
+ {
+ title: this.lang.get('italic'),
+ func: 'inline.format'
+ },
+ deleted:
+ {
+ title: this.lang.get('deleted'),
+ func: 'inline.format'
+ },
+ underline:
+ {
+ title: this.lang.get('underline'),
+ func: 'inline.format'
+ },
+ unorderedlist:
+ {
+ title: '• ' + this.lang.get('unorderedlist'),
+ func: 'list.toggle'
+ },
+ orderedlist:
+ {
+ title: '1. ' + this.lang.get('orderedlist'),
+ func: 'list.toggle'
+ },
+ outdent:
+ {
+ title: '< ' + this.lang.get('outdent'),
+ func: 'indent.decrease'
+ },
+ indent:
+ {
+ title: '> ' + this.lang.get('indent'),
+ func: 'indent.increase'
+ },
+ image:
+ {
+ title: this.lang.get('image'),
+ func: 'image.show'
+ },
+ file:
+ {
+ title: this.lang.get('file'),
+ func: 'file.show'
+ },
+ link:
+ {
+ title: this.lang.get('link'),
+ dropdown:
+ {
+ link:
+ {
+ title: this.lang.get('link_insert'),
+ func: 'link.show'
+ },
+ unlink:
+ {
+ title: this.lang.get('unlink'),
+ func: 'link.unlink'
+ }
+ }
+ },
+ alignment:
+ {
+ title: this.lang.get('alignment'),
+ dropdown:
+ {
+ left:
+ {
+ title: this.lang.get('align_left'),
+ func: 'alignment.left'
+ },
+ center:
+ {
+ title: this.lang.get('align_center'),
+ func: 'alignment.center'
+ },
+ right:
+ {
+ title: this.lang.get('align_right'),
+ func: 'alignment.right'
+ },
+ justify:
+ {
+ title: this.lang.get('align_justify'),
+ func: 'alignment.justify'
+ }
+ }
+ },
+ horizontalrule:
+ {
+ title: this.lang.get('horizontalrule'),
+ func: 'line.insert'
+ }
+ };
+ },
+ build: function()
+ {
+ this.toolbar.hideButtons();
+ this.toolbar.hideButtonsOnMobile();
+ this.toolbar.isButtonSourceNeeded();
+
+ if (this.opts.buttons.length === 0) return;
+
+ this.$toolbar = this.toolbar.createContainer();
+
+ this.toolbar.setOverflow();
+ this.toolbar.append();
+ this.toolbar.setFormattingTags();
+ this.toolbar.loadButtons();
+ this.toolbar.setTabindex();
+ this.toolbar.setFixed();
+
+ // buttons response
+ if (this.opts.activeButtons)
+ {
+ this.$editor.on('mouseup.redactor keyup.redactor focus.redactor', $.proxy(this.observe.buttons, this));
+ }
+
+ },
+ createContainer: function()
+ {
+ return $('
');
- }
-
- // $ fix
- html = html.replace(/$/g, '$');
-
- html = this.cleanEmpty(html);
-
- this.$editor.html(html);
-
- // set no editable
- this.setNonEditable();
- this.setSpansVerified();
-
- 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 });
- }
-
- // set no editable
- this.setNonEditable();
- this.setSpansVerified();
- this.sync();
-
- },
- setFullpageOnInit: function(html)
- {
- this.fullpageDoctype = html.match(/^<\!doctype[^>]*>/i);
- if (this.fullpageDoctype && this.fullpageDoctype.length == 1)
- {
- html = html.replace(/^<\!doctype[^>]*>/i, '');
- }
-
- html = this.cleanSavePreCode(html, true);
- html = this.cleanConverters(html);
- html = this.cleanEmpty(html);
-
- // set code
- this.$editor.html(html);
-
- // set no editable
- this.setNonEditable();
- this.setSpansVerified();
- this.sync();
- },
- setFullpageDoctype: function()
- {
- if (this.fullpageDoctype && this.fullpageDoctype.length == 1)
- {
- var source = this.fullpageDoctype[0] + '\n' + this.$source.val();
- this.$source.val(source);
- }
- },
- setSpansVerified: function()
- {
- var spans = this.$editor.find('span');
- var replacementTag = 'inline';
-
- $.each(spans, function() {
- var outer = this.outerHTML;
-
- // Replace opening tag
- var regex = new RegExp('<' + this.tagName, 'gi');
- var newTag = outer.replace(regex, '<' + replacementTag);
-
- // Replace closing tag
- regex = new RegExp('' + this.tagName, 'gi');
- newTag = newTag.replace(regex, '' + replacementTag);
-
- $(this).replaceWith(newTag);
- });
-
- },
- setSpansVerifiedHtml: function(html)
- {
- html = html.replace(//, '
') html = '';
-
- // xhtml
- if (this.opts.xhtml)
- {
- var xhtmlTags = ['br', 'hr', 'img', 'link', 'input', 'meta'];
- $.each(xhtmlTags, function(i,s)
- {
- html = html.replace(new RegExp('<' + s + '(.*?[^\/$]?)>', 'gi'), '<' + s + '$1 />');
- });
-
- }
-
- // before callback
- html = this.callback('syncBefore', false, html);
-
- this.$source.val(html);
- this.setFullpageDoctype();
-
- // onchange & after callback
- this.callback('syncAfter', false, html);
-
- if (this.start === false)
- {
-
- if (typeof e != 'undefined')
- {
- switch(e.which)
- {
- case 37: // left
- break;
- case 38: // up
- break;
- case 39: // right
- break;
- case 40: // down
- break;
-
- default: this.callback('change', false, html);
- }
- }
- else
- {
- this.callback('change', false, html);
- }
- }
-
- },
- syncClean: function(html)
- {
- if (!this.opts.fullpage) html = this.cleanStripTags(html);
-
- // trim
- html = $.trim(html);
-
- // removeplaceholder
- html = this.placeholderRemoveFromCode(html);
-
- // remove space
- html = html.replace(//gi, '');
- html = html.replace(//gi, '');
- html = html.replace(/<\/a> /gi, '<\/a> ');
- html = html.replace(/\u200B/g, '');
-
- if (html == '' || html == '
\n?<\/(P|H[1-6]|LI|ADDRESS|SECTION|HEADER|FOOTER|ASIDE|ARTICLE)>/gi, '$1>');
-
- // remove image resize
- html = html.replace(/([\w\W]*?)<\/span>/gi, '$3
');
- html = html.replace(/(.*?)<\/span>/gi, '');
- html = html.replace(/(.*?)<\/span>/gi, '');
-
- // remove empty lists
- html = html.replace(/<(ul|ol)>\s*\t*\n*<\/(ul|ol)>/gi, '');
-
- // remove font
- if (this.opts.cleanFontTag)
- {
- html = html.replace(/([\w\W]*?)<\/font>/gi, '$2');
- }
-
- // remove spans
- html = html.replace(/([\w\W]*?)<\/span>/gi, '$2');
- html = html.replace(/
/gi, '
');
-
- // special characters
- html = html.replace(/&/gi, '&');
- html = html.replace(/\u2122/gi, '™');
- html = html.replace(/\u00a9/gi, '©');
- html = html.replace(/\u2026/gi, '…');
- html = html.replace(/\u2014/gi, '—');
- html = html.replace(/\u2010/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');
- // FF fix bug with line-height rendering
- else if (this.browser('mozilla') && this.opts.linebreaks)
- {
- this.$editor.css('min-height', '45px');
- }
- // FF fix bug with line-height rendering
- if (this.browser('mozilla') && this.opts.linebreaks)
- {
- this.$editor.css('padding-bottom', '10px');
- }
-
-
- if (this.opts.maxHeight)
- {
- this.opts.autoresize = false;
- this.sourceHeight = this.opts.maxHeight;
- }
- if (this.opts.wym) this.$editor.addClass('redactor_editor_wym');
- if (this.opts.typewriter) this.$editor.addClass('redactor-editor-typewriter');
- if (!this.opts.autoresize) $source.css('height', this.sourceHeight);
-
- },
- buildAfter: function()
- {
- this.start = false;
-
- // load toolbar
- if (this.opts.toolbar)
- {
- this.opts.toolbar = this.toolbarInit(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()
- {
- this.dblEnter = 0;
-
- if (this.opts.dragUpload && (this.opts.imageUpload !== false || this.opts.s3 !== false))
- {
- this.$editor.on('drop.redactor', $.proxy(this.buildEventDrop, this));
- }
-
- this.$editor.on('click.redactor', $.proxy(function()
- {
- this.selectall = false;
-
- }, this));
-
- this.$editor.on('input.redactor', $.proxy(this.sync, 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));
- }
-
- var clickedElement;
- $(document).mousedown(function(e) {
- clickedElement = $(e.target);
- });
-
- // blur callback
- this.$editor.on('blur.redactor', $.proxy(function(e)
- {
- if (!$(clickedElement).hasClass('redactor_toolbar') && $(clickedElement).parents('.redactor_toolbar').size() == 0)
- {
- this.selectall = false;
- if ($.isFunction(this.opts.blurCallback)) this.callback('blur', e);
- }
- }, this));
-
- },
- buildEventDrop: function(e)
- {
- e = e.originalEvent || e;
-
- if (window.FormData === undefined || !e.dataTransfer) 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();
-
- this.showProgressBar();
-
- if (this.opts.s3 === false)
- {
- this.dragUploadAjax(this.opts.imageUpload, file, true, e, this.opts.imageUploadParam);
- }
- else
- {
- this.s3uploadFile(file);
- }
-
-
- },
- buildEventPaste: function(e)
- {
- var oldsafari = false;
- if (this.browser('webkit') && navigator.userAgent.indexOf('Chrome') === -1)
- {
- var arr = this.browser('version').split('.');
- if (arr[0] < 536) oldsafari = true;
- }
-
- if (oldsafari) return true;
-
- // paste except opera (not webkit)
- if (this.browser('opera')) return true;
-
- // clipboard upload
- if (this.opts.clipboardUpload && this.buildEventClipboardUpload(e)) return true;
-
- if (this.opts.cleanup)
- {
- this.rtePaste = true;
-
- this.selectionSave();
-
- if (!this.selectall)
- {
- if (this.opts.autoresize === true && this.fullscreen !== true)
- {
- this.$editor.height(this.$editor.height());
- this.saveScroll = this.document.body.scrollTop;
+ return (typeof data == 'undefined') ? callback.call(this, e) : callback.call(this, e, data);
}
else
{
- this.saveScroll = this.$editor.scrollTop();
+ return (typeof data == 'undefined') ? e : data;
}
- }
-
- var frag = this.extractContent();
-
- setTimeout($.proxy(function()
+ },
+ destroy: function()
{
- var pastedFrag = this.extractContent();
- this.$editor.append(frag);
+ this.core.setCallback('destroy');
- this.selectionRestore();
+ // off events and remove data
+ this.$element.off('.redactor').removeData('redactor');
+ this.$editor.off('.redactor');
- var html = this.getFragmentHtml(pastedFrag);
- this.pasteClean(html);
+ // common
+ this.$editor.removeClass('redactor-editor redactor-linebreaks redactor-placeholder');
+ this.$editor.removeAttr('contenteditable');
- if (this.opts.autoresize === true && this.fullscreen !== true) this.$editor.css('height', 'auto');
+ var html = this.code.get();
- }, this), 1);
- }
+ if (this.build.isTextarea())
+ {
+ this.$box.after(this.$element);
+ this.$box.remove();
+ this.$element.val(html).show();
+ }
+ else
+ {
+ this.$box.after(this.$editor);
+ this.$box.remove();
+ this.$element.html(html).show();
+ }
+
+ // paste box
+ if (this.$pasteBox) this.$pasteBox.remove();
+
+ // modal
+ if (this.$modalBox) this.$modalBox.remove();
+ if (this.$modalOverlay) this.$modalOverlay.remove();
+
+ // buttons tooltip
+ $('.redactor-toolbar-tooltip').remove();
+
+ // autosave
+ clearInterval(this.autosaveInterval);
+
+ }
+ };
},
- buildEventClipboardUpload: function(e)
+ build: function()
{
- var event = e.originalEvent || e;
- this.clipboardFilePaste = false;
-
-
- if (typeof(event.clipboardData) === 'undefined') return false;
- if (event.clipboardData.items)
- {
- var file = event.clipboardData.items[0].getAsFile();
- if (file !== null)
+ return {
+ run: function()
{
- this.bufferSet();
- this.clipboardFilePaste = true;
- var reader = new FileReader();
- reader.onload = $.proxy(this.pasteClipboardUpload, this);
- reader.readAsDataURL(file);
+ this.build.createContainerBox();
+ this.build.loadContent();
+ this.build.loadEditor();
+ this.build.enableEditor();
+ this.build.setCodeAndCall();
- return true;
- }
- }
-
- return false;
-
- },
- buildEventKeydown: function(e)
- {
- if (this.rtePaste) return false;
-
- var key = e.which;
- var ctrl = e.ctrlKey || e.metaKey;
- var parent = this.getParent();
- var current = this.getCurrent();
- var block = this.getBlock();
- var pre = false;
-
- this.callback('keydown', e);
-
- /*
- firefox cmd+left/Cmd+right browser back/forward fix -
- http://joshrhoderick.wordpress.com/2010/05/05/how-firefoxs-command-key-bug-kills-usability-on-the-mac/
- */
- if (this.browser('mozilla') && "modify" in window.getSelection())
- {
- if ((ctrl) && (e.keyCode===37 || e.keyCode===39))
+ },
+ isTextarea: function()
{
- var selection = this.getSelection();
- var lineOrWord = (e.metaKey ? "line" : "word");
- if (e.keyCode===37)
+ return (this.$element[0].tagName === 'TEXTAREA');
+ },
+ createContainerBox: function()
+ {
+ this.$box = $('');
+ },
+ createTextarea: function()
+ {
+ this.$textarea = $('').attr('name', this.build.getTextareaName());
+ },
+ getTextareaName: function()
+ {
+ var name = this.$element.attr('id');
+ if (typeof(name) == 'undefined')
{
- selection.modify("extend","left",lineOrWord);
- if (!e.shiftKey)
- {
- selection.collapseToStart();
- }
- }
- if (e.keyCode===39)
- {
- selection.modify("extend","right",lineOrWord);
- if (!e.shiftKey)
- {
- selection.collapseToEnd();
- }
+ name = 'content-' + this.uuid;
}
- e.preventDefault();
- }
- }
-
-
- this.imageResizeHide(false);
-
- // pre & down
- if ((parent && $(parent).get(0).tagName === 'PRE') || (current && $(current).get(0).tagName === 'PRE'))
- {
- pre = true;
- if (key === this.keyCode.DOWN) this.insertAfterLastElement(block);
- }
-
- // down
- if (key === this.keyCode.DOWN)
- {
- if (parent && $(parent)[0].tagName === 'BLOCKQUOTE') this.insertAfterLastElement(parent);
- if (current && $(current)[0].tagName === 'BLOCKQUOTE') this.insertAfterLastElement(current);
-
- if (parent && $(parent)[0].tagName === 'P' && $(parent).parent()[0].tagName == 'BLOCKQUOTE')
+ return name;
+ },
+ loadContent: function()
{
- this.insertAfterLastElement(parent, $(parent).parent()[0]);
- }
- if (current && $(current)[0].tagName === 'P' && parent && $(parent)[0].tagName == 'BLOCKQUOTE')
+ var func = (this.build.isTextarea()) ? 'val' : 'html';
+ this.content = $.trim(this.$element[func]());
+ },
+ enableEditor: function()
{
- this.insertAfterLastElement(current, parent);
- }
- }
-
- // shortcuts setup
- this.shortcuts(e, key);
-
- // buffer setup
- if (ctrl && key === 90 && !e.shiftKey && !e.altKey) // z key
- {
- e.preventDefault();
- if (this.opts.buffer.length) this.bufferUndo();
- else this.document.execCommand('undo', false, false);
- return;
- }
- // undo
- else if (ctrl && key === 90 && e.shiftKey && !e.altKey)
- {
- e.preventDefault();
- if (this.opts.rebuffer.length != 0) this.bufferRedo();
- else this.document.execCommand('redo', false, false);
- return;
- }
-
- // space
- if (key == 32)
- {
- this.bufferSet();
- }
-
- // select all
- if (ctrl && key === 65)
- {
- this.bufferSet();
- this.selectall = true;
- }
- else if (key != this.keyCode.LEFT_WIN && !ctrl)
- {
- this.selectall = false;
- }
-
- // enter
- if (key == this.keyCode.ENTER && !e.shiftKey && !e.ctrlKey && !e.metaKey)
- {
- // remove selected content on enter
- var range = this.getRange();
- if (range && range.collapsed === false)
+ this.$editor.attr({ 'contenteditable': true, 'dir': this.opts.direction });
+ },
+ loadEditor: function()
{
- sel = this.getSelection();
- if (sel.rangeCount)
+ var func = (this.build.isTextarea()) ? 'fromTextarea' : 'fromElement';
+ this.build[func]();
+ },
+ fromTextarea: function()
+ {
+ this.$editor = $('');
+ this.$textarea = this.$element;
+ this.$box.insertAfter(this.$element).append(this.$editor).append(this.$element);
+ this.$editor.addClass('redactor-editor');
+
+ this.$element.hide();
+ },
+ fromElement: function()
+ {
+ this.$editor = this.$element;
+ this.build.createTextarea();
+ this.$box.insertAfter(this.$editor).append(this.$editor).append(this.$textarea);
+ this.$editor.addClass('redactor-editor');
+
+ this.$textarea.hide();
+ },
+ setCodeAndCall: function()
+ {
+ // set code
+ this.code.set(this.content);
+
+ this.build.setOptions();
+ this.build.callEditor();
+
+ // code mode
+ if (!this.opts.visual)
{
- range.deleteContents();
+ setTimeout($.proxy(this.code.showCode, this), 200);
}
- }
-
- // In ie, opera in the tables are created paragraphs, fix it.
- if (this.browser('msie') && (parent.nodeType == 1 && (parent.tagName == 'TD' || parent.tagName == 'TH')))
+ },
+ callEditor: function()
{
- e.preventDefault();
- this.bufferSet();
- this.insertNode(document.createElement('br'));
- this.callback('enter', e);
- return false;
- }
+ this.build.disableMozillaEditing();
+ this.build.setEvents();
+ this.build.setHelpers();
- // blockquote exit
- if (block && (block.tagName == 'BLOCKQUOTE' || $(block).parent()[0].tagName == 'BLOCKQUOTE'))
- {
- if (this.isEndOfElement())
+ // load toolbar
+ if (this.opts.toolbar)
{
- if (this.dblEnter == 1)
- {
- var element;
- var last;
- if (block.tagName == 'BLOCKQUOTE')
- {
- last = 'br';
- element = block;
- }
- else
- {
- last = 'p';
- element = $(block).parent()[0];
- }
-
- e.preventDefault();
- this.insertingAfterLastElement(element);
- this.dblEnter = 0;
-
- if (last == 'p')
- {
- $(block).parent().find('p').last().remove();
- }
- else
- {
- var tmp = $.trim($(block).html());
- $(block).html(tmp.replace(/
$/i, ''));
- }
-
- return;
- }
- else this.dblEnter++;
- }
- else this.dblEnter++;
- }
-
- // pre
- if (pre === true)
- {
- return this.buildEventKeydownPre(e, current);
- }
- else
- {
- if (!this.opts.linebreaks)
- {
- // lists exit
- if (block && block.tagName == 'LI')
- {
- var listCurrent = this.getBlock();
- if (listCurrent !== false || listCurrent.tagName === 'LI')
- {
- var listText = $.trim($(block).text());
- var listCurrentText = $.trim($(listCurrent).text());
- if (listText == ''
- && listCurrentText == ''
- && $(listCurrent).next('li').size() == 0
- && $(listCurrent).parents('li').size() == 0)
- {
- this.bufferSet();
-
- var $list = $(listCurrent).closest('ol, ul');
- $(listCurrent).remove();
- var node = $('
' + this.opts.invisibleSpace);
-
- $(current).replaceWith(node);
- this.selectionStart(node);
- this.sync();
- }
-
- if (typeof current.nodeValue !== 'undefined' && current.nodeValue !== null)
- {
- if (current.remove && current.nodeType === 3 && current.nodeValue.match(/[^\u200B]/g) == null)
- {
- $(current).prev().remove();
- this.sync();
- }
- }
- },
- buildEventKeydownInsertLineBreak: function(e)
- {
- this.bufferSet();
- e.preventDefault();
- this.insertLineBreak();
- this.callback('enter', e);
- return;
- },
- buildEventKeyup: function(e)
- {
- if (this.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);
+ },
+ setFormattingTags: function()
+ {
+ $.each(this.opts.toolbar.formatting.dropdown, $.proxy(function (i, s)
+ {
+ if ($.inArray(i, this.opts.formatting) == -1) delete this.opts.toolbar.formatting.dropdown[i];
+ }, this));
+
+ },
+ loadButtons: function()
+ {
+ $.each(this.opts.buttons, $.proxy(function(i, btnName)
+ {
+ if (!this.opts.toolbar[btnName]) return;
+
+ if (this.opts.fileUpload === false && btnName === 'file') return true;
+ if ((this.opts.imageUpload === false && this.opts.s3 === false) && btnName === 'image') return true;
+
+ var btnObject = this.opts.toolbar[btnName];
+ this.$toolbar.append($('
').addClass('redactor_toolbar').attr('id', 'redactor_toolbar_' + this.uuid);
-
- if (this.opts.typewriter)
- {
- this.$toolbar.addClass('redactor-toolbar-typewriter');
- }
-
- if (this.opts.toolbarOverflow && this.isMobile())
- {
- this.$toolbar.addClass('redactor-toolbar-overflow');
- }
-
- if (this.opts.air)
- {
- // air box
- this.$air = $('