redactor-rails 0.3.7 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
- ---
2
- SHA1:
3
- data.tar.gz: dd812071b4bfa7e5f8d15eea9bad6d8cbfe7cbe6
4
- metadata.gz: c9c5f2eb311372f81ce21b53e68a7371288b82d7
5
- SHA512:
6
- data.tar.gz: 62efd7ce4a5037b095c454bc8400aa071739667c40d296c6d629fa454a4aaa4cd3586ecad6f40a2db3afeb8396ebb0c57240cc10ac26a3df0ced64c888b80f28
7
- metadata.gz: 2eba13a9b040de4cb08d3390036c1101c617fe8cc65317c987cf0de03ab15882125be6660eecf0c7f287d8c8aaf7b53847fa76310cb40e054dd285ce2870bff5
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b7c9a0d89bbfb5867a646c9133ac5a223c6afe5c
4
+ data.tar.gz: f4b59a31c081303a758d7952f56eb0de73c2c5c7
5
+ SHA512:
6
+ metadata.gz: de54c5344288c59cca3f7d269d3944c5a5778f8aa669eb423651ecdad33443f5c8057f45ef57771dfcbec61b2c0e49bc83897919cb103667a5070e473dde8942
7
+ data.tar.gz: 7c85e211eadc3d0fe82be50b73f2a693d72a551d09a6e2614edb4d151bcbefdd2361110aae30d0bd8e51401ef70b95418fda0ee1e171051982f2891232072d9b
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The redactor-rails gem integrates the [Redactor](http://redactorjs.com/) editor with the Rails 3.2 asset pipeline.
4
4
 
5
- This gem bundles Redactor version 9.1.4 which is the most recent version as of September 10, 2013. Check [Redactor's changelog](http://imperavi.com/redactor/log/) for further updates.
5
+ This gem bundles Redactor version 9.0.4 which is the most recent version as of July 11, 2013. Check [Redactor's changelog](http://imperavi.com/redactor/log/) for further updates.
6
6
 
7
7
  ## Installation
8
8
 
@@ -1,5 +1,5 @@
1
1
  class RedactorRails::DocumentsController < ApplicationController
2
- before_filter :redactor_authenticate_user!
2
+ before_filter :redactor_authenticate_user! if RedactorRails.document_model.new.respond_to?(RedactorRails.devise_user)
3
3
 
4
4
  def index
5
5
  @documents = RedactorRails.document_model.where(
@@ -23,12 +23,4 @@ class RedactorRails::DocumentsController < ApplicationController
23
23
  render :nothing => true
24
24
  end
25
25
  end
26
-
27
- private
28
-
29
- def redactor_authenticate_user!
30
- if RedactorRails.document_model.new.respond_to?(RedactorRails.devise_user)
31
- super
32
- end
33
- end
34
26
  end
@@ -1,5 +1,5 @@
1
1
  class RedactorRails::PicturesController < ApplicationController
2
- before_filter :redactor_authenticate_user!
2
+ before_filter :redactor_authenticate_user! if RedactorRails.picture_model.new.respond_to?(RedactorRails.devise_user)
3
3
 
4
4
  def index
5
5
  @pictures = RedactorRails.picture_model.where(
@@ -23,12 +23,4 @@ class RedactorRails::PicturesController < ApplicationController
23
23
  render :nothing => true
24
24
  end
25
25
  end
26
-
27
- private
28
-
29
- def redactor_authenticate_user!
30
- if RedactorRails.picture_model.new.respond_to?(RedactorRails.devise_user)
31
- super
32
- end
33
- end
34
26
  end
@@ -15,7 +15,7 @@ module RedactorRails
15
15
  self.table_name = "redactor_assets"
16
16
 
17
17
  belongs_to :assetable, :polymorphic => true
18
- belongs_to RedactorRails.devise_user, :foreign_key => RedactorRails.devise_user_key
18
+ belongs_to RedactorRails.devise_user, :dependent => :destroy, :foreign_key => RedactorRails.devise_user_key
19
19
 
20
20
  if defined?(ActiveModel::ForbiddenAttributesProtection) && base.ancestors.include?(ActiveModel::ForbiddenAttributesProtection)
21
21
  # Ok
@@ -1,3 +1,3 @@
1
1
  module RedactorRails
2
- VERSION = "0.3.7"
2
+ VERSION = "0.4"
3
3
  end
@@ -1,2 +1,2 @@
1
- //= require ./redactor
1
+ //= require ./redactor.min
2
2
  //= require ./config
@@ -1,6 +1,6 @@
1
1
  /*
2
- Redactor v9.1.4
3
- Updated: Sep 10, 2013
2
+ Redactor v9.0.4
3
+ Updated: Jul 11, 2013
4
4
 
5
5
  http://imperavi.com/redactor/
6
6
 
@@ -72,9 +72,26 @@
72
72
  }
73
73
 
74
74
  $.Redactor = Redactor;
75
- $.Redactor.VERSION = '9.1.4';
75
+ $.Redactor.VERSION = '9.0.4';
76
76
  $.Redactor.opts = {
77
77
 
78
+ // callbacks
79
+ initCallback: false,
80
+ changeCallback: false,
81
+ focusCallback: false,
82
+ blurCallback: false,
83
+ keydownCallback: false,
84
+ keyupCallback: false,
85
+ execCommandCallback: false,
86
+ pasteBeforeCallback: false,
87
+ pasteAfterCallback: false,
88
+ autosaveCallback: false,
89
+ imageUploadCallback: false,
90
+ imageUploadErrorCallback: false,
91
+ imageDeleteCallback: false,
92
+ fileUploadCallback: false,
93
+ fileUploadErrorCallback: false,
94
+
78
95
  // settings
79
96
  rangy: false,
80
97
 
@@ -90,10 +107,7 @@
90
107
  wym: false,
91
108
  mobile: true,
92
109
  cleanup: true,
93
- tidyHtml: true,
94
- pastePlainText: false,
95
110
  removeEmptyTags: true,
96
- templateVars: false,
97
111
 
98
112
  visual: true,
99
113
  focus: false,
@@ -110,36 +124,26 @@
110
124
  linkAnchor: false,
111
125
  linkEmail: false,
112
126
  linkProtocol: 'http://',
113
- linkNofollow: false,
114
127
 
115
- imageFloatMargin: '10px',
116
128
  imageGetJson: false, // url (ex. /folder/images.json ) or false
117
129
 
118
130
  imageUpload: false, // url
119
131
  fileUpload: false, // url
120
- clipboardUpload: true, // or false
121
- clipboardUploadUrl: false, // url
122
- dragUpload: true, // false
123
-
124
- dnbImageTypes: ['image/png', 'image/jpeg', 'image/gif'], // or false
125
132
 
126
133
  s3: false,
127
134
  uploadFields: false,
128
135
 
129
136
  observeImages: true,
130
- observeLinks: true,
131
137
 
132
138
  modalOverlay: true,
133
139
 
134
- tabSpaces: false, // true or number of spaces
135
140
  tabFocus: true,
136
141
 
137
142
  air: false,
138
- airButtons: ['formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent'],
143
+ airButtons: ['formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 'fontcolor', 'backcolor'],
139
144
 
140
145
  toolbar: true,
141
146
  toolbarFixed: false,
142
- toolbarFixedTarget: document,
143
147
  toolbarFixedTopOffset: 0, // pixels
144
148
  toolbarFixedBox: false,
145
149
  toolbarExternal: false, // ID selector
@@ -149,7 +153,8 @@
149
153
 
150
154
  buttonsCustom: {},
151
155
  buttonsAdd: [],
152
- buttons: ['html', '|', 'formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 'image', 'video', 'file', 'table', 'link', '|', 'alignment', '|', 'horizontalrule'], // 'underline', 'alignleft', 'aligncenter', 'alignright', 'justify'
156
+ buttons: ['html', '|', 'formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 'image', 'video', 'file', 'table', 'link', '|', 'fontcolor', 'backcolor', '|', 'alignment', '|', 'horizontalrule'], // 'underline', 'alignleft', 'aligncenter', 'alignright', 'justify'
157
+ colors: ['#ffffff', '#000000', '#eeece1', '#1f497d', '#4f81bd', '#c0504d', '#9bbb59', '#8064a2', '#4bacc6', '#f79646', '#ffff00', '#f2f2f2', '#7f7f7f', '#ddd9c3', '#c6d9f0', '#dbe5f1', '#f2dcdb', '#ebf1dd', '#e5e0ec', '#dbeef3', '#fdeada', '#fff2ca', '#d8d8d8', '#595959', '#c4bd97', '#8db3e2', '#b8cce4', '#e5b9b7', '#d7e3bc', '#ccc1d9', '#b7dde8', '#fbd5b5', '#ffe694', '#bfbfbf', '#3f3f3f', '#938953', '#548dd4', '#95b3d7', '#d99694', '#c3d69b', '#b2a2c7', '#b7dde8', '#fac08f', '#f2c314', '#a5a5a5', '#262626', '#494429', '#17365d', '#366092', '#953734', '#76923c', '#5f497a', '#92cddc', '#e36c09', '#c09100', '#7f7f7f', '#0c0c0c', '#1d1b10', '#0f243e', '#244061', '#632423', '#4f6128', '#3f3151', '#31859b', '#974806', '#7f6000'],
153
158
 
154
159
  activeButtons: ['deleted', 'italic', 'bold', 'underline', 'unorderedlist', 'orderedlist', 'alignleft', 'aligncenter', 'alignright', 'justify', 'table'],
155
160
  activeButtonsStates: {
@@ -168,14 +173,12 @@
168
173
  },
169
174
  activeButtonsAdd: false, // object, ex.: { tag: 'buttonName' }
170
175
 
171
- formattingTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
176
+ formattingTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4'],
172
177
 
173
178
  linebreaks: false,
174
179
  paragraphy: true,
175
180
  convertDivs: true,
176
181
  convertLinks: true,
177
- convertImageLinks: false,
178
- convertVideoLinks: false,
179
182
  formattingPre: false,
180
183
  phpTags: false,
181
184
 
@@ -201,7 +204,7 @@
201
204
  newLevel: ['blockquote', 'div', 'dl', 'fieldset', 'form', 'frameset', 'map', 'ol', 'p', 'pre', 'select', 'td', 'th', 'tr', 'ul'],
202
205
  blockLevelElements: ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DD', 'DL', 'DT', 'DIV', 'LI',
203
206
  'BLOCKQUOTE', 'OUTPUT', 'FIGCAPTION', 'PRE', 'ADDRESS', 'SECTION',
204
- 'HEADER', 'FOOTER', 'ASIDE', 'ARTICLE', 'TD'],
207
+ 'HEADER', 'FOOTER', 'ASIDE', 'ARTICLE'],
205
208
  // lang
206
209
  langs: {
207
210
  en: {
@@ -221,7 +224,6 @@
221
224
  header2: 'Header 2',
222
225
  header3: 'Header 3',
223
226
  header4: 'Header 4',
224
- header5: 'Header 5',
225
227
  bold: 'Bold',
226
228
  italic: 'Italic',
227
229
  fontcolor: 'Font Color',
@@ -272,8 +274,7 @@
272
274
  link_new_tab: 'Open link in new tab',
273
275
  underline: 'Underline',
274
276
  alignment: 'Alignment',
275
- filename: 'Name (optional)',
276
- edit: 'Edit'
277
+ filename: 'Name (optional)'
277
278
  }
278
279
  }
279
280
  };
@@ -281,7 +282,8 @@
281
282
  // Functionality
282
283
  Redactor.fn = $.Redactor.prototype = {
283
284
 
284
- keyCode: {
285
+ keyCode:
286
+ {
285
287
  BACKSPACE: 8,
286
288
  DELETE: 46,
287
289
  DOWN: 40,
@@ -301,13 +303,10 @@
301
303
  this.$element = this.$source = $(el);
302
304
  this.uuid = uuid++;
303
305
 
304
- // clonning options
305
- var opts = $.extend(true, {}, $.Redactor.opts);
306
-
307
306
  // current settings
308
307
  this.opts = $.extend(
309
308
  {},
310
- opts,
309
+ $.Redactor.opts,
311
310
  this.$element.data(),
312
311
  options
313
312
  );
@@ -419,12 +418,6 @@
419
418
  title: lang.header4,
420
419
  func: 'formatBlocks',
421
420
  className: 'redactor_format_h4'
422
- },
423
- h5:
424
- {
425
- title: lang.header5,
426
- func: 'formatBlocks',
427
- className: 'redactor_format_h5'
428
421
  }
429
422
  }
430
423
  },
@@ -656,7 +649,6 @@
656
649
  clearInterval(this.autosaveInterval);
657
650
 
658
651
  $(window).off('.redactor');
659
- this.$source.off('redactor-textarea');
660
652
  this.$element.off('.redactor').removeData('redactor');
661
653
 
662
654
  var html = this.get();
@@ -677,11 +669,6 @@
677
669
 
678
670
  $elem.removeClass('redactor_editor').removeClass('redactor_editor_wym').removeAttr('contenteditable').html(html).show();
679
671
  }
680
-
681
- if (this.opts.air)
682
- {
683
- $('.redactor_air').remove();
684
- }
685
672
  },
686
673
 
687
674
  // API GET
@@ -720,14 +707,12 @@
720
707
 
721
708
  return html;
722
709
  },
723
- set: function(html, strip, placeholderRemove)
710
+ set: function(html, strip)
724
711
  {
725
712
  html = html.toString();
726
713
 
727
714
  if (this.opts.fullpage) this.setCodeIframe(html);
728
715
  else this.setEditor(html, strip);
729
-
730
- if (placeholderRemove !== false) this.placeholderRemove();
731
716
  },
732
717
  setEditor: function(html, strip)
733
718
  {
@@ -799,14 +784,19 @@
799
784
 
800
785
  if ($.trim(html) === '<br>') html = '';
801
786
 
802
- if (html !== '' && this.opts.tidyHtml) html = this.cleanHtml(html);
803
- html = html.replace(/<br>/gi, '<br />');
787
+ if (html !== '') html = this.cleanHtml(html);
804
788
 
805
789
  // before callback
806
790
  html = this.callback('syncBefore', false, html);
807
791
 
808
792
  this.$source.val(html);
809
793
 
794
+ // TMP:
795
+ if (typeof htmlEncode != 'undefined')
796
+ {
797
+ $('#' + this.$element[0].id + '_code').html(htmlEncode(html));
798
+ }
799
+
810
800
  // onchange & after callback
811
801
  this.callback('syncAfter', false, html);
812
802
 
@@ -830,40 +820,23 @@
830
820
  html = html.replace(/&#8203;/gi, '');
831
821
  html = html.replace(/&nbsp;/gi, ' ');
832
822
 
833
- // link nofollow
834
- if (this.opts.linkNofollow)
835
- {
836
- html = html.replace(/<a(.*?)rel="nofollow"(.*?)>/gi, '<a$1$2>');
837
- html = html.replace(/<a(.*?)>/gi, '<a$1 rel="nofollow">');
838
- }
839
-
840
823
  // php code fix
841
824
  html = html.replace('<!--?php', '<?php');
842
825
  html = html.replace('?-->', '?>');
843
826
 
827
+
828
+ // Remove verified attr
844
829
  html = html.replace(/ data-tagblock=""/gi, '');
845
830
  html = html.replace(/<br\s?\/?>\n?<\/(P|H[1-6]|LI|ADDRESS|SECTION|HEADER|FOOTER|ASIDE|ARTICLE)>/gi, '</$1>');
846
831
 
847
- // remove image resize
848
- html = html.replace(/<span(.*?)id="redactor-image-box"(.*?)>([\w\W]*?)<img(.*?)><\/span>/i, '$3<img$4>');
849
- html = html.replace(/<span(.*?)id="redactor-image-resizer"(.*?)>(.*?)<\/span>/i, '');
850
- html = html.replace(/<span(.*?)id="redactor-image-editter"(.*?)>(.*?)<\/span>/i, '');
851
-
852
- // remove spans
853
832
  html = html.replace(/<span\s*?>([\w\W]*?)<\/span>/gi, '$1');
854
833
  html = html.replace(/<span(.*?)data-redactor="verified"(.*?)>([\w\W]*?)<\/span>/gi, '<span$1$2>$3</span>');
855
834
  html = html.replace(/<span(.*?)data-redactor-inlineMethods=""(.*?)>([\w\W]*?)<\/span>/gi, '<span$1$2>$3</span>' );
856
835
  html = html.replace(/<span\s*?>([\w\W]*?)<\/span>/gi, '$1');
857
836
  html = html.replace(/<span\s*?id="selection-marker(.*?)"(.*?)>([\w\W]*?)<\/span>/gi, '');
858
837
  html = html.replace(/<span\s*?>([\w\W]*?)<\/span>/gi, '$1');
859
- html = html.replace(/<span(.*?)data-redactor="verified"(.*?)>([\w\W]*?)<\/span>/gi, '<span$1$2>$3</span>');
860
- html = html.replace(/<span(.*?)data-redactor-inlineMethods=""(.*?)>([\w\W]*?)<\/span>/gi, '<span$1$2>$3</span>' );
861
838
  html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');
862
839
 
863
- // amp fix
864
- html = html.replace(/;amp;/gi, ';');
865
-
866
-
867
840
  html = this.cleanReConvertProtected(html);
868
841
 
869
842
  return html;
@@ -962,7 +935,7 @@
962
935
  this.$source.attr('dir', this.opts.direction).hide();
963
936
 
964
937
  // set code
965
- this.set(this.content, true, false);
938
+ this.set(this.content);
966
939
  },
967
940
  buildOptions: function()
968
941
  {
@@ -1029,408 +1002,333 @@
1029
1002
  },
1030
1003
  buildBindKeyboard: function()
1031
1004
  {
1032
- if (this.opts.dragUpload)
1005
+ var oldsafari = false;
1006
+ if (this.browser('webkit') && navigator.userAgent.indexOf('Chrome') === -1)
1033
1007
  {
1034
- this.$editor.on('drop.redactor', $.proxy(this.buildEventDrop, this));
1008
+ var arr = this.browser('version').split('.');
1009
+ if (arr[0] < 536) oldsafari = true;
1035
1010
  }
1036
1011
 
1037
- this.$editor.on('paste.redactor', $.proxy(this.buildEventPaste, this));
1038
- this.$editor.on('keydown.redactor', $.proxy(this.buildEventKeydown, this));
1039
- this.$editor.on('keyup.redactor', $.proxy(this.buildEventKeyup, this));
1040
-
1041
-
1042
-
1043
- // textarea callback
1044
- if ($.isFunction(this.opts.textareaKeydownCallback))
1012
+ this.$editor.on('paste.redactor', $.proxy(function(e)
1045
1013
  {
1046
- this.$source.on('keydown.redactor-textarea', $.proxy(this.opts.textareaKeydownCallback, this));
1047
- }
1014
+ if (oldsafari) return true;
1048
1015
 
1049
- // focus callback
1050
- if ($.isFunction(this.opts.focusCallback))
1051
- {
1052
- this.$editor.on('focus.redactor', $.proxy(this.opts.focusCallback, this));
1053
- }
1016
+ // paste except opera
1017
+ if (this.browser('opera')) return true;
1054
1018
 
1055
- // blur callback
1056
- this.$editor.on('blur.redactor', $.proxy(function()
1057
- {
1058
- this.selectall = false;
1059
- }, this));
1060
- if ($.isFunction(this.opts.blurCallback))
1061
- {
1062
- this.$editor.on('blur.redactor', $.proxy(this.opts.blurCallback, this));
1063
- }
1019
+ if (this.opts.cleanup)
1020
+ {
1021
+ rtePaste = true;
1064
1022
 
1065
- },
1066
- buildEventDrop: function(e)
1067
- {
1068
- e = e.originalEvent || e;
1023
+ this.selectionSave();
1069
1024
 
1070
- if (window.FormData === undefined) return true;
1025
+ if (!this.selectall)
1026
+ {
1027
+ if (this.opts.autoresize === true )
1028
+ {
1029
+ this.$editor.height(this.$editor.height());
1030
+ this.saveScroll = this.document.body.scrollTop;
1031
+ }
1032
+ else
1033
+ {
1034
+ this.saveScroll = this.$editor.scrollTop();
1035
+ }
1036
+ }
1071
1037
 
1072
- var length = e.dataTransfer.files.length;
1073
- if (length == 0) return true;
1038
+ var frag = this.extractContent();
1074
1039
 
1075
- e.preventDefault();
1040
+ setTimeout($.proxy(function()
1041
+ {
1042
+ var pastedFrag = this.extractContent();
1043
+ this.$editor.append(frag);
1076
1044
 
1077
- var file = e.dataTransfer.files[0];
1045
+ this.selectionRestore();
1078
1046
 
1079
- if (this.opts.dnbImageTypes !== false && this.opts.dnbImageTypes.indexOf(file.type) == -1)
1080
- {
1081
- return true;
1082
- }
1047
+ var html = this.getFragmentHtml(pastedFrag);
1048
+ this.pasteClean(html);
1083
1049
 
1084
- this.bufferSet();
1050
+ if (this.opts.autoresize === true) this.$editor.css('height', 'auto');
1085
1051
 
1086
- 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>');
1087
- $(document.body).append(progress);
1052
+ }, this), 1);
1053
+ }
1088
1054
 
1089
- this.dragUploadAjax(this.opts.imageUpload, file, true, progress, e);
1055
+ }, this));
1090
1056
 
1091
- },
1092
- buildEventPaste: function(e)
1093
- {
1094
- var oldsafari = false;
1095
- if (this.browser('webkit') && navigator.userAgent.indexOf('Chrome') === -1)
1057
+ this.$editor.on('keydown.redactor', $.proxy(function(e)
1096
1058
  {
1097
- var arr = this.browser('version').split('.');
1098
- if (arr[0] < 536) oldsafari = true;
1099
- }
1059
+ if (rtePaste) return false;
1060
+
1061
+ var key = e.which;
1062
+ var ctrl = e.ctrlKey || e.metaKey;
1063
+ var parent = this.getParent();
1064
+ var current = this.getCurrent();
1065
+ var block = this.getBlock();
1066
+ var pre = false;
1100
1067
 
1101
- if (oldsafari) return true;
1068
+ this.callback('keydown', e);
1102
1069
 
1103
- // paste except opera (not webkit)
1104
- if (this.browser('opera')) return true;
1070
+ // pre & down
1071
+ if ((parent && $(parent).get(0).tagName === 'PRE') || (current && $(current).get(0).tagName === 'PRE'))
1072
+ {
1073
+ pre = true;
1074
+ if (key === this.keyCode.DOWN) this.insertAfterLastElement(block);
1075
+ }
1105
1076
 
1106
- // clipboard upload
1107
- if (this.opts.clipboardUpload && this.buildEventClipboardUpload(e)) return true;
1077
+ // down
1078
+ if (key === this.keyCode.DOWN)
1079
+ {
1080
+ if (parent && $(parent).get(0).tagName === 'BLOCKQUOTE') this.insertAfterLastElement(parent);
1081
+ if (current && $(current).get(0).tagName === 'BLOCKQUOTE') this.insertAfterLastElement(current);
1082
+ }
1108
1083
 
1109
- if (this.opts.cleanup)
1110
- {
1111
- rtePaste = true;
1084
+ // shortcuts setup
1085
+ if (ctrl && !e.shiftKey) this.shortcuts(e, key);
1112
1086
 
1113
- this.selectionSave();
1087
+ // buffer setup
1088
+ if (ctrl && key === 90 && !e.shiftKey && !e.altKey) // z key
1089
+ {
1090
+ e.preventDefault();
1091
+ if (this.opts.buffer.length) this.bufferUndo();
1092
+ else this.document.execCommand('undo', false, false);
1093
+ return;
1094
+ }
1095
+ // undo
1096
+ else if (ctrl && key === 90 && e.shiftKey && !e.altKey)
1097
+ {
1098
+ e.preventDefault();
1099
+ if (this.opts.rebuffer.length != 0) this.bufferRedo();
1100
+ else this.document.execCommand('redo', false, false);
1101
+ return;
1102
+ }
1114
1103
 
1115
- if (!this.selectall)
1104
+ // select all
1105
+ if (ctrl && key === 65)
1116
1106
  {
1117
- if (this.opts.autoresize === true )
1118
- {
1119
- this.$editor.height(this.$editor.height());
1120
- this.saveScroll = this.document.body.scrollTop;
1121
- }
1122
- else
1123
- {
1124
- this.saveScroll = this.$editor.scrollTop();
1125
- }
1107
+ this.selectall = true;
1108
+ }
1109
+ else if (key != this.keyCode.LEFT_WIN && !ctrl)
1110
+ {
1111
+ this.selectall = false;
1126
1112
  }
1127
1113
 
1128
- var frag = this.extractContent();
1129
1114
 
1130
- setTimeout($.proxy(function()
1115
+ // enter
1116
+ if (key == this.keyCode.ENTER && !e.shiftKey && !e.ctrlKey && !e.metaKey )
1131
1117
  {
1132
- var pastedFrag = this.extractContent();
1133
- this.$editor.append(frag);
1134
-
1135
- this.selectionRestore();
1118
+ // In ie, opera in the tables are created paragraphs, fix it.
1119
+ if (parent.nodeType == 1 && (parent.tagName == 'TD' || parent.tagName == 'TH'))
1120
+ {
1121
+ this.bufferSet();
1136
1122
 
1137
- var html = this.getFragmentHtml(pastedFrag);
1138
- this.pasteClean(html);
1123
+ this.insertNode(document.createElement('br'));
1124
+ e.preventDefault();
1125
+ return false;
1126
+ }
1139
1127
 
1140
- if (this.opts.autoresize === true) this.$editor.css('height', 'auto');
1128
+ // pre
1129
+ if (pre === true)
1130
+ {
1131
+ this.bufferSet();
1132
+ e.preventDefault();
1141
1133
 
1142
- }, this), 1);
1143
- }
1144
- },
1145
- buildEventClipboardUpload: function(e)
1146
- {
1147
- var event = e.originalEvent || e;
1148
- this.clipboardFilePaste = false;
1134
+ var html = $(current).parent().text();
1135
+ this.insertNode(document.createTextNode('\n'));
1136
+ if (html.search(/\s$/) == -1)
1137
+ {
1138
+ this.insertNode(document.createTextNode('\n'));
1139
+ }
1149
1140
 
1150
- if (typeof(event.clipboardData) === 'undefined') return false;
1151
- if (event.clipboardData.items)
1152
- {
1153
- var file = event.clipboardData.items[0].getAsFile();
1154
- if (file !== null)
1155
- {
1156
- this.bufferSet();
1157
- this.clipboardFilePaste = true;
1141
+ this.sync();
1158
1142
 
1159
- var reader = new FileReader();
1160
- reader.onload = $.proxy(this.pasteClipboardUpload, this);
1161
- reader.readAsDataURL(file);
1143
+ return false;
1144
+ }
1145
+ else
1146
+ {
1147
+ if (!this.opts.linebreaks)
1148
+ {
1149
+ // replace div to p
1150
+ if (block && this.opts.rBlockTest.test(block.tagName))
1151
+ {
1152
+ // hit enter
1153
+ this.bufferSet();
1162
1154
 
1163
- return true;
1164
- }
1165
- }
1155
+ setTimeout($.proxy(function()
1156
+ {
1157
+ var blockElem = this.getBlock();
1158
+ if (blockElem.tagName === 'DIV' && !$(blockElem).hasClass('redactor_editor'))
1159
+ {
1160
+ var node = $('<p>' + this.opts.invisibleSpace + '</p>');
1161
+ $(blockElem).replaceWith(node);
1162
+ this.selectionStart(node);
1163
+ }
1166
1164
 
1167
- return false;
1168
1165
 
1169
- },
1170
- buildEventKeydown: function(e)
1171
- {
1172
- if (rtePaste) return false;
1166
+ }, this), 1);
1167
+ }
1168
+ else if (block === false)
1169
+ {
1170
+ // hit enter
1171
+ this.bufferSet();
1173
1172
 
1174
- var key = e.which;
1175
- var ctrl = e.ctrlKey || e.metaKey;
1176
- var parent = this.getParent();
1177
- var current = this.getCurrent();
1178
- var block = this.getBlock();
1179
- var pre = false;
1173
+ var node = $('<p>' + this.opts.invisibleSpace + '</p>');
1174
+ this.insertNode(node[0]);
1175
+ this.selectionStart(node);
1176
+ return false;
1177
+ }
1180
1178
 
1181
- this.callback('keydown', e);
1179
+ }
1182
1180
 
1183
- this.imageResizeHide(false);
1181
+ if (this.opts.linebreaks)
1182
+ {
1183
+ // replace div to br
1184
+ if (block && this.opts.rBlockTest.test(block.tagName))
1185
+ {
1186
+ // hit enter
1187
+ this.bufferSet();
1184
1188
 
1185
- // pre & down
1186
- if ((parent && $(parent).get(0).tagName === 'PRE') || (current && $(current).get(0).tagName === 'PRE'))
1187
- {
1188
- pre = true;
1189
- if (key === this.keyCode.DOWN) this.insertAfterLastElement(block);
1190
- }
1189
+ setTimeout($.proxy(function()
1190
+ {
1191
+ var blockElem = this.getBlock();
1192
+ if ((blockElem.tagName === 'DIV' || blockElem.tagName === 'P') && !$(blockElem).hasClass('redactor_editor'))
1193
+ {
1194
+ this.replaceLineBreak(blockElem);
1195
+ }
1191
1196
 
1192
- // down
1193
- if (key === this.keyCode.DOWN)
1194
- {
1195
- if (parent && $(parent).get(0).tagName === 'BLOCKQUOTE') this.insertAfterLastElement(parent);
1196
- if (current && $(current).get(0).tagName === 'BLOCKQUOTE') this.insertAfterLastElement(current);
1197
- }
1197
+ }, this), 1);
1198
+ }
1199
+ else
1200
+ {
1201
+ // hit enter
1202
+ this.bufferSet();
1198
1203
 
1199
- // shortcuts setup
1200
- if (ctrl && !e.shiftKey) this.shortcuts(e, key);
1204
+ this.insertLineBreak();
1205
+ e.preventDefault();
1206
+ return;
1207
+ }
1208
+ }
1201
1209
 
1202
- // buffer setup
1203
- if (ctrl && key === 90 && !e.shiftKey && !e.altKey) // z key
1204
- {
1205
- e.preventDefault();
1206
- if (this.opts.buffer.length) this.bufferUndo();
1207
- else this.document.execCommand('undo', false, false);
1208
- return;
1209
- }
1210
- // undo
1211
- else if (ctrl && key === 90 && e.shiftKey && !e.altKey)
1212
- {
1213
- e.preventDefault();
1214
- if (this.opts.rebuffer.length != 0) this.bufferRedo();
1215
- else this.document.execCommand('redo', false, false);
1216
- return;
1217
- }
1210
+ // blockquote, figcaption
1211
+ if (block.tagName == 'BLOCKQUOTE'
1212
+ || block.tagName == 'FIGCAPTION')
1213
+ {
1214
+ // hit enter
1215
+ this.bufferSet();
1218
1216
 
1219
- // select all
1220
- if (ctrl && key === 65) this.selectall = true;
1221
- else if (key != this.keyCode.LEFT_WIN && !ctrl) this.selectall = false;
1217
+ this.insertLineBreak();
1218
+ e.preventDefault();
1219
+ return;
1220
+ }
1222
1221
 
1223
- // enter
1224
- if (key == this.keyCode.ENTER && !e.shiftKey && !e.ctrlKey && !e.metaKey )
1225
- {
1226
- // In ie, opera in the tables are created paragraphs, fix it.
1227
- if (parent.nodeType == 1 && (parent.tagName == 'TD' || parent.tagName == 'TH'))
1222
+ }
1223
+ }
1224
+ else if (key === this.keyCode.ENTER && (e.ctrlKey || e.shiftKey)) // Shift+Enter or Ctrl+Enter
1228
1225
  {
1229
- e.preventDefault();
1230
1226
  this.bufferSet();
1231
- this.insertNode(document.createElement('br'));
1232
- this.callback('enter', e);
1233
- return false;
1227
+
1228
+ e.preventDefault();
1229
+ this.insertLineBreak();
1234
1230
  }
1235
1231
 
1236
- // pre
1237
- if (pre === true)
1232
+ // tab
1233
+ if (key === this.keyCode.TAB && this.opts.shortcuts )
1238
1234
  {
1235
+ if (!this.opts.tabFocus) return true;
1236
+ if (this.isEmpty(this.get())) return true;
1237
+
1239
1238
  e.preventDefault();
1240
- this.bufferSet();
1241
- var html = $(current).parent().text();
1242
- this.insertNode(document.createTextNode('\n'));
1243
- if (html.search(/\s$/) == -1)
1239
+
1240
+ if (pre === true && !e.shiftKey)
1244
1241
  {
1245
- this.insertNode(document.createTextNode('\n'));
1242
+ this.bufferSet();
1243
+ this.insertNode(document.createTextNode('\t'));
1244
+ this.sync();
1245
+ return false;
1246
+ }
1247
+ else
1248
+ {
1249
+ if (!e.shiftKey) this.indentingIndent();
1250
+ else this.indentingOutdent();
1246
1251
  }
1247
1252
 
1248
- this.sync();
1249
- this.callback('enter', e);
1250
1253
  return false;
1251
1254
  }
1252
- else
1255
+
1256
+ // delete zero-width space before the removing
1257
+ if (key === this.keyCode.BACKSPACE)
1253
1258
  {
1254
- if (!this.opts.linebreaks)
1259
+ if (typeof current.tagName !== 'undefined' && /^(H[1-6])$/i.test(current.tagName))
1255
1260
  {
1256
- // replace div to p
1257
- if (block && this.opts.rBlockTest.test(block.tagName))
1258
- {
1259
- // hit enter
1260
- this.bufferSet();
1261
-
1262
- setTimeout($.proxy(function()
1263
- {
1264
- var blockElem = this.getBlock();
1265
- if (blockElem.tagName === 'DIV' && !$(blockElem).hasClass('redactor_editor'))
1266
- {
1267
- var node = $('<p>' + this.opts.invisibleSpace + '</p>');
1268
- $(blockElem).replaceWith(node);
1269
- this.selectionStart(node);
1270
- }
1271
-
1272
- }, this), 1);
1273
- }
1274
- else if (block === false)
1275
- {
1276
- // hit enter
1277
- this.bufferSet();
1278
-
1279
- var node = $('<p>' + this.opts.invisibleSpace + '</p>');
1280
- this.insertNode(node[0]);
1281
- this.selectionStart(node);
1282
- this.callback('enter', e);
1283
- return false;
1284
- }
1261
+ var node;
1262
+ if (this.opts.linebreaks === false) node = $('<p>' + this.opts.invisibleSpace + '</p>');
1263
+ else node = $('<br>' + this.opts.invisibleSpace);
1285
1264
 
1265
+ $(current).replaceWith(node);
1266
+ this.selectionStart(node);
1286
1267
  }
1287
1268
 
1288
- if (this.opts.linebreaks)
1269
+ if (typeof current.nodeValue !== 'undefined' && current.nodeValue !== null)
1289
1270
  {
1290
- // replace div to br
1291
- if (block && this.opts.rBlockTest.test(block.tagName))
1271
+ var value = $.trim(current.nodeValue.replace(/[^\u0000-~]/g, ''));
1272
+ if (current.remove && current.nodeType === 3 && current.nodeValue.charCodeAt(0) == 8203 && value == '')
1292
1273
  {
1293
- // hit enter
1294
- this.bufferSet();
1295
-
1296
- setTimeout($.proxy(function()
1297
- {
1298
- var blockElem = this.getBlock();
1299
- if ((blockElem.tagName === 'DIV' || blockElem.tagName === 'P') && !$(blockElem).hasClass('redactor_editor'))
1300
- {
1301
- this.replaceLineBreak(blockElem);
1302
- }
1303
-
1304
- }, this), 1);
1305
- }
1306
- else
1307
- {
1308
- return this.buildEventKeydownInsertLineBreak(e);
1274
+ current.remove();
1309
1275
  }
1310
1276
  }
1311
-
1312
- // blockquote, figcaption
1313
- if (block.tagName == 'BLOCKQUOTE' || block.tagName == 'FIGCAPTION')
1314
- {
1315
- return this.buildEventKeydownInsertLineBreak(e);
1316
- }
1317
-
1318
1277
  }
1319
1278
 
1320
- this.callback('enter', e);
1321
- }
1322
- else if (key === this.keyCode.ENTER && (e.ctrlKey || e.shiftKey)) // Shift+Enter or Ctrl+Enter
1323
- {
1324
- this.bufferSet();
1325
-
1326
- e.preventDefault();
1327
- this.insertLineBreak();
1328
- }
1279
+ }, this));
1329
1280
 
1330
- // tab
1331
- if (key === this.keyCode.TAB && this.opts.shortcuts )
1281
+ this.$editor.on('keyup.redactor', $.proxy(function(e)
1332
1282
  {
1333
- if (!this.opts.tabFocus) return true;
1334
- if (this.isEmpty(this.get())) return true;
1335
-
1336
- e.preventDefault();
1283
+ if (rtePaste) return false;
1337
1284
 
1338
- if (pre === true && !e.shiftKey)
1339
- {
1340
- this.bufferSet();
1341
- this.insertNode(document.createTextNode('\t'));
1342
- this.sync();
1343
- return false;
1285
+ var key = e.which;
1286
+ var parent = this.getParent();
1287
+ var current = this.getCurrent();
1344
1288
 
1345
- }
1346
- else if (this.opts.tabSpaces !== false)
1289
+ // replace to p before / after the table or body
1290
+ if (!this.opts.linebreaks && current.nodeType == 3 && (parent == false || parent.tagName == 'BODY'))
1347
1291
  {
1348
- this.bufferSet();
1349
- this.insertNode(document.createTextNode(Array(this.opts.tabSpaces + 1).join('\u00a0')));
1350
- this.sync();
1351
- return false;
1352
- }
1353
- else
1354
- {
1355
- if (!e.shiftKey) this.indentingIndent();
1356
- else this.indentingOutdent();
1292
+ var node = $('<p>').append($(current).clone());
1293
+ $(current).replaceWith(node);
1294
+ var next = $(node).next();
1295
+ if (typeof(next[0]) !== 'undefined' && next[0].tagName == 'BR')
1296
+ {
1297
+ next.remove();
1298
+ }
1299
+ this.selectionEnd(node);
1357
1300
  }
1358
1301
 
1359
- return false;
1360
- }
1361
-
1362
- // delete zero-width space before the removing
1363
- if (key === this.keyCode.BACKSPACE)
1364
- {
1365
- if (typeof current.tagName !== 'undefined' && /^(H[1-6])$/i.test(current.tagName))
1302
+ // convert links
1303
+ if (this.opts.convertLinks && key === this.keyCode.ENTER)
1366
1304
  {
1367
- var node;
1368
- if (this.opts.linebreaks === false) node = $('<p>' + this.opts.invisibleSpace + '</p>');
1369
- else node = $('<br>' + this.opts.invisibleSpace);
1370
-
1371
- $(current).replaceWith(node);
1372
- this.selectionStart(node);
1305
+ this.formatLinkify(this.opts.linkProtocol);
1373
1306
  }
1374
1307
 
1375
- if (typeof current.nodeValue !== 'undefined' && current.nodeValue !== null)
1308
+ // if empty
1309
+ if (this.opts.linebreaks === false && (key === this.keyCode.DELETE || key === this.keyCode.BACKSPACE))
1376
1310
  {
1377
- var value = $.trim(current.nodeValue.replace(/[^\u0000-\u1C7F]/g, ''));
1378
- if (current.remove && current.nodeType === 3 && current.nodeValue.charCodeAt(0) == 8203 && value == '')
1379
- {
1380
- current.remove();
1381
- }
1311
+ return this.formatEmpty(e);
1382
1312
  }
1383
- }
1384
- },
1385
- buildEventKeydownInsertLineBreak: function(e)
1386
- {
1387
- this.bufferSet();
1388
- e.preventDefault();
1389
- this.insertLineBreak();
1390
- this.callback('enter', e);
1391
- return;
1392
- },
1393
- buildEventKeyup: function(e)
1394
- {
1395
- if (rtePaste) return false;
1396
1313
 
1397
- var key = e.which;
1398
- var parent = this.getParent();
1399
- var current = this.getCurrent();
1314
+ this.callback('keyup', e);
1315
+ this.sync();
1400
1316
 
1401
- // replace to p before / after the table or body
1402
- if (!this.opts.linebreaks && current.nodeType == 3 && (parent == false || parent.tagName == 'BODY'))
1403
- {
1404
- var node = $('<p>').append($(current).clone());
1405
- $(current).replaceWith(node);
1406
- var next = $(node).next();
1407
- if (typeof(next[0]) !== 'undefined' && next[0].tagName == 'BR')
1408
- {
1409
- next.remove();
1410
- }
1411
- this.selectionEnd(node);
1412
- }
1317
+ }, this));
1413
1318
 
1414
- // convert links
1415
- if ((this.opts.convertLinks || this.opts.convertImageLinks || this.opts.convertVideoLinks) && key === this.keyCode.ENTER)
1416
- {
1417
- this.formatLinkify(this.opts.linkProtocol, this.opts.convertLinks, this.opts.convertImageLinks, this.opts.convertVideoLinks);
1418
1319
 
1419
- setTimeout($.proxy(function()
1420
- {
1421
- if (this.opts.convertImageLinks) this.observeImages();
1422
- if (this.opts.observeLinks) this.observeLinks();
1423
- }, this), 5);
1320
+ // focus callback
1321
+ if ($.isFunction(this.opts.focusCallback))
1322
+ {
1323
+ this.$editor.on('focus.redactor', $.proxy(this.opts.focusCallback, this));
1424
1324
  }
1425
1325
 
1426
- // if empty
1427
- if (this.opts.linebreaks === false && (key === this.keyCode.DELETE || key === this.keyCode.BACKSPACE))
1326
+ // blur callback
1327
+ if ($.isFunction(this.opts.blurCallback))
1428
1328
  {
1429
- return this.formatEmpty(e);
1329
+ this.$editor.on('blur.redactor', $.proxy(this.opts.blurCallback, this));
1430
1330
  }
1431
1331
 
1432
- this.callback('keyup', e);
1433
- this.sync();
1434
1332
  },
1435
1333
  buildPlugins: function()
1436
1334
  {
@@ -1536,7 +1434,7 @@
1536
1434
  this.iframeAddCss();
1537
1435
 
1538
1436
  if (this.opts.fullpage) this.setFullpageOnInit(this.$editor.html());
1539
- else this.set(this.content, true, false);
1437
+ else this.set(this.content);
1540
1438
 
1541
1439
  this.buildOptions();
1542
1440
  this.buildAfter();
@@ -1685,7 +1583,7 @@
1685
1583
  this.$source.height(height).show().focus();
1686
1584
 
1687
1585
  // textarea indenting
1688
- this.$source.on('keydown.redactor-textarea-indenting', function (e)
1586
+ this.$source.on('keydown.redactor-textarea', function (e)
1689
1587
  {
1690
1588
  if (e.keyCode === 9)
1691
1589
  {
@@ -1727,7 +1625,7 @@
1727
1625
 
1728
1626
  if (this.opts.fullpage ) this.$editor.attr('contenteditable', true );
1729
1627
 
1730
- this.$source.off('keydown.redactor-textarea-indenting');
1628
+ this.$source.off('keydown.redactor-textarea');
1731
1629
 
1732
1630
  this.$editor.focus();
1733
1631
  this.selectionRestore();
@@ -1823,6 +1721,8 @@
1823
1721
 
1824
1722
  $.each(this.opts.buttons, $.proxy(function(i, btnName)
1825
1723
  {
1724
+
1725
+
1826
1726
  // separator
1827
1727
  if ( btnName === '|' ) this.$toolbar.append($(this.opts.buttonSeparator));
1828
1728
  else if(this.opts.toolbar[btnName])
@@ -1840,7 +1740,7 @@
1840
1740
  if (this.opts.toolbarFixed)
1841
1741
  {
1842
1742
  this.toolbarObserveScroll();
1843
- $(this.opts.toolbarFixedTarget).on('scroll.redactor', $.proxy(this.toolbarObserveScroll, this));
1743
+ $(document).on('scroll.redactor', $.proxy(this.toolbarObserveScroll, this));
1844
1744
  }
1845
1745
 
1846
1746
  // buttons response
@@ -1852,7 +1752,7 @@
1852
1752
  },
1853
1753
  toolbarObserveScroll: function()
1854
1754
  {
1855
- var scrollTop = $(this.opts.toolbarFixedTarget).scrollTop();
1755
+ var scrollTop = $(this.document).scrollTop();
1856
1756
  var boxTop = this.$box.offset().top;
1857
1757
  var left = 0;
1858
1758
 
@@ -2009,6 +1909,53 @@
2009
1909
  if (this.opts.iframe) hideHandler(this.document);
2010
1910
  },
2011
1911
 
1912
+ // COLORPICKER
1913
+ pickerBuild: function($dropdown, key)
1914
+ {
1915
+ $dropdown.width(210);
1916
+
1917
+ var rule = 'color';
1918
+ if (key === 'backcolor') rule = 'background-color';
1919
+
1920
+ var len = this.opts.colors.length;
1921
+ var _self = this;
1922
+ for (var i = 0; i < len; i++)
1923
+ {
1924
+ var color = this.opts.colors[i];
1925
+
1926
+ var $swatch = $('<a rel="' + color + '" href="javascript:;" class="redactor_color_link"></a>').css({ 'backgroundColor': color });
1927
+ $dropdown.append($swatch);
1928
+
1929
+ $swatch.on('click', function()
1930
+ {
1931
+ var type = $(this).attr('rel');
1932
+ if (key === 'backcolor') type = $(this).css('background-color');
1933
+
1934
+ _self.pickerSet(rule, type);
1935
+ });
1936
+ }
1937
+
1938
+ var $elNone = $('<a href="javascript:;" class="redactor_color_none"></a>')
1939
+ .html(this.opts.curLang.none)
1940
+ .on('click', function()
1941
+ {
1942
+ _self.pickerSet(rule, false);
1943
+ });
1944
+
1945
+ $dropdown.append($elNone);
1946
+ },
1947
+
1948
+ pickerSet: function(rule, type)
1949
+ {
1950
+ this.bufferSet();
1951
+
1952
+ this.$editor.focus();
1953
+ this.inlineRemoveStyle(rule);
1954
+ if (type !== false) this.inlineSetStyle(rule, type);
1955
+ if (this.opts.air) this.$air.fadeOut(100);
1956
+ this.sync();
1957
+ },
1958
+
2012
1959
  // DROPDOWNS
2013
1960
  dropdownBuild: function($dropdown, dropdownObject)
2014
1961
  {
@@ -2020,7 +1967,7 @@
2020
1967
  if (btnObject.name === 'separator') $item = $('<a class="redactor_separator_drop">');
2021
1968
  else
2022
1969
  {
2023
- $item = $('<a href="#" class="' + btnObject.className + ' redactor_dropdown_' + btnName + '">' + btnObject.title + '</a>');
1970
+ $item = $('<a href="javascript:;" class="' + btnObject.className + ' redactor_dropdown_' + btnName + '">' + btnObject.title + '</a>');
2024
1971
  $item.on('click', $.proxy(function(e)
2025
1972
  {
2026
1973
  if (e.preventDefault) e.preventDefault();
@@ -2040,7 +1987,7 @@
2040
1987
 
2041
1988
  }, this));
2042
1989
  },
2043
- dropdownShow: function(e, key)
1990
+ dropdownShow: function (e, $dropdown, key)
2044
1991
  {
2045
1992
  if (!this.opts.visual)
2046
1993
  {
@@ -2048,43 +1995,30 @@
2048
1995
  return false;
2049
1996
  }
2050
1997
 
2051
- var $dropdown = this.$toolbar.find('.redactor_dropdown_box_' + key);
2052
- var $button = this.buttonGet(key);
2053
-
2054
- if ($button.hasClass('dropact')) this.dropdownHideAll();
1998
+ if (this.buttonGet(key).hasClass('dropact')) this.dropdownHideAll();
2055
1999
  else
2056
2000
  {
2057
2001
  this.dropdownHideAll();
2058
2002
 
2059
2003
  this.buttonActive(key);
2060
- $button.addClass('dropact');
2004
+ this.buttonGet(key).addClass('dropact');
2005
+
2006
+ var keyPosition = this.buttonGet(key).position(), left = keyPosition.left + 'px', btnHeight = 29;
2061
2007
 
2062
- var keyPosition = $button.position();
2063
- if (this.toolbarFixed)
2008
+ if (this.opts.air)
2064
2009
  {
2065
- keyPosition = $button.offset();
2010
+ $dropdown.css({ position: 'absolute', left: left, top: btnHeight + 'px' }).show();
2066
2011
  }
2067
-
2068
- // fix right placement
2069
- var dropdownWidth = $dropdown.width();
2070
- if ((keyPosition.left + dropdownWidth) > $(document).width())
2012
+ else if (this.opts.toolbarFixed && this.toolbarFixed)
2071
2013
  {
2072
- keyPosition.left -= dropdownWidth;
2014
+ $dropdown.css({ position: 'fixed', left: left, top: btnHeight + 'px' }).show();
2015
+ }
2016
+ else
2017
+ {
2018
+ $dropdown.css({ position: 'absolute', left: left, top: keyPosition.top + btnHeight + 'px' }).show();
2073
2019
  }
2074
-
2075
- var left = keyPosition.left + 'px';
2076
- var btnHeight = 29;
2077
-
2078
- var position = 'absolute';
2079
- var top = btnHeight + 'px';
2080
-
2081
- if (this.opts.toolbarFixed && this.toolbarFixed) position = 'fixed';
2082
- else if (!this.opts.air) top = keyPosition.top + btnHeight + 'px';
2083
-
2084
- $dropdown.css({ position: position, left: left, top: top }).show();
2085
2020
  }
2086
2021
 
2087
-
2088
2022
  var hdlHideDropDown = $.proxy(function(e)
2089
2023
  {
2090
2024
  this.dropdownHide(e, $dropdown);
@@ -2114,6 +2048,7 @@
2114
2048
  buttonBuild: function(btnName, btnObject)
2115
2049
  {
2116
2050
  var $button = $('<a href="javascript:;" title="' + btnObject.title + '" class="redactor_btn redactor_btn_' + btnName + '"></a>');
2051
+ var $dropdown = $('<div class="redactor_dropdown" style="display: none;">');
2117
2052
 
2118
2053
  $button.on('click', $.proxy(function(e)
2119
2054
  {
@@ -2146,9 +2081,9 @@
2146
2081
  this.airBindMousemoveHide();
2147
2082
 
2148
2083
  }
2149
- else if (btnObject.dropdown)
2084
+ else if (btnName === 'backcolor' || btnName === 'fontcolor' || btnObject.dropdown)
2150
2085
  {
2151
- this.dropdownShow(e, btnName);
2086
+ this.dropdownShow(e, $dropdown, btnName);
2152
2087
  }
2153
2088
 
2154
2089
  this.buttonActiveObserver(false, btnName);
@@ -2156,11 +2091,12 @@
2156
2091
  }, this));
2157
2092
 
2158
2093
  // dropdown
2159
- if (btnObject.dropdown)
2094
+ if (btnName === 'backcolor' || btnName === 'fontcolor' || btnObject.dropdown)
2160
2095
  {
2161
- var $dropdown = $('<div class="redactor_dropdown redactor_dropdown_box_' + btnName + '" style="display: none;">');
2162
2096
  $dropdown.appendTo(this.$toolbar);
2163
- this.dropdownBuild($dropdown, btnObject.dropdown);
2097
+
2098
+ if ( btnName === 'backcolor' || btnName === 'fontcolor') this.pickerBuild($dropdown, btnName);
2099
+ else this.dropdownBuild($dropdown, btnObject.dropdown);
2164
2100
  }
2165
2101
 
2166
2102
  return $button;
@@ -2256,18 +2192,14 @@
2256
2192
  if (!this.opts.toolbar) return;
2257
2193
  var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown });
2258
2194
  var $btn = this.buttonGet(afterkey);
2259
-
2260
- if ($btn.size() !== 0) $btn.parent().after($('<li>').append(btn));
2261
- else this.$toolbar.append($('<li>').append(btn));
2195
+ $btn.parent().after($('<li>').append(btn));
2262
2196
  },
2263
2197
  buttonAddBefore: function(beforekey, key, title, callback, dropdown)
2264
2198
  {
2265
2199
  if (!this.opts.toolbar) return;
2266
2200
  var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown });
2267
2201
  var $btn = this.buttonGet(beforekey);
2268
-
2269
- if ($btn.size() !== 0) $btn.parent().before($('<li>').append(btn));
2270
- else this.$toolbar.append($('<li>').append(btn));
2202
+ $btn.parent().before($('<li>').append(btn));
2271
2203
  },
2272
2204
  buttonRemove: function (key, separator)
2273
2205
  {
@@ -2283,10 +2215,7 @@
2283
2215
 
2284
2216
  if (e === false && btnName !== 'html')
2285
2217
  {
2286
- if ($.inArray(btnName, this.opts.activeButtons) != -1)
2287
- {
2288
- this.buttonActiveToggle(btnName);
2289
- }
2218
+ this.buttonActiveToggle(btnName);
2290
2219
  return;
2291
2220
  }
2292
2221
 
@@ -2443,7 +2372,7 @@
2443
2372
  this.document.execCommand(cmd);
2444
2373
 
2445
2374
  var parent = this.getParent();
2446
- var $list = $(parent).closest('ol, ul');
2375
+ var $list = $(parent).parents('ol, ul');
2447
2376
 
2448
2377
  if ($list.length)
2449
2378
  {
@@ -2470,14 +2399,14 @@
2470
2399
  return;
2471
2400
  }
2472
2401
 
2473
- if (cmd === 'unlink')
2402
+ if (cmd === 'unlink' )
2474
2403
  {
2475
2404
  this.bufferSet();
2476
2405
 
2477
- var link = this.currentOrParentIs('A');
2478
- if (link)
2406
+ var parent = this.getParent();
2407
+ if (parent && $(parent)[0].tagName === 'A')
2479
2408
  {
2480
- $(link).replaceWith($(link).text());
2409
+ $(parent).replaceWith($(parent).text());
2481
2410
 
2482
2411
  this.sync();
2483
2412
  this.callback('execCommand', cmd, param);
@@ -2559,8 +2488,6 @@
2559
2488
  {
2560
2489
  var $el = false;
2561
2490
 
2562
- if (elem.tagName === 'TD') return;
2563
-
2564
2491
  if ($.inArray(elem.tagName, this.opts.alignmentTags) !== -1)
2565
2492
  {
2566
2493
  $el = $(elem);
@@ -2688,12 +2615,6 @@
2688
2615
  },
2689
2616
  cleanConvertProtected: function(html)
2690
2617
  {
2691
- if (this.opts.templateVars)
2692
- {
2693
- html = html.replace(/\{\{(.*?)\}\}/gi, '<!-- template double $1 -->');
2694
- html = html.replace(/\{(.*?)\}/gi, '<!-- template $1 -->');
2695
- }
2696
-
2697
2618
  html = html.replace(/<script(.*?)>([\w\W]*?)<\/script>/gi, '<title type="text/javascript" style="display: none;" class="redactor-script-tag"$1>$2</title>');
2698
2619
  html = html.replace(/<style(.*?)>([\w\W]*?)<\/style>/gi, '<section$1 style="display: none;" rel="redactor-style-tag">$2</section>');
2699
2620
  html = html.replace(/<form(.*?)>([\w\W]*?)<\/form>/gi, '<section$1 rel="redactor-form-tag">$2</section>');
@@ -2706,12 +2627,6 @@
2706
2627
  },
2707
2628
  cleanReConvertProtected: function(html)
2708
2629
  {
2709
- if (this.opts.templateVars)
2710
- {
2711
- html = html.replace(/<!-- template double (.*?) -->/gi, '{{$1}}');
2712
- html = html.replace(/<!-- template (.*?) -->/gi, '{$1}');
2713
- }
2714
-
2715
2630
  html = html.replace(/<title type="text\/javascript" style="display: none;" class="redactor-script-tag"(.*?)>([\w\W]*?)<\/title>/gi, '<script$1 type="text/javascript">$2</script>');
2716
2631
  html = html.replace(/<section(.*?) style="display: none;" rel="redactor-style-tag">([\w\W]*?)<\/section>/gi, '<style$1>$2</style>');
2717
2632
  html = html.replace(/<section(.*?)rel="redactor-form-tag"(.*?)>([\w\W]*?)<\/section>/gi, '<form$1$2>$3</form>');
@@ -2725,23 +2640,31 @@
2725
2640
  {
2726
2641
  if (buffer !== false)
2727
2642
  {
2728
- var buffer = []
2729
- var matches = html.match(/<(pre|style|script|title)(.*?)>([\w\W]*?)<\/(pre|style|script|title)>/gi);
2730
- if (matches === null) matches = [];
2731
-
2732
- if (this.opts.phpTags)
2643
+ // save code
2644
+ var buffer = [], z = 0, code;
2645
+ code = html.match(/<(pre|style|script|title)(.*?)>([\w\W]*?)<\/(pre|style|script|title)>/gi);
2646
+ if (code !== null)
2733
2647
  {
2734
- var phpMatches = html.match(/<\?php([\w\W]*?)\?>/gi);
2735
- if (phpMatches) matches = $.merge(matches, phpMatches);
2648
+ $.each(code, function(i,s)
2649
+ {
2650
+ z = i;
2651
+ html = html.replace(s, 'buffer_' + z);
2652
+ buffer.push(s);
2653
+ });
2736
2654
  }
2737
2655
 
2738
- if (matches)
2656
+ if (this.opts.phpTags)
2739
2657
  {
2740
- $.each(matches, function(i, s)
2658
+ code = html.match(/<\?php([\w\W]*?)\?>/gi);
2659
+ if (code !== null)
2741
2660
  {
2742
- html = html.replace(s, 'buffer_' + i);
2743
- buffer.push(s);
2744
- });
2661
+ $.each(code, function(i,s)
2662
+ {
2663
+ z = z + i;
2664
+ html = html.replace(s, 'buffer_' + i);
2665
+ buffer.push(s);
2666
+ });
2667
+ }
2745
2668
  }
2746
2669
  }
2747
2670
 
@@ -2750,22 +2673,26 @@
2750
2673
  html = html.replace(/\n\s*\n/g, "\n");
2751
2674
  html = html.replace(/^[\s\n]*/g, ' ');
2752
2675
  html = html.replace(/[\s\n]*$/g, ' ');
2753
- html = html.replace( />\s{2,}</g, '> <'); // between inline tags can be only one space
2676
+ html = html.replace( />\s{2,}</g, '><' ); // between inline tags can be only one space
2754
2677
 
2755
- html = this.cleanReplacer(html, buffer);
2678
+ if (buffer !== false)
2679
+ {
2680
+ html = this.cleanReplacer(buffer, html);
2681
+ }
2756
2682
 
2757
2683
  html = html.replace(/\n\n/g, "\n");
2758
2684
 
2759
2685
  return html;
2760
2686
  },
2761
- cleanReplacer: function(html, buffer)
2687
+ cleanReplacer: function(arr, html)
2762
2688
  {
2763
- if (buffer === false) return html;
2764
-
2765
- $.each(buffer, function(i,s)
2689
+ if (arr)
2766
2690
  {
2767
- html = html.replace('buffer_' + i, s);
2768
- });
2691
+ $.each(arr, function(i,s)
2692
+ {
2693
+ html = html.replace('buffer_' + i, s);
2694
+ });
2695
+ }
2769
2696
 
2770
2697
  return html;
2771
2698
  },
@@ -2803,29 +2730,35 @@
2803
2730
  html = html + "\n";
2804
2731
 
2805
2732
  var safes = [];
2733
+ var z = 0;
2806
2734
  var matches = html.match(/<(table|div|pre|object)(.*?)>([\w\W]*?)<\/(table|div|pre|object)>/gi);
2807
- if (matches === null) matches = [];
2808
2735
 
2809
- var commentsMatches = html.match(/<!--([\w\W]*?)-->/gi);
2810
- if (commentsMatches) matches = $.merge(matches, commentsMatches);
2736
+ if (matches)
2737
+ {
2738
+ $.each(matches, function(i,s)
2739
+ {
2740
+ z++;
2741
+ safes[z] = s;
2742
+ html = html.replace(s, '{replace' + z + '}\n');
2743
+ });
2744
+ }
2811
2745
 
2812
2746
  if (this.opts.phpTags)
2813
2747
  {
2814
2748
  var phpMatches = html.match(/<section(.*?)rel="redactor-php-tag">([\w\W]*?)<\/section>/gi);
2815
2749
  if (phpMatches)
2816
2750
  {
2817
- matches = $.merge(matches, phpMatches);
2751
+ $.each(phpMatches, function(i,s)
2752
+ {
2753
+ z++;
2754
+ safes[z] = s;
2755
+ html = html.replace(s, '{replace' + z + '}\n');
2756
+ });
2818
2757
  }
2819
2758
  }
2820
2759
 
2821
- if (matches)
2822
- {
2823
- $.each(matches, function(i,s)
2824
- {
2825
- safes[i] = s;
2826
- html = html.replace(s, '{replace' + i + '}\n');
2827
- });
2828
- }
2760
+ // comments safe
2761
+ html = html.replace(/<\!\-\-([\w\W]*?)\-\->/gi, "<comment>$1</comment>");
2829
2762
 
2830
2763
  html = html.replace(/<br \/>\s*<br \/>/gi, "\n\n");
2831
2764
 
@@ -2880,24 +2813,23 @@
2880
2813
  html = R('<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)', 'gi', '$1');
2881
2814
  html = R("\n</p>", 'gi', '</p>');
2882
2815
 
2883
- html = R('<li><p>', 'gi', '<li>');
2884
- html = R('</p></li>', 'gi', '</li>');
2885
2816
  html = R('</li><p>', 'gi', '</li>');
2886
2817
  //html = R('</ul><p>(.*?)</li>', 'gi', '</ul></li>');
2887
- /* html = R('</ol><p>', 'gi', '</ol>'); */
2818
+ html = R('</ol><p>', 'gi', '</ol>');
2888
2819
  html = R('<p>\t?\n?<p>', 'gi', '<p>');
2889
2820
  html = R('</dt><p>', 'gi', '</dt>');
2890
2821
  html = R('</dd><p>', 'gi', '</dd>');
2891
2822
  html = R('<br></p></blockquote>', 'gi', '</blockquote>');
2892
- html = R('<p>\t*</p>', 'gi', '');
2893
-
2823
+ html = R('<p> </p>', 'gi', '');
2894
2824
 
2895
- // restore safes
2896
2825
  $.each(safes, function(i,s)
2897
2826
  {
2898
2827
  html = html.replace('{replace' + i + '}', s);
2899
2828
  });
2900
2829
 
2830
+ // comments safe
2831
+ html = html.replace(/<comment>([\w\W]*?)<\/comment>/gi, '<!--$1-->');
2832
+
2901
2833
  return $.trim(html);
2902
2834
  },
2903
2835
  cleanConvertInlineTags: function(html)
@@ -2978,18 +2910,18 @@
2978
2910
 
2979
2911
  var $elem = this.$editor.find('li, img, a, b, strong, sub, sup, i, em, u, small, strike, del, span, cite');
2980
2912
 
2981
- $elem.not('[data-redactor="verified"]').filter('[style*="font-size"][style*="line-height"]')
2913
+ $elem.filter('[style*="font-size"][style*="line-height"]')
2982
2914
  .css('font-size', '')
2983
2915
  .css('line-height', '');
2984
2916
 
2985
- $elem.not('[data-redactor="verified"]').filter('[style*="background-color: transparent;"][style*="line-height"]')
2917
+ $elem.filter('[style*="background-color: transparent;"][style*="line-height"]')
2986
2918
  .css('background-color', '')
2987
2919
  .css('line-height', '');
2988
2920
 
2989
- $elem.not('[data-redactor="verified"]').filter('[style*="background-color: transparent;"]')
2921
+ $elem.filter('[style*="background-color: transparent;"]')
2990
2922
  .css('background-color', '');
2991
2923
 
2992
- $elem.not('[data-redactor="verified"]').css('line-height', '');
2924
+ $elem.css('line-height', '');
2993
2925
 
2994
2926
  $.each($elem, $.proxy(function(i,s)
2995
2927
  {
@@ -3406,10 +3338,8 @@
3406
3338
  $(wrapper).html(html);
3407
3339
  this.selectionElement(wrapper);
3408
3340
  var next = $(wrapper).next();
3409
- if (next.size() != 0 && next[0].tagName === 'BR')
3410
- {
3411
- next.remove();
3412
- }
3341
+ if (next[0].tagName === 'BR') next.remove();
3342
+
3413
3343
  }
3414
3344
  }
3415
3345
 
@@ -3530,7 +3460,7 @@
3530
3460
  var range = this.getRange()
3531
3461
  var el = this.getElement();
3532
3462
 
3533
- if ((range.collapsed || range.startContainer === range.endContainer) && el && !this.nodeTestBlocks(el))
3463
+ if (range.collapsed || range.startContainer === range.endContainer && el)
3534
3464
  {
3535
3465
  $(el)[type](attr, value);
3536
3466
  }
@@ -3637,22 +3567,15 @@
3637
3567
 
3638
3568
  var utag = tag.toUpperCase();
3639
3569
  var nodes = this.getNodes();
3640
- var parent = $(this.getParent()).parent();
3641
3570
 
3642
3571
  $.each(nodes, function(i, s)
3643
3572
  {
3644
- if (s.tagName === utag) this.inlineRemoveFormatReplace(s);
3573
+ if (s.tagName === utag) $(s).replaceWith($(s).contents());
3645
3574
  });
3646
3575
 
3647
- if (parent && parent[0].tagName === utag) this.inlineRemoveFormatReplace(parent);
3648
-
3649
3576
  this.selectionRestore();
3650
3577
  this.sync();
3651
3578
  },
3652
- inlineRemoveFormatReplace: function(el)
3653
- {
3654
- $(el).replaceWith($(el).contents());
3655
- },
3656
3579
 
3657
3580
  // INSERT
3658
3581
  insertHtml: function (html, sync)
@@ -3694,20 +3617,17 @@
3694
3617
  }
