Created
September 15, 2014 11:43
-
-
Save ivan-ivanic-cm/4e9b6d78b0476d5fde9c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/library/class_upfront_theme.php b/library/class_upfront_theme.php | |
| index d3559e0..188d532 100644 | |
| --- a/library/class_upfront_theme.php | |
| +++ b/library/class_upfront_theme.php | |
| @@ -80,19 +80,19 @@ class Upfront_Theme { | |
| return $this->regions; | |
| } | |
| - public function get_default_layout($cascade, $layout_slug = "", $add_global_regions = false) { | |
| + public function get_default_layout($cascade, $layout_slug = "") { | |
| $regions = new Upfront_Layout_Maker(); | |
| $template_path = $this->find_default_layout($cascade, $layout_slug); | |
| $current_theme = Upfront_ChildTheme::get_instance(); | |
| - if ($add_global_regions && $current_theme && $current_theme->has_global_region('header')) { | |
| + if ($current_theme && $current_theme->has_global_region('header')) { | |
| include(get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'global-regions' . DIRECTORY_SEPARATOR . 'header.php'); | |
| } | |
| require $template_path; | |
| - if ($add_global_regions && $current_theme && $current_theme->has_global_region('footer')) { | |
| + if ($current_theme && $current_theme->has_global_region('footer')) { | |
| include(get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'global-regions' . DIRECTORY_SEPARATOR . 'footer.php'); | |
| } | |
| @@ -320,7 +320,7 @@ class Upfront_Virtual_Region { | |
| $breakpoint_data[$breakpoint->get_id()]['col'] = $wrapper_col; | |
| } | |
| } | |
| - | |
| + | |
| } | |
| if ( $group && $this->modules[$group] ){ | |
| $class = $this->get_property('class', $this->modules[$group]['wrappers'][$this->current_group_wrapper]); | |
| @@ -507,16 +507,12 @@ class Upfront_Virtual_Region { | |
| public function add_group($options){ | |
| $properties = array(); | |
| - if(isset($options['id']) && !empty($options['id'])) | |
| + if(!isset($options['id'])) | |
| $properties['element_id'] = $options['id']; | |
| - if(isset($options['breakpoint']) && !empty($options['breakpoint'])) | |
| - $properties['breakpoint'] = $options['breakpoint']; | |
| if(!isset($options['close_wrapper'])) | |
| $options['close_wrapper'] = true; | |
| if(!isset($options['new_line'])) | |
| $options['new_line'] = false; | |
| - if(!isset($options['wrapper_id'])) | |
| - $options['wrapper_id'] = false; | |
| $pos = array_merge(array( | |
| 'columns' => 24, | |
| 'margin_left' => 0, | |
| @@ -528,7 +524,7 @@ class Upfront_Virtual_Region { | |
| 'margin-top' => $pos['margin_top'] | |
| ); | |
| if(!$this->current_wrapper) | |
| - $this->start_wrapper($options['wrapper_id'], $options['new_line']); | |
| + $this->start_wrapper(false, $options['new_line']); | |
| $this->start_module_group($position, $properties); | |
| $group_id = $this->current_group; | |
| @@ -648,15 +644,15 @@ class Upfront_Layout_Maker { | |
| else | |
| $side_regions_after[] = $sidedata; | |
| } | |
| - usort($side_regions_before, array(Upfront_Theme, '_sort_region')); | |
| - usort($side_regions_after, array(Upfront_Theme, '_sort_region')); | |
| - | |
| + usort($side_regions_before, array("Upfront_Theme", '_sort_region')); | |
| + usort($side_regions_after, array("Upfront_Theme", '_sort_region')); | |
| + | |
| foreach($side_regions_before as $side){ | |
| $regions[] = $side; | |
| } | |
| - | |
| + | |
| $regions[] = $region; | |
| - | |
| + | |
| foreach($side_regions_after as $side){ | |
| $regions[] = $side; | |
| } | |
| @@ -680,8 +676,7 @@ abstract class Upfront_ChildTheme implements IUpfront_Server { | |
| $this->version = wp_get_theme()->version; | |
| $this->themeSettings = new Upfront_Theme_Settings(get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'settings.php'); | |
| self::$instance = $this; | |
| - //add_filter('upfront_create_default_layout', array($this, 'load_page_regions'), 10, 3); // Soooo... this no longer works, yay | |
| - add_filter('upfront_override_layout_data', array($this, 'load_page_regions'), 10, 2); // This goes in instead of the above ^ | |
| + add_filter('upfront_create_default_layout', array($this, 'load_page_regions'), 10, 3); | |
| add_filter('upfront_get_layout_properties', array($this, 'getLayoutProperties')); | |
| add_filter('upfront_get_theme_fonts', array($this, 'getThemeFonts'), 10, 2); | |
| add_filter('upfront_get_theme_colors', array($this, 'getThemeColors'), 10, 2); | |
| @@ -876,7 +871,7 @@ abstract class Upfront_ChildTheme implements IUpfront_Server { | |
| public function getResponsiveSettings($settings) { | |
| if (empty($settings) === false) return $settings; | |
| - $properties = $this->themeSettings->get('responsive_settings'); | |
| + $properties = $this->themeSettings->get('responsive'); | |
| if (!empty($properties)) { | |
| $properties = json_decode($properties, true); | |
| } | |
| @@ -999,12 +994,12 @@ abstract class Upfront_ChildTheme implements IUpfront_Server { | |
| */ | |
| } | |
| - public function load_page_regions($data, $ids/*, $cascade*/){ | |
| + public function load_page_regions($data, $ids, $cascade){ | |
| $layoutId = $this->_get_page_default_layout($ids); | |
| if($layoutId){ | |
| $theme = Upfront_Theme::get_instance(); | |
| $ids['theme_defined'] = $layoutId; | |
| - $data['regions'] = $theme->get_default_layout($ids, $layoutId); | |
| + $data['regions'] = $theme->get_default_layout($ids); | |
| //$data['regions'] = $theme->get_default_layout(array(), $layoutId); | |
| } | |
| //return apply_filters('upfront_augment_theme_layout', $data); // So, this doesn't work anymore either. Yay. | |
| diff --git a/scripts/redactor/redactor.js b/scripts/redactor/redactor.js | |
| index f9d9781..76081af 100755 | |
| --- a/scripts/redactor/redactor.js | |
| +++ b/scripts/redactor/redactor.js | |
| @@ -1,15 +1,14 @@ | |
| /* | |
| - Redactor v9.1.8 | |
| - Updated: Nov 20, 2013 | |
| + Redactor v9.2.6 | |
| + Updated: Jul 19, 2014 | |
| http://imperavi.com/redactor/ | |
| - Copyright (c) 2009-2013, Imperavi LLC. | |
| + Copyright (c) 2009-2014, Imperavi LLC. | |
| License: http://imperavi.com/redactor/license/ | |
| Usage: $('#content').redactor(); | |
| */ | |
| - | |
| (function($) | |
| { | |
| var uuid = 0; | |
| @@ -31,6 +30,9 @@ | |
| 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 reUrlVimeo = /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/; | |
| + | |
| // Plugin | |
| $.fn.redactor = function(options) | |
| { | |
| @@ -71,7 +73,7 @@ | |
| } | |
| $.Redactor = Redactor; | |
| - $.Redactor.VERSION = '9.1.8'; | |
| + $.Redactor.VERSION = '9.2.6'; | |
| $.Redactor.opts = { | |
| // settings | |
| @@ -86,12 +88,15 @@ | |
| placeholder: false, | |
| + typewriter: false, | |
| wym: false, | |
| mobile: true, | |
| cleanup: true, | |
| tidyHtml: true, | |
| pastePlainText: false, | |
| removeEmptyTags: true, | |
| + cleanSpaces: true, | |
| + cleanFontTag: true, | |
| templateVars: false, | |
| xhtml: false, | |
| @@ -101,29 +106,43 @@ | |
| autoresize: true, | |
| minHeight: false, | |
| maxHeight: false, | |
| - shortcuts: true, | |
| + 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: false, | |
| autosave: false, // false or url | |
| autosaveInterval: 60, // seconds | |
| plugins: false, // array | |
| - linkAnchor: true, | |
| - linkEmail: true, | |
| + //linkAnchor: true, | |
| + //linkEmail: true, | |
| linkProtocol: 'http://', | |
| linkNofollow: false, | |
| linkSize: 50, | |
| + predefinedLinks: false, // json url (ex. /some-url.json ) or false | |
| imageFloatMargin: '10px', | |
| - imageGetJson: false, // url (ex. /folder/images.json ) or false | |
| + imageGetJson: false, // json url (ex. /some-images.json ) or false | |
| + dragUpload: true, // false | |
| + imageTabLink: true, | |
| imageUpload: false, // url | |
| imageUploadParam: 'file', // input name | |
| + imageResizable: true, | |
| + | |
| fileUpload: false, // url | |
| fileUploadParam: 'file', // input name | |
| clipboardUpload: true, // or false | |
| clipboardUploadUrl: false, // url | |
| - dragUpload: true, // false | |
| dnbImageTypes: ['image/png', 'image/jpeg', 'image/gif'], // or false | |
| @@ -139,7 +158,7 @@ | |
| tabFocus: true, | |
| air: false, | |
| - airButtons: ['formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent'], | |
| + airButtons: ['formatting', 'bold', 'italic', 'deleted', 'unorderedlist', 'orderedlist', 'outdent', 'indent'], | |
| toolbar: true, | |
| toolbarFixed: false, | |
| @@ -147,15 +166,16 @@ | |
| toolbarFixedTopOffset: 0, // pixels | |
| toolbarFixedBox: false, | |
| toolbarExternal: false, // ID selector | |
| + toolbarOverflow: false, | |
| buttonSource: true, | |
| - buttonSeparator: '<li class="redactor_separator"></li>', | |
| + buttons: ['html', 'formatting', 'bold', 'italic', 'deleted', 'unorderedlist', 'orderedlist', | |
| + 'outdent', 'indent', 'image', 'video', 'file', 'table', 'link', 'alignment', '|', | |
| + 'horizontalrule'], // 'underline', 'alignleft', 'aligncenter', 'alignright', 'justify' | |
| + buttonsHideOnMobile: [], | |
| - 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'], | |
| + activeButtons: ['deleted', 'italic', 'bold', 'underline', 'unorderedlist', 'orderedlist', | |
| + 'alignleft', 'aligncenter', 'alignright', 'justify', 'table'], | |
| activeButtonsStates: { | |
| b: 'bold', | |
| strong: 'bold', | |
| @@ -170,7 +190,6 @@ | |
| td: 'table', | |
| table: 'table' | |
| }, | |
| - activeButtonsAdd: false, // object, ex.: { tag: 'buttonName' } | |
| formattingTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], | |
| @@ -206,6 +225,8 @@ | |
| 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: { | |
| @@ -255,6 +276,7 @@ | |
| none: 'None', | |
| left: 'Left', | |
| right: 'Right', | |
| + center: 'Center', | |
| image_web_link: 'Image Web Link', | |
| text: 'Text', | |
| mailto: 'Email', | |
| @@ -301,7 +323,6 @@ | |
| // Initialization | |
| init: function(el, options) | |
| { | |
| - | |
| this.rtePaste = false; | |
| this.$element = this.$source = $(el); | |
| this.uuid = uuid++; | |
| @@ -377,6 +398,12 @@ | |
| // load lang | |
| this.opts.curLang = this.opts.langs[this.opts.lang]; | |
| + // extend shortcuts | |
| + $.extend(this.opts.shortcuts, this.opts.shortcutsAdd); | |
| + | |
| + // init placeholder | |
| + this.placeholderInit(); | |
| + | |
| // Build | |
| this.buildStart(); | |
| @@ -586,16 +613,6 @@ | |
| } | |
| } | |
| }, | |
| - fontcolor: | |
| - { | |
| - title: lang.fontcolor, | |
| - func: 'show' | |
| - }, | |
| - backcolor: | |
| - { | |
| - title: lang.backcolor, | |
| - func: 'show' | |
| - }, | |
| alignment: | |
| { | |
| title: lang.alignment, | |
| @@ -639,7 +656,7 @@ | |
| title: lang.align_right, | |
| func: 'alignmentRight' | |
| }, | |
| - justify: | |
| + alignjustify: | |
| { | |
| title: lang.align_justify, | |
| func: 'alignmentJustify' | |
| @@ -694,6 +711,11 @@ | |
| $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(); | |
| @@ -738,26 +760,32 @@ | |
| 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.placeholderRemove(); | |
| + 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); | |
| + if (this.opts.linebreaks === false) html = this.cleanConverters(html); | |
| else html = html.replace(/<p(.*?)>([\w\W]*?)<\/p>/gi, '$2<br>'); | |
| } | |
| + // $ fix | |
| + html = html.replace(/&#36;/g, '$'); | |
| + | |
| html = this.cleanEmpty(html); | |
| this.$editor.html(html); | |
| @@ -765,6 +793,7 @@ | |
| // set no editable | |
| this.setNonEditable(); | |
| this.setSpansVerified(); | |
| + | |
| this.sync(); | |
| }, | |
| setCodeIframe: function(html) | |
| @@ -794,6 +823,12 @@ | |
| }, | |
| 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); | |
| @@ -806,6 +841,14 @@ | |
| 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'); | |
| @@ -837,7 +880,7 @@ | |
| }, | |
| // SYNC | |
| - sync: function() | |
| + sync: function(e) | |
| { | |
| var html = ''; | |
| @@ -847,9 +890,17 @@ | |
| else html = this.$editor.html(); | |
| html = this.syncClean(html); | |
| - //html = this.cleanRemoveSpaces(html); | |
| html = this.cleanRemoveEmptyTags(html); | |
| + // is there a need to synchronize | |
| + var source = this.cleanRemoveSpaces(this.$source.val(), false); | |
| + var editor = this.cleanRemoveSpaces(html, false); | |
| + | |
| + if (source == editor) | |
| + { | |
| + // do not sync | |
| + return false; | |
| + } | |
| // fix second level up ul, ol | |
| html = html.replace(/<\/li><(ul|ol)>([\w\W]*?)<\/(ul|ol)>/gi, '<$1>$2</$1></li>'); | |
| @@ -870,13 +921,34 @@ | |
| html = this.callback('syncBefore', false, html); | |
| this.$source.val(html); | |
| + this.setFullpageDoctype(); | |
| // onchange & after callback | |
| this.callback('syncAfter', false, html); | |
| if (this.start === false) | |
| { | |
| - this.callback('change', false, html); | |
| + | |
| + 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); | |
| + } | |
| } | |
| }, | |
| @@ -884,6 +956,7 @@ | |
| { | |
| if (!this.opts.fullpage) html = this.cleanStripTags(html); | |
| + // trim | |
| html = $.trim(html); | |
| // removeplaceholder | |
| @@ -893,6 +966,12 @@ | |
| html = html.replace(/​/gi, ''); | |
| html = html.replace(/​/gi, ''); | |
| html = html.replace(/<\/a> /gi, '<\/a> '); | |
| + html = html.replace(/\u200B/g, ''); | |
| + | |
| + if (html == '<p></p>' || html == '<p> </p>' || html == '<p> </p>') | |
| + { | |
| + html = ''; | |
| + } | |
| // link nofollow | |
| if (this.opts.linkNofollow) | |
| @@ -912,25 +991,41 @@ | |
| html = html.replace(/<br\s?\/?>\n?<\/(P|H[1-6]|LI|ADDRESS|SECTION|HEADER|FOOTER|ASIDE|ARTICLE)>/gi, '</$1>'); | |
| // remove image resize | |
| - html = html.replace(/<span(.*?)id="redactor-image-box"(.*?)>([\w\W]*?)<img(.*?)><\/span>/i, '$3<img$4>'); | |
| - html = html.replace(/<span(.*?)id="redactor-image-resizer"(.*?)>(.*?)<\/span>/i, ''); | |
| - html = html.replace(/<span(.*?)id="redactor-image-editter"(.*?)>(.*?)<\/span>/i, ''); | |
| + html = html.replace(/<span(.*?)id="redactor-image-box"(.*?)>([\w\W]*?)<img(.*?)><\/span>/gi, '$3<img$4>'); | |
| + html = html.replace(/<span(.*?)id="redactor-image-resizer"(.*?)>(.*?)<\/span>/gi, ''); | |
| + html = html.replace(/<span(.*?)id="redactor-image-editter"(.*?)>(.*?)<\/span>/gi, ''); | |
| + | |
| + // remove empty lists | |
| + html = html.replace(/<(ul|ol)>\s*\t*\n*<\/(ul|ol)>/gi, ''); | |
| // remove font | |
| - html = html.replace(/<font(.*?)>([\w\W]*?)<\/font>/gi, '$2'); | |
| + if (this.opts.cleanFontTag) | |
| + { | |
| + html = html.replace(/<font(.*?)>([\w\W]*?)<\/font>/gi, '$2'); | |
| + } | |
| // remove spans | |
| html = html.replace(/<span(.*?)>([\w\W]*?)<\/span>/gi, '$2'); | |
| + html = html.replace(/<inline>([\w\W]*?)<\/inline>/gi, '$1'); | |
| html = html.replace(/<inline>/gi, '<span>'); | |
| html = html.replace(/<inline /gi, '<span '); | |
| html = html.replace(/<\/inline>/gi, '</span>'); | |
| - html = html.replace(/<span(.*?)class="redactor_placeholder"(.*?)>([\w\W]*?)<\/span>/gi, ''); | |
| - // fixes | |
| - html = html.replace(/&/gi, '&'); | |
| - html = html.replace(/™/gi, '™'); | |
| - html = html.replace(/©/gi, '©'); | |
| + if (this.opts.removeEmptyTags) | |
| + { | |
| + html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1'); | |
| + } | |
| + | |
| + html = html.replace(/<span(.*?)class="redactor_placeholder"(.*?)>([\w\W]*?)<\/span>/gi, ''); | |
| + html = html.replace(/<img(.*?)contenteditable="false"(.*?)>/gi, '<img$1$2>'); | |
| + // 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); | |
| @@ -938,6 +1033,7 @@ | |
| }, | |
| + | |
| // BUILD | |
| buildStart: function() | |
| { | |
| @@ -1039,14 +1135,29 @@ | |
| // 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; | |
| - $source.css('max-height', this.opts.maxHeight + 'px'); | |
| + 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() | |
| { | |
| @@ -1104,11 +1215,18 @@ | |
| { | |
| this.dblEnter = 0; | |
| - if (this.opts.dragUpload && this.opts.imageUpload !== false) | |
| + 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)); | |
| @@ -1161,18 +1279,18 @@ | |
| this.bufferSet(); | |
| - var progress = $('<div id="redactor-progress-drag" class="redactor-progress redactor-progress-striped"><div id="redactor-progress-bar" class="redactor-progress-bar" style="width: 100%;"></div></div>'); | |
| - $(document.body).append(progress); | |
| + this.showProgressBar(); | |
| if (this.opts.s3 === false) | |
| { | |
| - this.dragUploadAjax(this.opts.imageUpload, file, true, progress, e, this.opts.imageUploadParam); | |
| + this.dragUploadAjax(this.opts.imageUpload, file, true, e, this.opts.imageUploadParam); | |
| } | |
| else | |
| { | |
| this.s3uploadFile(file); | |
| } | |
| + | |
| }, | |
| buildEventPaste: function(e) | |
| { | |
| @@ -1232,6 +1350,7 @@ | |
| var event = e.originalEvent || e; | |
| this.clipboardFilePaste = false; | |
| + | |
| if (typeof(event.clipboardData) === 'undefined') return false; | |
| if (event.clipboardData.items) | |
| { | |
| @@ -1265,6 +1384,38 @@ | |
| 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)) | |
| + { | |
| + var selection = this.getSelection(); | |
| + var lineOrWord = (e.metaKey ? "line" : "word"); | |
| + if (e.keyCode===37) | |
| + { | |
| + selection.modify("extend","left",lineOrWord); | |
| + if (!e.shiftKey) | |
| + { | |
| + selection.collapseToStart(); | |
| + } | |
| + } | |
| + if (e.keyCode===39) | |
| + { | |
| + selection.modify("extend","right",lineOrWord); | |
| + if (!e.shiftKey) | |
| + { | |
| + selection.collapseToEnd(); | |
| + } | |
| + } | |
| + | |
| + e.preventDefault(); | |
| + } | |
| + } | |
| + | |
| + | |
| this.imageResizeHide(false); | |
| // pre & down | |
| @@ -1291,7 +1442,7 @@ | |
| } | |
| // shortcuts setup | |
| - if (ctrl && !e.shiftKey) this.shortcuts(e, key); | |
| + this.shortcuts(e, key); | |
| // buffer setup | |
| if (ctrl && key === 90 && !e.shiftKey && !e.altKey) // z key | |
| @@ -1310,13 +1461,37 @@ | |
| return; | |
| } | |
| + // space | |
| + if (key == 32) | |
| + { | |
| + this.bufferSet(); | |
| + } | |
| + | |
| // select all | |
| - if (ctrl && key === 65) this.selectall = true; | |
| - else if (key != this.keyCode.LEFT_WIN && !ctrl) this.selectall = false; | |
| + 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 ) | |
| + 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) | |
| + { | |
| + sel = this.getSelection(); | |
| + if (sel.rangeCount) | |
| + { | |
| + range.deleteContents(); | |
| + } | |
| + } | |
| + | |
| // In ie, opera in the tables are created paragraphs, fix it. | |
| if (this.browser('msie') && (parent.nodeType == 1 && (parent.tagName == 'TD' || parent.tagName == 'TH'))) | |
| { | |
| @@ -1368,14 +1543,44 @@ | |
| else this.dblEnter++; | |
| } | |
| - | |
| - | |
| // pre | |
| - if (pre === true) return this.buildEventKeydownPre(e, current); | |
| + 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 = $('<p>' + this.opts.invisibleSpace + '</p>'); | |
| + $list.after(node); | |
| + this.selectionStart(node); | |
| + | |
| + this.sync(); | |
| + this.callback('enter', e); | |
| + return false; | |
| + } | |
| + } | |
| + | |
| + } | |
| + | |
| // replace div to p | |
| if (block && this.opts.rBlockTest.test(block.tagName)) | |
| { | |
| @@ -1398,7 +1603,6 @@ | |
| { | |
| // hit enter | |
| this.bufferSet(); | |
| - | |
| var node = $('<p>' + this.opts.invisibleSpace + '</p>'); | |
| this.insertNode(node[0]); | |
| this.selectionStart(node); | |
| @@ -1450,11 +1654,14 @@ | |
| this.insertLineBreak(); | |
| } | |
| - // tab | |
| - if (key === this.keyCode.TAB && this.opts.shortcuts) return this.buildEventKeydownTab(e, pre); | |
| + // tab (cmd + [) | |
| + if ((key === this.keyCode.TAB || e.metaKey && key === 219) && this.opts.shortcuts) | |
| + { | |
| + return this.buildEventKeydownTab(e, pre, key); | |
| + } | |
| // delete zero-width space before the removing | |
| - if (key === this.keyCode.BACKSPACE) this.buildEventKeydownBackspace(current); | |
| + if (key === this.keyCode.BACKSPACE) this.buildEventKeydownBackspace(e, current, parent); | |
| }, | |
| buildEventKeydownPre: function(e, current) | |
| @@ -1472,7 +1679,7 @@ | |
| this.callback('enter', e); | |
| return false; | |
| }, | |
| - buildEventKeydownTab: function(e, pre) | |
| + buildEventKeydownTab: function(e, pre, key) | |
| { | |
| if (!this.opts.tabFocus) return true; | |
| if (this.isEmpty(this.get()) && this.opts.tabSpaces === false) return true; | |
| @@ -1502,8 +1709,23 @@ | |
| return false; | |
| }, | |
| - buildEventKeydownBackspace: function(current) | |
| + buildEventKeydownBackspace: function(e, current, parent) | |
| { | |
| + // remove empty list in table | |
| + if (parent && current && parent.parentNode.tagName == 'TD' | |
| + && parent.tagName == 'UL' && current.tagName == 'LI' && $(parent).children('li').size() == 1) | |
| + { | |
| + var text = $(current).text().replace(/[\u200B-\u200D\uFEFF]/g, ''); | |
| + if (text == '') | |
| + { | |
| + var node = parent.parentNode; | |
| + $(parent).remove(); | |
| + this.selectionStart(node); | |
| + this.sync(); | |
| + return false; | |
| + } | |
| + } | |
| + | |
| if (typeof current.tagName !== 'undefined' && /^(H[1-6])$/i.test(current.tagName)) | |
| { | |
| var node; | |
| @@ -1512,14 +1734,15 @@ | |
| $(current).replaceWith(node); | |
| this.selectionStart(node); | |
| + this.sync(); | |
| } | |
| if (typeof current.nodeValue !== 'undefined' && current.nodeValue !== null) | |
| { | |
| - //var value = $.trim(current.nodeValue.replace(/[^\u0000-\u1C7F]/g, '')); | |
| - if (current.remove && current.nodeType === 3 && current.nodeValue.match(/[^/\u200B]/g) == null) | |
| + if (current.remove && current.nodeType === 3 && current.nodeValue.match(/[^\u200B]/g) == null) | |
| { | |
| - current.remove(); | |
| + $(current).prev().remove(); | |
| + this.sync(); | |
| } | |
| } | |
| }, | |
| @@ -1549,6 +1772,7 @@ | |
| { | |
| next.remove(); | |
| } | |
| + | |
| this.selectionEnd(node); | |
| } | |
| @@ -1565,7 +1789,7 @@ | |
| } | |
| this.callback('keyup', e); | |
| - this.sync(); | |
| + this.sync(e); | |
| }, | |
| buildEventKeyupConverters: function() | |
| { | |
| @@ -1680,7 +1904,10 @@ | |
| // iframe css | |
| this.iframeAddCss(); | |
| - if (this.opts.fullpage) this.setFullpageOnInit(this.$editor.html()); | |
| + if (this.opts.fullpage) | |
| + { | |
| + this.setFullpageOnInit(this.$source.val()); | |
| + } | |
| else this.set(this.content, true, false); | |
| this.buildOptions(); | |
| @@ -1688,30 +1915,85 @@ | |
| }, | |
| // 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.isEmpty(html)) | |
| + if (this.opts.placeholder === false) | |
| { | |
| - if (this.$element.attr('placeholder')) this.opts.placeholder = this.$element.attr('placeholder'); | |
| - if (this.opts.placeholder === '') this.opts.placeholder = false; | |
| + return false; | |
| + } | |
| - if (this.opts.placeholder !== false) | |
| - { | |
| - this.opts.focus = false; | |
| - this.$editor.one('focus.redactor_placeholder', $.proxy(this.placeholderFocus, this)); | |
| + if (this.isEmpty(html)) | |
| + { | |
| + this.opts.focus = false; | |
| + this.placeholderOnFocus(); | |
| + this.placeholderOnBlur(); | |
| - return $('<span class="redactor_placeholder" data-redactor="verified">').attr('contenteditable', false).text(this.opts.placeholder); | |
| - } | |
| + 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 = $('<span class="redactor_placeholder">').data('redactor', 'verified') | |
| + .attr('contenteditable', false).text(this.placeholderText); | |
| + | |
| + if (this.opts.linebreaks === false) | |
| + { | |
| + return $('<p>').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; | |
| + if (this.opts.linebreaks === false) | |
| + { | |
| + html = this.opts.emptyHtml; | |
| + } | |
| this.$editor.off('focus.redactor_placeholder'); | |
| this.$editor.html(html); | |
| @@ -1728,9 +2010,8 @@ | |
| this.sync(); | |
| }, | |
| - placeholderRemove: function() | |
| + placeholderRemoveFromEditor: function() | |
| { | |
| - this.opts.placeholder = false; | |
| this.$editor.find('span.redactor_placeholder').remove(); | |
| this.$editor.off('focus.redactor_placeholder'); | |
| }, | |
| @@ -1743,109 +2024,221 @@ | |
| shortcuts: function(e, key) | |
| { | |
| - if (!this.opts.shortcuts) return; | |
| - | |
| - if (!e.altKey) | |
| + // disable browser's hot keys for bold and italic | |
| + if (!this.opts.shortcuts) | |
| { | |
| - if (key === 77) this.shortcutsLoad(e, 'removeFormat'); // Ctrl + m | |
| - else if (key === 66) this.shortcutsLoad(e, 'bold'); // Ctrl + b | |
| - else if (key === 73) this.shortcutsLoad(e, 'italic'); // Ctrl + i | |
| - | |
| - else if (key === 74) this.shortcutsLoad(e, 'insertunorderedlist'); // Ctrl + j | |
| - else if (key === 75) this.shortcutsLoad(e, 'insertorderedlist'); // Ctrl + k | |
| + if ((e.ctrlKey || e.metaKey) && (key === 66 || key === 73)) | |
| + { | |
| + e.preventDefault(); | |
| + } | |
| - else if (key === 72) this.shortcutsLoad(e, 'superscript'); // Ctrl + h | |
| - else if (key === 76) this.shortcutsLoad(e, 'subscript'); // Ctrl + l | |
| + return false; | |
| } | |
| - else | |
| + | |
| + $.each(this.opts.shortcuts, $.proxy(function(str, command) | |
| { | |
| - if (key === 48) this.shortcutsLoadFormat(e, 'p'); // ctrl + alt + 0 | |
| - else if (key === 49) this.shortcutsLoadFormat(e, 'h1'); // ctrl + alt + 1 | |
| - else if (key === 50) this.shortcutsLoadFormat(e, 'h2'); // ctrl + alt + 2 | |
| - else if (key === 51) this.shortcutsLoadFormat(e, 'h3'); // ctrl + alt + 3 | |
| - else if (key === 52) this.shortcutsLoadFormat(e, 'h4'); // ctrl + alt + 4 | |
| - else if (key === 53) this.shortcutsLoadFormat(e, 'h5'); // ctrl + alt + 5 | |
| - else if (key === 54) this.shortcutsLoadFormat(e, 'h6'); // ctrl + alt + 6 | |
| + var keys = str.split(','); | |
| + for (var i in keys) | |
| + { | |
| + if (typeof keys[i] === 'string') | |
| + { | |
| + this.shortcutsHandler(e, $.trim(keys[i]), $.proxy(function() | |
| + { | |
| + eval(command); | |
| + }, this)); | |
| + } | |
| - } | |
| + } | |
| + | |
| + }, this)); | |
| - }, | |
| - shortcutsLoad: function(e, cmd) | |
| - { | |
| - e.preventDefault(); | |
| - this.execCommand(cmd, false); | |
| - }, | |
| - shortcutsLoadFormat: function(e, cmd) | |
| - { | |
| - e.preventDefault(); | |
| - this.formatBlocks(cmd); | |
| - }, | |
| - // FOCUS | |
| - focus: function() | |
| - { | |
| - if (!this.browser('opera')) this.window.setTimeout($.proxy(this.focusSet, this, true), 1); | |
| - else this.$editor.focus(); | |
| - }, | |
| - focusEnd: function() | |
| - { | |
| - this.focusSet(); | |
| }, | |
| - focusSet: function(collapse) | |
| + shortcutsHandler: function(e, keys, origHandler) | |
| { | |
| - this.$editor.focus(); | |
| + // 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 range = this.getRange(); | |
| - range.selectNodeContents(this.$editor[0]); | |
| - // collapse - controls the position of focus: the beginning (true), at the end (false). | |
| - range.collapse(collapse || false); | |
| + var hotkeysShiftNums = | |
| + { | |
| + "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", | |
| + "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", | |
| + ".": ">", "/": "?", "\\": "|" | |
| + }; | |
| - var sel = this.getSelection(); | |
| - sel.removeAllRanges(); | |
| - sel.addRange(range); | |
| - }, | |
| + keys = keys.toLowerCase().split(" "); | |
| + var special = hotkeysSpecialKeys[e.keyCode], | |
| + character = String.fromCharCode( e.which ).toLowerCase(), | |
| + modif = "", possible = {}; | |
| - // TOGGLE | |
| - toggle: function(direct) | |
| - { | |
| - if (this.opts.visual) this.toggleCode(direct); | |
| - else this.toggleVisual(); | |
| - }, | |
| - toggleVisual: function() | |
| - { | |
| - var html = this.$source.hide().val(); | |
| + $.each([ "alt", "ctrl", "meta", "shift"], function(index, specialKey) | |
| + { | |
| + if (e[specialKey + 'Key'] && special !== specialKey) | |
| + { | |
| + modif += specialKey + '+'; | |
| + } | |
| + }); | |
| - if (typeof this.modified !== 'undefined') | |
| + | |
| + if (special) | |
| { | |
| - this.modified = this.cleanRemoveSpaces(this.modified, false) !== this.cleanRemoveSpaces(html, false); | |
| + possible[modif + special] = true; | |
| } | |
| - if (this.modified) | |
| + if (character) | |
| { | |
| - // don't remove the iframe even if cleared all. | |
| - if (this.opts.fullpage && html === '') this.setFullpageOnInit(html); | |
| - else | |
| + possible[modif + character] = true; | |
| + possible[modif + hotkeysShiftNums[character]] = true; | |
| + | |
| + // "$" can be triggered as "Shift+4" or "Shift+$" or just "$" | |
| + if (modif === "shift+") | |
| { | |
| - this.set(html); | |
| - if (this.opts.fullpage) this.buildBindKeyboard(); | |
| + possible[hotkeysShiftNums[character]] = true; | |
| } | |
| } | |
| - 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(); | |
| + for (var i = 0, l = keys.length; i < l; i++) | |
| + { | |
| + if (possible[keys[i]]) | |
| + { | |
| + e.preventDefault(); | |
| + return origHandler.apply(this, arguments); | |
| + } | |
| + } | |
| + }, | |
| - this.observeStart(); | |
| - this.buttonActiveVisual(); | |
| - this.buttonInactive('html'); | |
| + // 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) | |
| + { | |
| + this.buildBindKeyboard(); | |
| + } | |
| + } | |
| + | |
| + this.callback('change', false, html); | |
| + } | |
| + | |
| + 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) | |
| { | |
| @@ -1904,13 +2297,25 @@ | |
| var html = this.get(); | |
| if (savedHtml !== html) | |
| { | |
| + var name = this.$source.attr('name'); | |
| $.ajax({ | |
| url: this.opts.autosave, | |
| type: 'post', | |
| - data: this.$source.attr('name') + '=' + escape(encodeURIComponent(html)), | |
| + data: 'name=' + name + '&' + name + '=' + escape(encodeURIComponent(html)), | |
| success: $.proxy(function(data) | |
| { | |
| - this.callback('autosave', false, 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) | |
| @@ -1922,6 +2327,17 @@ | |
| // TOOLBAR | |
| toolbarBuild: function() | |
| { | |
| + // hide on mobile | |
| + if (this.isMobile() && this.opts.buttonsHideOnMobile.length > 0) | |
| + { | |
| + $.each(this.opts.buttonsHideOnMobile, $.proxy(function(i, s) | |
| + { | |
| + var index = this.opts.buttons.indexOf(s); | |
| + this.opts.buttons.splice(index, 1); | |
| + | |
| + }, this)); | |
| + } | |
| + | |
| // extend buttons | |
| if (this.opts.air) | |
| { | |
| @@ -1931,19 +2347,11 @@ | |
| { | |
| if (!this.opts.buttonSource) | |
| { | |
| - var index = this.opts.buttons.indexOf('html'), next = this.opts.buttons[index + 1]; | |
| + var index = this.opts.buttons.indexOf('html'); | |
| this.opts.buttons.splice(index, 1); | |
| - if (next === '|') this.opts.buttons.splice(index, 1); | |
| } | |
| } | |
| - $.extend(this.opts.toolbar, this.opts.buttonsCustom); | |
| - $.each(this.opts.buttonsAdd, $.proxy(function(i, s) | |
| - { | |
| - this.opts.buttons.push(s); | |
| - | |
| - }, this)); | |
| - | |
| // formatting tags | |
| if (this.opts.toolbar) | |
| { | |
| @@ -1963,6 +2371,16 @@ | |
| // toolbar build | |
| this.$toolbar = $('<ul>').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 | |
| @@ -1972,15 +2390,17 @@ | |
| } | |
| else | |
| { | |
| - if (this.opts.toolbarExternal) $(this.opts.toolbarExternal).html(this.$toolbar); | |
| + if (this.opts.toolbarExternal) | |
| + { | |
| + this.$toolbar.addClass('redactor-toolbar-external'); | |
| + $(this.opts.toolbarExternal).html(this.$toolbar); | |
| + } | |
| else this.$box.prepend(this.$toolbar); | |
| } | |
| $.each(this.opts.buttons, $.proxy(function(i, btnName) | |
| { | |
| - // separator | |
| - if ( btnName === '|' ) this.$toolbar.append($(this.opts.buttonSeparator)); | |
| - else if(this.opts.toolbar[btnName]) | |
| + if (this.opts.toolbar[btnName]) | |
| { | |
| var btnObject = this.opts.toolbar[btnName]; | |
| if (this.opts.fileUpload === false && btnName === 'file') return true; | |
| @@ -2001,17 +2421,27 @@ | |
| // buttons response | |
| if (this.opts.activeButtons) | |
| { | |
| - var buttonActiveObserver = $.proxy(this.buttonActiveObserver, this); | |
| - this.$editor.on('mouseup.redactor keyup.redactor', buttonActiveObserver); | |
| + this.$editor.on('mouseup.redactor keyup.redactor', $.proxy(this.buttonActiveObserver, this)); | |
| } | |
| }, | |
| toolbarObserveScroll: function() | |
| { | |
| var scrollTop = $(this.opts.toolbarFixedTarget).scrollTop(); | |
| - var boxTop = this.$box.offset().top; | |
| + | |
| + var boxTop = 0; | |
| var left = 0; | |
| + var end = 0; | |
| + | |
| + if (this.opts.toolbarFixedTarget === document) | |
| + { | |
| + boxTop = this.$box.offset().top; | |
| + } | |
| + else | |
| + { | |
| + boxTop = 1; | |
| + } | |
| - var end = boxTop + this.$box.height() + 40; | |
| + end = boxTop + this.$box.height() + 40; | |
| if (scrollTop > boxTop) | |
| { | |
| @@ -2024,13 +2454,27 @@ | |
| } | |
| this.toolbarFixed = true; | |
| - this.$toolbar.css({ | |
| - position: 'fixed', | |
| - width: width, | |
| - zIndex: 1005, | |
| - top: this.opts.toolbarFixedTopOffset + 'px', | |
| - left: left | |
| - }); | |
| + | |
| + if (this.opts.toolbarFixedTarget === document) | |
| + { | |
| + this.$toolbar.css({ | |
| + position: 'fixed', | |
| + width: width, | |
| + zIndex: 10005, | |
| + top: this.opts.toolbarFixedTopOffset + 'px', | |
| + left: left | |
| + }); | |
| + } | |
| + else | |
| + { | |
| + this.$toolbar.css({ | |
| + position: 'absolute', | |
| + width: width, | |
| + zIndex: 10005, | |
| + top: (this.opts.toolbarFixedTopOffset + scrollTop) + 'px', | |
| + left: 0 | |
| + }); | |
| + } | |
| if (scrollTop < end) this.$toolbar.css('visibility', 'visible'); | |
| else this.$toolbar.css('visibility', 'hidden'); | |
| @@ -2072,6 +2516,8 @@ | |
| { | |
| if (!this.opts.air) return; | |
| + this.selectionSave(); | |
| + | |
| var left, top; | |
| $('.redactor_air').hide(); | |
| @@ -2177,6 +2623,11 @@ | |
| $item = $('<a href="#" class="' + btnObject.className + ' redactor_dropdown_' + btnName + '">' + btnObject.title + '</a>'); | |
| $item.on('click', $.proxy(function(e) | |
| { | |
| + if (this.opts.air) | |
| + { | |
| + this.selectionRestore(); | |
| + } | |
| + | |
| if (e.preventDefault) e.preventDefault(); | |
| if (this.browser('msie')) e.returnValue = false; | |
| @@ -2187,6 +2638,7 @@ | |
| this.buttonActiveObserver(); | |
| if (this.opts.air) this.$air.fadeOut(100); | |
| + | |
| }, this)); | |
| } | |
| @@ -2202,22 +2654,21 @@ | |
| return false; | |
| } | |
| - var $dropdown = this.$toolbar.find('.redactor_dropdown_box_' + key); | |
| var $button = this.buttonGet(key); | |
| + // Always re-append it to the end of <body> so it always has the highest sub-z-index. | |
| + var $dropdown = $button.data('dropdown').appendTo(document.body); | |
| + | |
| if ($button.hasClass('dropact')) this.dropdownHideAll(); | |
| else | |
| { | |
| this.dropdownHideAll(); | |
| + this.callback('dropdownShow', { dropdown: $dropdown, key: key, button: $button }); | |
| this.buttonActive(key); | |
| $button.addClass('dropact'); | |
| - var keyPosition = $button.position(); | |
| - if (this.toolbarFixed) | |
| - { | |
| - keyPosition = $button.offset(); | |
| - } | |
| + var keyPosition = $button.offset(); | |
| // fix right placement | |
| var dropdownWidth = $dropdown.width(); | |
| @@ -2227,15 +2678,16 @@ | |
| } | |
| var left = keyPosition.left + 'px'; | |
| - var btnHeight = 29; | |
| + var btnHeight = $button.innerHeight(); | |
| var position = 'absolute'; | |
| - var top = btnHeight + 'px'; | |
| + var top = (btnHeight + this.opts.toolbarFixedTopOffset) + 'px'; | |
| if (this.opts.toolbarFixed && this.toolbarFixed) position = 'fixed'; | |
| - else if (!this.opts.air) top = keyPosition.top + btnHeight + 'px'; | |
| + else top = keyPosition.top + btnHeight + 'px'; | |
| $dropdown.css({ position: position, left: left, top: top }).show(); | |
| + this.callback('dropdownShown', { dropdown: $dropdown, key: key, button: $button }); | |
| } | |
| @@ -2247,13 +2699,17 @@ | |
| $(document).one('click', hdlHideDropDown); | |
| this.$editor.one('click', hdlHideDropDown); | |
| + this.$editor.one('touchstart', hdlHideDropDown); | |
| + | |
| e.stopPropagation(); | |
| + this.focusWithSaveScroll(); | |
| }, | |
| dropdownHideAll: function() | |
| { | |
| this.$toolbar.find('a.dropact').removeClass('redactor_act').removeClass('dropact'); | |
| $('.redactor_dropdown').hide(); | |
| + this.callback('dropdownHide'); | |
| }, | |
| dropdownHide: function (e, $dropdown) | |
| { | |
| @@ -2265,9 +2721,14 @@ | |
| }, | |
| // BUTTONS | |
| - buttonBuild: function(btnName, btnObject) | |
| + buttonBuild: function(btnName, btnObject, buttonImage) | |
| { | |
| - var $button = $('<a href="javascript:;" title="' + btnObject.title + '" tabindex="-1" class="redactor_btn redactor_btn_' + btnName + '"></a>'); | |
| + var $button = $('<a href="javascript:;" title="' + btnObject.title + '" tabindex="-1" class="re-icon re-' + btnName + '"></a>'); | |
| + | |
| + if (typeof buttonImage != 'undefined') | |
| + { | |
| + $button.addClass('redactor-btn-image'); | |
| + } | |
| $button.on('click', $.proxy(function(e) | |
| { | |
| @@ -2278,12 +2739,13 @@ | |
| if (this.isFocused() === false && !btnObject.exec) | |
| { | |
| - this.$editor.focus(); | |
| + this.focusWithSaveScroll(); | |
| } | |
| if (btnObject.exec) | |
| { | |
| - this.$editor.focus(); | |
| + this.focusWithSaveScroll(); | |
| + | |
| this.execCommand(btnObject.exec, btnName); | |
| this.airBindMousemoveHide(); | |
| @@ -2313,7 +2775,7 @@ | |
| if (btnObject.dropdown) | |
| { | |
| var $dropdown = $('<div class="redactor_dropdown redactor_dropdown_box_' + btnName + '" style="display: none;">'); | |
| - $dropdown.appendTo(this.$toolbar); | |
| + $button.data('dropdown', $dropdown); | |
| this.dropdownBuild($dropdown, btnObject.dropdown); | |
| } | |
| @@ -2322,112 +2784,103 @@ | |
| buttonGet: function(key) | |
| { | |
| if (!this.opts.toolbar) return false; | |
| - return $(this.$toolbar.find('a.redactor_btn_' + key)); | |
| + return $(this.$toolbar.find('a.re-' + key)); | |
| + }, | |
| + buttonTagToActiveState: function(buttonName, tagName) | |
| + { | |
| + this.opts.activeButtons.push(buttonName); | |
| + this.opts.activeButtonsStates[tagName] = buttonName; | |
| }, | |
| buttonActiveToggle: function(key) | |
| { | |
| var btn = this.buttonGet(key); | |
| - if (btn.hasClass('redactor_act')) btn.removeClass('redactor_act'); | |
| - else btn.addClass('redactor_act'); | |
| + if (btn.hasClass('redactor_act')) | |
| + { | |
| + this.buttonInactive(key); | |
| + } | |
| + else | |
| + { | |
| + this.buttonActive(key); | |
| + } | |
| }, | |
| buttonActive: function(key) | |
| { | |
| - this.buttonGet(key).addClass('redactor_act'); | |
| + var btn = this.buttonGet(key); | |
| + btn.addClass('redactor_act'); | |
| }, | |
| buttonInactive: function(key) | |
| { | |
| - this.buttonGet(key).removeClass('redactor_act'); | |
| + var btn = this.buttonGet(key); | |
| + btn.removeClass('redactor_act'); | |
| }, | |
| buttonInactiveAll: function(btnName) | |
| { | |
| - $.each(this.opts.toolbar, $.proxy(function(k) | |
| - { | |
| - if (k != btnName) this.buttonInactive(k); | |
| - | |
| - }, this)); | |
| + this.$toolbar.find('a.re-icon').not('.re-' + btnName).removeClass('redactor_act'); | |
| }, | |
| buttonActiveVisual: function() | |
| { | |
| - this.$toolbar.find('a.redactor_btn').not('a.redactor_btn_html').removeClass('redactor_button_disabled'); | |
| + this.$toolbar.find('a.re-icon').not('a.re-html').removeClass('redactor_button_disabled'); | |
| }, | |
| buttonInactiveVisual: function() | |
| { | |
| - this.$toolbar.find('a.redactor_btn').not('a.redactor_btn_html').addClass('redactor_button_disabled'); | |
| + this.$toolbar.find('a.re-icon').not('a.re-html').addClass('redactor_button_disabled'); | |
| }, | |
| buttonChangeIcon: function (key, classname) | |
| { | |
| - this.buttonGet(key).addClass('redactor_btn_' + classname); | |
| + this.buttonGet(key).addClass('re-' + classname); | |
| }, | |
| buttonRemoveIcon: function(key, classname) | |
| { | |
| - this.buttonGet(key).removeClass('redactor_btn_' + classname); | |
| - }, | |
| - buttonAddSeparator: function() | |
| - { | |
| - this.$toolbar.append($(this.opts.buttonSeparator)); | |
| + this.buttonGet(key).removeClass('re-' + classname); | |
| }, | |
| - buttonAddSeparatorAfter: function(key) | |
| + buttonAwesome: function(key, name) | |
| { | |
| - this.buttonGet(key).parent().after($(this.opts.buttonSeparator)); | |
| - }, | |
| - buttonAddSeparatorBefore: function(key) | |
| - { | |
| - this.buttonGet(key).parent().before($(this.opts.buttonSeparator)); | |
| - }, | |
| - buttonRemoveSeparatorAfter: function(key) | |
| - { | |
| - this.buttonGet(key).parent().next().remove(); | |
| - }, | |
| - buttonRemoveSeparatorBefore: function(key) | |
| - { | |
| - this.buttonGet(key).parent().prev().remove(); | |
| - }, | |
| - buttonSetRight: function(key) | |
| - { | |
| - if (!this.opts.toolbar) return; | |
| - this.buttonGet(key).parent().addClass('redactor_btn_right'); | |
| - }, | |
| - buttonSetLeft: function(key) | |
| - { | |
| - if (!this.opts.toolbar) return; | |
| - this.buttonGet(key).parent().removeClass('redactor_btn_right'); | |
| + var button = this.buttonGet(key); | |
| + button.removeClass('redactor-btn-image'); | |
| + button.addClass('fa-redactor-btn'); | |
| + button.html('<i class="fa ' + name + '"></i>'); | |
| }, | |
| buttonAdd: function(key, title, callback, dropdown) | |
| { | |
| if (!this.opts.toolbar) return; | |
| - var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }); | |
| - this.$toolbar.append( $('<li>').append(btn)); | |
| + var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }, true); | |
| + | |
| + this.$toolbar.append($('<li>').append(btn)); | |
| + | |
| + return btn; | |
| }, | |
| buttonAddFirst: function(key, title, callback, dropdown) | |
| { | |
| if (!this.opts.toolbar) return; | |
| - var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }); | |
| + var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }, true); | |
| this.$toolbar.prepend($('<li>').append(btn)); | |
| }, | |
| buttonAddAfter: function(afterkey, key, title, callback, dropdown) | |
| { | |
| if (!this.opts.toolbar) return; | |
| - var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }); | |
| + var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }, true); | |
| var $btn = this.buttonGet(afterkey); | |
| if ($btn.size() !== 0) $btn.parent().after($('<li>').append(btn)); | |
| else this.$toolbar.append($('<li>').append(btn)); | |
| + | |
| + return btn; | |
| }, | |
| buttonAddBefore: function(beforekey, key, title, callback, dropdown) | |
| { | |
| if (!this.opts.toolbar) return; | |
| - var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }); | |
| + var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }, true); | |
| var $btn = this.buttonGet(beforekey); | |
| if ($btn.size() !== 0) $btn.parent().before($('<li>').append(btn)); | |
| else this.$toolbar.append($('<li>').append(btn)); | |
| + | |
| + return btn; | |
| }, | |
| - buttonRemove: function (key, separator) | |
| + buttonRemove: function (key) | |
| { | |
| var $btn = this.buttonGet(key); | |
| - if (separator) $btn.parent().next().remove(); | |
| - $btn.parent().removeClass('redactor_btn_right'); | |
| $btn.remove(); | |
| }, | |
| buttonActiveObserver: function(e, btnName) | |
| @@ -2447,17 +2900,6 @@ | |
| if (parent && parent.tagName === 'A') this.$toolbar.find('a.redactor_dropdown_link').text(this.opts.curLang.link_edit); | |
| else this.$toolbar.find('a.redactor_dropdown_link').text(this.opts.curLang.link_insert); | |
| - if (this.opts.activeButtonsAdd) | |
| - { | |
| - $.each(this.opts.activeButtonsAdd, $.proxy(function(i,s) | |
| - { | |
| - this.opts.activeButtons.push(s); | |
| - | |
| - }, this)); | |
| - | |
| - $.extend(this.opts.activeButtonsStates, this.opts.activeButtonsAdd); | |
| - } | |
| - | |
| $.each(this.opts.activeButtonsStates, $.proxy(function(key, value) | |
| { | |
| if ($(parent).closest(key, this.$editor.get()[0]).length != 0) | |
| @@ -2471,34 +2913,61 @@ | |
| if ($parent.length) | |
| { | |
| var align = $parent.css('text-align'); | |
| - | |
| - switch (align) | |
| + if (align == '') | |
| { | |
| - case 'right': | |
| - this.buttonActive('alignright'); | |
| - break; | |
| - case 'center': | |
| - this.buttonActive('aligncenter'); | |
| - break; | |
| - case 'justify': | |
| - this.buttonActive('justify'); | |
| - break; | |
| - default: | |
| - this.buttonActive('alignleft'); | |
| - break; | |
| + align = 'left'; | |
| } | |
| + | |
| + this.buttonActive('align' + align); | |
| } | |
| }, | |
| // EXEC | |
| + execPasteFrag: function(html) | |
| + { | |
| + var sel = this.getSelection(); | |
| + if (sel.getRangeAt && sel.rangeCount) | |
| + { | |
| + var range = this.getRange(); | |
| + range.deleteContents(); | |
| + | |
| + var el = this.document.createElement("div"); | |
| + el.innerHTML = html; | |
| + | |
| + var frag = this.document.createDocumentFragment(), node, lastNode; | |
| + while ((node = el.firstChild)) | |
| + { | |
| + lastNode = frag.appendChild(node); | |
| + } | |
| + | |
| + var firstNode = frag.firstChild; | |
| + range.insertNode(frag); | |
| + | |
| + if (lastNode) | |
| + { | |
| + range = range.cloneRange(); | |
| + range.setStartAfter(lastNode); | |
| + range.collapse(true); | |
| + } | |
| + sel.removeAllRanges(); | |
| + sel.addRange(range); | |
| + } | |
| + }, | |
| exec: function(cmd, param, sync) | |
| { | |
| - if (cmd === 'formatblock' && this.browser('msie')) param = '<' + param + '>'; | |
| + if (cmd === 'formatblock' && this.browser('msie')) | |
| + { | |
| + param = '<' + param + '>'; | |
| + } | |
| if (cmd === 'inserthtml' && this.browser('msie')) | |
| { | |
| - this.$editor.focus(); | |
| - this.document.selection.createRange().pasteHTML(param); | |
| + if (!this.isIe11()) | |
| + { | |
| + this.focusWithSaveScroll(); | |
| + this.document.selection.createRange().pasteHTML(param); | |
| + } | |
| + else this.execPasteFrag(param); | |
| } | |
| else | |
| { | |
| @@ -2516,6 +2985,24 @@ | |
| return false; | |
| } | |
| + if ( cmd === 'bold' | |
| + || cmd === 'italic' | |
| + || cmd === 'underline' | |
| + || cmd === 'strikethrough') | |
| + { | |
| + this.bufferSet(); | |
| + } | |
| + | |
| + | |
| + if (cmd === 'superscript' || cmd === 'subscript') | |
| + { | |
| + var parent = this.getParent(); | |
| + if (parent.tagName === 'SUP' || parent.tagName === 'SUB') | |
| + { | |
| + this.inlineRemoveFormatReplace(parent); | |
| + } | |
| + } | |
| + | |
| if (cmd === 'inserthtml') | |
| { | |
| this.insertHtml(param, sync); | |
| @@ -2559,9 +3046,15 @@ | |
| var parent = this.getParent(); | |
| var $list = $(parent).closest('ol, ul'); | |
| + | |
| + if (!this.isParentRedactor($list) && $list.size() != 0) | |
| + { | |
| + $list = false; | |
| + } | |
| + | |
| var remove = false; | |
| - if ($list.length) | |
| + if ($list && $list.length) | |
| { | |
| remove = true; | |
| var listTag = $list[0].tagName; | |
| @@ -2577,6 +3070,7 @@ | |
| // remove lists | |
| if (remove) | |
| { | |
| + | |
| var nodes = this.getNodes(); | |
| var elems = this.getBlocks(nodes); | |
| @@ -2595,8 +3089,15 @@ | |
| var cloned = $s.clone(); | |
| cloned.find('ul', 'ol').remove(); | |
| - if (this.opts.linebreaks === false) data += this.outerHtml($('<p>').append(cloned.contents())); | |
| - else data += cloned.html() + '<br>'; | |
| + if (this.opts.linebreaks === false) | |
| + { | |
| + data += this.outerHtml($('<p>').append(cloned.contents())); | |
| + } | |
| + else | |
| + { | |
| + var clonedHtml = cloned.html().replace(/<br\s?\/?>$/i, ''); | |
| + data += clonedHtml + '<br>'; | |
| + } | |
| if (i == 0) | |
| { | |
| @@ -2608,6 +3109,7 @@ | |
| }, this)); | |
| + | |
| html = this.$editor.html().replace(replaced, '</' + listTag + '>' + data + '<' + listTag + '>'); | |
| this.$editor.html(html); | |
| @@ -2618,38 +3120,74 @@ | |
| // insert lists | |
| else | |
| { | |
| - var firstParent = this.getParent(); | |
| + var firstParent = $(this.getParent()).closest('td'); | |
| + | |
| + if (this.browser('msie') && !this.isIe11() && this.opts.linebreaks) | |
| + { | |
| + var wrapper = this.selectionWrap('div'); | |
| + var wrapperHtml = $(wrapper).html(); | |
| + var tmpList = $('<ul>'); | |
| + if (cmd == 'insertorderedlist') | |
| + { | |
| + tmpList = $('<ol>'); | |
| + } | |
| + | |
| + var tmpLi = $('<li>'); | |
| - this.document.execCommand(cmd); | |
| + if ($.trim(wrapperHtml) == '') | |
| + { | |
| + tmpLi.append(wrapperHtml + '<span id="selection-marker-1">' + this.opts.invisibleSpace + '</span>'); | |
| + tmpList.append(tmpLi); | |
| + this.$editor.find('#selection-marker-1').replaceWith(tmpList); | |
| + } | |
| + else | |
| + { | |
| + tmpLi.append(wrapperHtml); | |
| + tmpList.append(tmpLi); | |
| + $(wrapper).replaceWith(tmpList); | |
| + } | |
| + } | |
| + else | |
| + { | |
| + this.document.execCommand(cmd); | |
| + } | |
| var parent = this.getParent(); | |
| var $list = $(parent).closest('ol, ul'); | |
| - if (firstParent && firstParent.tagName == 'TD') | |
| + if (this.opts.linebreaks === false) | |
| + { | |
| + var listText = $.trim($list.text()); | |
| + if (listText == '') | |
| + { | |
| + $list.children('li').find('br').remove(); | |
| + $list.children('li').append('<span id="selection-marker-1">' + this.opts.invisibleSpace + '</span>'); | |
| + } | |
| + } | |
| + | |
| + if (firstParent.size() != 0) | |
| { | |
| $list.wrapAll('<td>'); | |
| } | |
| if ($list.length) | |
| { | |
| - if ((this.browser('msie') || this.browser('mozilla')) && parent.tagName !== 'LI') | |
| - { | |
| - $(parent).replaceWith($(parent).html()); | |
| - } | |
| - | |
| + // remove block-element list wrapper | |
| var $listParent = $list.parent(); | |
| - if (this.isParentRedactor($listParent) && this.nodeTestBlocks($listParent[0])) | |
| + if (this.isParentRedactor($listParent) && $listParent[0].tagName != 'LI' && this.nodeTestBlocks($listParent[0])) | |
| { | |
| $listParent.replaceWith($listParent.contents()); | |
| } | |
| } | |
| - if (this.browser('mozilla')) this.$editor.focus(); | |
| - | |
| + if (this.browser('mozilla')) | |
| + { | |
| + this.$editor.focus(); | |
| + } | |
| } | |
| this.selectionRestore(); | |
| - | |
| + this.$editor.find('#selection-marker-1').removeAttr('id'); | |
| this.sync(); | |
| this.callback('execCommand', cmd, param); | |
| return; | |
| @@ -2777,7 +3315,7 @@ | |
| // linebreaks | |
| if (this.opts.linebreaks === true && typeof($el.data('tagblock')) !== 'undefined') | |
| { | |
| - $el.replaceWith($el.html()); | |
| + $el.replaceWith($el.html() + '<br>'); | |
| } | |
| // all block tags | |
| else | |
| @@ -2860,8 +3398,8 @@ | |
| if (!block && this.opts.linebreaks) | |
| { | |
| // one element | |
| - this.exec('formatBlock', 'blockquote'); | |
| - this.selectionRestore(); | |
| + this.exec('formatblock', 'div'); | |
| + | |
| var newblock = this.getBlock(); | |
| var block = $('<div data-tagblock="">').html($(newblock).html()); | |
| $(newblock).replaceWith(block); | |
| @@ -2900,7 +3438,6 @@ | |
| } | |
| this.selectionRestore(); | |
| - | |
| this.sync(); | |
| }, | |
| @@ -2921,7 +3458,11 @@ | |
| cleanConverters: function(html) | |
| { | |
| // convert div to p | |
| - if (this.opts.convertDivs) html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p$1>$2</p>'); | |
| + if (this.opts.convertDivs && !this.opts.gallery) | |
| + { | |
| + html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p$1>$2</p>'); | |
| + } | |
| + | |
| if (this.opts.paragraphy) html = this.cleanParagraphy(html); | |
| return html; | |
| @@ -3011,8 +3552,6 @@ | |
| }, | |
| cleanRemoveEmptyTags: function(html) | |
| { | |
| - html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1'); | |
| - | |
| // remove zero width-space | |
| html = html.replace(/[\u200B-\u200D\uFEFF]/g, ''); | |
| @@ -3042,6 +3581,10 @@ | |
| html = html + "\n"; | |
| + if (this.opts.removeEmptyTags === false) | |
| + { | |
| + return html; | |
| + } | |
| var safes = []; | |
| var matches = html.match(/<(table|div|pre|object)(.*?)>([\w\W]*?)<\/(table|div|pre|object)>/gi); | |
| @@ -3066,6 +3609,7 @@ | |
| } | |
| html = html.replace(/<br \/>\s*<br \/>/gi, "\n\n"); | |
| + html = html.replace(/<br><br>/gi, "\n\n"); | |
| function R(str, mod, r) | |
| { | |
| @@ -3089,20 +3633,31 @@ | |
| { | |
| if (htmls[i].search('{replace') == -1) | |
| { | |
| - html += '<p>' + htmls[i].replace(/^\n+|\n+$/g, "") + "</p>"; | |
| + htmls[i] = htmls[i].replace(/<p>\n\t?<\/p>/gi, ''); | |
| + htmls[i] = htmls[i].replace(/<p><\/p>/gi, ''); | |
| + | |
| + if (htmls[i] != '') | |
| + { | |
| + html += '<p>' + htmls[i].replace(/^\n+|\n+$/g, "") + "</p>"; | |
| + } | |
| } | |
| else html += htmls[i]; | |
| } | |
| } | |
| - html = R('<p>\s*</p>', 'gi', ''); | |
| + html = R('<p><p>', 'gi', '<p>'); | |
| + html = R('</p></p>', 'gi', '</p>'); | |
| + | |
| + html = R('<p>\s?</p>', 'gi', ''); | |
| + | |
| html = R('<p>([^<]+)</(div|address|form)>', 'gi', "<p>$1</p></$2>"); | |
| - html = R('<p>\s*(</?' + blocks + '[^>]*>)\s*</p>', 'gi', "$1"); | |
| + | |
| + html = R('<p>(</?' + blocks + '[^>]*>)</p>', 'gi', "$1"); | |
| html = R("<p>(<li.+?)</p>", 'gi', "$1"); | |
| - html = R('<p>\s*(</?' + blocks + '[^>]*>)', 'gi', "$1"); | |
| + html = R('<p>\s?(</?' + blocks + '[^>]*>)', 'gi', "$1"); | |
| - html = R('(</?' + blocks + '[^>]*>)\s*</p>', 'gi', "$1"); | |
| - html = R('(</?' + blocks + '[^>]*>)\s*<br />', 'gi', "$1"); | |
| + html = R('(</?' + blocks + '[^>]*>)\s?</p>', 'gi', "$1"); | |
| + html = R('(</?' + blocks + '[^>]*>)\s?<br />', 'gi', "$1"); | |
| html = R('<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)', 'gi', '$1'); | |
| html = R("\n</p>", 'gi', '</p>'); | |
| @@ -3110,14 +3665,13 @@ | |
| html = R('</p></li>', 'gi', '</li>'); | |
| html = R('</li><p>', 'gi', '</li>'); | |
| //html = R('</ul><p>(.*?)</li>', 'gi', '</ul></li>'); | |
| - /* html = R('</ol><p>', 'gi', '</ol>'); */ | |
| + // html = R('</ol><p>', 'gi', '</ol>'); | |
| html = R('<p>\t?\n?<p>', 'gi', '<p>'); | |
| html = R('</dt><p>', 'gi', '</dt>'); | |
| html = R('</dd><p>', 'gi', '</dd>'); | |
| html = R('<br></p></blockquote>', 'gi', '</blockquote>'); | |
| html = R('<p>\t*</p>', 'gi', ''); | |
| - | |
| // restore safes | |
| $.each(safes, function(i,s) | |
| { | |
| @@ -3144,14 +3698,10 @@ | |
| if (this.opts.italicTag === 'em') html = html.replace(/<i>([\w\W]*?)<\/i>/gi, '<em>$1</em>'); | |
| else html = html.replace(/<em>([\w\W]*?)<\/em>/gi, '<i>$1</i>'); | |
| - if (set !== true) | |
| - { | |
| - html = html.replace(/<strike>([\w\W]*?)<\/strike>/gi, '<del>$1</del>'); | |
| - } | |
| - else | |
| - { | |
| - html = html.replace(/<del>([\w\W]*?)<\/del>/gi, '<strike>$1</strike>'); | |
| - } | |
| + html = html.replace(/<span style="text-decoration: underline;">([\w\W]*?)<\/span>/gi, '<u>$1</u>'); | |
| + | |
| + if (set !== true) html = html.replace(/<strike>([\w\W]*?)<\/strike>/gi, '<del>$1</del>'); | |
| + else html = html.replace(/<del>([\w\W]*?)<\/del>/gi, '<strike>$1</strike>'); | |
| return html; | |
| }, | |
| @@ -3189,6 +3739,9 @@ | |
| if (encode !== false) arr[3] = this.cleanEncodeEntities(arr[3]); | |
| + // $ fix | |
| + arr[3] = arr[3].replace(/\$/g, '$'); | |
| + | |
| html = html.replace(s, '<' + arr[1] + arr[2] + '>' + arr[3] + '</' + arr[1] + '>'); | |
| }, this)); | |
| @@ -3199,7 +3752,7 @@ | |
| cleanEncodeEntities: function(str) | |
| { | |
| str = String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); | |
| - return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); | |
| + return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); | |
| }, | |
| cleanUnverified: function() | |
| { | |
| @@ -3220,9 +3773,23 @@ | |
| this.removeEmptyAttr(s, 'style'); | |
| }, this)); | |
| + var $elem2 = this.$editor.find('b, strong, i, em, u, strike, del'); | |
| + $elem2.css('font-size', ''); | |
| + | |
| + $.each($elem2, $.proxy(function(i,s) | |
| + { | |
| + this.removeEmptyAttr(s, 'style'); | |
| + }, this)); | |
| + | |
| // When we paste text in Safari is wrapping inserted div (remove it) | |
| this.$editor.find('div[style="text-align: -webkit-auto;"]').contents().unwrap(); | |
| + | |
| + // Remove all styles in ul, ol, li | |
| + this.$editor.find('ul, ol, li').removeAttr('style'); | |
| }, | |
| + | |
| + | |
| + // TEXTAREA CODE FORMATTING | |
| cleanHtml: function(code) | |
| { | |
| var i = 0, | |
| @@ -3332,7 +3899,7 @@ | |
| } | |
| } | |
| - return this.cleanFinish( out ); | |
| + return this.cleanFinish(out); | |
| }, | |
| cleanGetTabs: function() | |
| { | |
| @@ -3346,10 +3913,10 @@ | |
| }, | |
| cleanFinish: function(code) | |
| { | |
| - code = code.replace( /\n\s*\n/g, '\n' ); | |
| - code = code.replace( /^[\s\n]*/, '' ); | |
| - code = code.replace( /[\s\n]*$/, '' ); | |
| - code = code.replace( /<script(.*?)>\n<\/script>/gi, '<script$1></script>' ); | |
| + code = code.replace(/\n\s*\n/g, '\n'); | |
| + code = code.replace(/^[\s\n]*/, ''); | |
| + code = code.replace(/[\s\n]*$/, ''); | |
| + code = code.replace(/<script(.*?)>\n<\/script>/gi, '<script$1></script>'); | |
| this.cleanlevel = 0; | |
| @@ -3438,6 +4005,11 @@ | |
| }, | |
| formatBlocks: function(tag) | |
| { | |
| + if (this.browser('mozilla') && this.isFocused()) | |
| + { | |
| + this.$editor.focus(); | |
| + } | |
| + | |
| this.bufferSet(); | |
| var nodes = this.getBlocks(); | |
| @@ -3460,7 +4032,14 @@ | |
| this.formatQuote(); | |
| return; | |
| } | |
| - else if (this.opts.linebreaks) return; | |
| + else if (this.opts.linebreaks) | |
| + { | |
| + if (node && node.tagName.search(/H[1-6]/) == 0) | |
| + { | |
| + $(node).replaceWith(node.innerHTML + '<br>'); | |
| + } | |
| + else return; | |
| + } | |
| else | |
| { | |
| this.formatBlock(tag, node); | |
| @@ -3480,9 +4059,9 @@ | |
| formatBlock: function(tag, block) | |
| { | |
| if (block === false) block = this.getBlock(); | |
| - if (block === false) | |
| + if (block === false && this.opts.linebreaks === true) | |
| { | |
| - if (this.opts.linebreaks === true) this.execCommand('formatblock', tag); | |
| + this.execCommand('formatblock', tag); | |
| return true; | |
| } | |
| @@ -3535,6 +4114,11 @@ | |
| // QUOTE | |
| formatQuote: function() | |
| { | |
| + if (this.browser('mozilla') && this.isFocused()) | |
| + { | |
| + this.$editor.focus(); | |
| + } | |
| + | |
| this.bufferSet(); | |
| // paragraphy | |
| @@ -3695,7 +4279,6 @@ | |
| }); | |
| var blocksElems = this.opts.blockLevelElements; | |
| - blocksElems.push('td'); | |
| $.each(blocksElems, function(i,s) | |
| { | |
| html = html.replace(new RegExp('<' + s + '(.*?)>', 'gi'), ''); | |
| @@ -3775,7 +4358,6 @@ | |
| this.selectionRestore(); | |
| this.sync(); | |
| }, | |
| - | |
| inlineSetClass: function(className) | |
| { | |
| var current = this.getCurrent(); | |
| @@ -3834,7 +4416,25 @@ | |
| } | |
| else | |
| { | |
| - this.document.execCommand('fontSize', false, 4 ); | |
| + var cmd, arg = value; | |
| + switch (attr) | |
| + { | |
| + case 'font-size': | |
| + cmd = 'fontSize'; | |
| + arg = 4; | |
| + break; | |
| + case 'font-family': | |
| + cmd = 'fontName'; | |
| + break; | |
| + case 'color': | |
| + cmd = 'foreColor'; | |
| + break; | |
| + case 'background-color': | |
| + cmd = 'backColor'; | |
| + break; | |
| + } | |
| + | |
| + this.document.execCommand(cmd, false, arg); | |
| var fonts = this.$editor.find('font'); | |
| $.each(fonts, $.proxy(function(i, s) | |
| @@ -3842,17 +4442,21 @@ | |
| this.inlineSetMethods(type, s, attr, value); | |
| }, this)); | |
| + | |
| } | |
| this.selectionRestore(); | |
| - | |
| this.sync(); | |
| }, | |
| inlineSetMethods: function(type, s, attr, value) | |
| { | |
| var parent = $(s).parent(), el; | |
| - if (parent && parent[0].tagName === 'INLINE' && parent[0].attributes.length != 0) | |
| + var selectionHtml = this.getSelectionText(); | |
| + var parentHtml = $(parent).text(); | |
| + var selected = selectionHtml == parentHtml; | |
| + | |
| + if (selected && parent && parent[0].tagName === 'INLINE' && parent[0].attributes.length != 0) | |
| { | |
| el = parent; | |
| $(s).replaceWith($(s).html()); | |
| @@ -3863,6 +4467,7 @@ | |
| $(s).replaceWith(el); | |
| } | |
| + | |
| $(el)[type](attr, value); | |
| return el; | |
| @@ -3885,7 +4490,11 @@ | |
| { | |
| if (!collapsed && node.tagName !== 'INLINE') | |
| { | |
| - if (node.parentNode.tagName === 'INLINE' && !$(node.parentNode).hasClass('redactor_editor')) | |
| + var selectionHtml = this.getSelectionText(); | |
| + var parentHtml = $(node).parent().text(); | |
| + var selected = selectionHtml == parentHtml; | |
| + | |
| + if (selected && node.parentNode.tagName === 'INLINE' && !$(node.parentNode).hasClass('redactor_editor')) | |
| { | |
| node = node.parentNode; | |
| } | |
| @@ -3952,13 +4561,14 @@ | |
| $(el).replaceWith($(el).contents()); | |
| }, | |
| + | |
| // INSERT | |
| insertHtml: function (html, sync) | |
| { | |
| var current = this.getCurrent(); | |
| var parent = current.parentNode; | |
| - this.$editor.focus(); | |
| + this.focusWithSaveScroll(); | |
| this.bufferSet(); | |
| @@ -3969,7 +4579,6 @@ | |
| // Update value | |
| $html = $('<div>').append($.parseHTML(html)); | |
| - | |
| var currBlock = this.getBlock(); | |
| if ($html.contents().length == 1) | |
| @@ -3979,11 +4588,16 @@ | |
| // If the inserted and received text tags match | |
| if (htmlTagName != 'P' && htmlTagName == currBlock.tagName || htmlTagName == 'PRE') | |
| { | |
| - html = $html.text(); | |
| + //html = $html.html(); | |
| $html = $('<div>').append(html); | |
| } | |
| } | |
| + if (this.opts.linebreaks) | |
| + { | |
| + html = html.replace(/<p(.*?)>([\w\W]*?)<\/p>/gi, '$2<br>'); | |
| + } | |
| + | |
| // add text in a paragraph | |
| if (!this.opts.linebreaks && $html.contents().length == 1 && $html.contents()[0].nodeType == 3 | |
| && (this.getRangeSelectedNodes().length > 2 || (!current || current.tagName == 'BODY' && !parent || parent.tagName == 'HTML'))) | |
| @@ -3994,11 +4608,23 @@ | |
| html = this.setSpansVerifiedHtml(html); | |
| if ($html.contents().length > 1 && currBlock | |
| - || $html.contents().is('p, :header, ul, ol, li, div, table, td, blockquote, pre, address, section, header, footer, aside, article')) | |
| + || $html.contents().is('p, :header, ul, ol, li, div, table, td, blockquote, pre, address, section, header, footer, aside, article')) | |
| { | |
| - if (this.browser('msie')) this.document.selection.createRange().pasteHTML(html); | |
| - else this.document.execCommand('inserthtml', false, html); | |
| - //else { this.insertHtmlAdvanced(html, false); this.callback('execCommand', 'inserthtml', html); } | |
| + if (this.browser('msie')) | |
| + { | |
| + if (!this.isIe11()) | |
| + { | |
| + this.document.selection.createRange().pasteHTML(html); | |
| + } | |
| + else | |
| + { | |
| + this.execPasteFrag(html); | |
| + } | |
| + } | |
| + else | |
| + { | |
| + this.document.execCommand('inserthtml', false, html); | |
| + } | |
| } | |
| else this.insertHtmlAdvanced(html, false); | |
| @@ -4030,9 +4656,9 @@ | |
| var range = sel.getRangeAt(0); | |
| range.deleteContents(); | |
| - var el = this.document.createElement('div'); | |
| + var el = document.createElement('div'); | |
| el.innerHTML = html; | |
| - var frag = this.document.createDocumentFragment(), node, lastNode; | |
| + var frag = document.createDocumentFragment(), node, lastNode; | |
| while ((node = el.firstChild)) | |
| { | |
| lastNode = frag.appendChild(node); | |
| @@ -4082,10 +4708,23 @@ | |
| if ($html.length) html = $html.text(); | |
| - this.$editor.focus(); | |
| + this.focusWithSaveScroll(); | |
| - if (this.browser('msie')) this.document.selection.createRange().pasteHTML(html); | |
| - else this.document.execCommand('inserthtml', false, html); | |
| + if (this.browser('msie')) | |
| + { | |
| + if (!this.isIe11()) | |
| + { | |
| + this.document.selection.createRange().pasteHTML(html); | |
| + } | |
| + else | |
| + { | |
| + this.execPasteFrag(html); | |
| + } | |
| + } | |
| + else | |
| + { | |
| + this.document.execCommand('inserthtml', false, html); | |
| + } | |
| this.sync(); | |
| }, | |
| @@ -4121,6 +4760,8 @@ | |
| sel.removeAllRanges(); | |
| sel.addRange(range); | |
| } | |
| + | |
| + return node; | |
| }, | |
| insertNodeToCaretPositionFromPoint: function(e, node) | |
| { | |
| @@ -4159,7 +4800,13 @@ | |
| if (this.opts.linebreaks) | |
| { | |
| var contents = $('<div>').append($.trim(this.$editor.html())).contents(); | |
| - if (this.outerHtml(contents.last()[0]) != this.outerHtml(element)) | |
| + var last = contents.last()[0]; | |
| + if (last.tagName == 'SPAN' && last.innerHTML == '') | |
| + { | |
| + last = contents.prev()[0]; | |
| + } | |
| + | |
| + if (this.outerHtml(last) != this.outerHtml(element)) | |
| { | |
| return false; | |
| } | |
| @@ -4194,21 +4841,60 @@ | |
| this.$editor.find('span#selection-marker-1').removeAttr('id'); | |
| } | |
| }, | |
| - insertLineBreak: function() | |
| + insertLineBreak: function(twice) | |
| { | |
| this.selectionSave(); | |
| - this.$editor.find('#selection-marker-1').before('<br>' + (this.browser('webkit') ? this.opts.invisibleSpace : '')); | |
| - this.selectionRestore(); | |
| + | |
| + var br = '<br>'; | |
| + if (twice == true) | |
| + { | |
| + br = '<br><br>'; | |
| + } | |
| + | |
| + if (this.browser('mozilla')) | |
| + { | |
| + var span = $('<span>').html(this.opts.invisibleSpace); | |
| + this.$editor.find('#selection-marker-1').before(br).before(span).before(this.opts.invisibleSpace); | |
| + | |
| + this.setCaretAfter(span[0]); | |
| + span.remove(); | |
| + | |
| + this.selectionRemoveMarkers(); | |
| + } | |
| + else | |
| + { | |
| + var parent = this.getParent(); | |
| + if (parent && parent.tagName === 'A') | |
| + { | |
| + var offset = this.getCaretOffset(parent); | |
| + | |
| + var text = $.trim($(parent).text()).replace(/\n\r\n/g, ''); | |
| + var len = text.length; | |
| + | |
| + if (offset == len) | |
| + { | |
| + this.selectionRemoveMarkers(); | |
| + | |
| + var node = $('<span id="selection-marker-1">' + this.opts.invisibleSpace + '</span>', this.document)[0]; | |
| + $(parent).after(node); | |
| + $(node).before(br + (this.browser('webkit') ? this.opts.invisibleSpace : '')); | |
| + this.selectionRestore(); | |
| + | |
| + return true; | |
| + } | |
| + | |
| + } | |
| + | |
| + this.$editor.find('#selection-marker-1').before(br + (this.browser('webkit') ? this.opts.invisibleSpace : '')); | |
| + this.selectionRestore(); | |
| + } | |
| }, | |
| insertDoubleLineBreak: function() | |
| { | |
| - this.selectionSave(); | |
| - this.$editor.find('#selection-marker-1').before('<br><br>' + (this.browser('webkit') ? this.opts.invisibleSpace : '')); | |
| - this.selectionRestore(); | |
| + this.insertLineBreak(true); | |
| }, | |
| replaceLineBreak: function(element) | |
| { | |
| - //var node = this.document.createTextNode('\uFEFF'); | |
| var node = $('<br>' + this.opts.invisibleSpace); | |
| $(element).replaceWith(node); | |
| this.selectionStart(node); | |
| @@ -4246,6 +4932,21 @@ | |
| return false; | |
| } | |
| + // clean up table | |
| + var tablePaste = false; | |
| + if (this.currentOrParentIs('TD')) | |
| + { | |
| + tablePaste = true; | |
| + var blocksElems = this.opts.blockLevelElements; | |
| + blocksElems.push('tr'); | |
| + blocksElems.push('table'); | |
| + $.each(blocksElems, function(i,s) | |
| + { | |
| + html = html.replace(new RegExp('<' + s + '(.*?)>', 'gi'), ''); | |
| + html = html.replace(new RegExp('</' + s + '>', 'gi'), '<br>'); | |
| + }); | |
| + } | |
| + | |
| // clean up pre | |
| if (this.currentOrParentIs('PRE')) | |
| { | |
| @@ -4254,6 +4955,8 @@ | |
| return true; | |
| } | |
| + // ms words shapes | |
| + html = html.replace(/<img(.*?)v:shapes=(.*?)>/gi, ''); | |
| // ms word list | |
| html = html.replace(/<p(.*?)class="MsoListParagraphCxSpFirst"([\w\W]*?)<\/p>/gi, '<ul><li$2</li>'); | |
| @@ -4268,18 +4971,29 @@ | |
| html = html.replace(/<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi, ''); | |
| // remove nbsp | |
| - html = html.replace(/( ){2,}/gi, ' '); | |
| - html = html.replace(/ /gi, ' '); | |
| + if (this.opts.cleanSpaces === true) | |
| + { | |
| + html = html.replace(/( ){2,}/gi, ' '); | |
| + html = html.replace(/ /gi, ' '); | |
| + } | |
| // remove google docs marker | |
| html = html.replace(/<b\sid="internal-source-marker(.*?)">([\w\W]*?)<\/b>/gi, "$2"); | |
| html = html.replace(/<b(.*?)id="docs-internal-guid(.*?)">([\w\W]*?)<\/b>/gi, "$3"); | |
| + | |
| + html = html.replace(/<span[^>]*(font-style: italic; font-weight: bold|font-weight: bold; font-style: italic)[^>]*>/gi, '<span style="font-weight: bold;"><span style="font-style: italic;">'); | |
| + html = html.replace(/<span[^>]*font-style: italic[^>]*>/gi, '<span style="font-style: italic;">'); | |
| + html = html.replace(/<span[^>]*font-weight: bold[^>]*>/gi, '<span style="font-weight: bold;">'); | |
| + html = html.replace(/<span[^>]*text-decoration: underline[^>]*>/gi, '<span style="text-decoration: underline;">'); | |
| + | |
| // strip tags | |
| - html = this.cleanStripTags(html); | |
| + //html = this.cleanStripTags(html); | |
| + | |
| + | |
| // prevert | |
| - html = html.replace(/<td><\/td>/gi, '[td]'); | |
| + html = html.replace(/<td>\u200b*<\/td>/gi, '[td]'); | |
| html = html.replace(/<td> <\/td>/gi, '[td]'); | |
| html = html.replace(/<td><br><\/td>/gi, '[td]'); | |
| html = html.replace(/<td(.*?)colspan="(.*?)"(.*?)>([\w\W]*?)<\/td>/gi, '[td colspan="$2"]$4[/td]'); | |
| @@ -4291,6 +5005,7 @@ | |
| html = html.replace(/<embed(.*?)>([\w\W]*?)<\/embed>/gi, '[embed$1]$2[/embed]'); | |
| html = html.replace(/<object(.*?)>([\w\W]*?)<\/object>/gi, '[object$1]$2[/object]'); | |
| html = html.replace(/<param(.*?)>/gi, '[param$1]'); | |
| + | |
| html = html.replace(/<img(.*?)>/gi, '[img$1]'); | |
| // remove classes | |
| @@ -4300,7 +5015,24 @@ | |
| html = html.replace(/<(\w+)([\w\W]*?)>/gi, '<$1>'); | |
| // remove empty | |
| - html = html.replace(/<[^\/>][^>]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, ''); | |
| + if (this.opts.linebreaks) | |
| + { | |
| + // prevent double linebreaks when an empty line in RTF has bold or underlined formatting associated with it | |
| + html = html.replace(/<strong><\/strong>/gi, ''); | |
| + html = html.replace(/<u><\/u>/gi, ''); | |
| + | |
| + if (this.opts.cleanFontTag) | |
| + { | |
| + html = html.replace(/<font(.*?)>([\w\W]*?)<\/font>/gi, '$2'); | |
| + } | |
| + | |
| + html = html.replace(/<[^\/>][^>]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, '<br>'); | |
| + } | |
| + else | |
| + { | |
| + html = html.replace(/<[^\/>][^>]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, ''); | |
| + } | |
| + | |
| html = html.replace(/<div>\s*?\t*?\n*?(<ul>|<ol>|<p>)/gi, '$1'); | |
| // revert | |
| @@ -4322,24 +5054,31 @@ | |
| html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p>$2</p>'); | |
| html = html.replace(/<\/div><p>/gi, '<p>'); | |
| html = html.replace(/<\/p><\/div>/gi, '</p>'); | |
| + html = html.replace(/<p><\/p>/gi, '<br />'); | |
| } | |
| + else | |
| + { | |
| + html = html.replace(/<div><\/div>/gi, '<br />'); | |
| + } | |
| + | |
| + // strip tags | |
| + html = this.cleanStripTags(html); | |
| if (this.currentOrParentIs('LI')) | |
| { | |
| html = html.replace(/<p>([\w\W]*?)<\/p>/gi, '$1<br>'); | |
| } | |
| - else | |
| + else if (tablePaste === false) | |
| { | |
| html = this.cleanParagraphy(html); | |
| } | |
| - | |
| // remove span | |
| html = html.replace(/<span(.*?)>([\w\W]*?)<\/span>/gi, '$2'); | |
| // remove empty | |
| html = html.replace(/<img>/gi, ''); | |
| - html = html.replace(/<[^\/>][^>][^img|param|source]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, ''); | |
| + html = html.replace(/<[^\/>][^>][^img|param|source|td][^<]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, ''); | |
| html = html.replace(/\n{3,}/gi, '\n'); | |
| @@ -4356,7 +5095,7 @@ | |
| } | |
| // remove empty finally | |
| - html = html.replace(/<[^\/>][^>][^img|param|source]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, ''); | |
| + html = html.replace(/<[^\/>][^>][^img|param|source|td][^<]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, ''); | |
| // remove safari local images | |
| html = html.replace(/<img src="webkit-fake-url\:\/\/(.*?)"(.*?)>/gi, ''); | |
| @@ -4365,8 +5104,11 @@ | |
| html = html.replace(/<td(.*?)>(\s*|\t*|\n*)<p>([\w\W]*?)<\/p>(\s*|\t*|\n*)<\/td>/gi, '<td$1>$3</td>'); | |
| // remove divs | |
| - html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '$2'); | |
| - html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '$2'); | |
| + if (this.opts.convertDivs) | |
| + { | |
| + html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '$2'); | |
| + html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '$2'); | |
| + } | |
| // FF specific | |
| this.pasteClipboardMozilla = false; | |
| @@ -4397,11 +5139,28 @@ | |
| html = html.replace(/<p>•([\w\W]*?)<\/p>/gi, '<li>$1</li>'); | |
| // ie inserts a blank font tags when pasting | |
| - while (/<font>([\w\W]*?)<\/font>/gi.test(html)) | |
| + if (this.browser('msie')) | |
| { | |
| - html = html.replace(/<font>([\w\W]*?)<\/font>/gi, '$1'); | |
| + while (/<font>([\w\W]*?)<\/font>/gi.test(html)) | |
| + { | |
| + html = html.replace(/<font>([\w\W]*?)<\/font>/gi, '$1'); | |
| + } | |
| + } | |
| + | |
| + // remove table paragraphs | |
| + if (tablePaste === false) | |
| + { | |
| + html = html.replace(/<td(.*?)>([\w\W]*?)<p(.*?)>([\w\W]*?)<\/td>/gi, '<td$1>$2$4</td>'); | |
| + html = html.replace(/<td(.*?)>([\w\W]*?)<\/p>([\w\W]*?)<\/td>/gi, '<td$1>$2$3</td>'); | |
| + html = html.replace(/<td(.*?)>([\w\W]*?)<p(.*?)>([\w\W]*?)<\/td>/gi, '<td$1>$2$4</td>'); | |
| + html = html.replace(/<td(.*?)>([\w\W]*?)<\/p>([\w\W]*?)<\/td>/gi, '<td$1>$2$3</td>'); | |
| } | |
| + // ms word break lines | |
| + html = html.replace(/\n/g, ' '); | |
| + | |
| + // ms word lists break lines | |
| + html = html.replace(/<p>\n?<li>/gi, '<li>'); | |
| this.pasteInsert(html); | |
| @@ -4416,19 +5175,22 @@ | |
| }, | |
| pasteInsert: function(html) | |
| { | |
| + html = this.callback('pasteAfter', false, html); | |
| + | |
| if (this.selectall) | |
| { | |
| - if (!this.opts.linebreaks) this.$editor.html(this.opts.emptyHtml); | |
| - else this.$editor.html(''); | |
| - | |
| - this.$editor.focus(); | |
| + this.$editor.html(html); | |
| + this.selectionRemove(); | |
| + this.focusEnd(); | |
| + this.sync(); | |
| + } | |
| + else | |
| + { | |
| + this.insertHtml(html); | |
| } | |
| - | |
| - html = this.callback('pasteAfter', false, html); | |
| - | |
| - this.insertHtml(html); | |
| this.selectall = false; | |
| + | |
| setTimeout($.proxy(function() | |
| { | |
| this.rtePaste = false; | |
| @@ -4445,8 +5207,29 @@ | |
| }, this), 100); | |
| - if (this.opts.autoresize && this.fullscreen !== true) $(this.document.body).scrollTop(this.saveScroll); | |
| - else this.$editor.scrollTop(this.saveScroll); | |
| + if (this.opts.autoresize && this.fullscreen !== true) | |
| + { | |
| + $(this.document.body).scrollTop(this.saveScroll); | |
| + } | |
| + else | |
| + { | |
| + this.$editor.scrollTop(this.saveScroll); | |
| + } | |
| + }, | |
| + pasteClipboardAppendFields: function(postData) | |
| + { | |
| + // 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(); | |
| + postData[k] = v; | |
| + | |
| + }, this)); | |
| + } | |
| + | |
| + return postData; | |
| }, | |
| pasteClipboardUploadMozilla: function() | |
| { | |
| @@ -4455,13 +5238,15 @@ | |
| { | |
| var $s = $(s); | |
| var arr = s.src.split(","); | |
| - var data = arr[1]; // raw base64 | |
| - var contentType = arr[0].split(";")[0].split(":")[1]; | |
| + var postData = { | |
| + 'contentType': arr[0].split(";")[0].split(":")[1], | |
| + 'data': arr[1] // raw base64 | |
| + }; | |
| - $.post(this.opts.clipboardUploadUrl, { | |
| - contentType: contentType, | |
| - data: data | |
| - }, | |
| + // append hidden fields | |
| + postData = this.pasteClipboardAppendFields(postData); | |
| + | |
| + $.post(this.opts.clipboardUploadUrl, postData, | |
| $.proxy(function(data) | |
| { | |
| var json = (typeof data === 'string' ? $.parseJSON(data) : data); | |
| @@ -4481,15 +5266,18 @@ | |
| { | |
| var result = e.target.result; | |
| var arr = result.split(","); | |
| - var data = arr[1]; // raw base64 | |
| - var contentType = arr[0].split(";")[0].split(":")[1]; | |
| + var postData = { | |
| + 'contentType': arr[0].split(";")[0].split(":")[1], | |
| + 'data': arr[1] // raw base64 | |
| + }; | |
| + | |
| if (this.opts.clipboardUpload) | |
| { | |
| - $.post(this.opts.clipboardUploadUrl, { | |
| - contentType: contentType, | |
| - data: data | |
| - }, | |
| + // append hidden fields | |
| + postData = this.pasteClipboardAppendFields(postData); | |
| + | |
| + $.post(this.opts.clipboardUploadUrl, postData, | |
| $.proxy(function(data) | |
| { | |
| var json = (typeof data === 'string' ? $.parseJSON(data) : data); | |
| @@ -4520,21 +5308,26 @@ | |
| }, | |
| // BUFFER | |
| - bufferSet: function(html) | |
| + bufferSet: function(selectionSave) | |
| { | |
| - if (html !== undefined) this.opts.buffer.push(html); | |
| - else | |
| + if (selectionSave !== false) | |
| { | |
| this.selectionSave(); | |
| - this.opts.buffer.push(this.$editor.html()); | |
| + } | |
| + | |
| + this.opts.buffer.push(this.$editor.html()); | |
| + | |
| + if (selectionSave !== false) | |
| + { | |
| this.selectionRemoveMarkers('buffer'); | |
| } | |
| + | |
| }, | |
| bufferUndo: function() | |
| { | |
| if (this.opts.buffer.length === 0) | |
| { | |
| - this.$editor.focus(); | |
| + this.focusWithSaveScroll(); | |
| return; | |
| } | |
| @@ -4552,7 +5345,7 @@ | |
| { | |
| if (this.opts.rebuffer.length === 0) | |
| { | |
| - this.$editor.focus(); | |
| + this.focusWithSaveScroll(); | |
| return false; | |
| } | |
| @@ -4576,11 +5369,18 @@ | |
| observeLinks: function() | |
| { | |
| this.$editor.find('a').on('click', $.proxy(this.linkObserver, this)); | |
| + | |
| this.$editor.on('click.redactor', $.proxy(function(e) | |
| { | |
| this.linkObserverTooltipClose(e); | |
| }, this)); | |
| + | |
| + $(document).on('click.redactor', $.proxy(function(e) | |
| + { | |
| + this.linkObserverTooltipClose(e); | |
| + | |
| + }, this)); | |
| }, | |
| observeImages: function() | |
| { | |
| @@ -4589,13 +5389,31 @@ | |
| this.$editor.find('img').each($.proxy(function(i, elem) | |
| { | |
| if (this.browser('msie')) $(elem).attr('unselectable', 'on'); | |
| - this.imageResize(elem); | |
| + | |
| + var parent = $(elem).parent(); | |
| + if (!parent.hasClass('royalSlider') && !parent.hasClass('fotorama')) | |
| + { | |
| + this.imageResize(elem); | |
| + } | |
| }, this)); | |
| + | |
| + // royalSlider and fotorama | |
| + this.$editor.find('.fotorama, .royalSlider').on('click', $.proxy(this.editGallery, this)); | |
| + | |
| }, | |
| linkObserver: function(e) | |
| { | |
| var $link = $(e.target); | |
| + | |
| + var parent = $(e.target).parent(); | |
| + if (parent.hasClass('royalSlider') || parent.hasClass('fotorama')) | |
| + { | |
| + return; | |
| + } | |
| + | |
| + if ($link.size() == 0 || $link[0].tagName !== 'A') return; | |
| + | |
| var pos = $link.offset(); | |
| if (this.opts.iframe) | |
| { | |
| @@ -4607,7 +5425,12 @@ | |
| var tooltip = $('<span class="redactor-link-tooltip"></span>'); | |
| var href = $link.attr('href'); | |
| - if (href.length > 24) href = href.substring(0,24) + '...'; | |
| + if (href === undefined) | |
| + { | |
| + href = ''; | |
| + } | |
| + | |
| + if (href.length > 24) href = href.substring(0, 24) + '...'; | |
| var aLink = $('<a href="' + $link.attr('href') + '" target="_blank">' + href + '</a>').on('click', $.proxy(function(e) | |
| { | |
| @@ -4698,6 +5521,19 @@ | |
| var sel = this.getSelection(); | |
| if (!sel) return; | |
| + if (orgn.tagName == 'P' && orgn.innerHTML == '') | |
| + { | |
| + orgn.innerHTML = this.opts.invisibleSpace; | |
| + } | |
| + | |
| + if (orgn.tagName == 'BR' && this.opts.linebreaks === false) | |
| + { | |
| + var par = $(this.opts.emptyHtml)[0]; | |
| + $(orgn).replaceWith(par); | |
| + orgn = par; | |
| + focn = orgn; | |
| + } | |
| + | |
| var range = this.getRange(); | |
| range.setStart(orgn, orgo); | |
| range.setEnd(focn, foco ); | |
| @@ -4801,6 +5637,33 @@ | |
| sel.removeAllRanges(); | |
| sel.addRange( range ); | |
| }, | |
| + setCaretAfter: function(node) | |
| + { | |
| + this.$editor.focus(); | |
| + | |
| + node = node[0] || node; | |
| + | |
| + var range = this.document.createRange() | |
| + | |
| + var start = 1; | |
| + var end = -1; | |
| + | |
| + range.setStart(node, start) | |
| + range.setEnd(node, end + 2) | |
| + | |
| + | |
| + var selection = this.window.getSelection() | |
| + var cursorRange = this.document.createRange() | |
| + | |
| + var emptyElement = this.document.createTextNode('\u200B') | |
| + $(node).after(emptyElement) | |
| + | |
| + cursorRange.setStartAfter(emptyElement) | |
| + | |
| + selection.removeAllRanges() | |
| + selection.addRange(cursorRange) | |
| + $(emptyElement).remove(); | |
| + }, | |
| getTextNodesIn: function (node) | |
| { | |
| var textNodes = []; | |
| @@ -4824,7 +5687,11 @@ | |
| var el = false; | |
| var sel = this.getSelection(); | |
| - if (sel.rangeCount > 0) el = sel.getRangeAt(0).startContainer; | |
| + if (sel && sel.rangeCount > 0) | |
| + { | |
| + el = sel.getRangeAt(0).startContainer; | |
| + //el = sel.getRangeAt(0).commonAncestorContainer; | |
| + } | |
| return this.isParentRedactor(el); | |
| }, | |
| @@ -4872,6 +5739,12 @@ | |
| return newnodes; | |
| }, | |
| + isInlineNode: function(node) | |
| + { | |
| + if (node.nodeType != 1) return false; | |
| + | |
| + return !this.rTestBlock.test(node.nodeName); | |
| + }, | |
| nodeTestBlocks: function(node) | |
| { | |
| return node.nodeType == 1 && this.rTestBlock.test(node.nodeName); | |
| @@ -5025,7 +5898,10 @@ | |
| // SAVE & RESTORE | |
| selectionSave: function() | |
| { | |
| - if (!this.isFocused()) this.$editor.focus(); | |
| + if (!this.isFocused()) | |
| + { | |
| + this.focusWithSaveScroll(); | |
| + } | |
| if (!this.opts.rangy) | |
| { | |
| @@ -5062,10 +5938,19 @@ | |
| { | |
| var boundaryRange = range.cloneRange(); | |
| - boundaryRange.collapse(type); | |
| + try { | |
| + boundaryRange.collapse(type); | |
| + boundaryRange.insertNode(node); | |
| + boundaryRange.detach(); | |
| + } | |
| + catch (e) | |
| + { | |
| + var html = this.opts.emptyHtml; | |
| + if (this.opts.linebreaks) html = '<br>'; | |
| - boundaryRange.insertNode(node); | |
| - boundaryRange.detach(); | |
| + this.$editor.prepend(html); | |
| + this.focus(); | |
| + } | |
| }, | |
| selectionRestore: function(replace, remove) | |
| { | |
| @@ -5085,11 +5970,12 @@ | |
| } | |
| else if (!this.isFocused()) | |
| { | |
| - this.$editor.focus(); | |
| + this.focusWithSaveScroll(); | |
| } | |
| if (node1.length != 0 && node2.length != 0) | |
| { | |
| + | |
| this.selectionSet(node1[0], 0, node2[0], 0); | |
| } | |
| else if (node1.length != 0) | |
| @@ -5152,6 +6038,8 @@ | |
| }, | |
| tableInsert: function() | |
| { | |
| + this.bufferSet(false); | |
| + | |
| var rows = $('#redactor_table_rows').val(), | |
| columns = $('#redactor_table_columns').val(), | |
| $table_box = $('<div></div>'), | |
| @@ -5168,7 +6056,10 @@ | |
| $column = $('<td>' + this.opts.invisibleSpace + '</td>'); | |
| // set the focus to the first td | |
| - if (i === 0 && z === 0) $column.append('<span id="selection-marker-1">' + this.opts.invisibleSpace + '</span>'); | |
| + if (i === 0 && z === 0) | |
| + { | |
| + $column.append('<span id="selection-marker-1">' + this.opts.invisibleSpace + '</span>'); | |
| + } | |
| $($row).append($column); | |
| } | |
| @@ -5179,20 +6070,37 @@ | |
| $table_box.append($table); | |
| var html = $table_box.html(); | |
| + if (this.opts.linebreaks === false && this.browser('mozilla')) | |
| + { | |
| + html += '<p>' + this.opts.invisibleSpace + '</p>'; | |
| + } | |
| + | |
| this.modalClose(); | |
| this.selectionRestore(); | |
| var current = this.getBlock() || this.getCurrent(); | |
| - if (current && current.tagName != 'BODY') $(current).after(html) | |
| - else this.insertHtmlAdvanced(html, false); | |
| + if (current && current.tagName != 'BODY') | |
| + { | |
| + if (current.tagName == 'LI') | |
| + { | |
| + var current = $(current).closest('ul, ol'); | |
| + } | |
| + | |
| + $(current).after(html) | |
| + } | |
| + else | |
| + { | |
| + | |
| + this.insertHtmlAdvanced(html, false); | |
| + } | |
| this.selectionRestore(); | |
| var table = this.$editor.find('#table' + tableId); | |
| this.buttonActiveObserver(); | |
| - table.find('span#selection-marker-1').remove(); | |
| + table.find('span#selection-marker-1, inline#selection-marker-1').remove(); | |
| table.removeAttr('id'); | |
| this.sync(); | |
| @@ -5210,13 +6118,16 @@ | |
| }, | |
| tableDeleteRow: function() | |
| { | |
| - var $table = $(this.getParent()).closest('table'); | |
| + var parent = this.getParent(); | |
| + var $table = $(parent).closest('table'); | |
| + | |
| + | |
| if (!this.isParentRedactor($table)) return false; | |
| if ($table.size() == 0) return false; | |
| this.bufferSet(); | |
| - var $current_tr = $(this.getParent()).closest('tr'); | |
| + var $current_tr = $(parent).closest('tr'); | |
| var $focus_tr = $current_tr.prev().length ? $current_tr.prev() : $current_tr.next(); | |
| if ($focus_tr.length) | |
| { | |
| @@ -5229,17 +6140,25 @@ | |
| $current_tr.remove(); | |
| this.selectionRestore(); | |
| + $table.find('span#selection-marker-1').remove(); | |
| this.sync(); | |
| }, | |
| tableDeleteColumn: function() | |
| { | |
| - var $table = $(this.getParent()).closest('table'); | |
| + var parent = this.getParent(); | |
| + var $table = $(parent).closest('table'); | |
| + | |
| if (!this.isParentRedactor($table)) return false; | |
| if ($table.size() == 0) return false; | |
| this.bufferSet(); | |
| - var $current_td = $(this.getParent()).closest('td'); | |
| + var $current_td = $(parent).closest('td'); | |
| + if (!($current_td.is('td'))) | |
| + { | |
| + $current_td = $current_td.closest('td'); | |
| + } | |
| + | |
| var index = $current_td.get(0).cellIndex; | |
| // Set the focus correctly | |
| @@ -5256,6 +6175,7 @@ | |
| }, this)); | |
| this.selectionRestore(); | |
| + $table.find('span#selection-marker-1').remove(); | |
| this.sync(); | |
| }, | |
| tableAddHead: function() | |
| @@ -5326,7 +6246,9 @@ | |
| }, | |
| tableAddColumn: function (type) | |
| { | |
| - var $table = $(this.getParent()).closest('table'); | |
| + var parent = this.getParent(); | |
| + var $table = $(parent).closest('table'); | |
| + | |
| if (!this.isParentRedactor($table)) return false; | |
| if ($table.size() == 0) return false; | |
| @@ -5334,8 +6256,9 @@ | |
| var index = 0; | |
| - var $current_tr = $(this.getParent()).closest('tr'); | |
| - var $current_td = $(this.getParent()).closest('td'); | |
| + var current = this.getCurrent(); | |
| + var $current_tr = $(current).closest('tr'); | |
| + var $current_td = $(current).closest('td'); | |
| $current_tr.find('td').each($.proxy(function(i, elem) | |
| { | |
| @@ -5379,6 +6302,19 @@ | |
| var data = $('#redactor_insert_video_area').val(); | |
| data = this.cleanStripTags(data); | |
| + // parse if it is link on youtube & vimeo | |
| + var iframeStart = '<iframe width="500" height="281" src="', | |
| + iframeEnd = '" frameborder="0" allowfullscreen></iframe>'; | |
| + | |
| + if (data.match(reUrlYoutube)) | |
| + { | |
| + data = data.replace(reUrlYoutube, iframeStart + '//www.youtube.com/embed/$1' + iframeEnd); | |
| + } | |
| + else if (data.match(reUrlVimeo)) | |
| + { | |
| + data = data.replace(reUrlVimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd); | |
| + } | |
| + | |
| this.selectionRestore(); | |
| var current = this.getBlock() || this.getCurrent(); | |
| @@ -5390,13 +6326,48 @@ | |
| this.modalClose(); | |
| }, | |
| + | |
| // LINK | |
| linkShow: function() | |
| { | |
| this.selectionSave(); | |
| - var callback = $.proxy(function() | |
| - { | |
| + var callback = $.proxy(function() | |
| + { | |
| + // Predefined links | |
| + if (this.opts.predefinedLinks !== false) | |
| + { | |
| + this.predefinedLinksStorage = {}; | |
| + var that = this; | |
| + $.getJSON(this.opts.predefinedLinks, function(data) | |
| + { | |
| + var $select = $('#redactor-predefined-links'); | |
| + $select .html(''); | |
| + $.each(data, function(key, val) | |
| + { | |
| + that.predefinedLinksStorage[key] = val; | |
| + $select.append($('<option>').val(key).html(val.name)); | |
| + }); | |
| + | |
| + $select.on('change', function() | |
| + { | |
| + var key = $(this).val(); | |
| + var name = '', url = ''; | |
| + if (key != 0) | |
| + { | |
| + name = that.predefinedLinksStorage[key].name; | |
| + url = that.predefinedLinksStorage[key].url; | |
| + } | |
| + | |
| + $('#redactor_link_url').val(url); | |
| + $('#redactor_link_url_text').val(name); | |
| + | |
| + }); | |
| + | |
| + $select.show(); | |
| + }); | |
| + } | |
| + | |
| this.insert_link_node = false; | |
| var sel = this.getSelection(); | |
| @@ -5419,52 +6390,31 @@ | |
| } | |
| else text = sel.toString(); | |
| - $('.redactor_link_text').val(text); | |
| + $('#redactor_link_url_text').val(text); | |
| var thref = self.location.href.replace(/\/$/i, ''); | |
| - var turl = url.replace(thref, ''); | |
| + url = url.replace(thref, ''); | |
| + url = url.replace(/^\/#/, '#'); | |
| + url = url.replace('mailto:', ''); | |
| // remove host from href | |
| if (this.opts.linkProtocol === false) | |
| { | |
| var re = new RegExp('^(http|ftp|https)://' + self.location.host, 'i'); | |
| - turl = turl.replace(re, ''); | |
| + url = url.replace(re, ''); | |
| } | |
| - var tabs = $('#redactor_tabs').find('a'); | |
| + // set url | |
| + $('#redactor_link_url').val(url); | |
| - if (this.opts.linkEmail === false) tabs.eq(1).remove(); | |
| - if (this.opts.linkAnchor === false) tabs.eq(2).remove(); | |
| - if (this.opts.linkEmail === false && this.opts.linkAnchor === false) | |
| - { | |
| - $('#redactor_tabs').remove(); | |
| - $('#redactor_link_url').val(turl); | |
| - } | |
| - else | |
| + if (target === '_blank') | |
| { | |
| - if (url.search('mailto:') === 0) | |
| - { | |
| - this.modalSetTab.call(this, 2); | |
| - | |
| - $('#redactor_tab_selected').val(2); | |
| - $('#redactor_link_mailto').val(url.replace('mailto:', '')); | |
| - } | |
| - else if (turl.search(/^#/gi) === 0) | |
| - { | |
| - this.modalSetTab.call(this, 3); | |
| - | |
| - $('#redactor_tab_selected').val(3); | |
| - $('#redactor_link_anchor').val(turl.replace(/^#/gi, '' )); | |
| - } | |
| - else | |
| - { | |
| - $('#redactor_link_url').val(turl); | |
| - } | |
| + $('#redactor_link_blank').prop('checked', true); | |
| } | |
| - if (target === '_blank') $('#redactor_link_blank').prop('checked', true); | |
| + this.linkInsertPressed = false; | |
| + $('#redactor_insert_link_btn').on('click', $.proxy(this.linkProcess, this)); | |
| - $('#redactor_insert_link_btn').click($.proxy(this.linkProcess, this)); | |
| setTimeout(function() | |
| { | |
| @@ -5479,15 +6429,25 @@ | |
| }, | |
| linkProcess: function() | |
| { | |
| - var tab_selected = $('#redactor_tab_selected').val(); | |
| - var link = '', text = '', target = '', targetBlank = ''; | |
| - | |
| - // url | |
| - if (tab_selected === '1') | |
| + if (this.linkInsertPressed) | |
| { | |
| - link = $('#redactor_link_url').val(); | |
| - text = $('#redactor_link_url_text').val(); | |
| + return; | |
| + } | |
| + this.linkInsertPressed = true; | |
| + var target = '', targetBlank = ''; | |
| + | |
| + var link = $('#redactor_link_url').val(); | |
| + var text = $('#redactor_link_url_text').val(); | |
| + | |
| + // mailto | |
| + if (link.search('@') != -1 && /(http|ftp|https):\/\//i.test(link) === false) | |
| + { | |
| + link = 'mailto:' + link; | |
| + } | |
| + // url, not anchor | |
| + else if (link.search('#') != 0) | |
| + { | |
| if ($('#redactor_link_blank').prop('checked')) | |
| { | |
| target = ' target="_blank"'; | |
| @@ -5504,21 +6464,15 @@ | |
| link = this.opts.linkProtocol + link; | |
| } | |
| } | |
| - // mailto | |
| - else if (tab_selected === '2') | |
| - { | |
| - link = 'mailto:' + $('#redactor_link_mailto').val(); | |
| - text = $('#redactor_link_mailto_text').val(); | |
| - } | |
| - // anchor | |
| - else if (tab_selected === '3') | |
| + | |
| + text = text.replace(/<|>/g, ''); | |
| + var extra = ' '; | |
| + if (this.browser('mozilla')) | |
| { | |
| - link = '#' + $('#redactor_link_anchor').val(); | |
| - text = $('#redactor_link_anchor_text').val(); | |
| + extra = ' '; | |
| } | |
| - text = text.replace(/<|>/g, ''); | |
| - this.linkInsert('<a href="' + link + '"' + target + '>' + text + '</a>', $.trim(text), link, targetBlank); | |
| + this.linkInsert('<a href="' + link + '"' + target + '>' + text + '</a>' + extra, $.trim(text), link, targetBlank); | |
| }, | |
| linkInsert: function (a, text, link, target) | |
| @@ -5533,21 +6487,37 @@ | |
| $(this.insert_link_node).text(text).attr('href', link); | |
| - if (target !== '') $(this.insert_link_node).attr('target', target); | |
| - else $(this.insert_link_node).removeAttr('target'); | |
| - | |
| - this.sync(); | |
| + if (target !== '') | |
| + { | |
| + $(this.insert_link_node).attr('target', target); | |
| + } | |
| + else | |
| + { | |
| + $(this.insert_link_node).removeAttr('target'); | |
| + } | |
| } | |
| else | |
| { | |
| - this.exec('inserthtml', a); | |
| + var $a = $(a).addClass('redactor-added-link'); | |
| + this.exec('inserthtml', this.outerHtml($a), false); | |
| + | |
| + var link = this.$editor.find('a.redactor-added-link'); | |
| + | |
| + link.removeAttr('style').removeClass('redactor-added-link').each(function() | |
| + { | |
| + if (this.className == '') $(this).removeAttr('class'); | |
| + }); | |
| + | |
| } | |
| + | |
| + this.sync(); | |
| } | |
| // link tooltip | |
| setTimeout($.proxy(function() | |
| { | |
| if (this.opts.observeLinks) this.observeLinks(); | |
| + | |
| }, this), 5); | |
| this.modalClose(); | |
| @@ -5570,7 +6540,7 @@ | |
| $('#redactor_filename').val(text); | |
| // dragupload | |
| - if (!this.isMobile()) | |
| + if (!this.isMobile() && !this.isIPad()) | |
| { | |
| this.draguploadInit('#redactor_file', { | |
| url: this.opts.fileUpload, | |
| @@ -5645,6 +6615,7 @@ | |
| // json | |
| if (this.opts.imageGetJson) | |
| { | |
| + | |
| $.getJSON(this.opts.imageGetJson, $.proxy(function(data) | |
| { | |
| var folders = {}, count = 0; | |
| @@ -5706,13 +6677,13 @@ | |
| } | |
| else | |
| { | |
| - $('#redactor_tabs').find('a').eq(1).remove(); | |
| + $('#redactor-tab-control-2').remove(); | |
| } | |
| if (this.opts.imageUpload || this.opts.s3) | |
| { | |
| // dragupload | |
| - if (!this.isMobile() && this.opts.s3 === false) | |
| + if (!this.isMobile() && !this.isIPad() && this.opts.s3 === false) | |
| { | |
| if ($('#redactor_file' ).length) | |
| { | |
| @@ -5761,13 +6732,17 @@ | |
| } | |
| else | |
| { | |
| - var tabs = $('#redactor_tabs').find('a'); | |
| - tabs.eq(0).remove(); | |
| - tabs.eq(1).addClass('redactor_tabs_act'); | |
| + $('#redactor-tab-control-1').remove(); | |
| + $('#redactor-tab-control-2').addClass('redactor_tabs_act'); | |
| $('#redactor_tab2').show(); | |
| } | |
| } | |
| + if (!this.opts.imageTabLink && (this.opts.imageUpload || this.opts.imageGetJson)) | |
| + { | |
| + $('#redactor-tab-control-3').hide(); | |
| + } | |
| + | |
| $('#redactor_upload_btn').click($.proxy(this.imageCallbackLink, this)); | |
| if (!this.opts.imageUpload && !this.opts.imageGetJson) | |
| @@ -5793,7 +6768,15 @@ | |
| { | |
| $('#redactor_file_alt').val($el.attr('alt')); | |
| $('#redactor_image_edit_src').attr('href', $el.attr('src')); | |
| - $('#redactor_form_image_align').val($el.css('float')); | |
| + | |
| + if ($el.css('display') == 'block' && $el.css('float') == 'none') | |
| + { | |
| + $('#redactor_form_image_align').val('center'); | |
| + } | |
| + else | |
| + { | |
| + $('#redactor_form_image_align').val($el.css('float')); | |
| + } | |
| if ($(parent).get(0).tagName === 'A') | |
| { | |
| @@ -5824,13 +6807,30 @@ | |
| }, | |
| imageRemove: function(el) | |
| { | |
| + var parentLink = $(el).parent().parent(); | |
| var parent = $(el).parent(); | |
| - $(el).remove(); | |
| + var parentEl = false; | |
| + | |
| + if (parentLink.length && parentLink[0].tagName === 'A') | |
| + { | |
| + parentEl = true; | |
| + $(parentLink).remove(); | |
| + } | |
| + else if (parent.length && parent[0].tagName === 'A') | |
| + { | |
| + parentEl = true; | |
| + $(parent).remove(); | |
| + } | |
| + else | |
| + { | |
| + $(el).remove(); | |
| + } | |
| if (parent.length && parent[0].tagName === 'P') | |
| { | |
| - this.$editor.focus(); | |
| - this.selectionStart(parent); | |
| + this.focusWithSaveScroll(); | |
| + | |
| + if (parentEl === false) this.selectionStart(parent); | |
| } | |
| // delete callback | |
| @@ -5841,29 +6841,33 @@ | |
| }, | |
| imageSave: function(el) | |
| { | |
| + this.imageResizeHide(false); | |
| + | |
| var $el = $(el); | |
| var parent = $el.parent(); | |
| $el.attr('alt', $('#redactor_file_alt').val()); | |
| var floating = $('#redactor_form_image_align').val(); | |
| + var margin = ''; | |
| if (floating === 'left') | |
| { | |
| - this.imageMargin = '0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + ' 0'; | |
| - $el.css({ 'float': 'left', 'margin': this.imageMargin }); | |
| + margin = '0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + ' 0'; | |
| + $el.css({ 'float': 'left', 'margin': margin }); | |
| } | |
| else if (floating === 'right') | |
| { | |
| - this.imageMargin = '0 0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + ''; | |
| - $el.css({ 'float': 'right', 'margin': this.imageMargin }); | |
| + margin = '0 0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + ''; | |
| + $el.css({ 'float': 'right', 'margin': margin }); | |
| + } | |
| + else if (floating === 'center') | |
| + { | |
| + $el.css({ 'float': '', 'display': 'block', 'margin': 'auto' }); | |
| } | |
| else | |
| { | |
| - this.imageMargin = '0px'; | |
| - var imageBox = $el.closest('#redactor-image-box'); | |
| - if (imageBox.size() != 0) imageBox.css({ 'float': '', 'margin': '' }); | |
| - $el.css({ 'float': '', 'margin': '' }); | |
| + $el.css({ 'float': '', 'display': '', 'margin': '' }); | |
| } | |
| // as link | |
| @@ -5928,13 +6932,15 @@ | |
| this.$editor.find('#redactor-image-editter, #redactor-image-resizer').remove(); | |
| + imageBox.find('img').css({ | |
| + marginTop: imageBox[0].style.marginTop, | |
| + marginBottom: imageBox[0].style.marginBottom, | |
| + marginLeft: imageBox[0].style.marginLeft, | |
| + marginRight: imageBox[0].style.marginRight | |
| + }); | |
| + | |
| + imageBox.css('margin', ''); | |
| - if (this.imageMargin != '0px') | |
| - { | |
| - imageBox.find('img').css('margin', this.imageMargin); | |
| - imageBox.css('margin', ''); | |
| - this.imageMargin = '0px'; | |
| - } | |
| imageBox.find('img').css('opacity', ''); | |
| imageBox.replaceWith(function() | |
| @@ -5991,63 +6997,66 @@ | |
| // resize | |
| var isResizing = false; | |
| - imageResizer.on('mousedown', function(e) | |
| + if (imageResizer !== false) | |
| { | |
| - isResizing = true; | |
| - e.preventDefault(); | |
| + imageResizer.on('mousedown', function(e) | |
| + { | |
| + isResizing = true; | |
| + e.preventDefault(); | |
| - ratio = $image.width() / $image.height(); | |
| + ratio = $image.width() / $image.height(); | |
| - start_x = Math.round(e.pageX - $image.eq(0).offset().left); | |
| - start_y = Math.round(e.pageY - $image.eq(0).offset().top); | |
| + start_x = Math.round(e.pageX - $image.eq(0).offset().left); | |
| + start_y = Math.round(e.pageY - $image.eq(0).offset().top); | |
| - }); | |
| + }); | |
| - $(this.document.body).on('mousemove', $.proxy(function(e) | |
| - { | |
| - if (isResizing) | |
| + $(this.document.body).on('mousemove', $.proxy(function(e) | |
| { | |
| - var mouse_x = Math.round(e.pageX - $image.eq(0).offset().left) - start_x; | |
| - var mouse_y = Math.round(e.pageY - $image.eq(0).offset().top) - start_y; | |
| - | |
| - var div_h = $image.height(); | |
| + if (isResizing) | |
| + { | |
| + var mouse_x = Math.round(e.pageX - $image.eq(0).offset().left) - start_x; | |
| + var mouse_y = Math.round(e.pageY - $image.eq(0).offset().top) - start_y; | |
| - var new_h = parseInt(div_h, 10) + mouse_y; | |
| - var new_w = Math.round(new_h * ratio); | |
| + var div_h = $image.height(); | |
| - if (new_w > min_w) | |
| - { | |
| - $image.width(new_w); | |
| + var new_h = parseInt(div_h, 10) + mouse_y; | |
| + var new_w = Math.round(new_h * ratio); | |
| - if (new_w < 100) | |
| - { | |
| - this.imageEditter.css({ | |
| - marginTop: '-7px', | |
| - marginLeft: '-13px', | |
| - fontSize: '9px', | |
| - padding: '3px 5px' | |
| - }); | |
| - } | |
| - else | |
| + if (new_w > min_w) | |
| { | |
| - this.imageEditter.css({ | |
| - marginTop: '-11px', | |
| - marginLeft: '-18px', | |
| - fontSize: '11px', | |
| - padding: '7px 10px' | |
| - }); | |
| + $image.width(new_w); | |
| + | |
| + if (new_w < 100) | |
| + { | |
| + this.imageEditter.css({ | |
| + marginTop: '-7px', | |
| + marginLeft: '-13px', | |
| + fontSize: '9px', | |
| + padding: '3px 5px' | |
| + }); | |
| + } | |
| + else | |
| + { | |
| + this.imageEditter.css({ | |
| + marginTop: '-11px', | |
| + marginLeft: '-18px', | |
| + fontSize: '11px', | |
| + padding: '7px 10px' | |
| + }); | |
| + } | |
| } | |
| - } | |
| - start_x = Math.round(e.pageX - $image.eq(0).offset().left); | |
| - start_y = Math.round(e.pageY - $image.eq(0).offset().top); | |
| + start_x = Math.round(e.pageX - $image.eq(0).offset().left); | |
| + start_y = Math.round(e.pageY - $image.eq(0).offset().top); | |
| - this.sync() | |
| - } | |
| - }, this)).on('mouseup', function() | |
| - { | |
| - isResizing = false; | |
| - }); | |
| + this.sync() | |
| + } | |
| + }, this)).on('mouseup', function() | |
| + { | |
| + isResizing = false; | |
| + }); | |
| + } | |
| this.$editor.on('keydown.redactor-image-delete', $.proxy(function(e) | |
| @@ -6056,7 +7065,7 @@ | |
| if (this.keyCode.BACKSPACE == key || this.keyCode.DELETE == key) | |
| { | |
| - this.bufferSet(); | |
| + this.bufferSet(false); | |
| this.imageResizeHide(false); | |
| this.imageRemove($image); | |
| } | |
| @@ -6081,12 +7090,21 @@ | |
| }); | |
| imageBox.attr('contenteditable', false); | |
| - this.imageMargin = $image[0].style.margin; | |
| - if (this.imageMargin != '0px') | |
| + if ($image[0].style.margin != 'auto') | |
| { | |
| - imageBox.css('margin', this.imageMargin); | |
| + imageBox.css({ | |
| + marginTop: $image[0].style.marginTop, | |
| + marginBottom: $image[0].style.marginBottom, | |
| + marginLeft: $image[0].style.marginLeft, | |
| + marginRight: $image[0].style.marginRight | |
| + }); | |
| + | |
| $image.css('margin', ''); | |
| } | |
| + else | |
| + { | |
| + imageBox.css({ 'display': 'block', 'margin': 'auto' }); | |
| + } | |
| $image.css('opacity', .5).after(imageBox); | |
| @@ -6094,7 +7112,7 @@ | |
| this.imageEditter = $('<span id="redactor-image-editter" data-redactor="verified">' + this.opts.curLang.edit + '</span>'); | |
| this.imageEditter.css({ | |
| position: 'absolute', | |
| - zIndex: 2, | |
| + zIndex: 5, | |
| top: '50%', | |
| left: '50%', | |
| marginTop: '-11px', | |
| @@ -6114,25 +7132,34 @@ | |
| imageBox.append(this.imageEditter); | |
| // resizer | |
| - var imageResizer = $('<span id="redactor-image-resizer" data-redactor="verified"></span>'); | |
| - imageResizer.css({ | |
| - position: 'absolute', | |
| - zIndex: 2, | |
| - lineHeight: 1, | |
| - cursor: 'nw-resize', | |
| - bottom: '-4px', | |
| - right: '-5px', | |
| - border: '1px solid #fff', | |
| - backgroundColor: '#000', | |
| - width: '8px', | |
| - height: '8px' | |
| - }); | |
| - imageResizer.attr('contenteditable', false); | |
| - imageBox.append(imageResizer); | |
| + if (this.opts.imageResizable) | |
| + { | |
| + var imageResizer = $('<span id="redactor-image-resizer" data-redactor="verified"></span>'); | |
| + imageResizer.css({ | |
| + position: 'absolute', | |
| + zIndex: 2, | |
| + lineHeight: 1, | |
| + cursor: 'nw-resize', | |
| + bottom: '-4px', | |
| + right: '-5px', | |
| + border: '1px solid #fff', | |
| + backgroundColor: '#000', | |
| + width: '8px', | |
| + height: '8px' | |
| + }); | |
| + imageResizer.attr('contenteditable', false); | |
| + imageBox.append(imageResizer); | |
| - imageBox.append($image); | |
| + imageBox.append($image); | |
| + | |
| + return imageResizer; | |
| + } | |
| + else | |
| + { | |
| + imageBox.append($image); | |
| - return imageResizer; | |
| + return false; | |
| + } | |
| }, | |
| imageThumbClick: function(e) | |
| { | |
| @@ -6165,7 +7192,6 @@ | |
| { | |
| this.selectionRestore(); | |
| - | |
| if (json !== false) | |
| { | |
| var html = ''; | |
| @@ -6201,16 +7227,31 @@ | |
| this.observeImages(); | |
| }, | |
| + // PROGRESS BAR | |
| + buildProgressBar: function() | |
| + { | |
| + if ($('#redactor-progress').size() != 0) return; | |
| + | |
| + this.$progressBar = $('<div id="redactor-progress"><span></span></div>'); | |
| + $(document.body).append(this.$progressBar); | |
| + }, | |
| + showProgressBar: function() | |
| + { | |
| + this.buildProgressBar(); | |
| + $('#redactor-progress').fadeIn(); | |
| + }, | |
| + hideProgressBar: function() | |
| + { | |
| + $('#redactor-progress').fadeOut(1500); | |
| + }, | |
| + | |
| // MODAL | |
| modalTemplatesInit: function() | |
| { | |
| $.extend( this.opts, | |
| { | |
| modal_file: String() | |
| - + '<section>' | |
| - + '<div id="redactor-progress" class="redactor-progress redactor-progress-striped" style="display: none;">' | |
| - + '<div id="redactor-progress-bar" class="redactor-progress-bar" style="width: 100%;"></div>' | |
| - + '</div>' | |
| + + '<section id="redactor-modal-file-insert">' | |
| + '<form id="redactorUploadFileForm" method="post" action="" enctype="multipart/form-data">' | |
| + '<label>' + this.opts.curLang.filename + '</label>' | |
| + '<input type="text" id="redactor_filename" class="redactor_input" />' | |
| @@ -6221,34 +7262,32 @@ | |
| + '</section>', | |
| modal_image_edit: String() | |
| - + '<section>' | |
| + + '<section id="redactor-modal-image-edit">' | |
| + '<label>' + this.opts.curLang.title + '</label>' | |
| - + '<input id="redactor_file_alt" class="redactor_input" />' | |
| + + '<input type="text" id="redactor_file_alt" class="redactor_input" />' | |
| + '<label>' + this.opts.curLang.link + '</label>' | |
| - + '<input id="redactor_file_link" class="redactor_input" />' | |
| + + '<input type="text" id="redactor_file_link" class="redactor_input" />' | |
| + '<label><input type="checkbox" id="redactor_link_blank"> ' + this.opts.curLang.link_new_tab + '</label>' | |
| + '<label>' + this.opts.curLang.image_position + '</label>' | |
| + '<select id="redactor_form_image_align">' | |
| + '<option value="none">' + this.opts.curLang.none + '</option>' | |
| + '<option value="left">' + this.opts.curLang.left + '</option>' | |
| + + '<option value="center">' + this.opts.curLang.center + '</option>' | |
| + '<option value="right">' + this.opts.curLang.right + '</option>' | |
| + '</select>' | |
| + '</section>' | |
| + '<footer>' | |
| - + '<button id="redactor_image_delete_btn" class="redactor_modal_btn redactor_modal_delete_btn">' + this.opts.curLang._delete + '</button> ' | |
| + + '<button id="redactor_image_delete_btn" class="redactor_modal_btn redactor_modal_delete_btn">' + this.opts.curLang._delete + '</button>' | |
| + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' | |
| - + '<input type="button" name="save" class="redactor_modal_btn redactor_modal_action_btn" id="redactorSaveBtn" value="' + this.opts.curLang.save + '" />' | |
| + + '<button id="redactorSaveBtn" class="redactor_modal_btn redactor_modal_action_btn">' + this.opts.curLang.save + '</button>' | |
| + '</footer>', | |
| modal_image: String() | |
| - + '<section>' | |
| + + '<section id="redactor-modal-image-insert">' | |
| + '<div id="redactor_tabs">' | |
| - + '<a href="#" class="redactor_tabs_act">' + this.opts.curLang.upload + '</a>' | |
| - + '<a href="#">' + this.opts.curLang.choose + '</a>' | |
| - + '<a href="#">' + this.opts.curLang.link + '</a>' | |
| - + '</div>' | |
| - + '<div id="redactor-progress" class="redactor-progress redactor-progress-striped" style="display: none;">' | |
| - + '<div id="redactor-progress-bar" class="redactor-progress-bar" style="width: 100%;"></div>' | |
| + + '<a href="#" id="redactor-tab-control-1" class="redactor_tabs_act">' + this.opts.curLang.upload + '</a>' | |
| + + '<a href="#" id="redactor-tab-control-2">' + this.opts.curLang.choose + '</a>' | |
| + + '<a href="#" id="redactor-tab-control-3">' + this.opts.curLang.link + '</a>' | |
| + '</div>' | |
| + '<form id="redactorInsertImageForm" method="post" action="" enctype="multipart/form-data">' | |
| + '<div id="redactor_tab1" class="redactor_tab">' | |
| @@ -6260,51 +7299,30 @@ | |
| + '</form>' | |
| + '<div id="redactor_tab3" class="redactor_tab" style="display: none;">' | |
| + '<label>' + this.opts.curLang.image_web_link + '</label>' | |
| - + '<input type="text" name="redactor_file_link" id="redactor_file_link" class="redactor_input" />' | |
| + + '<input type="text" name="redactor_file_link" id="redactor_file_link" class="redactor_input" /><br><br>' | |
| + '</div>' | |
| + '</section>' | |
| + '<footer>' | |
| + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' | |
| - + '<input type="button" name="upload" class="redactor_modal_btn redactor_modal_action_btn" id="redactor_upload_btn" value="' + this.opts.curLang.insert + '" />' | |
| + + '<button class="redactor_modal_btn redactor_modal_action_btn" id="redactor_upload_btn">' + this.opts.curLang.insert + '</button>' | |
| + '</footer>', | |
| modal_link: String() | |
| - + '<section>' | |
| - + '<form id="redactorInsertLinkForm" method="post" action="">' | |
| - + '<div id="redactor_tabs">' | |
| - + '<a href="#" class="redactor_tabs_act">URL</a>' | |
| - + '<a href="#">Email</a>' | |
| - + '<a href="#">' + this.opts.curLang.anchor + '</a>' | |
| - + '</div>' | |
| - + '<input type="hidden" id="redactor_tab_selected" value="1" />' | |
| - + '<div class="redactor_tab" id="redactor_tab1">' | |
| - + '<label>URL</label>' | |
| - + '<input type="text" id="redactor_link_url" class="redactor_input" />' | |
| - + '<label>' + this.opts.curLang.text + '</label>' | |
| - + '<input type="text" class="redactor_input redactor_link_text" id="redactor_link_url_text" />' | |
| - + '<label><input type="checkbox" id="redactor_link_blank"> ' + this.opts.curLang.link_new_tab + '</label>' | |
| - + '</div>' | |
| - + '<div class="redactor_tab" id="redactor_tab2" style="display: none;">' | |
| - + '<label>Email</label>' | |
| - + '<input type="text" id="redactor_link_mailto" class="redactor_input" />' | |
| - + '<label>' + this.opts.curLang.text + '</label>' | |
| - + '<input type="text" class="redactor_input redactor_link_text" id="redactor_link_mailto_text" />' | |
| - + '</div>' | |
| - + '<div class="redactor_tab" id="redactor_tab3" style="display: none;">' | |
| - + '<label>' + this.opts.curLang.anchor + '</label>' | |
| - + '<input type="text" class="redactor_input" id="redactor_link_anchor" />' | |
| - + '<label>' + this.opts.curLang.text + '</label>' | |
| - + '<input type="text" class="redactor_input redactor_link_text" id="redactor_link_anchor_text" />' | |
| - + '</div>' | |
| - + '</form>' | |
| + + '<section id="redactor-modal-link-insert">' | |
| + + '<select id="redactor-predefined-links" style="width: 99.5%; display: none;"></select>' | |
| + + '<label>URL</label>' | |
| + + '<input type="text" class="redactor_input" id="redactor_link_url" />' | |
| + + '<label>' + this.opts.curLang.text + '</label>' | |
| + + '<input type="text" class="redactor_input" id="redactor_link_url_text" />' | |
| + + '<label><input type="checkbox" id="redactor_link_blank"> ' + this.opts.curLang.link_new_tab + '</label>' | |
| + '</section>' | |
| + '<footer>' | |
| + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' | |
| - + '<input type="button" class="redactor_modal_btn redactor_modal_action_btn" id="redactor_insert_link_btn" value="' + this.opts.curLang.insert + '" />' | |
| + + '<button id="redactor_insert_link_btn" class="redactor_modal_btn redactor_modal_action_btn">' + this.opts.curLang.insert + '</button>' | |
| + '</footer>', | |
| modal_table: String() | |
| - + '<section>' | |
| + + '<section id="redactor-modal-table-insert">' | |
| + '<label>' + this.opts.curLang.rows + '</label>' | |
| + '<input type="text" size="5" value="2" id="redactor_table_rows" />' | |
| + '<label>' + this.opts.curLang.columns + '</label>' | |
| @@ -6312,11 +7330,11 @@ | |
| + '</section>' | |
| + '<footer>' | |
| + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' | |
| - + '<input type="button" name="upload" class="redactor_modal_btn redactor_modal_action_btn" id="redactor_insert_table_btn" value="' + this.opts.curLang.insert + '" />' | |
| + + '<button id="redactor_insert_table_btn" class="redactor_modal_btn redactor_modal_action_btn">' + this.opts.curLang.insert + '</button>' | |
| + '</footer>', | |
| modal_video: String() | |
| - + '<section>' | |
| + + '<section id="redactor-modal-video-insert">' | |
| + '<form id="redactorInsertVideoForm">' | |
| + '<label>' + this.opts.curLang.video_html_code + '</label>' | |
| + '<textarea id="redactor_insert_video_area" style="width: 99%; height: 160px;"></textarea>' | |
| @@ -6324,51 +7342,114 @@ | |
| + '</section>' | |
| + '<footer>' | |
| + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' | |
| - + '<input type="button" class="redactor_modal_btn redactor_modal_action_btn" id="redactor_insert_video_btn" value="' + this.opts.curLang.insert + '" />' | |
| + + '<button id="redactor_insert_video_btn" class="redactor_modal_btn redactor_modal_action_btn">' + this.opts.curLang.insert + '</button>' | |
| + '</footer>' | |
| }); | |
| }, | |
| modalInit: function(title, content, width, callback) | |
| { | |
| - var $redactorModalOverlay = $('#redactor_modal_overlay'); | |
| + this.modalSetOverlay(); | |
| - // modal overlay | |
| - if (!$redactorModalOverlay.length) | |
| + this.$redactorModalWidth = width; | |
| + this.$redactorModal = $('#redactor_modal'); | |
| + | |
| + if (!this.$redactorModal.length) | |
| { | |
| - this.$overlay = $redactorModalOverlay = $('<div id="redactor_modal_overlay" style="display: none;"></div>'); | |
| - $('body').prepend(this.$overlay); | |
| + this.$redactorModal = $('<div id="redactor_modal" style="display: none;" />'); | |
| + this.$redactorModal.append($('<div id="redactor_modal_close">×</div>')); | |
| + this.$redactorModal.append($('<header id="redactor_modal_header" />')); | |
| + this.$redactorModal.append($('<div id="redactor_modal_inner" />')); | |
| + this.$redactorModal.appendTo(document.body); | |
| } | |
| - if (this.opts.modalOverlay) | |
| + $('#redactor_modal_close').on('click', $.proxy(this.modalClose, this)); | |
| + $(document).on('keyup', $.proxy(this.modalCloseHandler, this)); | |
| + this.$editor.on('keyup', $.proxy(this.modalCloseHandler, this)); | |
| + | |
| + this.modalSetContent(content); | |
| + this.modalSetTitle(title); | |
| + this.modalSetDraggable(); | |
| + this.modalLoadTabs(); | |
| + this.modalOnCloseButton(); | |
| + this.modalSetButtonsWidth(); | |
| + | |
| + this.saveModalScroll = this.document.body.scrollTop; | |
| + if (this.opts.autoresize === false) | |
| { | |
| - $redactorModalOverlay.show().on('click', $.proxy(this.modalClose, this)); | |
| + this.saveModalScroll = this.$editor.scrollTop(); | |
| } | |
| - var $redactorModal = $('#redactor_modal'); | |
| + if (this.isMobile() === false) this.modalShowOnDesktop(); | |
| + else this.modalShowOnMobile(); | |
| - if (!$redactorModal.length) | |
| + // modal actions callback | |
| + if (typeof callback === 'function') | |
| { | |
| - this.$modal = $redactorModal = $('<div id="redactor_modal" style="display: none;"><div id="redactor_modal_close">×</div><header id="redactor_modal_header"></header><div id="redactor_modal_inner"></div></div>'); | |
| - $('body').append(this.$modal); | |
| + callback(); | |
| } | |
| - $('#redactor_modal_close').on('click', $.proxy(this.modalClose, this)); | |
| + // modal shown callback | |
| + setTimeout($.proxy(function() | |
| + { | |
| + this.callback('modalOpened', this.$redactorModal); | |
| + | |
| + }, this), 11); | |
| - this.hdlModalClose = $.proxy(function(e) | |
| + // fix bootstrap modal focus | |
| + $(document).off('focusin.modal'); | |
| + | |
| + // enter | |
| + this.$redactorModal.find('input[type=text]').on('keypress', $.proxy(function(e) | |
| { | |
| - if (e.keyCode === this.keyCode.ESC) | |
| + if (e.which === 13) | |
| { | |
| - this.modalClose(); | |
| - return false; | |
| + this.$redactorModal.find('.redactor_modal_action_btn').click(); | |
| + e.preventDefault(); | |
| } | |
| + }, this)); | |
| - }, this); | |
| + return this.$redactorModal; | |
| + | |
| + }, | |
| + modalShowOnDesktop: function() | |
| + { | |
| + this.$redactorModal.css({ | |
| + position: 'fixed', | |
| + top: '-2000px', | |
| + left: '50%', | |
| + width: this.$redactorModalWidth + 'px', | |
| + marginLeft: '-' + (this.$redactorModalWidth / 2) + 'px' | |
| + }).show(); | |
| - $(document).keyup(this.hdlModalClose); | |
| - this.$editor.keyup(this.hdlModalClose); | |
| + this.modalSaveBodyOveflow = $(document.body).css('overflow'); | |
| + $(document.body).css('overflow', 'hidden'); | |
| - // set content | |
| + setTimeout($.proxy(function() | |
| + { | |
| + var height = this.$redactorModal.outerHeight(); | |
| + this.$redactorModal.css({ | |
| + top: '50%', | |
| + height: 'auto', | |
| + minHeight: 'auto', | |
| + marginTop: '-' + (height + 10) / 2 + 'px' | |
| + }); | |
| + }, this), 15); | |
| + }, | |
| + modalShowOnMobile: function() | |
| + { | |
| + this.$redactorModal.css({ | |
| + position: 'fixed', | |
| + width: '100%', | |
| + height: '100%', | |
| + top: '0', | |
| + left: '0', | |
| + margin: '0', | |
| + minHeight: '300px' | |
| + }).show(); | |
| + }, | |
| + modalSetContent: function(content) | |
| + { | |
| this.modalcontent = false; | |
| if (content.indexOf('#') == 0) | |
| { | |
| @@ -6381,104 +7462,85 @@ | |
| { | |
| $('#redactor_modal_inner').empty().append(content); | |
| } | |
| - | |
| - $redactorModal.find('#redactor_modal_header').html(title); | |
| - | |
| - // draggable | |
| - if (typeof $.fn.draggable !== 'undefined') | |
| + }, | |
| + modalSetTitle: function(title) | |
| + { | |
| + this.$redactorModal.find('#redactor_modal_header').html(title); | |
| + }, | |
| + modalSetButtonsWidth: function() | |
| + { | |
| + var buttons = this.$redactorModal.find('footer button').not('.redactor_modal_btn_hidden'); | |
| + var buttonsSize = buttons.size(); | |
| + if (buttonsSize > 0) | |
| { | |
| - $redactorModal.draggable({ handle: '#redactor_modal_header' }); | |
| - $redactorModal.find('#redactor_modal_header').css('cursor', 'move'); | |
| + $(buttons).css('width', (this.$redactorModalWidth/buttonsSize) + 'px') | |
| } | |
| - | |
| - var $redactor_tabs = $('#redactor_tabs'); | |
| - | |
| - // tabs | |
| - if ($redactor_tabs.length ) | |
| + }, | |
| + modalOnCloseButton: function() | |
| + { | |
| + this.$redactorModal.find('.redactor_btn_modal_close').on('click', $.proxy(this.modalClose, this)); | |
| + }, | |
| + modalSetOverlay: function() | |
| + { | |
| + if (this.opts.modalOverlay) | |
| { | |
| - var that = this; | |
| - $redactor_tabs.find('a').each(function(i, s) | |
| + this.$redactorModalOverlay = $('#redactor_modal_overlay'); | |
| + if (!this.$redactorModalOverlay.length) | |
| { | |
| - 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)); | |
| + this.$redactorModalOverlay = $('<div id="redactor_modal_overlay" style="display: none;"></div>'); | |
| + $('body').prepend(this.$redactorModalOverlay); | |
| + } | |
| - // save scroll | |
| - if (this.opts.autoresize === true) | |
| - { | |
| - this.saveModalScroll = this.document.body.scrollTop; | |
| + this.$redactorModalOverlay.show().on('click', $.proxy(this.modalClose, this)); | |
| } | |
| - else | |
| + }, | |
| + modalSetDraggable: function() | |
| + { | |
| + if (typeof $.fn.draggable !== 'undefined') | |
| { | |
| - this.saveModalScroll = this.$editor.scrollTop(); | |
| + this.$redactorModal.draggable({ handle: '#redactor_modal_header' }); | |
| + this.$redactorModal.find('#redactor_modal_header').css('cursor', 'move'); | |
| } | |
| + }, | |
| + modalLoadTabs: function() | |
| + { | |
| + var $redactor_tabs = $('#redactor_tabs'); | |
| + if (!$redactor_tabs.length) return false; | |
| - if (this.isMobile() === false) | |
| + var that = this; | |
| + $redactor_tabs.find('a').each(function(i, s) | |
| { | |
| - $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'); | |
| + i++; | |
| + $(s).on('click', function(e) | |
| + { | |
| + e.preventDefault(); | |
| - } | |
| - else | |
| - { | |
| - $redactorModal.css({ | |
| - position: 'fixed', | |
| - width: '100%', | |
| - height: '100%', | |
| - top: '0', | |
| - left: '0', | |
| - margin: '0', | |
| - minHeight: '300px' | |
| - }).show(); | |
| - } | |
| + $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); | |
| - // callback | |
| - if (typeof callback === 'function') callback(); | |
| + if (that.isMobile() === false) | |
| + { | |
| + var height = that.$redactorModal.outerHeight(); | |
| + that.$redactorModal.css('margin-top', '-' + (height + 10) / 2 + 'px'); | |
| + } | |
| + }); | |
| + }); | |
| - if (this.isMobile() === false) | |
| + }, | |
| + modalCloseHandler: function(e) | |
| + { | |
| + if (e.keyCode === this.keyCode.ESC) | |
| { | |
| - setTimeout(function() | |
| - { | |
| - var height = $redactorModal.outerHeight(); | |
| - $redactorModal.css({ | |
| - top: '50%', | |
| - height: 'auto', | |
| - minHeight: 'auto', | |
| - marginTop: '-' + (height + 10) / 2 + 'px' | |
| - }); | |
| - }, 10); | |
| + this.modalClose(); | |
| + return false; | |
| } | |
| - | |
| }, | |
| modalClose: function() | |
| { | |
| - $('#redactor_modal_close').off('click', this.modalClose ); | |
| + $('#redactor_modal_close').off('click', this.modalClose); | |
| $('#redactor_modal').fadeOut('fast', $.proxy(function() | |
| { | |
| var redactorModalInner = $('#redactor_modal_inner'); | |
| @@ -6496,8 +7558,8 @@ | |
| $('#redactor_modal_overlay').hide().off('click', this.modalClose); | |
| } | |
| - $(document).unbind('keyup', this.hdlModalClose); | |
| - this.$editor.unbind('keyup', this.hdlModalClose); | |
| + $(document).off('keyup', this.modalCloseHandler); | |
| + this.$editor.off('keyup', this.modalCloseHandler); | |
| this.selectionRestore(); | |
| @@ -6511,6 +7573,8 @@ | |
| this.$editor.scrollTop(this.saveModalScroll); | |
| } | |
| + this.callback('modalClosed'); | |
| + | |
| }, this)); | |
| @@ -6555,13 +7619,14 @@ | |
| xhr.open('GET', this.opts.s3 + mark + 'name=' + file.name + '&type=' + file.type, true); | |
| // Hack to pass bytes through unprocessed. | |
| - xhr.overrideMimeType('text/plain; charset=x-user-defined'); | |
| + if (xhr.overrideMimeType) xhr.overrideMimeType('text/plain; charset=x-user-defined'); | |
| + var that = this; | |
| xhr.onreadystatechange = function(e) | |
| { | |
| if (this.readyState == 4 && this.status == 200) | |
| { | |
| - $('#redactor-progress').fadeIn(); | |
| + that.showProgressBar(); | |
| callback(decodeURIComponent(this.responseText)); | |
| } | |
| else if(this.readyState == 4 && this.status != 200) | |
| @@ -6606,7 +7671,7 @@ | |
| { | |
| //setProgress(100, 'Upload completed.'); | |
| - $('#redactor-progress, #redactor-progress-drag').hide(); | |
| + this.hideProgressBar(); | |
| var s3image = url.split('?'); | |
| @@ -6716,7 +7781,7 @@ | |
| }, | |
| uploadSubmit: function(e) | |
| { | |
| - $('#redactor-progress').fadeIn(); | |
| + this.showProgressBar(); | |
| this.uploadForm(this.element, this.uploadFrame()); | |
| }, | |
| uploadFrame: function() | |
| @@ -6797,7 +7862,7 @@ | |
| // Success | |
| if (this.uploadOptions.success) | |
| { | |
| - $('#redactor-progress').hide(); | |
| + this.hideProgressBar(); | |
| if (typeof d !== 'undefined') | |
| { | |
| @@ -6873,15 +7938,13 @@ | |
| e.preventDefault(); | |
| this.dropareabox.removeClass('hover').addClass('drop'); | |
| - | |
| - this.dragUploadAjax(this.draguploadOptions.url, e.dataTransfer.files[0], false, false, false, this.draguploadOptions.uploadParam); | |
| + this.showProgressBar(); | |
| + this.dragUploadAjax(this.draguploadOptions.url, e.dataTransfer.files[0], false, e, this.draguploadOptions.uploadParam); | |
| }, this ); | |
| }, | |
| - dragUploadAjax: function(url, file, directupload, progress, e, uploadParam) | |
| + dragUploadAjax: function(url, file, directupload, e, uploadParam) | |
| { | |
| - | |
| - | |
| if (!directupload) | |
| { | |
| var xhr = $.ajaxSettings.xhr(); | |
| @@ -6895,6 +7958,9 @@ | |
| }); | |
| } | |
| + // drop callback | |
| + this.callback('drop', e); | |
| + | |
| var fd = new FormData(); | |
| // append file data | |
| @@ -6933,13 +7999,10 @@ | |
| var json = (typeof data === 'string' ? $.parseJSON(data) : data); | |
| + this.hideProgressBar(); | |
| + | |
| if (directupload) | |
| { | |
| - progress.fadeOut('slow', function() | |
| - { | |
| - $(this).remove(); | |
| - }); | |
| - | |
| var $img = $('<img>'); | |
| $img.attr('src', json.filelink).attr('id', 'drag-image-marker'); | |
| @@ -6995,6 +8058,10 @@ | |
| { | |
| return /(iPhone|iPod|BlackBerry|Android)/.test(navigator.userAgent); | |
| }, | |
| + isIPad: function() | |
| + { | |
| + return /iPad/.test(navigator.userAgent); | |
| + }, | |
| normalize: function(str) | |
| { | |
| if (typeof(str) === 'undefined') return 0; | |
| @@ -7004,6 +8071,12 @@ | |
| { | |
| return $('<div>').append($(el).eq(0).clone()).html(); | |
| }, | |
| + stripHtml: function(html) | |
| + { | |
| + var tmp = document.createElement("DIV"); | |
| + tmp.innerHTML = html; | |
| + return tmp.textContent || tmp.innerText || ""; | |
| + }, | |
| isString: function(obj) | |
| { | |
| return Object.prototype.toString.call(obj) == '[object String]'; | |
| @@ -7014,23 +8087,47 @@ | |
| html = html.replace(/\s/g, ''); | |
| html = html.replace(/^<p>[^\W\w\D\d]*?<\/p>$/i, ''); | |
| - | |
| return html == ''; | |
| }, | |
| + getInternetExplorerVersion: function() | |
| + { | |
| + var rv = false; | |
| + if (navigator.appName == 'Microsoft Internet Explorer') | |
| + { | |
| + var ua = navigator.userAgent; | |
| + var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); | |
| + if (re.exec(ua) != null) | |
| + { | |
| + rv = parseFloat(RegExp.$1); | |
| + } | |
| + } | |
| + | |
| + return rv; | |
| + }, | |
| + isIe11: function() | |
| + { | |
| + return !!navigator.userAgent.match(/Trident\/7\./); | |
| + }, | |
| 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) | |
| - || []; | |
| + var match = /(opr)[\/]([\w.]+)/.exec( ua ) || | |
| + /(chrome)[ \/]([\w.]+)/.exec( ua ) || | |
| + /(webkit)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(ua) || | |
| + /(webkit)[ \/]([\w.]+)/.exec( ua ) || | |
| + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || | |
| + /(msie) ([\w.]+)/.exec( ua ) || | |
| + ua.indexOf("trident") >= 0 && /(rv)(?::| )([\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'); | |
| + if (match[1] == 'rv') return browser == 'msie'; | |
| + if (match[1] == 'opr') return browser == 'webkit'; | |
| + | |
| + return browser == match[1]; | |
| - return match[1] == browser; | |
| }, | |
| oldIE: function() | |
| { | |
| @@ -7121,11 +8218,9 @@ | |
| // LINKIFY | |
| $.Redactor.fn.formatLinkify = function(protocol, convertLinks, convertImageLinks, convertVideoLinks, linkSize) | |
| { | |
| - var url1 = /(^|<|\s)(www\..+?\..+?)(\s|>|$)/g, | |
| - url2 = /(^|<|\s)(((https?|ftp):\/\/|mailto:).+?)(\s|>|$)/g, | |
| - urlImage = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif))/gi, | |
| - urlYoutube = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig, | |
| - urlVimeo = /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/; | |
| + var url = /(((https?|ftps?):\/\/)|www[.][^\s])(.+?\..+?)([.),]?)(\s|\.\s+|\)|$)/gi, | |
| + rProtocol = /(https?|ftp):\/\//i, | |
| + urlImage = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif))/gi; | |
| var childNodes = (this.$editor ? this.$editor.get(0) : this).childNodes, i = childNodes.length; | |
| while (i--) | |
| @@ -7141,14 +8236,14 @@ | |
| var iframeStart = '<iframe width="500" height="281" src="', | |
| iframeEnd = '" frameborder="0" allowfullscreen></iframe>'; | |
| - if (html.match(urlYoutube)) | |
| + if (html.match(reUrlYoutube)) | |
| { | |
| - html = html.replace(urlYoutube, iframeStart + '//www.youtube.com/embed/$1' + iframeEnd); | |
| + html = html.replace(reUrlYoutube, iframeStart + '//www.youtube.com/embed/$1' + iframeEnd); | |
| $(n).after(html).remove(); | |
| } | |
| - else if (html.match(urlVimeo)) | |
| + else if (html.match(reUrlVimeo)) | |
| { | |
| - html = html.replace(urlVimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd); | |
| + html = html.replace(reUrlVimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd); | |
| $(n).after(html).remove(); | |
| } | |
| } | |
| @@ -7162,18 +8257,33 @@ | |
| } | |
| // link | |
| - if (convertLinks && html && (html.match(url1) || html.match(url2))) | |
| + if (convertLinks && html && html.match(url)) | |
| { | |
| - var href = (html.match(url1) || html.match(url2)); | |
| - href = href[0]; | |
| - if (href.length > linkSize) href = href.substring(0, linkSize) + '...'; | |
| + var matches = html.match(url); | |
| + | |
| + for (var i in matches) | |
| + { | |
| + var href = matches[i]; | |
| + var text = href; | |
| + | |
| + var space = ''; | |
| + if (href.match(/\s$/) !== null) space = ' '; | |
| - html = html.replace(/&/g, '&') | |
| - .replace(/</g, '<') | |
| - .replace(/>/g, '>') | |
| - .replace(url1, '$1<a href="' + protocol + '$2">' + $.trim(href) + '</a>$3') | |
| - .replace(url2, '$1<a href="$2">' + $.trim(href) + '</a>$5'); | |
| + var addProtocol = protocol; | |
| + if (href.match(rProtocol) !== null) addProtocol = ''; | |
| + if (text.length > linkSize) text = text.substring(0, linkSize) + '...'; | |
| + | |
| + text = text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') | |
| + | |
| + /* | |
| + To handle URLs which may have $ characters in them, need to escape $ -> $$ to prevent $1 from getting treated as a backreference. | |
| + See http://gotofritz.net/blog/code-snippets/escaping-in-replace-strings-in-javascript/ | |
| + */ | |
| + var escapedBackReferences = text.replace('$', '$$$'); | |
| + | |
| + html = html.replace(href, '<a href=\"' + addProtocol + $.trim(href) + '\">' + $.trim(escapedBackReferences) + '</a>' + space); | |
| + } | |
| $(n).after(html).remove(); | |
| } | |
| diff --git a/scripts/redactor/ueditor-templates.html b/scripts/redactor/ueditor-templates.html | |
| index dcbc2dd..a61be69 100755 | |
| --- a/scripts/redactor/ueditor-templates.html | |
| +++ b/scripts/redactor/ueditor-templates.html | |
| @@ -113,16 +113,16 @@ | |
| </div> | |
| <ul class="upfront-font-icons-controlls"> | |
| <li> | |
| - <label for="font-icons-size"> | |
| + <label> | |
| Size: | |
| </label> | |
| - <input id="font-icons-size" class="upfront-field-number" type="number" value="27" step="1" min="16" max="200"> | |
| + <input class="upfront-field-number font-icons-size" type="number" value="27" step="1" min="16" max="200"> | |
| </li> | |
| <li class="font-icons-top-li"> | |
| - <label for="font-icons-top"> | |
| + <label> | |
| Top: | |
| </label> | |
| - <input id="font-icons-top" class="upfront-field-number" type="number" value="0" step="1" min="-35" max="45"> | |
| + <input class="upfront-field-number font-icons-top" type="number" value="0" step="1" min="-35" max="45"> | |
| </li> | |
| </ul> | |
| </script> | |
| diff --git a/scripts/redactor/ueditor.js b/scripts/redactor/ueditor.js | |
| index 5826efc..3b90141 100755 | |
| --- a/scripts/redactor/ueditor.js | |
| +++ b/scripts/redactor/ueditor.js | |
| @@ -82,6 +82,41 @@ var hackRedactor = function(){ | |
| this.set(this.content, false, false); | |
| }; | |
| + // Let Ctrl/Cmd+A (yeah...) work normally | |
| + $.Redactor.prototype.airEnable = function () { | |
| + if (!this.opts.air || !this.opts.airButtons) return; | |
| + var _cmd_keys = [224, 17, 91, 93]; // Yay for Mac OS X | |
| + | |
| + this.$editor.on('mouseup.redactor keyup.redactor', this, $.proxy(function(e) { | |
| + var insert = $(e.target).closest('.ueditor-insert'); | |
| + if(insert.length && insert.closest(this.$box).length) | |
| + return; | |
| + | |
| + var text = this.getSelectionText(); | |
| + this.opts.toolbarFixedTopOffset = "50"; | |
| + if (e.type === 'mouseup' && text != '') this.airShow(e); | |
| + if (e.type === 'keyup' && e.shiftKey && text != '') { | |
| + var $focusElem = $(this.getElement(this.getSelection().focusNode)), offset = $focusElem.offset(); | |
| + offset.height = $focusElem.height(); | |
| + this.airShow(offset, true); | |
| + } | |
| + // Additional ctrl/cmd stuffs | |
| + if ('keyup' === e.type && e.ctrlKey && '' != text) this.airShow(e); // Ctrl | |
| + if ('keyup' === e.type && _cmd_keys.indexOf(e.which) > 0 && '' != text) this.airShow(e); // Cmd (?) | |
| + /** | |
| + * If redactor is to high for the user to see it, show it under the selected text | |
| + */ | |
| + if( this.$air.offset().top < 0 ){ | |
| + this.$air.css({ | |
| + top : e.clientY + 14 + this.$box.position().top + "px" | |
| + }); | |
| + this.$air.addClass("under"); | |
| + }else{ | |
| + this.$air.removeClass("under"); | |
| + } | |
| + }, this)); | |
| + }; | |
| + | |
| // We already have all the plugins' methods in redactor, just call init | |
| $.Redactor.prototype.buildPlugins = function() { | |
| var me = this; | |
| @@ -94,42 +129,8 @@ var hackRedactor = function(){ | |
| }); | |
| }; | |
| - // Let Ctrl/Cmd+A (yeah...) work normally | |
| - $.Redactor.prototype.airEnable = function () { | |
| - if (!this.opts.air || !this.opts.airButtons) return; | |
| - var _cmd_keys = [224, 17, 91, 93]; // Yay for Mac OS X | |
| - | |
| - this.$editor.on('mouseup.redactor keyup.redactor', this, $.proxy(function(e) { | |
| - var insert = $(e.target).closest('.ueditor-insert'); | |
| - if(insert.length && insert.closest(this.$box).length) | |
| - return; | |
| - | |
| - var text = this.getSelectionText(); | |
| -// console.log("this", this); | |
| - this.opts.toolbarFixedTopOffset = "50"; | |
| - if (e.type === 'mouseup' && text != '') this.airShow(e); | |
| - if (e.type === 'keyup' && e.shiftKey && text != '') { | |
| - var $focusElem = $(this.getElement(this.getSelection().focusNode)), offset = $focusElem.offset(); | |
| - offset.height = $focusElem.height(); | |
| - this.airShow(offset, true); | |
| - } | |
| - // Additional ctrl/cmd stuffs | |
| - if ('keyup' === e.type && e.ctrlKey && '' != text) this.airShow(e); // Ctrl | |
| - if ('keyup' === e.type && _cmd_keys.indexOf(e.which) > 0 && '' != text) this.airShow(e); // Cmd (?) | |
| - /** | |
| - * If redactor is to high for the user to see it, show it under the selected text | |
| - */ | |
| - if( this.$air.offset().top < 0 ){ | |
| - this.$air.css({ | |
| - top : e.clientY + 14 + this.$box.position().top + "px" | |
| - }); | |
| - this.$air.addClass("under"); | |
| - }else{ | |
| - this.$air.removeClass("under"); | |
| - } | |
| - }, this)); | |
| - }; | |
| + | |
| // Make click consistent | |
| $.Redactor.prototype.airBindHide = function () { | |
| if (!this.opts.air) return; | |
| @@ -140,7 +141,8 @@ var hackRedactor = function(){ | |
| if ($(e.target).closest(this.$toolbar).length === 0) { | |
| if (!this.getSelectionText()) { | |
| this.$air.fadeOut(100); | |
| - //this.selectionRemove(); | |
| + $(".redactor_dropdown").hide(); | |
| + this.$toolbar.find(".dropact").removeClass("dropact"); | |
| $(doc).off(e); | |
| } | |
| } | |
| @@ -148,10 +150,8 @@ var hackRedactor = function(){ | |
| if (e.which === this.keyCode.ESC) { | |
| this.getSelection().collapseToStart(); | |
| } | |
| - | |
| this.$air.fadeOut(100); | |
| $(doc).off(e); | |
| - | |
| }, this)); | |
| }, this); | |
| @@ -197,7 +197,7 @@ var hackRedactor = function(){ | |
| $('.redactor_air').hide(); | |
| - this.selectionRemoveMarkers(); | |
| + // this.selectionRemoveMarkers(); | |
| this.selectionSave(); | |
| var width = this.airWidth || this.$air.width(), | |
| @@ -246,7 +246,7 @@ var hackRedactor = function(){ | |
| this.airBindHide(); | |
| this.$air.trigger('show'); | |
| - }, | |
| + }; | |
| // Add possiblity to disable linebreak (for one line title) | |
| $.Redactor.prototype.doInsertLineBreak = $.Redactor.prototype.insertLineBreak; | |
| @@ -256,6 +256,7 @@ var hackRedactor = function(){ | |
| return this.doInsertLineBreak(); | |
| return false; | |
| }; | |
| + | |
| /* | |
| $.Redactor.prototype.getCurrent = function(){ | |
| var el = false; | |
| @@ -269,6 +270,9 @@ var hackRedactor = function(){ | |
| return this.isParentRedactor(el); | |
| }; | |
| */ | |
| + | |
| + | |
| + | |
| hackedRedactor = true; | |
| $.Redactor.prototype.events = UeditorEvents; | |
| @@ -303,7 +307,7 @@ var Ueditor = function($el, options) { | |
| focus: true, | |
| cleanup: false, | |
| plugins: plugins, | |
| - airButtons: ['upfrontFormatting', 'bold', 'italic', 'blockquote', 'upfrontLink', 'stateLists', 'stateAlign', 'upfrontColor', 'icons'], | |
| + airButtons: ['upfrontFormatting', 'bold', 'italic', 'blockquote', 'upfrontLink', 'stateLists', 'stateAlign', 'upfrontColor', 'upftonIcons'], | |
| buttonsCustom: {}, | |
| activeButtonsAdd: {}, | |
| observeLinks: false, | |
| @@ -314,7 +318,8 @@ var Ueditor = function($el, options) { | |
| ; | |
| /* --- Redactor allows for single callbacks - let's dispatch events instead --- */ | |
| - | |
| + this.options.dropdownShowCallback = function () { UeditorEvents.trigger("ueditor:dropdownShow", this); }; | |
| + this.options.dropdownHideCallback = function () { UeditorEvents.trigger("ueditor:dropdownHide", this); }; | |
| this.options.initCallback = function () { UeditorEvents.trigger("ueditor:init", this); }; | |
| this.options.enterCallback = function () { UeditorEvents.trigger("ueditor:enter", this); }; | |
| this.options.changeCallback = function () { UeditorEvents.trigger("ueditor:change", this); }; | |
| @@ -522,7 +527,7 @@ Ueditor.prototype = { | |
| } | |
| }, | |
| pluginList: function(options){ | |
| - var allPlugins = ['stateAlignment', 'stateAlignmentCTA', 'stateLists', 'blockquote', 'stateButtons', 'upfrontLink', 'upfrontLinkCTA', 'upfrontColor', 'panelButtons', /* 'upfrontMedia', 'upfrontImages', */'upfrontFormatting', 'upfrontSink', 'upfrontPlaceholder', 'icons'], | |
| + var allPlugins = ['stateAlignment', 'stateLists', 'blockquote', 'stateButtons', 'upfrontLink', 'upfrontColor', 'panelButtons', /* 'upfrontMedia', 'upfrontImages', */'upfrontFormatting', 'upfrontSink', 'upfrontPlaceholder', 'upftonIcons'], | |
| pluginList = [] | |
| ; | |
| $.each(allPlugins, function(i, name){ | |
| @@ -573,29 +578,40 @@ Ueditor.prototype = { | |
| if (!RedactorPlugins) var RedactorPlugins = {}; | |
| +UpfrontRedactorPanels = _.extend(RedactorPlugins, { | |
| + init : function(){ | |
| + console.log(this.buttons); | |
| + } | |
| +}); | |
| /* | |
| STATE BUTTONS PLUGIN | |
| */ | |
| RedactorPlugins.stateButtons = { | |
| - beforeInit: function(){ | |
| + init: function(){ | |
| + var self = this; | |
| this.addStateButtons(); | |
| this.startStateObserver(); | |
| - }, | |
| + }, | |
| addStateButtons: function(){ | |
| if(this.stateButtons) | |
| return; | |
| var me = this; | |
| - | |
| this.stateButtons = {}; | |
| $.each(this.opts.stateButtons, function(id, data){ | |
| var button = new me.StateButton(id, data); | |
| - me.stateButtons[id] = button; | |
| - me.opts.buttonsCustom[id] = button; | |
| + me.buttonAdd(id, data.title, function(){ me.stateCallback( id, button ) }); | |
| + // set state of button | |
| + me.$air.on("show", function(){ | |
| + button.guessState(me); | |
| + }); | |
| }); | |
| }, | |
| - | |
| + stateCallback : function( id, button ){ | |
| + button.guessState( this ); | |
| + button.callback(id, this.buttonGet(id) ,button ); | |
| + }, | |
| startStateObserver: function(){ | |
| var observer = $.proxy(this.stateObserver, this); | |
| this.$element.on('mouseup.redactor keyup.redactor', observer); | |
| @@ -640,7 +656,6 @@ RedactorPlugins.stateButtons = { | |
| }; | |
| me.setState = function(id, el){ | |
| this.currentState = id; | |
| - | |
| el.removeClass(this.iconClasses) | |
| .addClass(this.states[this.currentState].iconClass) | |
| ; | |
| @@ -656,15 +671,11 @@ RedactorPlugins.stateButtons = { | |
| }); | |
| if(!found) | |
| found = this.defaultState; | |
| - | |
| - | |
| - this.setState(found, this.getElement(redactor)); | |
| + this.setState(found, redactor.buttonGet(this.id)); | |
| }; | |
| - | |
| me.getElement = function(redactor){ | |
| return redactor.$toolbar.find('.redactor_btn_' + this.id); | |
| }; | |
| - | |
| return { | |
| id: id, | |
| title: data.title, | |
| @@ -687,6 +698,7 @@ RedactorPlugins.stateButtons = { | |
| --------------------- */ | |
| RedactorPlugins.stateAlignment = { | |
| beforeInit: function(){ | |
| + var self = this; | |
| this.opts.stateButtons.stateAlign = { | |
| title: 'Text alignment', | |
| defaultState: 'left', | |
| @@ -700,7 +712,7 @@ RedactorPlugins.stateAlignment = { | |
| return $parent.length && $parent.css('text-align') == 'left'; | |
| }, | |
| callback: function(name, el , button){ | |
| - this.alignmentLeft(); | |
| + self.alignmentLeft(); | |
| } | |
| }, | |
| center: { | |
| @@ -712,7 +724,7 @@ RedactorPlugins.stateAlignment = { | |
| return $parent.length && $parent.css('text-align') == 'center'; | |
| }, | |
| callback: function(name, el , button){ | |
| - this.alignmentCenter(); | |
| + self.alignmentCenter(); | |
| } | |
| }, | |
| right: { | |
| @@ -724,7 +736,7 @@ RedactorPlugins.stateAlignment = { | |
| return $parent.length && $parent.css('text-align') == 'right'; | |
| }, | |
| callback: function(name, el , button){ | |
| - this.alignmentRight(); | |
| + self.alignmentRight(); | |
| } | |
| }, | |
| justify: { | |
| @@ -736,7 +748,7 @@ RedactorPlugins.stateAlignment = { | |
| return $parent.length && $parent.css('text-align') == 'justify'; | |
| }, | |
| callback: function(name, el , button){ | |
| - this.alignmentJustify(); | |
| + self.alignmentJustify(); | |
| } | |
| } | |
| } | |
| @@ -744,65 +756,10 @@ RedactorPlugins.stateAlignment = { | |
| } | |
| } | |
| -RedactorPlugins.stateAlignmentCTA = { | |
| - beforeInit: function(){ | |
| - this.opts.stateButtons.stateAlignCTA = { | |
| - title: 'Text alignment', | |
| - defaultState: 'left', | |
| - states: { | |
| - left: { | |
| - iconClass: 'ueditor-left', | |
| - isActive: function(redactor){ | |
| - | |
| - return true; | |
| - | |
| - }, | |
| - callback: function(name, el , button){ | |
| - this.$element.css('text-align', 'left'); | |
| - //this.alignmentLeft(); | |
| - } | |
| - }, | |
| - center: { | |
| - iconClass: 'ueditor-center', | |
| - isActive: function(redactor){ | |
| - | |
| - return true; | |
| - | |
| - }, | |
| - callback: function(name, el , button){ | |
| - this.$element.css('text-align', 'center'); | |
| - //this.alignmentCenter(); | |
| - } | |
| - }, | |
| - right: { | |
| - iconClass: 'ueditor-right', | |
| - isActive: function(redactor){ | |
| - | |
| - return true; | |
| - | |
| - }, | |
| - callback: function(name, el , button){ | |
| - this.$element.css('text-align', 'right'); | |
| - } | |
| - }, | |
| - justify: { | |
| - iconClass: 'ueditor-justify', | |
| - isActive: function(redactor){ | |
| - | |
| - return true; | |
| - | |
| - }, | |
| - callback: function(name, el , button){ | |
| - this.$element.css('text-align', 'justify'); | |
| - } | |
| - } | |
| - } | |
| - } | |
| - } | |
| -} | |
| RedactorPlugins.stateLists = { | |
| beforeInit: function(){ | |
| + var self = this; | |
| this.opts.stateButtons.stateLists = { | |
| title: 'List style', | |
| defaultState: 'none', | |
| @@ -814,7 +771,7 @@ RedactorPlugins.stateLists = { | |
| return $parent.length && $parent.css('text-align') == 'left'; | |
| }, | |
| callback: function(name, el , button){ | |
| - this.execLists('insertorderedlist', 'orderedlist'); | |
| + self.execLists('insertorderedlist', 'orderedlist'); | |
| } | |
| }, | |
| unordered: { | |
| @@ -829,7 +786,7 @@ RedactorPlugins.stateLists = { | |
| return false; | |
| }, | |
| callback: function(name, el , button){ | |
| - this.execLists('insertunorderedlist', 'unorderedlist'); | |
| + self.execLists('insertunorderedlist', 'unorderedlist'); | |
| } | |
| }, | |
| ordered: { | |
| @@ -844,7 +801,7 @@ RedactorPlugins.stateLists = { | |
| return false; | |
| }, | |
| callback: function(name, el , button){ | |
| - this.execLists('insertorderedlist', 'orderedlist'); | |
| + self.execLists('insertorderedlist', 'orderedlist'); | |
| } | |
| } | |
| } | |
| @@ -857,13 +814,21 @@ RedactorPlugins.stateLists = { | |
| -------------------*/ | |
| RedactorPlugins.panelButtons = { | |
| + beforeInit : function(){ | |
| + var self = this; | |
| + // $.each(this.opts.buttonsCustom, function(id, b){ | |
| + // console.log(id, b); | |
| + // self.buttonAdd(id, b.title); | |
| + // }); | |
| + }, | |
| init: function(){ | |
| var me = this; | |
| $.each(this.opts.buttonsCustom, function(id, b){ | |
| if(b.panel){ | |
| var $panel = $('<div class="redactor_dropdown ueditor_panel redactor_dropdown_box_' + id + '" style="display: none;">'), | |
| - $button = me.$toolbar.find('.redactor_btn_' + id) | |
| + $button = me.buttonGet( id ) | |
| ; | |
| + | |
| b.panel = new b.panel({redactor: me, button: $button, panel: $panel}); | |
| $panel.html(b.panel.$el); | |
| $panel.appendTo(me.$toolbar); | |
| @@ -892,6 +857,38 @@ RedactorPlugins.panelButtons = { | |
| e.stopPropagation(); | |
| }) | |
| ; | |
| + me.buttonAdd(id, b.title, function(){ | |
| + var $button = me.buttonGet( id ), | |
| + left = $button.position().left; | |
| + | |
| + $(".re-icon").removeClass( "redactor_act dropact" ); | |
| + $button.addClass("redactor_act dropact"); | |
| + $(".redactor_dropdown").not($panel).hide(); | |
| + | |
| + $panel.css("left", left + "px").toggle(); | |
| + | |
| + | |
| + /** | |
| + * Triggers panel open or close events | |
| + */ | |
| + if( $panel.is(":visible") && typeof b.panel.open === "function" ){ | |
| + b.panel.open.apply(b.panel, [jQuery.Event( "open" ), me]); | |
| + }else{ | |
| + if( typeof b.panel.close === "function" ){ | |
| + b.panel.close.apply(jQuery.Event( "close" ), [$.Event, me]); | |
| + } | |
| + } | |
| + | |
| + /** | |
| + * Makes sure the last button's panel is kept under the toolbar | |
| + * @type {[type]} | |
| + */ | |
| + var $last = $(".redactor_dropdown.ueditor_panel").last(), | |
| + lastDropdownLeft = left - $last.innerWidth() + $button.width(); | |
| + $last.css( "left", lastDropdownLeft + "px" ); | |
| + }, false); | |
| + | |
| + | |
| } | |
| }); | |
| } | |
| @@ -969,6 +966,13 @@ var UeditorPanel = Backbone.View.extend({ | |
| -----------------------*/ | |
| RedactorPlugins.upfrontLink = { | |
| + // init : function(){ | |
| + // this.buttonAdd("link", "Link", this.openPanel); | |
| + // }, | |
| + openPanel : function(){ | |
| + var left = this.buttonGet( "link" ).position().left; | |
| + $(".redactor_dropdown_box_upfrontLink").css("left", left + "px").toggle(); | |
| + }, | |
| beforeInit: function(){ | |
| this.opts.buttonsCustom.upfrontLink = { | |
| title: 'Link', | |
| @@ -1062,93 +1066,6 @@ RedactorPlugins.upfrontLink = { | |
| }) | |
| } | |
| -RedactorPlugins.upfrontLinkCTA = { | |
| - beforeInit: function(){ | |
| - this.opts.buttonsCustom.upfrontLinkCTA = { | |
| - title: 'Link', | |
| - panel: this.panel | |
| - }; | |
| - }, | |
| - panel: UeditorPanel.extend({ | |
| - tpl: _.template($(tpl).find('#link-tpl').html()), | |
| - events:{ | |
| - open: 'open' | |
| - }, | |
| - initialize: function(){ | |
| - this.linkPanel = new Upfront.Views.Editor.LinkPanel({linkTypes: {unlink: true}, button: true}); | |
| - this.bindEvents(); | |
| - UeditorPanel.prototype.initialize.apply(this, arguments); | |
| - }, | |
| - render: function(options){ | |
| - options = options || {}; | |
| - console.log(options); | |
| - this.linkPanel.model.set({ | |
| - url: options.url, | |
| - type: options.link || this.guessLinkType(options.url) | |
| - }); | |
| - | |
| - this.linkPanel.render(); | |
| - this.$el.html(this.linkPanel.el); | |
| - this.linkPanel.delegateEvents(); | |
| - }, | |
| - open: function(e, redactor){ | |
| - this.redactor = redactor; | |
| - | |
| - var link = redactor.currentOrParentIs('A'); | |
| - | |
| - if(link){ | |
| - this.render({url: $(link).attr('href'), link: $(link).attr('rel') || 'external'}); | |
| - } | |
| - else | |
| - this.render(); | |
| - }, | |
| - close: function(e, redactor){ | |
| - this.redactor.selectionRemoveMarkers(); | |
| - }, | |
| - unlink: function(e){ | |
| - if(e) | |
| - e.preventDefault(); | |
| - this.redactor.$element.attr('href', '#'); | |
| - | |
| - }, | |
| - link: function(url, type){ | |
| - if(url){ | |
| - this.redactor.$element.attr('href', url); | |
| - } | |
| - }, | |
| - | |
| - bindEvents: function(){ | |
| - this.listenTo(this.linkPanel, 'link:ok', function(data){ | |
| - if(data.type == 'unlink') | |
| - this.unlink(); | |
| - else | |
| - this.link(data.url, data.type); | |
| - | |
| - this.closeToolbar(); | |
| - }); | |
| - | |
| - this.listenTo(this.linkPanel, 'link:postselector', this.disableEditorStop); | |
| - | |
| - this.listenTo(this.linkPanel, 'link:postselected', function(data){ | |
| - this.enableEditorStop(); | |
| - this.link(data.url, data.type); | |
| - }); | |
| - }, | |
| - | |
| - guessLinkType: function(url){ | |
| - if(!$.trim(url)) | |
| - return 'unlink'; | |
| - if(url.lenght && url[0] == '#') | |
| - return 'anchor'; | |
| - if(url.substring(0, location.origin.length) == location.origin) | |
| - return 'entry'; | |
| - | |
| - return 'external'; | |
| - } | |
| - | |
| - }) | |
| -} | |
| - | |
| RedactorPlugins.upfrontColor = { | |
| beforeInit: function(){ | |
| this.opts.buttonsCustom.upfrontColor = { | |
| @@ -1162,21 +1079,26 @@ RedactorPlugins.upfrontColor = { | |
| events:{ | |
| 'open': 'open' | |
| }, | |
| + close : function(e, redactor){ | |
| + redactor.cleanRemoveEmptyTags(redactor.getCurrent()); | |
| + }, | |
| setCurrentColors: function() { | |
| - var parent = this.redactor.getParent(); | |
| - if(parent || (parent && $(parent).prop('tagName')=='INLINE')) { | |
| - var rgb_a = $(parent).css('background-color').split(','); | |
| + var parent = this.redactor.getCurrent(); | |
| + if( (parent && $(parent).prop('tagName')=='INLINE') || $( parent ).hasClass(".upfront_theme_colors")) { | |
| + | |
| + var bg_color = tinycolor($(parent).css('background-color')); | |
| this.current_color = $(parent).css('color'); | |
| - if(rgb_a.length < 4 || parseFloat(rgb_a[3].replace(')', '')) > 0) | |
| + if(bg_color.getAlpha() > 0) | |
| this.current_bg = $(parent).css('background-color'); | |
| - | |
| } | |
| else { | |
| this.current_color = this.current_bg = false; | |
| } | |
| }, | |
| open: function(e, redactor){ | |
| + redactor.selectionSave(); | |
| + this.updateIcon(); | |
| this.setCurrentColors(); | |
| var self = this, | |
| foreground_picker = new Upfront.Views.Editor.Field.Color({ | |
| @@ -1192,7 +1114,7 @@ RedactorPlugins.upfrontColor = { | |
| showInput: true, | |
| allowEmpty: true, | |
| change: function(color) { | |
| - self.updateColors(); | |
| + self.current_color = color; | |
| }, | |
| move: function(color) { | |
| redactor.selectionRestore(true, false); | |
| @@ -1214,7 +1136,7 @@ RedactorPlugins.upfrontColor = { | |
| showInput: true, | |
| allowEmpty: true, | |
| change: function(color) { | |
| - self.updateColors(); | |
| + self.current_bg = color; | |
| }, | |
| move: function(color) { | |
| redactor.selectionRestore(true, false); | |
| @@ -1275,10 +1197,12 @@ RedactorPlugins.upfrontColor = { | |
| // this.$('input.foreground').spectrum('resetUI'); | |
| // this.$('input.background').spectrum('resetUI'); | |
| // | |
| -console.log("color picker opened"); | |
| + | |
| this.$(".sp-choose").on("click", function(){ | |
| + self.updateColors(); | |
| self.closePanel(); | |
| self.closeToolbar(); | |
| + self.redactor.dropdownHideAll(); | |
| }); | |
| }, | |
| render: function(){ | |
| @@ -1295,9 +1219,7 @@ console.log("color picker opened"); | |
| redac.bufferAirBindHide = this.redactor.airBindHide; | |
| redac.airBindHide = function() { | |
| - | |
| self.updateIcon(); | |
| - | |
| redac.bufferAirBindHide(); | |
| }; | |
| @@ -1320,142 +1242,150 @@ console.log("color picker opened"); | |
| updateIcon : function () { | |
| var self = this; | |
| self.setCurrentColors(); | |
| - | |
| if(self.current_bg){ | |
| var color = tinycolor( self.current_bg ); | |
| if( color.getAlpha() === 0 ){ | |
| - this.redactor.$toolbar.find('.redactor_btn.redactor_btn_upfrontColor').css('border-color', color.toRgbString()); | |
| + this.redactor.$toolbar.find('.re-icon.re-upfrontColor').addClass('transparent').css('border-color', ""); | |
| }else{ | |
| - this.redactor.$toolbar.find('.redactor_btn.redactor_btn_upfrontColor').removeClass('transparent').css('border-color', color.toRgbString()); | |
| + this.redactor.$toolbar.find('.re-icon.re-upfrontColor').removeClass('transparent').css('border-color', color.toRgbString()); | |
| } | |
| } | |
| else{ | |
| - this.redactor.$toolbar.find('.redactor_btn.redactor_btn_upfrontColor').addClass('transparent').css('border-color', ''); | |
| + this.redactor.$toolbar.find('.re-icon.re-upfrontColor').addClass('transparent').css('border-color', ''); | |
| } | |
| if(self.current_color) | |
| - this.redactor.$toolbar.find('.redactor_btn.redactor_btn_upfrontColor').css('color', self.current_color ); | |
| + this.redactor.$toolbar.find('.re-icon.re-upfrontColor').css('color', self.current_color ); | |
| else | |
| - this.redactor.$toolbar.find('.redactor_btn.redactor_btn_upfrontColor').css('color', ''); | |
| + this.redactor.$toolbar.find('.re-icon.re-upfrontColor').css('color', ''); | |
| }, | |
| updateColors : function() { | |
| - var self = this; | |
| + | |
| + var self = this, | |
| + parent = this.redactor.getParent(), | |
| + bg = ""; | |
| + bg_class = "", | |
| + html = ""; | |
| + | |
| + /** | |
| + * Set background color | |
| + */ | |
| + if(self.current_bg && typeof(self.current_bg) == 'object') { | |
| + this.redactor.inlineRemoveStyle("background-color"); | |
| + bg = 'background-color:' + self.current_bg.toRgbString(); | |
| + bg_class = Upfront.Views.Theme_Colors.colors.get_css_class( self.current_bg.toHexString(), true ); | |
| + | |
| + if( bg_class ){ | |
| + bg = ""; | |
| + bg_class += " upfront_theme_colors"; | |
| + }else{ | |
| + bg_class = "inline_color"; | |
| + } | |
| + } | |
| + | |
| + /** | |
| + * Set font color | |
| + */ | |
| if(self.current_color && typeof(self.current_color) == 'object') { | |
| var theme_color_classname = Upfront.Views.Theme_Colors.colors.get_css_class( self.current_color.toHexString() ); | |
| if( theme_color_classname ){ | |
| var current = this.redactor.getCurrent(); | |
| if( !$(current).hasClass(theme_color_classname) ){ | |
| - // remove inline color if any | |
| - // this.redactor.inlineRemoveStyle("color"); | |
| - | |
| - // this.redactor.inlineRemoveStyle('color'); | |
| - // this.redactor.inlineRemoveClass("inline_color"); | |
| - var html = this.redactor.getSelectionHtml(); | |
| - $(html).removeClass("inline_color upfront_theme_colors"); | |
| - $(html).css("color", ""); | |
| - $(html).children().removeClass("inline_color upfront_theme_colors"); | |
| - $(html).children().css("color", ""); | |
| - | |
| - html = "<span class='upfront_theme_colors " + theme_color_classname + "'>" + html + "</span>"; | |
| - if( $(this.redactor.getCurrent()).hasClass("upfront_theme_colors") ){ | |
| - $(this.redactor.getCurrent()).replaceWith( html ); | |
| - }else{ | |
| - this.redactor.execCommand("inserthtml", html, true); | |
| - } | |
| + | |
| + this.redactor.selectionRestore(true, true); | |
| + this.redactor.bufferSet(); | |
| + this.redactor.$editor.focus(); | |
| + this.redactor.inlineRemoveStyle("color"); | |
| + this.redactor.inlineRemoveClass( "upfront_theme_colors" ); | |
| + this.redactor.inlineRemoveClass( "inline_color" ); | |
| + html = this.redactor.cleanHtml(this.redactor.cleanRemoveEmptyTags(this.redactor.getSelectionHtml())); | |
| + | |
| + html = "<span class='upfront_theme_colors " + theme_color_classname + " " + bg_class + "' style='" + bg + "'>" + html + "</span>"; | |
| + //this.redactor.execCommand("inserthtml", html, true); | |
| } | |
| }else{ | |
| - this.redactor.selectionRestore(true, false); | |
| - // make sure it doesn't have any theme color classes | |
| + // Making sure it doesn't have any theme color classes | |
| _.each(Upfront.Views.Theme_Colors.colors.get_all_classes(), function( cls ){ | |
| self.redactor.inlineRemoveClass( cls ); | |
| }); | |
| - this.redactor.inlineRemoveClass( "upfront_theme_colors" ); | |
| - this.redactor.inlineRemoveClass( "inline_color" ); | |
| - var html = this.redactor.cleanHtml(this.redactor.cleanRemoveEmptyTags(this.redactor.getSelectionHtml())); | |
| - | |
| - $(html).removeClass("upfront_theme_colors"); | |
| - $(html).removeClass("inline_color"); | |
| - $(html).css("color", ""); | |
| - $(html).children().removeClass("inline_color"); | |
| - $(html).children().removeClass("upfront_theme_colors"); | |
| - $(html).children().css("color", ""); | |
| - // $(this.redactor.getCurrent()).removeClass("inline_color"); | |
| - html = "<span class='inline_color' style='color: " + self.current_color.toRgbString() + "'>" + html + "</span>"; | |
| - if( $(this.redactor.getCurrent()).hasClass("inline_color") ){ | |
| - $(this.redactor.getCurrent()).replaceWith( html ); | |
| - }else{ | |
| - this.redactor.execCommand("inserthtml", html, true); | |
| - // $(this.redactor.getCurrent()).replaceWith( html ); | |
| - } | |
| - | |
| - // this.redactor.inlineSetStyle('color', self.current_color.toRgbString()); | |
| - } | |
| + this.redactor.selectionRestore(true, true); | |
| + this.redactor.bufferSet(); | |
| + this.redactor.$editor.focus(); | |
| + this.redactor.inlineRemoveStyle("color"); | |
| + this.redactor.inlineRemoveClass( "upfront_theme_colors" ); | |
| + this.redactor.inlineRemoveClass( "inline_color" ); | |
| + html = this.redactor.cleanHtml(this.redactor.cleanRemoveEmptyTags(this.redactor.getSelectionHtml())); | |
| + html = "<inline class='inline_color' style='color: " + self.current_color.toRgbString() + ";" + bg +"'>" + html + "</inline>"; | |
| + | |
| + } | |
| } | |
| - if(self.current_bg && typeof(self.current_bg) == 'object') { | |
| - this.redactor.selectionRestore(true, false); | |
| - this.redactor.inlineRemoveStyle('background-color'); | |
| - // if(self.current_bg.toRgbString().toLowerCase() != 'rgba(0, 0, 0, 0)') | |
| - this.redactor.inlineSetStyle('background-color', self.current_bg.toRgbString()); | |
| + | |
| + if( html === "" ){ | |
| + html = this.redactor.cleanHtml(this.redactor.cleanRemoveEmptyTags(this.redactor.getSelectionHtml())); | |
| + html = "<inline class='" + bg_class + "' style='" + bg +"'>" + html + "</inline>"; | |
| } | |
| + | |
| + this.redactor.execCommand("inserthtml", html, true); | |
| + | |
| + // Doing more cleanup | |
| + if( $.trim( $(parent).text() ).localeCompare( $.trim( $(html).text() ) ) === 0 && ( $(parent).hasClass("inline_color") || $(parent).hasClass("upfront_theme_colors") ) ){ | |
| + // $(parent).replaceWith( html ); | |
| + } | |
| self.updateIcon(); | |
| - self.redactor.selectionRemove(); | |
| - self.redactor.sync(); | |
| - | |
| + self.redactor.selectionRemoveMarkers(); | |
| + self.redactor.syncClean(); | |
| } | |
| - | |
| }) | |
| }; | |
| RedactorPlugins.upfrontFormatting = { | |
| - beforeInit: function(){ | |
| - this.opts.buttonsCustom.upfrontFormatting = { | |
| - title: 'Formatting', | |
| - panel: this.panel | |
| - }; | |
| + init: function(){ | |
| + var self = this, | |
| + buttons = {}, | |
| + tags = { | |
| + p: 'P', | |
| + h1: 'H1', | |
| + h2: 'H2', | |
| + h3: 'H3', | |
| + h4: 'H4', | |
| + h5: 'H5', | |
| + pre: '</>', | |
| + blockquote: '"' | |
| + }; | |
| + $.each( tags, function( id, tag ){ | |
| + buttons[id] = { title: tag, callback: self.applyTag }; | |
| + } ); | |
| + this.buttonAddFirst('upfrontFormatting', 'Formatting', false, buttons); | |
| + | |
| + UeditorEvents.on("ueditor:dropdownShow", function(){ | |
| + var tag = $(self.getElement()).length ? $(self.getElement())[0].tagName : false; | |
| + if( tag ){ | |
| + tag = tag.toLowerCase(); | |
| + $(".redactor_dropdown_box_upfrontFormatting a").removeClass("active"); | |
| + $(".redactor_dropdown_" + tag).addClass("active"); | |
| + } | |
| + }); | |
| }, | |
| - panel: UeditorPanel.extend({ | |
| - tags: { | |
| - p: 'P', | |
| - h1: 'H1', | |
| - h2: 'H2', | |
| - h3: 'H3', | |
| - h4: 'H4', | |
| - h5: 'H5', | |
| - pre: '</>', | |
| - blockquote: '"' | |
| - }, | |
| - events: { | |
| - 'click .ueditor-format-option': 'applyTag', | |
| - 'open': 'selectionSave' | |
| - }, | |
| - render: function(){ | |
| - var me = this, | |
| - out = '' | |
| - ; | |
| - _.each(this.redactor.opts.formattingTags, function(tag){ | |
| - out += '<a class="ueditor-format-option ueditor-format-' + tag + '" data-value="' + tag + '">' + me.tags[tag] + '</a>'; | |
| - }); | |
| + applyTag: function(tag){ | |
| + this.selectionRestore(true, true); | |
| + this.bufferSet(); | |
| + this.$editor.focus(); | |
| + var text_align = $( this.getCurrent() ).css("text-align"); | |
| - this.button.html('¶'); | |
| - this.$el.html(out); | |
| - }, | |
| - applyTag: function(e){ | |
| - var tag = $(e.target).data('value'); | |
| - this.redactor.selectionRestore(); | |
| - this.redactor.formatBlocks(tag); | |
| - this.closePanel(); | |
| - }, | |
| - selectionSave: function(e){ | |
| - this.redactor.selectionSave(); | |
| - } | |
| - }) | |
| + this.formatBlocks(tag); | |
| + | |
| + if( typeof text_align !== "undefined" ) | |
| + this.blockSetStyle( "text-align", text_align ); | |
| + | |
| + this.dropdownHideAll(); | |
| + } | |
| }; | |
| RedactorPlugins.blockquote = { | |
| @@ -2298,7 +2228,7 @@ RedactorPlugins.upfrontPlaceholder = { | |
| if (placeholder === '') placeholder = false; | |
| if (placeholder !== false) | |
| { | |
| - this.placeholderRemove(); | |
| + this.placeholderRemoveFromEditor(); | |
| this.$placeholder = this.$editor.clone(false); | |
| this.$placeholder.attr('contenteditable', false).removeClass('ueditable redactor_editor').addClass('ueditor-placeholder').html( this.opts.linebreaks ? placeholder : this.cleanParagraphy(placeholder) ); | |
| this.$editor.after(this.$placeholder); | |
| @@ -2332,13 +2262,13 @@ RedactorPlugins.upfrontPlaceholder = { | |
| /*-------------------- | |
| Font icons button | |
| -----------------------*/ | |
| -RedactorPlugins.icons = { | |
| +RedactorPlugins.upftonIcons = { | |
| + $sel : false, | |
| beforeInit: function(){ | |
| - this.opts.buttonsCustom.icons = { | |
| + this.opts.buttonsCustom.upftonIcons = { | |
| title: 'Icons', | |
| panel: this.panel | |
| }; | |
| - | |
| }, | |
| init : function(){ | |
| UeditorEvents.on("ueditor:key:down", function(redactor, e){ | |
| @@ -2352,7 +2282,8 @@ RedactorPlugins.icons = { | |
| panel: UeditorPanel.extend(_.extend({}, Upfront.Views.Mixins.Upfront_Scroll_Mixin, { | |
| tpl: _.template($(tpl).find('#font-icons').html()), | |
| events:{ | |
| - 'click .ueditor-font-icon': 'select_icon', | |
| + 'click .ueditor-font-icon': 'insert_icon', | |
| + // "change input.font-icons-top" : 'update_offset', | |
| 'open': 'open', | |
| 'closed': 'close' | |
| }, | |
| @@ -2364,30 +2295,42 @@ RedactorPlugins.icons = { | |
| this.redactor = redactor; | |
| this.redactor.selectionRestore(); | |
| this.redactor.selectionSave(); | |
| - this.select_current_icon(); | |
| + this.set_current_icon(); | |
| + | |
| this.$el.parent().css({ | |
| left : 193 | |
| }); | |
| }, | |
| close : function(){ | |
| - this.redactor.selectionRemoveMarkers(); | |
| + if( this.redactor ){ | |
| + this.redactor.selectionRemoveMarkers(); | |
| + } | |
| }, | |
| - select_icon : function(e){ | |
| - this.redactor.selectionRestore(true, false); | |
| + // update_offset : function( e ){ | |
| + // console.log(this.$sel); | |
| + // if( this.$sel && this.$sel.hasClass( "uf_font_icon" ) ){ | |
| + // window.$sel = this.$sel; | |
| + // this.$sel.css("top", parseFloat( $(e.target).val() ) + "px" ); | |
| + // this.redactor.selectionRestore(); | |
| + // this.redactor.sync(); | |
| + // } | |
| + // }, | |
| + insert_icon : function(e){ | |
| + this.redactor.selectionRestore(true, false); | |
| var $icon = $( $(e.target).hasClass("ueditor-font-icon") ? $(e.target).html() : $(e.target).closest(".ueditor-font-icon").html() ), | |
| - fontSize = this.$("#font-icons-size").val(), | |
| - top = this.$("#font-icons-top").val(); | |
| + fontSize = this.$(".font-icons-size").val(), | |
| + top = this.$(".font-icons-top").val(); | |
| $icon.css({ | |
| "font-size" : fontSize + "px", | |
| "top" : top + "px" | |
| }); | |
| this.redactor.execCommand("inserthtml", $icon[0].outerHTML , true); | |
| - // $(this.redactor.getCurrent()).replaceWith( $icon ); | |
| this.redactor.sync(); | |
| this.closePanel(); | |
| }, | |
| - select_current_icon : function(){ | |
| + set_current_icon : function(){ | |
| this.redactor.selectionRestore(true, false); | |
| + window.re = this.redactor; | |
| var $sel = $(this.redactor.getParent()).eq(0), | |
| self = this; | |
| @@ -2395,25 +2338,26 @@ RedactorPlugins.icons = { | |
| if( $sel.parent().hasClass("uf_font_icon") ) {$sel = $sel.parent()}; | |
| } | |
| if( $sel.hasClass("uf_font_icon") ){ | |
| - this.$("#font-icons-size").val( parseFloat( $sel.css("font-size") ) ); | |
| - this.$("#font-icons-top").val( parseFloat( $sel.css("top") ) ); | |
| + this.$(".font-icons-size").val( parseFloat( $sel.css("font-size") ) ); | |
| + this.$(".font-icons-top").val( parseFloat( $sel.css("top") ) ); | |
| this.$(".upfront-font-icons-controlls input").on("change", function(e){ | |
| e.stopPropagation(); | |
| e.preventDefault(); | |
| + self.redactor.selectionSave(); | |
| + self.redactor.bufferSet(); | |
| var val = $(this).val() + "px"; | |
| - | |
| - if( this.id === "font-icons-size" ){ | |
| + | |
| + if( $(this).hasClass("font-icons-size") ){ | |
| $sel.css("font-size", val); | |
| } | |
| - if( this.id === "font-icons-top" ){ | |
| + if( $(this).hasClass( "font-icons-top" ) ){ | |
| $sel.css("top", val); | |
| } | |
| self.redactor.sync(); | |
| self.redactor.selectionRestore(); | |
| - // self.redactor.execCommand("inserthtml", $sel[0].outerHTML , true); | |
| }); | |
| diff --git a/scripts/upfront/upfront-views-editor.js b/scripts/upfront/upfront-views-editor.js | |
| index 99398eb..ffbd804 100644 | |
| --- a/scripts/upfront/upfront-views-editor.js | |
| +++ b/scripts/upfront/upfront-views-editor.js | |
| @@ -1763,28 +1763,30 @@ define([ | |
| color = this.color_to_hex( color ); | |
| return _.indexOf(this.get_colors(), color) !== -1 | |
| }, | |
| - get_css_class : function(color){ | |
| + get_css_class : function(color, bg){ | |
| color = this.color_to_hex( color ); | |
| + var prefix = _.isUndefined( bg ) || bg === false ? "upfront_theme_color_" : "upfront_theme_bg_color_"; | |
| if( this.is_theme_color(color) ){ | |
| var model = this.findWhere({ | |
| color : color | |
| }); | |
| if( model ){ | |
| var index = this.indexOf( model ); | |
| - return "upfront_theme_color_" + index; | |
| + return prefix + index; | |
| } | |
| } | |
| return false | |
| }, | |
| - get_all_classes : function(){ | |
| + get_all_classes : function( bg ){ | |
| + var prefix = _.isUndefined( bg ) || bg === false ? "upfront_theme_color_" : "upfront_theme_bg_color_"; | |
| var classes = []; | |
| _.each( this.get_colors(), function(item, index){ | |
| - classes.push("upfront_theme_color_" + index); | |
| + classes.push(prefix + index); | |
| }); | |
| return classes; | |
| }, | |
| - remove_theme_color_classes : function( $el ){ | |
| - _.each(this.get_all_classes(), function(cls){ | |
| + remove_theme_color_classes : function( $el, bg ){ | |
| + _.each(this.get_all_classes( bg ), function(cls){ | |
| $el.removeClass(cls); | |
| }); | |
| }, | |
| @@ -1855,6 +1857,9 @@ define([ | |
| self.styles += " .upfront_theme_color_" + index +"{ color: " + item.get("color") + ";}"; | |
| self.styles += " a .upfront_theme_color_" + index +":hover{ color: " + item.get_hover_color() + ";}"; | |
| self.styles += " button .upfront_theme_color_" + index +":hover{ color: " + item.get_hover_color() + ";}"; | |
| + self.styles += " .upfront_theme_bg_color_" + index +"{ background-color: " + item.get("color") + ";}"; | |
| + self.styles += " a .upfront_theme_bg_color_" + index +":hover{ background-color: " + item.get_hover_color() + ";}"; | |
| + self.styles += " button .upfront_theme_bg_color_" + index +":hover{ background-color: " + item.get_hover_color() + ";}"; | |
| }); | |
| $("#upfront_theme_colors_dom_styles").remove(); | |
| $("<style id='upfront_theme_colors_dom_styles' type='text/css'>" + this.styles + "</style>").appendTo("body"); | |
| @@ -3731,7 +3736,7 @@ define([ | |
| blank_alpha : 1 | |
| }, | |
| spectrumDefaults: { | |
| - clickoutFiresChange: true, | |
| + clickoutFiresChange: false, | |
| chooseText: 'OK', | |
| showSelectionPalette: true, | |
| showAlpha: true, | |
| diff --git a/styles/editor-interface.css b/styles/editor-interface.css | |
| index 4f11f20..ac0f070 100644 | |
| --- a/styles/editor-interface.css | |
| +++ b/styles/editor-interface.css | |
| @@ -1067,7 +1067,7 @@ span.draggable-post-element.element-dragging | |
| #upfront-general-csseditor .ace_scrollbar::-webkit-scrollbar, | |
| .upfront_code-editor-complex-wrapper .ace_scrollbar-inner::-webkit-scrollbar, | |
| .upfront_code-editor-complex-wrapper .ace_scrollbar::-webkit-scrollbar, | |
| -.redactor_dropdown_box_icons div.icons::-webkit-scrollbar | |
| +.redactor_dropdown_box_upftonIcons div.icons::-webkit-scrollbar | |
| { | |
| background: none; | |
| width: 5px; | |
| @@ -1112,7 +1112,7 @@ span.draggable-post-element.element-dragging | |
| #upfront-general-csseditor .ace_scrollbar::-webkit-scrollbar-thumb, | |
| .upfront_code-editor-complex-wrapper .ace_scrollbar-inner::-webkit-scrollbar-thumb, | |
| .upfront_code-editor-complex-wrapper .ace_scrollbar::-webkit-scrollbar-thumb, | |
| -.redactor_dropdown_box_icons div.icons::-webkit-scrollbar-thumb | |
| +.redactor_dropdown_box_upftonIcons div.icons::-webkit-scrollbar-thumb | |
| { | |
| border-right: 5px solid #1fcd8f; | |
| } | |
| @@ -9312,10 +9312,10 @@ only screen and ( min-resolution: 2dppx) { | |
| */ | |
| body .redactor_toolbar li a.redactor_btn_html { background-position: 0px; } | |
| body .redactor_toolbar li a.redactor_btn_formatting { background-position: -25px; } | |
| -body .redactor_toolbar li a.redactor_btn_bold { background-position: -510px -41px; } | |
| -body .redactor_toolbar li a.redactor_btn_bold.redactor_act { background-position: -552px -41px; } | |
| -body .redactor_toolbar li a.redactor_btn_italic { background-position: -594px -42px; } | |
| -body .redactor_toolbar li a.redactor_btn_italic.redactor_act { background-position: -636px -42px } | |
| +body .redactor_toolbar li a.re-bold { background-position: -510px -41px; } | |
| +body .redactor_toolbar li a.re-bold.redactor_act { background-position: -552px -41px; } | |
| +body .redactor_toolbar li a.re-italic { background-position: -594px -42px; } | |
| +body .redactor_toolbar li a.re-italic.redactor_act { background-position: -636px -42px } | |
| body .redactor_toolbar li a.redactor_btn_deleted { background-position: -500px; } | |
| body .redactor_toolbar li a.redactor_btn_unorderedlist { background-position: -100px; } | |
| body .redactor_toolbar li a.redactor_btn_orderedlist { background-position: -125px; } | |
| @@ -9361,8 +9361,8 @@ body .redactor_toolbar li a.redactor_btn_quote.redactor_act { background-positio | |
| body .redactor_toolbar li a.ueditor-quote-alternative { background-position: -594px -208px; } | |
| body .redactor_toolbar li a.redactor_btn_pre { background-position: -875px; } | |
| -body .redactor_toolbar li a.redactor_btn_icons { background-position: -593px -252px; } | |
| -body .redactor_toolbar li a.redactor_btn_icons:hover { background-position: -635px -252px; } | |
| +body .redactor_toolbar li a.re-upftonIcons { background-position: -593px -252px; } | |
| +body .redactor_toolbar li a.re-upftonIcons:hover { background-position: -635px -252px; } | |
| ul.redactor_toolbar li a.ueditor-justify { | |
| @@ -9381,7 +9381,7 @@ ul.redactor_toolbar li a.ueditor-right { | |
| background-position: -594px -82px; | |
| } | |
| -ul.redactor_toolbar li a.ueditor-nolist { | |
| +ul.redactor_toolbar li a.re-stateLists{ | |
| background-position: -510px -124px; | |
| } | |
| @@ -9393,7 +9393,7 @@ ul.redactor_toolbar li a.ueditor-unorderedlist { | |
| background-position: -552px -124px; | |
| } | |
| -ul.redactor_toolbar li a.redactor_btn_upfrontLink, ul.redactor_toolbar li a.redactor_btn_upfrontLinkCTA{ | |
| +ul.redactor_toolbar li a.re-upfrontLink{ | |
| background-position: -510px -167px; | |
| } | |
| @@ -9404,7 +9404,7 @@ ul.redactor_toolbar.ueditor-sink-open li a.redactor_btn_upfrontSink{ | |
| background-position: -636px -167px; | |
| } | |
| -body .redactor_toolbar li a.redactor_btn_upfrontLink.redactor_act { background-position: -552px -167px; } | |
| +body .redactor_toolbar li a.re-upfrontLink.redactor_act { background-position: -552px -167px; } | |
| /* | |
| Toolbar classes | |
| @@ -9511,20 +9511,24 @@ body .redactor_toolbar li a.redactor_btn_upfrontLink.redactor_act { background-p | |
| padding: 0; | |
| } | |
| */ | |
| -a.ueditor-format-option { | |
| +.redactor_dropdown_box_upfrontFormatting a { | |
| color: #97b8da !important; | |
| width: 38px; | |
| line-height: 30px; | |
| padding: 2px 0; | |
| display: block; | |
| + z-index: 99999; | |
| + margin-top: 0; | |
| +} | |
| +.redactor_dropdown_box_upfrontFormatting a.active{ | |
| + color: #40a6ff !important; | |
| } | |
| - | |
| a.ueditor-format-pre{ | |
| font-size: 15px; | |
| font-weight: bold; | |
| } | |
| -.redactor_toolbar li a.redactor_btn_upfrontFormatting { | |
| +.redactor_toolbar li a.re-upfrontFormatting { | |
| text-indent: 0; | |
| font-family: Georgia, serif; | |
| color: #97b8da; | |
| @@ -9532,7 +9536,9 @@ a.ueditor-format-pre{ | |
| line-height: 36px; | |
| text-align: center; | |
| } | |
| - | |
| +.redactor_toolbar li a.re-upfrontFormatting:after{ | |
| + content : "¶"; | |
| +} | |
| /* MODAL */ | |
| /* 300 lines deleted here, not using modals */ | |
| @@ -9749,8 +9755,8 @@ li#tabbackground-content .sp-palette-row-selection span.sp-thumb-el:last-child > | |
| width:auto; | |
| background-color: transparent; | |
| box-shadow: none; | |
| - top: -164px !important; | |
| - left: -30px !important; | |
| + /*top: -164px !important;*/ | |
| + /*left: -30px !important;*/ | |
| font-family: Verdana, sans-serif!important; | |
| } | |
| .redactor_air.under .redactor_dropdown_box_upfrontColor{ | |
| @@ -10021,7 +10027,7 @@ border:none; | |
| } | |
| div.sp-val:active .sp-dragger:after { display:block;} | |
| -.redactor_btn.redactor_btn_upfrontColor { | |
| +.re-icon.re-upfrontColor { | |
| text-indent: 0; | |
| position:relative; | |
| border-radius: 3px; | |
| @@ -10033,7 +10039,7 @@ div.sp-val:active .sp-dragger:after { display:block;} | |
| /*box-shadow: 0 3px 0 rgba(0,0,0,0.1);*/ | |
| } | |
| -.redactor_btn.redactor_btn_upfrontColor:after { | |
| +.re-icon.re-upfrontColor:after { | |
| content: 'T'; | |
| color: inherit; | |
| display: block; | |
| @@ -10052,7 +10058,7 @@ div.sp-val:active .sp-dragger:after { display:block;} | |
| } | |
| -.redactor_btn.redactor_btn_upfrontColor.transparent:after { | |
| +.re-icon.re-upfrontColor.transparent:after { | |
| border: none; | |
| height: 24px; | |
| width: 24px; | |
| @@ -11038,7 +11044,7 @@ li#new-custom-breakpoint { | |
| margin: 10px 0 10px 15px; | |
| } | |
| /*------------ Font Icons --------------*/ | |
| -.redactor_dropdown_box_icons div.icons{ | |
| +.redactor_dropdown_box_upftonIcons div.icons{ | |
| font-size: 24px; | |
| height: 140px; | |
| overflow-x: hidden; | |
| @@ -11046,22 +11052,22 @@ li#new-custom-breakpoint { | |
| padding: 7px; | |
| margin-right: 1px; | |
| } | |
| -.redactor_dropdown.redactor_dropdown_box_icons{ | |
| +.redactor_dropdown.redactor_dropdown_box_upftonIcons{ | |
| min-width: 153px; | |
| width: 153px; | |
| line-height: 38px; | |
| padding: 0; | |
| opacity: 0.9; | |
| } | |
| -.redactor_dropdown.redactor_dropdown_box_icons a, | |
| -.redactor_dropdown.redactor_dropdown_box_icons a:link{ | |
| +.redactor_dropdown.redactor_dropdown_box_upftonIcons a, | |
| +.redactor_dropdown.redactor_dropdown_box_upftonIcons a:link{ | |
| color: #97b8da !important; | |
| text-decoration: none; | |
| display: inline-block; | |
| width: 28px; | |
| text-align: center; | |
| } | |
| -.redactor_dropdown.redactor_dropdown_box_icons a:hover{ | |
| +.redactor_dropdown.redactor_dropdown_box_upftonIcons a:hover{ | |
| color: rgb(64, 166, 255) !important; | |
| } | |
| .upfront-font-icons-controlls{ | |
| @@ -12372,3 +12378,4 @@ div.upfront-region.empty_in_theme_mode:not(.upfront-region-floating):not(.upfron | |
| .upfront-region-bg-setting-add-global-region { | |
| margin-bottom: 20px; | |
| } | |
| +>>>>>>> eea43a57793d2b674014aac2b20fc534316c3fc9 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment