character_editor 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /*
2
- Redactor v9.2.2
3
- Updated: Apr 14, 2014
2
+ Redactor v9.2.6
3
+ Updated: Jul 19, 2014
4
4
 
5
5
  http://imperavi.com/redactor/
6
6
 
@@ -9,7 +9,6 @@
9
9
 
10
10
  Usage: $('#content').redactor();
11
11
  */
12
-
13
12
  (function($)
14
13
  {
15
14
  var uuid = 0;
@@ -74,7 +73,7 @@
74
73
  }
75
74
 
76
75
  $.Redactor = Redactor;
77
- $.Redactor.VERSION = '9.2.2';
76
+ $.Redactor.VERSION = '9.2.6';
78
77
  $.Redactor.opts = {
79
78
 
80
79
  // settings
@@ -117,7 +116,7 @@
117
116
  'ctrl+shift+7': "this.execCommand('insertorderedlist', false)",
118
117
  'ctrl+shift+8': "this.execCommand('insertunorderedlist', false)"
119
118
  },
120
- shortcutsAdd: {},
119
+ shortcutsAdd: false,
121
120
 
122
121
  autosave: false, // false or url
123
122
  autosaveInterval: 60, // seconds
@@ -210,7 +209,6 @@
210
209
  italicTag: 'em',
211
210
 
212
211
  // private
213
- zIndexMax: 500,
214
212
  indentValue: 20,
215
213
  buffer: [],
216
214
  rebuffer: [],
@@ -903,8 +901,6 @@
903
901
  // do not sync
904
902
  return false;
905
903
  }
906
-
907
-
908
904
  // fix second level up ul, ol
909
905
  html = html.replace(/<\/li><(ul|ol)>([\w\W]*?)<\/(ul|ol)>/gi, '<$1>$2</$1></li>');
910
906
 
@@ -1010,24 +1006,26 @@
1010
1006
 
1011
1007
  // remove spans
1012
1008
  html = html.replace(/<span(.*?)>([\w\W]*?)<\/span>/gi, '$2');
1009
+ html = html.replace(/<inline>([\w\W]*?)<\/inline>/gi, '$1');
1013
1010
  html = html.replace(/<inline>/gi, '<span>');
1014
1011
  html = html.replace(/<inline /gi, '<span ');
1015
1012
  html = html.replace(/<\/inline>/gi, '</span>');
1016
- html = html.replace(/<span(.*?)class="redactor_placeholder"(.*?)>([\w\W]*?)<\/span>/gi, '');
1017
- /*
1018
- FIX 9.2.2
1013
+
1014
+ if (this.opts.removeEmptyTags)
1015
+ {
1019
1016
  html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');
1020
- */
1017
+ }
1021
1018
 
1019
+ html = html.replace(/<span(.*?)class="redactor_placeholder"(.*?)>([\w\W]*?)<\/span>/gi, '');
1020
+ html = html.replace(/<img(.*?)contenteditable="false"(.*?)>/gi, '<img$1$2>');
1022
1021
 
1023
1022
  // special characters
1024
- html = html.replace(/&amp;/gi, '&');
1025
- html = html.replace(/™/gi, '&trade;');
1026
- html = html.replace(/©/gi, '&copy;');
1027
- html = html.replace(/…/gi, '&hellip;');
1028
- html = html.replace(/—/gi, '&mdash;');
1029
- html = html.replace(/‐/gi, '&dash;');
1030
-
1023
+ html = html.replace(/&/gi, '&');
1024
+ html = html.replace(/\u2122/gi, '&trade;');
1025
+ html = html.replace(/\u00a9/gi, '&copy;');
1026
+ html = html.replace(/\u2026/gi, '&hellip;');
1027
+ html = html.replace(/\u2014/gi, '&mdash;');
1028
+ html = html.replace(/\u2010/gi, '&dash;');
1031
1029
 
1032
1030
  html = this.cleanReConvertProtected(html);
1033
1031
 
@@ -1035,6 +1033,7 @@
1035
1033
  },
1036
1034
 
1037
1035
 
1036
+
1038
1037
  // BUILD
1039
1038
  buildStart: function()
1040
1039
  {
@@ -1043,7 +1042,6 @@
1043
1042
 
1044
1043
  // container
1045
1044
  this.$box = $('<div class="redactor_box" />');
1046
- this.$box.css('z-index', this.opts.zIndexMax - this.uuid);
1047
1045
 
1048
1046
  // textarea test
1049
1047
  if (this.$source[0].tagName === 'TEXTAREA') this.opts.textareamode = true;
@@ -1222,6 +1220,12 @@
1222
1220
  this.$editor.on('drop.redactor', $.proxy(this.buildEventDrop, this));
1223
1221
  }
1224
1222
 
1223
+ this.$editor.on('click.redactor', $.proxy(function()
1224
+ {
1225
+ this.selectall = false;
1226
+
1227
+ }, this));
1228
+
1225
1229
  this.$editor.on('input.redactor', $.proxy(this.sync, this));
1226
1230
  this.$editor.on('paste.redactor', $.proxy(this.buildEventPaste, this));
1227
1231
  this.$editor.on('keydown.redactor', $.proxy(this.buildEventKeydown, this));
@@ -1380,7 +1384,6 @@
1380
1384
 
1381
1385
  this.callback('keydown', e);
1382
1386
 
1383
-
1384
1387
  /*
1385
1388
  firefox cmd+left/Cmd+right browser back/forward fix -
1386
1389
  http://joshrhoderick.wordpress.com/2010/05/05/how-firefoxs-command-key-bug-kills-usability-on-the-mac/
@@ -1476,7 +1479,7 @@
1476
1479
  }
1477
1480
 
1478
1481
  // enter
1479
- if (key == this.keyCode.ENTER && !e.shiftKey && !e.ctrlKey && !e.metaKey )
1482
+ if (key == this.keyCode.ENTER && !e.shiftKey && !e.ctrlKey && !e.metaKey)
1480
1483
  {
1481
1484
  // remove selected content on enter
1482
1485
  var range = this.getRange();
@@ -1658,7 +1661,7 @@
1658
1661
  }
1659
1662
 
1660
1663
  // delete zero-width space before the removing
1661
- if (key === this.keyCode.BACKSPACE) this.buildEventKeydownBackspace(e, current);
1664
+ if (key === this.keyCode.BACKSPACE) this.buildEventKeydownBackspace(e, current, parent);
1662
1665
 
1663
1666
  },
1664
1667
  buildEventKeydownPre: function(e, current)
@@ -1706,8 +1709,23 @@
1706
1709
 
1707
1710
  return false;
1708
1711
  },
1709
- buildEventKeydownBackspace: function(e, current)
1712
+ buildEventKeydownBackspace: function(e, current, parent)
1710
1713
  {
1714
+ // remove empty list in table
1715
+ if (parent && current && parent.parentNode.tagName == 'TD'
1716
+ && parent.tagName == 'UL' && current.tagName == 'LI' && $(parent).children('li').size() == 1)
1717
+ {
1718
+ var text = $(current).text().replace(/[\u200B-\u200D\uFEFF]/g, '');
1719
+ if (text == '')
1720
+ {
1721
+ var node = parent.parentNode;
1722
+ $(parent).remove();
1723
+ this.selectionStart(node);
1724
+ this.sync();
1725
+ return false;
1726
+ }
1727
+ }
1728
+
1711
1729
  if (typeof current.tagName !== 'undefined' && /^(H[1-6])$/i.test(current.tagName))
1712
1730
  {
1713
1731
  var node;
@@ -1716,6 +1734,7 @@
1716
1734
 
1717
1735
  $(current).replaceWith(node);
1718
1736
  this.selectionStart(node);
1737
+ this.sync();
1719
1738
  }
1720
1739
 
1721
1740
  if (typeof current.nodeValue !== 'undefined' && current.nodeValue !== null)
@@ -1723,6 +1742,7 @@
1723
1742
  if (current.remove && current.nodeType === 3 && current.nodeValue.match(/[^\u200B]/g) == null)
1724
1743
  {
1725
1744
  $(current).prev().remove();
1745
+ this.sync();
1726
1746
  }
1727
1747
  }
1728
1748
  },
@@ -2020,11 +2040,14 @@
2020
2040
  var keys = str.split(',');
2021
2041
  for (var i in keys)
2022
2042
  {
2023
- this.shortcutsHandler(e, $.trim(keys[i]), $.proxy(function()
2043
+ if (typeof keys[i] === 'string')
2024
2044
  {
2025
- eval(command);
2045
+ this.shortcutsHandler(e, $.trim(keys[i]), $.proxy(function()
2046
+ {
2047
+ eval(command);
2048
+ }, this));
2049
+ }
2026
2050
 
2027
- }, this));
2028
2051
  }
2029
2052
 
2030
2053
  }, this));
@@ -2171,16 +2194,23 @@
2171
2194
  toggleVisual: function()
2172
2195
  {
2173
2196
  var html = this.$source.hide().val();
2174
-
2175
2197
  if (typeof this.modified !== 'undefined')
2176
2198
  {
2177
- this.modified = this.cleanRemoveSpaces(this.modified, false) !== this.cleanRemoveSpaces(html, false);
2199
+ var modified = this.modified.replace(/\n/g, '');
2200
+
2201
+ var thtml = html.replace(/\n/g, '');
2202
+ thtml = this.cleanRemoveSpaces(thtml, false);
2203
+
2204
+ this.modified = this.cleanRemoveSpaces(modified, false) !== thtml;
2178
2205
  }
2179
2206
 
2180
2207
  if (this.modified)
2181
2208
  {
2182
2209
  // don't remove the iframe even if cleared all.
2183
- if (this.opts.fullpage && html === '') this.setFullpageOnInit(html);
2210
+ if (this.opts.fullpage && html === '')
2211
+ {
2212
+ this.setFullpageOnInit(html);
2213
+ }
2184
2214
  else
2185
2215
  {
2186
2216
  this.set(html);
@@ -2189,6 +2219,8 @@
2189
2219
  this.buildBindKeyboard();
2190
2220
  }
2191
2221
  }
2222
+
2223
+ this.callback('change', false, html);
2192
2224
  }
2193
2225
 
2194
2226
  if (this.opts.iframe) this.$frame.show();
@@ -2205,6 +2237,8 @@
2205
2237
  this.buttonActiveVisual();
2206
2238
  this.buttonInactive('html');
2207
2239
  this.opts.visual = true;
2240
+
2241
+
2208
2242
  },
2209
2243
  toggleCode: function(direct)
2210
2244
  {
@@ -2482,6 +2516,8 @@
2482
2516
  {
2483
2517
  if (!this.opts.air) return;
2484
2518
 
2519
+ this.selectionSave();
2520
+
2485
2521
  var left, top;
2486
2522
  $('.redactor_air').hide();
2487
2523
 
@@ -2587,6 +2623,11 @@
2587
2623
  $item = $('<a href="#" class="' + btnObject.className + ' redactor_dropdown_' + btnName + '">' + btnObject.title + '</a>');
2588
2624
  $item.on('click', $.proxy(function(e)
2589
2625
  {
2626
+ if (this.opts.air)
2627
+ {
2628
+ this.selectionRestore();
2629
+ }
2630
+
2590
2631
  if (e.preventDefault) e.preventDefault();
2591
2632
  if (this.browser('msie')) e.returnValue = false;
2592
2633
 
@@ -2597,6 +2638,7 @@
2597
2638
  this.buttonActiveObserver();
2598
2639
  if (this.opts.air) this.$air.fadeOut(100);
2599
2640
 
2641
+
2600
2642
  }, this));
2601
2643
  }
2602
2644
 
@@ -2612,9 +2654,11 @@
2612
2654
  return false;
2613
2655
  }
2614
2656
 
2615
- var $dropdown = this.$toolbar.find('.redactor_dropdown_box_' + key);
2616
2657
  var $button = this.buttonGet(key);
2617
2658
 
2659
+ // Always re-append it to the end of <body> so it always has the highest sub-z-index.
2660
+ var $dropdown = $button.data('dropdown').appendTo(document.body);
2661
+
2618
2662
  if ($button.hasClass('dropact')) this.dropdownHideAll();
2619
2663
  else
2620
2664
  {
@@ -2624,11 +2668,7 @@
2624
2668
  this.buttonActive(key);
2625
2669
  $button.addClass('dropact');
2626
2670
 
2627
- var keyPosition = $button.position();
2628
- if (this.toolbarFixed)
2629
- {
2630
- keyPosition = $button.offset();
2631
- }
2671
+ var keyPosition = $button.offset();
2632
2672
 
2633
2673
  // fix right placement
2634
2674
  var dropdownWidth = $dropdown.width();
@@ -2641,10 +2681,10 @@
2641
2681
  var btnHeight = $button.innerHeight();
2642
2682
 
2643
2683
  var position = 'absolute';
2644
- var top = btnHeight + 'px';
2684
+ var top = (btnHeight + this.opts.toolbarFixedTopOffset) + 'px';
2645
2685
 
2646
2686
  if (this.opts.toolbarFixed && this.toolbarFixed) position = 'fixed';
2647
- else if (!this.opts.air) top = keyPosition.top + btnHeight + 'px';
2687
+ else top = keyPosition.top + btnHeight + 'px';
2648
2688
 
2649
2689
  $dropdown.css({ position: position, left: left, top: top }).show();
2650
2690
  this.callback('dropdownShown', { dropdown: $dropdown, key: key, button: $button });
@@ -2659,6 +2699,8 @@
2659
2699
 
2660
2700
  $(document).one('click', hdlHideDropDown);
2661
2701
  this.$editor.one('click', hdlHideDropDown);
2702
+ this.$editor.one('touchstart', hdlHideDropDown);
2703
+
2662
2704
 
2663
2705
  e.stopPropagation();
2664
2706
  this.focusWithSaveScroll();
@@ -2733,7 +2775,7 @@
2733
2775
  if (btnObject.dropdown)
2734
2776
  {
2735
2777
  var $dropdown = $('<div class="redactor_dropdown redactor_dropdown_box_' + btnName + '" style="display: none;">');
2736
- $dropdown.appendTo(this.$toolbar);
2778
+ $button.data('dropdown', $dropdown);
2737
2779
  this.dropdownBuild($dropdown, btnObject.dropdown);
2738
2780
  }
2739
2781
 
@@ -2871,22 +2913,12 @@
2871
2913
  if ($parent.length)
2872
2914
  {
2873
2915
  var align = $parent.css('text-align');
2874
-
2875
- switch (align)
2916
+ if (align == '')
2876
2917
  {
2877
- case 'right':
2878
- this.buttonActive('alignright');
2879
- break;
2880
- case 'center':
2881
- this.buttonActive('aligncenter');
2882
- break;
2883
- case 'justify':
2884
- this.buttonActive('alignjustify');
2885
- break;
2886
- default:
2887
- this.buttonActive('alignleft');
2888
- break;
2918
+ align = 'left';
2889
2919
  }
2920
+
2921
+ this.buttonActive('align' + align);
2890
2922
  }
2891
2923
  },
2892
2924
 
@@ -3090,7 +3122,7 @@
3090
3122
  {
3091
3123
  var firstParent = $(this.getParent()).closest('td');
3092
3124
 
3093
- if (this.browser('msie') && this.opts.linebreaks)
3125
+ if (this.browser('msie') && !this.isIe11() && this.opts.linebreaks)
3094
3126
  {
3095
3127
  var wrapper = this.selectionWrap('div');
3096
3128
  var wrapperHtml = $(wrapper).html();
@@ -3155,7 +3187,7 @@
3155
3187
  }
3156
3188
 
3157
3189
  this.selectionRestore();
3158
-
3190
+ this.$editor.find('#selection-marker-1').removeAttr('id');
3159
3191
  this.sync();
3160
3192
  this.callback('execCommand', cmd, param);
3161
3193
  return;
@@ -3283,7 +3315,7 @@
3283
3315
  // linebreaks
3284
3316
  if (this.opts.linebreaks === true && typeof($el.data('tagblock')) !== 'undefined')
3285
3317
  {
3286
- $el.replaceWith($el.html());
3318
+ $el.replaceWith($el.html() + '<br>');
3287
3319
  }
3288
3320
  // all block tags
3289
3321
  else
@@ -3406,7 +3438,6 @@
3406
3438
  }
3407
3439
 
3408
3440
  this.selectionRestore();
3409
-
3410
3441
  this.sync();
3411
3442
  },
3412
3443
 
@@ -3427,7 +3458,11 @@
3427
3458
  cleanConverters: function(html)
3428
3459
  {
3429
3460
  // convert div to p
3430
- if (this.opts.convertDivs) html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p$1>$2</p>');
3461
+ if (this.opts.convertDivs && !this.opts.gallery)
3462
+ {
3463
+ html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p$1>$2</p>');
3464
+ }
3465
+
3431
3466
  if (this.opts.paragraphy) html = this.cleanParagraphy(html);
3432
3467
 
3433
3468
  return html;
@@ -3517,11 +3552,6 @@
3517
3552
  },
3518
3553
  cleanRemoveEmptyTags: function(html)
3519
3554
  {
3520
- /*
3521
- FIX 9.2.2
3522
- html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');
3523
- */
3524
-
3525
3555
  // remove zero width-space