3695
3618
 
3696
3619
  // in the quote, we can insert text or links only
3697
- /*
3698
3620
  if (currBlock.tagName == 'BLOCKQUOTE' && html.indexOf('<a') === -1)
3699
3621
  {
3700
3622
  this.insertText(html);
3701
3623
  }
3702
- else
3703
- */
3704
- if ($html.contents().length > 1 && currBlock
3624
+ else if ($html.contents().length > 1 && currBlock
3705
3625
  || $html.contents().is('p, :header, ul, ol, div, table, blockquote, pre, address, section, header, footer, aside, article'))
3706
3626
  {
3707
- if (this.browser('msie')) this.document.selection.createRange().pasteHTML(html);
3627
+ if(this.browser('msie')) this.document.selection.createRange().pasteHTML(html);
3708
3628
  else this.document.execCommand('inserthtml', false, html);
3709
3629
  }
3710
- else this.insertHtmlAdvanced(html, false);
3630
+ else this.insertHtmlAdvanced(html);
3711
3631
 
3712
3632
  if (this.selectall)
3713
3633
  {
@@ -3723,7 +3643,7 @@
3723
3643
 
3724
3644
  if (sync !== false) this.sync();
3725
3645
  },
3726
- insertHtmlAdvanced: function(html, sync)
3646
+ insertHtmlAdvanced: function(html)
3727
3647
  {
3728
3648
  var sel = this.getSelection();
3729
3649
 
@@ -3751,12 +3671,6 @@
3751
3671
  sel.addRange(range);
3752
3672
  }
3753
3673
  }
