simditor 2.1.15 → 2.2.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.
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * Simditor v2.1.15
3
3
  * http://simditor.tower.im/
4
- * 2015-07-01
4
+ * 2015-07-28
5
5
  */
6
6
  (function (root, factory) {
7
7
  if (typeof define === 'function' && define.amd) {
@@ -34,48 +34,196 @@ Selection = (function(superClass) {
34
34
 
35
35
  Selection.pluginName = 'Selection';
36
36
 
37
+ Selection.prototype._range = null;
38
+
39
+ Selection.prototype._startNodes = null;
40
+
41
+ Selection.prototype._endNodes = null;
42
+
43
+ Selection.prototype._containerNode = null;
44
+
45
+ Selection.prototype._nodes = null;
46
+
47
+ Selection.prototype._blockNodes = null;
48
+
49
+ Selection.prototype._rootNodes = null;
50
+
37
51
  Selection.prototype._init = function() {
38
52
  this.editor = this._module;
39
- return this.sel = document.getSelection();
53
+ this._selection = document.getSelection();
54
+ this.editor.on('selectionchanged', (function(_this) {
55
+ return function(e) {
56
+ _this._reset();
57
+ return _this._range = _this._selection.getRangeAt(0);
58
+ };
59
+ })(this));
60
+ return this.editor.on('blur', (function(_this) {
61
+ return function(e) {
62
+ return _this.clear();
63
+ };
64
+ })(this));
65
+ };
66
+
67
+ Selection.prototype._reset = function() {
68
+ this._range = null;
69
+ this._startNodes = null;
70
+ this._endNodes = null;
71
+ this._containerNode = null;
72
+ this._nodes = null;
73
+ this._blockNodes = null;
74
+ return this._rootNodes = null;
40
75
  };
41
76
 
42
77
  Selection.prototype.clear = function() {
43
78
  var e;
44
79
  try {
45
- return this.sel.removeAllRanges();
80
+ this._selection.removeAllRanges();
46
81
  } catch (_error) {
47
82
  e = _error;
48
83
  }
84
+ return this._reset();
49
85
  };
50
86
 
51
- Selection.prototype.getRange = function() {
52
- if (!this.editor.inputManager.focused || !this.sel.rangeCount) {
53
- return null;
87
+ Selection.prototype.range = function(range) {
88
+ var ffOrIE;
89
+ if (range) {
90
+ this.clear();
91
+ this._selection.addRange(range);
92
+ this._range = range;
93
+ ffOrIE = this.editor.util.browser.firefox || this.editor.util.browser.msie;
94
+ if (!this.editor.inputManager.focused && ffOrIE) {
95
+ this.editor.body.focus();
96
+ }
97
+ } else if (!this._range && this.editor.inputManager.focused && this._selection.rangeCount) {
98
+ this._range = this._selection.getRangeAt(0);
54
99
  }
55
- return this.sel.getRangeAt(0);
100
+ return this._range;
56
101
  };
57
102
 
58
- Selection.prototype.selectRange = function(range) {
59
- this.clear();
60
- this.sel.addRange(range);
61
- if (!this.editor.inputManager.focused && (this.editor.util.browser.firefox || this.editor.util.browser.msie)) {
62
- this.editor.body.focus();
103
+ Selection.prototype.startNodes = function() {
104
+ if (this._range) {
105
+ this._startNodes || (this._startNodes = (function(_this) {
106
+ return function() {
107
+ var startNodes;
108
+ startNodes = $(_this._range.startContainer).parentsUntil(_this.editor.body).get();
109
+ startNodes.unshift(_this._range.startContainer);
110
+ return $(startNodes);
111
+ };
112
+ })(this)());
63
113
  }
64
- return range;
114
+ return this._startNodes;
115
+ };
116
+
117
+ Selection.prototype.endNodes = function() {
118
+ var endNodes;
119
+ if (this._range) {
120
+ this._endNodes || (this._endNodes = this._range.collapsed ? this.startNodes() : (endNodes = $(this._range.endContainer).parentsUntil(this.editor.body).get(), endNodes.unshift(this._range.endContainer), $(endNodes)));
121
+ }
122
+ return this._endNodes;
123
+ };
124
+
125
+ Selection.prototype.containerNode = function() {
126
+ if (this._range) {
127
+ this._containerNode || (this._containerNode = $(this._range.commonAncestorContainer));
128
+ }
129
+ return this._containerNode;
130
+ };
131
+
132
+ Selection.prototype.nodes = function() {
133
+ if (this._range) {
134
+ this._nodes || (this._nodes = (function(_this) {
135
+ return function() {
136
+ var nodes;
137
+ nodes = [];
138
+ if (_this.startNodes().first().is(_this.endNodes().first())) {
139
+ nodes = _this.startNodes().get();
140
+ } else {
141
+ _this.startNodes().each(function(i, node) {
142
+ var $endNode, $node, $nodes, endIndex, index, sharedIndex, startIndex;
143
+ $node = $(node);
144
+ if (_this.endNodes().index($node) > -1) {
145
+ return nodes.push(node);
146
+ } else if ($node.parent().is(_this.editor.body) || (sharedIndex = _this.endNodes().index($node.parent())) > -1) {
147
+ if (sharedIndex && sharedIndex > -1) {
148
+ $endNode = _this.endNodes().eq(sharedIndex - 1);
149
+ } else {
150
+ $endNode = _this.endNodes().last();
151
+ }
152
+ $nodes = $node.parent().contents();
153
+ startIndex = $nodes.index($node);
154
+ endIndex = $nodes.index($endNode);
155
+ return $.merge(nodes, $nodes.slice(startIndex, endIndex).get());
156
+ } else {
157
+ $nodes = $node.parent().contents();
158
+ index = $nodes.index($node);
159
+ return $.merge(nodes, $nodes.slice(index).get());
160
+ }
161
+ });
162
+ _this.endNodes().each(function(i, node) {
163
+ var $node, $nodes, index;
164
+ $node = $(node);
165
+ if ($node.parent().is(_this.editor.body) || _this.startNodes().index($node.parent()) > -1) {
166
+ nodes.push(node);
167
+ return false;
168
+ } else {
169
+ $nodes = $node.parent().contents();
170
+ index = $nodes.index($node);
171
+ return $.merge(nodes, $nodes.slice(0, index + 1));
172
+ }
173
+ });
174
+ }
175
+ return $($.unique(nodes));
176
+ };
177
+ })(this)());
178
+ }
179
+ return this._nodes;
180
+ };
181
+
182
+ Selection.prototype.blockNodes = function() {
183
+ if (!this._range) {
184
+ return;
185
+ }
186
+ this._blockNodes || (this._blockNodes = (function(_this) {
187
+ return function() {
188
+ return _this.nodes().filter(function(i, node) {
189
+ return _this.editor.util.isBlockNode(node);
190
+ });
191
+ };
192
+ })(this)());
193
+ return this._blockNodes;
194
+ };
195
+
196
+ Selection.prototype.rootNodes = function() {
197
+ if (!this._range) {
198
+ return;
199
+ }
200
+ this._rootNodes || (this._rootNodes = (function(_this) {
201
+ return function() {
202
+ return _this.nodes().filter(function(i, node) {
203
+ var $parent;
204
+ $parent = $(node).parent();
205
+ return $parent.is(_this.editor.body) || $parent.is('blockquote');
206
+ });
207
+ };
208
+ })(this)());
209
+ return this._rootNodes;
65
210
  };
66
211
 
67
212
  Selection.prototype.rangeAtEndOf = function(node, range) {
68
- var endNode, endNodeLength, result;
213
+ var afterLastNode, beforeLastNode, endNode, endNodeLength, lastNodeIsBr, result;
69
214
  if (range == null) {
70
- range = this.getRange();
215
+ range = this.range();
71
216
  }
72
- if (!((range != null) && range.collapsed)) {
217
+ if (!(range && range.collapsed)) {
73
218
  return;
74
219
  }
75
220
  node = $(node)[0];
76
221
  endNode = range.endContainer;
77
222
  endNodeLength = this.editor.util.getNodeLength(endNode);
78
- if (!(range.endOffset === endNodeLength - 1 && $(endNode).contents().last().is('br')) && range.endOffset !== endNodeLength) {
223
+ beforeLastNode = range.endOffset === endNodeLength - 1;
224
+ lastNodeIsBr = $(endNode).contents().last().is('br');
225
+ afterLastNode = range.endOffset === endNodeLength;
226
+ if (!((beforeLastNode && lastNodeIsBr) || afterLastNode)) {
79
227
  return false;
80
228
  }
81
229
  if (node === endNode) {
@@ -84,28 +232,28 @@ Selection = (function(superClass) {
84
232
  return false;
85
233
  }
86
234
  result = true;
87
- $(endNode).parentsUntil(node).addBack().each((function(_this) {
88
- return function(i, n) {
89
- var $lastChild, nodes;
90
- nodes = $(n).parent().contents().filter(function() {
91
- return !(this !== n && this.nodeType === 3 && !this.nodeValue);
92
- });
93
- $lastChild = nodes.last();
94
- if (!($lastChild.get(0) === n || ($lastChild.is('br') && $lastChild.prev().get(0) === n))) {
95
- result = false;
96
- return false;
97
- }
98
- };
99
- })(this));
235
+ $(endNode).parentsUntil(node).addBack().each(function(i, n) {
236
+ var $lastChild, beforeLastbr, isLastNode, nodes;
237
+ nodes = $(n).parent().contents().filter(function() {
238
+ return !(this !== n && this.nodeType === 3 && !this.nodeValue);
239
+ });
240
+ $lastChild = nodes.last();
241
+ isLastNode = $lastChild.get(0) === n;
242
+ beforeLastbr = $lastChild.is('br') && $lastChild.prev().get(0) === n;
243
+ if (!(isLastNode || beforeLastbr)) {
244
+ result = false;
245
+ return false;
246
+ }
247
+ });
100
248
  return result;
101
249
  };
102
250
 
103
251
  Selection.prototype.rangeAtStartOf = function(node, range) {
104
252
  var result, startNode;
105
253
  if (range == null) {
106
- range = this.getRange();
254
+ range = this.range();
107
255
  }
108
- if (!((range != null) && range.collapsed)) {
256
+ if (!(range && range.collapsed)) {
109
257
  return;
110
258
  }
111
259
  node = $(node)[0];
@@ -119,25 +267,23 @@ Selection = (function(superClass) {
119
267
  return false;
120
268
  }
121
269
  result = true;
122
- $(startNode).parentsUntil(node).addBack().each((function(_this) {
123
- return function(i, n) {
124
- var nodes;
125
- nodes = $(n).parent().contents().filter(function() {
126
- return !(this !== n && this.nodeType === 3 && !this.nodeValue);
127
- });
128
- if (nodes.first().get(0) !== n) {
129
- return result = false;
130
- }
131
- };
132
- })(this));
270
+ $(startNode).parentsUntil(node).addBack().each(function(i, n) {
271
+ var nodes;
272
+ nodes = $(n).parent().contents().filter(function() {
273
+ return !(this !== n && this.nodeType === 3 && !this.nodeValue);
274
+ });
275
+ if (nodes.first().get(0) !== n) {
276
+ return result = false;
277
+ }
278
+ });
133
279
  return result;
134
280
  };
135
281
 
136
282
  Selection.prototype.insertNode = function(node, range) {
137
283
  if (range == null) {
138
- range = this.getRange();
284
+ range = this.range();
139
285
  }
140
- if (range == null) {
286
+ if (!range) {
141
287
  return;
142
288
  }
143
289
  node = $(node)[0];
@@ -147,7 +293,7 @@ Selection = (function(superClass) {
147
293
 
148
294
  Selection.prototype.setRangeAfter = function(node, range) {
149
295
  if (range == null) {
150
- range = this.getRange();
296
+ range = this.range();
151
297
  }
152
298
  if (range == null) {
153
299
  return;
@@ -155,12 +301,12 @@ Selection = (function(superClass) {
155
301
  node = $(node)[0];
156
302
  range.setEndAfter(node);
157
303
  range.collapse(false);
158
- return this.selectRange(range);
304
+ return this.range(range);
159
305
  };
160
306
 
161
307
  Selection.prototype.setRangeBefore = function(node, range) {
162
308
  if (range == null) {
163
- range = this.getRange();
309
+ range = this.range();
164
310
  }
165
311
  if (range == null) {
166
312
  return;
@@ -168,35 +314,36 @@ Selection = (function(superClass) {
168
314
  node = $(node)[0];
169
315
  range.setEndBefore(node);
170
316
  range.collapse(false);
171
- return this.selectRange(range);
317
+ return this.range(range);
172
318
  };
173
319
 
174
320
  Selection.prototype.setRangeAtStartOf = function(node, range) {
175
321
  if (range == null) {
176
- range = this.getRange();
322
+ range = this.range();
177
323
  }
178
324
  node = $(node).get(0);
179
325
  range.setEnd(node, 0);
180
326
  range.collapse(false);
181
- return this.selectRange(range);
327
+ return this.range(range);
182
328
  };
183
329
 
184
330
  Selection.prototype.setRangeAtEndOf = function(node, range) {
185
- var $lastNode, $node, contents, lastChild, lastText, nodeLength;
331
+ var $lastNode, $node, contents, lastChild, lastChildLength, lastText, nodeLength;
186
332
  if (range == null) {
187
- range = this.getRange();
333
+ range = this.range();
188
334
  }
189
335
  $node = $(node);
190
- node = $node.get(0);
336
+ node = $node[0];
191
337
  if ($node.is('pre')) {
192
338
  contents = $node.contents();
193
339
  if (contents.length > 0) {
194
340
  lastChild = contents.last();
195
341
  lastText = lastChild.text();
342
+ lastChildLength = this.editor.util.getNodeLength(lastChild[0]);
196
343
  if (lastText.charAt(lastText.length - 1) === '\n') {
197
- range.setEnd(lastChild[0], this.editor.util.getNodeLength(lastChild[0]) - 1);
344
+ range.setEnd(lastChild[0], lastChildLength - 1);
198
345
  } else {
199
- range.setEnd(lastChild[0], this.editor.util.getNodeLength(lastChild[0]));
346
+ range.setEnd(lastChild[0], lastChildLength);
200
347
  }
201
348
  } else {
202
349
  range.setEnd(node, 0);
@@ -216,23 +363,25 @@ Selection = (function(superClass) {
216
363
  range.setEnd(node, nodeLength);
217
364
  }
218
365
  range.collapse(false);
219
- return this.selectRange(range);
366
+ return this.range(range);
220
367
  };
221
368
 
222
369
  Selection.prototype.deleteRangeContents = function(range) {
223
- var endRange, startRange;
370
+ var atEndOfBody, atStartOfBody, endRange, startRange;
224
371
  if (range == null) {
225
- range = this.getRange();
372
+ range = this.range();
226
373
  }
227
374
  startRange = range.cloneRange();
228
375
  endRange = range.cloneRange();
229
376
  startRange.collapse(true);
230
377
  endRange.collapse(false);
231
- if (!range.collapsed && this.rangeAtStartOf(this.editor.body, startRange) && this.rangeAtEndOf(this.editor.body, endRange)) {
378
+ atStartOfBody = this.rangeAtStartOf(this.editor.body, startRange);
379
+ atEndOfBody = this.rangeAtEndOf(this.editor.body, endRange);
380
+ if (!range.collapsed && atStartOfBody && atEndOfBody) {
232
381
  this.editor.body.empty();
233
382
  range.setStart(this.editor.body[0], 0);
234
383
  range.collapse(true);
235
- this.selectRange(range);
384
+ this.range(range);
236
385
  } else {
237
386
  range.deleteContents();
238
387
  }
@@ -242,7 +391,7 @@ Selection = (function(superClass) {
242
391
  Selection.prototype.breakBlockEl = function(el, range) {
243
392
  var $el;
244
393
  if (range == null) {
245
- range = this.getRange();
394
+ range = this.range();
246
395
  }
247
396
  $el = $(el);
248
397
  if (!range.collapsed) {
@@ -258,7 +407,7 @@ Selection = (function(superClass) {
258
407
  Selection.prototype.save = function(range) {
259
408
  var endCaret, endRange, startCaret;
260
409
  if (range == null) {
261
- range = this.getRange();
410
+ range = this.range();
262
411
  }
263
412
  if (this._selectionSaved) {
264
413
  return;
@@ -293,7 +442,7 @@ Selection = (function(superClass) {
293
442
  range.setEnd(endContainer.get(0), endOffset);
294
443
  startCaret.remove();
295
444
  endCaret.remove();
296
- this.selectRange(range);
445
+ this.range(range);
297
446
  } else {
298
447
  startCaret.remove();
299
448
  endCaret.remove();
@@ -316,26 +465,28 @@ Formatter = (function(superClass) {
316
465
  Formatter.pluginName = 'Formatter';
317
466
 
318
467
  Formatter.prototype.opts = {
319
- allowedTags: null,
320
- allowedAttributes: null
468
+ allowedTags: [],
469
+ allowedAttributes: {},
470
+ allowedStyles: {}
321
471
  };
322
472
 
323
473
  Formatter.prototype._init = function() {
324
474
  this.editor = this._module;
325
- this._allowedTags = this.opts.allowedTags || ['br', 'a', 'img', 'b', 'strong', 'i', 'u', 'font', 'p', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'h1', 'h2', 'h3', 'h4', 'hr'];
326
- this._allowedAttributes = this.opts.allowedAttributes || {
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);
476
+ this._allowedAttributes = $.extend({
327
477
  img: ['src', 'alt', 'width', 'height', 'data-non-image'],
328
478
  a: ['href', 'target'],
329
479
  font: ['color'],
330
480
  code: ['class']
331
- };
332
- this._allowedStyles = this.opts.allowedStyles || {
481
+ }, this.opts.allowedAttributes);
482
+ this._allowedStyles = $.extend({
483
+ span: ['color'],
333
484
  p: ['margin-left', 'text-align'],
334
- h1: ['margin-left'],
335
- h2: ['margin-left'],
336
- h3: ['margin-left'],
337
- h4: ['margin-left']
338
- };
485
+ h1: ['margin-left', 'text-align'],
486
+ h2: ['margin-left', 'text-align'],
487
+ h3: ['margin-left', 'text-align'],
488
+ h4: ['margin-left', 'text-align']
489
+ }, this.opts.allowedStyles);
339
490
  return this.editor.body.on('click', 'a', function(e) {
340
491
  return false;
341
492
  });
@@ -345,7 +496,8 @@ Formatter = (function(superClass) {
345
496
  if ($el == null) {
346
497
  $el = this.editor.body;
347
498
  }
348
- return this.editor.trigger('decorate', [$el]);
499
+ this.editor.trigger('decorate', [$el]);
500
+ return $el;
349
501
  };
350
502
 
351
503
  Formatter.prototype.undecorate = function($el) {
@@ -353,11 +505,11 @@ Formatter = (function(superClass) {
353
505
  $el = this.editor.body.clone();
354
506
  }
355
507
  this.editor.trigger('undecorate', [$el]);
356
- return $.trim($el.html());
508
+ return $el;
357
509
  };
358
510
 
359
511
  Formatter.prototype.autolink = function($el) {
360
- var $link, $node, findLinkNode, j, lastIndex, len, linkNodes, match, re, replaceEls, subStr, text, uri;
512
+ var $link, $node, findLinkNode, k, lastIndex, len, linkNodes, match, re, replaceEls, subStr, text, uri;
361
513
  if ($el == null) {
362
514
  $el = this.editor.body;
363
515
  }
@@ -369,7 +521,7 @@ Formatter = (function(superClass) {
369
521
  if ($node.is('a') || $node.closest('a, pre', $el).length) {
370
522
  return;
371
523
  }
372
- if ($node.contents().length) {
524
+ if (!$node.is('iframe') && $node.contents().length) {
373
525
  return findLinkNode($node);
374
526
  } else if ((text = $node.text()) && /https?:\/\/|www\./ig.test(text)) {
375
527
  return linkNodes.push($node);
@@ -378,8 +530,8 @@ Formatter = (function(superClass) {
378
530
  };
379
531
  findLinkNode($el);
380
532
  re = /(https?:\/\/|www\.)[\w\-\.\?&=\/#%:,@\!\+]+/ig;
381
- for (j = 0, len = linkNodes.length; j < len; j++) {
382
- $node = linkNodes[j];
533
+ for (k = 0, len = linkNodes.length; k < len; k++) {
534
+ $node = linkNodes[k];
383
535
  text = $node.text();
384
536
  replaceEls = [];
385
537
  match = null;
@@ -399,7 +551,7 @@ Formatter = (function(superClass) {
399
551
  };
400
552
 
401
553
  Formatter.prototype.format = function($el) {
402
- var $node, blockNode, j, k, len, len1, n, node, ref, ref1;
554
+ var $node, blockNode, k, l, len, len1, n, node, ref, ref1;
403
555
  if ($el == null) {
404
556
  $el = this.editor.body;
405
557
  }
@@ -408,13 +560,13 @@ Formatter = (function(superClass) {
408
560
  return $el;
409
561
  }
410
562
  ref = $el.contents();
411
- for (j = 0, len = ref.length; j < len; j++) {
412
- n = ref[j];
563
+ for (k = 0, len = ref.length; k < len; k++) {
564
+ n = ref[k];
413
565
  this.cleanNode(n, true);
414
566
  }
415
567
  ref1 = $el.contents();
416
- for (k = 0, len1 = ref1.length; k < len1; k++) {
417
- node = ref1[k];
568
+ for (l = 0, len1 = ref1.length; l < len1; l++) {
569
+ node = ref1[l];
418
570
  $node = $(node);
419
571
  if ($node.is('br')) {
420
572
  if (typeof blockNode !== "undefined" && blockNode !== null) {
@@ -443,7 +595,7 @@ Formatter = (function(superClass) {
443
595
  };
444
596
 
445
597
  Formatter.prototype.cleanNode = function(node, recursive) {
446
- var $childImg, $node, $p, $td, allowedAttributes, attr, contents, isDecoration, j, k, len, len1, n, ref, ref1, text, textNode;
598
+ var $childImg, $node, $p, $td, allowedAttributes, attr, contents, isDecoration, k, l, len, len1, n, ref, ref1, text, textNode;
447
599
  $node = $(node);
448
600
  if (!($node.length > 0)) {
449
601
  return;
@@ -458,8 +610,8 @@ Formatter = (function(superClass) {
458
610
  }
459
611
  return;
460
612
  }
461
- contents = $node.contents();
462
- isDecoration = $node.is('[class^="simditor-"]');
613
+ contents = $node.is('iframe') ? null : $node.contents();
614
+ isDecoration = this.editor.util.isDecoratedNode($node);
463
615
  if ($node.is(this._allowedTags.join(',')) || isDecoration) {
464
616
  if ($node.is('a') && ($childImg = $node.find('img')).length > 0) {
465
617
  $node.replaceWith($childImg);
@@ -472,15 +624,18 @@ Formatter = (function(superClass) {
472
624
  if (!isDecoration) {
473
625
  allowedAttributes = this._allowedAttributes[$node[0].tagName.toLowerCase()];
474
626
  ref = $.makeArray($node[0].attributes);
475
- for (j = 0, len = ref.length; j < len; j++) {
476
- attr = ref[j];
627
+ for (k = 0, len = ref.length; k < len; k++) {
628
+ attr = ref[k];
477
629
  if (attr.name === 'style') {
478
630
  continue;
479
631
  }
480
632
  if (!((allowedAttributes != null) && (ref1 = attr.name, indexOf.call(allowedAttributes, ref1) >= 0))) {
481
633
  $node.removeAttr(attr.name);
482
634
  }
483
- this._cleanNodeStyles($node);
635
+ }
636
+ this._cleanNodeStyles($node);
637
+ if ($node.is('span') && $node[0].attributes.length === 0) {
638
+ $node.contents().first().unwrap();
484
639
  }
485
640
  }
486
641
  } else if ($node[0].nodeType === 1 && !$node.is(':empty')) {
@@ -508,8 +663,8 @@ Formatter = (function(superClass) {
508
663
  contents = null;
509
664
  }
510
665
  if (recursive && (contents != null) && !$node.is('pre')) {
511
- for (k = 0, len1 = contents.length; k < len1; k++) {
512
- n = contents[k];
666
+ for (l = 0, len1 = contents.length; l < len1; l++) {
667
+ n = contents[l];
513
668
  this.cleanNode(n, true);
514
669
  }
515
670
  }
@@ -517,7 +672,7 @@ Formatter = (function(superClass) {
517
672
  };
518
673
 
519
674
  Formatter.prototype._cleanNodeStyles = function($node) {
520
- var allowedStyles, j, len, pair, ref, ref1, style, styleStr, styles;
675
+ var allowedStyles, k, len, pair, ref, ref1, style, styleStr, styles;
521
676
  styleStr = $node.attr('style');
522
677
  if (!styleStr) {
523
678
  return;
@@ -529,8 +684,8 @@ Formatter = (function(superClass) {
529
684
  }
530
685
  styles = {};
531
686
  ref = styleStr.split(';');
532
- for (j = 0, len = ref.length; j < len; j++) {
533
- style = ref[j];
687
+ for (k = 0, len = ref.length; k < len; k++) {
688
+ style = ref[k];
534
689
  style = $.trim(style);
535
690
  pair = style.split(':');
536
691
  if (!(pair.length = 2)) {
@@ -561,8 +716,8 @@ Formatter = (function(superClass) {
561
716
  return result += node.nodeValue;
562
717
  } else if (node.nodeType === 1) {
563
718
  $node = $(node);
564
- children = $node.contents();
565
- if (children.length > 0) {
719
+ children = $node.is('iframe') ? null : $node.contents();
720
+ if (children && children.length > 0) {
566
721
  result += _this.clearHtml(children);
567
722
  }
568
723
  if (lineBreak && i < contents.length - 1 && $node.is('br, p, div, li,tr, pre, address, artticle, aside, dl, figcaption, footer, h1, h2,h3, h4, header')) {
@@ -614,16 +769,18 @@ InputManager = (function(superClass) {
614
769
  InputManager.prototype._init = function() {
615
770
  var submitKey;
616
771
  this.editor = this._module;
617
- this.throttledTrigger = this.editor.util.throttle((function(_this) {
618
- return function() {
619
- var args;
620
- args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
772
+ this.throttledValueChanged = this.editor.util.throttle((function(_this) {
773
+ return function(params) {
621
774
  return setTimeout(function() {
622
- var ref;
623
- return (ref = _this.editor).trigger.apply(ref, args);
775
+ return _this.editor.trigger('valuechanged', params);
624
776
  }, 10);
625
777
  };
626
778
  })(this), 300);
779
+ this.throttledSelectionChanged = this.editor.util.throttle((function(_this) {
780
+ return function() {
781
+ return _this.editor.trigger('selectionchanged');
782
+ };
783
+ })(this), 50);
627
784
  if (this.opts.pasteImage && typeof this.opts.pasteImage !== 'string') {
628
785
  this.opts.pasteImage = 'inline';
629
786
  }
@@ -647,18 +804,13 @@ InputManager = (function(superClass) {
647
804
  if (!_this.focused) {
648
805
  return;
649
806
  }
650
- if (_this._selectionTimer) {
651
- clearTimeout(_this._selectionTimer);
652
- _this._selectionTimer = null;
653
- }
654
- return _this._selectionTimer = setTimeout(function() {
655
- return _this.editor.trigger('selectionchanged');
656
- }, 20);
807
+ return _this.throttledSelectionChanged();
657
808
  };
658
809
  })(this));
659
810
  this.editor.on('valuechanged', (function(_this) {
660
811
  return function() {
661
- if (!_this.editor.util.closestBlockEl() && _this.focused) {
812
+ _this.lastCaretPosition = null;
813
+ if (_this.focused && !_this.editor.selection.blockNodes().length) {
662
814
  _this.editor.selection.save();
663
815
  _this.editor.formatter.format();
664
816
  _this.editor.selection.restore();
@@ -677,36 +829,29 @@ InputManager = (function(superClass) {
677
829
  formatted = true;
678
830
  }
679
831
  if (formatted) {
680
- return setTimeout(function() {
681
- return _this.editor.trigger('valuechanged');
682
- }, 10);
832
+ return _this.throttledValueChanged();
683
833
  }
684
834
  }
685
835
  });
686
836
  _this.editor.body.find('pre:empty').append(_this.editor.util.phBr);
687
837
  if (!_this.editor.util.support.onselectionchange && _this.focused) {
688
- return _this.editor.trigger('selectionchanged');
838
+ return _this.throttledValueChanged();
689
839
  }
690
840
  };
691
841
  })(this));
692
- this.editor.on('selectionchanged', (function(_this) {
693
- return function(e) {
694
- return _this.editor.undoManager.update();
695
- };
696
- })(this));
697
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));
698
843
  if (this.editor.util.browser.firefox) {
699
844
  this.addShortcut('cmd+left', (function(_this) {
700
845
  return function(e) {
701
846
  e.preventDefault();
702
- _this.editor.selection.sel.modify('move', 'backward', 'lineboundary');
847
+ _this.editor.selection._selection.modify('move', 'backward', 'lineboundary');
703
848
  return false;
704
849
  };
705
850
  })(this));
706
851
  this.addShortcut('cmd+right', (function(_this) {
707
852
  return function(e) {
708
853
  e.preventDefault();
709
- _this.editor.selection.sel.modify('move', 'forward', 'lineboundary');
854
+ _this.editor.selection._selection.modify('move', 'forward', 'lineboundary');
710
855
  return false;
711
856
  };
712
857
  })(this));
@@ -722,7 +867,7 @@ InputManager = (function(superClass) {
722
867
  range = document.createRange();
723
868
  range.setStart(firstBlock, 0);
724
869
  range.setEnd(lastBlock, _this.editor.util.getNodeLength(lastBlock));
725
- _this.editor.selection.selectRange(range);
870
+ _this.editor.selection.range(range);
726
871
  return false;
727
872
  };
728
873
  })(this));
@@ -750,7 +895,9 @@ InputManager = (function(superClass) {
750
895
  return setTimeout((function(_this) {
751
896
  return function() {
752
897
  _this.editor.triggerHandler('focus');
753
- return _this.editor.trigger('selectionchanged');
898
+ if (!_this.editor.util.support.onselectionchange) {
899
+ return _this.throttledSelectionChanged();
900
+ }
754
901
  };
755
902
  })(this), 0);
756
903
  };
@@ -766,11 +913,7 @@ InputManager = (function(superClass) {
766
913
 
767
914
  InputManager.prototype._onMouseUp = function(e) {
768
915
  if (!this.editor.util.support.onselectionchange) {
769
- return setTimeout((function(_this) {
770
- return function() {
771
- return _this.editor.trigger('selectionchanged');
772
- };
773
- })(this), 0);
916
+ return this.throttledSelectionChanged();
774
917
  }
775
918
  };
776
919
 
@@ -785,13 +928,13 @@ InputManager = (function(superClass) {
785
928
  if (e.which in this._keystrokeHandlers) {
786
929
  result = typeof (base = this._keystrokeHandlers[e.which])['*'] === "function" ? base['*'](e) : void 0;
787
930
  if (result) {
788
- this.editor.trigger('valuechanged');
931
+ this.throttledValueChanged();
789
932
  return false;
790
933
  }
791
- this.editor.util.traverseUp((function(_this) {
792
- return function(node) {
934
+ this.editor.selection.startNodes().each((function(_this) {
935
+ return function(i, node) {
793
936
  var handler, ref;
794
- if (node.nodeType !== document.ELEMENT_NODE) {
937
+ if (node.nodeType !== Node.ELEMENT_NODE) {
795
938
  return;
796
939
  }
797
940
  handler = (ref = _this._keystrokeHandlers[e.which]) != null ? ref[node.tagName.toLowerCase()] : void 0;
@@ -802,7 +945,7 @@ InputManager = (function(superClass) {
802
945
  };
803
946
  })(this));
804
947
  if (result) {
805
- this.editor.trigger('valuechanged');
948
+ this.throttledValueChanged();
806
949
  return false;
807
950
  }
808
951
  }
@@ -813,7 +956,7 @@ InputManager = (function(superClass) {
813
956
  return;
814
957
  }
815
958
  if (!this.editor.util.support.oninput) {
816
- this.throttledTrigger('valuechanged', ['typing']);
959
+ this.throttledValueChanged(['typing']);
817
960
  }
818
961
  return null;
819
962
  };
@@ -830,7 +973,7 @@ InputManager = (function(superClass) {
830
973
  return false;
831
974
  }
832
975
  if (!this.editor.util.support.onselectionchange && (ref = e.which, indexOf.call(this._arrowKeys, ref) >= 0)) {
833
- this.editor.trigger('selectionchanged');
976
+ this.throttledValueChanged();
834
977
  return;
835
978
  }
836
979
  if ((e.which === 8 || e.which === 46) && this.editor.util.isEmptyNode(this.editor.body)) {
@@ -849,7 +992,8 @@ InputManager = (function(superClass) {
849
992
  if (!range.collapsed) {
850
993
  range.collapse(true);
851
994
  }
852
- $blockEl = this.editor.util.closestBlockEl();
995
+ this.editor.selection.range(range);
996
+ $blockEl = this.editor.selection.blockNodes().last();
853
997
  cleanPaste = $blockEl.is('pre, table');
854
998
  if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.items && e.originalEvent.clipboardData.items.length > 0) {
855
999
  pasteItem = e.originalEvent.clipboardData.items[0];
@@ -871,7 +1015,7 @@ InputManager = (function(superClass) {
871
1015
  }
872
1016
  processPasteContent = (function(_this) {
873
1017
  return function(pasteContent) {
874
- var $img, blob, children, insertPosition, j, k, l, lastLine, len, len1, len2, len3, len4, line, lines, m, node, o, ref1, ref2, ref3;
1018
+ var $img, blob, children, insertPosition, k, l, lastLine, len, len1, len2, len3, len4, line, lines, m, node, o, q, ref1, ref2, ref3;
875
1019
  if (_this.editor.triggerHandler('pasting', [pasteContent]) === false) {
876
1020
  return;
877
1021
  }
@@ -881,8 +1025,8 @@ InputManager = (function(superClass) {
881
1025
  if ($blockEl.is('table')) {
882
1026
  lines = pasteContent.split('\n');
883
1027
  lastLine = lines.pop();
884
- for (j = 0, len = lines.length; j < len; j++) {
885
- line = lines[j];
1028
+ for (k = 0, len = lines.length; k < len; k++) {
1029
+ line = lines[k];
886
1030
  _this.editor.selection.insertNode(document.createTextNode(line));
887
1031
  _this.editor.selection.insertNode($('<br/>'));
888
1032
  }
@@ -890,14 +1034,14 @@ InputManager = (function(superClass) {
890
1034
  } else {
891
1035
  pasteContent = $('<div/>').text(pasteContent);
892
1036
  ref1 = pasteContent.contents();
893
- for (k = 0, len1 = ref1.length; k < len1; k++) {
894
- node = ref1[k];
1037
+ for (l = 0, len1 = ref1.length; l < len1; l++) {
1038
+ node = ref1[l];
895
1039
  _this.editor.selection.insertNode($(node)[0], range);
896
1040
  }
897
1041
  }
898
1042
  } else if ($blockEl.is(_this.editor.body)) {
899
- for (l = 0, len2 = pasteContent.length; l < len2; l++) {
900
- node = pasteContent[l];
1043
+ for (m = 0, len2 = pasteContent.length; m < len2; m++) {
1044
+ node = pasteContent[m];
901
1045
  _this.editor.selection.insertNode(node, range);
902
1046
  }
903
1047
  } else if (pasteContent.length < 1) {
@@ -923,8 +1067,8 @@ InputManager = (function(superClass) {
923
1067
  return;
924
1068
  }
925
1069
  }
926
- for (m = 0, len3 = children.length; m < len3; m++) {
927
- node = children[m];
1070
+ for (o = 0, len3 = children.length; o < len3; o++) {
1071
+ node = children[o];
928
1072
  _this.editor.selection.insertNode(node, range);
929
1073
  }
930
1074
  } else if ($blockEl.is('p') && _this.editor.util.isEmptyNode($blockEl)) {
@@ -934,8 +1078,8 @@ InputManager = (function(superClass) {
934
1078
  if (pasteContent.find('li').length === 1) {
935
1079
  pasteContent = $('<div/>').text(pasteContent.text());
936
1080
  ref3 = pasteContent.contents();
937
- for (o = 0, len4 = ref3.length; o < len4; o++) {
938
- node = ref3[o];
1081
+ for (q = 0, len4 = ref3.length; q < len4; q++) {
1082
+ node = ref3[q];
939
1083
  _this.editor.selection.insertNode($(node)[0], range);
940
1084
  }
941
1085
  } else if ($blockEl.is('li')) {
@@ -964,7 +1108,7 @@ InputManager = (function(superClass) {
964
1108
  $blockEl[insertPosition](pasteContent);
965
1109
  _this.editor.selection.setRangeAtEndOf(pasteContent.last(), range);
966
1110
  }
967
- return _this.editor.trigger('valuechanged');
1111
+ return _this.throttledValueChanged();
968
1112
  };
969
1113
  })(this);
970
1114
  if (cleanPaste) {
@@ -1006,15 +1150,11 @@ InputManager = (function(superClass) {
1006
1150
  if (this.editor.triggerHandler(e) === false) {
1007
1151
  return false;
1008
1152
  }
1009
- return setTimeout((function(_this) {
1010
- return function() {
1011
- return _this.editor.trigger('valuechanged');
1012
- };
1013
- })(this), 0);
1153
+ return this.throttledValueChanged();
1014
1154
  };
1015
1155
 
1016
1156
  InputManager.prototype._onInput = function(e) {
1017
- return this.throttledTrigger('valuechanged', ['oninput']);
1157
+ return this.throttledValueChanged(['oninput']);
1018
1158
  };
1019
1159
 
1020
1160
  InputManager.prototype.addKeystrokeHandler = function(key, node, handler) {
@@ -1051,7 +1191,7 @@ Keystroke = (function(superClass) {
1051
1191
  if (!e.shiftKey) {
1052
1192
  return;
1053
1193
  }
1054
- $blockEl = _this.editor.util.closestBlockEl();
1194
+ $blockEl = _this.editor.selection.blockNodes().last();
1055
1195
  if ($blockEl.is('pre')) {
1056
1196
  return;
1057
1197
  }
@@ -1088,8 +1228,8 @@ Keystroke = (function(superClass) {
1088
1228
  }
1089
1229
  this.editor.inputManager.addKeystrokeHandler('8', '*', (function(_this) {
1090
1230
  return function(e) {
1091
- var $blockEl, $prevBlockEl, $rootBlock;
1092
- $rootBlock = _this.editor.util.furthestBlockEl();
1231
+ var $blockEl, $prevBlockEl, $rootBlock, isWebkit;
1232
+ $rootBlock = _this.editor.selection.rootNodes().first();
1093
1233
  $prevBlockEl = $rootBlock.prev();
1094
1234
  if ($prevBlockEl.is('hr') && _this.editor.selection.rangeAtStartOf($rootBlock)) {
1095
1235
  _this.editor.selection.save();
@@ -1097,8 +1237,9 @@ Keystroke = (function(superClass) {
1097
1237
  _this.editor.selection.restore();
1098
1238
  return true;
1099
1239
  }
1100
- $blockEl = _this.editor.util.closestBlockEl();
1101
- if (_this.editor.util.browser.webkit && _this.editor.selection.rangeAtStartOf($blockEl)) {
1240
+ $blockEl = _this.editor.selection.blockNodes().last();
1241
+ isWebkit = _this.editor.util.browser.webkit;
1242
+ if (isWebkit && _this.editor.selection.rangeAtStartOf($blockEl)) {
1102
1243
  _this.editor.selection.save();
1103
1244
  _this.editor.formatter.cleanNode($blockEl, true);
1104
1245
  _this.editor.selection.restore();
@@ -1111,7 +1252,7 @@ Keystroke = (function(superClass) {
1111
1252
  var $cloneNode, listEl, newBlockEl, newListEl;
1112
1253
  $cloneNode = $node.clone();
1113
1254
  $cloneNode.find('ul, ol').remove();
1114
- if (!(_this.editor.util.isEmptyNode($cloneNode) && $node.is(_this.editor.util.closestBlockEl()))) {
1255
+ if (!(_this.editor.util.isEmptyNode($cloneNode) && $node.is(_this.editor.selection.blockNodes().last()))) {
1115
1256
  return;
1116
1257
  }
1117
1258
  listEl = $node.parent();
@@ -1161,7 +1302,7 @@ Keystroke = (function(superClass) {
1161
1302
  _this.editor.selection.setRangeAtStartOf($p);
1162
1303
  return true;
1163
1304
  }
1164
- range = _this.editor.selection.getRange();
1305
+ range = _this.editor.selection.range();
1165
1306
  breakNode = null;
1166
1307
  range.deleteContents();
1167
1308
  if (!_this.editor.util.browser.msie && _this.editor.selection.rangeAtEndOf($node)) {
@@ -1174,14 +1315,14 @@ Keystroke = (function(superClass) {
1174
1315
  range.setStartAfter(breakNode);
1175
1316
  }
1176
1317
  range.collapse(false);
1177
- _this.editor.selection.selectRange(range);
1318
+ _this.editor.selection.range(range);
1178
1319
  return true;
1179
1320
  };
1180
1321
  })(this));
1181
1322
  this.editor.inputManager.addKeystrokeHandler('13', 'blockquote', (function(_this) {
1182
1323
  return function(e, $node) {
1183
1324
  var $closestBlock, range;
1184
- $closestBlock = _this.editor.util.closestBlockEl();
1325
+ $closestBlock = _this.editor.selection.blockNodes().last();
1185
1326
  if (!($closestBlock.is('p') && !$closestBlock.next().length && _this.editor.util.isEmptyNode($closestBlock))) {
1186
1327
  return;
1187
1328
  }
@@ -1193,7 +1334,7 @@ Keystroke = (function(superClass) {
1193
1334
  })(this));
1194
1335
  this.editor.inputManager.addKeystrokeHandler('8', 'li', (function(_this) {
1195
1336
  return function(e, $node) {
1196
- var $br, $childList, $newLi, $prevChildList, $prevNode, $textNode, range, text;
1337
+ var $br, $childList, $newLi, $prevChildList, $prevNode, $textNode, isFF, range, text;
1197
1338
  $childList = $node.children('ul, ol');
1198
1339
  $prevNode = $node.prev('li');
1199
1340
  if (!($childList.length > 0 && $prevNode.length > 0)) {
@@ -1215,7 +1356,8 @@ Keystroke = (function(superClass) {
1215
1356
  }
1216
1357
  return $textNode = $(n);
1217
1358
  });
1218
- if ($textNode && text.length === 1 && _this.editor.util.browser.firefox && !$textNode.next('br').length) {
1359
+ isFF = _this.editor.util.browser.firefox && !$textNode.next('br').length;
1360
+ if ($textNode && text.length === 1 && isFF) {
1219
1361
  $br = $(_this.editor.util.phBr).insertAfter($textNode);
1220
1362
  $textNode.remove();
1221
1363
  _this.editor.selection.setRangeBefore($br);
@@ -1234,7 +1376,7 @@ Keystroke = (function(superClass) {
1234
1376
  _this.editor.selection.setRangeAtEndOf($prevNode, range);
1235
1377
  $prevNode.append($childList);
1236
1378
  $node.remove();
1237
- _this.editor.selection.selectRange(range);
1379
+ _this.editor.selection.range(range);
1238
1380
  }
1239
1381
  return true;
1240
1382
  };
@@ -1245,8 +1387,8 @@ Keystroke = (function(superClass) {
1245
1387
  if (!_this.editor.selection.rangeAtStartOf($node)) {
1246
1388
  return;
1247
1389
  }
1248
- codeStr = $node.html().replace('\n', '<br/>');
1249
- $newNode = $('<p/>').append(codeStr || _this.editor.util.phBr).insertAfter($node);
1390
+ codeStr = $node.html().replace('\n', '<br/>') || _this.editor.util.phBr;
1391
+ $newNode = $('<p/>').append(codeStr).insertAfter($node);
1250
1392
  $node.remove();
1251
1393
  range = document.createRange();
1252
1394
  _this.editor.selection.setRangeAtStartOf($newNode, range);
@@ -1282,12 +1424,14 @@ UndoManager = (function(superClass) {
1282
1424
 
1283
1425
  UndoManager.prototype._index = -1;
1284
1426
 
1285
- UndoManager.prototype._capacity = 50;
1427
+ UndoManager.prototype._capacity = 20;
1428
+
1429
+ UndoManager.prototype._startPosition = null;
1286
1430
 
1287
- UndoManager.prototype._timer = null;
1431
+ UndoManager.prototype._endPosition = null;
1288
1432
 
1289
1433
  UndoManager.prototype._init = function() {
1290
- var redoShortcut, undoShortcut;
1434
+ var redoShortcut, throttledPushState, undoShortcut;
1291
1435
  this.editor = this._module;
1292
1436
  this._stack = [];
1293
1437
  if (this.editor.util.os.mac) {
@@ -1314,23 +1458,55 @@ UndoManager = (function(superClass) {
1314
1458
  return false;
1315
1459
  };
1316
1460
  })(this));
1317
- return this.editor.on('valuechanged', (function(_this) {
1318
- return function(e, src) {
1319
- if (src === 'undo' || src === 'redo') {
1320
- return;
1321
- }
1322
- if (_this._timer) {
1323
- clearTimeout(_this._timer);
1324
- _this._timer = null;
1325
- }
1326
- return _this._timer = setTimeout(function() {
1327
- _this._pushUndoState();
1328
- return _this._timer = null;
1329
- }, 200);
1461
+ throttledPushState = this.editor.util.throttle((function(_this) {
1462
+ return function() {
1463
+ return _this._pushUndoState();
1464
+ };
1465
+ })(this), 500);
1466
+ this.editor.on('valuechanged', function(e, src) {
1467
+ if (src === 'undo' || src === 'redo') {
1468
+ return;
1469
+ }
1470
+ return throttledPushState();
1471
+ });
1472
+ this.editor.on('selectionchanged', (function(_this) {
1473
+ return function(e) {
1474
+ _this._startPosition = null;
1475
+ _this._endPosition = null;
1476
+ return _this.update();
1477
+ };
1478
+ })(this));
1479
+ return this.editor.on('blur', (function(_this) {
1480
+ return function(e) {
1481
+ _this._startPosition = null;
1482
+ return _this._endPosition = null;
1330
1483
  };
1331
1484
  })(this));
1332
1485
  };
1333
1486
 
1487
+ UndoManager.prototype.startPosition = function() {
1488
+ if (this.editor.selection._range) {
1489
+ this._startPosition || (this._startPosition = this._getPosition('start'));
1490
+ }
1491
+ return this._startPosition;
1492
+ };
1493
+
1494
+ UndoManager.prototype.endPosition = function() {
1495
+ if (this.editor.selection._range) {
1496
+ this._endPosition || (this._endPosition = (function(_this) {
1497
+ return function() {
1498
+ var range;
1499
+ range = _this.editor.selection.range();
1500
+ if (range.collapsed) {
1501
+ return _this._startPosition;
1502
+ }
1503
+ return _this._getPosition('end');
1504
+ };
1505
+ })(this)());
1506
+ }
1507
+ return this._endPosition;
1508
+ };
1509
+
1334
1510
  UndoManager.prototype._pushUndoState = function() {
1335
1511
  var currentState, html;
1336
1512
  if (this.editor.triggerHandler('pushundostate') === false) {
@@ -1414,53 +1590,57 @@ UndoManager = (function(superClass) {
1414
1590
  }
1415
1591
  offset = 0;
1416
1592
  merging = false;
1417
- $parent.contents().each((function(_this) {
1418
- return function(i, child) {
1419
- if (index === i || node === child) {
1420
- return false;
1421
- }
1422
- if (child.nodeType === 3) {
1423
- if (!merging) {
1424
- offset += 1;
1425
- merging = true;
1426
- }
1427
- } else {
1593
+ $parent.contents().each(function(i, child) {
1594
+ if (index === i || node === child) {
1595
+ return false;
1596
+ }
1597
+ if (child.nodeType === 3) {
1598
+ if (!merging) {
1428
1599
  offset += 1;
1429
- merging = false;
1600
+ merging = true;
1430
1601
  }
1431
- return null;
1432
- };
1433
- })(this));
1602
+ } else {
1603
+ offset += 1;
1604
+ merging = false;
1605
+ }
1606
+ return null;
1607
+ });
1434
1608
  return offset;
1435
1609
  };
1436
1610
 
1437
- UndoManager.prototype._getNodePosition = function(node, offset) {
1438
- var position, prevNode;
1439
- if (node.nodeType === 3) {
1611
+ UndoManager.prototype._getPosition = function(type) {
1612
+ var $nodes, node, nodes, offset, position, prevNode, range;
1613
+ if (type == null) {
1614
+ type = 'start';
1615
+ }
1616
+ range = this.editor.selection.range();
1617
+ offset = range[type + "Offset"];
1618
+ $nodes = this.editor.selection[type + "Nodes"]();
1619
+ if ((node = $nodes.first()[0]).nodeType === Node.TEXT_NODE) {
1440
1620
  prevNode = node.previousSibling;
1441
- while (prevNode && prevNode.nodeType === 3) {
1621
+ while (prevNode && prevNode.nodeType === Node.TEXT_NODE) {
1442
1622
  node = prevNode;
1443
1623
  offset += this.editor.util.getNodeLength(prevNode);
1444
1624
  prevNode = prevNode.previousSibling;
1445
1625
  }
1446
- } else {
1447
- offset = this._getNodeOffset(node, offset);
1626
+ nodes = $nodes.get();
1627
+ nodes[0] = node;
1628
+ $nodes = $(nodes);
1448
1629
  }
1449
- position = [];
1450
- position.unshift(offset);
1451
- this.editor.util.traverseUp((function(_this) {
1452
- return function(n) {
1453
- return position.unshift(_this._getNodeOffset(n));
1630
+ position = [offset];
1631
+ $nodes.each((function(_this) {
1632
+ return function(i, node) {
1633
+ return position.unshift(_this._getNodeOffset(node));
1454
1634
  };
1455
- })(this), node);
1635
+ })(this));
1456
1636
  return position;
1457
1637
  };
1458
1638
 
1459
1639
  UndoManager.prototype._getNodeByPosition = function(position) {
1460
- var child, childNodes, i, j, len, node, offset, ref;
1640
+ var child, childNodes, i, k, len, node, offset, ref;
1461
1641
  node = this.editor.body[0];
1462
1642
  ref = position.slice(0, position.length - 1);
1463
- for (i = j = 0, len = ref.length; j < len; i = ++j) {
1643
+ for (i = k = 0, len = ref.length; k < len; i = ++k) {
1464
1644
  offset = ref[i];
1465
1645
  childNodes = node.childNodes;
1466
1646
  if (offset > childNodes.length - 1) {
@@ -1481,20 +1661,12 @@ UndoManager = (function(superClass) {
1481
1661
  UndoManager.prototype.caretPosition = function(caret) {
1482
1662
  var endContainer, endOffset, range, startContainer, startOffset;
1483
1663
  if (!caret) {
1484
- range = this.editor.selection.getRange();
1485
- if (!(this.editor.inputManager.focused && (range != null))) {
1486
- return {};
1487
- }
1488
- caret = {
1489
- start: [],
1490
- end: null,
1491
- collapsed: true
1492
- };
1493
- caret.start = this._getNodePosition(range.startContainer, range.startOffset);
1494
- if (!range.collapsed) {
1495
- caret.end = this._getNodePosition(range.endContainer, range.endOffset);
1496
- caret.collapsed = false;
1497
- }
1664
+ range = this.editor.selection.range();
1665
+ caret = this.editor.inputManager.focused && (range != null) ? {
1666
+ start: this.startPosition(),
1667
+ end: this.endPosition(),
1668
+ collapsed: range.collapsed
1669
+ } : {};
1498
1670
  return caret;
1499
1671
  } else {
1500
1672
  if (!this.editor.inputManager.focused) {
@@ -1520,7 +1692,7 @@ UndoManager = (function(superClass) {
1520
1692
  range = document.createRange();
1521
1693
  range.setStart(startContainer, startOffset);
1522
1694
  range.setEnd(endContainer, endOffset);
1523
- return this.editor.selection.selectRange(range);
1695
+ return this.editor.selection.range(range);
1524
1696
  }
1525
1697
  };
1526
1698
 
@@ -1645,6 +1817,10 @@ Util = (function(superClass) {
1645
1817
  return $node.is(':empty') || (!$node.text() && !$node.find(':not(br, span, div)').length);
1646
1818
  };
1647
1819
 
1820
+ Util.prototype.isDecoratedNode = function(node) {
1821
+ return $(node).is('[class^="simditor-"]');
1822
+ };
1823
+
1648
1824
  Util.prototype.blockNodes = ["div", "p", "ul", "ol", "li", "blockquote", "hr", "pre", "h1", "h2", "h3", "h4", "table"];
1649
1825
 
1650
1826
  Util.prototype.isBlockNode = function(node) {
@@ -1655,61 +1831,8 @@ Util = (function(superClass) {
1655
1831
  return new RegExp("^(" + (this.blockNodes.join('|')) + ")$").test(node.nodeName.toLowerCase());
1656
1832
  };
1657
1833
 
1658
- Util.prototype.closestBlockEl = function(node) {
1659
- var $node, blockEl, range;
1660
- if (node == null) {
1661
- range = this.editor.selection.getRange();
1662
- node = range != null ? range.commonAncestorContainer : void 0;
1663
- }
1664
- $node = $(node);
1665
- if (!$node.length) {
1666
- return null;
1667
- }
1668
- blockEl = $node.parentsUntil(this.editor.body).addBack();
1669
- blockEl = blockEl.filter((function(_this) {
1670
- return function(i) {
1671
- return _this.isBlockNode(blockEl.eq(i));
1672
- };
1673
- })(this));
1674
- if (blockEl.length) {
1675
- return blockEl.last();
1676
- } else {
1677
- return null;
1678
- }
1679
- };
1680
-
1681
- Util.prototype.furthestNode = function(node, filter) {
1682
- var $node, blockEl, range;
1683
- if (node == null) {
1684
- range = this.editor.selection.getRange();
1685
- node = range != null ? range.commonAncestorContainer : void 0;
1686
- }
1687
- $node = $(node);
1688
- if (!$node.length) {
1689
- return null;
1690
- }
1691
- blockEl = $node.parentsUntil(this.editor.body).addBack();
1692
- blockEl = blockEl.filter(function(i) {
1693
- var $n;
1694
- $n = blockEl.eq(i);
1695
- if ($.isFunction(filter)) {
1696
- return filter($n);
1697
- } else {
1698
- return $n.is(filter);
1699
- }
1700
- });
1701
- if (blockEl.length) {
1702
- return blockEl.first();
1703
- } else {
1704
- return null;
1705
- }
1706
- };
1707
-
1708
- Util.prototype.furthestBlockEl = function(node) {
1709
- return this.furthestNode(node, $.proxy(this.isBlockNode, this));
1710
- };
1711
-
1712
1834
  Util.prototype.getNodeLength = function(node) {
1835
+ node = $(node)[0];
1713
1836
  switch (node.nodeType) {
1714
1837
  case 7:
1715
1838
  case 10:
@@ -1722,32 +1845,8 @@ Util = (function(superClass) {
1722
1845
  }
1723
1846
  };
1724
1847
 
1725
- Util.prototype.traverseUp = function(callback, node) {
1726
- var j, len, n, nodes, range, result, results1;
1727
- if (node == null) {
1728
- range = this.editor.selection.getRange();
1729
- node = range != null ? range.commonAncestorContainer : void 0;
1730
- }
1731
- if ((node == null) || !$.contains(this.editor.body[0], node)) {
1732
- return false;
1733
- }
1734
- nodes = $(node).parentsUntil(this.editor.body).get();
1735
- nodes.unshift(node);
1736
- results1 = [];
1737
- for (j = 0, len = nodes.length; j < len; j++) {
1738
- n = nodes[j];
1739
- result = callback(n);
1740
- if (result === false) {
1741
- break;
1742
- } else {
1743
- results1.push(void 0);
1744
- }
1745
- }
1746
- return results1;
1747
- };
1748
-
1749
1848
  Util.prototype.dataURLtoBlob = function(dataURL) {
1750
- var BlobBuilder, arrayBuffer, bb, blobArray, byteString, hasArrayBufferViewSupport, hasBlobConstructor, i, intArray, j, mimeString, ref, supportBlob;
1849
+ var BlobBuilder, arrayBuffer, bb, blobArray, byteString, hasArrayBufferViewSupport, hasBlobConstructor, i, intArray, k, mimeString, ref, supportBlob;
1751
1850
  hasBlobConstructor = window.Blob && (function() {
1752
1851
  var e;
1753
1852
  try {
@@ -1778,7 +1877,7 @@ Util = (function(superClass) {
1778
1877
  }
1779
1878
  arrayBuffer = new ArrayBuffer(byteString.length);
1780
1879
  intArray = new Uint8Array(arrayBuffer);
1781
- for (i = j = 0, ref = byteString.length; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) {
1880
+ for (i = k = 0, ref = byteString.length; 0 <= ref ? k <= ref : k >= ref; i = 0 <= ref ? ++k : --k) {
1782
1881
  intArray[i] = byteString.charCodeAt(i);
1783
1882
  }
1784
1883
  mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];
@@ -1794,38 +1893,30 @@ Util = (function(superClass) {
1794
1893
  };
1795
1894
 
1796
1895
  Util.prototype.throttle = function(func, wait) {
1797
- var delayedCallTimeout, previousCallTime, stopDelayedCall;
1798
- delayedCallTimeout = null;
1799
- previousCallTime = 0;
1800
- stopDelayedCall = function() {
1801
- if (delayedCallTimeout) {
1802
- clearTimeout(delayedCallTimeout);
1803
- return delayedCallTimeout = null;
1804
- }
1896
+ var args, call, ctx, last, rtn, throttled, timeoutID;
1897
+ last = 0;
1898
+ timeoutID = 0;
1899
+ ctx = args = rtn = null;
1900
+ call = function() {
1901
+ timeoutID = 0;
1902
+ last = +new Date();
1903
+ rtn = func.apply(ctx, args);
1904
+ ctx = null;
1905
+ return args = null;
1805
1906
  };
1806
- return function() {
1807
- var args, now, remaining, result;
1808
- now = Date.now();
1809
- previousCallTime || (previousCallTime = now);
1810
- remaining = wait - (now - previousCallTime);
1811
- result = null;
1812
- if ((0 < remaining && remaining < wait)) {
1813
- previousCallTime = now;
1814
- stopDelayedCall();
1815
- args = arguments;
1816
- delayedCallTimeout = setTimeout(function() {
1817
- previousCallTime = 0;
1818
- delayedCallTimeout = null;
1819
- return result = func.apply(null, args);
1820
- }, wait);
1821
- } else {
1822
- stopDelayedCall();
1823
- if (previousCallTime !== now) {
1824
- previousCallTime = 0;
1907
+ return throttled = function() {
1908
+ var delta;
1909
+ ctx = this;
1910
+ args = arguments;
1911
+ delta = new Date() - last;
1912
+ if (!timeoutID) {
1913
+ if (delta >= wait) {
1914
+ call();
1915
+ } else {
1916
+ timeoutID = setTimeout(call, wait - delta);
1825
1917
  }
1826
- result = func.apply(null, arguments);
1827
1918
  }
1828
- return result;
1919
+ return rtn;
1829
1920
  };
1830
1921
  };
1831
1922
 
@@ -1903,11 +1994,9 @@ Toolbar = (function(superClass) {
1903
1994
  this.opts.toolbar = ['bold', 'italic', 'underline', 'strikethrough', '|', 'ol', 'ul', 'blockquote', 'code', '|', 'link', 'image', '|', 'indent', 'outdent'];
1904
1995
  }
1905
1996
  this._render();
1906
- this.list.on('click', (function(_this) {
1907
- return function(e) {
1908
- return false;
1909
- };
1910
- })(this));
1997
+ this.list.on('click', function(e) {
1998
+ return false;
1999
+ });
1911
2000
  this.wrapper.on('mousedown', (function(_this) {
1912
2001
  return function(e) {
1913
2002
  return _this.list.find('.menu-on').removeClass('.menu-on');
@@ -1953,17 +2042,12 @@ Toolbar = (function(superClass) {
1953
2042
  };
1954
2043
  })(this));
1955
2044
  }
1956
- this.editor.on('selectionchanged', (function(_this) {
1957
- return function() {
1958
- return _this.toolbarStatus();
1959
- };
1960
- })(this));
1961
2045
  this.editor.on('destroy', (function(_this) {
1962
2046
  return function() {
1963
2047
  return _this.buttons.length = 0;
1964
2048
  };
1965
2049
  })(this));
1966
- return $(document).on('mousedown.simditor-' + this.editor.id, (function(_this) {
2050
+ return $(document).on("mousedown.simditor-" + this.editor.id, (function(_this) {
1967
2051
  return function(e) {
1968
2052
  return _this.list.find('li.menu-on').removeClass('menu-on');
1969
2053
  };
@@ -1971,19 +2055,19 @@ Toolbar = (function(superClass) {
1971
2055
  };
1972
2056
 
1973
2057
  Toolbar.prototype._render = function() {
1974
- var j, len, name, ref;
2058
+ var k, len, name, ref;
1975
2059
  this.buttons = [];
1976
2060
  this.wrapper = $(this._tpl.wrapper).prependTo(this.editor.wrapper);
1977
2061
  this.list = this.wrapper.find('ul');
1978
2062
  ref = this.opts.toolbar;
1979
- for (j = 0, len = ref.length; j < len; j++) {
1980
- name = ref[j];
2063
+ for (k = 0, len = ref.length; k < len; k++) {
2064
+ name = ref[k];
1981
2065
  if (name === '|') {
1982
2066
  $(this._tpl.separator).appendTo(this.list);
1983
2067
  continue;
1984
2068
  }
1985
2069
  if (!this.constructor.buttons[name]) {
1986
- throw new Error('simditor: invalid toolbar button "' + name + '"');
2070
+ throw new Error("simditor: invalid toolbar button " + name);
1987
2071
  continue;
1988
2072
  }
1989
2073
  this.buttons.push(new this.constructor.buttons[name]({
@@ -1995,37 +2079,6 @@ Toolbar = (function(superClass) {
1995
2079
  }
1996
2080
  };
1997
2081
 
1998
- Toolbar.prototype.toolbarStatus = function(name) {
1999
- var buttons;
2000
- if (!this.editor.inputManager.focused) {
2001
- return;
2002
- }
2003
- buttons = this.buttons.slice(0);
2004
- return this.editor.util.traverseUp((function(_this) {
2005
- return function(node) {
2006
- var button, i, j, k, len, len1, removeButtons;
2007
- removeButtons = [];
2008
- for (i = j = 0, len = buttons.length; j < len; i = ++j) {
2009
- button = buttons[i];
2010
- if ((name != null) && button.name !== name) {
2011
- continue;
2012
- }
2013
- if (!button.status || button.status($(node)) === true) {
2014
- removeButtons.push(button);
2015
- }
2016
- }
2017
- for (k = 0, len1 = removeButtons.length; k < len1; k++) {
2018
- button = removeButtons[k];
2019
- i = $.inArray(button, buttons);
2020
- buttons.splice(i, 1);
2021
- }
2022
- if (buttons.length === 0) {
2023
- return false;
2024
- }
2025
- };
2026
- })(this));
2027
- };
2028
-
2029
2082
  Toolbar.prototype.findButton = function(name) {
2030
2083
  var button;
2031
2084
  button = this.list.find('.toolbar-item-' + name).data('button');
@@ -2070,40 +2123,51 @@ Indentation = (function(superClass) {
2070
2123
  };
2071
2124
 
2072
2125
  Indentation.prototype.indent = function(isBackward) {
2073
- var $blockEls, $endBlock, $startBlock, range, result;
2074
- range = this.editor.selection.getRange();
2075
- if (!range) {
2076
- return;
2077
- }
2078
- $startBlock = this.editor.util.closestBlockEl(range.startContainer);
2079
- $endBlock = this.editor.util.closestBlockEl(range.endContainer);
2080
- if (!($startBlock.is('li') && $endBlock.is('li') && $startBlock.parent().is($endBlock.parent()))) {
2081
- $startBlock = this.editor.util.furthestBlockEl($startBlock);
2082
- $endBlock = this.editor.util.furthestBlockEl($endBlock);
2083
- }
2084
- if ($startBlock.is($endBlock)) {
2085
- $blockEls = $startBlock;
2086
- } else {
2087
- $blockEls = $startBlock.nextUntil($endBlock).add($startBlock).add($endBlock);
2088
- }
2126
+ var $blockNodes, $endNodes, $startNodes, nodes, result;
2127
+ $startNodes = this.editor.selection.startNodes();
2128
+ $endNodes = this.editor.selection.endNodes();
2129
+ $blockNodes = this.editor.selection.blockNodes();
2130
+ nodes = [];
2131
+ $blockNodes = $blockNodes.each(function(i, node) {
2132
+ var include, j, k, len, n;
2133
+ include = true;
2134
+ for (j = k = 0, len = nodes.length; k < len; j = ++k) {
2135
+ n = nodes[j];
2136
+ if ($.contains(node, n)) {
2137
+ include = false;
2138
+ break;
2139
+ } else if ($.contains(n, node)) {
2140
+ nodes.splice(j, 1, node);
2141
+ include = false;
2142
+ break;
2143
+ }
2144
+ }
2145
+ if (include) {
2146
+ return nodes.push(node);
2147
+ }
2148
+ });
2149
+ $blockNodes = $(nodes);
2089
2150
  result = false;
2090
- $blockEls.each((function(_this) {
2151
+ $blockNodes.each((function(_this) {
2091
2152
  return function(i, blockEl) {
2092
- return result = isBackward ? _this.outdentBlock(blockEl) : _this.indentBlock(blockEl);
2153
+ var r;
2154
+ r = isBackward ? _this.outdentBlock(blockEl) : _this.indentBlock(blockEl);
2155
+ if (r) {
2156
+ return result = r;
2157
+ }
2093
2158
  };
2094
2159
  })(this));
2095
2160
  return result;
2096
2161
  };
2097
2162
 
2098
2163
  Indentation.prototype.indentBlock = function(blockEl) {
2099
- var $blockEl, $childList, $nextTd, $nextTr, $parentLi, $pre, $td, $tr, marginLeft, range, tagName;
2164
+ var $blockEl, $childList, $nextTd, $nextTr, $parentLi, $pre, $td, $tr, marginLeft, tagName;
2100
2165
  $blockEl = $(blockEl);
2101
2166
  if (!$blockEl.length) {
2102
2167
  return;
2103
2168
  }
2104
2169
  if ($blockEl.is('pre')) {
2105
- range = this.editor.selection.getRange();
2106
- $pre = $(range.commonAncestorContainer);
2170
+ $pre = this.editor.selection.containerNode;
2107
2171
  if (!($pre.is($blockEl) || $pre.closest('pre').is($blockEl))) {
2108
2172
  return;
2109
2173
  }
@@ -2127,8 +2191,7 @@ Indentation = (function(superClass) {
2127
2191
  marginLeft = (Math.round(marginLeft / this.opts.indentWidth) + 1) * this.opts.indentWidth;
2128
2192
  $blockEl.css('margin-left', marginLeft);
2129
2193
  } else if ($blockEl.is('table') || $blockEl.is('.simditor-table')) {
2130
- range = this.editor.selection.getRange();
2131
- $td = $(range.commonAncestorContainer).closest('td, th');
2194
+ $td = this.editor.selection.containerNode.closest('td, th');
2132
2195
  $nextTd = $td.next('td, th');
2133
2196
  if (!($nextTd.length > 0)) {
2134
2197
  $tr = $td.parent('tr');
@@ -2139,9 +2202,11 @@ Indentation = (function(superClass) {
2139
2202
  $nextTd = $nextTr.find('td:first, th:first');
2140
2203
  }
2141
2204
  if (!($td.length > 0 && $nextTd.length > 0)) {
2142
- return false;
2205
+ return;
2143
2206
  }
2144
2207
  this.editor.selection.setRangeAtEndOf($nextTd);
2208
+ } else {
2209
+ return false;
2145
2210
  }
2146
2211
  return true;
2147
2212
  };
@@ -2154,21 +2219,20 @@ Indentation = (function(superClass) {
2154
2219
  range.insertNode(textNode);
2155
2220
  if (text) {
2156
2221
  range.selectNode(textNode);
2157
- return this.editor.selection.selectRange(range);
2222
+ return this.editor.selection.range(range);
2158
2223
  } else {
2159
2224
  return this.editor.selection.setRangeAfter(textNode);
2160
2225
  }
2161
2226
  };
2162
2227
 
2163
2228
  Indentation.prototype.outdentBlock = function(blockEl) {
2164
- var $blockEl, $parent, $parentLi, $pre, $prevTd, $prevTr, $td, $tr, button, marginLeft, range;
2229
+ var $blockEl, $parent, $parentLi, $pre, $prevTd, $prevTr, $td, $tr, marginLeft, range;
2165
2230
  $blockEl = $(blockEl);
2166
2231
  if (!($blockEl && $blockEl.length > 0)) {
2167
2232
  return;
2168
2233
  }
2169
2234
  if ($blockEl.is('pre')) {
2170
- range = this.editor.selection.getRange();
2171
- $pre = $(range.commonAncestorContainer);
2235
+ $pre = this.editor.selection.containerNode;
2172
2236
  if (!($pre.is($blockEl) || $pre.closest('pre').is($blockEl))) {
2173
2237
  return;
2174
2238
  }
@@ -2176,20 +2240,22 @@ Indentation = (function(superClass) {
2176
2240
  } else if ($blockEl.is('li')) {
2177
2241
  $parent = $blockEl.parent();
2178
2242
  $parentLi = $parent.parent('li');
2243
+ this.editor.selection.save();
2179
2244
  if ($parentLi.length < 1) {
2180
- button = this.editor.toolbar.findButton($parent[0].tagName.toLowerCase());
2181
- if (button != null) {
2182
- button.command();
2245
+ range = document.createRange();
2246
+ range.setStartBefore($parent[0]);
2247
+ range.setEndBefore($blockEl[0]);
2248
+ $parent.before(range.extractContents());
2249
+ $('<p/>').insertBefore($parent).after($blockEl.children('ul, ol')).append($blockEl.contents());
2250
+ $blockEl.remove();
2251
+ } else {
2252
+ if ($blockEl.next('li').length > 0) {
2253
+ $('<' + $parent[0].tagName + '/>').append($blockEl.nextAll('li')).appendTo($blockEl);
2254
+ }
2255
+ $blockEl.insertAfter($parentLi);
2256
+ if ($parent.children('li').length < 1) {
2257
+ $parent.remove();
2183
2258
  }
2184
- return;
2185
- }
2186
- this.editor.selection.save();
2187
- if ($blockEl.next('li').length > 0) {
2188
- $('<' + $parent[0].tagName + '/>').append($blockEl.nextAll('li')).appendTo($blockEl);
2189
- }
2190
- $blockEl.insertAfter($parentLi);
2191
- if ($parent.children('li').length < 1) {
2192
- $parent.remove();
2193
2259
  }
2194
2260
  this.editor.selection.restore();
2195
2261
  } else if ($blockEl.is('p, h1, h2, h3, h4')) {
@@ -2197,8 +2263,7 @@ Indentation = (function(superClass) {
2197
2263
  marginLeft = Math.max(Math.round(marginLeft / this.opts.indentWidth) - 1, 0) * this.opts.indentWidth;
2198
2264
  $blockEl.css('margin-left', marginLeft === 0 ? '' : marginLeft);
2199
2265
  } else if ($blockEl.is('table') || $blockEl.is('.simditor-table')) {
2200
- range = this.editor.selection.getRange();
2201
- $td = $(range.commonAncestorContainer).closest('td, th');
2266
+ $td = this.editor.selection.containerNode.closest('td, th');
2202
2267
  $prevTd = $td.prev('td, th');
2203
2268
  if (!($prevTd.length > 0)) {
2204
2269
  $tr = $td.parent('tr');
@@ -2212,6 +2277,8 @@ Indentation = (function(superClass) {
2212
2277
  return;
2213
2278
  }
2214
2279
  this.editor.selection.setRangeAtEndOf($prevTd);
2280
+ } else {
2281
+ return false;
2215
2282
  }
2216
2283
  return true;
2217
2284
  };
@@ -2233,14 +2300,14 @@ Simditor = (function(superClass) {
2233
2300
 
2234
2301
  Simditor.connect(InputManager);
2235
2302
 
2303
+ Simditor.connect(Selection);
2304
+
2236
2305
  Simditor.connect(UndoManager);
2237
2306
 
2238
2307
  Simditor.connect(Keystroke);
2239
2308
 
2240
2309
  Simditor.connect(Formatter);
2241
2310
 
2242
- Simditor.connect(Selection);
2243
-
2244
2311
  Simditor.connect(Toolbar);
2245
2312
 
2246
2313
  Simditor.connect(Indentation);
@@ -2300,8 +2367,8 @@ Simditor = (function(superClass) {
2300
2367
  if (this.util.browser.mozilla) {
2301
2368
  this.util.reflow();
2302
2369
  try {
2303
- document.execCommand("enableObjectResizing", false, false);
2304
- return document.execCommand("enableInlineTableEditing", false, false);
2370
+ document.execCommand('enableObjectResizing', false, false);
2371
+ return document.execCommand('enableInlineTableEditing', false, false);
2305
2372
  } catch (_error) {
2306
2373
  e = _error;
2307
2374
  }
@@ -2311,7 +2378,7 @@ Simditor = (function(superClass) {
2311
2378
  Simditor.prototype._tpl = "<div class=\"simditor\">\n <div class=\"simditor-wrapper\">\n <div class=\"simditor-placeholder\"></div>\n <div class=\"simditor-body\" contenteditable=\"true\">\n </div>\n </div>\n</div>";
2312
2379
 
2313
2380
  Simditor.prototype._render = function() {
2314
- var key, ref, results1, val;
2381
+ var key, ref, results, val;
2315
2382
  this.el = $(this._tpl).insertBefore(this.textarea);
2316
2383
  this.wrapper = this.el.find('.simditor-wrapper');
2317
2384
  this.body = this.wrapper.find('.simditor-body');
@@ -2330,16 +2397,16 @@ Simditor = (function(superClass) {
2330
2397
  }
2331
2398
  if (this.opts.params) {
2332
2399
  ref = this.opts.params;
2333
- results1 = [];
2400
+ results = [];
2334
2401
  for (key in ref) {
2335
2402
  val = ref[key];
2336
- results1.push($('<input/>', {
2403
+ results.push($('<input/>', {
2337
2404
  type: 'hidden',
2338
2405
  name: key,
2339
2406
  value: val
2340
2407
  }).insertAfter(this.textarea));
2341
2408
  }
2342
- return results1;
2409
+ return results;
2343
2410
  }
2344
2411
  };
2345
2412
 
@@ -2489,6 +2556,50 @@ Simditor.i18n = {
2489
2556
  'alignLeft': '居左',
2490
2557
  'alignRight': '居右',
2491
2558
  'selectLanguage': '选择程序语言'
2559
+ },
2560
+ 'en-US': {
2561
+ 'blockquote': 'Block Quote',
2562
+ 'bold': 'Bold',
2563
+ 'code': 'Code',
2564
+ 'color': 'Text Color',
2565
+ 'hr': 'Horizontal Line',
2566
+ 'image': 'Insert Image',
2567
+ 'externalImage': 'External Image',
2568
+ 'uploadImage': 'Upload Image',
2569
+ 'uploadFailed': 'Upload failed',
2570
+ 'uploadError': 'Error occurs during upload',
2571
+ 'imageUrl': 'Url',
2572
+ 'imageSize': 'Size',
2573
+ 'imageAlt': 'Alt',
2574
+ 'restoreImageSize': 'Restore Origin Size',
2575
+ 'uploading': 'Uploading',
2576
+ 'indent': 'Indent',
2577
+ 'outdent': 'Outdent',
2578
+ 'italic': 'Italic',
2579
+ 'link': 'Insert Link',
2580
+ 'text': 'Text',
2581
+ 'linkText': 'Link Text',
2582
+ 'linkUrl': 'Link Url',
2583
+ 'removeLink': 'Remove Link',
2584
+ 'ol': 'Ordered List',
2585
+ 'ul': 'Unordered List',
2586
+ 'strikethrough': 'Strikethrough',
2587
+ 'table': 'Table',
2588
+ 'deleteRow': 'Delete Row',
2589
+ 'insertRowAbove': 'Insert Row Above',
2590
+ 'insertRowBelow': 'Insert Row Below',
2591
+ 'deleteColumn': 'Delete Column',
2592
+ 'insertColumnLeft': 'Insert Column Left',
2593
+ 'insertColumnRight': 'Insert Column Right',
2594
+ 'deleteTable': 'Delete Table',
2595
+ 'title': 'Title',
2596
+ 'normalText': 'Text',
2597
+ 'underline': 'Underline',
2598
+ 'alignment': 'Alignment',
2599
+ 'alignCenter': 'Align Center',
2600
+ 'alignLeft': 'Align Left',
2601
+ 'alignRight': 'Align Right',
2602
+ 'selectLanguage': 'Select Language'
2492
2603
  }
2493
2604
  };
2494
2605
 
@@ -2531,13 +2642,14 @@ Button = (function(superClass) {
2531
2642
  }
2532
2643
 
2533
2644
  Button.prototype._init = function() {
2534
- var j, len, ref, results1, tag;
2645
+ var k, len, ref, tag;
2535
2646
  this.render();
2536
2647
  this.el.on('mousedown', (function(_this) {
2537
2648
  return function(e) {
2538
- var exceed, param;
2649
+ var exceed, noFocus, param;
2539
2650
  e.preventDefault();
2540
- if (_this.el.hasClass('disabled') || (_this.needFocus && !_this.editor.inputManager.focused)) {
2651
+ noFocus = _this.needFocus && !_this.editor.inputManager.focused;
2652
+ if (_this.el.hasClass('disabled') || noFocus) {
2541
2653
  return false;
2542
2654
  }
2543
2655
  if (_this.menu) {
@@ -2561,11 +2673,12 @@ Button = (function(superClass) {
2561
2673
  })(this));
2562
2674
  this.wrapper.on('click', 'a.menu-item', (function(_this) {
2563
2675
  return function(e) {
2564
- var btn, param;
2676
+ var btn, noFocus, param;
2565
2677
  e.preventDefault();
2566
2678
  btn = $(e.currentTarget);
2567
2679
  _this.wrapper.removeClass('menu-on');
2568
- if (btn.hasClass('disabled') || (_this.needFocus && !_this.editor.inputManager.focused)) {
2680
+ noFocus = _this.needFocus && !_this.editor.inputManager.focused;
2681
+ if (btn.hasClass('disabled') || noFocus) {
2569
2682
  return false;
2570
2683
  }
2571
2684
  _this.editor.toolbar.wrapper.removeClass('menu-on');
@@ -2574,14 +2687,14 @@ Button = (function(superClass) {
2574
2687
  return false;
2575
2688
  };
2576
2689
  })(this));
2577
- this.wrapper.on('mousedown', 'a.menu-item', (function(_this) {
2578
- return function(e) {
2579
- return false;
2580
- };
2581
- })(this));
2690
+ this.wrapper.on('mousedown', 'a.menu-item', function(e) {
2691
+ return false;
2692
+ });
2582
2693
  this.editor.on('blur', (function(_this) {
2583
2694
  return function() {
2584
- if (!(_this.editor.body.is(':visible') && _this.editor.body.is('[contenteditable]'))) {
2695
+ var editorActive;
2696
+ editorActive = _this.editor.body.is(':visible') && _this.editor.body.is('[contenteditable]');
2697
+ if (!editorActive) {
2585
2698
  return;
2586
2699
  }
2587
2700
  _this.setActive(false);
@@ -2597,17 +2710,20 @@ Button = (function(superClass) {
2597
2710
  })(this));
2598
2711
  }
2599
2712
  ref = this.htmlTag.split(',');
2600
- results1 = [];
2601
- for (j = 0, len = ref.length; j < len; j++) {
2602
- tag = ref[j];
2713
+ for (k = 0, len = ref.length; k < len; k++) {
2714
+ tag = ref[k];
2603
2715
  tag = $.trim(tag);
2604
2716
  if (tag && $.inArray(tag, this.editor.formatter._allowedTags) < 0) {
2605
- results1.push(this.editor.formatter._allowedTags.push(tag));
2606
- } else {
2607
- results1.push(void 0);
2717
+ this.editor.formatter._allowedTags.push(tag);
2608
2718
  }
2609
2719
  }
2610
- return results1;
2720
+ return this.editor.on('selectionchanged', (function(_this) {
2721
+ return function(e) {
2722
+ if (_this.editor.inputManager.focused) {
2723
+ return _this._status();
2724
+ }
2725
+ };
2726
+ })(this));
2611
2727
  };
2612
2728
 
2613
2729
  Button.prototype.iconClassOf = function(icon) {
@@ -2636,15 +2752,15 @@ Button = (function(superClass) {
2636
2752
  };
2637
2753
 
2638
2754
  Button.prototype.renderMenu = function() {
2639
- var $menuBtnEl, $menuItemEl, j, len, menuItem, ref, ref1, results1;
2755
+ var $menuBtnEl, $menuItemEl, k, len, menuItem, ref, ref1, results;
2640
2756
  if (!$.isArray(this.menu)) {
2641
2757
  return;
2642
2758
  }
2643
2759
  this.menuEl = $('<ul/>').appendTo(this.menuWrapper);
2644
2760
  ref = this.menu;
2645
- results1 = [];
2646
- for (j = 0, len = ref.length; j < len; j++) {
2647
- menuItem = ref[j];
2761
+ results = [];
2762
+ for (k = 0, len = ref.length; k < len; k++) {
2763
+ menuItem = ref[k];
2648
2764
  if (menuItem === '|') {
2649
2765
  $(this._tpl.separator).appendTo(this.menuEl);
2650
2766
  continue;
@@ -2655,12 +2771,12 @@ Button = (function(superClass) {
2655
2771
  'data-param': menuItem.param
2656
2772
  }).addClass('menu-item-' + menuItem.name);
2657
2773
  if (menuItem.icon) {
2658
- results1.push($menuBtnEl.find('span').addClass(this.iconClassOf(menuItem.icon)));
2774
+ results.push($menuBtnEl.find('span').addClass(this.iconClassOf(menuItem.icon)));
2659
2775
  } else {
2660
- results1.push($menuBtnEl.find('span').text(menuItem.text));
2776
+ results.push($menuBtnEl.find('span').text(menuItem.text));
2661
2777
  }
2662
2778
  }
2663
- return results1;
2779
+ return results;
2664
2780
  };
2665
2781
 
2666
2782
  Button.prototype.setActive = function(active) {
@@ -2668,8 +2784,7 @@ Button = (function(superClass) {
2668
2784
  return;
2669
2785
  }
2670
2786
  this.active = active;
2671
- this.el.toggleClass('active', this.active);
2672
- return this.editor.toolbar.trigger('buttonstatus', [this]);
2787
+ return this.el.toggleClass('active', this.active);
2673
2788
  };
2674
2789
 
2675
2790
  Button.prototype.setDisabled = function(disabled) {
@@ -2677,23 +2792,41 @@ Button = (function(superClass) {
2677
2792
  return;
2678
2793
  }
2679
2794
  this.disabled = disabled;
2680
- this.el.toggleClass('disabled', this.disabled);
2681
- return this.editor.toolbar.trigger('buttonstatus', [this]);
2795
+ return this.el.toggleClass('disabled', this.disabled);
2682
2796
  };
2683
2797
 
2684
- Button.prototype.status = function($node) {
2685
- if ($node != null) {
2686
- this.setDisabled($node.is(this.disableTag));
2687
- }
2798
+ Button.prototype._disableStatus = function() {
2799
+ var disabled, endNodes, startNodes;
2800
+ startNodes = this.editor.selection.startNodes();
2801
+ endNodes = this.editor.selection.endNodes();
2802
+ disabled = startNodes.filter(this.disableTag).length > 0 || endNodes.filter(this.disableTag).length > 0;
2803
+ this.setDisabled(disabled);
2688
2804
  if (this.disabled) {
2689
- return true;
2690
- }
2691
- if ($node != null) {
2692
- this.setActive($node.is(this.htmlTag));
2805
+ this.setActive(false);
2693
2806
  }
2807
+ return this.disabled;
2808
+ };
2809
+
2810
+ Button.prototype._activeStatus = function() {
2811
+ var active, endNode, endNodes, startNode, startNodes;
2812
+ startNodes = this.editor.selection.startNodes();
2813
+ endNodes = this.editor.selection.endNodes();
2814
+ startNode = startNodes.filter(this.htmlTag);
2815
+ endNode = endNodes.filter(this.htmlTag);
2816
+ active = startNode.length > 0 && endNode.length > 0 && startNode.is(endNode);
2817
+ this.node = active ? startNode : null;
2818
+ this.setActive(active);
2694
2819
  return this.active;
2695
2820
  };
2696
2821
 
2822
+ Button.prototype._status = function() {
2823
+ this._disableStatus();
2824
+ if (this.disabled) {
2825
+ return;
2826
+ }
2827
+ return this._activeStatus();
2828
+ };
2829
+
2697
2830
  Button.prototype.command = function(param) {};
2698
2831
 
2699
2832
  Button.prototype._t = function() {
@@ -2754,14 +2887,12 @@ Popover = (function(superClass) {
2754
2887
  if ($target == null) {
2755
2888
  return;
2756
2889
  }
2757
- this.el.siblings('.simditor-popover').each((function(_this) {
2758
- return function(i, popover) {
2759
- popover = $(popover).data('popover');
2760
- if (popover.active) {
2761
- return popover.hide();
2762
- }
2763
- };
2764
- })(this));
2890
+ this.el.siblings('.simditor-popover').each(function(i, popover) {
2891
+ popover = $(popover).data('popover');
2892
+ if (popover.active) {
2893
+ return popover.hide();
2894
+ }
2895
+ });
2765
2896
  if (this.active && this.target) {
2766
2897
  this.target.removeClass('selected');
2767
2898
  }
@@ -2774,12 +2905,9 @@ Popover = (function(superClass) {
2774
2905
  this.el.css({
2775
2906
  left: -9999
2776
2907
  }).show();
2777
- return setTimeout((function(_this) {
2778
- return function() {
2779
- _this.refresh(position);
2780
- return _this.trigger('popovershow');
2781
- };
2782
- })(this), 0);
2908
+ this.editor.util.reflow();
2909
+ this.refresh(position);
2910
+ return this.trigger('popovershow');
2783
2911
  }
2784
2912
  };
2785
2913
 
@@ -2797,7 +2925,7 @@ Popover = (function(superClass) {
2797
2925
  };
2798
2926
 
2799
2927
  Popover.prototype.refresh = function(position) {
2800
- var editorOffset, left, targetH, targetOffset, top;
2928
+ var editorOffset, left, maxLeft, targetH, targetOffset, top;
2801
2929
  if (position == null) {
2802
2930
  position = 'bottom';
2803
2931
  }
@@ -2812,7 +2940,8 @@ Popover = (function(superClass) {
2812
2940
  } else if (position === 'top') {
2813
2941
  top = targetOffset.top - editorOffset.top - this.el.height();
2814
2942
  }
2815
- left = Math.min(targetOffset.left - editorOffset.left, this.editor.wrapper.width() - this.el.outerWidth() - 10);
2943
+ maxLeft = this.editor.wrapper.width() - this.el.outerWidth() - 10;
2944
+ left = Math.min(targetOffset.left - editorOffset.left, maxLeft);
2816
2945
  return this.el.css({
2817
2946
  top: top + this.offset.top,
2818
2947
  left: left + this.offset.left
@@ -2888,73 +3017,33 @@ TitleButton = (function(superClass) {
2888
3017
 
2889
3018
  TitleButton.prototype.setActive = function(active, param) {
2890
3019
  TitleButton.__super__.setActive.call(this, active);
3020
+ if (active) {
3021
+ param || (param = this.node[0].tagName.toLowerCase());
3022
+ }
2891
3023
  this.el.removeClass('active-p active-h1 active-h2 active-h3');
2892
3024
  if (active) {
2893
3025
  return this.el.addClass('active active-' + param);
2894
3026
  }
2895
3027
  };
2896
3028
 
2897
- TitleButton.prototype.status = function($node) {
2898
- var param, ref;
2899
- if ($node != null) {
2900
- this.setDisabled($node.is(this.disableTag));
2901
- }
2902
- if (this.disabled) {
2903
- return true;
2904
- }
2905
- if ($node != null) {
2906
- param = (ref = $node[0].tagName) != null ? ref.toLowerCase() : void 0;
2907
- this.setActive($node.is(this.htmlTag), param);
2908
- }
2909
- return this.active;
2910
- };
2911
-
2912
3029
  TitleButton.prototype.command = function(param) {
2913
- var $contents, $endBlock, $startBlock, endNode, j, len, node, range, ref, results, startNode;
2914
- range = this.editor.selection.getRange();
2915
- startNode = range.startContainer;
2916
- endNode = range.endContainer;
2917
- $startBlock = this.editor.util.closestBlockEl(startNode);
2918
- $endBlock = this.editor.util.closestBlockEl(endNode);
3030
+ var $rootNodes;
3031
+ $rootNodes = this.editor.selection.rootNodes();
2919
3032
  this.editor.selection.save();
2920
- range.setStartBefore($startBlock[0]);
2921
- range.setEndAfter($endBlock[0]);
2922
- $contents = $(range.extractContents());
2923
- results = [];
2924
- $contents.children().each((function(_this) {
2925
- return function(i, el) {
2926
- var c, converted, j, len, results1;
2927
- converted = _this._convertEl(el, param);
2928
- results1 = [];
2929
- for (j = 0, len = converted.length; j < len; j++) {
2930
- c = converted[j];
2931
- results1.push(results.push(c));
3033
+ $rootNodes.each((function(_this) {
3034
+ return function(i, node) {
3035
+ var $node;
3036
+ $node = $(node);
3037
+ if ($node.is('blockquote') || $node.is(param) || $node.is(_this.disableTag) || _this.editor.util.isDecoratedNode($node)) {
3038
+ return;
2932
3039
  }
2933
- return results1;
3040
+ return $('<' + param + '/>').append($node.contents()).replaceAll($node);
2934
3041
  };
2935
3042
  })(this));
2936
- ref = results.reverse();
2937
- for (j = 0, len = ref.length; j < len; j++) {
2938
- node = ref[j];
2939
- range.insertNode(node[0]);
2940
- }
2941
3043
  this.editor.selection.restore();
2942
3044
  return this.editor.trigger('valuechanged');
2943
3045
  };
2944
3046
 
2945
- TitleButton.prototype._convertEl = function(el, param) {
2946
- var $block, $el, results;
2947
- $el = $(el);
2948
- results = [];
2949
- if ($el.is(param)) {
2950
- results.push($el);
2951
- } else {
2952
- $block = $('<' + param + '/>').append($el.contents());
2953
- results.push($block);
2954
- }
2955
- return results;
2956
- };
2957
-
2958
3047
  return TitleButton;
2959
3048
 
2960
3049
  })(Button);
@@ -2988,17 +3077,11 @@ BoldButton = (function(superClass) {
2988
3077
  return BoldButton.__super__._init.call(this);
2989
3078
  };
2990
3079
 
2991
- BoldButton.prototype.status = function($node) {
3080
+ BoldButton.prototype._activeStatus = function() {
2992
3081
  var active;
2993
- if ($node != null) {
2994
- this.setDisabled($node.is(this.disableTag));
2995
- }
2996
- if (this.disabled) {
2997
- return true;
2998
- }
2999
3082
  active = document.queryCommandState('bold') === true;
3000
3083
  this.setActive(active);
3001
- return active;
3084
+ return this.active;
3002
3085
  };
3003
3086
 
3004
3087
  BoldButton.prototype.command = function() {
@@ -3034,25 +3117,19 @@ ItalicButton = (function(superClass) {
3034
3117
 
3035
3118
  ItalicButton.prototype._init = function() {
3036
3119
  if (this.editor.util.os.mac) {
3037
- this.title = this.title + ' ( Cmd + i )';
3120
+ this.title = this.title + " ( Cmd + i )";
3038
3121
  } else {
3039
- this.title = this.title + ' ( Ctrl + i )';
3122
+ this.title = this.title + " ( Ctrl + i )";
3040
3123
  this.shortcut = 'ctrl+i';
3041
3124
  }
3042
3125
  return ItalicButton.__super__._init.call(this);
3043
3126
  };
3044
3127
 
3045
- ItalicButton.prototype.status = function($node) {
3128
+ ItalicButton.prototype._activeStatus = function() {
3046
3129
  var active;
3047
- if ($node != null) {
3048
- this.setDisabled($node.is(this.disableTag));
3049
- }
3050
- if (this.disabled) {
3051
- return this.disabled;
3052
- }
3053
3130
  active = document.queryCommandState('italic') === true;
3054
3131
  this.setActive(active);
3055
- return active;
3132
+ return this.active;
3056
3133
  };
3057
3134
 
3058
3135
  ItalicButton.prototype.command = function() {
@@ -3096,17 +3173,11 @@ UnderlineButton = (function(superClass) {
3096
3173
  return UnderlineButton.__super__.render.call(this);
3097
3174
  };
3098
3175
 
3099
- UnderlineButton.prototype.status = function($node) {
3176
+ UnderlineButton.prototype._activeStatus = function() {
3100
3177
  var active;
3101
- if ($node != null) {
3102
- this.setDisabled($node.is(this.disableTag));
3103
- }
3104
- if (this.disabled) {
3105
- return this.disabled;
3106
- }
3107
3178
  active = document.queryCommandState('underline') === true;
3108
3179
  this.setActive(active);
3109
- return active;
3180
+ return this.active;
3110
3181
  };
3111
3182
 
3112
3183
  UnderlineButton.prototype.command = function() {
@@ -3145,7 +3216,7 @@ ColorButton = (function(superClass) {
3145
3216
  };
3146
3217
 
3147
3218
  ColorButton.prototype.renderMenu = function() {
3148
- $('<ul class="color-list">\n <li><a href="javascript:;" class="font-color font-color-1" data-color=""></a></li>\n <li><a href="javascript:;" class="font-color font-color-2" data-color=""></a></li>\n <li><a href="javascript:;" class="font-color font-color-3" data-color=""></a></li>\n <li><a href="javascript:;" class="font-color font-color-4" data-color=""></a></li>\n <li><a href="javascript:;" class="font-color font-color-5" data-color=""></a></li>\n <li><a href="javascript:;" class="font-color font-color-6" data-color=""></a></li>\n <li><a href="javascript:;" class="font-color font-color-7" data-color=""></a></li>\n <li><a href="javascript:;" class="font-color font-color-default" data-color=""></a></li>\n</ul>').appendTo(this.menuWrapper);
3219
+ $('<ul class="color-list">\n <li><a href="javascript:;" class="font-color font-color-1"></a></li>\n <li><a href="javascript:;" class="font-color font-color-2"></a></li>\n <li><a href="javascript:;" class="font-color font-color-3"></a></li>\n <li><a href="javascript:;" class="font-color font-color-4"></a></li>\n <li><a href="javascript:;" class="font-color font-color-5"></a></li>\n <li><a href="javascript:;" class="font-color font-color-6"></a></li>\n <li><a href="javascript:;" class="font-color font-color-7"></a></li>\n <li><a href="javascript:;" class="font-color font-color-default"></a></li>\n</ul>').appendTo(this.menuWrapper);
3149
3220
  this.menuWrapper.on('mousedown', '.color-list', function(e) {
3150
3221
  return false;
3151
3222
  });
@@ -3168,7 +3239,9 @@ ColorButton = (function(superClass) {
3168
3239
  if (!hex) {
3169
3240
  return;
3170
3241
  }
3242
+ document.execCommand('styleWithCSS', false, true);
3171
3243
  document.execCommand('foreColor', false, hex);
3244
+ document.execCommand('styleWithCSS', false, false);
3172
3245
  if (!_this.editor.util.support.oninput) {
3173
3246
  return _this.editor.trigger('valuechanged');
3174
3247
  }
@@ -3216,129 +3289,43 @@ ListButton = (function(superClass) {
3216
3289
 
3217
3290
  ListButton.prototype.disableTag = 'pre, table';
3218
3291
 
3219
- ListButton.prototype.status = function($node) {
3220
- var anotherType;
3221
- if ($node != null) {
3222
- this.setDisabled($node.is(this.disableTag));
3223
- }
3224
- if (this.disabled) {
3225
- return true;
3226
- }
3227
- if ($node == null) {
3228
- return this.active;
3229
- }
3230
- anotherType = this.type === 'ul' ? 'ol' : 'ul';
3231
- if ($node.is(anotherType)) {
3232
- this.setActive(false);
3233
- return true;
3234
- } else {
3235
- this.setActive($node.is(this.htmlTag));
3236
- return this.active;
3237
- }
3238
- };
3239
-
3240
3292
  ListButton.prototype.command = function(param) {
3241
- var $contents, $endBlock, $furthestEnd, $furthestStart, $parent, $startBlock, endLevel, endNode, getListLevel, j, len, node, range, ref, results, startLevel, startNode;
3242
- range = this.editor.selection.getRange();
3243
- startNode = range.startContainer;
3244
- endNode = range.endContainer;
3245
- $startBlock = this.editor.util.closestBlockEl(startNode);
3246
- $endBlock = this.editor.util.closestBlockEl(endNode);
3293
+ var $list, $rootNodes, anotherType;
3294
+ $rootNodes = this.editor.selection.blockNodes();
3295
+ anotherType = this.type === 'ul' ? 'ol' : 'ul';
3247
3296
  this.editor.selection.save();
3248
- range.setStartBefore($startBlock[0]);
3249
- range.setEndAfter($endBlock[0]);
3250
- if ($startBlock.is('li') && $endBlock.is('li')) {
3251
- $furthestStart = this.editor.util.furthestNode($startBlock, 'ul, ol');
3252
- $furthestEnd = this.editor.util.furthestNode($endBlock, 'ul, ol');
3253
- if ($furthestStart.is($furthestEnd)) {
3254
- getListLevel = function($li) {
3255
- var lvl;
3256
- lvl = 1;
3257
- while (!$li.parent().is($furthestStart)) {
3258
- lvl += 1;
3259
- $li = $li.parent();
3260
- }
3261
- return lvl;
3262
- };
3263
- startLevel = getListLevel($startBlock);
3264
- endLevel = getListLevel($endBlock);
3265
- if (startLevel > endLevel) {
3266
- $parent = $endBlock.parent();
3267
- } else {
3268
- $parent = $startBlock.parent();
3297
+ $list = null;
3298
+ $rootNodes.each((function(_this) {
3299
+ return function(i, node) {
3300
+ var $node;
3301
+ $node = $(node);
3302
+ if ($node.is('blockquote, li') || $node.is(_this.disableTag) || _this.editor.util.isDecoratedNode($node) || !$.contains(document, node)) {
3303
+ return;
3269
3304
  }
3270
- range.setStartBefore($parent[0]);
3271
- range.setEndAfter($parent[0]);
3272
- } else {
3273
- range.setStartBefore($furthestStart[0]);
3274
- range.setEndAfter($furthestEnd[0]);
3275
- }
3276
- }
3277
- $contents = $(range.extractContents());
3278
- results = [];
3279
- $contents.children().each((function(_this) {
3280
- return function(i, el) {
3281
- var c, converted, j, len, results1;
3282
- converted = _this._convertEl(el);
3283
- results1 = [];
3284
- for (j = 0, len = converted.length; j < len; j++) {
3285
- c = converted[j];
3286
- if (results.length && results[results.length - 1].is(_this.type) && c.is(_this.type)) {
3287
- results1.push(results[results.length - 1].append(c.children()));
3288
- } else {
3289
- results1.push(results.push(c));
3290
- }
3305
+ if ($node.is(_this.type)) {
3306
+ $node.children('li').each(function(i, li) {
3307
+ var $childList, $li;
3308
+ $li = $(li);
3309
+ $childList = $li.children('ul, ol').insertAfter($node);
3310
+ return $('<p/>').append($(li).html() || _this.editor.util.phBr).insertBefore($node);
3311
+ });
3312
+ return $node.remove();
3313
+ } else if ($node.is(anotherType)) {
3314
+ return $('<' + _this.type + '/>').append($node.contents()).replaceAll($node);
3315
+ } else if ($list && $node.prev().is($list)) {
3316
+ $('<li/>').append($node.html() || _this.editor.util.phBr).appendTo($list);
3317
+ return $node.remove();
3318
+ } else {
3319
+ $list = $("<" + _this.type + "><li></li></" + _this.type + ">");
3320
+ $list.find('li').append($node.html() || _this.editor.util.phBr);
3321
+ return $list.replaceAll($node);
3291
3322
  }
3292
- return results1;
3293
3323
  };
3294
3324
  })(this));
3295
- ref = results.reverse();
3296
- for (j = 0, len = ref.length; j < len; j++) {
3297
- node = ref[j];
3298
- range.insertNode(node[0]);
3299
- }
3300
3325
  this.editor.selection.restore();
3301
3326
  return this.editor.trigger('valuechanged');
3302
3327
  };
3303
3328
 
3304
- ListButton.prototype._convertEl = function(el) {
3305
- var $el, anotherType, block, child, children, j, len, ref, results;
3306
- $el = $(el);
3307
- results = [];
3308
- anotherType = this.type === 'ul' ? 'ol' : 'ul';
3309
- if ($el.is(this.type)) {
3310
- $el.children('li').each((function(_this) {
3311
- return function(i, li) {
3312
- var $childList, $li, block;
3313
- $li = $(li);
3314
- $childList = $li.children('ul, ol').remove();
3315
- block = $('<p/>').append($(li).html() || _this.editor.util.phBr);
3316
- results.push(block);
3317
- if ($childList.length > 0) {
3318
- return results.push($childList);
3319
- }
3320
- };
3321
- })(this));
3322
- } else if ($el.is(anotherType)) {
3323
- block = $('<' + this.type + '/>').append($el.html());
3324
- results.push(block);
3325
- } else if ($el.is('blockquote')) {
3326
- ref = $el.children().get();
3327
- for (j = 0, len = ref.length; j < len; j++) {
3328
- child = ref[j];
3329
- children = this._convertEl(child);
3330
- }
3331
- $.merge(results, children);
3332
- } else if ($el.is('table')) {
3333
-
3334
- } else {
3335
- block = $('<' + this.type + '><li></li></' + this.type + '>');
3336
- block.find('li').append($el.html() || this.editor.util.phBr);
3337
- results.push(block);
3338
- }
3339
- return results;
3340
- };
3341
-
3342
3329
  return ListButton;
3343
3330
 
3344
3331
  })(Button);
@@ -3425,59 +3412,40 @@ BlockquoteButton = (function(superClass) {
3425
3412
  BlockquoteButton.prototype.disableTag = 'pre, table';
3426
3413
 
3427
3414
  BlockquoteButton.prototype.command = function() {
3428
- var $contents, $endBlock, $startBlock, endNode, j, len, node, range, ref, results, startNode;
3429
- range = this.editor.selection.getRange();
3430
- startNode = range.startContainer;
3431
- endNode = range.endContainer;
3432
- $startBlock = this.editor.util.furthestBlockEl(startNode);
3433
- $endBlock = this.editor.util.furthestBlockEl(endNode);
3415
+ var $rootNodes, clearCache, nodeCache;
3416
+ $rootNodes = this.editor.selection.rootNodes();
3434
3417
  this.editor.selection.save();
3435
- range.setStartBefore($startBlock[0]);
3436
- range.setEndAfter($endBlock[0]);
3437
- $contents = $(range.extractContents());
3438
- results = [];
3439
- $contents.children().each((function(_this) {
3440
- return function(i, el) {
3441
- var c, converted, j, len, results1;
3442
- converted = _this._convertEl(el);
3443
- results1 = [];
3444
- for (j = 0, len = converted.length; j < len; j++) {
3445
- c = converted[j];
3446
- if (results.length && results[results.length - 1].is(_this.htmlTag) && c.is(_this.htmlTag)) {
3447
- results1.push(results[results.length - 1].append(c.children()));
3448
- } else {
3449
- results1.push(results.push(c));
3450
- }
3418
+ nodeCache = [];
3419
+ clearCache = (function(_this) {
3420
+ return function() {
3421
+ if (nodeCache.length > 0) {
3422
+ $("<" + _this.htmlTag + "/>").insertBefore(nodeCache[0]).append(nodeCache);
3423
+ return nodeCache.length = 0;
3424
+ }
3425
+ };
3426
+ })(this);
3427
+ $rootNodes.each((function(_this) {
3428
+ return function(i, node) {
3429
+ var $node;
3430
+ $node = $(node);
3431
+ if (!$node.parent().is(_this.editor.body)) {
3432
+ return;
3433
+ }
3434
+ if ($node.is(_this.htmlTag)) {
3435
+ clearCache();
3436
+ return $node.children().unwrap();
3437
+ } else if ($node.is(_this.disableTag) || _this.editor.util.isDecoratedNode($node)) {
3438
+ return clearCache();
3439
+ } else {
3440
+ return nodeCache.push(node);
3451
3441
  }
3452
- return results1;
3453
3442
  };
3454
3443
  })(this));
3455
- ref = results.reverse();
3456
- for (j = 0, len = ref.length; j < len; j++) {
3457
- node = ref[j];
3458
- range.insertNode(node[0]);
3459
- }
3444
+ clearCache();
3460
3445
  this.editor.selection.restore();
3461
3446
  return this.editor.trigger('valuechanged');
3462
3447
  };
3463
3448
 
3464
- BlockquoteButton.prototype._convertEl = function(el) {
3465
- var $el, block, results;
3466
- $el = $(el);
3467
- results = [];
3468
- if ($el.is(this.htmlTag)) {
3469
- $el.children().each((function(_this) {
3470
- return function(i, node) {
3471
- return results.push($(node));
3472
- };
3473
- })(this));
3474
- } else {
3475
- block = $('<' + this.htmlTag + '/>').append($el);
3476
- results.push(block);
3477
- }
3478
- return results;
3479
- };
3480
-
3481
3449
  return BlockquoteButton;
3482
3450
 
3483
3451
  })(Button);
@@ -3497,7 +3465,7 @@ CodeButton = (function(superClass) {
3497
3465
 
3498
3466
  CodeButton.prototype.htmlTag = 'pre';
3499
3467
 
3500
- CodeButton.prototype.disableTag = 'li, table';
3468
+ CodeButton.prototype.disableTag = 'ul, ol, table';
3501
3469
 
3502
3470
  CodeButton.prototype._init = function() {
3503
3471
  CodeButton.__super__._init.call(this);
@@ -3526,15 +3494,13 @@ CodeButton = (function(superClass) {
3526
3494
  });
3527
3495
  };
3528
3496
 
3529
- CodeButton.prototype.status = function($node) {
3530
- var result;
3531
- result = CodeButton.__super__.status.call(this, $node);
3497
+ CodeButton.prototype._status = function() {
3498
+ CodeButton.__super__._status.call(this);
3532
3499
  if (this.active) {
3533
- this.popover.show($node);
3534
- } else if (this.editor.util.isBlockNode($node)) {
3535
- this.popover.hide();
3500
+ return this.popover.show(this.node);
3501
+ } else {
3502
+ return this.popover.hide();
3536
3503
  }
3537
- return result;
3538
3504
  };
3539
3505
 
3540
3506
  CodeButton.prototype.decorate = function($pre) {
@@ -3560,60 +3526,40 @@ CodeButton = (function(superClass) {
3560
3526
  };
3561
3527
 
3562
3528
  CodeButton.prototype.command = function() {
3563
- var $contents, $endBlock, $startBlock, endNode, j, len, node, range, ref, results, startNode;
3564
- range = this.editor.selection.getRange();
3565
- startNode = range.startContainer;
3566
- endNode = range.endContainer;
3567
- $startBlock = this.editor.util.closestBlockEl(startNode);
3568
- $endBlock = this.editor.util.closestBlockEl(endNode);
3569
- range.setStartBefore($startBlock[0]);
3570
- range.setEndAfter($endBlock[0]);
3571
- $contents = $(range.extractContents());
3572
- results = [];
3573
- $contents.children().each((function(_this) {
3574
- return function(i, el) {
3575
- var c, converted, j, len, results1;
3576
- converted = _this._convertEl(el);
3577
- results1 = [];
3578
- for (j = 0, len = converted.length; j < len; j++) {
3579
- c = converted[j];
3580
- if (results.length && results[results.length - 1].is(_this.htmlTag) && c.is(_this.htmlTag)) {
3581
- results1.push(results[results.length - 1].append(c.contents()));
3582
- } else {
3583
- results1.push(results.push(c));
3584
- }
3529
+ var $rootNodes, clearCache, nodeCache, pres;
3530
+ $rootNodes = this.editor.selection.rootNodes();
3531
+ nodeCache = [];
3532
+ pres = [];
3533
+ clearCache = (function(_this) {
3534
+ return function() {
3535
+ var $pre;
3536
+ if (!(nodeCache.length > 0)) {
3537
+ return;
3538
+ }
3539
+ $pre = $("<" + _this.htmlTag + "/>").insertBefore(nodeCache[0]).text(_this.editor.formatter.clearHtml(nodeCache));
3540
+ pres.push($pre[0]);
3541
+ return nodeCache.length = 0;
3542
+ };
3543
+ })(this);
3544
+ $rootNodes.each((function(_this) {
3545
+ return function(i, node) {
3546
+ var $node;
3547
+ $node = $(node);
3548
+ if ($node.is(_this.htmlTag)) {
3549
+ clearCache();
3550
+ return $('<p/>').append($node.html().replace('\n', '<br/>')).replaceAll($node);
3551
+ } else if ($node.is(_this.disableTag) || _this.editor.util.isDecoratedNode($node) || $node.is('blockquote')) {
3552
+ return clearCache();
3553
+ } else {
3554
+ return nodeCache.push(node);
3585
3555
  }
3586
- return results1;
3587
3556
  };
3588
3557
  })(this));
3589
- ref = results.reverse();
3590
- for (j = 0, len = ref.length; j < len; j++) {
3591
- node = ref[j];
3592
- range.insertNode(node[0]);
3593
- }
3594
- this.editor.selection.setRangeAtEndOf(results[0]);
3558
+ clearCache();
3559
+ this.editor.selection.setRangeAtEndOf($(pres).last());
3595
3560
  return this.editor.trigger('valuechanged');
3596
3561
  };
3597
3562
 
3598
- CodeButton.prototype._convertEl = function(el) {
3599
- var $el, block, codeStr, results;
3600
- $el = $(el);
3601
- results = [];
3602
- if ($el.is(this.htmlTag)) {
3603
- block = $('<p/>').append($el.html().replace('\n', '<br/>'));
3604
- results.push(block);
3605
- } else {
3606
- if (!$el.text() && $el.children().length === 1 && $el.children().is('br')) {
3607
- codeStr = '\n';
3608
- } else {
3609
- codeStr = this.editor.formatter.clearHtml($el);
3610
- }
3611
- block = $('<' + this.htmlTag + '/>').text(codeStr);
3612
- results.push(block);
3613
- }
3614
- return results;
3615
- };
3616
-
3617
3563
  return CodeButton;
3618
3564
 
3619
3565
  })(Button);
@@ -3626,7 +3572,7 @@ CodePopover = (function(superClass) {
3626
3572
  }
3627
3573
 
3628
3574
  CodePopover.prototype.render = function() {
3629
- var $option, j, lang, len, ref;
3575
+ var $option, k, lang, len, ref;
3630
3576
  this._tpl = "<div class=\"code-settings\">\n <div class=\"settings-field\">\n <select class=\"select-lang\">\n <option value=\"-1\">" + (this._t('selectLanguage')) + "</option>\n </select>\n </div>\n</div>";
3631
3577
  this.langs = this.editor.opts.codeLanguages || [
3632
3578
  {
@@ -3694,8 +3640,8 @@ CodePopover = (function(superClass) {
3694
3640
  this.el.addClass('code-popover').append(this._tpl);
3695
3641
  this.selectEl = this.el.find('.select-lang');
3696
3642
  ref = this.langs;
3697
- for (j = 0, len = ref.length; j < len; j++) {
3698
- lang = ref[j];
3643
+ for (k = 0, len = ref.length; k < len; k++) {
3644
+ lang = ref[k];
3699
3645
  $option = $('<option/>', {
3700
3646
  text: lang.name,
3701
3647
  value: lang.value
@@ -3767,48 +3713,23 @@ LinkButton = (function(superClass) {
3767
3713
  });
3768
3714
  };
3769
3715
 
3770
- LinkButton.prototype.status = function($node) {
3771
- var showPopover;
3772
- if ($node != null) {
3773
- this.setDisabled($node.is(this.disableTag));
3774
- }
3775
- if (this.disabled) {
3776
- return true;
3777
- }
3778
- if ($node == null) {
3779
- return this.active;
3780
- }
3781
- showPopover = true;
3782
- if (!$node.is(this.htmlTag) || $node.is('[class^="simditor-"]')) {
3783
- this.setActive(false);
3784
- showPopover = false;
3785
- } else if (this.editor.selection.rangeAtEndOf($node)) {
3786
- this.setActive(true);
3787
- showPopover = false;
3716
+ LinkButton.prototype._status = function() {
3717
+ LinkButton.__super__._status.call(this);
3718
+ if (this.active && !this.editor.selection.rangeAtEndOf(this.node)) {
3719
+ return this.popover.show(this.node);
3788
3720
  } else {
3789
- this.setActive(true);
3790
- }
3791
- if (showPopover) {
3792
- this.popover.show($node);
3793
- } else if (this.editor.util.isBlockNode($node)) {
3794
- this.popover.hide();
3721
+ return this.popover.hide();
3795
3722
  }
3796
- return this.active;
3797
3723
  };
3798
3724
 
3799
3725
  LinkButton.prototype.command = function() {
3800
- var $contents, $endBlock, $link, $newBlock, $startBlock, endNode, linkText, range, startNode, txtNode;
3801
- range = this.editor.selection.getRange();
3726
+ var $contents, $link, $newBlock, linkText, range, txtNode;
3727
+ range = this.editor.selection.range();
3802
3728
  if (this.active) {
3803
- $link = $(range.commonAncestorContainer).closest('a');
3804
- txtNode = document.createTextNode($link.text());
3805
- $link.replaceWith(txtNode);
3729
+ txtNode = document.createTextNode(this.node.text());
3730
+ this.node.replaceWith(txtNode);
3806
3731
  range.selectNode(txtNode);
3807
3732
  } else {
3808
- startNode = range.startContainer;
3809
- endNode = range.endContainer;
3810
- $startBlock = this.editor.util.closestBlockEl(startNode);
3811
- $endBlock = this.editor.util.closestBlockEl(endNode);
3812
3733
  $contents = $(range.extractContents());
3813
3734
  linkText = this.editor.formatter.clearHtml($contents.contents(), false);
3814
3735
  $link = $('<a/>', {
@@ -3816,7 +3737,7 @@ LinkButton = (function(superClass) {
3816
3737
  target: '_blank',
3817
3738
  text: linkText || this._t('linkText')
3818
3739
  });
3819
- if ($startBlock[0] === $endBlock[0]) {
3740
+ if (this.editor.selection.blockNodes().length === 1) {
3820
3741
  range.insertNode($link[0]);
3821
3742
  } else {
3822
3743
  $newBlock = $('<p/>').append($link);
@@ -3835,7 +3756,7 @@ LinkButton = (function(superClass) {
3835
3756
  };
3836
3757
  })(this));
3837
3758
  }
3838
- this.editor.selection.selectRange(range);
3759
+ this.editor.selection.range(range);
3839
3760
  return this.editor.trigger('valuechanged');
3840
3761
  };
3841
3762
 
@@ -3852,7 +3773,7 @@ LinkPopover = (function(superClass) {
3852
3773
 
3853
3774
  LinkPopover.prototype.render = function() {
3854
3775
  var tpl;
3855
- tpl = "<div class=\"link-settings\">\n <div class=\"settings-field\">\n <label>" + (this._t('text')) + "</label>\n <input class=\"link-text\" type=\"text\"/>\n <a class=\"btn-unlink\" href=\"javascript:;\" title=\"" + (this._t('removeLink')) + "\" tabindex=\"-1\"><span class=\"simditor-icon simditor-icon-unlink\"></span></a>\n </div>\n <div class=\"settings-field\">\n <label>" + (this._t('linkUrl')) + "</label>\n <input class=\"link-url\" type=\"text\"/>\n </div>\n</div>";
3776
+ tpl = "<div class=\"link-settings\">\n <div class=\"settings-field\">\n <label>" + (this._t('text')) + "</label>\n <input class=\"link-text\" type=\"text\"/>\n <a class=\"btn-unlink\" href=\"javascript:;\" title=\"" + (this._t('removeLink')) + "\"\n tabindex=\"-1\">\n <span class=\"simditor-icon simditor-icon-unlink\"></span>\n </a>\n </div>\n <div class=\"settings-field\">\n <label>" + (this._t('linkUrl')) + "</label>\n <input class=\"link-url\" type=\"text\"/>\n </div>\n</div>";
3856
3777
  this.el.addClass('link-popover').append(tpl);
3857
3778
  this.textEl = this.el.find('.link-text');
3858
3779
  this.urlEl = this.el.find('.link-url');
@@ -3880,15 +3801,13 @@ LinkPopover = (function(superClass) {
3880
3801
  })(this));
3881
3802
  $([this.urlEl[0], this.textEl[0]]).on('keydown', (function(_this) {
3882
3803
  return function(e) {
3804
+ var range;
3883
3805
  if (e.which === 13 || e.which === 27 || (!e.shiftKey && e.which === 9 && $(e.target).hasClass('link-url'))) {
3884
3806
  e.preventDefault();
3885
- return setTimeout(function() {
3886
- var range;
3887
- range = document.createRange();
3888
- _this.editor.selection.setRangeAfter(_this.target, range);
3889
- _this.hide();
3890
- return _this.editor.trigger('valuechanged');
3891
- }, 0);
3807
+ range = document.createRange();
3808
+ _this.editor.selection.setRangeAfter(_this.target, range);
3809
+ _this.hide();
3810
+ return _this.editor.trigger('valuechanged');
3892
3811
  }
3893
3812
  };
3894
3813
  })(this));
@@ -3939,13 +3858,13 @@ ImageButton = (function(superClass) {
3939
3858
  ImageButton.prototype.needFocus = false;
3940
3859
 
3941
3860
  ImageButton.prototype._init = function() {
3942
- var item, j, len, ref;
3861
+ var item, k, len, ref;
3943
3862
  if (this.editor.opts.imageButton) {
3944
3863
  if (Array.isArray(this.editor.opts.imageButton)) {
3945
3864
  this.menu = [];
3946
3865
  ref = this.editor.opts.imageButton;
3947
- for (j = 0, len = ref.length; j < len; j++) {
3948
- item = ref[j];
3866
+ for (k = 0, len = ref.length; k < len; k++) {
3867
+ item = ref[k];
3949
3868
  this.menu.push({
3950
3869
  name: item + '-image',
3951
3870
  text: this._t(item + 'Image')
@@ -3976,22 +3895,20 @@ ImageButton = (function(superClass) {
3976
3895
  $img = $(e.currentTarget);
3977
3896
  range = document.createRange();
3978
3897
  range.selectNode($img[0]);
3979
- _this.editor.selection.selectRange(range);
3898
+ _this.editor.selection.range(range);
3980
3899
  if (!_this.editor.util.support.onselectionchange) {
3981
3900
  _this.editor.trigger('selectionchanged');
3982
3901
  }
3983
3902
  return false;
3984
3903
  };
3985
3904
  })(this));
3986
- this.editor.body.on('mouseup', 'img:not([data-non-image])', (function(_this) {
3987
- return function(e) {
3988
- return false;
3989
- };
3990
- })(this));
3905
+ this.editor.body.on('mouseup', 'img:not([data-non-image])', function(e) {
3906
+ return false;
3907
+ });
3991
3908
  this.editor.on('selectionchanged.image', (function(_this) {
3992
3909
  return function() {
3993
3910
  var $contents, $img, range;
3994
- range = _this.editor.selection.getRange();
3911
+ range = _this.editor.selection.range();
3995
3912
  if (range == null) {
3996
3913
  return;
3997
3914
  }
@@ -4051,7 +3968,7 @@ ImageButton = (function(superClass) {
4051
3968
  };
4052
3969
 
4053
3970
  ImageButton.prototype._initUploader = function($uploadItem) {
4054
- var $input, createInput;
3971
+ var $input, createInput, uploadProgress;
4055
3972
  if ($uploadItem == null) {
4056
3973
  $uploadItem = this.menuEl.find('.menu-item-upload-image');
4057
3974
  }
@@ -4065,15 +3982,17 @@ ImageButton = (function(superClass) {
4065
3982
  if ($input) {
4066
3983
  $input.remove();
4067
3984
  }
4068
- return $input = $('<input type="file" title="' + _this._t('uploadImage') + '" accept="image/*">').appendTo($uploadItem);
3985
+ return $input = $('<input/>', {
3986
+ type: 'file',
3987
+ title: _this._t('uploadImage'),
3988
+ accept: 'image/*'
3989
+ }).appendTo($uploadItem);
4069
3990
  };
4070
3991
  })(this);
4071
3992
  createInput();
4072
- $uploadItem.on('click mousedown', 'input[type=file]', (function(_this) {
4073
- return function(e) {
4074
- return e.stopPropagation();
4075
- };
4076
- })(this));
3993
+ $uploadItem.on('click mousedown', 'input[type=file]', function(e) {
3994
+ return e.stopPropagation();
3995
+ });
4077
3996
  $uploadItem.on('change', 'input[type=file]', (function(_this) {
4078
3997
  return function(e) {
4079
3998
  if (_this.editor.inputManager.focused) {
@@ -4122,7 +4041,7 @@ ImageButton = (function(superClass) {
4122
4041
  });
4123
4042
  };
4124
4043
  })(this));
4125
- this.editor.uploader.on('uploadprogress', $.proxy(this.editor.util.throttle(function(e, file, loaded, total) {
4044
+ uploadProgress = $.proxy(this.editor.util.throttle(function(e, file, loaded, total) {
4126
4045
  var $img, $mask, percent;
4127
4046
  if (!file.inline) {
4128
4047
  return;
@@ -4142,7 +4061,8 @@ ImageButton = (function(superClass) {
4142
4061
  percent = 99;
4143
4062
  }
4144
4063
  return $mask.find('.progress').height((100 - percent) + "%");
4145
- }, 500), this));
4064
+ }, 500), this);
4065
+ this.editor.uploader.on('uploadprogress', uploadProgress);
4146
4066
  this.editor.uploader.on('uploadsuccess', (function(_this) {
4147
4067
  return function(e, file, result) {
4148
4068
  var $img, $mask, msg;
@@ -4230,13 +4150,8 @@ ImageButton = (function(superClass) {
4230
4150
  })(this));
4231
4151
  };
4232
4152
 
4233
- ImageButton.prototype.status = function($node) {
4234
- if ($node != null) {
4235
- this.setDisabled($node.is(this.disableTag));
4236
- }
4237
- if (this.disabled) {
4238
- return true;
4239
- }
4153
+ ImageButton.prototype._status = function() {
4154
+ return this._disableStatus();
4240
4155
  };
4241
4156
 
4242
4157
  ImageButton.prototype.loadImage = function($img, src, callback) {
@@ -4257,7 +4172,7 @@ ImageButton = (function(superClass) {
4257
4172
  $img.addClass('loading');
4258
4173
  $mask = $img.data('mask');
4259
4174
  if (!$mask) {
4260
- $mask = $('<div class="simditor-image-loading"><div class="progress"></div></div>').hide().appendTo(this.editor.wrapper);
4175
+ $mask = $('<div class="simditor-image-loading">\n <div class="progress"></div>\n</div>').hide().appendTo(this.editor.wrapper);
4261
4176
  positionMask();
4262
4177
  $img.data('mask', $mask);
4263
4178
  $mask.data('img', $img);
@@ -4273,6 +4188,8 @@ ImageButton = (function(superClass) {
4273
4188
  height = img.height;
4274
4189
  $img.attr({
4275
4190
  src: src,
4191
+ width: width,
4192
+ height: height,
4276
4193
  'data-image-size': width + ',' + height
4277
4194
  }).removeClass('loading');
4278
4195
  if ($img.hasClass('uploading')) {
@@ -4285,38 +4202,29 @@ ImageButton = (function(superClass) {
4285
4202
  return callback(img);
4286
4203
  };
4287
4204
  })(this);
4288
- img.onerror = (function(_this) {
4289
- return function() {
4290
- callback(false);
4291
- $mask.remove();
4292
- return $img.removeData('mask').removeClass('loading');
4293
- };
4294
- })(this);
4205
+ img.onerror = function() {
4206
+ callback(false);
4207
+ $mask.remove();
4208
+ return $img.removeData('mask').removeClass('loading');
4209
+ };
4295
4210
  return img.src = src;
4296
4211
  };
4297
4212
 
4298
4213
  ImageButton.prototype.createImage = function(name) {
4299
- var $block, $img, $nextBlock, range;
4214
+ var $img, range;
4300
4215
  if (name == null) {
4301
4216
  name = 'Image';
4302
4217
  }
4303
4218
  if (!this.editor.inputManager.focused) {
4304
4219
  this.editor.focus();
4305
4220
  }
4306
- range = this.editor.selection.getRange();
4221
+ range = this.editor.selection.range();
4307
4222
  range.deleteContents();
4308
- $block = this.editor.util.closestBlockEl();
4309
- if ($block.is('p') && !this.editor.util.isEmptyNode($block)) {
4310
- $block = $('<p/>').append(this.editor.util.phBr).insertAfter($block);
4311
- this.editor.selection.setRangeAtStartOf($block, range);
4312
- }
4223
+ this.editor.selection.range(range);
4313
4224
  $img = $('<img/>').attr('alt', name);
4314
4225
  range.insertNode($img[0]);
4315
- $nextBlock = $block.next('p');
4316
- if (!($nextBlock.length > 0)) {
4317
- $nextBlock = $('<p/>').append(this.editor.util.phBr).insertAfter($block);
4318
- }
4319
- this.editor.selection.setRangeAtStartOf($nextBlock);
4226
+ this.editor.selection.setRangeAfter($img, range);
4227
+ this.editor.trigger('valuechanged');
4320
4228
  return $img;
4321
4229
  };
4322
4230
 
@@ -4354,7 +4262,7 @@ ImagePopover = (function(superClass) {
4354
4262
 
4355
4263
  ImagePopover.prototype.render = function() {
4356
4264
  var tpl;
4357
- tpl = "<div class=\"link-settings\">\n <div class=\"settings-field\">\n <label>" + (this._t('imageUrl')) + "</label>\n <input class=\"image-src\" type=\"text\" tabindex=\"1\" />\n <a class=\"btn-upload\" href=\"javascript:;\" title=\"" + (this._t('uploadImage')) + "\" tabindex=\"-1\">\n <span class=\"simditor-icon simditor-icon-upload\"></span>\n </a>\n </div>\n <div class='settings-field'>\n <label>" + (this._t('imageAlt')) + "</label>\n <input class=\"image-alt\" id=\"image-alt\" type=\"text\" tabindex=\"1\" />\n </div>\n <div class=\"settings-field\">\n <label>" + (this._t('imageSize')) + "</label>\n <input class=\"image-size\" id=\"image-width\" type=\"text\" tabindex=\"2\" />\n <span class=\"times\">×</span>\n <input class=\"image-size\" id=\"image-height\" type=\"text\" tabindex=\"3\" />\n <a class=\"btn-restore\" href=\"javascript:;\" title=\"" + (this._t('restoreImageSize')) + "\" tabindex=\"-1\">\n <span class=\"simditor-icon simditor-icon-undo\"></span>\n </a>\n </div>\n</div>";
4265
+ tpl = "<div class=\"link-settings\">\n <div class=\"settings-field\">\n <label>" + (this._t('imageUrl')) + "</label>\n <input class=\"image-src\" type=\"text\" tabindex=\"1\" />\n <a class=\"btn-upload\" href=\"javascript:;\"\n title=\"" + (this._t('uploadImage')) + "\" tabindex=\"-1\">\n <span class=\"simditor-icon simditor-icon-upload\"></span>\n </a>\n </div>\n <div class='settings-field'>\n <label>" + (this._t('imageAlt')) + "</label>\n <input class=\"image-alt\" id=\"image-alt\" type=\"text\" tabindex=\"1\" />\n </div>\n <div class=\"settings-field\">\n <label>" + (this._t('imageSize')) + "</label>\n <input class=\"image-size\" id=\"image-width\" type=\"text\" tabindex=\"2\" />\n <span class=\"times\">×</span>\n <input class=\"image-size\" id=\"image-height\" type=\"text\" tabindex=\"3\" />\n <a class=\"btn-restore\" href=\"javascript:;\"\n title=\"" + (this._t('restoreImageSize')) + "\" tabindex=\"-1\">\n <span class=\"simditor-icon simditor-icon-undo\"></span>\n </a>\n </div>\n</div>";
4358
4266
  this.el.addClass('image-popover').append(tpl);
4359
4267
  this.srcEl = this.el.find('.image-src');
4360
4268
  this.widthEl = this.el.find('#image-width');
@@ -4457,15 +4365,17 @@ ImagePopover = (function(superClass) {
4457
4365
  if (_this.input) {
4458
4366
  _this.input.remove();
4459
4367
  }
4460
- return _this.input = $('<input type="file" title="' + _this._t('uploadImage') + '" accept="image/*">').appendTo($uploadBtn);
4368
+ return _this.input = $('<input/>', {
4369
+ type: 'file',
4370
+ title: _this._t('uploadImage'),
4371
+ accept: 'image/*'
4372
+ }).appendTo($uploadBtn);
4461
4373
  };
4462
4374
  })(this);
4463
4375
  createInput();
4464
- this.el.on('click mousedown', 'input[type=file]', (function(_this) {
4465
- return function(e) {
4466
- return e.stopPropagation();
4467
- };
4468
- })(this));
4376
+ this.el.on('click mousedown', 'input[type=file]', function(e) {
4377
+ return e.stopPropagation();
4378
+ });
4469
4379
  return this.el.on('change', 'input[type=file]', (function(_this) {
4470
4380
  return function(e) {
4471
4381
  _this.editor.uploader.upload(_this.input, {
@@ -4487,16 +4397,18 @@ ImagePopover = (function(superClass) {
4487
4397
  return;
4488
4398
  }
4489
4399
  if (inputEl.is(this.widthEl)) {
4400
+ width = value;
4490
4401
  height = this.height * value / this.width;
4491
4402
  this.heightEl.val(height);
4492
4403
  } else {
4404
+ height = value;
4493
4405
  width = this.width * value / this.height;
4494
4406
  this.widthEl.val(width);
4495
4407
  }
4496
4408
  if (!onlySetVal) {
4497
4409
  this.target.attr({
4498
- width: width || value,
4499
- height: height || value
4410
+ width: width,
4411
+ height: height
4500
4412
  });
4501
4413
  }
4502
4414
  return this.editor.trigger('valuechanged');
@@ -4521,6 +4433,9 @@ ImagePopover = (function(superClass) {
4521
4433
  }
4522
4434
  return;
4523
4435
  }
4436
+ if (this.target.attr('src') === src) {
4437
+ return;
4438
+ }
4524
4439
  return this.button.loadImage(this.target, src, (function(_this) {
4525
4440
  return function(img) {
4526
4441
  var blob;
@@ -4532,7 +4447,6 @@ ImagePopover = (function(superClass) {
4532
4447
  _this.height = img.height;
4533
4448
  _this.widthEl.val(_this.width);
4534
4449
  _this.heightEl.val(_this.height);
4535
- _this.target.removeAttr('width').removeAttr('height');
4536
4450
  }
4537
4451
  if (/^data:image/.test(src)) {
4538
4452
  blob = _this.editor.util.dataURLtoBlob(src);
@@ -4591,9 +4505,7 @@ IndentButton = (function(superClass) {
4591
4505
  return IndentButton.__super__._init.call(this);
4592
4506
  };
4593
4507
 
4594
- IndentButton.prototype.status = function($node) {
4595
- return true;
4596
- };
4508
+ IndentButton.prototype._status = function() {};
4597
4509
 
4598
4510
  IndentButton.prototype.command = function() {
4599
4511
  return this.editor.indentation.indent();
@@ -4621,9 +4533,7 @@ OutdentButton = (function(superClass) {
4621
4533
  return OutdentButton.__super__._init.call(this);
4622
4534
  };
4623
4535
 
4624
- OutdentButton.prototype.status = function($node) {
4625
- return true;
4626
- };
4536
+ OutdentButton.prototype._status = function() {};
4627
4537
 
4628
4538
  OutdentButton.prototype.command = function() {
4629
4539
  return this.editor.indentation.indent(true);
@@ -4648,13 +4558,11 @@ HrButton = (function(superClass) {
4648
4558
 
4649
4559
  HrButton.prototype.htmlTag = 'hr';
4650
4560
 
4651
- HrButton.prototype.status = function($node) {
4652
- return true;
4653
- };
4561
+ HrButton.prototype._status = function() {};
4654
4562
 
4655
4563
  HrButton.prototype.command = function() {
4656
4564
  var $hr, $newBlock, $nextBlock, $rootBlock;
4657
- $rootBlock = this.editor.util.furthestBlockEl();
4565
+ $rootBlock = this.editor.selection.rootNodes().first();
4658
4566
  $nextBlock = $rootBlock.next();
4659
4567
  if ($nextBlock.length > 0) {
4660
4568
  this.editor.selection.save();
@@ -4701,6 +4609,10 @@ TableButton = (function(superClass) {
4701
4609
  td: ['rowspan', 'colspan'],
4702
4610
  col: ['width']
4703
4611
  });
4612
+ $.extend(this.editor.formatter._allowedStyles, {
4613
+ td: ['text-align'],
4614
+ th: ['text-align']
4615
+ });
4704
4616
  this._initShortcuts();
4705
4617
  this.editor.on('decorate', (function(_this) {
4706
4618
  return function(e, $el) {
@@ -4720,11 +4632,11 @@ TableButton = (function(superClass) {
4720
4632
  return function(e) {
4721
4633
  var $container, range;
4722
4634
  _this.editor.body.find('.simditor-table td, .simditor-table th').removeClass('active');
4723
- range = _this.editor.selection.getRange();
4724
- if (range == null) {
4635
+ range = _this.editor.selection.range();
4636
+ if (!range) {
4725
4637
  return;
4726
4638
  }
4727
- $container = $(range.commonAncestorContainer);
4639
+ $container = _this.editor.selection.containerNode();
4728
4640
  if (range.collapsed && $container.is('.simditor-table')) {
4729
4641
  if (_this.editor.selection.rangeAtStartOf($container)) {
4730
4642
  $container = $container.find('th:first');
@@ -4807,88 +4719,83 @@ TableButton = (function(superClass) {
4807
4719
  $colgroup = $table.find('colgroup');
4808
4720
  if ($colgroup.length < 1) {
4809
4721
  $colgroup = $('<colgroup/>').prependTo($table);
4810
- $table.find('thead tr th').each((function(_this) {
4811
- return function(i, td) {
4812
- var $col;
4813
- return $col = $('<col/>').appendTo($colgroup);
4814
- };
4815
- })(this));
4722
+ $table.find('thead tr th').each(function(i, td) {
4723
+ var $col;
4724
+ return $col = $('<col/>').appendTo($colgroup);
4725
+ });
4816
4726
  this.refreshTableWidth($table);
4817
4727
  }
4818
- $resizeHandle = $('<div class="simditor-resize-handle" contenteditable="false"></div>').appendTo($wrapper);
4819
- $wrapper.on('mousemove', 'td, th', (function(_this) {
4820
- return function(e) {
4821
- var $col, $td, index, ref, ref1, x;
4822
- if ($wrapper.hasClass('resizing')) {
4823
- return;
4824
- }
4825
- $td = $(e.currentTarget);
4826
- x = e.pageX - $(e.currentTarget).offset().left;
4827
- if (x < 5 && $td.prev().length > 0) {
4828
- $td = $td.prev();
4829
- }
4830
- if ($td.next('td, th').length < 1) {
4831
- $resizeHandle.hide();
4832
- return;
4833
- }
4834
- if ((ref = $resizeHandle.data('td')) != null ? ref.is($td) : void 0) {
4835
- $resizeHandle.show();
4836
- return;
4837
- }
4838
- index = $td.parent().find('td, th').index($td);
4839
- $col = $colgroup.find('col').eq(index);
4840
- if ((ref1 = $resizeHandle.data('col')) != null ? ref1.is($col) : void 0) {
4841
- $resizeHandle.show();
4842
- return;
4843
- }
4844
- return $resizeHandle.css('left', $td.position().left + $td.outerWidth() - 5).data('td', $td).data('col', $col).show();
4845
- };
4846
- })(this));
4847
- $wrapper.on('mouseleave', (function(_this) {
4848
- return function(e) {
4849
- return $resizeHandle.hide();
4850
- };
4851
- })(this));
4852
- return $wrapper.on('mousedown', '.simditor-resize-handle', (function(_this) {
4853
- return function(e) {
4854
- var $handle, $leftCol, $leftTd, $rightCol, $rightTd, minWidth, startHandleLeft, startLeftWidth, startRightWidth, startX, tableWidth;
4855
- $handle = $(e.currentTarget);
4856
- $leftTd = $handle.data('td');
4857
- $leftCol = $handle.data('col');
4858
- $rightTd = $leftTd.next('td, th');
4859
- $rightCol = $leftCol.next('col');
4860
- startX = e.pageX;
4861
- startLeftWidth = $leftTd.outerWidth() * 1;
4862
- startRightWidth = $rightTd.outerWidth() * 1;
4863
- startHandleLeft = parseFloat($handle.css('left'));
4864
- tableWidth = $leftTd.closest('table').width();
4865
- minWidth = 50;
4866
- $(document).on('mousemove.simditor-resize-table', function(e) {
4867
- var deltaX, leftWidth, rightWidth;
4868
- deltaX = e.pageX - startX;
4869
- leftWidth = startLeftWidth + deltaX;
4728
+ $resizeHandle = $('<div />', {
4729
+ "class": 'simditor-resize-handle',
4730
+ contenteditable: 'false'
4731
+ }).appendTo($wrapper);
4732
+ $wrapper.on('mousemove', 'td, th', function(e) {
4733
+ var $col, $td, index, ref, ref1, x;
4734
+ if ($wrapper.hasClass('resizing')) {
4735
+ return;
4736
+ }
4737
+ $td = $(e.currentTarget);
4738
+ x = e.pageX - $(e.currentTarget).offset().left;
4739
+ if (x < 5 && $td.prev().length > 0) {
4740
+ $td = $td.prev();
4741
+ }
4742
+ if ($td.next('td, th').length < 1) {
4743
+ $resizeHandle.hide();
4744
+ return;
4745
+ }
4746
+ if ((ref = $resizeHandle.data('td')) != null ? ref.is($td) : void 0) {
4747
+ $resizeHandle.show();
4748
+ return;
4749
+ }
4750
+ index = $td.parent().find('td, th').index($td);
4751
+ $col = $colgroup.find('col').eq(index);
4752
+ if ((ref1 = $resizeHandle.data('col')) != null ? ref1.is($col) : void 0) {
4753
+ $resizeHandle.show();
4754
+ return;
4755
+ }
4756
+ return $resizeHandle.css('left', $td.position().left + $td.outerWidth() - 5).data('td', $td).data('col', $col).show();
4757
+ });
4758
+ $wrapper.on('mouseleave', function(e) {
4759
+ return $resizeHandle.hide();
4760
+ });
4761
+ return $wrapper.on('mousedown', '.simditor-resize-handle', function(e) {
4762
+ var $handle, $leftCol, $leftTd, $rightCol, $rightTd, minWidth, startHandleLeft, startLeftWidth, startRightWidth, startX, tableWidth;
4763
+ $handle = $(e.currentTarget);
4764
+ $leftTd = $handle.data('td');
4765
+ $leftCol = $handle.data('col');
4766
+ $rightTd = $leftTd.next('td, th');
4767
+ $rightCol = $leftCol.next('col');
4768
+ startX = e.pageX;
4769
+ startLeftWidth = $leftTd.outerWidth() * 1;
4770
+ startRightWidth = $rightTd.outerWidth() * 1;
4771
+ startHandleLeft = parseFloat($handle.css('left'));
4772
+ tableWidth = $leftTd.closest('table').width();
4773
+ minWidth = 50;
4774
+ $(document).on('mousemove.simditor-resize-table', function(e) {
4775
+ var deltaX, leftWidth, rightWidth;
4776
+ deltaX = e.pageX - startX;
4777
+ leftWidth = startLeftWidth + deltaX;
4778
+ rightWidth = startRightWidth - deltaX;
4779
+ if (leftWidth < minWidth) {
4780
+ leftWidth = minWidth;
4781
+ deltaX = minWidth - startLeftWidth;
4870
4782
  rightWidth = startRightWidth - deltaX;
4871
- if (leftWidth < minWidth) {
4872
- leftWidth = minWidth;
4873
- deltaX = minWidth - startLeftWidth;
4874
- rightWidth = startRightWidth - deltaX;
4875
- } else if (rightWidth < minWidth) {
4876
- rightWidth = minWidth;
4877
- deltaX = startRightWidth - minWidth;
4878
- leftWidth = startLeftWidth + deltaX;
4879
- }
4880
- $leftCol.attr('width', (leftWidth / tableWidth * 100) + '%');
4881
- $rightCol.attr('width', (rightWidth / tableWidth * 100) + '%');
4882
- return $handle.css('left', startHandleLeft + deltaX);
4883
- });
4884
- $(document).one('mouseup.simditor-resize-table', function(e) {
4885
- $(document).off('.simditor-resize-table');
4886
- return $wrapper.removeClass('resizing');
4887
- });
4888
- $wrapper.addClass('resizing');
4889
- return false;
4890
- };
4891
- })(this));
4783
+ } else if (rightWidth < minWidth) {
4784
+ rightWidth = minWidth;
4785
+ deltaX = startRightWidth - minWidth;
4786
+ leftWidth = startLeftWidth + deltaX;
4787
+ }
4788
+ $leftCol.attr('width', (leftWidth / tableWidth * 100) + '%');
4789
+ $rightCol.attr('width', (rightWidth / tableWidth * 100) + '%');
4790
+ return $handle.css('left', startHandleLeft + deltaX);
4791
+ });
4792
+ $(document).one('mouseup.simditor-resize-table', function(e) {
4793
+ $(document).off('.simditor-resize-table');
4794
+ return $wrapper.removeClass('resizing');
4795
+ });
4796
+ $wrapper.addClass('resizing');
4797
+ return false;
4798
+ });
4892
4799
  };
4893
4800
 
4894
4801
  TableButton.prototype._initShortcuts = function() {
@@ -4936,7 +4843,7 @@ TableButton = (function(superClass) {
4936
4843
 
4937
4844
  TableButton.prototype.renderMenu = function() {
4938
4845
  var $table;
4939
- $("<div class=\"menu-create-table\">\n</div>\n<div class=\"menu-edit-table\">\n <ul>\n <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"deleteRow\"><span>" + (this._t('deleteRow')) + "</span></a></li>\n <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"insertRowAbove\"><span>" + (this._t('insertRowAbove')) + " ( Ctrl + Alt + ↑ )</span></a></li>\n <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"insertRowBelow\"><span>" + (this._t('insertRowBelow')) + " ( Ctrl + Alt + ↓ )</span></a></li>\n <li><span class=\"separator\"></span></li>\n <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"deleteCol\"><span>" + (this._t('deleteColumn')) + "</span></a></li>\n <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"insertColLeft\"><span>" + (this._t('insertColumnLeft')) + " ( Ctrl + Alt + ← )</span></a></li>\n <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"insertColRight\"><span>" + (this._t('insertColumnRight')) + " ( Ctrl + Alt + → )</span></a></li>\n <li><span class=\"separator\"></span></li>\n <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"deleteTable\"><span>" + (this._t('deleteTable')) + "</span></a></li>\n </ul>\n</div>").appendTo(this.menuWrapper);
4846
+ $("<div class=\"menu-create-table\">\n</div>\n<div class=\"menu-edit-table\">\n <ul>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"deleteRow\">\n <span>" + (this._t('deleteRow')) + "</span>\n </a>\n </li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"insertRowAbove\">\n <span>" + (this._t('insertRowAbove')) + " ( Ctrl + Alt + ↑ )</span>\n </a>\n </li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"insertRowBelow\">\n <span>" + (this._t('insertRowBelow')) + " ( Ctrl + Alt + ↓ )</span>\n </a>\n </li>\n <li><span class=\"separator\"></span></li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"deleteCol\">\n <span>" + (this._t('deleteColumn')) + "</span>\n </a>\n </li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"insertColLeft\">\n <span>" + (this._t('insertColumnLeft')) + " ( Ctrl + Alt + ← )</span>\n </a>\n </li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"insertColRight\">\n <span>" + (this._t('insertColumnRight')) + " ( Ctrl + Alt + → )</span>\n </a>\n </li>\n <li><span class=\"separator\"></span></li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"deleteTable\">\n <span>" + (this._t('deleteTable')) + "</span>\n </a>\n </li>\n </ul>\n</div>").appendTo(this.menuWrapper);
4940
4847
  this.createMenu = this.menuWrapper.find('.menu-create-table');
4941
4848
  this.editMenu = this.menuWrapper.find('.menu-edit-table');
4942
4849
  $table = this.createTable(6, 6).appendTo(this.createMenu);
@@ -4954,11 +4861,9 @@ TableButton = (function(superClass) {
4954
4861
  return $trs.find("td:lt(" + num + "), th:lt(" + num + ")").addClass('selected');
4955
4862
  };
4956
4863
  })(this));
4957
- this.createMenu.on('mouseleave', (function(_this) {
4958
- return function(e) {
4959
- return $(e.currentTarget).find('td, th').removeClass('selected');
4960
- };
4961
- })(this));
4864
+ this.createMenu.on('mouseleave', function(e) {
4865
+ return $(e.currentTarget).find('td, th').removeClass('selected');
4866
+ });
4962
4867
  return this.createMenu.on('mousedown', 'td, th', (function(_this) {
4963
4868
  return function(e) {
4964
4869
  var $closestBlock, $td, $tr, colNum, rowNum;
@@ -4974,7 +4879,7 @@ TableButton = (function(superClass) {
4974
4879
  rowNum += 1;
4975
4880
  }
4976
4881
  $table = _this.createTable(rowNum, colNum, true);
4977
- $closestBlock = _this.editor.util.closestBlockEl();
4882
+ $closestBlock = _this.editor.selection.blockNodes().last();
4978
4883
  if (_this.editor.util.isEmptyNode($closestBlock)) {
4979
4884
  $closestBlock.replaceWith($table);
4980
4885
  } else {
@@ -4989,14 +4894,14 @@ TableButton = (function(superClass) {
4989
4894
  };
4990
4895
 
4991
4896
  TableButton.prototype.createTable = function(row, col, phBr) {
4992
- var $table, $tbody, $td, $thead, $tr, c, j, k, r, ref, ref1;
4897
+ var $table, $tbody, $td, $thead, $tr, c, k, l, r, ref, ref1;
4993
4898
  $table = $('<table/>');
4994
4899
  $thead = $('<thead/>').appendTo($table);
4995
4900
  $tbody = $('<tbody/>').appendTo($table);
4996
- for (r = j = 0, ref = row; 0 <= ref ? j < ref : j > ref; r = 0 <= ref ? ++j : --j) {
4901
+ for (r = k = 0, ref = row; 0 <= ref ? k < ref : k > ref; r = 0 <= ref ? ++k : --k) {
4997
4902
  $tr = $('<tr/>');
4998
4903
  $tr.appendTo(r === 0 ? $thead : $tbody);
4999
- for (c = k = 0, ref1 = col; 0 <= ref1 ? k < ref1 : k > ref1; c = 0 <= ref1 ? ++k : --k) {
4904
+ for (c = l = 0, ref1 = col; 0 <= ref1 ? l < ref1 : l > ref1; c = 0 <= ref1 ? ++l : --l) {
5000
4905
  $td = $(r === 0 ? '<th/>' : '<td/>').appendTo($tr);
5001
4906
  if (phBr) {
5002
4907
  $td.append(this.editor.util.phBr);
@@ -5010,13 +4915,11 @@ TableButton = (function(superClass) {
5010
4915
  var cols, tableWidth;
5011
4916
  tableWidth = $table.width();
5012
4917
  cols = $table.find('col');
5013
- return $table.find('thead tr th').each((function(_this) {
5014
- return function(i, td) {
5015
- var $col;
5016
- $col = cols.eq(i);
5017
- return $col.attr('width', ($(td).outerWidth() / tableWidth * 100) + '%');
5018
- };
5019
- })(this));
4918
+ return $table.find('thead tr th').each(function(i, td) {
4919
+ var $col;
4920
+ $col = cols.eq(i);
4921
+ return $col.attr('width', ($(td).outerWidth() / tableWidth * 100) + '%');
4922
+ });
5020
4923
  };
5021
4924
 
5022
4925
  TableButton.prototype.setActive = function(active) {
@@ -5031,13 +4934,11 @@ TableButton = (function(superClass) {
5031
4934
  };
5032
4935
 
5033
4936
  TableButton.prototype._changeCellTag = function($tr, tagName) {
5034
- return $tr.find('td, th').each((function(_this) {
5035
- return function(i, cell) {
5036
- var $cell;
5037
- $cell = $(cell);
5038
- return $cell.replaceWith("<" + tagName + ">" + ($cell.html()) + "</" + tagName + ">");
5039
- };
5040
- })(this));
4937
+ return $tr.find('td, th').each(function(i, cell) {
4938
+ var $cell;
4939
+ $cell = $(cell);
4940
+ return $cell.replaceWith("<" + tagName + ">" + ($cell.html()) + "</" + tagName + ">");
4941
+ });
5041
4942
  };
5042
4943
 
5043
4944
  TableButton.prototype.deleteRow = function($td) {
@@ -5061,18 +4962,16 @@ TableButton = (function(superClass) {
5061
4962
  };
5062
4963
 
5063
4964
  TableButton.prototype.insertRow = function($td, direction) {
5064
- var $newTr, $table, $tr, cellTag, colNum, i, index, j, ref;
4965
+ var $newTr, $table, $tr, cellTag, colNum, i, index, k, ref;
5065
4966
  if (direction == null) {
5066
4967
  direction = 'after';
5067
4968
  }
5068
4969
  $tr = $td.parent('tr');
5069
4970
  $table = $tr.closest('table');
5070
4971
  colNum = 0;
5071
- $table.find('tr').each((function(_this) {
5072
- return function(i, tr) {
5073
- return colNum = Math.max(colNum, $(tr).find('td').length);
5074
- };
5075
- })(this));
4972
+ $table.find('tr').each(function(i, tr) {
4973
+ return colNum = Math.max(colNum, $(tr).find('td').length);
4974
+ });
5076
4975
  index = $tr.find('td, th').index($td);
5077
4976
  $newTr = $('<tr/>');
5078
4977
  cellTag = 'td';
@@ -5086,16 +4985,18 @@ TableButton = (function(superClass) {
5086
4985
  } else {
5087
4986
  $tr[direction]($newTr);
5088
4987
  }
5089
- for (i = j = 1, ref = colNum; 1 <= ref ? j <= ref : j >= ref; i = 1 <= ref ? ++j : --j) {
4988
+ for (i = k = 1, ref = colNum; 1 <= ref ? k <= ref : k >= ref; i = 1 <= ref ? ++k : --k) {
5090
4989
  $("<" + cellTag + "/>").append(this.editor.util.phBr).appendTo($newTr);
5091
4990
  }
5092
4991
  return this.editor.selection.setRangeAtStartOf($newTr.find('td, th').eq(index));
5093
4992
  };
5094
4993
 
5095
4994
  TableButton.prototype.deleteCol = function($td) {
5096
- var $newTd, $table, $tr, index;
4995
+ var $newTd, $table, $tr, index, noOtherCol, noOtherRow;
5097
4996
  $tr = $td.parent('tr');
5098
- if ($tr.closest('table').find('tr').length < 1 && $td.siblings('td, th').length < 1) {
4997
+ noOtherRow = $tr.closest('table').find('tr').length < 2;
4998
+ noOtherCol = $td.siblings('td, th').length < 1;
4999
+ if (noOtherRow && noOtherCol) {
5099
5000
  return this.deleteTable($td);
5100
5001
  } else {
5101
5002
  index = $tr.find('td, th').index($td);
@@ -5105,11 +5006,9 @@ TableButton = (function(superClass) {
5105
5006
  }
5106
5007
  $table = $tr.closest('table');
5107
5008
  $table.find('col').eq(index).remove();
5108
- $table.find('tr').each((function(_this) {
5109
- return function(i, tr) {
5110
- return $(tr).find('td, th').eq(index).remove();
5111
- };
5112
- })(this));
5009
+ $table.find('tr').each(function(i, tr) {
5010
+ return $(tr).find('td, th').eq(index).remove();
5011
+ });
5113
5012
  this.refreshTableWidth($table);
5114
5013
  return this.editor.selection.setRangeAtEndOf($newTd);
5115
5014
  }
@@ -5154,9 +5053,8 @@ TableButton = (function(superClass) {
5154
5053
  };
5155
5054
 
5156
5055
  TableButton.prototype.command = function(param) {
5157
- var $td, range;
5158
- range = this.editor.selection.getRange();
5159
- $td = $(range.commonAncestorContainer).closest('td, th');
5056
+ var $td;
5057
+ $td = this.editor.selection.containerNode.closest('td, th');
5160
5058
  if (!($td.length > 0)) {
5161
5059
  return;
5162
5060
  }
@@ -5201,17 +5099,11 @@ StrikethroughButton = (function(superClass) {
5201
5099
 
5202
5100
  StrikethroughButton.prototype.disableTag = 'pre';
5203
5101
 
5204
- StrikethroughButton.prototype.status = function($node) {
5102
+ StrikethroughButton.prototype._activeStatus = function() {
5205
5103
  var active;
5206
- if ($node != null) {
5207
- this.setDisabled($node.is(this.disableTag));
5208
- }
5209
- if (this.disabled) {
5210
- return true;
5211
- }
5212
5104
  active = document.queryCommandState('strikethrough') === true;
5213
5105
  this.setActive(active);
5214
- return active;
5106
+ return this.active;
5215
5107
  };
5216
5108
 
5217
5109
  StrikethroughButton.prototype.command = function() {
@@ -5239,7 +5131,7 @@ AlignmentButton = (function(superClass) {
5239
5131
 
5240
5132
  AlignmentButton.prototype.icon = 'align-left';
5241
5133
 
5242
- AlignmentButton.prototype.htmlTag = 'p, h1, h2, h3, h4';
5134
+ AlignmentButton.prototype.htmlTag = 'p, h1, h2, h3, h4, td, th';
5243
5135
 
5244
5136
  AlignmentButton.prototype._init = function() {
5245
5137
  this.menu = [
@@ -5283,40 +5175,24 @@ AlignmentButton = (function(superClass) {
5283
5175
  return this.menuEl.find('.menu-item').show().end().find('.menu-item-' + align).hide();
5284
5176
  };
5285
5177
 
5286
- AlignmentButton.prototype.status = function($node) {
5287
- if ($node == null) {
5288
- return true;
5289
- }
5290
- if (!this.editor.util.isBlockNode($node)) {
5291
- return;
5292
- }
5293
- this.setDisabled(!$node.is(this.htmlTag));
5294
- if (this.disabled) {
5295
- this.setActive(false);
5296
- return true;
5178
+ AlignmentButton.prototype._status = function() {
5179
+ this.nodes = this.editor.selection.nodes().filter(this.htmlTag);
5180
+ if (this.nodes.length < 1) {
5181
+ this.setDisabled(true);
5182
+ return this.setActive(false);
5183
+ } else {
5184
+ this.setDisabled(false);
5185
+ return this.setActive(true, this.nodes.first().css('text-align'));
5297
5186
  }
5298
- this.setActive(true, $node.css('text-align'));
5299
- return this.active;
5300
5187
  };
5301
5188
 
5302
5189
  AlignmentButton.prototype.command = function(align) {
5303
- var $blockEls, $endBlock, $startBlock, block, endNode, j, len, range, ref, startNode;
5304
- if (['left', 'center', 'right'].indexOf(align) < 0) {
5305
- throw new Error("invalid " + align);
5306
- }
5307
- range = this.editor.selection.getRange();
5308
- startNode = range.startContainer;
5309
- endNode = range.endContainer;
5310
- $startBlock = this.editor.util.closestBlockEl(startNode);
5311
- $endBlock = this.editor.util.closestBlockEl(endNode);
5312
- this.editor.selection.save();
5313
- $blockEls = $startBlock.is($endBlock) ? $startBlock : $startBlock.nextUntil($endBlock).addBack().add($endBlock);
5314
- ref = $blockEls.filter(this.htmlTag);
5315
- for (j = 0, len = ref.length; j < len; j++) {
5316
- block = ref[j];
5317
- $(block).css('text-align', align === 'left' ? '' : align);
5190
+ if (align !== 'left' && align !== 'center' && align !== 'right') {
5191
+ throw new Error("simditor alignment button: invalid align " + align);
5318
5192
  }
5319
- this.editor.selection.restore();
5193
+ this.nodes.css({
5194
+ 'text-align': align === 'left' ? '' : align
5195
+ });
5320
5196
  return this.editor.trigger('valuechanged');
5321
5197
  };
5322
5198