3526
3556
  html = html.replace(/[\u200B-\u200D\uFEFF]/g, '');
3527
3557
 
@@ -3579,6 +3609,7 @@
3579
3609
  }
3580
3610
 
3581
3611
  html = html.replace(/<br \/>\s*<br \/>/gi, "\n\n");
3612
+ html = html.replace(/<br><br>/gi, "\n\n");
3582
3613
 
3583
3614
  function R(str, mod, r)
3584
3615
  {
@@ -3669,14 +3700,8 @@
3669
3700
 
3670
3701
  html = html.replace(/<span style="text-decoration: underline;">([\w\W]*?)<\/span>/gi, '<u>$1</u>');
3671
3702
 
3672
- if (set !== true)
3673
- {
3674
- html = html.replace(/<strike>([\w\W]*?)<\/strike>/gi, '<del>$1</del>');
3675
- }
3676
- else
3677
- {
3678
- html = html.replace(/<del>([\w\W]*?)<\/del>/gi, '<strike>$1</strike>');
3679
- }
3703
+ if (set !== true) html = html.replace(/<strike>([\w\W]*?)<\/strike>/gi, '<del>$1</del>');
3704
+ else html = html.replace(/<del>([\w\W]*?)<\/del>/gi, '<strike>$1</strike>');
3680
3705
 
3681
3706
  return html;
3682
3707
  },
