simditor 2.2.4 → 2.3.0

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
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87642817d1e352fd4361902f136770392a1f26b5
4
- data.tar.gz: db226516ec3ed5884e0cf4d9e9c548c3a821cf58
3
+ metadata.gz: 9e33c8a152c1ce8e7848a79dea866dc97e8a0720
4
+ data.tar.gz: 145e99e3c36d6595e9bffbcf04476024315bdadf
5
5
  SHA512:
6
- metadata.gz: 96314d217cf800af6c5f12d4bc26713ff067a8aac4bcc7302812a9ec5129d397c1474fe4af8cfdb1c23376989f8c16ef2ec96b82f2d8e0ab3f273aa2cd561552
7
- data.tar.gz: 9e60e8c0732f9ea65220c7ceb9772ba4dacf0653b90915601968624f7f8cef2bf332e66da1fbeba59575852c4169e47cee576923ac1a4d1817e19ceb533bd513
6
+ metadata.gz: bffdd4d399f8630ab1a43781145e762cf98412d18626b11ca85c74b48af5e5723617cc22b2b6651536355341dd5141465bbb52cc505ed6f36b54155cccc52af6
7
+ data.tar.gz: 4d48fc3bf0f9dc2c583cc77bb2a8321634faa1444cfe2e0b36d4e3ea7b42e08f291bcddc0e4196466e558c4e7a579adfc11ad45139daa4eb72fdfe5830022291
@@ -1,5 +1,5 @@
1
1
  module Simditor
2
2
  module Version
3
- EDITOR = "2.2.4"
3
+ EDITOR = "2.3.0"
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * Simditor v2.2.3
2
+ * Simditor v2.3.0
3
3
  * http://simditor.tower.im/
4
- * 2015-08-22
4
+ * 2015-10-08
5
5
  */
