redactor-rails 0.3.7 → 0.4

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