@@ -3874,7 +3899,7 @@
3874
3899
  }
3875
3900
  }
3876
3901
 
3877
- return this.cleanFinish( out );
3902
+ return this.cleanFinish(out);
3878
3903
  },
3879
3904
  cleanGetTabs: function()
3880
3905
  {
@@ -3888,10 +3913,10 @@
3888
3913
  },
3889
3914
  cleanFinish: function(code)
3890
3915
  {
3891
- code = code.replace( /\n\s*\n/g, '\n' );
3892
- code = code.replace( /^[\s\n]*/, '' );
3893
- code = code.replace( /[\s\n]*$/, '' );
3894
- code = code.replace( /<script(.*?)>\n<\/script>/gi, '<script$1></script>' );
3916
+ code = code.replace(/\n\s*\n/g, '\n');
3917
+ code = code.replace(/^[\s\n]*/, '');
3918
+ code = code.replace(/[\s\n]*$/, '');
3919
+ code = code.replace(/<script(.*?)>\n<\/script>/gi, '<script$1></script>');
3895
3920
 
3896
3921
  this.cleanlevel = 0;
3897
3922
 
@@ -3980,6 +4005,11 @@
3980
4005
  },
3981
4006
  formatBlocks: function(tag)
3982
4007
  {
4008
+ if (this.browser('mozilla') && this.isFocused())
4009
+ {
4010
+ this.$editor.focus();
4011
+ }
4012
+
3983
4013
  this.bufferSet();
3984
4014
 
3985
4015
  var nodes = this.getBlocks();
@@ -4084,6 +4114,11 @@
4084
4114
  // QUOTE
4085
4115
  formatQuote: function()
4086
4116
  {
4117
+ if (this.browser('mozilla') && this.isFocused())
4118
+ {
4119
+ this.$editor.focus();
4120
+ }
4121
+
4087
4122
  this.bufferSet();
4088
4123
 
4089
4124
  // paragraphy
@@ -4323,7 +4358,6 @@
4323
4358
  this.selectionRestore();
4324
4359
  this.sync();
4325
4360
  },
4326
-
4327
4361
  inlineSetClass: function(className)
4328
4362
  {
4329
4363
  var current = this.getCurrent();
@@ -4382,7 +4416,25 @@
4382
4416
  }
4383
4417
  else
4384
4418
  {
4385
- this.document.execCommand('fontSize', false, 4 );
4419
+ var cmd, arg = value;
4420
+ switch (attr)
4421
+ {
4422
+ case 'font-size':
4423
+ cmd = 'fontSize';
4424
+ arg = 4;
4425
+ break;
4426
+ case 'font-family':
4427
+ cmd = 'fontName';
4428
+ break;
4429
+ case 'color':
4430
+ cmd = 'foreColor';
4431
+ break;
4432
+ case 'background-color':
4433
+ cmd = 'backColor';
4434
+ break;
4435
+ }
4436
+
4437
+ this.document.execCommand(cmd, false, arg);
4386
4438
 
4387
4439
  var fonts = this.$editor.find('font');
4388
4440
  $.each(fonts, $.proxy(function(i, s)
@@ -4509,6 +4561,7 @@
4509
4561
  $(el).replaceWith($(el).contents());
4510
4562
  },
4511
4563
 
4564
+
4512
4565
  // INSERT
4513
4566
  insertHtml: function (html, sync)
4514
4567
  {
@@ -4603,9 +4656,9 @@
4603
4656
  var range = sel.getRangeAt(0);
4604
4657
  range.deleteContents();
4605
4658
 
4606
- var el = this.document.createElement('div');
4659
+ var el = document.createElement('div');
4607
4660
  el.innerHTML = html;
4608
- var frag = this.document.createDocumentFragment(), node, lastNode;
4661
+ var frag = document.createDocumentFragment(), node, lastNode;
4609
4662
  while ((node = el.firstChild))
4610
4663
  {
4611
4664
  lastNode = frag.appendChild(node);
@@ -4657,8 +4710,21 @@
4657
4710
 
4658
4711
  this.focusWithSaveScroll();
4659
4712
 
4660
- if (this.browser('msie') && !this.isIe11()) this.document.selection.createRange().pasteHTML(html);
4661
- else this.document.execCommand('inserthtml', false, html);
4713
+ if (this.browser('msie'))
4714
+ {
4715
+ if (!this.isIe11())
4716
+ {
4717
+ this.document.selection.createRange().pasteHTML(html);
4718
+ }
4719
+ else
4720
+ {
4721
+ this.execPasteFrag(html);
4722
+ }
4723
+ }
4724
+ else
4725
+ {
4726
+ this.document.execCommand('inserthtml', false, html);
4727
+ }
4662
4728
 
4663
4729
  this.sync();
4664
4730
  },
@@ -4694,6 +4760,8 @@
4694
4760
  sel.removeAllRanges();
4695
4761
  sel.addRange(range);
4696
4762
  }
4763
+
4764
+ return node;
4697
4765
  },
4698
4766
  insertNodeToCaretPositionFromPoint: function(e, node)
4699
4767
  {
@@ -4922,6 +4990,8 @@
4922
4990
  // strip tags
4923
4991
  //html = this.cleanStripTags(html);
4924
4992
 
4993
+
4994
+
4925
4995
  // prevert
4926
4996
  html = html.replace(/<td>\u200b*<\/td>/gi, '[td]');
4927
4997
  html = html.replace(/<td>&nbsp;<\/td>/gi, '[td]');
@@ -4935,6 +5005,7 @@
4935
5005
  html = html.replace(/<embed(.*?)>([\w\W]*?)<\/embed>/gi, '[embed$1]$2[/embed]');
4936
5006
  html = html.replace(/<object(.*?)>([\w\W]*?)<\/object>/gi, '[object$1]$2[/object]');
4937
5007
  html = html.replace(/<param(.*?)>/gi, '[param$1]');
5008
+
4938
5009
  html = html.replace(/<img(.*?)>/gi, '[img$1]');
4939
5010
 
4940
5011
  // remove classes
@@ -5298,11 +5369,13 @@
5298
5369
  observeLinks: function()
5299
5370
  {
5300
5371
  this.$editor.find('a').on('click', $.proxy(this.linkObserver, this));
5372
+
5301
5373
  this.$editor.on('click.redactor', $.proxy(function(e)
5302
5374
  {
5303
5375
  this.linkObserverTooltipClose(e);
5304
5376
 
5305
5377
  }, this));
5378
+
5306
5379
  $(document).on('click.redactor', $.proxy(function(e)
5307
5380
  {
5308
5381
  this.linkObserverTooltipClose(e);
@@ -5316,14 +5389,29 @@
5316
5389
  this.$editor.find('img').each($.proxy(function(i, elem)
5317
5390
  {
5318
5391
  if (this.browser('msie')) $(elem).attr('unselectable', 'on');
5319
- this.imageResize(elem);
5392
+
5393
+ var parent = $(elem).parent();
5394
+ if (!parent.hasClass('royalSlider') && !parent.hasClass('fotorama'))
5395
+ {
5396
+ this.imageResize(elem);
5397
+ }
5320
5398
 
5321
5399
  }, this));
5400
+
5401
+ // royalSlider and fotorama
5402
+ this.$editor.find('.fotorama, .royalSlider').on('click', $.proxy(this.editGallery, this));
5403
+
5322
5404
  },
5323
5405
  linkObserver: function(e)
5324
5406
  {
5325
5407
  var $link = $(e.target);
5326
5408
 
5409
+ var parent = $(e.target).parent();
5410
+ if (parent.hasClass('royalSlider') || parent.hasClass('fotorama'))
5411
+ {
5412
+ return;
5413
+ }
5414
+
5327
5415
  if ($link.size() == 0 || $link[0].tagName !== 'A') return;
5328
5416
 
5329
5417
  var pos = $link.offset();
@@ -5651,6 +5739,12 @@
5651
5739
 
5652
5740
  return newnodes;
5653
5741
  },
5742
+ isInlineNode: function(node)
5743
+ {
5744
+ if (node.nodeType != 1) return false;
5745
+
5746
+ return !this.rTestBlock.test(node.nodeName);
5747
+ },
5654
5748
  nodeTestBlocks: function(node)
5655
5749
  {
5656
5750
  return node.nodeType == 1 && this.rTestBlock.test(node.nodeName);
@@ -5804,7 +5898,10 @@
5804
5898
  // SAVE & RESTORE
5805
5899
  selectionSave: function()
5806
5900
  {
5807
- if (!this.isFocused()) this.focusWithSaveScroll();
5901
+ if (!this.isFocused())
5902
+ {
5903
+ this.focusWithSaveScroll();
5904
+ }
5808
5905
 
5809
5906
  if (!this.opts.rangy)
5810
5907
  {
@@ -5841,10 +5938,19 @@
5841
5938
  {
5842
5939
  var boundaryRange = range.cloneRange();
5843
5940
 
5844
- boundaryRange.collapse(type);
5941
+ try {
5942
+ boundaryRange.collapse(type);
5943
+ boundaryRange.insertNode(node);
5944
+ boundaryRange.detach();
5945
+ }
5946
+ catch (e)
5947
+ {
5948
+ var html = this.opts.emptyHtml;
5949
+ if (this.opts.linebreaks) html = '<br>';
5845
5950
 
5846
- boundaryRange.insertNode(node);
5847
- boundaryRange.detach();
5951
+ this.$editor.prepend(html);
5952
+ this.focus();
5953
+ }
5848
5954
  },
5849
5955
  selectionRestore: function(replace, remove)
5850
5956
  {
@@ -5869,6 +5975,7 @@
5869
5975
 
5870
5976
  if (node1.length != 0 && node2.length != 0)
5871
5977
  {
5978
+
5872
5979
  this.selectionSet(node1[0], 0, node2[0], 0);
5873
5980
  }
5874
5981
  else if (node1.length != 0)
@@ -5984,6 +6091,7 @@
5984
6091
  }
5985
6092
  else
5986
6093
  {
6094
+
5987
6095
  this.insertHtmlAdvanced(html, false);
5988
6096
  }
5989
6097
 
@@ -6333,7 +6441,7 @@
6333
6441
  var text = $('#redactor_link_url_text').val();
6334
6442
 
6335
6443
  // mailto
6336
- if (link.search('@') != -1)
6444
+ if (link.search('@') != -1 && /(http|ftp|https):\/\//i.test(link) === false)
6337
6445
  {
6338
6446
  link = 'mailto:' + link;
6339
6447
  }
@@ -6569,7 +6677,7 @@
6569
6677
  }
6570
6678
  else
6571
6679
  {
6572
- $('#redactor-modal-tab-2').remove();
6680
+ $('#redactor-tab-control-2').remove();
6573
6681
  }
6574
6682
 
6575
6683
  if (this.opts.imageUpload || this.opts.s3)
@@ -6624,8 +6732,8 @@
6624
6732
  }
6625
6733
  else
6626
6734
  {
6627
- $('#redactor-modal-tab-1').remove();
6628
- $('#redactor-modal-tab-2').addClass('redactor_tabs_act');
6735
+ $('#redactor-tab-control-1').remove();
6736
+ $('#redactor-tab-control-2').addClass('redactor_tabs_act');
6629
6737
  $('#redactor_tab2').show();
6630
6738
  }
6631
6739
  }
@@ -7130,12 +7238,11 @@
7130
7238
  showProgressBar: function()
7131
7239
  {
7132
7240
  this.buildProgressBar();
7133
- this.$progressBar.fadeIn();
7241
+ $('#redactor-progress').fadeIn();
7134
7242
  },
7135
7243
  hideProgressBar: function()
7136
7244
  {
7137
- this.buildProgressBar();
7138
- this.$progressBar.fadeOut(1500);
7245
+ $('#redactor-progress').fadeOut(1500);
7139
7246
  },
7140
7247
 
7141
7248
  // MODAL
@@ -7244,6 +7351,7 @@
7244
7351
  {
7245
7352
  this.modalSetOverlay();
7246
7353
 
7354
+ this.$redactorModalWidth = width;
7247
7355
  this.$redactorModal = $('#redactor_modal');
7248
7356
 
7249
7357
  if (!this.$redactorModal.length)
@@ -7252,19 +7360,19 @@
7252
7360
  this.$redactorModal.append($('<div id="redactor_modal_close">&times;</div>'));
7253
7361
  this.$redactorModal.append($('<header id="redactor_modal_header" />'));
7254
7362
  this.$redactorModal.append($('<div id="redactor_modal_inner" />'));
7255
- $('body').append(this.$redactorModal);
7363
+ this.$redactorModal.appendTo(document.body);
7256
7364
  }
7257
7365
 
7258
7366
  $('#redactor_modal_close').on('click', $.proxy(this.modalClose, this));
7259
- $(document).keyup($.proxy(this.modalCloseHandler, this));
7260
- this.$editor.keyup($.proxy(this.modalCloseHandler, this));
7367
+ $(document).on('keyup', $.proxy(this.modalCloseHandler, this));
7368
+ this.$editor.on('keyup', $.proxy(this.modalCloseHandler, this));
7261
7369
 
7262
7370
  this.modalSetContent(content);
7263
7371
  this.modalSetTitle(title);
7264
7372
  this.modalSetDraggable();
7265
7373
  this.modalLoadTabs();
7266
7374
  this.modalOnCloseButton();
7267
- this.modalSetButtonsWidth(width);
7375
+ this.modalSetButtonsWidth();
7268
7376
 
7269
7377
  this.saveModalScroll = this.document.body.scrollTop;
7270
7378
  if (this.opts.autoresize === false)
@@ -7272,7 +7380,7 @@
7272
7380
  this.saveModalScroll = this.$editor.scrollTop();
7273
7381
  }
7274
7382
 
7275
- if (this.isMobile() === false) this.modalShowOnDesktop(width);
7383
+ if (this.isMobile() === false) this.modalShowOnDesktop();
7276
7384
  else this.modalShowOnMobile();
7277
7385
 
7278
7386
  // modal actions callback
@@ -7304,14 +7412,14 @@
7304
7412
  return this.$redactorModal;
7305
7413
 
7306
7414
  },
7307
- modalShowOnDesktop: function(width)
7415
+ modalShowOnDesktop: function()
7308
7416
  {
7309
7417
  this.$redactorModal.css({
7310
7418
  position: 'fixed',
7311
7419
  top: '-2000px',
7312
7420
  left: '50%',
7313
- width: width + 'px',
7314
- marginLeft: '-' + (width / 2) + 'px'
7421
+ width: this.$redactorModalWidth + 'px',
7422
+ marginLeft: '-' + (this.$redactorModalWidth / 2) + 'px'
7315
7423
  }).show();
7316
7424
 
7317
7425
  this.modalSaveBodyOveflow = $(document.body).css('overflow');
@@ -7359,13 +7467,13 @@
7359
7467
  {
7360
7468
  this.$redactorModal.find('#redactor_modal_header').html(title);
7361
7469
  },
7362
- modalSetButtonsWidth: function(width)
7470
+ modalSetButtonsWidth: function()
7363
7471
  {
7364
- var buttons = this.$redactorModal.find('footer button');
7472
+ var buttons = this.$redactorModal.find('footer button').not('.redactor_modal_btn_hidden');
7365
7473
  var buttonsSize = buttons.size();
7366
7474
  if (buttonsSize > 0)
7367
7475
  {
7368
- $(buttons).css('width', (width/buttonsSize) + 'px')
7476
+ $(buttons).css('width', (this.$redactorModalWidth/buttonsSize) + 'px')
7369
7477
  }
7370
7478
  },
7371
7479
  modalOnCloseButton: function()
@@ -7450,8 +7558,8 @@
7450
7558
  $('#redactor_modal_overlay').hide().off('click', this.modalClose);
7451
7559
  }
7452
7560
 
7453
- $(document).unbind('keyup', this.hdlModalClose);
7454
- this.$editor.unbind('keyup', this.hdlModalClose);
7561
+ $(document).off('keyup', this.modalCloseHandler);
7562
+ this.$editor.off('keyup', this.modalCloseHandler);
7455
7563
 
7456
7564
  this.selectionRestore();
7457
7565
 
@@ -7981,6 +8089,21 @@
7981
8089
 
7982
8090
  return html == '';
7983
8091
  },
8092
+ getInternetExplorerVersion: function()
8093
+ {
8094
+ var rv = false;
8095
+ if (navigator.appName == 'Microsoft Internet Explorer')
8096
+ {
8097
+ var ua = navigator.userAgent;
8098
+ var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
8099
+ if (re.exec(ua) != null)
8100
+ {
8101
+ rv = parseFloat(RegExp.$1);
8102
+ }
8103
+ }
8104
+
8105
+ return rv;
8106
+ },
7984
8107
  isIe11: function()
7985
8108
  {
7986
8109
  return !!navigator.userAgent.match(/Trident\/7\./);
@@ -8095,7 +8218,7 @@
8095
8218
  // LINKIFY
8096
8219
  $.Redactor.fn.formatLinkify = function(protocol, convertLinks, convertImageLinks, convertVideoLinks, linkSize)
8097
8220
  {
8098
- var url = /(((https?|ftps?):\/\/)|www[.])(.+?\..+?)([.),]?)(\s|\.\s+|\)|$)/gi,
8221
+ var url = /(((https?|ftps?):\/\/)|www[.][^\s])(.+?\..+?)([.),]?)(\s|\.\s+|\)|$)/gi,
8099
8222
  rProtocol = /(https?|ftp):\/\//i,
8100
8223
  urlImage = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif))/gi;
8101
8224