character_editor 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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