3754
-
3755
- if (sync !== false)
3756
- {
3757
- this.sync();
3758
- }
3759
-
3760
3674
  },
3761
3675
  insertText: function(html)
3762
3676
  {
@@ -3787,41 +3701,11 @@
3787
3701
  sel.addRange(range);
3788
3702
  }
3789
3703
  },
3790
- insertNodeToCaretPositionFromPoint: function(e, node)
3791
- {
3792
- var range;
3793
- var x = e.clientX, y = e.clientY;
3794
- if (this.document.caretPositionFromPoint)
3795
- {
3796
- var pos = this.document.caretPositionFromPoint(x, y);
3797
- range = this.getRange();
3798
- range.setStart(pos.offsetNode, pos.offset);
3799
- range.collapse(true);
3800
- range.insertNode(node);
3801
- }
3802
- else if (this.document.caretRangeFromPoint)
3803
- {
3804
- range = this.document.caretRangeFromPoint(x, y);
3805
- range.insertNode(node);
3806
- }
3807
- else if (typeof document.body.createTextRange != "undefined")
3808
- {
3809
- range = this.document.body.createTextRange();
3810
- range.moveToPoint(x, y);
3811
- var endRange = range.duplicate();
3812
- endRange.moveToPoint(x, y);
3813
- range.setEndPoint("EndToEnd", endRange);
3814
- range.select();
3815
- }
3816
-
3817
- },
3818
3704
  insertAfterLastElement: function(element)