6
6
  (function (root, factory) {
7
7
  if (typeof define === 'function' && define.amd) {
@@ -19,7 +19,7 @@
19
19
  }
20
20
  }(this, function ($, SimpleModule, simpleHotkeys, simpleUploader) {
21
21
 
22
- var AlignmentButton, BlockquoteButton, BoldButton, Button, CodeButton, CodePopover, ColorButton, Formatter, HrButton, ImageButton, ImagePopover, IndentButton, Indentation, InputManager, ItalicButton, Keystroke, LinkButton, LinkPopover, ListButton, OrderListButton, OutdentButton, Popover, Selection, Simditor, StrikethroughButton, TableButton, TitleButton, Toolbar, UnderlineButton, UndoManager, UnorderListButton, Util,
22
+ var AlignmentButton, BlockquoteButton, BoldButton, Button, Clipboard, CodeButton, CodePopover, ColorButton, Formatter, HrButton, ImageButton, ImagePopover, IndentButton, Indentation, InputManager, ItalicButton, Keystroke, LinkButton, LinkPopover, ListButton, OrderListButton, OutdentButton, Popover, Selection, Simditor, StrikethroughButton, TableButton, TitleButton, Toolbar, UnderlineButton, UndoManager, UnorderListButton, Util,
23
23
  extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
24
24
  hasProp = {}.hasOwnProperty,
25
25
  indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
@@ -472,7 +472,7 @@ Formatter = (function(superClass) {
472
472
 
473
473
  Formatter.prototype._init = function() {
474
474
  this.editor = this._module;
475
- this._allowedTags = $.merge(['br', 'span', 'a', 'img', 'b', 'strong', 'i', 'u', 'font', 'p', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'h1', 'h2', 'h3', 'h4', 'hr'], this.opts.allowedTags);
475
+ this._allowedTags = $.merge(['br', 'span', 'a', 'img', 'b', 'strong', 'i', 'strike', 'u', 'font', 'p', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'h1', 'h2', 'h3', 'h4', 'hr'], this.opts.allowedTags);
476
476
  this._allowedAttributes = $.extend({
477
477
  img: ['src', 'alt', 'width', 'height', 'data-non-image'],
478
478
  a: ['href', 'target'],
@@ -481,6 +481,11 @@ Formatter = (function(superClass) {
481
481
  }, this.opts.allowedAttributes);
482
482
  this._allowedStyles = $.extend({
483
483
  span: ['color'],
484
+ b: ['color'],
485
+ i: ['color'],
486
+ strong: ['color'],
487
+ strike: ['color'],
488
+ u: ['color'],
484
489
  p: ['margin-left', 'text-align'],
485
490
  h1: ['margin-left', 'text-align'],
486
491
  h2: ['margin-left', 'text-align'],
@@ -758,16 +763,12 @@ InputManager = (function(superClass) {
758
763
 
759
764
  InputManager.pluginName = 'InputManager';
760
765
 
761
- InputManager.prototype.opts = {
762
- pasteImage: false
763
- };
764
-
765
766
  InputManager.prototype._modifierKeys = [16, 17, 18, 91, 93, 224];
766
767
 
767
768
  InputManager.prototype._arrowKeys = [37, 38, 39, 40];
768
769
 
769
770
  InputManager.prototype._init = function() {
770
- var submitKey;
771
+ var selectAllKey, submitKey;
771
772
  this.editor = this._module;
772
773
  this.throttledValueChanged = this.editor.util.throttle((function(_this) {
773
774
  return function(params) {
@@ -781,36 +782,39 @@ InputManager = (function(superClass) {
781
782
  return _this.editor.trigger('selectionchanged');
782
783
  };
783
784
  })(this), 50);
784
- if (this.opts.pasteImage && typeof this.opts.pasteImage !== 'string') {
785
- this.opts.pasteImage = 'inline';
786
- }
787
- this._keystrokeHandlers = {};
788
- this.hotkeys = simpleHotkeys({
789
- el: this.editor.body
790
- });
791
- this._pasteArea = $('<div/>').css({
792
- width: '1px',
793
- height: '1px',
794
- overflow: 'hidden',
795
- position: 'fixed',
796
- right: '0',
797
- bottom: '100px'
798
- }).attr({
799
- tabIndex: '-1',
800
- contentEditable: true
801
- }).addClass('simditor-paste-area').appendTo(this.editor.el);
802
785
  $(document).on('selectionchange.simditor' + this.editor.id, (function(_this) {
803
786
  return function(e) {
804
- if (!_this.focused) {
787
+ var triggerEvent;
788
+ if (!(_this.focused && !_this.editor.clipboard.pasting)) {
805
789
  return;
806
790
  }
807
- return _this.throttledSelectionChanged();
791
+ triggerEvent = function() {
792
+ if (_this._selectionTimer) {
793
+ clearTimeout(_this._selectionTimer);
794
+ _this._selectionTimer = null;
795
+ }
796
+ if (_this.editor.selection._selection.rangeCount > 0) {
797
+ return _this.throttledSelectionChanged();
798
+ } else {
799
+ return _this._selectionTimer = setTimeout(function() {
800
+ _this._selectionTimer = null;
801
+ if (_this.focused) {
802
+ return triggerEvent();
803
+ }
804
+ }, 10);
805
+ }
806
+ };
807
+ return triggerEvent();
808
808
  };
809
809
  })(this));
810
810
  this.editor.on('valuechanged', (function(_this) {
811
811
  return function() {
812
+ var $rootBlocks;
812
813
  _this.lastCaretPosition = null;
813
- if (_this.focused && !_this.editor.selection.blockNodes().length) {
814
+ $rootBlocks = _this.editor.body.children().filter(function(i, node) {
815
+ return _this.editor.util.isBlockNode(node);
816
+ });
817
+ if (_this.focused && $rootBlocks.length === 0) {
814
818
  _this.editor.selection.save();
815
819
  _this.editor.formatter.format();
816
820
  _this.editor.selection.restore();
@@ -839,23 +843,24 @@ InputManager = (function(superClass) {
839
843
  }
840
844
  };
841
845
  })(this));
842
- this.editor.body.on('keydown', $.proxy(this._onKeyDown, this)).on('keypress', $.proxy(this._onKeyPress, this)).on('keyup', $.proxy(this._onKeyUp, this)).on('mouseup', $.proxy(this._onMouseUp, this)).on('focus', $.proxy(this._onFocus, this)).on('blur', $.proxy(this._onBlur, this)).on('paste', $.proxy(this._onPaste, this)).on('drop', $.proxy(this._onDrop, this)).on('input', $.proxy(this._onInput, this));
846
+ this.editor.body.on('keydown', $.proxy(this._onKeyDown, this)).on('keypress', $.proxy(this._onKeyPress, this)).on('keyup', $.proxy(this._onKeyUp, this)).on('mouseup', $.proxy(this._onMouseUp, this)).on('focus', $.proxy(this._onFocus, this)).on('blur', $.proxy(this._onBlur, this)).on('drop', $.proxy(this._onDrop, this)).on('input', $.proxy(this._onInput, this));
843
847
  if (this.editor.util.browser.firefox) {
844
- this.addShortcut('cmd+left', (function(_this) {
848
+ this.editor.hotkeys.add('cmd+left', (function(_this) {
845
849
  return function(e) {
846
850
  e.preventDefault();
847
851
  _this.editor.selection._selection.modify('move', 'backward', 'lineboundary');
848
852
  return false;
849
853
  };
850
854
  })(this));
851
- this.addShortcut('cmd+right', (function(_this) {
855
+ this.editor.hotkeys.add('cmd+right', (function(_this) {
852
856
  return function(e) {
853
857
  e.preventDefault();
854
858
  _this.editor.selection._selection.modify('move', 'forward', 'lineboundary');
855
859
  return false;
856
860
  };
857
861
  })(this));
858
- this.addShortcut((this.editor.util.os.mac ? 'cmd+a' : 'ctrl+a'), (function(_this) {
862
+ selectAllKey = this.editor.util.os.mac ? 'cmd+a' : 'ctrl+a';
863
+ this.editor.hotkeys.add(selectAllKey, (function(_this) {
859
864
  return function(e) {
860
865
  var $children, firstBlock, lastBlock, range;
861
866
  $children = _this.editor.body.children();
@@ -873,7 +878,7 @@ InputManager = (function(superClass) {
873
878
  })(this));
874
879
  }
875
880
  submitKey = this.editor.util.os.mac ? 'cmd+enter' : 'ctrl+enter';
876
- this.addShortcut(submitKey, (function(_this) {
881
+ this.editor.hotkeys.add(submitKey, (function(_this) {
877
882
  return function(e) {
878
883
  _this.editor.el.closest('form').find('button:submit').click();
879
884
  return false;
@@ -889,6 +894,9 @@ InputManager = (function(superClass) {
889
894
  };
890
895
 
891
896
  InputManager.prototype._onFocus = function(e) {
897
+ if (this.editor.clipboard.pasting) {
898
+ return;
899
+ }
892
900
  this.editor.el.addClass('focus').removeClass('error');
893
901
  this.focused = true;
894
902
  this.lastCaretPosition = null;
@@ -904,6 +912,9 @@ InputManager = (function(superClass) {
904
912
 
905
913
  InputManager.prototype._onBlur = function(e) {
906
914
  var ref;
915
+ if (this.editor.clipboard.pasting) {
916
+ return;
917
+ }
907
918
  this.editor.el.removeClass('focus');
908
919
  this.editor.sync();
909
920
  this.focused = false;
@@ -918,36 +929,16 @@ InputManager = (function(superClass) {
918
929
  };
919
930
 
920
931
  InputManager.prototype._onKeyDown = function(e) {
921
- var base, ref, ref1, result;
932
+ var ref, ref1;
922
933
  if (this.editor.triggerHandler(e) === false) {
923
934
  return false;
924
935
  }
925
- if (this.hotkeys.respondTo(e)) {
936
+ if (this.editor.hotkeys.respondTo(e)) {
926
937
  return;
927
938
  }
928
- if (e.which in this._keystrokeHandlers) {
929
- result = typeof (base = this._keystrokeHandlers[e.which])['*'] === "function" ? base['*'](e) : void 0;
930
- if (result) {
931
- this.throttledValueChanged();
932
- return false;
933
- }
934
- this.editor.selection.startNodes().each((function(_this) {
935
- return function(i, node) {
936
- var handler, ref;
937
- if (node.nodeType !== Node.ELEMENT_NODE) {
938
- return;
939
- }
940
- handler = (ref = _this._keystrokeHandlers[e.which]) != null ? ref[node.tagName.toLowerCase()] : void 0;
941
- result = typeof handler === "function" ? handler(e, $(node)) : void 0;
942
- if (result === true || result === false) {
943
- return false;
944
- }
945
- };
946
- })(this));
947
- if (result) {
948
- this.throttledValueChanged();
949
- return false;
950
- }
939
+ if (this.editor.keystroke.respondTo(e)) {
940
+ this.throttledValueChanged();
941
+ return false;
951
942
  }
952
943
  if ((ref = e.which, indexOf.call(this._modifierKeys, ref) >= 0) || (ref1 = e.which, indexOf.call(this._arrowKeys, ref1) >= 0)) {
953
944
  return;
@@ -983,169 +974,6 @@ InputManager = (function(superClass) {
983
974
  }
984
975
  };
985
976
 
986
- InputManager.prototype._onPaste = function(e) {
987
- var $blockEl, cleanPaste, imageFile, pasteContent, pasteItem, processPasteContent, range, ref, uploadOpt;
988
- if (this.editor.triggerHandler(e) === false) {
989
- return false;
990
- }
991
- range = this.editor.selection.deleteRangeContents();
992
- if (!range.collapsed) {
993
- range.collapse(true);
994
- }
995
- this.editor.selection.range(range);
996
- $blockEl = this.editor.selection.blockNodes().last();
997
- cleanPaste = $blockEl.is('pre, table');
998
- if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.items && e.originalEvent.clipboardData.items.length > 0) {
999
- pasteItem = e.originalEvent.clipboardData.items[0];
1000
- if (/^image\//.test(pasteItem.type) && !cleanPaste) {
1001
- imageFile = pasteItem.getAsFile();
1002
- if (!((imageFile != null) && this.opts.pasteImage)) {
1003
- return;
1004
- }
1005
- if (!imageFile.name) {
1006
- imageFile.name = "Clipboard Image.png";
1007
- }
1008
- uploadOpt = {};
1009
- uploadOpt[this.opts.pasteImage] = true;
1010
- if ((ref = this.editor.uploader) != null) {
1011
- ref.upload(imageFile, uploadOpt);
1012
- }
1013
- return false;
1014
- }
1015
- }
1016
- processPasteContent = (function(_this) {
1017
- return function(pasteContent) {
1018
- var $img, blob, children, insertPosition, k, l, lastLine, len, len1, len2, len3, len4, line, lines, m, node, o, q, ref1, ref2, ref3;
1019
- if (_this.editor.triggerHandler('pasting', [pasteContent]) === false) {
1020
- return;
1021
- }
1022
- if (!pasteContent) {
1023
- return;
1024
- } else if (cleanPaste) {
1025
- if ($blockEl.is('table')) {
1026
- lines = pasteContent.split('\n');
1027
- lastLine = lines.pop();
1028
- for (k = 0, len = lines.length; k < len; k++) {
1029
- line = lines[k];
1030
- _this.editor.selection.insertNode(document.createTextNode(line));
1031
- _this.editor.selection.insertNode($('<br/>'));
1032
- }
1033
- _this.editor.selection.insertNode(document.createTextNode(lastLine));
1034
- } else {
1035
- pasteContent = $('<div/>').text(pasteContent);
1036
- ref1 = pasteContent.contents();
1037
- for (l = 0, len1 = ref1.length; l < len1; l++) {
1038
- node = ref1[l];
1039
- _this.editor.selection.insertNode($(node)[0], range);
1040
- }
1041
- }
1042
- } else if ($blockEl.is(_this.editor.body)) {
1043
- for (m = 0, len2 = pasteContent.length; m < len2; m++) {
1044
- node = pasteContent[m];
1045
- _this.editor.selection.insertNode(node, range);
1046
- }
1047
- } else if (pasteContent.length < 1) {
1048
- return;
1049
- } else if (pasteContent.length === 1) {
1050
- if (pasteContent.is('p')) {
1051
- children = pasteContent.contents();
1052
- if (children.length === 1 && children.is('img')) {
1053
- $img = children;
1054
- if (/^data:image/.test($img.attr('src'))) {
1055
- if (!_this.opts.pasteImage) {
1056
- return;
1057
- }
1058
- blob = _this.editor.util.dataURLtoBlob($img.attr("src"));
1059
- blob.name = "Clipboard Image.png";
1060
- uploadOpt = {};
1061
- uploadOpt[_this.opts.pasteImage] = true;
1062
- if ((ref2 = _this.editor.uploader) != null) {
1063
- ref2.upload(blob, uploadOpt);
1064
- }
1065
- return;
1066
- } else if ($img.is('img[src^="webkit-fake-url://"]')) {
1067
- return;
1068
- }
1069
- }
1070
- for (o = 0, len3 = children.length; o < len3; o++) {
1071
- node = children[o];
1072
- _this.editor.selection.insertNode(node, range);
1073
- }
1074
- } else if ($blockEl.is('p') && _this.editor.util.isEmptyNode($blockEl)) {
1075
- $blockEl.replaceWith(pasteContent);
1076
- _this.editor.selection.setRangeAtEndOf(pasteContent, range);
1077
- } else if (pasteContent.is('ul, ol')) {
1078
- if (pasteContent.find('li').length === 1) {
1079
- pasteContent = $('<div/>').text(pasteContent.text());
1080
- ref3 = pasteContent.contents();
1081
- for (q = 0, len4 = ref3.length; q < len4; q++) {
1082
- node = ref3[q];
1083
- _this.editor.selection.insertNode($(node)[0], range);
1084
- }
1085
- } else if ($blockEl.is('li')) {
1086
- $blockEl.parent().after(pasteContent);
1087
- _this.editor.selection.setRangeAtEndOf(pasteContent, range);
1088
- } else {
1089
- $blockEl.after(pasteContent);
1090
- _this.editor.selection.setRangeAtEndOf(pasteContent, range);
1091
- }
1092
- } else {
1093
- $blockEl.after(pasteContent);
1094
- _this.editor.selection.setRangeAtEndOf(pasteContent, range);
1095
- }
1096
- } else {
1097
- if ($blockEl.is('li')) {
1098
- $blockEl = $blockEl.parent();
1099
- }
1100
- if (_this.editor.selection.rangeAtStartOf($blockEl, range)) {
1101
- insertPosition = 'before';
1102
- } else if (_this.editor.selection.rangeAtEndOf($blockEl, range)) {
1103
- insertPosition = 'after';
1104
- } else {
1105
- _this.editor.selection.breakBlockEl($blockEl, range);
1106
- insertPosition = 'before';
1107
- }
1108
- $blockEl[insertPosition](pasteContent);
1109
- _this.editor.selection.setRangeAtEndOf(pasteContent.last(), range);
1110
- }
1111
- return _this.throttledValueChanged();
1112
- };
1113
- })(this);
1114
- if (cleanPaste) {
1115
- e.preventDefault();
1116
- if (this.editor.util.browser.msie) {
1117
- pasteContent = window.clipboardData.getData('Text');
1118
- } else {
1119
- pasteContent = e.originalEvent.clipboardData.getData('text/plain');
1120
- }
1121
- return processPasteContent(pasteContent);
1122
- } else {
1123
- this.editor.selection.save(range);
1124
- this._pasteArea.focus();
1125
- if (this.editor.util.browser.msie && this.editor.util.browser.version === 10) {
1126
- e.preventDefault();
1127
- this._pasteArea.html(window.clipboardData.getData('Text'));
1128
- }
1129
- return setTimeout((function(_this) {
1130
- return function() {
1131
- if (_this._pasteArea.is(':empty')) {
1132
- pasteContent = null;
1133
- } else {
1134
- pasteContent = $('<div/>').append(_this._pasteArea.contents());
1135
- pasteContent.find('table colgroup').remove();
1136
- _this.editor.formatter.format(pasteContent);
1137
- _this.editor.formatter.decorate(pasteContent);
1138
- _this.editor.formatter.beautify(pasteContent.children());
1139
- pasteContent = pasteContent.contents();
1140
- }
1141
- _this._pasteArea.empty();
1142
- range = _this.editor.selection.restore();
1143
- return processPasteContent(pasteContent);
1144
- };
1145
- })(this), 10);
1146
- }
1147
- };
1148
-
1149
977
  InputManager.prototype._onDrop = function(e) {
1150
978
  if (this.editor.triggerHandler(e) === false) {
1151
979
  return false;
@@ -1157,17 +985,6 @@ InputManager = (function(superClass) {
1157
985
  return this.throttledValueChanged(['oninput']);
1158
986
  };
1159
987
 
1160
- InputManager.prototype.addKeystrokeHandler = function(key, node, handler) {
1161
- if (!this._keystrokeHandlers[key]) {
1162
- this._keystrokeHandlers[key] = {};
1163
- }
1164
- return this._keystrokeHandlers[key][node] = handler;
1165
- };
1166
-
1167
- InputManager.prototype.addShortcut = function(keys, handler) {
1168
- return this.hotkeys.add(keys, $.proxy(handler, this));
1169
- };
1170
-
1171
988
  return InputManager;
1172
989
 
1173
990
  })(SimpleModule);
@@ -1182,10 +999,53 @@ Keystroke = (function(superClass) {
1182
999
  Keystroke.pluginName = 'Keystroke';
1183
1000
 
1184
1001
  Keystroke.prototype._init = function() {
1185
- var titleEnterHandler;
1186
1002
  this.editor = this._module;
1003
+ this._keystrokeHandlers = {};
1004
+ return this._initKeystrokeHandlers();
1005
+ };
1006
+
1007
+ Keystroke.prototype.add = function(key, node, handler) {
1008
+ key = key.toLowerCase();
1009
+ key = this.editor.hotkeys.constructor.aliases[key] || key;
1010
+ if (!this._keystrokeHandlers[key]) {
1011
+ this._keystrokeHandlers[key] = {};
1012
+ }
1013
+ return this._keystrokeHandlers[key][node] = handler;
1014
+ };
1015
+
1016
+ Keystroke.prototype.respondTo = function(e) {
1017
+ var base, key, ref, result;
1018
+ key = (ref = this.editor.hotkeys.constructor.keyNameMap[e.which]) != null ? ref.toLowerCase() : void 0;
1019
+ if (!key) {
1020
+ return;
1021
+ }
1022
+ if (key in this._keystrokeHandlers) {
1023
+ result = typeof (base = this._keystrokeHandlers[key])['*'] === "function" ? base['*'](e) : void 0;
1024
+ if (!result) {
1025
+ this.editor.selection.startNodes().each((function(_this) {
1026
+ return function(i, node) {
1027
+ var handler, ref1;
1028
+ if (node.nodeType !== Node.ELEMENT_NODE) {
1029
+ return;
1030
+ }
1031
+ handler = (ref1 = _this._keystrokeHandlers[key]) != null ? ref1[node.tagName.toLowerCase()] : void 0;
1032
+ result = typeof handler === "function" ? handler(e, $(node)) : void 0;
1033
+ if (result === true || result === false) {
1034
+ return false;
1035
+ }
1036
+ };
1037
+ })(this));
1038
+ }
1039
+ if (result) {
1040
+ return true;
1041
+ }
1042
+ }
1043
+ };
1044
+
1045
+ Keystroke.prototype._initKeystrokeHandlers = function() {
1046
+ var titleEnterHandler;
1187
1047
  if (this.editor.util.browser.safari) {
1188
- this.editor.inputManager.addKeystrokeHandler('13', '*', (function(_this) {
1048
+ this.add('enter', '*', (function(_this) {
1189
1049
  return function(e) {
1190
1050
  var $blockEl, $br;
1191
1051
  if (!e.shiftKey) {
@@ -1219,14 +1079,14 @@ Keystroke = (function(superClass) {
1219
1079
  return true;
1220
1080
  };
1221
1081
  })(this);
1222
- this.editor.inputManager.addKeystrokeHandler('13', 'h1', titleEnterHandler);
1223
- this.editor.inputManager.addKeystrokeHandler('13', 'h2', titleEnterHandler);
1224
- this.editor.inputManager.addKeystrokeHandler('13', 'h3', titleEnterHandler);
1225
- this.editor.inputManager.addKeystrokeHandler('13', 'h4', titleEnterHandler);
1226
- this.editor.inputManager.addKeystrokeHandler('13', 'h5', titleEnterHandler);
1227
- this.editor.inputManager.addKeystrokeHandler('13', 'h6', titleEnterHandler);
1228
- }
1229
- this.editor.inputManager.addKeystrokeHandler('8', '*', (function(_this) {
1082
+ this.add('enter', 'h1', titleEnterHandler);
1083
+ this.add('enter', 'h2', titleEnterHandler);
1084
+ this.add('enter', 'h3', titleEnterHandler);
1085
+ this.add('enter', 'h4', titleEnterHandler);
1086
+ this.add('enter', 'h5', titleEnterHandler);
1087
+ this.add('enter', 'h6', titleEnterHandler);
1088
+ }
1089
+ this.add('backspace', '*', (function(_this) {
1230
1090
  return function(e) {
1231
1091
  var $blockEl, $prevBlockEl, $rootBlock, isWebkit;
1232
1092
  $rootBlock = _this.editor.selection.rootNodes().first();
@@ -1247,7 +1107,7 @@ Keystroke = (function(superClass) {
1247
1107
  }
1248
1108
  };
1249
1109
  })(this));
1250
- this.editor.inputManager.addKeystrokeHandler('13', 'li', (function(_this) {
1110
+ this.add('enter', 'li', (function(_this) {
1251
1111
  return function(e, $node) {
1252
1112
  var $cloneNode, listEl, newBlockEl, newListEl;
1253
1113
  $cloneNode = $node.clone();
@@ -1293,7 +1153,7 @@ Keystroke = (function(superClass) {
1293
1153
  return true;
1294
1154
  };
1295
1155
  })(this));
1296
- this.editor.inputManager.addKeystrokeHandler('13', 'pre', (function(_this) {
1156
+ this.add('enter', 'pre', (function(_this) {
1297
1157
  return function(e, $node) {
1298
1158
  var $p, breakNode, range;
1299
1159
  e.preventDefault();
@@ -1319,7 +1179,7 @@ Keystroke = (function(superClass) {
1319
1179
  return true;
1320
1180
  };
1321
1181
  })(this));
1322
- this.editor.inputManager.addKeystrokeHandler('13', 'blockquote', (function(_this) {
1182
+ this.add('enter', 'blockquote', (function(_this) {
1323
1183
  return function(e, $node) {
1324
1184
  var $closestBlock, range;
1325
1185
  $closestBlock = _this.editor.selection.blockNodes().last();
@@ -1332,7 +1192,7 @@ Keystroke = (function(superClass) {
1332
1192
  return true;
1333
1193
  };
1334
1194
  })(this));
1335
- this.editor.inputManager.addKeystrokeHandler('8', 'li', (function(_this) {
1195
+ this.add('backspace', 'li', (function(_this) {
1336
1196
  return function(e, $node) {
1337
1197
  var $br, $childList, $newLi, $prevChildList, $prevNode, $textNode, isFF, range, text;
1338
1198
  $childList = $node.children('ul, ol');
@@ -1381,7 +1241,7 @@ Keystroke = (function(superClass) {
1381
1241
  return true;
1382
1242
  };
1383
1243
  })(this));
1384
- this.editor.inputManager.addKeystrokeHandler('8', 'pre', (function(_this) {
1244
+ this.add('backspace', 'pre', (function(_this) {
1385
1245
  return function(e, $node) {
1386
1246
  var $newNode, codeStr, range;
1387
1247
  if (!_this.editor.selection.rangeAtStartOf($node)) {
@@ -1395,7 +1255,7 @@ Keystroke = (function(superClass) {
1395
1255
  return true;
1396
1256
  };
1397
1257
  })(this));
1398
- return this.editor.inputManager.addKeystrokeHandler('8', 'blockquote', (function(_this) {
1258
+ return this.add('backspace', 'blockquote', (function(_this) {
1399
1259
  return function(e, $node) {
1400
1260
  var $firstChild, range;
1401
1261
  if (!_this.editor.selection.rangeAtStartOf($node)) {
@@ -1431,7 +1291,7 @@ UndoManager = (function(superClass) {
1431
1291
  UndoManager.prototype._endPosition = null;
1432
1292
 
1433
1293
  UndoManager.prototype._init = function() {
1434
- var redoShortcut, throttledPushState, undoShortcut;
1294
+ var redoShortcut, undoShortcut;
1435
1295
  this.editor = this._module;
1436
1296
  this._stack = [];
1437
1297
  if (this.editor.util.os.mac) {
@@ -1444,31 +1304,33 @@ UndoManager = (function(superClass) {
1444
1304
  undoShortcut = 'ctrl+z';
1445
1305
  redoShortcut = 'shift+ctrl+z';
1446
1306
  }
1447
- this.editor.inputManager.addShortcut(undoShortcut, (function(_this) {
1307
+ this.editor.hotkeys.add(undoShortcut, (function(_this) {
1448
1308
  return function(e) {
1449
1309
  e.preventDefault();
1450
1310
  _this.undo();
1451
1311
  return false;
1452
1312
  };
1453
1313
  })(this));
1454
- this.editor.inputManager.addShortcut(redoShortcut, (function(_this) {
1314
+ this.editor.hotkeys.add(redoShortcut, (function(_this) {
1455
1315
  return function(e) {
1456
1316
  e.preventDefault();
1457
1317
  _this.redo();
1458
1318
  return false;
1459
1319
  };
1460
1320
  })(this));
1461
- throttledPushState = this.editor.util.throttle((function(_this) {
1321
+ this.throttledPushState = this.editor.util.throttle((function(_this) {
1462
1322
  return function() {
1463
1323
  return _this._pushUndoState();
1464
1324
  };
1465
1325
  })(this), 500);
1466
- this.editor.on('valuechanged', function(e, src) {
1467
- if (src === 'undo' || src === 'redo') {
1468
- return;
1469
- }
1470
- return throttledPushState();
1471
- });
1326
+ this.editor.on('valuechanged', (function(_this) {
1327
+ return function(e, src) {
1328
+ if (src === 'undo' || src === 'redo') {
1329
+ return;
1330
+ }
1331
+ return _this.throttledPushState();
1332
+ };
1333
+ })(this));
1472
1334
  this.editor.on('selectionchanged', (function(_this) {
1473
1335
  return function(e) {
1474
1336
  _this._startPosition = null;
@@ -1569,24 +1431,18 @@ UndoManager = (function(superClass) {
1569
1431
 
1570
1432
  UndoManager.prototype.update = function() {
1571
1433
  var currentState, html;
1572
- if (this._timer) {
1573
- return;
1574
- }
1575
1434
  currentState = this.currentState();
1576
1435
  if (!currentState) {
1577
1436
  return;
1578
1437
  }
1579
1438
  html = this.editor.body.html();
1580
- if (html !== currentState.html) {
1581
- return;
1582
- }
1583
1439
  currentState.html = html;
1584
1440
  return currentState.caret = this.caretPosition();
1585
1441
  };
1586
1442
 
1587
1443
  UndoManager.prototype._getNodeOffset = function(node, index) {
1588
1444
  var $parent, merging, offset;
1589
- if (index) {
1445
+ if ($.isNumeric(index)) {
1590
1446
  $parent = $(node);
1591
1447
  } else {
1592
1448
  $parent = $(node).parent();
@@ -1594,10 +1450,10 @@ UndoManager = (function(superClass) {
1594
1450
  offset = 0;
1595
1451
  merging = false;
1596
1452
  $parent.contents().each(function(i, child) {
1597
- if (index === i || node === child) {
1453
+ if (node === child || (index === i && i === 0)) {
1598
1454
  return false;
1599
1455
  }
1600
- if (child.nodeType === 3) {
1456
+ if (child.nodeType === Node.TEXT_NODE) {
1601
1457
  if (!merging) {
1602
1458
  offset += 1;
1603
1459
  merging = true;
@@ -1606,6 +1462,9 @@ UndoManager = (function(superClass) {
1606
1462
  offset += 1;
1607
1463
  merging = false;
1608
1464
  }
1465
+ if (index - 1 === i) {
1466
+ return false;
1467
+ }
1609
1468
  return null;
1610
1469
  });
1611
1470
  return offset;
@@ -1619,7 +1478,8 @@ UndoManager = (function(superClass) {
1619
1478
  range = this.editor.selection.range();
1620
1479
  offset = range[type + "Offset"];
1621
1480
  $nodes = this.editor.selection[type + "Nodes"]();
1622
- if ((node = $nodes.first()[0]).nodeType === Node.TEXT_NODE) {
1481
+ node = $nodes.first()[0];
1482
+ if (node.nodeType === Node.TEXT_NODE) {
1623
1483
  prevNode = node.previousSibling;
1624
1484
  while (prevNode && prevNode.nodeType === Node.TEXT_NODE) {
1625
1485
  node = prevNode;
@@ -1629,6 +1489,8 @@ UndoManager = (function(superClass) {
1629
1489
  nodes = $nodes.get();
1630
1490
  nodes[0] = node;
1631
1491
  $nodes = $(nodes);
1492
+ } else {
1493
+ offset = this._getNodeOffset(node, offset);
1632
1494
  }
1633
1495
  position = [offset];
1634
1496
  $nodes.each((function(_this) {
@@ -1647,7 +1509,7 @@ UndoManager = (function(superClass) {
1647
1509
  offset = ref[i];
1648
1510
  childNodes = node.childNodes;
1649
1511
  if (offset > childNodes.length - 1) {
1650
- if (i === position.length - 2 && $(node).is('pre')) {
1512
+ if (i === position.length - 2 && $(node).is('pre:empty')) {
1651
1513
  child = document.createTextNode('');
1652
1514
  node.appendChild(child);
1653
1515
  childNodes = node.childNodes;
@@ -1736,34 +1598,41 @@ Util = (function(superClass) {
1736
1598
  })();
1737
1599
 
1738
1600
  Util.prototype.browser = (function() {
1739
- var chrome, firefox, ie, ref, ref1, ref2, ref3, safari, ua;
1601
+ var chrome, edge, firefox, ie, ref, ref1, ref2, ref3, ref4, safari, ua;
1740
1602
  ua = navigator.userAgent;
1741
1603
  ie = /(msie|trident)/i.test(ua);
1742
1604
  chrome = /chrome|crios/i.test(ua);
1743
1605
  safari = /safari/i.test(ua) && !chrome;
1744
1606
  firefox = /firefox/i.test(ua);
1607
+ edge = /edge/i.test(ua);
1745
1608
  if (ie) {
1746
1609
  return {
1747
1610
  msie: true,
1748
1611
  version: ((ref = ua.match(/(msie |rv:)(\d+(\.\d+)?)/i)) != null ? ref[2] : void 0) * 1
1749
1612
  };
1613
+ } else if (edge) {
1614
+ return {
1615
+ edge: true,
1616
+ webkit: true,
1617
+ version: ((ref1 = ua.match(/edge\/(\d+(\.\d+)?)/i)) != null ? ref1[1] : void 0) * 1
1618
+ };
1750
1619
  } else if (chrome) {
1751
1620
  return {
1752
1621
  webkit: true,
1753
1622
  chrome: true,
1754
- version: ((ref1 = ua.match(/(?:chrome|crios)\/(\d+(\.\d+)?)/i)) != null ? ref1[1] : void 0) * 1
1623
+ version: ((ref2 = ua.match(/(?:chrome|crios)\/(\d+(\.\d+)?)/i)) != null ? ref2[1] : void 0) * 1
1755
1624
  };
1756
1625
  } else if (safari) {
1757
1626
  return {
1758
1627
  webkit: true,
1759
1628
  safari: true,
1760
- version: ((ref2 = ua.match(/version\/(\d+(\.\d+)?)/i)) != null ? ref2[1] : void 0) * 1
1629
+ version: ((ref3 = ua.match(/version\/(\d+(\.\d+)?)/i)) != null ? ref3[1] : void 0) * 1
1761
1630
  };
1762
1631
  } else if (firefox) {
1763
1632
  return {
1764
1633
  mozilla: true,
1765
1634
  firefox: true,
1766
- version: ((ref3 = ua.match(/firefox\/(\d+(\.\d+)?)/i)) != null ? ref3[1] : void 0) * 1
1635
+ version: ((ref4 = ua.match(/firefox\/(\d+(\.\d+)?)/i)) != null ? ref4[1] : void 0) * 1
1767
1636
  };
1768
1637
  } else {
1769
1638
  return {};
@@ -1903,7 +1772,7 @@ Util = (function(superClass) {
1903
1772
  ctx = null;
1904
1773
  return args = null;
1905
1774
  };
1906
- return throttled = function() {
1775
+ throttled = function() {
1907
1776
  var delta;
1908
1777
  ctx = this;
1909
1778
  args = arguments;
@@ -1917,6 +1786,14 @@ Util = (function(superClass) {
1917
1786
  }
1918
1787
  return rtn;
1919
1788
  };
1789
+ throttled.clear = function() {
1790
+ if (!timeoutID) {
1791
+ return;
1792
+ }
1793
+ clearTimeout(timeoutID);
1794
+ return call();
1795
+ };
1796
+ return throttled;
1920
1797
  };
1921
1798
 
1922
1799
  Util.prototype.formatHTML = function(html) {
@@ -2119,7 +1996,7 @@ Indentation = (function(superClass) {
2119
1996
 
2120
1997
  Indentation.prototype._init = function() {
2121
1998
  this.editor = this._module;
2122
- return this.editor.inputManager.addKeystrokeHandler('9', '*', (function(_this) {
1999
+ return this.editor.keystroke.add('tab', '*', (function(_this) {
2123
2000
  return function(e) {
2124
2001
  var codeButton;
2125
2002
  codeButton = _this.editor.toolbar.findButton('code');
@@ -2180,7 +2057,7 @@ Indentation = (function(superClass) {
2180
2057
  if (!($pre.is($blockEl) || $pre.closest('pre').is($blockEl))) {
2181
2058
  return;
2182
2059
  }
2183
- this.indentText(range);
2060
+ this.indentText(this.editor.selection.range());
2184
2061
  } else if ($blockEl.is('li')) {
2185
2062
  $parentLi = $blockEl.prev('li');
2186
2063
  if ($parentLi.length < 1) {
@@ -2298,6 +2175,217 @@ Indentation = (function(superClass) {
2298
2175
 
2299
2176
  })(SimpleModule);
2300
2177
 
2178
+ Clipboard = (function(superClass) {
2179
+ extend(Clipboard, superClass);
2180
+
2181
+ function Clipboard() {
2182
+ return Clipboard.__super__.constructor.apply(this, arguments);
2183
+ }
2184
+
2185
+ Clipboard.pluginName = 'Clipboard';
2186
+
2187
+ Clipboard.prototype.opts = {
2188
+ pasteImage: false
2189
+ };
2190
+
2191
+ Clipboard.prototype._init = function() {
2192
+ this.editor = this._module;
2193
+ if (this.opts.pasteImage && typeof this.opts.pasteImage !== 'string') {
2194
+ this.opts.pasteImage = 'inline';
2195
+ }
2196
+ return this.editor.body.on('paste', (function(_this) {
2197
+ return function(e) {
2198
+ var $blockEl, isPlainText, range;
2199
+ if (_this.editor.triggerHandler(e) === false) {
2200
+ return false;
2201
+ }
2202
+ range = _this.editor.selection.deleteRangeContents();
2203
+ if (!range.collapsed) {
2204
+ range.collapse(true);
2205
+ }
2206
+ _this.editor.selection.range(range);
2207
+ $blockEl = _this.editor.selection.blockNodes().last();
2208
+ isPlainText = $blockEl.is('pre, table');
2209
+ if (!isPlainText && _this._processPasteByClipboardApi(e)) {
2210
+ return false;
2211
+ }
2212
+ if (_this._pasteBin) {
2213
+ return false;
2214
+ }
2215
+ _this.editor.inputManager.throttledValueChanged.clear();
2216
+ _this.editor.inputManager.throttledSelectionChanged.clear();
2217
+ _this.editor.undoManager.throttledPushState.clear();
2218
+ _this.pasting = true;
2219
+ return _this._getPasteContent(isPlainText, function(pasteContent) {
2220
+ _this._processPasteContent(isPlainText, $blockEl, pasteContent);
2221
+ return _this.pasting = false;
2222
+ });
2223
+ };
2224
+ })(this));
2225
+ };
2226
+
2227
+ Clipboard.prototype._processPasteByClipboardApi = function(e) {
2228
+ var imageFile, pasteItem, ref, uploadOpt;
2229
+ if (this.editor.util.browser.edge) {
2230
+ return;
2231
+ }
2232
+ if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.items && e.originalEvent.clipboardData.items.length > 0) {
2233
+ pasteItem = e.originalEvent.clipboardData.items[0];
2234
+ if (/^image\//.test(pasteItem.type)) {
2235
+ imageFile = pasteItem.getAsFile();
2236
+ if (!((imageFile != null) && this.opts.pasteImage)) {
2237
+ return;
2238
+ }
2239
+ if (!imageFile.name) {
2240
+ imageFile.name = "Clipboard Image.png";
2241
+ }
2242
+ if (this.editor.triggerHandler('pasting', [imageFile]) === false) {
2243
+ return;
2244
+ }
2245
+ uploadOpt = {};
2246
+ uploadOpt[this.opts.pasteImage] = true;
2247
+ if ((ref = this.editor.uploader) != null) {
2248
+ ref.upload(imageFile, uploadOpt);
2249
+ }
2250
+ return true;
2251
+ }
2252
+ }
2253
+ };
2254
+
2255
+ Clipboard.prototype._getPasteContent = function(isPlainText, callback) {
2256
+ var state;
2257
+ this._pasteBin = $('<div contenteditable="true" />').addClass('simditor-paste-bin').attr('tabIndex', '-1').appendTo(this.editor.el);
2258
+ state = {
2259
+ html: this.editor.body.html(),
2260
+ caret: this.editor.undoManager.caretPosition()
2261
+ };
2262
+ this._pasteBin.focus();
2263
+ return setTimeout((function(_this) {
2264
+ return function() {
2265
+ var pasteContent;
2266
+ _this.editor.hidePopover();
2267
+ _this.editor.body.html(state.html);
2268
+ _this.editor.undoManager.caretPosition(state.caret);
2269
+ _this.editor.body.focus();
2270
+ _this.editor.selection._reset();
2271
+ if (isPlainText) {
2272
+ pasteContent = _this.editor.formatter.clearHtml(_this._pasteBin.html(), true);
2273
+ } else {
2274
+ pasteContent = $('<div/>').append(_this._pasteBin.contents());
2275
+ pasteContent.find('table colgroup').remove();
2276
+ _this.editor.formatter.format(pasteContent);
2277
+ _this.editor.formatter.decorate(pasteContent);
2278
+ _this.editor.formatter.beautify(pasteContent.children());
2279
+ pasteContent = pasteContent.contents();
2280
+ }
2281
+ _this._pasteBin.remove();
2282
+ _this._pasteBin = null;
2283
+ return callback(pasteContent);
2284
+ };
2285
+ })(this), 0);
2286
+ };
2287
+
2288
+ Clipboard.prototype._processPasteContent = function(isPlainText, $blockEl, pasteContent) {
2289
+ var $img, blob, children, insertPosition, k, l, lastLine, len, len1, len2, len3, len4, line, lines, m, node, o, q, ref, ref1, ref2, uploadOpt;
2290
+ if (this.editor.triggerHandler('pasting', [pasteContent]) === false) {
2291
+ return;
2292
+ }
2293
+ if (!pasteContent) {
2294
+ return;
2295
+ } else if (isPlainText) {
2296
+ if ($blockEl.is('table')) {
2297
+ lines = pasteContent.split('\n');
2298
+ lastLine = lines.pop();
2299
+ for (k = 0, len = lines.length; k < len; k++) {
2300
+ line = lines[k];
2301
+ this.editor.selection.insertNode(document.createTextNode(line));
2302
+ this.editor.selection.insertNode($('<br/>'));
2303
+ }
2304
+ this.editor.selection.insertNode(document.createTextNode(lastLine));
2305
+ } else {
2306
+ pasteContent = $('<div/>').text(pasteContent);
2307
+ ref = pasteContent.contents();
2308
+ for (l = 0, len1 = ref.length; l < len1; l++) {
2309
+ node = ref[l];
2310
+ this.editor.selection.insertNode($(node)[0]);
2311
+ }
2312
+ }
2313
+ } else if ($blockEl.is(this.editor.body)) {
2314
+ for (m = 0, len2 = pasteContent.length; m < len2; m++) {
2315
+ node = pasteContent[m];
2316
+ this.editor.selection.insertNode(node);
2317
+ }
2318
+ } else if (pasteContent.length < 1) {
2319
+ return;
2320
+ } else if (pasteContent.length === 1) {
2321
+ if (pasteContent.is('p')) {
2322
+ children = pasteContent.contents();
2323
+ if (children.length === 1 && children.is('img')) {
2324
+ $img = children;
2325
+ if (/^data:image/.test($img.attr('src'))) {
2326
+ if (!this.opts.pasteImage) {
2327
+ return;
2328
+ }
2329
+ blob = this.editor.util.dataURLtoBlob($img.attr("src"));
2330
+ blob.name = "Clipboard Image.png";
2331
+ uploadOpt = {};
2332
+ uploadOpt[this.opts.pasteImage] = true;
2333
+ if ((ref1 = this.editor.uploader) != null) {
2334
+ ref1.upload(blob, uploadOpt);
2335
+ }
2336
+ return;
2337
+ } else if ($img.is('img[src^="webkit-fake-url://"]')) {
2338
+ return;
2339
+ }
2340
+ }
2341
+ for (o = 0, len3 = children.length; o < len3; o++) {
2342
+ node = children[o];
2343
+ this.editor.selection.insertNode(node);
2344
+ }
2345
+ } else if ($blockEl.is('p') && this.editor.util.isEmptyNode($blockEl)) {
2346
+ $blockEl.replaceWith(pasteContent);
2347
+ this.editor.selection.setRangeAtEndOf(pasteContent);
2348
+ } else if (pasteContent.is('ul, ol')) {
2349
+ if (pasteContent.find('li').length === 1) {
2350
+ pasteContent = $('<div/>').text(pasteContent.text());
2351
+ ref2 = pasteContent.contents();
2352
+ for (q = 0, len4 = ref2.length; q < len4; q++) {
2353
+ node = ref2[q];
2354
+ this.editor.selection.insertNode($(node)[0]);
2355
+ }
2356
+ } else if ($blockEl.is('li')) {
2357
+ $blockEl.parent().after(pasteContent);
2358
+ this.editor.selection.setRangeAtEndOf(pasteContent);
2359
+ } else {
2360
+ $blockEl.after(pasteContent);
2361
+ this.editor.selection.setRangeAtEndOf(pasteContent);
2362
+ }
2363
+ } else {
2364
+ $blockEl.after(pasteContent);
2365
+ this.editor.selection.setRangeAtEndOf(pasteContent);
2366
+ }
2367
+ } else {
2368
+ if ($blockEl.is('li')) {
2369
+ $blockEl = $blockEl.parent();
2370
+ }
2371
+ if (this.editor.selection.rangeAtStartOf($blockEl)) {
2372
+ insertPosition = 'before';
2373
+ } else if (this.editor.selection.rangeAtEndOf($blockEl)) {
2374
+ insertPosition = 'after';
2375
+ } else {
2376
+ this.editor.selection.breakBlockEl($blockEl);
2377
+ insertPosition = 'before';
2378
+ }
2379
+ $blockEl[insertPosition](pasteContent);
2380
+ this.editor.selection.setRangeAtEndOf(pasteContent.last());
2381
+ }
2382
+ return this.editor.inputManager.throttledValueChanged();
2383
+ };
2384
+
2385
+ return Clipboard;
2386
+
2387
+ })(SimpleModule);
2388
+
2301
2389
  Simditor = (function(superClass) {
2302
2390
  extend(Simditor, superClass);
2303
2391
 
@@ -2321,6 +2409,8 @@ Simditor = (function(superClass) {
2321
2409
 
2322
2410
  Simditor.connect(Indentation);
2323
2411
 
2412
+ Simditor.connect(Clipboard);
2413
+
2324
2414
  Simditor.count = 0;
2325
2415
 
2326
2416
  Simditor.prototype.opts = {
@@ -2346,6 +2436,14 @@ Simditor = (function(superClass) {
2346
2436
  }
2347
2437
  this.id = ++Simditor.count;
2348
2438
  this._render();
2439
+ if (simpleHotkeys) {
2440
+ this.hotkeys = simpleHotkeys({
2441
+ el: this.body
2442
+ });
2443
+ } else {
2444
+ throw new Error('simditor: simple-hotkeys is required.');
2445
+ return;
2446
+ }
2349
2447
  if (this.opts.upload && simpleUploader) {
2350
2448
  uploadOpts = typeof this.opts.upload === 'object' ? this.opts.upload : {};
2351
2449
  this.uploader = simpleUploader(uploadOpts);
@@ -2470,6 +2568,7 @@ Simditor = (function(superClass) {
2470
2568
  };
2471
2569
 
2472
2570
  Simditor.prototype.focus = function() {
2571
+ var $blockEl, range;
2473
2572
  if (!(this.body.is(':visible') && this.body.is('[contenteditable]'))) {
2474
2573
  this.el.find('textarea:visible').focus();
2475
2574
  return;
@@ -2477,6 +2576,12 @@ Simditor = (function(superClass) {
2477
2576
  if (this.inputManager.lastCaretPosition) {
2478
2577
  return this.undoManager.caretPosition(this.inputManager.lastCaretPosition);
2479
2578
  } else {
2579
+ $blockEl = this.body.children().last();
2580
+ if (!$blockEl.is('p')) {
2581
+ $blockEl = $('<p/>').append(this.util.phBr).appendTo(this.body);
2582
+ }
2583
+ range = document.createRange();
2584
+ this.selection.setRangeAtEndOf($blockEl, range);
2480
2585
  return this.body.focus();
2481
2586
  }
2482
2587
  };
@@ -2698,7 +2803,7 @@ Button = (function(superClass) {
2698
2803
  return function() {
2699
2804
  var editorActive;
2700
2805
  editorActive = _this.editor.body.is(':visible') && _this.editor.body.is('[contenteditable]');
2701
- if (!editorActive) {
2806
+ if (!(editorActive && !_this.editor.clipboard.pasting)) {
2702
2807
  return;
2703
2808
  }
2704
2809
  _this.setActive(false);
@@ -2706,7 +2811,7 @@ Button = (function(superClass) {
2706
2811
  };
2707
2812
  })(this));
2708
2813
  if (this.shortcut != null) {
2709
- this.editor.inputManager.addShortcut(this.shortcut, (function(_this) {
2814
+ this.editor.hotkeys.add(this.shortcut, (function(_this) {
2710
2815
  return function(e) {
2711
2816
  _this.el.mousedown();
2712
2817
  return false;
@@ -3510,7 +3615,6 @@ CodeButton = (function(superClass) {
3510
3615
 
3511
3616
  CodeButton.prototype._status = function() {
3512
3617
  CodeButton.__super__._status.call(this);
3513
- console.log('test');
3514
3618
  if (this.active) {
3515
3619
  return this.popover.show(this.node);
3516
3620
  } else {
@@ -3753,7 +3857,7 @@ LinkButton = (function(superClass) {
3753
3857
  target: '_blank',
3754
3858
  text: linkText || this._t('linkText')
3755
3859
  });
3756
- if (this.editor.selection.blockNodes().length === 1) {
3860
+ if (this.editor.selection.blockNodes().length > 0) {
3757
3861
  range.insertNode($link[0]);
3758
3862
  } else {
3759
3863
  $newBlock = $('<p/>').append($link);
@@ -4082,7 +4186,7 @@ ImageButton = (function(superClass) {
4082
4186
  this.editor.uploader.on('uploadprogress', uploadProgress);
4083
4187
  this.editor.uploader.on('uploadsuccess', (function(_this) {
4084
4188
  return function(e, file, result) {
4085
- var $img, $mask, msg;
4189
+ var $img, img_path, msg;
4086
4190
  if (!file.inline) {
4087
4191
  return;
4088
4192
  }
@@ -4090,13 +4194,6 @@ ImageButton = (function(superClass) {
4090
4194
  if (!($img.hasClass('uploading') && $img.parent().length > 0)) {
4091
4195
  return;
4092
4196
  }
4093
- $img.removeData('file');
4094
- $img.removeClass('uploading').removeClass('loading');
4095
- $mask = $img.data('mask');
4096
- if ($mask) {
4097
- $mask.remove();
4098
- }
4099
- $img.removeData('mask');
4100
4197
  if (typeof result !== 'object') {
4101
4198
  try {
4102
4199
  result = $.parseJSON(result);
@@ -4110,10 +4207,20 @@ ImageButton = (function(superClass) {
4110
4207
  if (result.success === false) {
4111
4208
  msg = result.msg || _this._t('uploadFailed');
4112
4209
  alert(msg);
4113
- $img.attr('src', _this.defaultImage);
4210
+ img_path = _this.defaultImage;
4114
4211
  } else {
4115
- $img.attr('src', result.file_path);
4212
+ img_path = result.file_path;
4116
4213
  }
4214
+ _this.loadImage($img, img_path, function() {
4215
+ var $mask;
4216
+ $img.removeData('file');
4217
+ $img.removeClass('uploading').removeClass('loading');
4218
+ $mask = $img.data('mask');
4219
+ if ($mask) {
4220
+ $mask.remove();
4221
+ }
4222
+ return $img.removeData('mask');
4223
+ });
4117
4224
  if (_this.popover.active) {
4118
4225
  _this.popover.srcEl.prop('disabled', false);
4119
4226
  _this.popover.srcEl.val(result.file_path);
@@ -4126,7 +4233,7 @@ ImageButton = (function(superClass) {
4126
4233
  })(this));
4127
4234
  return this.editor.uploader.on('uploaderror', (function(_this) {
4128
4235
  return function(e, file, xhr) {
4129
- var $img, $mask, msg, result;
4236
+ var $img, msg, result;
4130
4237
  if (!file.inline) {
4131
4238
  return;
4132
4239
  }
@@ -4147,14 +4254,16 @@ ImageButton = (function(superClass) {
4147
4254
  if (!($img.hasClass('uploading') && $img.parent().length > 0)) {
4148
4255
  return;
4149
4256
  }
4150
- $img.removeData('file');
4151
- $img.removeClass('uploading').removeClass('loading');
4152
- $mask = $img.data('mask');
4153
- if ($mask) {
4154
- $mask.remove();
4155
- }
4156
- $img.removeData('mask');
4157
- $img.attr('src', _this.defaultImage);
4257
+ _this.loadImage($img, _this.defaultImage, function() {
4258
+ var $mask;
4259
+ $img.removeData('file');
4260
+ $img.removeClass('uploading').removeClass('loading');
4261
+ $mask = $img.data('mask');
4262
+ if ($mask) {
4263
+ $mask.remove();
4264
+ }
4265
+ return $img.removeData('mask');
4266
+ });
4158
4267
  if (_this.popover.active) {
4159
4268
  _this.popover.srcEl.prop('disabled', false);
4160
4269
  _this.popover.srcEl.val(_this.defaultImage);
@@ -4216,11 +4325,15 @@ ImageButton = (function(superClass) {
4216
4325
  $mask.remove();
4217
4326
  $img.removeData('mask');
4218
4327
  }
4219
- return callback(img);
4328
+ if ($.isFunction(callback)) {
4329
+ return callback(img);
4330
+ }
4220
4331
  };
4221
4332
  })(this);
4222
4333
  img.onerror = function() {
4223
- callback(false);
4334
+ if ($.isFunction(callback)) {
4335
+ callback(false);
4336
+ }
4224
4337
  $mask.remove();
4225
4338
  return $img.removeData('mask').removeClass('loading');
4226
4339
  };
@@ -4674,25 +4787,25 @@ TableButton = (function(superClass) {
4674
4787
  return _this.editor.body.find('.simditor-table td, .simditor-table th').removeClass('active');
4675
4788
  };
4676
4789
  })(this));
4677
- this.editor.inputManager.addKeystrokeHandler('38', 'td', (function(_this) {
4790
+ this.editor.keystroke.add('up', 'td', (function(_this) {
4678
4791
  return function(e, $node) {
4679
4792
  _this._tdNav($node, 'up');
4680
4793
  return true;
4681
4794
  };
4682
4795
  })(this));
4683
- this.editor.inputManager.addKeystrokeHandler('38', 'th', (function(_this) {
4796
+ this.editor.keystroke.add('up', 'th', (function(_this) {
4684
4797
  return function(e, $node) {
4685
4798
  _this._tdNav($node, 'up');
4686
4799
  return true;
4687
4800
  };
4688
4801
  })(this));
4689
- this.editor.inputManager.addKeystrokeHandler('40', 'td', (function(_this) {
4802
+ this.editor.keystroke.add('down', 'td', (function(_this) {
4690
4803
  return function(e, $node) {
4691
4804
  _this._tdNav($node, 'down');
4692
4805
  return true;
4693
4806
  };
4694
4807
  })(this));
4695
- return this.editor.inputManager.addKeystrokeHandler('40', 'th', (function(_this) {
4808
+ return this.editor.keystroke.add('down', 'th', (function(_this) {
4696
4809
  return function(e, $node) {
4697
4810
  _this._tdNav($node, 'down');
4698
4811
  return true;
@@ -4820,25 +4933,25 @@ TableButton = (function(superClass) {
4820
4933
  };
4821
4934
 
4822
4935
  TableButton.prototype._initShortcuts = function() {
4823
- this.editor.inputManager.addShortcut('ctrl+alt+up', (function(_this) {
4936
+ this.editor.hotkeys.add('ctrl+alt+up', (function(_this) {
4824
4937
  return function(e) {
4825
4938
  _this.editMenu.find('.menu-item[data-param=insertRowAbove]').click();
4826
4939
  return false;
4827
4940
  };
4828
4941
  })(this));
4829
- this.editor.inputManager.addShortcut('ctrl+alt+down', (function(_this) {
4942
+ this.editor.hotkeys.add('ctrl+alt+down', (function(_this) {
4830
4943
  return function(e) {
4831
4944
  _this.editMenu.find('.menu-item[data-param=insertRowBelow]').click();
4832
4945
  return false;
4833
4946
  };
4834
4947
  })(this));
4835
- this.editor.inputManager.addShortcut('ctrl+alt+left', (function(_this) {
4948
+ this.editor.hotkeys.add('ctrl+alt+left', (function(_this) {
4836
4949
  return function(e) {
4837
4950
  _this.editMenu.find('.menu-item[data-param=insertColLeft]').click();
4838
4951
  return false;
4839
4952
  };
4840
4953
  })(this));
4841
- return this.editor.inputManager.addShortcut('ctrl+alt+right', (function(_this) {
4954
+ return this.editor.hotkeys.add('ctrl+alt+right', (function(_this) {
4842
4955
  return function(e) {
4843
4956
  _this.editMenu.find('.menu-item[data-param=insertColRight]').click();
4844
4957
  return false;
@@ -118,14 +118,18 @@ $simditor-button-height: 40px;
118
118
  }
119
119
  }
120
120
 
121
- .simditor-paste-area,
122
- .simditor-clean-paste-area {
123
- background: transparent;
124
- border: none;
125
- outline: none;
126
- resize: none;
121
+ .simditor-paste-bin {
122
+ position: fixed;
123
+ bottom: 100px;
124
+ right: 100px;
125
+ width: 100px;
126
+ height: 100px;
127
+ font-size: 1px;
128
+ line-height: 1px;
129
+ overflow: hidden;
127
130
  padding: 0;
128
131
  margin: 0;
132
+ -webkit-user-select: text;
129
133
  }
130
134
 
131
135
  .simditor-toolbar {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simditor
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.4
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wentao Liu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-22 00:00:00.000000000 Z
11
+ date: 2015-10-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Rails assets wrapper for https://github.com/mycolorway/simditor
14
14
  email: