Skip to content

Instantly share code, notes, and snippets.

@Spoygg
Created September 15, 2014 11:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Spoygg/4e9b6d78b0476d5fde9c to your computer and use it in GitHub Desktop.
Save Spoygg/4e9b6d78b0476d5fde9c to your computer and use it in GitHub Desktop.
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, '&#36;');
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(/&amp;#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(/&#x200b;/gi, '');
html = html.replace(/&#8203;/gi, '');
html = html.replace(/<\/a>&nbsp;/gi, '<\/a> ');
+ html = html.replace(/\u200B/g, '');
+
+ if (html == '<p></p>' || html == '<p> </p>' || html == '<p>&nbsp;</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(/&amp;/gi, '&');
- html = html.replace(/™/gi, '&trade;');
- html = html.replace(/©/gi, '&copy;');
+ 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, '&trade;');
+ html = html.replace(/\u00a9/gi, '&copy;');
+ html = html.replace(/\u2026/gi, '&hellip;');
+ html = html.replace(/\u2014/gi, '&mdash;');
+ html = html.replace(/\u2010/gi, '&dash;');
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, '&#36;');
+
html = html.replace(s, '<' + arr[1] + arr[2] + '>' + arr[3] + '</' + arr[1] + '>');
}, this));
@@ -3199,7 +3752,7 @@
cleanEncodeEntities: function(str)
{
str = String(str).replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"');
- return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
},
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(/(&nbsp;){2,}/gi, '&nbsp;');
- html = html.replace(/&nbsp;/gi, ' ');
+ if (this.opts.cleanSpaces === true)
+ {
+ html = html.replace(/(&nbsp;){2,}/gi, '&nbsp;');
+ html = html.replace(/&nbsp;/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>&nbsp;<\/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*|&nbsp;|<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*|&nbsp;|<br>)<\/[^>]+>/gi, '<br>');
+ }
+ else
+ {
+ html = html.replace(/<[^\/>][^>]*>(\s*|\t*|\n*|&nbsp;|<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*|&nbsp;|<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*|&nbsp;|<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 = '&nbsp;';
+ if (this.browser('mozilla'))
{
- link = '#' + $('#redactor_link_anchor').val();
- text = $('#redactor_link_anchor_text').val();
+ extra = '&nbsp;';
}
- 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>&nbsp;&nbsp;&nbsp;'
+ + '<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">&times;</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">&times;</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 = /(^|&lt;|\s)(www\..+?\..+?)(\s|&gt;|$)/g,
- url2 = /(^|&lt;|\s)(((https?|ftp):\/\/|mailto:).+?)(\s|&gt;|$)/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, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;')
- .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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
+
+ /*
+ 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: '&lt;/&gt;',
+ 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: '&lt;/&gt;',
- 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('&para;');
- 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