3819
3705
  {
3820
3706
  if (this.isEndOfElement())
3821
3707
  {
3822
-
3823
- if ($($.trim(this.$editor.html())).get(0) != $.trim(element)
3824
- && this.$editor.contents().last()[0] !== element) return false;
3708
+ if (this.$editor.contents().last()[0] !== element) return false;
3825
3709
 
3826
3710
  this.bufferSet();
3827
3711
 
@@ -3860,26 +3744,10 @@
3860
3744
  this.selectionStart(node);
3861
3745
  },
3862
3746
 
3863
- // PASTE
3864
- pasteClean: function(html)
3865
- {
3866
- html = this.callback('pasteBefore', false, html);
3867
-
3868
- if (this.opts.pastePlainText)
3869
- {
3870
- var tmp = this.document.createElement('div');
3871
-
3872
- html = html.replace(/<br>|<\/H[1-6]>|<\/p>|<\/div>/gi, '\n');
3873
-
3874
- tmp.innerHTML = html;
3875
- html = tmp.textContent || tmp.innerText;
3876
-
3877
- html = html.replace('\n', '<br>');
3878
- html = this.cleanParagraphy(html);
3879
-
3880
- this.pasteInsert(html);
3881
- return false;
3882
- }
3747
+ // PASTE
3748
+ pasteClean: function(html)
3749
+ {
3750
+ html = this.callback('pasteBefore', false, html);
3883
3751
 
3884
3752
  // clean up pre
3885
3753
  if (this.currentOrParentIs('PRE'))
@@ -3902,7 +3770,6 @@
3902
3770
 
3903
3771
  // remove google docs marker
3904
3772
  html = html.replace(/<b\sid="internal-source-marker(.*?)">([\w\W]*?)<\/b>/gi, "$2");
3905
- html = html.replace(/<b(.*?)id="docs-internal-guid(.*?)">([\w\W]*?)<\/b>/gi, "$3");
3906
3773
 
3907
3774
  // strip tags
3908
3775
  html = this.cleanStripTags(html);
@@ -3919,7 +3786,6 @@
3919
3786
  html = html.replace(/<object(.*?)>([\w\W]*?)<\/object>/gi, '[object$1]$2[/object]');
3920
3787
  html = html.replace(/<param(.*?)>/gi, '[param$1]');
3921
3788
  html = html.replace(/<img(.*?)style="(.*?)"(.*?)>/gi, '[img$1$3]');
3922
- html = html.replace(/<img(.*?)>/gi, '[img$1]');
3923
3789
 
3924
3790
  // remove classes
3925
3791
  html = html.replace(/ class="(.*?)"/gi, '');
@@ -3951,15 +3817,8 @@
3951
3817
  html = html.replace(/<\/p><\/div>/gi, '</p>');
3952
3818
  }
3953
3819
 
3954
- if (this.currentOrParentIs('LI'))
3955
- {
3956
- html = html.replace(/<p>([\w\W]*?)<\/p>/gi, '$1<br>');
3957
- }
3958
- else
3959
- {
3960
- html = this.cleanParagraphy(html);
3961
- }
3962
3820
 
3821
+ html = this.cleanParagraphy(html);
3963
3822
 
3964
3823
  // remove span
3965
3824
  html = html.replace(/<span(.*?)>([\w\W]*?)<\/span>/gi, '$2');
@@ -3985,28 +3844,9 @@
3985
3844
  // remove empty finally
3986
3845
  html = html.replace(/<[^\/>][^>][^img|param|source]*>(\s*|\t*|\n*|&nbsp;|<br>)<\/[^>]+>/gi, '');
3987
3846
 
3988
- // remove safari local images
3989
- html = html.replace(/<img src="webkit-fake-url\:\/\/(.*?)"(.*?)>/gi, '');
3990
-
3991
- // FF specific
3992
- this.pasteClipboardMozilla = false;
3847
+ // FF fix
3993
3848
  if (this.browser('mozilla'))
3994
3849
  {
3995
- if (this.opts.clipboardUpload)
3996
- {
3997
- var matches = html.match(/<img src="data:image(.*?)"(.*?)>/gi);
3998
- if (matches !== null)
3999
- {
4000
- this.pasteClipboardMozilla = matches;
4001
- for (k in matches)
4002
- {
4003
- var img = matches[k].replace('<img', '<img data-mozilla-paste-image="' + k + '" ');
4004
- html = html.replace(matches[k], img);
4005
- }
4006
- }
4007
- }
4008
-
4009
- // FF fix
4010
3850
  while (/<br>$/gi.test(html))
4011
3851
  {
4012
3852
  html = html.replace(/<br>$/gi, '');
@@ -4049,97 +3889,12 @@
4049
3889
  this.insertHtml(html);
4050
3890
 
4051
3891
  this.selectall = false;
4052
- setTimeout($.proxy(function()
4053
- {
4054
- rtePaste = false;
4055
-
4056
- // FF specific
4057
- if (this.browser('mozilla'))
4058
- {
4059
- this.$editor.find('p:empty').remove()
4060
- }
4061
- if (this.pasteClipboardMozilla !== false)
4062
- {
4063
- this.pasteClipboardUploadMozilla();
4064
- }
4065
-
4066
- }, this), 100);
3892
+ setTimeout(function() { rtePaste = false; }, 100);
4067
3893
 
4068
3894
  if (this.opts.autoresize) $(this.document.body).scrollTop(this.saveScroll);
4069
3895
  else this.$editor.scrollTop(this.saveScroll);
4070
3896
  },
4071
3897
 
4072
- pasteClipboardUploadMozilla: function()
4073
- {
4074
- var imgs = this.$editor.find('img[data-mozilla-paste-image]');
4075
- $.each(imgs, $.proxy(function(i,s)
4076
- {
4077
- var $s = $(s);
4078
- var arr = s.src.split(",");
4079
- var data = arr[1]; // raw base64
4080
- var contentType = arr[0].split(";")[0].split(":")[1];
4081
-
4082
- $.post(this.opts.clipboardUploadUrl, {
4083
- contentType: contentType,
4084
- data: data
4085
- },
4086
- $.proxy(function(data)
4087
- {
4088
- var json = $.parseJSON(data);
4089
- $s.attr('src', json.filelink);
4090
- $s.removeAttr('data-mozilla-paste-image');
4091
-
4092
- this.sync();
4093
-
4094
- // upload callback
4095
- this.callback('imageUpload', $s, json);
4096
-
4097
- }, this));
4098
-
4099
- }, this));
4100
- },
4101
- pasteClipboardUpload: function(e)
4102
- {
4103
- var result = e.target.result;
4104
- var arr = result.split(",");
4105
- var data = arr[1]; // raw base64
4106
- var contentType = arr[0].split(";")[0].split(":")[1];
4107
-
4108
- if (this.opts.clipboardUpload)
4109
- {
4110
- $.post(this.opts.clipboardUploadUrl, {
4111
- contentType: contentType,
4112
- data: data
4113
- },
4114
- $.proxy(function(data)
4115
- {
4116
- var json = $.parseJSON(data);
4117
-
4118
- var html = '<img src="' + json.filelink + '" id="clipboard-image-marker" />';
4119
- this.execCommand('inserthtml', html, false);
4120
-
4121
- var image = $(this.$editor.find('img#clipboard-image-marker'));
4122
-
4123
- if (image.length) image.removeAttr('id');
4124
- else image = false;
4125
-
4126
- this.sync();
4127
-
4128
- // upload callback
4129
- if (image)
4130
- {
4131
- this.callback('imageUpload', image, json);
4132
- }
4133
-
4134
-
4135
- }, this));
4136
- }
4137
- else
4138
- {
4139
- this.insertHtml('<img src="' + result + '" />');
4140
- }
4141
- },
4142
-
4143
3898
  // BUFFER
4144
3899
  bufferSet: function(html)
4145
3900
  {
@@ -4193,17 +3948,6 @@
4193
3948
  {
4194
3949
  this.observeImages();
4195
3950
  this.observeTables();
4196
-
4197
- if (this.opts.observeLinks) this.observeLinks();
4198
- },
4199
- observeLinks: function()
4200
- {
4201
- this.$editor.find('a').on('click', $.proxy(this.linkObserver, this));
4202
- this.$editor.on('click.redactor', $.proxy(function(e)
4203
- {
4204
- this.linkObserverTooltipClose(e);
4205
-
4206
- }, this));
4207
3951
  },
4208
3952
  observeTables: function()
4209
3953
  {
@@ -4220,62 +3964,6 @@
4220
3964
 
4221
3965
  }, this));
4222
3966
  },
4223
- linkObserver: function(e)
4224
- {
4225
- var $link = $(e.target);
4226
- var pos = $link.offset();
4227
- if (this.opts.iframe)
4228
- {
4229
- var posFrame = this.$frame.offset();
4230
- pos.top = posFrame.top + (pos.top - $(this.document).scrollTop());
4231
- pos.left += posFrame.left;
4232
- }
4233
-
4234
- var tooltip = $('<span class="redactor-link-tooltip"></span>');
4235
-
4236
- var href = $link.attr('href');
4237
- if (href.length > 24) href = href.substring(0,24) + '...';
4238
-
4239
- var aLink = $('<a href="' + $link.attr('href') + '" target="_blank">' + href + '</a>').on('click', $.proxy(function(e)
4240
- {
4241
- this.linkObserverTooltipClose(false);
4242
- }, this));
4243
-
4244
- var aEdit = $('<a href="#">' + this.opts.curLang.edit + '</a>').on('click', $.proxy(function(e)
4245
- {
4246
- e.preventDefault();
4247
- this.linkShow();
4248
- this.linkObserverTooltipClose(false);
4249
-
4250
- }, this));
4251
-
4252
- var aUnlink = $('<a href="#">' + this.opts.curLang.unlink + '</a>').on('click', $.proxy(function(e)
4253
- {
4254
- e.preventDefault();
4255
- this.execCommand('unlink');
4256
- this.linkObserverTooltipClose(false);
4257
-
4258
- }, this));
4259
-
4260
-
4261
- tooltip.append(aLink);
4262
- tooltip.append(' | ');
4263
- tooltip.append(aEdit);
4264
- tooltip.append(' | ');
4265
- tooltip.append(aUnlink);
4266
- tooltip.css({
4267
- top: (pos.top + 20) + 'px',
4268
- left: pos.left + 'px'
4269
- });
4270
-
4271
- $('.redactor-link-tooltip').remove();
4272
- $('body').append(tooltip);
4273
- },
4274
- linkObserverTooltipClose: function(e)
4275
- {
4276
- if (e !== false && e.target.tagName == 'A') return false;
4277
- $('.redactor-link-tooltip').remove();
4278
- },
4279
3967
 
4280
3968
 
4281
3969
  // SELECTION
@@ -4375,7 +4063,7 @@
4375
4063
  {
4376
4064
  var caretOffset = 0;
4377
4065
 
4378
- var range = this.getRange();
4066
+ var range = this.getSelection().getRangeAt(0);
4379
4067
  var preCaretRange = range.cloneRange();
4380
4068
  preCaretRange.selectNodeContents(element);
4381
4069
  preCaretRange.setEnd(range.endContainer, range.endOffset);
@@ -4503,11 +4191,7 @@
4503
4191
  var node1 = this.$editor.find('span#selection-marker-1');
4504
4192
  var node2 = this.$editor.find('span#selection-marker-2');
4505
4193
 
4506
- if (this.browser('mozilla'))
4507
- {
4508
- this.$editor.focus();
4509
- }
4510
- else if (!this.isFocused())
4194
+ if (!this.isFocused())
4511
4195
  {
4512
4196
  this.$editor.focus();
4513
4197
  }
@@ -4539,7 +4223,7 @@
4539
4223
  {
4540
4224
  $.each(this.$editor.find('span.redactor-selection-marker'), function()
4541
4225
  {
4542
- var html = $.trim($(this).html().replace(/[^\u0000-\u1C7F]/g, ''));
4226
+ var html = $.trim($(this).html().replace(/[^\u0000-~]/g, ''));
4543
4227
  if (html == '')
4544
4228
  {
4545
4229
  $(this).remove();
@@ -4843,13 +4527,13 @@
4843
4527
  this.selectionRestore();
4844
4528
 
4845
4529
  var current = this.getBlock() || this.getCurrent();
4846
- if (current && current.tagName != 'BODY')
4530
+ if (current)
4847
4531
  {
4848
4532
  $(current).after(html)
4849
4533
  }
4850
4534
  else
4851
4535
  {
4852
- this.insertHtmlAdvanced(html, false);
4536
+ this.insertHtmlAdvanced(html);
4853
4537
 
4854
4538
  }
4855
4539
 
@@ -4859,7 +4543,6 @@
4859
4543
  this.tableObserver(table);
4860
4544
  this.buttonActiveObserver();
4861
4545
 
4862
- table.find('span#selection-marker-1').remove();
4863
4546
  table.removeAttr('id');
4864
4547
 
4865
4548
  this.sync();
@@ -5031,11 +4714,13 @@
5031
4714
  this.selectionRestore();
5032
4715
 
5033
4716
  var current = this.getBlock() || this.getCurrent();
4717
+ if (current)
4718
+ {
4719
+ $(current).after(data)
4720
+ this.sync();
4721
+ }
4722
+ else this.insertHtmlAdvanced(data);
5034
4723
 
5035
- if (current) $(current).after(data)
5036
- else this.insertHtmlAdvanced(data, false);
5037
-
5038
- this.sync();
5039
4724
  this.modalClose();
5040
4725
  },
5041
4726
 
@@ -5073,13 +4758,6 @@
5073
4758
  var thref = self.location.href.replace(/\/$/i, '');
5074
4759
  var turl = url.replace(thref, '');
5075
4760
 
5076
- // remove host from href
5077
- if (this.opts.linkProtocol === false)
5078
- {
5079
- var re = new RegExp('^(http|ftp|https)://' + self.location.host, 'i');
5080
- turl = turl.replace(re, '');
5081
- }
5082
-
5083
4761
  var tabs = $('#redactor_tabs').find('a');
5084
4762
 
5085
4763
  if (this.opts.linkEmail === false) tabs.eq(1).remove();
@@ -5166,7 +4844,6 @@
5166
4844
  text = $('#redactor_link_anchor_text').val();
5167
4845
  }
5168
4846
 
5169
- text = text.replace(/<|>/g, '');
5170
4847
  this.linkInsert('<a href="' + link + '"' + target + '>' + text + '</a>', $.trim(text), link, targetBlank);
5171
4848
 
5172
4849
  },
@@ -5425,10 +5102,10 @@
5425
5102
  this.modalInit(this.opts.curLang.image, this.opts.modal_image, 610, callback);
5426
5103
 
5427
5104
  },
5428
- imageEdit: function(image)
5105
+ imageEdit: function(e)
5429
5106
  {
5430
- var $el = image;
5431
- var parent = $el.parent().parent();
5107
+ var $el = $(e.target);
5108
+ var parent = $el.parent();
5432
5109
 
5433
5110
  var callback = $.proxy(function()
5434
5111
  {
@@ -5438,12 +5115,7 @@
5438
5115
 
5439
5116
  if ($(parent).get(0).tagName === 'A')
5440
5117
  {
5441
- $('#redactor_file_link').val($(parent).attr('href'));
5442
-
5443
- if ($(parent).attr('target') == '_blank')
5444
- {
5445
- $('#redactor_link_blank').prop('checked', true);
5446
- }
5118
+ $('#redactor_file_link').val($( parent ).attr('href'));
5447
5119
  }
5448
5120
 
5449
5121
  $('#redactor_image_delete_btn').click($.proxy(function()
@@ -5482,67 +5154,43 @@
5482
5154
  },
5483
5155
  imageSave: function(el)
5484
5156
  {
5485
- var $el = $(el);
5486
- var parent = $el.parent();
5157
+ var parent = $(el).parent();
5487
5158
 
5488
- $el.attr('alt', $('#redactor_file_alt').val());
5159
+ $(el).attr('alt', $('#redactor_file_alt').val());
5489
5160
 
5490
5161
  var floating = $('#redactor_form_image_align').val();
5491
5162
 
5492
5163
  if (floating === 'left')
5493
5164
  {
5494
- $el.css({ 'float': 'left', 'margin': '0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + ' 0' });
5165
+ $(el).css({ 'float': 'left', 'margin': '0 10px 10px 0' });
5495
5166
  }
5496
5167
  else if (floating === 'right')
5497
5168
  {
5498
- $el.css({ 'float': 'right', 'margin': '0 0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + '' });
5169
+ $(el).css({ 'float': 'right', 'margin': '0 0 10px 10px' });
5499
5170
  }
5500
5171
  else
5501
5172
  {
5502
- var imageBox = $el.closest('#redactor-image-box');
5503
- if (imageBox.size() != 0) imageBox.css({ 'float': '', 'margin': '' });
5504
- $el.css({ 'float': '', 'margin': '' });
5173
+ $(el).css({ 'float': 'none', 'margin': '0' });
5505
5174
  }
5506
5175
 
5507
5176
  // as link
5508
5177
  var link = $.trim($('#redactor_file_link').val());
5509
5178
  if (link !== '')
5510
5179
  {
5511
- var target = false;
5512
- if ($('#redactor_link_blank').prop('checked'))
5513
- {
5514
- target = true;
5515
- }
5516
-
5517
- if (parent.get(0).tagName !== 'A')
5180
+ if ($(parent).get(0).tagName !== 'A')
5518
5181
  {
5519
- var a = $('<a href="' + link + '">' + this.outerHtml(el) + '</a>');
5520
-
5521
- if (target)
5522
- {
5523
- a.attr('target', '_blank');
5524
- }
5525
-
5526
- $el.replaceWith(a);
5182
+ $(el).replaceWith('<a href="' + link + '">' + this.outerHtml(el) + '</a>');
5527
5183
  }
5528
5184
  else
5529
5185
  {
5530
- parent.attr('href', link);
5531
- if (target)
5532
- {
5533
- parent.attr('target', '_blank');
5534
- }
5535
- else
5536
- {
5537
- parent.removeAttr('target');
5538
- }
5186
+ $(parent).attr('href', link);
5539
5187
  }
5540
5188
  }
5541
5189
  else
5542
5190
  {
5543
- if (parent.get(0).tagName === 'A')
5191
+ if ($(parent).get(0).tagName === 'A')
5544
5192
  {
5545
- parent.replaceWith(this.outerHtml(el));
5193
+ $(parent).replaceWith(this.outerHtml(el));
5546
5194
  }
5547
5195
  }
5548
5196
 
@@ -5551,224 +5199,76 @@
5551
5199
  this.sync();
5552
5200
 
5553
5201
  },
5554
- imageResizeHide: function(e)
5202
+ imageResize: function(image)
5555
5203
  {
5556
- if (e !== false && $(e.target).parent().size() != 0 && $(e.target).parent()[0].id === 'redactor-image-box')
5557
- {
5558
- return false;
5559
- }
5560
-
5561
- var imageBox = this.$editor.find('#redactor-image-box');
5562
- if (imageBox.size() == 0)
5563
- {
5564
- return false;
5565
- }
5204
+ var $image = $(image),
5205
+ clicked = false,
5206
+ clicker = false,
5207
+ start_x,
5208
+ start_y,
5209
+ ratio = $image.width() / $image.height(),
5210
+ min_w = 10,
5211
+ min_h = 10;
5566
5212
 
5567
- this.$editor.find('#redactor-image-editter, #redactor-image-resizer').remove();
5213
+ $image.off('hover mousedown mouseup click mousemove');
5568
5214
 
5569
- var margin = imageBox.css('margin');
5570
- if (margin != '0px')
5215
+ $image.hover(function()
5571
5216
  {
5572
- imageBox.find('img').css('margin', margin);
5573
- imageBox.css('margin', '');
5574
- }
5575
-
5576
- imageBox.find('img').css('opacity', '');
5577
- imageBox.replaceWith(function()
5217
+ $image.css('cursor', 'nw-resize');
5218
+ },
5219
+ function()
5578
5220
  {
5579
- return $(this).contents();
5221
+ $image.css('cursor', '');
5222
+ clicked = false;
5580
5223
  });
5581
5224
 
5582
- $(document).off('click.redactor-image-resize-hide');
5583
- this.$editor.off('click.redactor-image-resize-hide');
5584
- this.$editor.off('keydown.redactor-image-delete');
5225
+ $image.mousedown(function(e)
5226
+ {
5227
+ e.preventDefault();
5585
5228
 
5586
- this.sync()
5229
+ ratio = $image.width() / $image.height();
5587
5230
 
5588
- },
5589
- imageResize: function(image)
5590
- {
5591
- var $image = $(image);
5231
+ clicked = true;
5232
+ clicker = true;
5592
5233
 
5593
- $image.on('mousedown', $.proxy(function()
5594
- {
5595
- this.imageResizeHide(false);
5596
- }, this));
5234
+ start_x = Math.round(e.pageX - $image.eq( 0 ).offset().left);
5235
+ start_y = Math.round(e.pageY - $image.eq( 0 ).offset().top);
5236
+ });
5597
5237
 
5598
- $image.on('dragstart', $.proxy(function()
5238
+ $image.mouseup( $.proxy(function(e)
5599
5239
  {
5600
- this.$editor.on('drop.redactor-image-inside-drop', $.proxy(function()
5601
- {
5602
- setTimeout($.proxy(function()
5603
- {
5604
- this.observeImages();
5605
- this.$editor.off('drop.redactor-image-inside-drop');
5606
- this.sync();
5607
-
5608
- }, this), 1);
5240
+ clicked = false;
5241
+ $image.css('cursor', '');
5242
+ this.sync();
5609
5243
 
5610
- },this));
5611
5244
  }, this));
5612
5245
 
5613
- $image.on('click', $.proxy(function(e)
5246
+ $image.click( $.proxy(function(e)
5614
5247
  {
5615
- if (this.$editor.find('#redactor-image-box').size() != 0)
5616
- {
5617
- return false;
5618
- }
5619
-
5620
- var clicked = false,
5621
- start_x,
5622
- start_y,
5623
- ratio = $image.width() / $image.height(),
5624
- min_w = 20,
5625
- min_h = 10;
5626
-
5627
- var imageResizer = this.imageResizeControls($image);
5628
-
5629
- // resize
5630
- var isResizing = false;
5631
- imageResizer.on('mousedown', function(e)
5632
- {
5633
- isResizing = true;
5634
- e.preventDefault();
5635
-
5636
- ratio = $image.width() / $image.height();
5637
-
5638
- start_x = Math.round(e.pageX - $image.eq(0).offset().left);
5639
- start_y = Math.round(e.pageY - $image.eq(0).offset().top);
5640
-
5641
- });
5642
-
5643
- $(this.document.body).on('mousemove', $.proxy(function(e)
5644
- {
5645
- if (isResizing)
5646
- {
5647
- var mouse_x = Math.round(e.pageX - $image.eq(0).offset().left) - start_x;
5648
- var mouse_y = Math.round(e.pageY - $image.eq(0).offset().top) - start_y;
5649
-
5650
- var div_h = $image.height();
5651
-
5652
- var new_h = parseInt(div_h, 10) + mouse_y;
5653
- var new_w = Math.round(new_h * ratio);
5654
-
5655
- if (new_w > min_w)
5656
- {
5657
- $image.width(new_w);
5658
-
5659
- if (new_w < 100)
5660
- {
5661
- this.imageEditter.css({
5662
- marginTop: '-7px',
5663
- marginLeft: '-13px',
5664
- fontSize: '9px',
5665
- padding: '3px 5px'
5666
- });
5667
- }
5668
- else
5669
- {
5670
- this.imageEditter.css({
5671
- marginTop: '-11px',
5672
- marginLeft: '-18px',
5673
- fontSize: '11px',
5674
- padding: '7px 10px'
5675
- });
5676
- }
5677
- }
5678
-
5679
- start_x = Math.round(e.pageX - $image.eq(0).offset().left);
5680
- start_y = Math.round(e.pageY - $image.eq(0).offset().top);
5681
-
5682
- this.sync()
5683
- }
5684
- }, this)).on('mouseup', function()
5685
- {
5686
- isResizing = false;
5687
- });
5248
+ if (clicker) this.imageEdit(e);
5688
5249
 
5250
+ }, this));
5689
5251
 
5690
- this.$editor.on('keydown.redactor-image-delete', $.proxy(function(e)
5252
+ $image.mousemove(function(e)
5253
+ {
5254
+ if (clicked)
5691
5255
  {
5692
- var key = e.which;
5256
+ clicker = false;
5693
5257
 
5694
- if (this.keyCode.BACKSPACE == key || this.keyCode.DELETE == key)
5695
- {
5696
- this.imageResizeHide(false);
5697
- this.imageRemove($image);
5698
- }
5258
+ var mouse_x = Math.round(e.pageX - $(this).eq(0).offset().left) - start_x;
5259
+ var mouse_y = Math.round(e.pageY - $(this).eq(0).offset().top) - start_y;
5699
5260
 
5700
- }, this));
5261
+ var div_h = $image.height();
5701
5262
 
5702
- $(document).on('click.redactor-image-resize-hide', $.proxy(this.imageResizeHide, this));
5703
- this.$editor.on('click.redactor-image-resize-hide', $.proxy(this.imageResizeHide, this));
5263
+ var new_h = parseInt(div_h, 10) + mouse_y;
5264
+ var new_w = Math.round(new_h * ratio);
5704
5265
 
5266
+ if (new_w > min_w) $image.width(new_w);
5705
5267
 
5706
- }, this));
5707
- },
5708
- imageResizeControls: function($image)
5709
- {
5710
- var imageBox = $('<span id="redactor-image-box" data-redactor="verified">');
5711
- imageBox.css({
5712
- position: 'relative',
5713
- display: 'inline-block',
5714
- lineHeight: 0,
5715
- outline: '1px dashed rgba(0, 0, 0, .6)',
5716
- 'float': $image.css('float')
5717
- });
5718
- imageBox.attr('contenteditable', false);
5719
-
5720
- var margin = $image.css('margin');
5721
- if (margin != '0px')
5722
- {
5723
- imageBox.css('margin', margin);
5724
- $image.css('margin', '');
5725
- }
5726
-
5727
- $image.css('opacity', .5).after(imageBox);
5728
-
5729
- // editter
5730
- this.imageEditter = $('<span id="redactor-image-editter" data-redactor="verified">' + this.opts.curLang.edit + '</span>');
5731
- this.imageEditter.css({
5732
- position: 'absolute',
5733
- zIndex: 2,
5734
- top: '50%',
5735
- left: '50%',
5736
- marginTop: '-11px',
5737
- marginLeft: '-18px',
5738
- lineHeight: 1,
5739
- backgroundColor: '#000',
5740
- color: '#fff',
5741
- fontSize: '11px',
5742
- padding: '7px 10px',
5743
- cursor: 'pointer'
5744
- });
5745
- this.imageEditter.attr('contenteditable', false);
5746
- this.imageEditter.on('click', $.proxy(function()
5747
- {
5748
- this.imageEdit($image);
5749
- }, this));
5750
- imageBox.append(this.imageEditter);
5751
-
5752
- // resizer
5753
- var imageResizer = $('<span id="redactor-image-resizer" data-redactor="verified"></span>');
5754
- imageResizer.css({
5755
- position: 'absolute',
5756
- zIndex: 2,
5757
- lineHeight: 1,
5758
- cursor: 'nw-resize',
5759
- bottom: '-4px',
5760
- right: '-5px',
5761
- border: '1px solid #fff',
5762
- backgroundColor: '#000',
5763
- width: '8px',
5764
- height: '8px'
5268
+ start_x = Math.round(e.pageX - $(this).eq(0).offset().left);
5269
+ start_y = Math.round(e.pageY - $(this).eq(0).offset().top);
5270
+ }
5765
5271
  });
5766
- imageResizer.attr('contenteditable', false);
5767
- imageBox.append(imageResizer);
5768
-
5769
- imageBox.append($image);
5770
-
5771
- return imageResizer;
5772
5272
  },
5773
5273
  imageThumbClick: function(e)
5774
5274
  {
@@ -5855,7 +5355,6 @@
5855
5355
  + '<input id="redactor_file_alt" class="redactor_input" />'
5856
5356
  + '<label>' + this.opts.curLang.link + '</label>'
5857
5357
  + '<input id="redactor_file_link" class="redactor_input" />'
5858
- + '<label><input type="checkbox" id="redactor_link_blank"> ' + this.opts.curLang.link_new_tab + '</label>'
5859
5358
  + '<label>' + this.opts.curLang.image_position + '</label>'
5860
5359
  + '<select id="redactor_form_image_align">'
5861
5360
  + '<option value="none">' + this.opts.curLang.none + '</option>'
@@ -5864,8 +5363,8 @@
5864
5363
  + '</select>'
5865
5364
  + '</section>'
5866
5365
  + '<footer>'
5867
- + '<button id="redactor_image_delete_btn" class="redactor_modal_btn">' + this.opts.curLang._delete + '</button>&nbsp;&nbsp;&nbsp;'
5868
- + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>'
5366
+ + '<a href="#" id="redactor_image_delete_btn" class="redactor_modal_btn">' + this.opts.curLang._delete + '</a>&nbsp;&nbsp;&nbsp;'
5367
+ + '<a href="#" class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</a>'
5869
5368
  + '<input type="button" name="save" class="redactor_modal_btn" id="redactorSaveBtn" value="' + this.opts.curLang.save + '" />'
5870
5369
  + '</footer>',
5871
5370
 
@@ -5893,7 +5392,7 @@
5893
5392
  + '</div>'
5894
5393
  + '</section>'
5895
5394
  + '<footer>'
5896
- + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>'
5395
+ + '<a href="#" class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</a>'
5897
5396
  + '<input type="button" name="upload" class="redactor_modal_btn" id="redactor_upload_btn" value="' + this.opts.curLang.insert + '" />'
5898
5397
  + '</footer>',
5899
5398
 
@@ -5928,7 +5427,7 @@
5928
5427
  + '</form>'
5929
5428
  + '</section>'
5930
5429
  + '<footer>'
5931
- + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>'
5430
+ + '<a href="#" class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</a>'
5932
5431
  + '<input type="button" class="redactor_modal_btn" id="redactor_insert_link_btn" value="' + this.opts.curLang.insert + '" />'
5933
5432
  + '</footer>',
5934
5433
 
@@ -5940,7 +5439,7 @@
5940
5439
  + '<input type="text" size="5" value="3" id="redactor_table_columns" />'
5941
5440
  + '</section>'
5942
5441
  + '<footer>'
5943
- + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>'
5442
+ + '<a href="#" class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</a>'
5944
5443
  + '<input type="button" name="upload" class="redactor_modal_btn" id="redactor_insert_table_btn" value="' + this.opts.curLang.insert + '" />'
5945
5444
  + '</footer>',
5946
5445
 
@@ -5952,7 +5451,7 @@
5952
5451
  + '</form>'
5953
5452
  + '</section>'
5954
5453
  + '<footer>'
5955
- + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>'
5454
+ + '<a href="javascript:void(null);" class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</a>'
5956
5455
  + '<input type="button" class="redactor_modal_btn" id="redactor_insert_video_btn" value="' + this.opts.curLang.insert + '" />'
5957
5456
  + '</footer>'
5958
5457
 
@@ -6050,9 +5549,6 @@
6050
5549
 
6051
5550
  $redactorModal.find('.redactor_btn_modal_close').on('click', $.proxy(this.modalClose, this));
6052
5551
 
6053
- // save scroll
6054
- if (this.opts.autoresize === true) this.saveModalScroll = this.document.body.scrollTop;
6055
-
6056
5552
  if (this.isMobile() === false)
6057
5553
  {
6058
5554
  $redactorModal.css({
@@ -6094,7 +5590,7 @@
6094
5590
  minHeight: 'auto',
6095
5591
  marginTop: '-' + (height + 10) / 2 + 'px'
6096
5592
  });
6097
- }, 10);
5593
+ }, 20 );
6098
5594
  }
6099
5595
 
6100
5596
  },
@@ -6123,9 +5619,6 @@
6123
5619
 
6124
5620
  this.selectionRestore();
6125
5621
 
6126
- // restore scroll
6127
- if (this.opts.autoresize && this.saveModalScroll) $(this.document.body).scrollTop(this.saveModalScroll);
6128
-
6129
5622
  }, this));
6130
5623
 
6131
5624
 
@@ -6377,7 +5870,7 @@
6377
5870
  }
6378
5871
 
6379
5872
  var oldElement = this.uploadOptions.input;
6380
- var newElement = $(oldElement).clone();
5873
+ var newElement = $( oldElement ).clone();
6381
5874
 
6382
5875
  $(oldElement).attr('id', fileId).before(newElement).appendTo(this.form);
6383
5876
 
@@ -6486,36 +5979,28 @@
6486
5979
 
6487
5980
  this.dropareabox.removeClass('hover').addClass('drop');
6488
5981
 
6489
- this.dragUploadAjax(this.draguploadOptions.url, e.dataTransfer.files[0], false);
5982
+ //this.handleFileSelect(e);
5983
+ this.draguploadUpload(e.dataTransfer.files[0]);
6490
5984
 
6491
5985
  }, this );
6492
5986
  },
6493
- dragUploadAjax: function(url, file, directupload, progress, e)
5987
+ draguploadUpload: function(file)
6494
5988
  {
5989
+ var xhr = jQuery.ajaxSettings.xhr();
6495
5990
 
6496
-
6497
- if (!directupload)
5991
+ if (xhr.upload)
6498
5992
  {
6499
- var xhr = $.ajaxSettings.xhr();
6500
- if (xhr.upload)
6501
- {
6502
- xhr.upload.addEventListener('progress', $.proxy(this.uploadProgress, this), false);
6503
- }
6504
-
6505
- $.ajaxSetup({
6506
- xhr: function () { return xhr; }
6507
- });
5993
+ xhr.upload.addEventListener('progress', $.proxy(this.uploadProgress, this), false);
6508
5994
  }
6509
5995
 
6510
- var fd = new FormData();
5996
+ var provider = function () { return xhr; };
6511
5997
 
6512
- // append file data
6513
- fd.append('file', file);
5998
+ var fd = new FormData();
6514
5999
 
6515
6000
  // append hidden fields
6516
- if (this.opts.uploadFields !== false && typeof this.opts.uploadFields === 'object')
6001
+ if (this.draguploadOptions.uploadFields !== false && typeof this.draguploadOptions.uploadFields === 'object')
6517
6002
  {
6518
- $.each(this.opts.uploadFields, $.proxy(function(k, v)
6003
+ $.each(this.draguploadOptions.uploadFields, $.proxy(function(k, v)
6519
6004
  {
6520
6005
  if (v != null && v.toString().indexOf('#') === 0) v = $(v).val();
6521
6006
  fd.append(k, v);
@@ -6523,10 +6008,14 @@
6523
6008
  }, this));
6524
6009
  }
6525
6010
 
6011
+ // append file data
6012
+ fd.append('file', file);
6013
+
6526
6014
  $.ajax({
6527
- url: url,
6015
+ url: this.draguploadOptions.url,
6528
6016
  dataType: 'html',
6529
6017
  data: fd,
6018
+ xhr: provider,
6530
6019
  cache: false,
6531
6020
  contentType: false,
6532
6021
  processData: false,
@@ -6538,46 +6027,19 @@
6538
6027
 
6539
6028
  var json = $.parseJSON(data);
6540
6029
 
6541
- if (directupload)
6030
+ if (typeof json.error == 'undefined')
6542
6031
  {
6543
- progress.fadeOut('slow', function()
6544
- {
6545
- $(this).remove();
6546
- });
6547
-
6548
- var $img = $('<img>');
6549
- $img.attr('src', json.filelink).attr('id', 'drag-image-marker');
6550
-
6551
- this.insertNodeToCaretPositionFromPoint(e, $img[0]);
6552
-
6553
- var image = $(this.$editor.find('img#drag-image-marker'));
6554
- if (image.length) image.removeAttr('id');
6555
- else image = false;
6556
-
6557
- this.sync();
6558
- this.observeImages();
6559
-
6560
- // upload callback
6561
- if (image) this.callback('imageUpload', image, json);
6562
-
6563
- // error callback
6564
- if (typeof json.error !== 'undefined') this.callback('imageUploadError', json);
6032
+ this.draguploadOptions.success(json);
6565
6033
  }
6566
6034
  else
6567
6035
  {
6568
- if (typeof json.error == 'undefined')
6569
- {
6570
- this.draguploadOptions.success(json);
6571
- }
6572
- else
6573
- {
6574
- this.draguploadOptions.error(this, json);
6575
- this.draguploadOptions.success(false);
6576
- }
6036
+ this.draguploadOptions.error(this, json);
6037
+ this.draguploadOptions.success(false);
6577
6038
  }
6578
6039
 
6579
6040
  }, this)
6580
6041
  });
6042
+
6581
6043
  },
6582
6044
  draguploadOndrag: function()
6583
6045
  {
@@ -6618,8 +6080,7 @@
6618
6080
  {
6619
6081
  html = html.replace(/&#x200b;|<br>|<br\/>|&nbsp;/gi, '');
6620
6082
  html = html.replace(/\s/g, '');
6621
- html = html.replace(/^<p>[^\W\w\D\d]*?<\/p>$/i, '');
6622
-
6083
+ html = html.replace(/^<p>[^\w\d]*?<\/p>$/i, '');
6623
6084
 
6624
6085
  return html == '';
6625
6086
  },
@@ -6685,7 +6146,6 @@
6685
6146
  var text = $.trim($(current).text()).replace(/\n\r\n/g, '');
6686
6147
 
6687
6148
  var len = text.length;
6688
-
6689
6149
  if (offset == len) return true;
6690
6150
  else return false;
6691
6151
  },
@@ -6724,13 +6184,10 @@
6724
6184
  Redactor.prototype.init.prototype = Redactor.prototype;
6725
6185
 
6726
6186
  // LINKIFY
6727
- $.Redactor.fn.formatLinkify = function(protocol, convertLinks, convertImageLinks, convertVideoLinks)
6187
+ $.Redactor.fn.formatLinkify = function(protocol)
6728
6188
  {
6729
6189
  var url1 = /(^|&lt;|\s)(www\..+?\..+?)(\s|&gt;|$)/g,
6730
- url2 = /(^|&lt;|\s)(((https?|ftp):\/\/|mailto:).+?)(\s|&gt;|$)/g,
6731
- urlImage = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif))/gi,
6732
- urlYoutube = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/,
6733
- urlVimeo = /http:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/;
6190
+ url2 = /(^|&lt;|\s)(((https?|ftp):\/\/|mailto:).+?)(\s|&gt;|$)/g;
6734
6191
 
6735
6192
  var childNodes = (this.$editor ? this.$editor.get(0) : this).childNodes, i = childNodes.length;
6736
6193
  while (i--)
@@ -6739,55 +6196,23 @@
6739
6196
  if (n.nodeType === 3)
6740
6197
  {
6741
6198
  var html = n.nodeValue;
6742
-
6743
- // youtube & vimeo
6744
- if (convertVideoLinks && html)
6199
+ if (html && (html.match(url1) || html.match(url2)))
6745
6200
  {
6746
- var iframeStart = '<iframe width="500" height="281" src="',
6747
- iframeEnd = '" frameborder="0" allowfullscreen></iframe>';
6748
-
6749
- if (html.match(urlYoutube))
6750
- {
6751
- html = html.replace(urlYoutube, iframeStart + '//www.youtube.com/embed/$2' + iframeEnd);
6752
- $(n).after(html).remove();
6753
- }
6754
- else if (html.match(urlVimeo))
6755
- {
6756
- html = html.replace(urlVimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd);
6757
- $(n).after(html).remove();
6758
- }
6759
- }
6760
-
6761
- // image
6762
- if (convertImageLinks && html && html.match(urlImage))
6763
- {
6764
- html = html.replace(urlImage, '<img src="$1">');
6765
-
6766
- $(n).after(html).remove();
6767
- }
6768
-
6769
- // link
6770
- if (convertLinks && html && (html.match(url1) || html.match(url2)))
6771
- {
6772
- var href = (html.match(url1) || html.match(url2));
6773
- href = href[0];
6774
- if (href.length > 50) href = href.substring(0, 50) + '...';
6775
-
6776
6201
  html = html.replace(/&/g, '&amp;')
6777
6202
  .replace(/</g, '&lt;')
6778
6203
  .replace(/>/g, '&gt;')
6779
- .replace(url1, '$1<a href="' + protocol + '$2">' + href + '</a>$3')
6780
- .replace(url2, '$1<a href="$2">' + href + '</a>$5');
6781
-
6204
+ .replace(url1, '$1<a href="' + protocol + '$2">$2</a>$3')
6205
+ .replace(url2, '$1<a href="$2">$2</a>$5');
6782
6206
 
6783
6207
  $(n).after(html).remove();
6784
6208
  }
6785
6209
  }
6786
6210
  else if (n.nodeType === 1 && !/^(a|button|textarea)$/i.test(n.tagName))
6787
6211
  {
6788
- $.Redactor.fn.formatLinkify.call(n, protocol, convertLinks, convertImageLinks, convertVideoLinks);
6212
+ $.Redactor.fn.formatLinkify.call(n, protocol);
6789
6213
  }
6790
6214
  }
6791
6215
  };
6792
6216
 
6217
+
6793
6218
  })(jQuery);