|
|
(function (root, factory) {
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
|
// AMD. Register as an anonymous module.
|
|
|
define('simditor', ["jquery",
|
|
|
"simple-module",
|
|
|
"simple-hotkeys",
|
|
|
"simple-uploader"], function ($, SimpleModule, simpleHotkeys, simpleUploader) {
|
|
|
return (root.returnExportsGlobal = factory($, SimpleModule, simpleHotkeys, simpleUploader));
|
|
|
});
|
|
|
} else if (typeof exports === 'object') {
|
|
|
// Node. Does not work with strict CommonJS, but
|
|
|
// only CommonJS-like enviroments that support module.exports,
|
|
|
// like Node.
|
|
|
module.exports = factory(require("jquery"),
|
|
|
require("simple-module"),
|
|
|
require("simple-hotkeys"),
|
|
|
require("simple-uploader"));
|
|
|
} else {
|
|
|
root['Simditor'] = factory(jQuery,
|
|
|
SimpleModule,
|
|
|
simple.hotkeys,
|
|
|
simple.uploader);
|
|
|
}
|
|
|
}(this, function ($, SimpleModule, simpleHotkeys, simpleUploader) {
|
|
|
|
|
|
var Selection,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
Selection = (function(_super) {
|
|
|
__extends(Selection, _super);
|
|
|
|
|
|
function Selection() {
|
|
|
return Selection.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
Selection.pluginName = 'Selection';
|
|
|
|
|
|
Selection.prototype._init = function() {
|
|
|
this.editor = this._module;
|
|
|
return this.sel = document.getSelection();
|
|
|
};
|
|
|
|
|
|
Selection.prototype.clear = function() {
|
|
|
var e;
|
|
|
try {
|
|
|
return this.sel.removeAllRanges();
|
|
|
} catch (_error) {
|
|
|
e = _error;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Selection.prototype.getRange = function() {
|
|
|
if (!this.editor.inputManager.focused || !this.sel.rangeCount) {
|
|
|
return null;
|
|
|
}
|
|
|
return this.sel.getRangeAt(0);
|
|
|
};
|
|
|
|
|
|
Selection.prototype.selectRange = function(range) {
|
|
|
this.clear();
|
|
|
this.sel.addRange(range);
|
|
|
if (!this.editor.inputManager.focused && (this.editor.util.browser.firefox || this.editor.util.browser.msie)) {
|
|
|
this.editor.body.focus();
|
|
|
}
|
|
|
return range;
|
|
|
};
|
|
|
|
|
|
Selection.prototype.rangeAtEndOf = function(node, range) {
|
|
|
var endNode, endNodeLength, result;
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
if (!((range != null) && range.collapsed)) {
|
|
|
return;
|
|
|
}
|
|
|
node = $(node)[0];
|
|
|
endNode = range.endContainer;
|
|
|
endNodeLength = this.editor.util.getNodeLength(endNode);
|
|
|
if (!(range.endOffset === endNodeLength - 1 && $(endNode).contents().last().is('br')) && range.endOffset !== endNodeLength) {
|
|
|
return false;
|
|
|
}
|
|
|
if (node === endNode) {
|
|
|
return true;
|
|
|
} else if (!$.contains(node, endNode)) {
|
|
|
return false;
|
|
|
}
|
|
|
result = true;
|
|
|
$(endNode).parentsUntil(node).addBack().each((function(_this) {
|
|
|
return function(i, n) {
|
|
|
var $lastChild, nodes;
|
|
|
nodes = $(n).parent().contents().filter(function() {
|
|
|
return !(this !== n && this.nodeType === 3 && !this.nodeValue);
|
|
|
});
|
|
|
$lastChild = nodes.last();
|
|
|
if (!($lastChild.get(0) === n || ($lastChild.is('br') && $lastChild.prev().get(0) === n))) {
|
|
|
result = false;
|
|
|
return false;
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
return result;
|
|
|
};
|
|
|
|
|
|
Selection.prototype.rangeAtStartOf = function(node, range) {
|
|
|
var result, startNode;
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
if (!((range != null) && range.collapsed)) {
|
|
|
return;
|
|
|
}
|
|
|
node = $(node)[0];
|
|
|
startNode = range.startContainer;
|
|
|
if (range.startOffset !== 0) {
|
|
|
return false;
|
|
|
}
|
|
|
if (node === startNode) {
|
|
|
return true;
|
|
|
} else if (!$.contains(node, startNode)) {
|
|
|
return false;
|
|
|
}
|
|
|
result = true;
|
|
|
$(startNode).parentsUntil(node).addBack().each((function(_this) {
|
|
|
return function(i, n) {
|
|
|
var nodes;
|
|
|
nodes = $(n).parent().contents().filter(function() {
|
|
|
return !(this !== n && this.nodeType === 3 && !this.nodeValue);
|
|
|
});
|
|
|
if (nodes.first().get(0) !== n) {
|
|
|
return result = false;
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
return result;
|
|
|
};
|
|
|
|
|
|
Selection.prototype.insertNode = function(node, range) {
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
if (range == null) {
|
|
|
return;
|
|
|
}
|
|
|
node = $(node)[0];
|
|
|
range.insertNode(node);
|
|
|
return this.setRangeAfter(node, range);
|
|
|
};
|
|
|
|
|
|
Selection.prototype.setRangeAfter = function(node, range) {
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
if (range == null) {
|
|
|
return;
|
|
|
}
|
|
|
node = $(node)[0];
|
|
|
range.setEndAfter(node);
|
|
|
range.collapse(false);
|
|
|
return this.selectRange(range);
|
|
|
};
|
|
|
|
|
|
Selection.prototype.setRangeBefore = function(node, range) {
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
if (range == null) {
|
|
|
return;
|
|
|
}
|
|
|
node = $(node)[0];
|
|
|
range.setEndBefore(node);
|
|
|
range.collapse(false);
|
|
|
return this.selectRange(range);
|
|
|
};
|
|
|
|
|
|
Selection.prototype.setRangeAtStartOf = function(node, range) {
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
node = $(node).get(0);
|
|
|
range.setEnd(node, 0);
|
|
|
range.collapse(false);
|
|
|
return this.selectRange(range);
|
|
|
};
|
|
|
|
|
|
Selection.prototype.setRangeAtEndOf = function(node, range) {
|
|
|
var $lastNode, $node, contents, lastChild, lastText, nodeLength;
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
$node = $(node);
|
|
|
node = $node.get(0);
|
|
|
if ($node.is('pre')) {
|
|
|
contents = $node.contents();
|
|
|
if (contents.length > 0) {
|
|
|
lastChild = contents.last();
|
|
|
lastText = lastChild.text();
|
|
|
if (lastText.charAt(lastText.length - 1) === '\n') {
|
|
|
range.setEnd(lastChild[0], this.editor.util.getNodeLength(lastChild[0]) - 1);
|
|
|
} else {
|
|
|
range.setEnd(lastChild[0], this.editor.util.getNodeLength(lastChild[0]));
|
|
|
}
|
|
|
} else {
|
|
|
range.setEnd(node, 0);
|
|
|
}
|
|
|
} else {
|
|
|
nodeLength = this.editor.util.getNodeLength(node);
|
|
|
if (node.nodeType !== 3 && nodeLength > 0) {
|
|
|
$lastNode = $(node).contents().last();
|
|
|
if ($lastNode.is('br')) {
|
|
|
nodeLength -= 1;
|
|
|
} else if ($lastNode[0].nodeType !== 3 && this.editor.util.isEmptyNode($lastNode)) {
|
|
|
$lastNode.append(this.editor.util.phBr);
|
|
|
node = $lastNode[0];
|
|
|
nodeLength = 0;
|
|
|
}
|
|
|
}
|
|
|
range.setEnd(node, nodeLength);
|
|
|
}
|
|
|
range.collapse(false);
|
|
|
return this.selectRange(range);
|
|
|
};
|
|
|
|
|
|
Selection.prototype.deleteRangeContents = function(range) {
|
|
|
var endRange, startRange;
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
startRange = range.cloneRange();
|
|
|
endRange = range.cloneRange();
|
|
|
startRange.collapse(true);
|
|
|
endRange.collapse(false);
|
|
|
if (!range.collapsed && this.rangeAtStartOf(this.editor.body, startRange) && this.rangeAtEndOf(this.editor.body, endRange)) {
|
|
|
this.editor.body.empty();
|
|
|
range.setStart(this.editor.body[0], 0);
|
|
|
range.collapse(true);
|
|
|
this.selectRange(range);
|
|
|
} else {
|
|
|
range.deleteContents();
|
|
|
}
|
|
|
return range;
|
|
|
};
|
|
|
|
|
|
Selection.prototype.breakBlockEl = function(el, range) {
|
|
|
var $el;
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
$el = $(el);
|
|
|
if (!range.collapsed) {
|
|
|
return $el;
|
|
|
}
|
|
|
range.setStartBefore($el.get(0));
|
|
|
if (range.collapsed) {
|
|
|
return $el;
|
|
|
}
|
|
|
return $el.before(range.extractContents());
|
|
|
};
|
|
|
|
|
|
Selection.prototype.save = function(range) {
|
|
|
var endCaret, endRange, startCaret;
|
|
|
if (range == null) {
|
|
|
range = this.getRange();
|
|
|
}
|
|
|
if (this._selectionSaved) {
|
|
|
return;
|
|
|
}
|
|
|
endRange = range.cloneRange();
|
|
|
endRange.collapse(false);
|
|
|
startCaret = $('<span/>').addClass('simditor-caret-start');
|
|
|
endCaret = $('<span/>').addClass('simditor-caret-end');
|
|
|
endRange.insertNode(endCaret[0]);
|
|
|
range.insertNode(startCaret[0]);
|
|
|
this.clear();
|
|
|
return this._selectionSaved = true;
|
|
|
};
|
|
|
|
|
|
Selection.prototype.restore = function() {
|
|
|
var endCaret, endContainer, endOffset, range, startCaret, startContainer, startOffset;
|
|
|
if (!this._selectionSaved) {
|
|
|
return false;
|
|
|
}
|
|
|
startCaret = this.editor.body.find('.simditor-caret-start');
|
|
|
endCaret = this.editor.body.find('.simditor-caret-end');
|
|
|
if (startCaret.length && endCaret.length) {
|
|
|
startContainer = startCaret.parent();
|
|
|
startOffset = startContainer.contents().index(startCaret);
|
|
|
endContainer = endCaret.parent();
|
|
|
endOffset = endContainer.contents().index(endCaret);
|
|
|
if (startContainer[0] === endContainer[0]) {
|
|
|
endOffset -= 1;
|
|
|
}
|
|
|
range = document.createRange();
|
|
|
range.setStart(startContainer.get(0), startOffset);
|
|
|
range.setEnd(endContainer.get(0), endOffset);
|
|
|
startCaret.remove();
|
|
|
endCaret.remove();
|
|
|
this.selectRange(range);
|
|
|
} else {
|
|
|
startCaret.remove();
|
|
|
endCaret.remove();
|
|
|
}
|
|
|
this._selectionSaved = false;
|
|
|
return range;
|
|
|
};
|
|
|
|
|
|
return Selection;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
var Formatter,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
|
|
|
|
|
Formatter = (function(_super) {
|
|
|
__extends(Formatter, _super);
|
|
|
|
|
|
function Formatter() {
|
|
|
return Formatter.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
Formatter.pluginName = 'Formatter';
|
|
|
|
|
|
Formatter.prototype._init = function() {
|
|
|
this.editor = this._module;
|
|
|
this._allowedTags = ['br', 'a', 'img', 'b', 'strong', 'i', 'u', 'font', 'p', 'ul', 'ol', 'li', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'hr'];
|
|
|
this._allowedAttributes = {
|
|
|
img: ['src', 'alt', 'width', 'height', 'data-image-src', 'data-image-size', 'data-image-name', 'data-non-image'],
|
|
|
a: ['href', 'target'],
|
|
|
font: ['color'],
|
|
|
pre: ['data-lang', 'class'],
|
|
|
p: ['data-indent'],
|
|
|
h1: ['data-indent'],
|
|
|
h2: ['data-indent'],
|
|
|
h3: ['data-indent'],
|
|
|
h4: ['data-indent']
|
|
|
};
|
|
|
return this.editor.body.on('click', 'a', (function(_this) {
|
|
|
return function(e) {
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
Formatter.prototype.decorate = function($el) {
|
|
|
if ($el == null) {
|
|
|
$el = this.editor.body;
|
|
|
}
|
|
|
return this.editor.trigger('decorate', [$el]);
|
|
|
};
|
|
|
|
|
|
Formatter.prototype.undecorate = function($el) {
|
|
|
if ($el == null) {
|
|
|
$el = this.editor.body.clone();
|
|
|
}
|
|
|
this.editor.trigger('undecorate', [$el]);
|
|
|
return $.trim($el.html());
|
|
|
};
|
|
|
|
|
|
Formatter.prototype.autolink = function($el) {
|
|
|
var $node, findLinkNode, lastIndex, linkNodes, match, re, replaceEls, text, uri, _i, _len;
|
|
|
if ($el == null) {
|
|
|
$el = this.editor.body;
|
|
|
}
|
|
|
linkNodes = [];
|
|
|
findLinkNode = function($parentNode) {
|
|
|
return $parentNode.contents().each(function(i, node) {
|
|
|
var $node, text;
|
|
|
$node = $(node);
|
|
|
if ($node.is('a') || $node.closest('a, pre', $el).length) {
|
|
|
return;
|
|
|
}
|
|
|
if ($node.contents().length) {
|
|
|
return findLinkNode($node);
|
|
|
} else if ((text = $node.text()) && /https?:\/\/|www\./ig.test(text)) {
|
|
|
return linkNodes.push($node);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
findLinkNode($el);
|
|
|
re = /(https?:\/\/|www\.)[\w\-\.\?&=\/#%:,@\!\+]+/ig;
|
|
|
for (_i = 0, _len = linkNodes.length; _i < _len; _i++) {
|
|
|
$node = linkNodes[_i];
|
|
|
text = $node.text();
|
|
|
replaceEls = [];
|
|
|
match = null;
|
|
|
lastIndex = 0;
|
|
|
while ((match = re.exec(text)) !== null) {
|
|
|
replaceEls.push(document.createTextNode(text.substring(lastIndex, match.index)));
|
|
|
lastIndex = re.lastIndex;
|
|
|
uri = /^(http(s)?:\/\/|\/)/.test(match[0]) ? match[0] : 'http://' + match[0];
|
|
|
replaceEls.push($('<a href="' + uri + '" rel="nofollow"></a>').text(match[0])[0]);
|
|
|
}
|
|
|
replaceEls.push(document.createTextNode(text.substring(lastIndex)));
|
|
|
$node.replaceWith($(replaceEls));
|
|
|
}
|
|
|
return $el;
|
|
|
};
|
|
|
|
|
|
Formatter.prototype.format = function($el) {
|
|
|
var $node, blockNode, n, node, _i, _j, _len, _len1, _ref, _ref1;
|
|
|
if ($el == null) {
|
|
|
$el = this.editor.body;
|
|
|
}
|
|
|
if ($el.is(':empty')) {
|
|
|
$el.append('<p>' + this.editor.util.phBr + '</p>');
|
|
|
return $el;
|
|
|
}
|
|
|
_ref = $el.contents();
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
n = _ref[_i];
|
|
|
this.cleanNode(n, true);
|
|
|
}
|
|
|
_ref1 = $el.contents();
|
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
|
node = _ref1[_j];
|
|
|
$node = $(node);
|
|
|
if ($node.is('br')) {
|
|
|
if (typeof blockNode !== "undefined" && blockNode !== null) {
|
|
|
blockNode = null;
|
|
|
}
|
|
|
$node.remove();
|
|
|
} else if (this.editor.util.isBlockNode(node)) {
|
|
|
if ($node.is('li')) {
|
|
|
if (blockNode && blockNode.is('ul, ol')) {
|
|
|
blockNode.append(node);
|
|
|
} else {
|
|
|
blockNode = $('<ul/>').insertBefore(node);
|
|
|
blockNode.append(node);
|
|
|
}
|
|
|
} else {
|
|
|
blockNode = null;
|
|
|
}
|
|
|
} else {
|
|
|
if (!blockNode || blockNode.is('ul, ol')) {
|
|
|
blockNode = $('<p/>').insertBefore(node);
|
|
|
}
|
|
|
blockNode.append(node);
|
|
|
}
|
|
|
}
|
|
|
return $el;
|
|
|
};
|
|
|
|
|
|
Formatter.prototype.cleanNode = function(node, recursive) {
|
|
|
var $childImg, $node, $p, $td, allowedAttributes, attr, contents, isDecoration, n, text, textNode, _i, _j, _len, _len1, _ref, _ref1;
|
|
|
$node = $(node);
|
|
|
if (!($node.length > 0)) {
|
|
|
return;
|
|
|
}
|
|
|
if ($node[0].nodeType === 3) {
|
|
|
text = $node.text().replace(/(\r\n|\n|\r)/gm, '');
|
|
|
if (text) {
|
|
|
textNode = document.createTextNode(text);
|
|
|
$node.replaceWith(textNode);
|
|
|
} else {
|
|
|
$node.remove();
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
contents = $node.contents();
|
|
|
isDecoration = $node.is('[class^="simditor-"]');
|
|
|
if ($node.is(this._allowedTags.join(',')) || isDecoration) {
|
|
|
if ($node.is('a') && ($childImg = $node.find('img')).length > 0) {
|
|
|
$node.replaceWith($childImg);
|
|
|
$node = $childImg;
|
|
|
contents = null;
|
|
|
}
|
|
|
if ($node.is('img') && $node.hasClass('uploading')) {
|
|
|
$node.remove();
|
|
|
}
|
|
|
if (!isDecoration) {
|
|
|
allowedAttributes = this._allowedAttributes[$node[0].tagName.toLowerCase()];
|
|
|
_ref = $.makeArray($node[0].attributes);
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
attr = _ref[_i];
|
|
|
if (!((allowedAttributes != null) && (_ref1 = attr.name, __indexOf.call(allowedAttributes, _ref1) >= 0))) {
|
|
|
$node.removeAttr(attr.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} else if ($node[0].nodeType === 1 && !$node.is(':empty')) {
|
|
|
if ($node.is('div, article, dl, header, footer, tr')) {
|
|
|
$node.append('<br/>');
|
|
|
contents.first().unwrap();
|
|
|
} else if ($node.is('table')) {
|
|
|
$p = $('<p/>');
|
|
|
$node.find('tr').each((function(_this) {
|
|
|
return function(i, tr) {
|
|
|
return $p.append($(tr).text() + '<br/>');
|
|
|
};
|
|
|
})(this));
|
|
|
$node.replaceWith($p);
|
|
|
contents = null;
|
|
|
} else if ($node.is('thead, tfoot')) {
|
|
|
$node.remove();
|
|
|
contents = null;
|
|
|
} else if ($node.is('th')) {
|
|
|
$td = $('<td/>').append($node.contents());
|
|
|
$node.replaceWith($td);
|
|
|
} else {
|
|
|
contents.first().unwrap();
|
|
|
}
|
|
|
} else {
|
|
|
$node.remove();
|
|
|
contents = null;
|
|
|
}
|
|
|
if (recursive && (contents != null) && !$node.is('pre')) {
|
|
|
for (_j = 0, _len1 = contents.length; _j < _len1; _j++) {
|
|
|
n = contents[_j];
|
|
|
this.cleanNode(n, true);
|
|
|
}
|
|
|
}
|
|
|
return null;
|
|
|
};
|
|
|
|
|
|
Formatter.prototype.clearHtml = function(html, lineBreak) {
|
|
|
var container, contents, result;
|
|
|
if (lineBreak == null) {
|
|
|
lineBreak = true;
|
|
|
}
|
|
|
container = $('<div/>').append(html);
|
|
|
contents = container.contents();
|
|
|
result = '';
|
|
|
contents.each((function(_this) {
|
|
|
return function(i, node) {
|
|
|
var $node, children;
|
|
|
if (node.nodeType === 3) {
|
|
|
return result += node.nodeValue;
|
|
|
} else if (node.nodeType === 1) {
|
|
|
$node = $(node);
|
|
|
children = $node.contents();
|
|
|
if (children.length > 0) {
|
|
|
result += _this.clearHtml(children);
|
|
|
}
|
|
|
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')) {
|
|
|
return result += '\n';
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
return result;
|
|
|
};
|
|
|
|
|
|
Formatter.prototype.beautify = function($contents) {
|
|
|
var uselessP;
|
|
|
uselessP = function($el) {
|
|
|
return !!($el.is('p') && !$el.text() && $el.children(':not(br)').length < 1);
|
|
|
};
|
|
|
return $contents.each((function(_this) {
|
|
|
return function(i, el) {
|
|
|
var $el;
|
|
|
$el = $(el);
|
|
|
if ($el.is(':not(img, br, col, td, hr, [class^="simditor-"]):empty')) {
|
|
|
$el.remove();
|
|
|
}
|
|
|
if (uselessP($el)) {
|
|
|
$el.remove();
|
|
|
}
|
|
|
return $el.find(':not(img, br, col, td, hr, [class^="simditor-"]):empty').remove();
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
return Formatter;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
var InputManager,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
|
|
|
|
|
InputManager = (function(_super) {
|
|
|
__extends(InputManager, _super);
|
|
|
|
|
|
function InputManager() {
|
|
|
return InputManager.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
InputManager.pluginName = 'InputManager';
|
|
|
|
|
|
InputManager.prototype.opts = {
|
|
|
pasteImage: false
|
|
|
};
|
|
|
|
|
|
InputManager.prototype._modifierKeys = [16, 17, 18, 91, 93, 224];
|
|
|
|
|
|
InputManager.prototype._arrowKeys = [37, 38, 39, 40];
|
|
|
|
|
|
InputManager.prototype._init = function() {
|
|
|
var submitKey;
|
|
|
this.editor = this._module;
|
|
|
if (this.opts.pasteImage && typeof this.opts.pasteImage !== 'string') {
|
|
|
this.opts.pasteImage = 'inline';
|
|
|
}
|
|
|
this._keystrokeHandlers = {};
|
|
|
this.hotkeys = simpleHotkeys({
|
|
|
el: this.editor.body
|
|
|
});
|
|
|
this._pasteArea = $('<div/>').css({
|
|
|
width: '1px',
|
|
|
height: '1px',
|
|
|
overflow: 'hidden',
|
|
|
position: 'fixed',
|
|
|
right: '0',
|
|
|
bottom: '100px'
|
|
|
}).attr({
|
|
|
tabIndex: '-1',
|
|
|
contentEditable: true
|
|
|
}).addClass('simditor-paste-area').appendTo(this.editor.el);
|
|
|
this._cleanPasteArea = $('<textarea/>').css({
|
|
|
width: '1px',
|
|
|
height: '1px',
|
|
|
overflow: 'hidden',
|
|
|
position: 'fixed',
|
|
|
right: '0',
|
|
|
bottom: '101px'
|
|
|
}).attr({
|
|
|
tabIndex: '-1'
|
|
|
}).addClass('simditor-clean-paste-area').appendTo(this.editor.el);
|
|
|
$(document).on('selectionchange.simditor' + this.editor.id, (function(_this) {
|
|
|
return function(e) {
|
|
|
if (!_this.focused) {
|
|
|
return;
|
|
|
}
|
|
|
if (_this._selectionTimer) {
|
|
|
clearTimeout(_this._selectionTimer);
|
|
|
_this._selectionTimer = null;
|
|
|
}
|
|
|
return _this._selectionTimer = setTimeout(function() {
|
|
|
return _this.editor.trigger('selectionchanged');
|
|
|
}, 20);
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('valuechanged', (function(_this) {
|
|
|
return function() {
|
|
|
if (!_this.editor.util.closestBlockEl() && _this.focused) {
|
|
|
_this.editor.selection.save();
|
|
|
_this.editor.formatter.format();
|
|
|
_this.editor.selection.restore();
|
|
|
}
|
|
|
_this.editor.body.find('hr, pre, .simditor-table').each(function(i, el) {
|
|
|
var $el, formatted;
|
|
|
$el = $(el);
|
|
|
if ($el.parent().is('blockquote') || $el.parent()[0] === _this.editor.body[0]) {
|
|
|
formatted = false;
|
|
|
if ($el.next().length === 0) {
|
|
|
$('<p/>').append(_this.editor.util.phBr).insertAfter($el);
|
|
|
formatted = true;
|
|
|
}
|
|
|
if ($el.prev().length === 0) {
|
|
|
$('<p/>').append(_this.editor.util.phBr).insertBefore($el);
|
|
|
formatted = true;
|
|
|
}
|
|
|
if (formatted) {
|
|
|
return setTimeout(function() {
|
|
|
return _this.editor.trigger('valuechanged');
|
|
|
}, 10);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
_this.editor.body.find('pre:empty').append(_this.editor.util.phBr);
|
|
|
if (!_this.editor.util.supportSelectionChange && _this.focused) {
|
|
|
return _this.editor.trigger('selectionchanged');
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('selectionchanged', (function(_this) {
|
|
|
return function(e) {
|
|
|
return _this.editor.undoManager.update();
|
|
|
};
|
|
|
})(this));
|
|
|
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));
|
|
|
if (this.editor.util.browser.firefox) {
|
|
|
this.addShortcut('cmd+left', (function(_this) {
|
|
|
return function(e) {
|
|
|
e.preventDefault();
|
|
|
_this.editor.selection.sel.modify('move', 'backward', 'lineboundary');
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.addShortcut('cmd+right', (function(_this) {
|
|
|
return function(e) {
|
|
|
e.preventDefault();
|
|
|
_this.editor.selection.sel.modify('move', 'forward', 'lineboundary');
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.addShortcut('cmd+a', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $children, firstBlock, lastBlock, range;
|
|
|
$children = _this.editor.body.children();
|
|
|
if (!($children.length > 0)) {
|
|
|
return;
|
|
|
}
|
|
|
firstBlock = $children.first().get(0);
|
|
|
lastBlock = $children.last().get(0);
|
|
|
range = document.createRange();
|
|
|
range.setStart(firstBlock, 0);
|
|
|
range.setEnd(lastBlock, _this.editor.util.getNodeLength(lastBlock));
|
|
|
_this.editor.selection.selectRange(range);
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
}
|
|
|
submitKey = this.editor.util.os.mac ? 'cmd+enter' : 'ctrl+enter';
|
|
|
this.addShortcut(submitKey, (function(_this) {
|
|
|
return function(e) {
|
|
|
_this.editor.el.closest('form').find('button:submit').click();
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
if (this.editor.textarea.attr('autofocus')) {
|
|
|
return setTimeout((function(_this) {
|
|
|
return function() {
|
|
|
return _this.editor.focus();
|
|
|
};
|
|
|
})(this), 0);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
InputManager.prototype._onFocus = function(e) {
|
|
|
this.editor.el.addClass('focus').removeClass('error');
|
|
|
this.focused = true;
|
|
|
this.lastCaretPosition = null;
|
|
|
return setTimeout((function(_this) {
|
|
|
return function() {
|
|
|
_this.editor.triggerHandler('focus');
|
|
|
return _this.editor.trigger('selectionchanged');
|
|
|
};
|
|
|
})(this), 0);
|
|
|
};
|
|
|
|
|
|
InputManager.prototype._onBlur = function(e) {
|
|
|
var _ref;
|
|
|
this.editor.el.removeClass('focus');
|
|
|
this.editor.sync();
|
|
|
this.focused = false;
|
|
|
this.lastCaretPosition = (_ref = this.editor.undoManager.currentState()) != null ? _ref.caret : void 0;
|
|
|
return this.editor.triggerHandler('blur');
|
|
|
};
|
|
|
|
|
|
InputManager.prototype._onMouseUp = function(e) {
|
|
|
if (!this.editor.util.supportSelectionChange) {
|
|
|
return setTimeout((function(_this) {
|
|
|
return function() {
|
|
|
return _this.editor.trigger('selectionchanged');
|
|
|
};
|
|
|
})(this), 0);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
InputManager.prototype._onKeyDown = function(e) {
|
|
|
var $blockEl, metaKey, result, _base, _ref, _ref1;
|
|
|
if (this.editor.triggerHandler(e) === false) {
|
|
|
return false;
|
|
|
}
|
|
|
if (this.hotkeys.respondTo(e)) {
|
|
|
return;
|
|
|
}
|
|
|
if (e.which in this._keystrokeHandlers) {
|
|
|
result = typeof (_base = this._keystrokeHandlers[e.which])['*'] === "function" ? _base['*'](e) : void 0;
|
|
|
if (result) {
|
|
|
this.editor.trigger('valuechanged');
|
|
|
return false;
|
|
|
}
|
|
|
this.editor.util.traverseUp((function(_this) {
|
|
|
return function(node) {
|
|
|
var handler, _ref;
|
|
|
if (node.nodeType !== 1) {
|
|
|
return;
|
|
|
}
|
|
|
handler = (_ref = _this._keystrokeHandlers[e.which]) != null ? _ref[node.tagName.toLowerCase()] : void 0;
|
|
|
result = typeof handler === "function" ? handler(e, $(node)) : void 0;
|
|
|
if (result === true || result === false) {
|
|
|
return false;
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
if (result) {
|
|
|
this.editor.trigger('valuechanged');
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
if ((_ref = e.which, __indexOf.call(this._modifierKeys, _ref) >= 0) || (_ref1 = e.which, __indexOf.call(this._arrowKeys, _ref1) >= 0)) {
|
|
|
return;
|
|
|
}
|
|
|
metaKey = this.editor.util.metaKey(e);
|
|
|
$blockEl = this.editor.util.closestBlockEl();
|
|
|
if (metaKey && e.which === 86) {
|
|
|
return;
|
|
|
}
|
|
|
if (this.editor.util.browser.webkit && e.which === 8 && this.editor.selection.rangeAtStartOf($blockEl)) {
|
|
|
setTimeout((function(_this) {
|
|
|
return function() {
|
|
|
var $newBlockEl;
|
|
|
if (!_this.focused) {
|
|
|
return;
|
|
|
}
|
|
|
$newBlockEl = _this.editor.util.closestBlockEl();
|
|
|
_this.editor.selection.save();
|
|
|
_this.editor.formatter.cleanNode($newBlockEl, true);
|
|
|
_this.editor.selection.restore();
|
|
|
return _this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
})(this), 10);
|
|
|
this.typing = true;
|
|
|
} else if (this._typing) {
|
|
|
if (this._typing !== true) {
|
|
|
clearTimeout(this._typing);
|
|
|
}
|
|
|
this._typing = setTimeout((function(_this) {
|
|
|
return function() {
|
|
|
_this.editor.trigger('valuechanged');
|
|
|
return _this._typing = false;
|
|
|
};
|
|
|
})(this), 200);
|
|
|
} else {
|
|
|
setTimeout((function(_this) {
|
|
|
return function() {
|
|
|
return _this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
})(this), 10);
|
|
|
this._typing = true;
|
|
|
}
|
|
|
return null;
|
|
|
};
|
|
|
|
|
|
InputManager.prototype._onKeyPress = function(e) {
|
|
|
if (this.editor.triggerHandler(e) === false) {
|
|
|
return false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
InputManager.prototype._onKeyUp = function(e) {
|
|
|
var p, _ref;
|
|
|
if (this.editor.triggerHandler(e) === false) {
|
|
|
return false;
|
|
|
}
|
|
|
if (!this.editor.util.supportSelectionChange && (_ref = e.which, __indexOf.call(this._arrowKeys, _ref) >= 0)) {
|
|
|
this.editor.trigger('selectionchanged');
|
|
|
return;
|
|
|
}
|
|
|
if ((e.which === 8 || e.which === 46) && this.editor.util.isEmptyNode(this.editor.body)) {
|
|
|
this.editor.body.empty();
|
|
|
p = $('<p/>').append(this.editor.util.phBr).appendTo(this.editor.body);
|
|
|
this.editor.selection.setRangeAtStartOf(p);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
InputManager.prototype._onPaste = function(e) {
|
|
|
var $blockEl, cleanPaste, imageFile, pasteItem, range, uploadOpt, _ref;
|
|
|
if (this.editor.triggerHandler(e) === false) {
|
|
|
return false;
|
|
|
}
|
|
|
range = this.editor.selection.deleteRangeContents();
|
|
|
if (!range.collapsed) {
|
|
|
range.collapse(true);
|
|
|
}
|
|
|
$blockEl = this.editor.util.closestBlockEl();
|
|
|
cleanPaste = $blockEl.is('pre, table');
|
|
|
if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.items && e.originalEvent.clipboardData.items.length > 0) {
|
|
|
pasteItem = e.originalEvent.clipboardData.items[0];
|
|
|
if (/^image\//.test(pasteItem.type) && !cleanPaste) {
|
|
|
imageFile = pasteItem.getAsFile();
|
|
|
if (!((imageFile != null) && this.opts.pasteImage)) {
|
|
|
return;
|
|
|
}
|
|
|
if (!imageFile.name) {
|
|
|
imageFile.name = "Clipboard Image.png";
|
|
|
}
|
|
|
uploadOpt = {};
|
|
|
uploadOpt[this.opts.pasteImage] = true;
|
|
|
if ((_ref = this.editor.uploader) != null) {
|
|
|
_ref.upload(imageFile, uploadOpt);
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
this.editor.selection.save(range);
|
|
|
if (cleanPaste) {
|
|
|
this._cleanPasteArea.focus();
|
|
|
if (this.editor.util.browser.firefox) {
|
|
|
e.preventDefault();
|
|
|
this._cleanPasteArea.val(e.originalEvent.clipboardData.getData('text/plain'));
|
|
|
} else if (this.editor.util.browser.msie && this.editor.util.browser.version === 10) {
|
|
|
e.preventDefault();
|
|
|
this._cleanPasteArea.val(window.clipboardData.getData('Text'));
|
|
|
}
|
|
|
} else {
|
|
|
this._pasteArea.focus();
|
|
|
if (this.editor.util.browser.msie && this.editor.util.browser.version === 10) {
|
|
|
e.preventDefault();
|
|
|
this._pasteArea.html(window.clipboardData.getData('Text'));
|
|
|
}
|
|
|
}
|
|
|
return setTimeout((function(_this) {
|
|
|
return function() {
|
|
|
var $img, blob, children, insertPosition, lastLine, line, lines, node, pasteContent, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref1, _ref2, _ref3;
|
|
|
if (_this._pasteArea.is(':empty') && !_this._cleanPasteArea.val()) {
|
|
|
pasteContent = null;
|
|
|
} else if (cleanPaste) {
|
|
|
pasteContent = _this._cleanPasteArea.val();
|
|
|
} else {
|
|
|
pasteContent = $('<div/>').append(_this._pasteArea.contents());
|
|
|
pasteContent.find('table colgroup').remove();
|
|
|
_this.editor.formatter.format(pasteContent);
|
|
|
_this.editor.formatter.decorate(pasteContent);
|
|
|
_this.editor.formatter.beautify(pasteContent.children());
|
|
|
pasteContent = pasteContent.contents();
|
|
|
}
|
|
|
_this._pasteArea.empty();
|
|
|
_this._cleanPasteArea.val('');
|
|
|
range = _this.editor.selection.restore();
|
|
|
if (_this.editor.triggerHandler('pasting', [pasteContent]) === false) {
|
|
|
return;
|
|
|
}
|
|
|
if (!pasteContent) {
|
|
|
return;
|
|
|
} else if (cleanPaste) {
|
|
|
if ($blockEl.is('table')) {
|
|
|
lines = pasteContent.split('\n');
|
|
|
lastLine = lines.pop();
|
|
|
for (_i = 0, _len = lines.length; _i < _len; _i++) {
|
|
|
line = lines[_i];
|
|
|
_this.editor.selection.insertNode(document.createTextNode(line));
|
|
|
_this.editor.selection.insertNode($('<br/>'));
|
|
|
}
|
|
|
_this.editor.selection.insertNode(document.createTextNode(lastLine));
|
|
|
} else {
|
|
|
pasteContent = $('<div/>').text(pasteContent);
|
|
|
_ref1 = pasteContent.contents();
|
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
|
node = _ref1[_j];
|
|
|
_this.editor.selection.insertNode($(node)[0], range);
|
|
|
}
|
|
|
}
|
|
|
} else if ($blockEl.is(_this.editor.body)) {
|
|
|
for (_k = 0, _len2 = pasteContent.length; _k < _len2; _k++) {
|
|
|
node = pasteContent[_k];
|
|
|
_this.editor.selection.insertNode(node, range);
|
|
|
}
|
|
|
} else if (pasteContent.length < 1) {
|
|
|
return;
|
|
|
} else if (pasteContent.length === 1) {
|
|
|
if (pasteContent.is('p')) {
|
|
|
children = pasteContent.contents();
|
|
|
if (children.length === 1 && children.is('img')) {
|
|
|
$img = children;
|
|
|
if (/^data:image/.test($img.attr('src'))) {
|
|
|
if (!_this.opts.pasteImage) {
|
|
|
return;
|
|
|
}
|
|
|
blob = _this.editor.util.dataURLtoBlob($img.attr("src"));
|
|
|
blob.name = "Clipboard Image.png";
|
|
|
uploadOpt = {};
|
|
|
uploadOpt[_this.opts.pasteImage] = true;
|
|
|
if ((_ref2 = _this.editor.uploader) != null) {
|
|
|
_ref2.upload(blob, uploadOpt);
|
|
|
}
|
|
|
return;
|
|
|
} else if ($img.is('img[src^="webkit-fake-url://"]')) {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
for (_l = 0, _len3 = children.length; _l < _len3; _l++) {
|
|
|
node = children[_l];
|
|
|
_this.editor.selection.insertNode(node, range);
|
|
|
}
|
|
|
} else if ($blockEl.is('p') && _this.editor.util.isEmptyNode($blockEl)) {
|
|
|
$blockEl.replaceWith(pasteContent);
|
|
|
_this.editor.selection.setRangeAtEndOf(pasteContent, range);
|
|
|
} else if (pasteContent.is('ul, ol')) {
|
|
|
if (pasteContent.find('li').length === 1) {
|
|
|
pasteContent = $('<div/>').text(pasteContent.text());
|
|
|
_ref3 = pasteContent.contents();
|
|
|
for (_m = 0, _len4 = _ref3.length; _m < _len4; _m++) {
|
|
|
node = _ref3[_m];
|
|
|
_this.editor.selection.insertNode($(node)[0], range);
|
|
|
}
|
|
|
} else if ($blockEl.is('li')) {
|
|
|
$blockEl.parent().after(pasteContent);
|
|
|
_this.editor.selection.setRangeAtEndOf(pasteContent, range);
|
|
|
} else {
|
|
|
$blockEl.after(pasteContent);
|
|
|
_this.editor.selection.setRangeAtEndOf(pasteContent, range);
|
|
|
}
|
|
|
} else {
|
|
|
$blockEl.after(pasteContent);
|
|
|
_this.editor.selection.setRangeAtEndOf(pasteContent, range);
|
|
|
}
|
|
|
} else {
|
|
|
if ($blockEl.is('li')) {
|
|
|
$blockEl = $blockEl.parent();
|
|
|
}
|
|
|
if (_this.editor.selection.rangeAtStartOf($blockEl, range)) {
|
|
|
insertPosition = 'before';
|
|
|
} else if (_this.editor.selection.rangeAtEndOf($blockEl, range)) {
|
|
|
insertPosition = 'after';
|
|
|
} else {
|
|
|
_this.editor.selection.breakBlockEl($blockEl, range);
|
|
|
insertPosition = 'before';
|
|
|
}
|
|
|
$blockEl[insertPosition](pasteContent);
|
|
|
_this.editor.selection.setRangeAtEndOf(pasteContent.last(), range);
|
|
|
}
|
|
|
return _this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
})(this), 10);
|
|
|
};
|
|
|
|
|
|
InputManager.prototype._onDrop = function(e) {
|
|
|
if (this.editor.triggerHandler(e) === false) {
|
|
|
return false;
|
|
|
}
|
|
|
return setTimeout((function(_this) {
|
|
|
return function() {
|
|
|
return _this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
})(this), 0);
|
|
|
};
|
|
|
|
|
|
InputManager.prototype.addKeystrokeHandler = function(key, node, handler) {
|
|
|
if (!this._keystrokeHandlers[key]) {
|
|
|
this._keystrokeHandlers[key] = {};
|
|
|
}
|
|
|
return this._keystrokeHandlers[key][node] = handler;
|
|
|
};
|
|
|
|
|
|
InputManager.prototype.addShortcut = function(keys, handler) {
|
|
|
return this.hotkeys.add(keys, $.proxy(handler, this));
|
|
|
};
|
|
|
|
|
|
return InputManager;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
var Keystroke,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
Keystroke = (function(_super) {
|
|
|
__extends(Keystroke, _super);
|
|
|
|
|
|
function Keystroke() {
|
|
|
return Keystroke.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
Keystroke.pluginName = 'Keystroke';
|
|
|
|
|
|
Keystroke.prototype._init = function() {
|
|
|
var titleEnterHandler;
|
|
|
this.editor = this._module;
|
|
|
if (this.editor.util.browser.safari) {
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', '*', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $blockEl, $br;
|
|
|
if (!e.shiftKey) {
|
|
|
return;
|
|
|
}
|
|
|
$blockEl = _this.editor.util.closestBlockEl();
|
|
|
if ($blockEl.is('pre')) {
|
|
|
return;
|
|
|
}
|
|
|
$br = $('<br/>');
|
|
|
if (_this.editor.selection.rangeAtEndOf($blockEl)) {
|
|
|
_this.editor.selection.insertNode($br);
|
|
|
_this.editor.selection.insertNode($('<br/>'));
|
|
|
_this.editor.selection.setRangeBefore($br);
|
|
|
} else {
|
|
|
_this.editor.selection.insertNode($br);
|
|
|
}
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
}
|
|
|
if (this.editor.util.browser.webkit || this.editor.util.browser.msie) {
|
|
|
titleEnterHandler = (function(_this) {
|
|
|
return function(e, $node) {
|
|
|
var $p;
|
|
|
if (!_this.editor.selection.rangeAtEndOf($node)) {
|
|
|
return;
|
|
|
}
|
|
|
$p = $('<p/>').append(_this.editor.util.phBr).insertAfter($node);
|
|
|
_this.editor.selection.setRangeAtStartOf($p);
|
|
|
return true;
|
|
|
};
|
|
|
})(this);
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', 'h1', titleEnterHandler);
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', 'h2', titleEnterHandler);
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', 'h3', titleEnterHandler);
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', 'h4', titleEnterHandler);
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', 'h5', titleEnterHandler);
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', 'h6', titleEnterHandler);
|
|
|
}
|
|
|
this.editor.inputManager.addKeystrokeHandler('8', '*', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $prevBlockEl, $rootBlock;
|
|
|
$rootBlock = _this.editor.util.furthestBlockEl();
|
|
|
$prevBlockEl = $rootBlock.prev();
|
|
|
if ($prevBlockEl.is('hr') && _this.editor.selection.rangeAtStartOf($rootBlock)) {
|
|
|
_this.editor.selection.save();
|
|
|
$prevBlockEl.remove();
|
|
|
_this.editor.selection.restore();
|
|
|
return true;
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addKeystrokeHandler('9', '*', (function(_this) {
|
|
|
return function(e) {
|
|
|
var codeButton;
|
|
|
codeButton = _this.editor.toolbar.findButton('code');
|
|
|
if (!(_this.editor.opts.tabIndent || (codeButton && codeButton.active))) {
|
|
|
return;
|
|
|
}
|
|
|
if (e.shiftKey) {
|
|
|
_this.editor.util.outdent();
|
|
|
} else {
|
|
|
_this.editor.util.indent();
|
|
|
}
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', 'li', (function(_this) {
|
|
|
return function(e, $node) {
|
|
|
var $cloneNode, listEl, newBlockEl, newListEl;
|
|
|
$cloneNode = $node.clone();
|
|
|
$cloneNode.find('ul, ol').remove();
|
|
|
if (!(_this.editor.util.isEmptyNode($cloneNode) && $node.is(_this.editor.util.closestBlockEl()))) {
|
|
|
return;
|
|
|
}
|
|
|
listEl = $node.parent();
|
|
|
if ($node.next('li').length > 0) {
|
|
|
if (!_this.editor.util.isEmptyNode($node)) {
|
|
|
return;
|
|
|
}
|
|
|
if (listEl.parent('li').length > 0) {
|
|
|
newBlockEl = $('<li/>').append(_this.editor.util.phBr).insertAfter(listEl.parent('li'));
|
|
|
newListEl = $('<' + listEl[0].tagName + '/>').append($node.nextAll('li'));
|
|
|
newBlockEl.append(newListEl);
|
|
|
} else {
|
|
|
newBlockEl = $('<p/>').append(_this.editor.util.phBr).insertAfter(listEl);
|
|
|
newListEl = $('<' + listEl[0].tagName + '/>').append($node.nextAll('li'));
|
|
|
newBlockEl.after(newListEl);
|
|
|
}
|
|
|
} else {
|
|
|
if (listEl.parent('li').length > 0) {
|
|
|
newBlockEl = $('<li/>').insertAfter(listEl.parent('li'));
|
|
|
if ($node.contents().length > 0) {
|
|
|
newBlockEl.append($node.contents());
|
|
|
} else {
|
|
|
newBlockEl.append(_this.editor.util.phBr);
|
|
|
}
|
|
|
} else {
|
|
|
newBlockEl = $('<p/>').append(_this.editor.util.phBr).insertAfter(listEl);
|
|
|
if ($node.children('ul, ol').length > 0) {
|
|
|
newBlockEl.after($node.children('ul, ol'));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if ($node.prev('li').length) {
|
|
|
$node.remove();
|
|
|
} else {
|
|
|
listEl.remove();
|
|
|
}
|
|
|
_this.editor.selection.setRangeAtStartOf(newBlockEl);
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', 'pre', (function(_this) {
|
|
|
return function(e, $node) {
|
|
|
var $p, breakNode, range;
|
|
|
e.preventDefault();
|
|
|
if (e.shiftKey) {
|
|
|
$p = $('<p/>').append(_this.editor.util.phBr).insertAfter($node);
|
|
|
_this.editor.selection.setRangeAtStartOf($p);
|
|
|
return true;
|
|
|
}
|
|
|
range = _this.editor.selection.getRange();
|
|
|
breakNode = null;
|
|
|
range.deleteContents();
|
|
|
if (!_this.editor.util.browser.msie && _this.editor.selection.rangeAtEndOf($node)) {
|
|
|
breakNode = document.createTextNode('\n\n');
|
|
|
range.insertNode(breakNode);
|
|
|
range.setEnd(breakNode, 1);
|
|
|
} else {
|
|
|
breakNode = document.createTextNode('\n');
|
|
|
range.insertNode(breakNode);
|
|
|
range.setStartAfter(breakNode);
|
|
|
}
|
|
|
range.collapse(false);
|
|
|
_this.editor.selection.selectRange(range);
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addKeystrokeHandler('13', 'blockquote', (function(_this) {
|
|
|
return function(e, $node) {
|
|
|
var $closestBlock, range;
|
|
|
$closestBlock = _this.editor.util.closestBlockEl();
|
|
|
if (!($closestBlock.is('p') && !$closestBlock.next().length && _this.editor.util.isEmptyNode($closestBlock))) {
|
|
|
return;
|
|
|
}
|
|
|
$node.after($closestBlock);
|
|
|
range = document.createRange();
|
|
|
_this.editor.selection.setRangeAtStartOf($closestBlock, range);
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addKeystrokeHandler('8', 'li', (function(_this) {
|
|
|
return function(e, $node) {
|
|
|
var $br, $childList, $newLi, $prevChildList, $prevNode, $textNode, range, text;
|
|
|
$childList = $node.children('ul, ol');
|
|
|
$prevNode = $node.prev('li');
|
|
|
if (!($childList.length > 0 && $prevNode.length > 0)) {
|
|
|
return false;
|
|
|
}
|
|
|
text = '';
|
|
|
$textNode = null;
|
|
|
$node.contents().each(function(i, n) {
|
|
|
if (n.nodeType === 1 && /UL|OL/.test(n.nodeName)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (n.nodeType === 1 && /BR/.test(n.nodeName)) {
|
|
|
return;
|
|
|
}
|
|
|
if (n.nodeType === 3 && n.nodeValue) {
|
|
|
text += n.nodeValue;
|
|
|
} else if (n.nodeType === 1) {
|
|
|
text += $(n).text();
|
|
|
}
|
|
|
return $textNode = $(n);
|
|
|
});
|
|
|
if ($textNode && text.length === 1 && _this.editor.util.browser.firefox && !$textNode.next('br').length) {
|
|
|
$br = $(_this.editor.util.phBr).insertAfter($textNode);
|
|
|
$textNode.remove();
|
|
|
_this.editor.selection.setRangeBefore($br);
|
|
|
return true;
|
|
|
} else if (text.length > 0) {
|
|
|
return false;
|
|
|
}
|
|
|
range = document.createRange();
|
|
|
$prevChildList = $prevNode.children('ul, ol');
|
|
|
if ($prevChildList.length > 0) {
|
|
|
$newLi = $('<li/>').append(_this.editor.util.phBr).appendTo($prevChildList);
|
|
|
$prevChildList.append($childList.children('li'));
|
|
|
$node.remove();
|
|
|
_this.editor.selection.setRangeAtEndOf($newLi, range);
|
|
|
} else {
|
|
|
_this.editor.selection.setRangeAtEndOf($prevNode, range);
|
|
|
$prevNode.append($childList);
|
|
|
$node.remove();
|
|
|
_this.editor.selection.selectRange(range);
|
|
|
}
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addKeystrokeHandler('8', 'pre', (function(_this) {
|
|
|
return function(e, $node) {
|
|
|
var $newNode, codeStr, range;
|
|
|
if (!_this.editor.selection.rangeAtStartOf($node)) {
|
|
|
return;
|
|
|
}
|
|
|
codeStr = $node.html().replace('\n', '<br/>');
|
|
|
$newNode = $('<p/>').append(codeStr || _this.editor.util.phBr).insertAfter($node);
|
|
|
$node.remove();
|
|
|
range = document.createRange();
|
|
|
_this.editor.selection.setRangeAtStartOf($newNode, range);
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
return this.editor.inputManager.addKeystrokeHandler('8', 'blockquote', (function(_this) {
|
|
|
return function(e, $node) {
|
|
|
var $firstChild, range;
|
|
|
if (!_this.editor.selection.rangeAtStartOf($node)) {
|
|
|
return;
|
|
|
}
|
|
|
$firstChild = $node.children().first().unwrap();
|
|
|
range = document.createRange();
|
|
|
_this.editor.selection.setRangeAtStartOf($firstChild, range);
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
return Keystroke;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
var UndoManager,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
UndoManager = (function(_super) {
|
|
|
__extends(UndoManager, _super);
|
|
|
|
|
|
function UndoManager() {
|
|
|
return UndoManager.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
UndoManager.pluginName = 'UndoManager';
|
|
|
|
|
|
UndoManager.prototype._index = -1;
|
|
|
|
|
|
UndoManager.prototype._capacity = 50;
|
|
|
|
|
|
UndoManager.prototype._timer = null;
|
|
|
|
|
|
UndoManager.prototype._init = function() {
|
|
|
var redoShortcut, undoShortcut;
|
|
|
this.editor = this._module;
|
|
|
this._stack = [];
|
|
|
if (this.editor.util.os.mac) {
|
|
|
undoShortcut = 'cmd+z';
|
|
|
redoShortcut = 'shift+cmd+z';
|
|
|
} else if (this.editor.util.os.win) {
|
|
|
undoShortcut = 'ctrl+z';
|
|
|
redoShortcut = 'ctrl+y';
|
|
|
} else {
|
|
|
undoShortcut = 'ctrl+z';
|
|
|
redoShortcut = 'shift+ctrl+z';
|
|
|
}
|
|
|
this.editor.inputManager.addShortcut(undoShortcut, (function(_this) {
|
|
|
return function(e) {
|
|
|
e.preventDefault();
|
|
|
_this.undo();
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addShortcut(redoShortcut, (function(_this) {
|
|
|
return function(e) {
|
|
|
e.preventDefault();
|
|
|
_this.redo();
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
return this.editor.on('valuechanged', (function(_this) {
|
|
|
return function(e, src) {
|
|
|
if (src === 'undo') {
|
|
|
return;
|
|
|
}
|
|
|
if (_this._timer) {
|
|
|
clearTimeout(_this._timer);
|
|
|
_this._timer = null;
|
|
|
}
|
|
|
return _this._timer = setTimeout(function() {
|
|
|
_this._pushUndoState();
|
|
|
return _this._timer = null;
|
|
|
}, 200);
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
UndoManager.prototype._pushUndoState = function() {
|
|
|
var currentState, html;
|
|
|
if (this.editor.triggerHandler('pushundostate') === false) {
|
|
|
return;
|
|
|
}
|
|
|
currentState = this.currentState();
|
|
|
html = this.editor.body.html();
|
|
|
if (currentState && currentState.html === html) {
|
|
|
return;
|
|
|
}
|
|
|
this._index += 1;
|
|
|
this._stack.length = this._index;
|
|
|
this._stack.push({
|
|
|
html: html,
|
|
|
caret: this.caretPosition()
|
|
|
});
|
|
|
if (this._stack.length > this._capacity) {
|
|
|
this._stack.shift();
|
|
|
return this._index -= 1;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
UndoManager.prototype.currentState = function() {
|
|
|
if (this._stack.length && this._index > -1) {
|
|
|
return this._stack[this._index];
|
|
|
} else {
|
|
|
return null;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
UndoManager.prototype.undo = function() {
|
|
|
var state;
|
|
|
if (this._index < 1 || this._stack.length < 2) {
|
|
|
return;
|
|
|
}
|
|
|
this.editor.hidePopover();
|
|
|
this._index -= 1;
|
|
|
state = this._stack[this._index];
|
|
|
this.editor.body.html(state.html);
|
|
|
this.caretPosition(state.caret);
|
|
|
this.editor.body.find('.selected').removeClass('selected');
|
|
|
this.editor.sync();
|
|
|
return this.editor.trigger('valuechanged', ['undo']);
|
|
|
};
|
|
|
|
|
|
UndoManager.prototype.redo = function() {
|
|
|
var state;
|
|
|
if (this._index < 0 || this._stack.length < this._index + 2) {
|
|
|
return;
|
|
|
}
|
|
|
this.editor.hidePopover();
|
|
|
this._index += 1;
|
|
|
state = this._stack[this._index];
|
|
|
this.editor.body.html(state.html);
|
|
|
this.caretPosition(state.caret);
|
|
|
this.editor.body.find('.selected').removeClass('selected');
|
|
|
this.editor.sync();
|
|
|
return this.editor.trigger('valuechanged', ['undo']);
|
|
|
};
|
|
|
|
|
|
UndoManager.prototype.update = function() {
|
|
|
var currentState, html;
|
|
|
if (this._timer) {
|
|
|
return;
|
|
|
}
|
|
|
currentState = this.currentState();
|
|
|
if (!currentState) {
|
|
|
return;
|
|
|
}
|
|
|
html = this.editor.body.html();
|
|
|
currentState.html = html;
|
|
|
return currentState.caret = this.caretPosition();
|
|
|
};
|
|
|
|
|
|
UndoManager.prototype._getNodeOffset = function(node, index) {
|
|
|
var $parent, merging, offset;
|
|
|
if (index) {
|
|
|
$parent = $(node);
|
|
|
} else {
|
|
|
$parent = $(node).parent();
|
|
|
}
|
|
|
offset = 0;
|
|
|
merging = false;
|
|
|
$parent.contents().each((function(_this) {
|
|
|
return function(i, child) {
|
|
|
if (index === i || node === child) {
|
|
|
return false;
|
|
|
}
|
|
|
if (child.nodeType === 3) {
|
|
|
if (!merging) {
|
|
|
offset += 1;
|
|
|
merging = true;
|
|
|
}
|
|
|
} else {
|
|
|
offset += 1;
|
|
|
merging = false;
|
|
|
}
|
|
|
return null;
|
|
|
};
|
|
|
})(this));
|
|
|
return offset;
|
|
|
};
|
|
|
|
|
|
UndoManager.prototype._getNodePosition = function(node, offset) {
|
|
|
var position, prevNode;
|
|
|
if (node.nodeType === 3) {
|
|
|
prevNode = node.previousSibling;
|
|
|
while (prevNode && prevNode.nodeType === 3) {
|
|
|
node = prevNode;
|
|
|
offset += this.editor.util.getNodeLength(prevNode);
|
|
|
prevNode = prevNode.previousSibling;
|
|
|
}
|
|
|
} else {
|
|
|
offset = this._getNodeOffset(node, offset);
|
|
|
}
|
|
|
position = [];
|
|
|
position.unshift(offset);
|
|
|
this.editor.util.traverseUp((function(_this) {
|
|
|
return function(n) {
|
|
|
return position.unshift(_this._getNodeOffset(n));
|
|
|
};
|
|
|
})(this), node);
|
|
|
return position;
|
|
|
};
|
|
|
|
|
|
UndoManager.prototype._getNodeByPosition = function(position) {
|
|
|
var child, childNodes, i, node, offset, _i, _len, _ref;
|
|
|
node = this.editor.body[0];
|
|
|
_ref = position.slice(0, position.length - 1);
|
|
|
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
|
|
offset = _ref[i];
|
|
|
childNodes = node.childNodes;
|
|
|
if (offset > childNodes.length - 1) {
|
|
|
if (i === position.length - 2 && $(node).is('pre')) {
|
|
|
child = document.createTextNode('');
|
|
|
node.appendChild(child);
|
|
|
childNodes = node.childNodes;
|
|
|
} else {
|
|
|
node = null;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
node = childNodes[offset];
|
|
|
}
|
|
|
return node;
|
|
|
};
|
|
|
|
|
|
UndoManager.prototype.caretPosition = function(caret) {
|
|
|
var endContainer, endOffset, range, startContainer, startOffset;
|
|
|
if (!caret) {
|
|
|
range = this.editor.selection.getRange();
|
|
|
if (!(this.editor.inputManager.focused && (range != null))) {
|
|
|
return {};
|
|
|
}
|
|
|
caret = {
|
|
|
start: [],
|
|
|
end: null,
|
|
|
collapsed: true
|
|
|
};
|
|
|
caret.start = this._getNodePosition(range.startContainer, range.startOffset);
|
|
|
if (!range.collapsed) {
|
|
|
caret.end = this._getNodePosition(range.endContainer, range.endOffset);
|
|
|
caret.collapsed = false;
|
|
|
}
|
|
|
return caret;
|
|
|
} else {
|
|
|
if (!this.editor.inputManager.focused) {
|
|
|
this.editor.body.focus();
|
|
|
}
|
|
|
if (!caret.start) {
|
|
|
this.editor.body.blur();
|
|
|
return;
|
|
|
}
|
|
|
startContainer = this._getNodeByPosition(caret.start);
|
|
|
startOffset = caret.start[caret.start.length - 1];
|
|
|
if (caret.collapsed) {
|
|
|
endContainer = startContainer;
|
|
|
endOffset = startOffset;
|
|
|
} else {
|
|
|
endContainer = this._getNodeByPosition(caret.end);
|
|
|
endOffset = caret.start[caret.start.length - 1];
|
|
|
}
|
|
|
if (!startContainer || !endContainer) {
|
|
|
throw new Error('simditor: invalid caret state');
|
|
|
return;
|
|
|
}
|
|
|
range = document.createRange();
|
|
|
range.setStart(startContainer, startOffset);
|
|
|
range.setEnd(endContainer, endOffset);
|
|
|
return this.editor.selection.selectRange(range);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
return UndoManager;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
var Util,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
Util = (function(_super) {
|
|
|
__extends(Util, _super);
|
|
|
|
|
|
function Util() {
|
|
|
return Util.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
Util.pluginName = 'Util';
|
|
|
|
|
|
Util.prototype._init = function() {
|
|
|
this.editor = this._module;
|
|
|
if (this.browser.msie && this.browser.version < 11) {
|
|
|
return this.phBr = '';
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Util.prototype.phBr = '<br/>';
|
|
|
|
|
|
Util.prototype.os = (function() {
|
|
|
var os;
|
|
|
os = {};
|
|
|
if (/Mac/.test(navigator.appVersion)) {
|
|
|
os.mac = true;
|
|
|
} else if (/Linux/.test(navigator.appVersion)) {
|
|
|
os.linux = true;
|
|
|
} else if (/Win/.test(navigator.appVersion)) {
|
|
|
os.win = true;
|
|
|
} else if (/X11/.test(navigator.appVersion)) {
|
|
|
os.unix = true;
|
|
|
}
|
|
|
if (/Mobi/.test(navigator.appVersion)) {
|
|
|
os.mobile = true;
|
|
|
}
|
|
|
return os;
|
|
|
})();
|
|
|
|
|
|
Util.prototype.browser = (function() {
|
|
|
var chrome, firefox, ie, safari, ua, _ref, _ref1, _ref2, _ref3;
|
|
|
ua = navigator.userAgent;
|
|
|
ie = /(msie|trident)/i.test(ua);
|
|
|
chrome = /chrome|crios/i.test(ua);
|
|
|
safari = /safari/i.test(ua) && !chrome;
|
|
|
firefox = /firefox/i.test(ua);
|
|
|
if (ie) {
|
|
|
return {
|
|
|
msie: true,
|
|
|
version: ((_ref = ua.match(/(msie |rv:)(\d+(\.\d+)?)/i)) != null ? _ref[2] : void 0) * 1
|
|
|
};
|
|
|
} else if (chrome) {
|
|
|
return {
|
|
|
webkit: true,
|
|
|
chrome: true,
|
|
|
version: ((_ref1 = ua.match(/(?:chrome|crios)\/(\d+(\.\d+)?)/i)) != null ? _ref1[1] : void 0) * 1
|
|
|
};
|
|
|
} else if (safari) {
|
|
|
return {
|
|
|
webkit: true,
|
|
|
safari: true,
|
|
|
version: ((_ref2 = ua.match(/version\/(\d+(\.\d+)?)/i)) != null ? _ref2[1] : void 0) * 1
|
|
|
};
|
|
|
} else if (firefox) {
|
|
|
return {
|
|
|
mozilla: true,
|
|
|
firefox: true,
|
|
|
version: ((_ref3 = ua.match(/firefox\/(\d+(\.\d+)?)/i)) != null ? _ref3[1] : void 0) * 1
|
|
|
};
|
|
|
} else {
|
|
|
return {};
|
|
|
}
|
|
|
})();
|
|
|
|
|
|
Util.prototype.supportSelectionChange = (function() {
|
|
|
var e, onselectionchange;
|
|
|
onselectionchange = document.onselectionchange;
|
|
|
if (onselectionchange !== void 0) {
|
|
|
try {
|
|
|
document.onselectionchange = 0;
|
|
|
return document.onselectionchange === null;
|
|
|
} catch (_error) {
|
|
|
e = _error;
|
|
|
} finally {
|
|
|
document.onselectionchange = onselectionchange;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
})();
|
|
|
|
|
|
Util.prototype.reflow = function(el) {
|
|
|
if (el == null) {
|
|
|
el = document;
|
|
|
}
|
|
|
return $(el)[0].offsetHeight;
|
|
|
};
|
|
|
|
|
|
Util.prototype.metaKey = function(e) {
|
|
|
var isMac;
|
|
|
isMac = /Mac/.test(navigator.userAgent);
|
|
|
if (isMac) {
|
|
|
return e.metaKey;
|
|
|
} else {
|
|
|
return e.ctrlKey;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Util.prototype.isEmptyNode = function(node) {
|
|
|
var $node;
|
|
|
$node = $(node);
|
|
|
return $node.is(':empty') || (!$node.text() && !$node.find(':not(br, span, div)').length);
|
|
|
};
|
|
|
|
|
|
Util.prototype.isBlockNode = function(node) {
|
|
|
node = $(node)[0];
|
|
|
if (!node || node.nodeType === 3) {
|
|
|
return false;
|
|
|
}
|
|
|
return /^(div|p|ul|ol|li|blockquote|hr|pre|h1|h2|h3|h4|table)$/.test(node.nodeName.toLowerCase());
|
|
|
};
|
|
|
|
|
|
Util.prototype.closestBlockEl = function(node) {
|
|
|
var $node, blockEl, range;
|
|
|
if (node == null) {
|
|
|
range = this.editor.selection.getRange();
|
|
|
node = range != null ? range.commonAncestorContainer : void 0;
|
|
|
}
|
|
|
$node = $(node);
|
|
|
if (!$node.length) {
|
|
|
return null;
|
|
|
}
|
|
|
blockEl = $node.parentsUntil(this.editor.body).addBack();
|
|
|
blockEl = blockEl.filter((function(_this) {
|
|
|
return function(i) {
|
|
|
return _this.isBlockNode(blockEl.eq(i));
|
|
|
};
|
|
|
})(this));
|
|
|
if (blockEl.length) {
|
|
|
return blockEl.last();
|
|
|
} else {
|
|
|
return null;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Util.prototype.furthestNode = function(node, filter) {
|
|
|
var $node, blockEl, range;
|
|
|
if (node == null) {
|
|
|
range = this.editor.selection.getRange();
|
|
|
node = range != null ? range.commonAncestorContainer : void 0;
|
|
|
}
|
|
|
$node = $(node);
|
|
|
if (!$node.length) {
|
|
|
return null;
|
|
|
}
|
|
|
blockEl = $node.parentsUntil(this.editor.body).addBack();
|
|
|
blockEl = blockEl.filter((function(_this) {
|
|
|
return function(i) {
|
|
|
var $n;
|
|
|
$n = blockEl.eq(i);
|
|
|
if ($.isFunction(filter)) {
|
|
|
return filter($n);
|
|
|
} else {
|
|
|
return $n.is(filter);
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
if (blockEl.length) {
|
|
|
return blockEl.first();
|
|
|
} else {
|
|
|
return null;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Util.prototype.furthestBlockEl = function(node) {
|
|
|
return this.furthestNode(node, this.isBlockNode);
|
|
|
};
|
|
|
|
|
|
Util.prototype.getNodeLength = function(node) {
|
|
|
switch (node.nodeType) {
|
|
|
case 7:
|
|
|
case 10:
|
|
|
return 0;
|
|
|
case 3:
|
|
|
case 8:
|
|
|
return node.length;
|
|
|
default:
|
|
|
return node.childNodes.length;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Util.prototype.traverseUp = function(callback, node) {
|
|
|
var n, nodes, range, result, _i, _len, _results;
|
|
|
if (node == null) {
|
|
|
range = this.editor.selection.getRange();
|
|
|
node = range != null ? range.commonAncestorContainer : void 0;
|
|
|
}
|
|
|
if ((node == null) || !$.contains(this.editor.body[0], node)) {
|
|
|
return false;
|
|
|
}
|
|
|
nodes = $(node).parentsUntil(this.editor.body).get();
|
|
|
nodes.unshift(node);
|
|
|
_results = [];
|
|
|
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
|
|
|
n = nodes[_i];
|
|
|
result = callback(n);
|
|
|
if (result === false) {
|
|
|
break;
|
|
|
} else {
|
|
|
_results.push(void 0);
|
|
|
}
|
|
|
}
|
|
|
return _results;
|
|
|
};
|
|
|
|
|
|
Util.prototype.indent = function() {
|
|
|
var $blockEl, $childList, $nextTd, $parentLi, $td, indentLevel, range, spaceNode, tagName, _ref;
|
|
|
$blockEl = this.editor.util.closestBlockEl();
|
|
|
if (!($blockEl && $blockEl.length > 0)) {
|
|
|
return false;
|
|
|
}
|
|
|
if ($blockEl.is('pre')) {
|
|
|
spaceNode = document.createTextNode('\u00A0\u00A0');
|
|
|
this.editor.selection.insertNode(spaceNode);
|
|
|
} else if ($blockEl.is('li')) {
|
|
|
$parentLi = $blockEl.prev('li');
|
|
|
if ($parentLi.length < 1) {
|
|
|
return false;
|
|
|
}
|
|
|
this.editor.selection.save();
|
|
|
tagName = $blockEl.parent()[0].tagName;
|
|
|
$childList = $parentLi.children('ul, ol');
|
|
|
if ($childList.length > 0) {
|
|
|
$childList.append($blockEl);
|
|
|
} else {
|
|
|
$('<' + tagName + '/>').append($blockEl).appendTo($parentLi);
|
|
|
}
|
|
|
this.editor.selection.restore();
|
|
|
} else if ($blockEl.is('p, h1, h2, h3, h4')) {
|
|
|
indentLevel = (_ref = $blockEl.attr('data-indent')) != null ? _ref : 0;
|
|
|
indentLevel = indentLevel * 1 + 1;
|
|
|
if (indentLevel > 10) {
|
|
|
indentLevel = 10;
|
|
|
}
|
|
|
$blockEl.attr('data-indent', indentLevel);
|
|
|
} else if ($blockEl.is('table')) {
|
|
|
range = this.editor.selection.getRange();
|
|
|
$td = $(range.commonAncestorContainer).closest('td');
|
|
|
$nextTd = $td.next('td');
|
|
|
if (!($nextTd.length > 0)) {
|
|
|
$nextTd = $td.parent('tr').next('tr').find('td:first');
|
|
|
}
|
|
|
if (!($td.length > 0 && $nextTd.length > 0)) {
|
|
|
return false;
|
|
|
}
|
|
|
this.editor.selection.setRangeAtEndOf($nextTd);
|
|
|
} else {
|
|
|
spaceNode = document.createTextNode('\u00A0\u00A0\u00A0\u00A0');
|
|
|
this.editor.selection.insertNode(spaceNode);
|
|
|
}
|
|
|
this.editor.trigger('valuechanged');
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
Util.prototype.outdent = function() {
|
|
|
var $blockEl, $parent, $parentLi, $prevTd, $td, button, indentLevel, range, _ref;
|
|
|
$blockEl = this.editor.util.closestBlockEl();
|
|
|
if (!($blockEl && $blockEl.length > 0)) {
|
|
|
return false;
|
|
|
}
|
|
|
if ($blockEl.is('pre')) {
|
|
|
return false;
|
|
|
} else if ($blockEl.is('li')) {
|
|
|
$parent = $blockEl.parent();
|
|
|
$parentLi = $parent.parent('li');
|
|
|
if ($parentLi.length < 1) {
|
|
|
button = this.editor.toolbar.findButton($parent[0].tagName.toLowerCase());
|
|
|
if (button != null) {
|
|
|
button.command();
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
this.editor.selection.save();
|
|
|
if ($blockEl.next('li').length > 0) {
|
|
|
$('<' + $parent[0].tagName + '/>').append($blockEl.nextAll('li')).appendTo($blockEl);
|
|
|
}
|
|
|
$blockEl.insertAfter($parentLi);
|
|
|
if ($parent.children('li').length < 1) {
|
|
|
$parent.remove();
|
|
|
}
|
|
|
this.editor.selection.restore();
|
|
|
} else if ($blockEl.is('p, h1, h2, h3, h4')) {
|
|
|
indentLevel = (_ref = $blockEl.attr('data-indent')) != null ? _ref : 0;
|
|
|
indentLevel = indentLevel * 1 - 1;
|
|
|
if (indentLevel < 0) {
|
|
|
indentLevel = 0;
|
|
|
}
|
|
|
$blockEl.attr('data-indent', indentLevel);
|
|
|
} else if ($blockEl.is('table')) {
|
|
|
range = this.editor.selection.getRange();
|
|
|
$td = $(range.commonAncestorContainer).closest('td');
|
|
|
$prevTd = $td.prev('td');
|
|
|
if (!($prevTd.length > 0)) {
|
|
|
$prevTd = $td.parent('tr').prev('tr').find('td:last');
|
|
|
}
|
|
|
if (!($td.length > 0 && $prevTd.length > 0)) {
|
|
|
return false;
|
|
|
}
|
|
|
this.editor.selection.setRangeAtEndOf($prevTd);
|
|
|
} else {
|
|
|
return false;
|
|
|
}
|
|
|
this.editor.trigger('valuechanged');
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
Util.prototype.dataURLtoBlob = function(dataURL) {
|
|
|
var BlobBuilder, arrayBuffer, bb, byteString, hasArrayBufferViewSupport, hasBlobConstructor, i, intArray, mimeString, _i, _ref;
|
|
|
hasBlobConstructor = window.Blob && (function() {
|
|
|
var e;
|
|
|
try {
|
|
|
return Boolean(new Blob());
|
|
|
} catch (_error) {
|
|
|
e = _error;
|
|
|
return false;
|
|
|
}
|
|
|
})();
|
|
|
hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array && (function() {
|
|
|
var e;
|
|
|
try {
|
|
|
return new Blob([new Uint8Array(100)]).size === 100;
|
|
|
} catch (_error) {
|
|
|
e = _error;
|
|
|
return false;
|
|
|
}
|
|
|
})();
|
|
|
BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
|
|
|
if (!((hasBlobConstructor || BlobBuilder) && window.atob && window.ArrayBuffer && window.Uint8Array)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (dataURL.split(',')[0].indexOf('base64') >= 0) {
|
|
|
byteString = atob(dataURL.split(',')[1]);
|
|
|
} else {
|
|
|
byteString = decodeURIComponent(dataURL.split(',')[1]);
|
|
|
}
|
|
|
arrayBuffer = new ArrayBuffer(byteString.length);
|
|
|
intArray = new Uint8Array(arrayBuffer);
|
|
|
for (i = _i = 0, _ref = byteString.length; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
|
|
intArray[i] = byteString.charCodeAt(i);
|
|
|
}
|
|
|
mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];
|
|
|
if (hasBlobConstructor) {
|
|
|
return new Blob([hasArrayBufferViewSupport ? intArray : arrayBuffer], {
|
|
|
type: mimeString
|
|
|
});
|
|
|
}
|
|
|
bb = new BlobBuilder();
|
|
|
bb.append(arrayBuffer);
|
|
|
return bb.getBlob(mimeString);
|
|
|
};
|
|
|
|
|
|
return Util;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
var Toolbar,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
Toolbar = (function(_super) {
|
|
|
__extends(Toolbar, _super);
|
|
|
|
|
|
function Toolbar() {
|
|
|
return Toolbar.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
Toolbar.pluginName = 'Toolbar';
|
|
|
|
|
|
Toolbar.prototype.opts = {
|
|
|
toolbar: true,
|
|
|
toolbarFloat: true,
|
|
|
toolbarHidden: false,
|
|
|
toolbarFloatOffset: 0
|
|
|
};
|
|
|
|
|
|
Toolbar.prototype._tpl = {
|
|
|
wrapper: '<div class="simditor-toolbar"><ul></ul></div>',
|
|
|
separator: '<li><span class="separator"></span></li>'
|
|
|
};
|
|
|
|
|
|
Toolbar.prototype._init = function() {
|
|
|
var toolbarHeight;
|
|
|
this.editor = this._module;
|
|
|
if (!this.opts.toolbar) {
|
|
|
return;
|
|
|
}
|
|
|
if (!$.isArray(this.opts.toolbar)) {
|
|
|
this.opts.toolbar = ['bold', 'italic', 'underline', 'strikethrough', '|', 'ol', 'ul', 'blockquote', 'code', '|', 'link', 'image', '|', 'indent', 'outdent'];
|
|
|
}
|
|
|
this._render();
|
|
|
this.list.on('click', (function(_this) {
|
|
|
return function(e) {
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.wrapper.on('mousedown', (function(_this) {
|
|
|
return function(e) {
|
|
|
return _this.list.find('.menu-on').removeClass('.menu-on');
|
|
|
};
|
|
|
})(this));
|
|
|
$(document).on('mousedown.simditor' + this.editor.id, (function(_this) {
|
|
|
return function(e) {
|
|
|
return _this.list.find('.menu-on').removeClass('.menu-on');
|
|
|
};
|
|
|
})(this));
|
|
|
if (!this.opts.toolbarHidden && this.opts.toolbarFloat) {
|
|
|
this.wrapper.width(this.wrapper.outerWidth());
|
|
|
this.wrapper.css('top', this.opts.toolbarFloatOffset);
|
|
|
toolbarHeight = this.wrapper.outerHeight();
|
|
|
if (!this.editor.util.os.mobile) {
|
|
|
$(window).on('resize.simditor-' + this.editor.id, (function(_this) {
|
|
|
return function(e) {
|
|
|
_this.wrapper.css('position', 'static');
|
|
|
_this.editor.util.reflow(_this.wrapper);
|
|
|
_this.wrapper.css('left', _this.wrapper.offset().left);
|
|
|
return _this.wrapper.css('position', '');
|
|
|
};
|
|
|
})(this)).resize();
|
|
|
}
|
|
|
$(window).on('scroll.simditor-' + this.editor.id, (function(_this) {
|
|
|
return function(e) {
|
|
|
var bottomEdge, scrollTop, topEdge;
|
|
|
topEdge = _this.editor.wrapper.offset().top;
|
|
|
bottomEdge = topEdge + _this.editor.wrapper.outerHeight() - 80;
|
|
|
scrollTop = $(document).scrollTop() + _this.opts.toolbarFloatOffset;
|
|
|
if (scrollTop <= topEdge || scrollTop >= bottomEdge) {
|
|
|
_this.editor.wrapper.removeClass('toolbar-floating').css('padding-top', '');
|
|
|
if (_this.editor.util.os.mobile) {
|
|
|
return _this.wrapper.css('top', _this.opts.toolbarFloatOffset);
|
|
|
}
|
|
|
} else {
|
|
|
_this.editor.wrapper.addClass('toolbar-floating').css('padding-top', toolbarHeight);
|
|
|
if (_this.editor.util.os.mobile) {
|
|
|
return _this.wrapper.css('top', scrollTop - topEdge + _this.opts.toolbarFloatOffset);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
}
|
|
|
this.editor.on('selectionchanged', (function(_this) {
|
|
|
return function() {
|
|
|
return _this.toolbarStatus();
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('destroy', (function(_this) {
|
|
|
return function() {
|
|
|
return _this.buttons.length = 0;
|
|
|
};
|
|
|
})(this));
|
|
|
return $(document).on('mousedown.simditor-' + this.editor.id, (function(_this) {
|
|
|
return function(e) {
|
|
|
return _this.list.find('li.menu-on').removeClass('menu-on');
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
Toolbar.prototype._render = function() {
|
|
|
var name, _i, _len, _ref;
|
|
|
this.buttons = [];
|
|
|
this.wrapper = $(this._tpl.wrapper).prependTo(this.editor.wrapper);
|
|
|
this.list = this.wrapper.find('ul');
|
|
|
_ref = this.opts.toolbar;
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
name = _ref[_i];
|
|
|
if (name === '|') {
|
|
|
$(this._tpl.separator).appendTo(this.list);
|
|
|
continue;
|
|
|
}
|
|
|
if (!this.constructor.buttons[name]) {
|
|
|
throw new Error('simditor: invalid toolbar button "' + name + '"');
|
|
|
continue;
|
|
|
}
|
|
|
this.buttons.push(new this.constructor.buttons[name]({
|
|
|
editor: this.editor
|
|
|
}));
|
|
|
}
|
|
|
if (this.opts.toolbarHidden) {
|
|
|
return this.wrapper.hide();
|
|
|
} else {
|
|
|
return this.editor.placeholderEl.css('top', this.wrapper.outerHeight());
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Toolbar.prototype.toolbarStatus = function(name) {
|
|
|
var buttons;
|
|
|
if (!this.editor.inputManager.focused) {
|
|
|
return;
|
|
|
}
|
|
|
buttons = this.buttons.slice(0);
|
|
|
return this.editor.util.traverseUp((function(_this) {
|
|
|
return function(node) {
|
|
|
var button, i, removeButtons, _i, _j, _len, _len1;
|
|
|
removeButtons = [];
|
|
|
for (i = _i = 0, _len = buttons.length; _i < _len; i = ++_i) {
|
|
|
button = buttons[i];
|
|
|
if ((name != null) && button.name !== name) {
|
|
|
continue;
|
|
|
}
|
|
|
if (!button.status || button.status($(node)) === true) {
|
|
|
removeButtons.push(button);
|
|
|
}
|
|
|
}
|
|
|
for (_j = 0, _len1 = removeButtons.length; _j < _len1; _j++) {
|
|
|
button = removeButtons[_j];
|
|
|
i = $.inArray(button, buttons);
|
|
|
buttons.splice(i, 1);
|
|
|
}
|
|
|
if (buttons.length === 0) {
|
|
|
return false;
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
Toolbar.prototype.findButton = function(name) {
|
|
|
var button;
|
|
|
button = this.list.find('.toolbar-item-' + name).data('button');
|
|
|
return button != null ? button : null;
|
|
|
};
|
|
|
|
|
|
Toolbar.addButton = function(btn) {
|
|
|
return this.buttons[btn.prototype.name] = btn;
|
|
|
};
|
|
|
|
|
|
Toolbar.buttons = {};
|
|
|
|
|
|
return Toolbar;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
var Simditor,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
Simditor = (function(_super) {
|
|
|
__extends(Simditor, _super);
|
|
|
|
|
|
function Simditor() {
|
|
|
return Simditor.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
Simditor.connect(Util);
|
|
|
|
|
|
Simditor.connect(InputManager);
|
|
|
|
|
|
Simditor.connect(UndoManager);
|
|
|
|
|
|
Simditor.connect(Keystroke);
|
|
|
|
|
|
Simditor.connect(Formatter);
|
|
|
|
|
|
Simditor.connect(Selection);
|
|
|
|
|
|
Simditor.connect(Toolbar);
|
|
|
|
|
|
Simditor.count = 0;
|
|
|
|
|
|
Simditor.prototype.opts = {
|
|
|
textarea: null,
|
|
|
placeholder: '',
|
|
|
defaultImage: 'images/image.png',
|
|
|
params: {},
|
|
|
upload: false,
|
|
|
tabIndent: true
|
|
|
};
|
|
|
|
|
|
Simditor.prototype._init = function() {
|
|
|
var e, editor, form, uploadOpts;
|
|
|
this.textarea = $(this.opts.textarea);
|
|
|
this.opts.placeholder = this.opts.placeholder || this.textarea.attr('placeholder');
|
|
|
if (!this.textarea.length) {
|
|
|
throw new Error('simditor: param textarea is required.');
|
|
|
return;
|
|
|
}
|
|
|
editor = this.textarea.data('simditor');
|
|
|
if (editor != null) {
|
|
|
editor.destroy();
|
|
|
}
|
|
|
this.id = ++Simditor.count;
|
|
|
this._render();
|
|
|
if (this.opts.upload && simpleUploader) {
|
|
|
uploadOpts = typeof this.opts.upload === 'object' ? this.opts.upload : {};
|
|
|
this.uploader = simpleUploader(uploadOpts);
|
|
|
}
|
|
|
form = this.textarea.closest('form');
|
|
|
if (form.length) {
|
|
|
form.on('submit.simditor-' + this.id, (function(_this) {
|
|
|
return function() {
|
|
|
return _this.sync();
|
|
|
};
|
|
|
})(this));
|
|
|
form.on('reset.simditor-' + this.id, (function(_this) {
|
|
|
return function() {
|
|
|
return _this.setValue('');
|
|
|
};
|
|
|
})(this));
|
|
|
}
|
|
|
this.on('initialized', (function(_this) {
|
|
|
return function() {
|
|
|
if (_this.opts.placeholder) {
|
|
|
_this.on('valuechanged', function() {
|
|
|
return _this._placeholder();
|
|
|
});
|
|
|
}
|
|
|
return _this.setValue(_this.textarea.val().trim() || '');
|
|
|
};
|
|
|
})(this));
|
|
|
if (this.util.browser.mozilla) {
|
|
|
this.util.reflow();
|
|
|
try {
|
|
|
document.execCommand("enableObjectResizing", false, false);
|
|
|
return document.execCommand("enableInlineTableEditing", false, false);
|
|
|
} catch (_error) {
|
|
|
e = _error;
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
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>";
|
|
|
|
|
|
Simditor.prototype._render = function() {
|
|
|
var key, val, _ref, _results;
|
|
|
this.el = $(this._tpl).insertBefore(this.textarea);
|
|
|
this.wrapper = this.el.find('.simditor-wrapper');
|
|
|
this.body = this.wrapper.find('.simditor-body');
|
|
|
this.placeholderEl = this.wrapper.find('.simditor-placeholder').append(this.opts.placeholder);
|
|
|
this.el.append(this.textarea).data('simditor', this);
|
|
|
this.textarea.data('simditor', this).hide().blur();
|
|
|
this.body.attr('tabindex', this.textarea.attr('tabindex'));
|
|
|
if (this.util.os.mac) {
|
|
|
this.el.addClass('simditor-mac');
|
|
|
} else if (this.util.os.linux) {
|
|
|
this.el.addClass('simditor-linux');
|
|
|
}
|
|
|
if (this.util.os.mobile) {
|
|
|
this.el.addClass('simditor-mobile');
|
|
|
}
|
|
|
if (this.opts.params) {
|
|
|
_ref = this.opts.params;
|
|
|
_results = [];
|
|
|
for (key in _ref) {
|
|
|
val = _ref[key];
|
|
|
_results.push($('<input/>', {
|
|
|
type: 'hidden',
|
|
|
name: key,
|
|
|
value: val
|
|
|
}).insertAfter(this.textarea));
|
|
|
}
|
|
|
return _results;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Simditor.prototype._placeholder = function() {
|
|
|
var children, _ref;
|
|
|
children = this.body.children();
|
|
|
if (children.length === 0 || (children.length === 1 && this.util.isEmptyNode(children) && ((_ref = children.data('indent')) != null ? _ref : 0) < 1)) {
|
|
|
return this.placeholderEl.show();
|
|
|
} else {
|
|
|
return this.placeholderEl.hide();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Simditor.prototype.setValue = function(val) {
|
|
|
this.hidePopover();
|
|
|
this.textarea.val(val);
|
|
|
this.body.html(val);
|
|
|
this.formatter.format();
|
|
|
this.formatter.decorate();
|
|
|
this.util.reflow(this.body);
|
|
|
this.inputManager.lastCaretPosition = null;
|
|
|
return this.trigger('valuechanged');
|
|
|
};
|
|
|
|
|
|
Simditor.prototype.getValue = function() {
|
|
|
return this.sync();
|
|
|
};
|
|
|
|
|
|
Simditor.prototype.sync = function() {
|
|
|
var children, cloneBody, emptyP, firstP, lastP, val;
|
|
|
cloneBody = this.body.clone();
|
|
|
this.formatter.undecorate(cloneBody);
|
|
|
this.formatter.format(cloneBody);
|
|
|
this.formatter.autolink(cloneBody);
|
|
|
children = cloneBody.children();
|
|
|
lastP = children.last('p');
|
|
|
firstP = children.first('p');
|
|
|
while (lastP.is('p') && this.util.isEmptyNode(lastP)) {
|
|
|
emptyP = lastP;
|
|
|
lastP = lastP.prev('p');
|
|
|
emptyP.remove();
|
|
|
}
|
|
|
while (firstP.is('p') && this.util.isEmptyNode(firstP)) {
|
|
|
emptyP = firstP;
|
|
|
firstP = lastP.next('p');
|
|
|
emptyP.remove();
|
|
|
}
|
|
|
cloneBody.find('img.uploading').remove();
|
|
|
val = $.trim(cloneBody.html());
|
|
|
this.textarea.val(val);
|
|
|
return val;
|
|
|
};
|
|
|
|
|
|
Simditor.prototype.focus = function() {
|
|
|
var $blockEl, range;
|
|
|
if (this.inputManager.lastCaretPosition) {
|
|
|
return this.undoManager.caretPosition(this.inputManager.lastCaretPosition);
|
|
|
} else {
|
|
|
$blockEl = this.body.find('p, li, pre, h1, h2, h3, h4, td').first();
|
|
|
if (!($blockEl.length > 0)) {
|
|
|
return;
|
|
|
}
|
|
|
range = document.createRange();
|
|
|
this.selection.setRangeAtStartOf($blockEl, range);
|
|
|
return this.body.focus();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Simditor.prototype.blur = function() {
|
|
|
return this.body.blur();
|
|
|
};
|
|
|
|
|
|
Simditor.prototype.hidePopover = function() {
|
|
|
return this.el.find('.simditor-popover').each((function(_this) {
|
|
|
return function(i, popover) {
|
|
|
popover = $(popover).data('popover');
|
|
|
if (popover.active) {
|
|
|
return popover.hide();
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
Simditor.prototype.destroy = function() {
|
|
|
this.triggerHandler('destroy');
|
|
|
this.textarea.closest('form').off('.simditor .simditor-' + this.id);
|
|
|
this.selection.clear();
|
|
|
this.inputManager.focused = false;
|
|
|
this.textarea.insertBefore(this.el).hide().val('').removeData('simditor');
|
|
|
this.el.remove();
|
|
|
$(document).off('.simditor-' + this.id);
|
|
|
$(window).off('.simditor-' + this.id);
|
|
|
return this.off();
|
|
|
};
|
|
|
|
|
|
return Simditor;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
Simditor.i18n = {
|
|
|
'zh-CN': {
|
|
|
'blockquote': '引用',
|
|
|
'bold': '加粗文字',
|
|
|
'code': '插入代码',
|
|
|
'color': '文字颜色',
|
|
|
'hr': '分隔线',
|
|
|
'image': '插入图片',
|
|
|
'localImage': '本地图片',
|
|
|
'externalImage': '外链图片',
|
|
|
'uploadImage': '上传图片',
|
|
|
'uploadFailed': '上传失败了',
|
|
|
'uploadError': '上传出错了',
|
|
|
'imageUrl': '图片地址',
|
|
|
'imageSize': '图片尺寸',
|
|
|
'restoreImageSize': '还原图片尺寸',
|
|
|
'uploading': '正在上传',
|
|
|
'indent': '向右缩进',
|
|
|
'outdent': '向左缩进',
|
|
|
'italic': '斜体文字',
|
|
|
'link': '插入链接',
|
|
|
'text': '文本',
|
|
|
'linkText': '链接文字',
|
|
|
'linkUrl': '地址',
|
|
|
'removeLink': '移除链接',
|
|
|
'ol': '有序列表',
|
|
|
'ul': '无序列表',
|
|
|
'strikethrough': '删除线文字',
|
|
|
'table': '表格',
|
|
|
'deleteRow': '删除行',
|
|
|
'insertRowAbove': '在上面插入行',
|
|
|
'insertRowBelow': '在下面插入行',
|
|
|
'deleteColumn': '删除列',
|
|
|
'insertColumnLeft': '在左边插入列',
|
|
|
'insertColumnRight': '在右边插入列',
|
|
|
'deleteTable': '删除表格',
|
|
|
'title': '标题',
|
|
|
'normalText': '普通文本',
|
|
|
'underline': '下划线文字'
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var Button,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
|
__slice = [].slice;
|
|
|
|
|
|
Button = (function(_super) {
|
|
|
__extends(Button, _super);
|
|
|
|
|
|
Button.prototype._tpl = {
|
|
|
item: '<li><a tabindex="-1" unselectable="on" class="toolbar-item" href="javascript:;"><span></span></a></li>',
|
|
|
menuWrapper: '<div class="toolbar-menu"></div>',
|
|
|
menuItem: '<li><a tabindex="-1" unselectable="on" class="menu-item" href="javascript:;"><span></span></a></li>',
|
|
|
separator: '<li><span class="separator"></span></li>'
|
|
|
};
|
|
|
|
|
|
Button.prototype.name = '';
|
|
|
|
|
|
Button.prototype.icon = '';
|
|
|
|
|
|
Button.prototype.title = '';
|
|
|
|
|
|
Button.prototype.text = '';
|
|
|
|
|
|
Button.prototype.htmlTag = '';
|
|
|
|
|
|
Button.prototype.disableTag = '';
|
|
|
|
|
|
Button.prototype.menu = false;
|
|
|
|
|
|
Button.prototype.active = false;
|
|
|
|
|
|
Button.prototype.disabled = false;
|
|
|
|
|
|
Button.prototype.needFocus = true;
|
|
|
|
|
|
Button.prototype.shortcut = null;
|
|
|
|
|
|
function Button(opts) {
|
|
|
this.editor = opts.editor;
|
|
|
this.title = this._t(this.name);
|
|
|
Button.__super__.constructor.call(this, opts);
|
|
|
}
|
|
|
|
|
|
Button.prototype._init = function() {
|
|
|
var tag, _i, _len, _ref, _results;
|
|
|
this.render();
|
|
|
this.el.on('mousedown', (function(_this) {
|
|
|
return function(e) {
|
|
|
var exceed, param;
|
|
|
e.preventDefault();
|
|
|
if (_this.el.hasClass('disabled') || (_this.needFocus && !_this.editor.inputManager.focused)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (_this.menu) {
|
|
|
_this.wrapper.toggleClass('menu-on').siblings('li').removeClass('menu-on');
|
|
|
if (_this.wrapper.is('.menu-on')) {
|
|
|
exceed = _this.menuWrapper.offset().left + _this.menuWrapper.outerWidth() + 5 - _this.editor.wrapper.offset().left - _this.editor.wrapper.outerWidth();
|
|
|
if (exceed > 0) {
|
|
|
_this.menuWrapper.css({
|
|
|
'left': 'auto',
|
|
|
'right': 0
|
|
|
});
|
|
|
}
|
|
|
_this.trigger('menuexpand');
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
param = _this.el.data('param');
|
|
|
_this.command(param);
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.wrapper.on('click', 'a.menu-item', (function(_this) {
|
|
|
return function(e) {
|
|
|
var btn, param;
|
|
|
e.preventDefault();
|
|
|
btn = $(e.currentTarget);
|
|
|
_this.wrapper.removeClass('menu-on');
|
|
|
if (btn.hasClass('disabled') || (_this.needFocus && !_this.editor.inputManager.focused)) {
|
|
|
return false;
|
|
|
}
|
|
|
_this.editor.toolbar.wrapper.removeClass('menu-on');
|
|
|
param = btn.data('param');
|
|
|
_this.command(param);
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.wrapper.on('mousedown', 'a.menu-item', (function(_this) {
|
|
|
return function(e) {
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('blur', (function(_this) {
|
|
|
return function() {
|
|
|
_this.setActive(false);
|
|
|
return _this.setDisabled(false);
|
|
|
};
|
|
|
})(this));
|
|
|
if (this.shortcut != null) {
|
|
|
this.editor.inputManager.addShortcut(this.shortcut, (function(_this) {
|
|
|
return function(e) {
|
|
|
_this.el.mousedown();
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
}
|
|
|
_ref = this.htmlTag.split(',');
|
|
|
_results = [];
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
tag = _ref[_i];
|
|
|
tag = $.trim(tag);
|
|
|
if (tag && $.inArray(tag, this.editor.formatter._allowedTags) < 0) {
|
|
|
_results.push(this.editor.formatter._allowedTags.push(tag));
|
|
|
} else {
|
|
|
_results.push(void 0);
|
|
|
}
|
|
|
}
|
|
|
return _results;
|
|
|
};
|
|
|
|
|
|
Button.prototype.render = function() {
|
|
|
this.wrapper = $(this._tpl.item).appendTo(this.editor.toolbar.list);
|
|
|
this.el = this.wrapper.find('a.toolbar-item');
|
|
|
this.el.attr('title', this.title).addClass('toolbar-item-' + this.name).data('button', this);
|
|
|
this.el.find('span').addClass(this.icon ? 'fa fa-' + this.icon : '').text(this.text);
|
|
|
if (!this.menu) {
|
|
|
return;
|
|
|
}
|
|
|
this.menuWrapper = $(this._tpl.menuWrapper).appendTo(this.wrapper);
|
|
|
this.menuWrapper.addClass('toolbar-menu-' + this.name);
|
|
|
return this.renderMenu();
|
|
|
};
|
|
|
|
|
|
Button.prototype.renderMenu = function() {
|
|
|
var $menuBtntnEl, $menuItemEl, menuItem, _i, _len, _ref, _ref1, _results;
|
|
|
if (!$.isArray(this.menu)) {
|
|
|
return;
|
|
|
}
|
|
|
this.menuEl = $('<ul/>').appendTo(this.menuWrapper);
|
|
|
_ref = this.menu;
|
|
|
_results = [];
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
menuItem = _ref[_i];
|
|
|
if (menuItem === '|') {
|
|
|
$(this._tpl.separator).appendTo(this.menuEl);
|
|
|
continue;
|
|
|
}
|
|
|
$menuItemEl = $(this._tpl.menuItem).appendTo(this.menuEl);
|
|
|
_results.push($menuBtntnEl = $menuItemEl.find('a.menu-item').attr({
|
|
|
'title': (_ref1 = menuItem.title) != null ? _ref1 : menuItem.text,
|
|
|
'data-param': menuItem.param
|
|
|
}).addClass('menu-item-' + menuItem.name).find('span').text(menuItem.text));
|
|
|
}
|
|
|
return _results;
|
|
|
};
|
|
|
|
|
|
Button.prototype.setActive = function(active) {
|
|
|
if (active === this.active) {
|
|
|
return;
|
|
|
}
|
|
|
this.active = active;
|
|
|
this.el.toggleClass('active', this.active);
|
|
|
return this.editor.toolbar.trigger('buttonstatus', [this]);
|
|
|
};
|
|
|
|
|
|
Button.prototype.setDisabled = function(disabled) {
|
|
|
if (disabled === this.disabled) {
|
|
|
return;
|
|
|
}
|
|
|
this.disabled = disabled;
|
|
|
this.el.toggleClass('disabled', this.disabled);
|
|
|
return this.editor.toolbar.trigger('buttonstatus', [this]);
|
|
|
};
|
|
|
|
|
|
Button.prototype.status = function($node) {
|
|
|
if ($node != null) {
|
|
|
this.setDisabled($node.is(this.disableTag));
|
|
|
}
|
|
|
if (this.disabled) {
|
|
|
return true;
|
|
|
}
|
|
|
if ($node != null) {
|
|
|
this.setActive($node.is(this.htmlTag));
|
|
|
}
|
|
|
return this.active;
|
|
|
};
|
|
|
|
|
|
Button.prototype.command = function(param) {};
|
|
|
|
|
|
Button.prototype._t = function() {
|
|
|
var args, result, _ref;
|
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
|
result = Button.__super__._t.apply(this, args);
|
|
|
if (!result) {
|
|
|
result = (_ref = this.editor)._t.apply(_ref, args);
|
|
|
}
|
|
|
return result;
|
|
|
};
|
|
|
|
|
|
return Button;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
Simditor.Button = Button;
|
|
|
|
|
|
var Popover,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
Popover = (function(_super) {
|
|
|
__extends(Popover, _super);
|
|
|
|
|
|
Popover.prototype.offset = {
|
|
|
top: 4,
|
|
|
left: 0
|
|
|
};
|
|
|
|
|
|
Popover.prototype.target = null;
|
|
|
|
|
|
Popover.prototype.active = false;
|
|
|
|
|
|
function Popover(opts) {
|
|
|
this.button = opts.button;
|
|
|
this.editor = opts.button.editor;
|
|
|
Popover.__super__.constructor.call(this, opts);
|
|
|
}
|
|
|
|
|
|
Popover.prototype._init = function() {
|
|
|
this.el = $('<div class="simditor-popover"></div>').appendTo(this.editor.el).data('popover', this);
|
|
|
this.render();
|
|
|
this.el.on('mouseenter', (function(_this) {
|
|
|
return function(e) {
|
|
|
return _this.el.addClass('hover');
|
|
|
};
|
|
|
})(this));
|
|
|
return this.el.on('mouseleave', (function(_this) {
|
|
|
return function(e) {
|
|
|
return _this.el.removeClass('hover');
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
Popover.prototype.render = function() {};
|
|
|
|
|
|
Popover.prototype.show = function($target, position) {
|
|
|
if (position == null) {
|
|
|
position = 'bottom';
|
|
|
}
|
|
|
if ($target == null) {
|
|
|
return;
|
|
|
}
|
|
|
this.el.siblings('.simditor-popover').each((function(_this) {
|
|
|
return function(i, popover) {
|
|
|
popover = $(popover).data('popover');
|
|
|
if (popover.active) {
|
|
|
return popover.hide();
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
this.target = $target.addClass('selected');
|
|
|
if (this.active) {
|
|
|
this.refresh(position);
|
|
|
return this.trigger('popovershow');
|
|
|
} else {
|
|
|
this.active = true;
|
|
|
this.el.css({
|
|
|
left: -9999
|
|
|
}).show();
|
|
|
return setTimeout((function(_this) {
|
|
|
return function() {
|
|
|
_this.refresh(position);
|
|
|
return _this.trigger('popovershow');
|
|
|
};
|
|
|
})(this), 0);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Popover.prototype.hide = function() {
|
|
|
if (!this.active) {
|
|
|
return;
|
|
|
}
|
|
|
if (this.target) {
|
|
|
this.target.removeClass('selected');
|
|
|
}
|
|
|
this.target = null;
|
|
|
this.active = false;
|
|
|
this.el.hide();
|
|
|
return this.trigger('popoverhide');
|
|
|
};
|
|
|
|
|
|
Popover.prototype.refresh = function(position) {
|
|
|
var editorOffset, left, targetH, targetOffset, top;
|
|
|
if (position == null) {
|
|
|
position = 'bottom';
|
|
|
}
|
|
|
if (!this.active) {
|
|
|
return;
|
|
|
}
|
|
|
editorOffset = this.editor.el.offset();
|
|
|
targetOffset = this.target.offset();
|
|
|
targetH = this.target.outerHeight();
|
|
|
if (position === 'bottom') {
|
|
|
top = targetOffset.top - editorOffset.top + targetH;
|
|
|
} else if (position === 'top') {
|
|
|
top = targetOffset.top - editorOffset.top - this.el.height();
|
|
|
}
|
|
|
left = Math.min(targetOffset.left - editorOffset.left, this.editor.wrapper.width() - this.el.outerWidth() - 10);
|
|
|
return this.el.css({
|
|
|
top: top + this.offset.top,
|
|
|
left: left + this.offset.left
|
|
|
});
|
|
|
};
|
|
|
|
|
|
Popover.prototype.destroy = function() {
|
|
|
this.target = null;
|
|
|
this.active = false;
|
|
|
this.editor.off('.linkpopover');
|
|
|
return this.el.remove();
|
|
|
};
|
|
|
|
|
|
return Popover;
|
|
|
|
|
|
})(SimpleModule);
|
|
|
|
|
|
Simditor.Popover = Popover;
|
|
|
|
|
|
var TitleButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
TitleButton = (function(_super) {
|
|
|
__extends(TitleButton, _super);
|
|
|
|
|
|
function TitleButton() {
|
|
|
return TitleButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
TitleButton.prototype.name = 'title';
|
|
|
|
|
|
TitleButton.prototype.htmlTag = 'h1, h2, h3, h4';
|
|
|
|
|
|
TitleButton.prototype.disableTag = 'pre, table';
|
|
|
|
|
|
TitleButton.prototype._init = function() {
|
|
|
this.menu = [
|
|
|
{
|
|
|
name: 'normal',
|
|
|
text: this._t('normalText'),
|
|
|
param: 'p'
|
|
|
}, '|', {
|
|
|
name: 'h1',
|
|
|
text: this._t('title') + ' 1',
|
|
|
param: 'h1'
|
|
|
}, {
|
|
|
name: 'h2',
|
|
|
text: this._t('title') + ' 2',
|
|
|
param: 'h2'
|
|
|
}, {
|
|
|
name: 'h3',
|
|
|
text: this._t('title') + ' 3',
|
|
|
param: 'h3'
|
|
|
}, {
|
|
|
name: 'h4',
|
|
|
text: this._t('title') + ' 4',
|
|
|
param: 'h4'
|
|
|
}, {
|
|
|
name: 'h5',
|
|
|
text: this._t('title') + ' 5',
|
|
|
param: 'h5'
|
|
|
}
|
|
|
];
|
|
|
return TitleButton.__super__._init.call(this);
|
|
|
};
|
|
|
|
|
|
TitleButton.prototype.setActive = function(active, param) {
|
|
|
TitleButton.__super__.setActive.call(this, active);
|
|
|
this.el.removeClass('active-p active-h1 active-h2 active-h3');
|
|
|
if (active) {
|
|
|
return this.el.addClass('active active-' + param);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
TitleButton.prototype.status = function($node) {
|
|
|
var param, _ref;
|
|
|
if ($node != null) {
|
|
|
this.setDisabled($node.is(this.disableTag));
|
|
|
}
|
|
|
if (this.disabled) {
|
|
|
return true;
|
|
|
}
|
|
|
if ($node != null) {
|
|
|
param = (_ref = $node[0].tagName) != null ? _ref.toLowerCase() : void 0;
|
|
|
this.setActive($node.is(this.htmlTag), param);
|
|
|
}
|
|
|
return this.active;
|
|
|
};
|
|
|
|
|
|
TitleButton.prototype.command = function(param) {
|
|
|
var $contents, $endBlock, $startBlock, endNode, node, range, results, startNode, _i, _len, _ref;
|
|
|
range = this.editor.selection.getRange();
|
|
|
startNode = range.startContainer;
|
|
|
endNode = range.endContainer;
|
|
|
$startBlock = this.editor.util.closestBlockEl(startNode);
|
|
|
$endBlock = this.editor.util.closestBlockEl(endNode);
|
|
|
this.editor.selection.save();
|
|
|
range.setStartBefore($startBlock[0]);
|
|
|
range.setEndAfter($endBlock[0]);
|
|
|
$contents = $(range.extractContents());
|
|
|
results = [];
|
|
|
$contents.children().each((function(_this) {
|
|
|
return function(i, el) {
|
|
|
var c, converted, _i, _len, _results;
|
|
|
converted = _this._convertEl(el, param);
|
|
|
_results = [];
|
|
|
for (_i = 0, _len = converted.length; _i < _len; _i++) {
|
|
|
c = converted[_i];
|
|
|
_results.push(results.push(c));
|
|
|
}
|
|
|
return _results;
|
|
|
};
|
|
|
})(this));
|
|
|
_ref = results.reverse();
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
node = _ref[_i];
|
|
|
range.insertNode(node[0]);
|
|
|
}
|
|
|
this.editor.selection.restore();
|
|
|
return this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
|
|
|
TitleButton.prototype._convertEl = function(el, param) {
|
|
|
var $block, $el, results;
|
|
|
$el = $(el);
|
|
|
results = [];
|
|
|
if ($el.is(param)) {
|
|
|
results.push($el);
|
|
|
} else {
|
|
|
$block = $('<' + param + '/>').append($el.contents());
|
|
|
results.push($block);
|
|
|
}
|
|
|
return results;
|
|
|
};
|
|
|
|
|
|
return TitleButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(TitleButton);
|
|
|
|
|
|
var BoldButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
BoldButton = (function(_super) {
|
|
|
__extends(BoldButton, _super);
|
|
|
|
|
|
function BoldButton() {
|
|
|
return BoldButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
BoldButton.prototype.name = 'bold';
|
|
|
|
|
|
BoldButton.prototype.icon = 'bold';
|
|
|
|
|
|
BoldButton.prototype.htmlTag = 'b, strong';
|
|
|
|
|
|
BoldButton.prototype.disableTag = 'pre';
|
|
|
|
|
|
BoldButton.prototype.shortcut = 'cmd+b';
|
|
|
|
|
|
BoldButton.prototype._init = function() {
|
|
|
if (this.editor.util.os.mac) {
|
|
|
this.title = this.title + ' ( Cmd + b )';
|
|
|
} else {
|
|
|
this.title = this.title + ' ( Ctrl + b )';
|
|
|
this.shortcut = 'ctrl+b';
|
|
|
}
|
|
|
return BoldButton.__super__._init.call(this);
|
|
|
};
|
|
|
|
|
|
BoldButton.prototype.status = function($node) {
|
|
|
var active;
|
|
|
if ($node != null) {
|
|
|
this.setDisabled($node.is(this.disableTag));
|
|
|
}
|
|
|
if (this.disabled) {
|
|
|
return true;
|
|
|
}
|
|
|
active = document.queryCommandState('bold') === true;
|
|
|
this.setActive(active);
|
|
|
return active;
|
|
|
};
|
|
|
|
|
|
BoldButton.prototype.command = function() {
|
|
|
document.execCommand('bold');
|
|
|
this.editor.trigger('valuechanged');
|
|
|
return $(document).trigger('selectionchange');
|
|
|
};
|
|
|
|
|
|
return BoldButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(BoldButton);
|
|
|
|
|
|
var ItalicButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
ItalicButton = (function(_super) {
|
|
|
__extends(ItalicButton, _super);
|
|
|
|
|
|
function ItalicButton() {
|
|
|
return ItalicButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
ItalicButton.prototype.name = 'italic';
|
|
|
|
|
|
ItalicButton.prototype.icon = 'italic';
|
|
|
|
|
|
ItalicButton.prototype.htmlTag = 'i';
|
|
|
|
|
|
ItalicButton.prototype.disableTag = 'pre';
|
|
|
|
|
|
ItalicButton.prototype.shortcut = 'cmd+i';
|
|
|
|
|
|
ItalicButton.prototype._init = function() {
|
|
|
if (this.editor.util.os.mac) {
|
|
|
this.title = this.title + ' ( Cmd + i )';
|
|
|
} else {
|
|
|
this.title = this.title + ' ( Ctrl + i )';
|
|
|
this.shortcut = 'ctrl+i';
|
|
|
}
|
|
|
return ItalicButton.__super__._init.call(this);
|
|
|
};
|
|
|
|
|
|
ItalicButton.prototype.status = function($node) {
|
|
|
var active;
|
|
|
if ($node != null) {
|
|
|
this.setDisabled($node.is(this.disableTag));
|
|
|
}
|
|
|
if (this.disabled) {
|
|
|
return this.disabled;
|
|
|
}
|
|
|
active = document.queryCommandState('italic') === true;
|
|
|
this.setActive(active);
|
|
|
return active;
|
|
|
};
|
|
|
|
|
|
ItalicButton.prototype.command = function() {
|
|
|
document.execCommand('italic');
|
|
|
this.editor.trigger('valuechanged');
|
|
|
return $(document).trigger('selectionchange');
|
|
|
};
|
|
|
|
|
|
return ItalicButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(ItalicButton);
|
|
|
|
|
|
var UnderlineButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
UnderlineButton = (function(_super) {
|
|
|
__extends(UnderlineButton, _super);
|
|
|
|
|
|
function UnderlineButton() {
|
|
|
return UnderlineButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
UnderlineButton.prototype.name = 'underline';
|
|
|
|
|
|
UnderlineButton.prototype.icon = 'underline';
|
|
|
|
|
|
UnderlineButton.prototype.htmlTag = 'u';
|
|
|
|
|
|
UnderlineButton.prototype.disableTag = 'pre';
|
|
|
|
|
|
UnderlineButton.prototype.shortcut = 'cmd+u';
|
|
|
|
|
|
UnderlineButton.prototype.render = function() {
|
|
|
if (this.editor.util.os.mac) {
|
|
|
this.title = this.title + ' ( Cmd + u )';
|
|
|
} else {
|
|
|
this.title = this.title + ' ( Ctrl + u )';
|
|
|
this.shortcut = 'ctrl+u';
|
|
|
}
|
|
|
return UnderlineButton.__super__.render.call(this);
|
|
|
};
|
|
|
|
|
|
UnderlineButton.prototype.status = function($node) {
|
|
|
var active;
|
|
|
if ($node != null) {
|
|
|
this.setDisabled($node.is(this.disableTag));
|
|
|
}
|
|
|
if (this.disabled) {
|
|
|
return this.disabled;
|
|
|
}
|
|
|
active = document.queryCommandState('underline') === true;
|
|
|
this.setActive(active);
|
|
|
return active;
|
|
|
};
|
|
|
|
|
|
UnderlineButton.prototype.command = function() {
|
|
|
document.execCommand('underline');
|
|
|
this.editor.trigger('valuechanged');
|
|
|
return $(document).trigger('selectionchange');
|
|
|
};
|
|
|
|
|
|
return UnderlineButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(UnderlineButton);
|
|
|
|
|
|
var ColorButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
|
__slice = [].slice;
|
|
|
|
|
|
ColorButton = (function(_super) {
|
|
|
__extends(ColorButton, _super);
|
|
|
|
|
|
function ColorButton() {
|
|
|
return ColorButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
ColorButton.prototype.name = 'color';
|
|
|
|
|
|
ColorButton.prototype.icon = 'font';
|
|
|
|
|
|
ColorButton.prototype.disableTag = 'pre';
|
|
|
|
|
|
ColorButton.prototype.menu = true;
|
|
|
|
|
|
ColorButton.prototype.render = function() {
|
|
|
var args;
|
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
|
return ColorButton.__super__.render.apply(this, args);
|
|
|
};
|
|
|
|
|
|
ColorButton.prototype.renderMenu = function() {
|
|
|
$('<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);
|
|
|
this.menuWrapper.on('mousedown', '.color-list', function(e) {
|
|
|
return false;
|
|
|
});
|
|
|
return this.menuWrapper.on('click', '.font-color', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $link, $p, hex, rgb;
|
|
|
_this.wrapper.removeClass('menu-on');
|
|
|
$link = $(e.currentTarget);
|
|
|
if ($link.hasClass('font-color-default')) {
|
|
|
$p = _this.editor.body.find('p, li');
|
|
|
if (!($p.length > 0)) {
|
|
|
return;
|
|
|
}
|
|
|
rgb = window.getComputedStyle($p[0], null).getPropertyValue('color');
|
|
|
hex = _this._convertRgbToHex(rgb);
|
|
|
} else {
|
|
|
rgb = window.getComputedStyle($link[0], null).getPropertyValue('background-color');
|
|
|
hex = _this._convertRgbToHex(rgb);
|
|
|
}
|
|
|
if (!hex) {
|
|
|
return;
|
|
|
}
|
|
|
document.execCommand('foreColor', false, hex);
|
|
|
return _this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
ColorButton.prototype._convertRgbToHex = function(rgb) {
|
|
|
var match, re, rgbToHex;
|
|
|
re = /rgb\((\d+),\s?(\d+),\s?(\d+)\)/g;
|
|
|
match = re.exec(rgb);
|
|
|
if (!match) {
|
|
|
return '';
|
|
|
}
|
|
|
rgbToHex = function(r, g, b) {
|
|
|
var componentToHex;
|
|
|
componentToHex = function(c) {
|
|
|
var hex;
|
|
|
hex = c.toString(16);
|
|
|
if (hex.length === 1) {
|
|
|
return '0' + hex;
|
|
|
} else {
|
|
|
return hex;
|
|
|
}
|
|
|
};
|
|
|
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
|
|
|
};
|
|
|
return rgbToHex(match[1] * 1, match[2] * 1, match[3] * 1);
|
|
|
};
|
|
|
|
|
|
return ColorButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(ColorButton);
|
|
|
|
|
|
var ListButton, OrderListButton, UnorderListButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
ListButton = (function(_super) {
|
|
|
__extends(ListButton, _super);
|
|
|
|
|
|
function ListButton() {
|
|
|
return ListButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
ListButton.prototype.type = '';
|
|
|
|
|
|
ListButton.prototype.disableTag = 'pre, table';
|
|
|
|
|
|
ListButton.prototype.status = function($node) {
|
|
|
var anotherType;
|
|
|
if ($node != null) {
|
|
|
this.setDisabled($node.is(this.disableTag));
|
|
|
}
|
|
|
if (this.disabled) {
|
|
|
return true;
|
|
|
}
|
|
|
if ($node == null) {
|
|
|
return this.active;
|
|
|
}
|
|
|
anotherType = this.type === 'ul' ? 'ol' : 'ul';
|
|
|
if ($node.is(anotherType)) {
|
|
|
this.setActive(false);
|
|
|
return true;
|
|
|
} else {
|
|
|
this.setActive($node.is(this.htmlTag));
|
|
|
return this.active;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
ListButton.prototype.command = function(param) {
|
|
|
var $contents, $endBlock, $furthestEnd, $furthestStart, $parent, $startBlock, endLevel, endNode, getListLevel, node, range, results, startLevel, startNode, _i, _len, _ref;
|
|
|
range = this.editor.selection.getRange();
|
|
|
startNode = range.startContainer;
|
|
|
endNode = range.endContainer;
|
|
|
$startBlock = this.editor.util.closestBlockEl(startNode);
|
|
|
$endBlock = this.editor.util.closestBlockEl(endNode);
|
|
|
this.editor.selection.save();
|
|
|
range.setStartBefore($startBlock[0]);
|
|
|
range.setEndAfter($endBlock[0]);
|
|
|
if ($startBlock.is('li') && $endBlock.is('li')) {
|
|
|
$furthestStart = this.editor.util.furthestNode($startBlock, 'ul, ol');
|
|
|
$furthestEnd = this.editor.util.furthestNode($endBlock, 'ul, ol');
|
|
|
if ($furthestStart.is($furthestEnd)) {
|
|
|
getListLevel = function($li) {
|
|
|
var lvl;
|
|
|
lvl = 1;
|
|
|
while (!$li.parent().is($furthestStart)) {
|
|
|
lvl += 1;
|
|
|
$li = $li.parent();
|
|
|
}
|
|
|
return lvl;
|
|
|
};
|
|
|
startLevel = getListLevel($startBlock);
|
|
|
endLevel = getListLevel($endBlock);
|
|
|
if (startLevel > endLevel) {
|
|
|
$parent = $endBlock.parent();
|
|
|
} else {
|
|
|
$parent = $startBlock.parent();
|
|
|
}
|
|
|
range.setStartBefore($parent[0]);
|
|
|
range.setEndAfter($parent[0]);
|
|
|
} else {
|
|
|
range.setStartBefore($furthestStart[0]);
|
|
|
range.setEndAfter($furthestEnd[0]);
|
|
|
}
|
|
|
}
|
|
|
$contents = $(range.extractContents());
|
|
|
results = [];
|
|
|
$contents.children().each((function(_this) {
|
|
|
return function(i, el) {
|
|
|
var c, converted, _i, _len, _results;
|
|
|
converted = _this._convertEl(el);
|
|
|
_results = [];
|
|
|
for (_i = 0, _len = converted.length; _i < _len; _i++) {
|
|
|
c = converted[_i];
|
|
|
if (results.length && results[results.length - 1].is(_this.type) && c.is(_this.type)) {
|
|
|
_results.push(results[results.length - 1].append(c.children()));
|
|
|
} else {
|
|
|
_results.push(results.push(c));
|
|
|
}
|
|
|
}
|
|
|
return _results;
|
|
|
};
|
|
|
})(this));
|
|
|
_ref = results.reverse();
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
node = _ref[_i];
|
|
|
range.insertNode(node[0]);
|
|
|
}
|
|
|
this.editor.selection.restore();
|
|
|
return this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
|
|
|
ListButton.prototype._convertEl = function(el) {
|
|
|
var $el, anotherType, block, child, children, results, _i, _len, _ref;
|
|
|
$el = $(el);
|
|
|
results = [];
|
|
|
anotherType = this.type === 'ul' ? 'ol' : 'ul';
|
|
|
if ($el.is(this.type)) {
|
|
|
$el.children('li').each((function(_this) {
|
|
|
return function(i, li) {
|
|
|
var $childList, $li, block;
|
|
|
$li = $(li);
|
|
|
$childList = $li.children('ul, ol').remove();
|
|
|
block = $('<p/>').append($(li).html() || _this.editor.util.phBr);
|
|
|
results.push(block);
|
|
|
if ($childList.length > 0) {
|
|
|
return results.push($childList);
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
} else if ($el.is(anotherType)) {
|
|
|
block = $('<' + this.type + '/>').append($el.html());
|
|
|
results.push(block);
|
|
|
} else if ($el.is('blockquote')) {
|
|
|
_ref = $el.children().get();
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
child = _ref[_i];
|
|
|
children = this._convertEl(child);
|
|
|
}
|
|
|
$.merge(results, children);
|
|
|
} else if ($el.is('table')) {
|
|
|
|
|
|
} else {
|
|
|
block = $('<' + this.type + '><li></li></' + this.type + '>');
|
|
|
block.find('li').append($el.html() || this.editor.util.phBr);
|
|
|
results.push(block);
|
|
|
}
|
|
|
return results;
|
|
|
};
|
|
|
|
|
|
return ListButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
OrderListButton = (function(_super) {
|
|
|
__extends(OrderListButton, _super);
|
|
|
|
|
|
function OrderListButton() {
|
|
|
return OrderListButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
OrderListButton.prototype.type = 'ol';
|
|
|
|
|
|
OrderListButton.prototype.name = 'ol';
|
|
|
|
|
|
OrderListButton.prototype.icon = 'list-ol';
|
|
|
|
|
|
OrderListButton.prototype.htmlTag = 'ol';
|
|
|
|
|
|
OrderListButton.prototype.shortcut = 'cmd+/';
|
|
|
|
|
|
OrderListButton.prototype._init = function() {
|
|
|
if (this.editor.util.os.mac) {
|
|
|
this.title = this.title + ' ( Cmd + / )';
|
|
|
} else {
|
|
|
this.title = this.title + ' ( ctrl + / )';
|
|
|
this.shortcut = 'ctrl+/';
|
|
|
}
|
|
|
return OrderListButton.__super__._init.call(this);
|
|
|
};
|
|
|
|
|
|
return OrderListButton;
|
|
|
|
|
|
})(ListButton);
|
|
|
|
|
|
UnorderListButton = (function(_super) {
|
|
|
__extends(UnorderListButton, _super);
|
|
|
|
|
|
function UnorderListButton() {
|
|
|
return UnorderListButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
UnorderListButton.prototype.type = 'ul';
|
|
|
|
|
|
UnorderListButton.prototype.name = 'ul';
|
|
|
|
|
|
UnorderListButton.prototype.icon = 'list-ul';
|
|
|
|
|
|
UnorderListButton.prototype.htmlTag = 'ul';
|
|
|
|
|
|
UnorderListButton.prototype.shortcut = 'cmd+.';
|
|
|
|
|
|
UnorderListButton.prototype._init = function() {
|
|
|
if (this.editor.util.os.mac) {
|
|
|
this.title = this.title + ' ( Cmd + . )';
|
|
|
} else {
|
|
|
this.title = this.title + ' ( Ctrl + . )';
|
|
|
this.shortcut = 'ctrl+.';
|
|
|
}
|
|
|
return UnorderListButton.__super__._init.call(this);
|
|
|
};
|
|
|
|
|
|
return UnorderListButton;
|
|
|
|
|
|
})(ListButton);
|
|
|
|
|
|
Simditor.Toolbar.addButton(OrderListButton);
|
|
|
|
|
|
Simditor.Toolbar.addButton(UnorderListButton);
|
|
|
|
|
|
var BlockquoteButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
BlockquoteButton = (function(_super) {
|
|
|
__extends(BlockquoteButton, _super);
|
|
|
|
|
|
function BlockquoteButton() {
|
|
|
return BlockquoteButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
BlockquoteButton.prototype.name = 'blockquote';
|
|
|
|
|
|
BlockquoteButton.prototype.icon = 'quote-left';
|
|
|
|
|
|
BlockquoteButton.prototype.htmlTag = 'blockquote';
|
|
|
|
|
|
BlockquoteButton.prototype.disableTag = 'pre, table';
|
|
|
|
|
|
BlockquoteButton.prototype.command = function() {
|
|
|
var $contents, $endBlock, $startBlock, endNode, node, range, results, startNode, _i, _len, _ref;
|
|
|
range = this.editor.selection.getRange();
|
|
|
startNode = range.startContainer;
|
|
|
endNode = range.endContainer;
|
|
|
$startBlock = this.editor.util.furthestBlockEl(startNode);
|
|
|
$endBlock = this.editor.util.furthestBlockEl(endNode);
|
|
|
this.editor.selection.save();
|
|
|
range.setStartBefore($startBlock[0]);
|
|
|
range.setEndAfter($endBlock[0]);
|
|
|
$contents = $(range.extractContents());
|
|
|
results = [];
|
|
|
$contents.children().each((function(_this) {
|
|
|
return function(i, el) {
|
|
|
var c, converted, _i, _len, _results;
|
|
|
converted = _this._convertEl(el);
|
|
|
_results = [];
|
|
|
for (_i = 0, _len = converted.length; _i < _len; _i++) {
|
|
|
c = converted[_i];
|
|
|
if (results.length && results[results.length - 1].is(_this.htmlTag) && c.is(_this.htmlTag)) {
|
|
|
_results.push(results[results.length - 1].append(c.children()));
|
|
|
} else {
|
|
|
_results.push(results.push(c));
|
|
|
}
|
|
|
}
|
|
|
return _results;
|
|
|
};
|
|
|
})(this));
|
|
|
_ref = results.reverse();
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
node = _ref[_i];
|
|
|
range.insertNode(node[0]);
|
|
|
}
|
|
|
this.editor.selection.restore();
|
|
|
return this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
|
|
|
BlockquoteButton.prototype._convertEl = function(el) {
|
|
|
var $el, block, results;
|
|
|
$el = $(el);
|
|
|
results = [];
|
|
|
if ($el.is(this.htmlTag)) {
|
|
|
$el.children().each((function(_this) {
|
|
|
return function(i, node) {
|
|
|
return results.push($(node));
|
|
|
};
|
|
|
})(this));
|
|
|
} else {
|
|
|
block = $('<' + this.htmlTag + '/>').append($el);
|
|
|
results.push(block);
|
|
|
}
|
|
|
return results;
|
|
|
};
|
|
|
|
|
|
return BlockquoteButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(BlockquoteButton);
|
|
|
|
|
|
var CodeButton, CodePopover,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
|
__slice = [].slice;
|
|
|
|
|
|
CodeButton = (function(_super) {
|
|
|
__extends(CodeButton, _super);
|
|
|
|
|
|
function CodeButton() {
|
|
|
return CodeButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
CodeButton.prototype.name = 'code';
|
|
|
|
|
|
CodeButton.prototype.icon = 'code';
|
|
|
|
|
|
CodeButton.prototype.htmlTag = 'pre';
|
|
|
|
|
|
CodeButton.prototype.disableTag = 'li, table';
|
|
|
|
|
|
CodeButton.prototype._init = function() {
|
|
|
CodeButton.__super__._init.call(this);
|
|
|
this.editor.on('decorate', (function(_this) {
|
|
|
return function(e, $el) {
|
|
|
return $el.find('pre').each(function(i, pre) {
|
|
|
return _this.decorate($(pre));
|
|
|
});
|
|
|
};
|
|
|
})(this));
|
|
|
return this.editor.on('undecorate', (function(_this) {
|
|
|
return function(e, $el) {
|
|
|
return $el.find('pre').each(function(i, pre) {
|
|
|
return _this.undecorate($(pre));
|
|
|
});
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
CodeButton.prototype.render = function() {
|
|
|
var args;
|
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
|
CodeButton.__super__.render.apply(this, args);
|
|
|
return this.popover = new CodePopover({
|
|
|
button: this
|
|
|
});
|
|
|
};
|
|
|
|
|
|
CodeButton.prototype.status = function($node) {
|
|
|
var result;
|
|
|
result = CodeButton.__super__.status.call(this, $node);
|
|
|
if (this.active) {
|
|
|
this.popover.show($node);
|
|
|
} else if (this.editor.util.isBlockNode($node)) {
|
|
|
this.popover.hide();
|
|
|
}
|
|
|
return result;
|
|
|
};
|
|
|
|
|
|
CodeButton.prototype.decorate = function($pre) {
|
|
|
var lang;
|
|
|
lang = $pre.attr('data-lang');
|
|
|
$pre.removeClass();
|
|
|
if (lang && lang !== -1) {
|
|
|
return $pre.addClass('lang-' + lang);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
CodeButton.prototype.undecorate = function($pre) {
|
|
|
var lang;
|
|
|
lang = $pre.attr('data-lang');
|
|
|
$pre.removeClass();
|
|
|
if (lang && lang !== -1) {
|
|
|
return $pre.addClass('lang-' + lang);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
CodeButton.prototype.command = function() {
|
|
|
var $contents, $endBlock, $startBlock, endNode, node, range, results, startNode, _i, _len, _ref;
|
|
|
range = this.editor.selection.getRange();
|
|
|
startNode = range.startContainer;
|
|
|
endNode = range.endContainer;
|
|
|
$startBlock = this.editor.util.closestBlockEl(startNode);
|
|
|
$endBlock = this.editor.util.closestBlockEl(endNode);
|
|
|
range.setStartBefore($startBlock[0]);
|
|
|
range.setEndAfter($endBlock[0]);
|
|
|
$contents = $(range.extractContents());
|
|
|
results = [];
|
|
|
$contents.children().each((function(_this) {
|
|
|
return function(i, el) {
|
|
|
var c, converted, _i, _len, _results;
|
|
|
converted = _this._convertEl(el);
|
|
|
_results = [];
|
|
|
for (_i = 0, _len = converted.length; _i < _len; _i++) {
|
|
|
c = converted[_i];
|
|
|
if (results.length && results[results.length - 1].is(_this.htmlTag) && c.is(_this.htmlTag)) {
|
|
|
_results.push(results[results.length - 1].append(c.contents()));
|
|
|
} else {
|
|
|
_results.push(results.push(c));
|
|
|
}
|
|
|
}
|
|
|
return _results;
|
|
|
};
|
|
|
})(this));
|
|
|
_ref = results.reverse();
|
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
|
node = _ref[_i];
|
|
|
range.insertNode(node[0]);
|
|
|
}
|
|
|
this.editor.selection.setRangeAtEndOf(results[0]);
|
|
|
return this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
|
|
|
CodeButton.prototype._convertEl = function(el) {
|
|
|
var $el, block, codeStr, results;
|
|
|
$el = $(el);
|
|
|
results = [];
|
|
|
if ($el.is(this.htmlTag)) {
|
|
|
block = $('<p/>').append($el.html().replace('\n', '<br/>'));
|
|
|
results.push(block);
|
|
|
} else {
|
|
|
if (!$el.text() && $el.children().length === 1 && $el.children().is('br')) {
|
|
|
codeStr = '\n';
|
|
|
} else {
|
|
|
codeStr = this.editor.formatter.clearHtml($el);
|
|
|
}
|
|
|
block = $('<' + this.htmlTag + '/>').text(codeStr);
|
|
|
results.push(block);
|
|
|
}
|
|
|
return results;
|
|
|
};
|
|
|
|
|
|
return CodeButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
CodePopover = (function(_super) {
|
|
|
__extends(CodePopover, _super);
|
|
|
|
|
|
function CodePopover() {
|
|
|
return CodePopover.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
CodePopover.prototype._tpl = "<div class=\"code-settings\">\n <div class=\"settings-field\">\n <select class=\"select-lang\">\n <option value=\"-1\">选择程序语言</option>\n <option value=\"bash\">Bash</option>\n <option value=\"c++\">C++</option>\n <option value=\"cs\">C#</option>\n <option value=\"css\">CSS</option>\n <option value=\"erlang\">Erlang</option>\n <option value=\"less\">Less</option>\n <option value=\"scss\">Sass</option>\n <option value=\"diff\">Diff</option>\n <option value=\"coffeeScript\">CoffeeScript</option>\n <option value=\"html\">Html,XML</option>\n <option value=\"json\">JSON</option>\n <option value=\"java\">Java</option>\n <option value=\"js\">JavaScript</option>\n <option value=\"markdown\">Markdown</option>\n <option value=\"oc\">Objective C</option>\n <option value=\"php\">PHP</option>\n <option value=\"perl\">Perl</option>\n <option value=\"python\">Python</option>\n <option value=\"ruby\">Ruby</option>\n <option value=\"sql\">SQL</option>\n </select>\n </div>\n</div>";
|
|
|
|
|
|
CodePopover.prototype.render = function() {
|
|
|
this.el.addClass('code-popover').append(this._tpl);
|
|
|
this.selectEl = this.el.find('.select-lang');
|
|
|
return this.selectEl.on('change', (function(_this) {
|
|
|
return function(e) {
|
|
|
var selected;
|
|
|
_this.lang = _this.selectEl.val();
|
|
|
selected = _this.target.hasClass('selected');
|
|
|
_this.target.removeClass().removeAttr('data-lang');
|
|
|
if (_this.lang !== -1) {
|
|
|
_this.target.addClass('lang-' + _this.lang);
|
|
|
_this.target.attr('data-lang', _this.lang);
|
|
|
}
|
|
|
if (selected) {
|
|
|
return _this.target.addClass('selected');
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
CodePopover.prototype.show = function() {
|
|
|
var args;
|
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
|
CodePopover.__super__.show.apply(this, args);
|
|
|
this.lang = this.target.attr('data-lang');
|
|
|
if (this.lang != null) {
|
|
|
return this.selectEl.val(this.lang);
|
|
|
} else {
|
|
|
return this.selectEl.val(-1);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
return CodePopover;
|
|
|
|
|
|
})(Popover);
|
|
|
|
|
|
Simditor.Toolbar.addButton(CodeButton);
|
|
|
|
|
|
var LinkButton, LinkPopover,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
|
__slice = [].slice;
|
|
|
|
|
|
LinkButton = (function(_super) {
|
|
|
__extends(LinkButton, _super);
|
|
|
|
|
|
function LinkButton() {
|
|
|
return LinkButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
LinkButton.prototype.name = 'link';
|
|
|
|
|
|
LinkButton.prototype.icon = 'link';
|
|
|
|
|
|
LinkButton.prototype.htmlTag = 'a';
|
|
|
|
|
|
LinkButton.prototype.disableTag = 'pre';
|
|
|
|
|
|
LinkButton.prototype.render = function() {
|
|
|
var args;
|
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
|
LinkButton.__super__.render.apply(this, args);
|
|
|
return this.popover = new LinkPopover({
|
|
|
button: this
|
|
|
});
|
|
|
};
|
|
|
|
|
|
LinkButton.prototype.status = function($node) {
|
|
|
var showPopover;
|
|
|
if ($node != null) {
|
|
|
this.setDisabled($node.is(this.disableTag));
|
|
|
}
|
|
|
if (this.disabled) {
|
|
|
return true;
|
|
|
}
|
|
|
if ($node == null) {
|
|
|
return this.active;
|
|
|
}
|
|
|
showPopover = true;
|
|
|
if (!$node.is(this.htmlTag) || $node.is('[class^="simditor-"]')) {
|
|
|
this.setActive(false);
|
|
|
showPopover = false;
|
|
|
} else if (this.editor.selection.rangeAtEndOf($node)) {
|
|
|
this.setActive(true);
|
|
|
showPopover = false;
|
|
|
} else {
|
|
|
this.setActive(true);
|
|
|
}
|
|
|
if (showPopover) {
|
|
|
this.popover.show($node);
|
|
|
} else if (this.editor.util.isBlockNode($node)) {
|
|
|
this.popover.hide();
|
|
|
}
|
|
|
return this.active;
|
|
|
};
|
|
|
|
|
|
LinkButton.prototype.command = function() {
|
|
|
var $contents, $endBlock, $link, $newBlock, $startBlock, endNode, linkText, range, startNode, txtNode;
|
|
|
range = this.editor.selection.getRange();
|
|
|
if (this.active) {
|
|
|
$link = $(range.commonAncestorContainer).closest('a');
|
|
|
txtNode = document.createTextNode($link.text());
|
|
|
$link.replaceWith(txtNode);
|
|
|
range.selectNode(txtNode);
|
|
|
} else {
|
|
|
startNode = range.startContainer;
|
|
|
endNode = range.endContainer;
|
|
|
$startBlock = this.editor.util.closestBlockEl(startNode);
|
|
|
$endBlock = this.editor.util.closestBlockEl(endNode);
|
|
|
$contents = $(range.extractContents());
|
|
|
linkText = this.editor.formatter.clearHtml($contents.contents(), false);
|
|
|
$link = $('<a/>', {
|
|
|
href: 'http://www.example.com',
|
|
|
target: '_blank',
|
|
|
text: linkText || this._t('linkText')
|
|
|
});
|
|
|
if ($startBlock[0] === $endBlock[0]) {
|
|
|
range.insertNode($link[0]);
|
|
|
} else {
|
|
|
$newBlock = $('<p/>').append($link);
|
|
|
range.insertNode($newBlock[0]);
|
|
|
}
|
|
|
range.selectNodeContents($link[0]);
|
|
|
this.popover.one('popovershow', (function(_this) {
|
|
|
return function() {
|
|
|
if (linkText) {
|
|
|
_this.popover.urlEl.focus();
|
|
|
return _this.popover.urlEl[0].select();
|
|
|
} else {
|
|
|
_this.popover.textEl.focus();
|
|
|
return _this.popover.textEl[0].select();
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
}
|
|
|
this.editor.selection.selectRange(range);
|
|
|
return this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
|
|
|
return LinkButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
LinkPopover = (function(_super) {
|
|
|
__extends(LinkPopover, _super);
|
|
|
|
|
|
function LinkPopover() {
|
|
|
return LinkPopover.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
LinkPopover.prototype.render = function() {
|
|
|
var tpl;
|
|
|
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=\"fa fa-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>";
|
|
|
this.el.addClass('link-popover').append(tpl);
|
|
|
this.textEl = this.el.find('.link-text');
|
|
|
this.urlEl = this.el.find('.link-url');
|
|
|
this.unlinkEl = this.el.find('.btn-unlink');
|
|
|
this.textEl.on('keyup', (function(_this) {
|
|
|
return function(e) {
|
|
|
if (e.which === 13) {
|
|
|
return;
|
|
|
}
|
|
|
return _this.target.text(_this.textEl.val());
|
|
|
};
|
|
|
})(this));
|
|
|
this.urlEl.on('keyup', (function(_this) {
|
|
|
return function(e) {
|
|
|
var val;
|
|
|
if (e.which === 13) {
|
|
|
return;
|
|
|
}
|
|
|
val = _this.urlEl.val();
|
|
|
if (!(/https?:\/\/|^\//ig.test(val) || !val)) {
|
|
|
val = 'http://' + val;
|
|
|
}
|
|
|
return _this.target.attr('href', val);
|
|
|
};
|
|
|
})(this));
|
|
|
$([this.urlEl[0], this.textEl[0]]).on('keydown', (function(_this) {
|
|
|
return function(e) {
|
|
|
if (e.which === 13 || e.which === 27 || (!e.shiftKey && e.which === 9 && $(e.target).hasClass('link-url'))) {
|
|
|
e.preventDefault();
|
|
|
return setTimeout(function() {
|
|
|
var range;
|
|
|
range = document.createRange();
|
|
|
_this.editor.selection.setRangeAfter(_this.target, range);
|
|
|
_this.hide();
|
|
|
return _this.editor.trigger('valuechanged');
|
|
|
}, 0);
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
return this.unlinkEl.on('click', (function(_this) {
|
|
|
return function(e) {
|
|
|
var range, txtNode;
|
|
|
txtNode = document.createTextNode(_this.target.text());
|
|
|
_this.target.replaceWith(txtNode);
|
|
|
_this.hide();
|
|
|
range = document.createRange();
|
|
|
_this.editor.selection.setRangeAfter(txtNode, range);
|
|
|
return _this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
LinkPopover.prototype.show = function() {
|
|
|
var args;
|
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
|
LinkPopover.__super__.show.apply(this, args);
|
|
|
this.textEl.val(this.target.text());
|
|
|
return this.urlEl.val(this.target.attr('href'));
|
|
|
};
|
|
|
|
|
|
return LinkPopover;
|
|
|
|
|
|
})(Popover);
|
|
|
|
|
|
Simditor.Toolbar.addButton(LinkButton);
|
|
|
|
|
|
var ImageButton, ImagePopover,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
|
__slice = [].slice;
|
|
|
|
|
|
ImageButton = (function(_super) {
|
|
|
__extends(ImageButton, _super);
|
|
|
|
|
|
function ImageButton() {
|
|
|
return ImageButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
ImageButton.prototype.name = 'image';
|
|
|
|
|
|
ImageButton.prototype.icon = 'picture-o';
|
|
|
|
|
|
ImageButton.prototype.htmlTag = 'img';
|
|
|
|
|
|
ImageButton.prototype.disableTag = 'pre, table';
|
|
|
|
|
|
ImageButton.prototype.defaultImage = '';
|
|
|
|
|
|
ImageButton.prototype.needFocus = false;
|
|
|
|
|
|
ImageButton.prototype._init = function() {
|
|
|
if (this.editor.uploader != null) {
|
|
|
this.menu = [
|
|
|
{
|
|
|
name: 'upload-image',
|
|
|
text: this._t('localImage')
|
|
|
}, {
|
|
|
name: 'external-image',
|
|
|
text: this._t('externalImage')
|
|
|
}
|
|
|
];
|
|
|
} else {
|
|
|
this.menu = false;
|
|
|
}
|
|
|
this.defaultImage = this.editor.opts.defaultImage;
|
|
|
this.editor.body.on('click', 'img:not([data-non-image])', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $img, range;
|
|
|
$img = $(e.currentTarget);
|
|
|
range = document.createRange();
|
|
|
range.selectNode($img[0]);
|
|
|
_this.editor.selection.selectRange(range);
|
|
|
if (!_this.editor.util.supportSelectionChange) {
|
|
|
_this.editor.trigger('selectionchanged');
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.body.on('mouseup', 'img:not([data-non-image])', (function(_this) {
|
|
|
return function(e) {
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('selectionchanged.image', (function(_this) {
|
|
|
return function() {
|
|
|
var $contents, $img, range;
|
|
|
range = _this.editor.selection.getRange();
|
|
|
if (range == null) {
|
|
|
return;
|
|
|
}
|
|
|
$contents = $(range.cloneContents()).contents();
|
|
|
if ($contents.length === 1 && $contents.is('img:not([data-non-image])')) {
|
|
|
$img = $(range.startContainer).contents().eq(range.startOffset);
|
|
|
return _this.popover.show($img);
|
|
|
} else {
|
|
|
return _this.popover.hide();
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('valuechanged.image', (function(_this) {
|
|
|
return function() {
|
|
|
var $masks;
|
|
|
$masks = _this.editor.wrapper.find('.simditor-image-loading');
|
|
|
if (!($masks.length > 0)) {
|
|
|
return;
|
|
|
}
|
|
|
return $masks.each(function(i, mask) {
|
|
|
var $img, $mask, file;
|
|
|
$mask = $(mask);
|
|
|
$img = $mask.data('img');
|
|
|
if (!($img && $img.parent().length > 0)) {
|
|
|
$mask.remove();
|
|
|
if ($img) {
|
|
|
file = $img.data('file');
|
|
|
if (file) {
|
|
|
_this.editor.uploader.cancel(file);
|
|
|
if (_this.editor.body.find('img.uploading').length < 1) {
|
|
|
return _this.editor.uploader.trigger('uploadready', [file]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
})(this));
|
|
|
return ImageButton.__super__._init.call(this);
|
|
|
};
|
|
|
|
|
|
ImageButton.prototype.render = function() {
|
|
|
var args;
|
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
|
ImageButton.__super__.render.apply(this, args);
|
|
|
return this.popover = new ImagePopover({
|
|
|
button: this
|
|
|
});
|
|
|
};
|
|
|
|
|
|
ImageButton.prototype.renderMenu = function() {
|
|
|
var $input, $uploadItem, createInput;
|
|
|
ImageButton.__super__.renderMenu.call(this);
|
|
|
$uploadItem = this.menuEl.find('.menu-item-upload-image');
|
|
|
$input = null;
|
|
|
createInput = (function(_this) {
|
|
|
return function() {
|
|
|
if ($input) {
|
|
|
$input.remove();
|
|
|
}
|
|
|
return $input = $('<input type="file" title="' + _this._t('uploadImage') + '" accept="image/*">').appendTo($uploadItem);
|
|
|
};
|
|
|
})(this);
|
|
|
createInput();
|
|
|
$uploadItem.on('click mousedown', 'input[type=file]', (function(_this) {
|
|
|
return function(e) {
|
|
|
return e.stopPropagation();
|
|
|
};
|
|
|
})(this));
|
|
|
$uploadItem.on('change', 'input[type=file]', (function(_this) {
|
|
|
return function(e) {
|
|
|
if (_this.editor.inputManager.focused) {
|
|
|
_this.editor.uploader.upload($input, {
|
|
|
inline: true
|
|
|
});
|
|
|
createInput();
|
|
|
} else {
|
|
|
_this.editor.one('focus', function(e) {
|
|
|
_this.editor.uploader.upload($input, {
|
|
|
inline: true
|
|
|
});
|
|
|
return createInput();
|
|
|
});
|
|
|
_this.editor.focus();
|
|
|
}
|
|
|
return _this.wrapper.removeClass('menu-on');
|
|
|
};
|
|
|
})(this));
|
|
|
return this._initUploader();
|
|
|
};
|
|
|
|
|
|
ImageButton.prototype._initUploader = function() {
|
|
|
if (this.editor.uploader == null) {
|
|
|
this.el.find('.btn-upload').remove();
|
|
|
return;
|
|
|
}
|
|
|
this.editor.uploader.on('beforeupload', (function(_this) {
|
|
|
return function(e, file) {
|
|
|
var $img;
|
|
|
if (!file.inline) {
|
|
|
return;
|
|
|
}
|
|
|
if (file.img) {
|
|
|
$img = $(file.img);
|
|
|
} else {
|
|
|
$img = _this.createImage(file.name);
|
|
|
file.img = $img;
|
|
|
}
|
|
|
$img.addClass('uploading');
|
|
|
$img.data('file', file);
|
|
|
return _this.editor.uploader.readImageFile(file.obj, function(img) {
|
|
|
var src;
|
|
|
if (!$img.hasClass('uploading')) {
|
|
|
return;
|
|
|
}
|
|
|
src = img ? img.src : _this.defaultImage;
|
|
|
return _this.loadImage($img, src, function() {
|
|
|
if (_this.popover.active) {
|
|
|
_this.popover.refresh();
|
|
|
return _this.popover.srcEl.val(_this._t('uploading')).prop('disabled', true);
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.uploader.on('uploadprogress', (function(_this) {
|
|
|
return function(e, file, loaded, total) {
|
|
|
var $img, $mask, $txt, percent;
|
|
|
if (!file.inline) {
|
|
|
return;
|
|
|
}
|
|
|
percent = loaded / total;
|
|
|
percent = (percent * 100).toFixed(0);
|
|
|
if (percent > 99) {
|
|
|
percent = 99;
|
|
|
}
|
|
|
$mask = file.img.data('mask');
|
|
|
if ($mask) {
|
|
|
$img = $mask.data('img');
|
|
|
$txt = $mask.find('span');
|
|
|
if ($img && $img.parent().length > 0 && percent !== $txt.text()) {
|
|
|
return $txt.text(percent);
|
|
|
} else {
|
|
|
return $mask.remove();
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.uploader.on('uploadsuccess', (function(_this) {
|
|
|
return function(e, file, result) {
|
|
|
var $img, $mask, msg;
|
|
|
if (!file.inline) {
|
|
|
return;
|
|
|
}
|
|
|
$img = file.img;
|
|
|
$img.removeData('file');
|
|
|
$img.removeClass('uploading');
|
|
|
$mask = $img.data('mask');
|
|
|
if ($mask) {
|
|
|
$mask.remove();
|
|
|
}
|
|
|
$img.removeData('mask');
|
|
|
if (result.success === false) {
|
|
|
msg = result.msg || _this._t('uploadFailed');
|
|
|
alert(msg);
|
|
|
$img.attr('src', _this.defaultImage);
|
|
|
} else {
|
|
|
$img.attr('src', result.file_path);
|
|
|
}
|
|
|
if (_this.popover.active) {
|
|
|
_this.popover.srcEl.prop('disabled', false);
|
|
|
_this.popover.srcEl.val(result.file_path);
|
|
|
}
|
|
|
_this.editor.trigger('valuechanged');
|
|
|
if (_this.editor.body.find('img.uploading').length < 1) {
|
|
|
return _this.editor.uploader.trigger('uploadready', [file, result]);
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
return this.editor.uploader.on('uploaderror', (function(_this) {
|
|
|
return function(e, file, xhr) {
|
|
|
var $img, $mask, msg, result;
|
|
|
if (!file.inline) {
|
|
|
return;
|
|
|
}
|
|
|
if (xhr.statusText === 'abort') {
|
|
|
return;
|
|
|
}
|
|
|
if (xhr.responseText) {
|
|
|
try {
|
|
|
result = $.parseJSON(xhr.responseText);
|
|
|
msg = result.msg;
|
|
|
} catch (_error) {
|
|
|
e = _error;
|
|
|
msg = _this._t('uploadError');
|
|
|
}
|
|
|
alert(msg);
|
|
|
}
|
|
|
$img = file.img;
|
|
|
$img.removeData('file');
|
|
|
$img.removeClass('uploading');
|
|
|
$mask = $img.data('mask');
|
|
|
if ($mask) {
|
|
|
$mask.remove();
|
|
|
}
|
|
|
$img.removeData('mask');
|
|
|
$img.attr('src', _this.defaultImage);
|
|
|
if (_this.popover.active) {
|
|
|
_this.popover.srcEl.prop('disabled', false);
|
|
|
_this.popover.srcEl.val(_this.defaultImage);
|
|
|
}
|
|
|
_this.editor.trigger('valuechanged');
|
|
|
if (_this.editor.body.find('img.uploading').length < 1) {
|
|
|
return _this.editor.uploader.trigger('uploadready', [file, result]);
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
ImageButton.prototype.status = function($node) {
|
|
|
if ($node != null) {
|
|
|
this.setDisabled($node.is(this.disableTag));
|
|
|
}
|
|
|
if (this.disabled) {
|
|
|
return true;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
ImageButton.prototype.loadImage = function($img, src, callback) {
|
|
|
var $mask, img;
|
|
|
$mask = $img.data('mask');
|
|
|
if (!$mask) {
|
|
|
$mask = $('<div class="simditor-image-loading"><span></span></div>').hide().appendTo(this.editor.wrapper);
|
|
|
if ($img.hasClass('uploading')) {
|
|
|
$mask.addClass('uploading');
|
|
|
}
|
|
|
$img.data('mask', $mask);
|
|
|
$mask.data('img', $img);
|
|
|
}
|
|
|
img = new Image();
|
|
|
img.onload = (function(_this) {
|
|
|
return function() {
|
|
|
var height, imgOffset, width, wrapperOffset;
|
|
|
if ($mask.hasClass('uploading') && !$img.hasClass('uploading')) {
|
|
|
return;
|
|
|
}
|
|
|
width = img.width;
|
|
|
height = img.height;
|
|
|
$img.attr({
|
|
|
src: src,
|
|
|
'data-image-size': width + ',' + height
|
|
|
});
|
|
|
if ($img.hasClass('uploading')) {
|
|
|
_this.editor.util.reflow(_this.editor.body);
|
|
|
wrapperOffset = _this.editor.wrapper.offset();
|
|
|
imgOffset = $img.offset();
|
|
|
$mask.css({
|
|
|
top: imgOffset.top - wrapperOffset.top,
|
|
|
left: imgOffset.left - wrapperOffset.left,
|
|
|
width: $img.width(),
|
|
|
height: $img.height()
|
|
|
}).show();
|
|
|
} else {
|
|
|
$mask.remove();
|
|
|
$img.removeData('mask');
|
|
|
}
|
|
|
return callback(img);
|
|
|
};
|
|
|
})(this);
|
|
|
img.onerror = (function(_this) {
|
|
|
return function() {
|
|
|
callback(false);
|
|
|
$mask.remove();
|
|
|
return $img.removeData('mask');
|
|
|
};
|
|
|
})(this);
|
|
|
return img.src = src;
|
|
|
};
|
|
|
|
|
|
ImageButton.prototype.createImage = function(name) {
|
|
|
var $block, $img, $nextBlock, range;
|
|
|
if (name == null) {
|
|
|
name = 'Image';
|
|
|
}
|
|
|
if (!this.editor.inputManager.focused) {
|
|
|
this.editor.focus();
|
|
|
}
|
|
|
range = this.editor.selection.getRange();
|
|
|
range.deleteContents();
|
|
|
$block = this.editor.util.closestBlockEl();
|
|
|
if ($block.is('p') && !this.editor.util.isEmptyNode($block)) {
|
|
|
$block = $('<p/>').append(this.editor.util.phBr).insertAfter($block);
|
|
|
this.editor.selection.setRangeAtStartOf($block, range);
|
|
|
}
|
|
|
$img = $('<img/>').attr('alt', name);
|
|
|
range.insertNode($img[0]);
|
|
|
$nextBlock = $block.next('p');
|
|
|
if (!($nextBlock.length > 0)) {
|
|
|
$nextBlock = $('<p/>').append(this.editor.util.phBr).insertAfter($block);
|
|
|
}
|
|
|
this.editor.selection.setRangeAtStartOf($nextBlock);
|
|
|
return $img;
|
|
|
};
|
|
|
|
|
|
ImageButton.prototype.command = function(src) {
|
|
|
var $img;
|
|
|
$img = this.createImage();
|
|
|
return this.loadImage($img, src || this.defaultImage, (function(_this) {
|
|
|
return function() {
|
|
|
_this.editor.trigger('valuechanged');
|
|
|
_this.editor.util.reflow($img);
|
|
|
$img.click();
|
|
|
return _this.popover.one('popovershow', function() {
|
|
|
_this.popover.srcEl.focus();
|
|
|
return _this.popover.srcEl[0].select();
|
|
|
});
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
return ImageButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
ImagePopover = (function(_super) {
|
|
|
__extends(ImagePopover, _super);
|
|
|
|
|
|
function ImagePopover() {
|
|
|
return ImagePopover.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
ImagePopover.prototype.offset = {
|
|
|
top: 6,
|
|
|
left: -4
|
|
|
};
|
|
|
|
|
|
ImagePopover.prototype.render = function() {
|
|
|
var tpl;
|
|
|
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=\"fa fa-upload\"></span>\n </a>\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=\"fa fa-reply\"></span>\n </a>\n </div>\n</div>";
|
|
|
this.el.addClass('image-popover').append(tpl);
|
|
|
this.srcEl = this.el.find('.image-src');
|
|
|
this.srcEl.on('keydown', (function(_this) {
|
|
|
return function(e) {
|
|
|
var hideAndFocus, src;
|
|
|
if (!(e.which === 13 || e.which === 27)) {
|
|
|
return;
|
|
|
}
|
|
|
e.preventDefault();
|
|
|
hideAndFocus = function() {
|
|
|
_this.button.editor.body.focus();
|
|
|
_this.button.editor.selection.setRangeAfter(_this.target);
|
|
|
return _this.hide();
|
|
|
};
|
|
|
if (e.which === 13 && !_this.target.hasClass('uploading')) {
|
|
|
src = _this.srcEl.val();
|
|
|
if (/^data:image/.test(src) && !_this.editor.uploader) {
|
|
|
hideAndFocus();
|
|
|
return;
|
|
|
}
|
|
|
return _this.button.loadImage(_this.target, src, function(success) {
|
|
|
var blob;
|
|
|
if (!success) {
|
|
|
return;
|
|
|
}
|
|
|
if (/^data:image/.test(src)) {
|
|
|
blob = _this.editor.util.dataURLtoBlob(src);
|
|
|
blob.name = "Base64 Image.png";
|
|
|
return _this.editor.uploader.upload(blob, {
|
|
|
inline: true,
|
|
|
img: _this.target
|
|
|
});
|
|
|
} else {
|
|
|
hideAndFocus();
|
|
|
return _this.editor.trigger('valuechanged');
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
return hideAndFocus();
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
this.widthEl = this.el.find('#image-width');
|
|
|
this.heightEl = this.el.find('#image-height');
|
|
|
this.el.find('.image-size').on('blur', (function(_this) {
|
|
|
return function(e) {
|
|
|
_this._resizeImg($(e.currentTarget));
|
|
|
return _this.el.data('popover').refresh();
|
|
|
};
|
|
|
})(this));
|
|
|
this.el.find('.image-size').on('keyup', (function(_this) {
|
|
|
return function(e) {
|
|
|
var inputEl;
|
|
|
inputEl = $(e.currentTarget);
|
|
|
if (!(e.which === 13 || e.which === 27 || e.which === 9)) {
|
|
|
return _this._resizeImg(inputEl, true);
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
this.el.find('.image-size').on('keydown', (function(_this) {
|
|
|
return function(e) {
|
|
|
var inputEl;
|
|
|
inputEl = $(e.currentTarget);
|
|
|
if (e.which === 13 || e.which === 27) {
|
|
|
e.preventDefault();
|
|
|
if (e.which === 13) {
|
|
|
_this._resizeImg(inputEl);
|
|
|
} else {
|
|
|
_this._restoreImg();
|
|
|
}
|
|
|
_this.button.editor.body.focus();
|
|
|
_this.button.editor.selection.setRangeAfter(_this.target);
|
|
|
return _this.hide();
|
|
|
} else if (e.which === 9) {
|
|
|
return _this.el.data('popover').refresh();
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
this.el.find('.btn-restore').on('click', (function(_this) {
|
|
|
return function(e) {
|
|
|
_this._restoreImg();
|
|
|
return _this.el.data('popover').refresh();
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('valuechanged', (function(_this) {
|
|
|
return function(e) {
|
|
|
if (_this.active) {
|
|
|
return _this.refresh();
|
|
|
}
|
|
|
};
|
|
|
})(this));
|
|
|
return this._initUploader();
|
|
|
};
|
|
|
|
|
|
ImagePopover.prototype._initUploader = function() {
|
|
|
var $uploadBtn, createInput;
|
|
|
$uploadBtn = this.el.find('.btn-upload');
|
|
|
if (this.editor.uploader == null) {
|
|
|
$uploadBtn.remove();
|
|
|
return;
|
|
|
}
|
|
|
createInput = (function(_this) {
|
|
|
return function() {
|
|
|
if (_this.input) {
|
|
|
_this.input.remove();
|
|
|
}
|
|
|
return _this.input = $('<input type="file" title="' + _this._t('uploadImage') + '" accept="image/*">').appendTo($uploadBtn);
|
|
|
};
|
|
|
})(this);
|
|
|
createInput();
|
|
|
this.el.on('click mousedown', 'input[type=file]', (function(_this) {
|
|
|
return function(e) {
|
|
|
return e.stopPropagation();
|
|
|
};
|
|
|
})(this));
|
|
|
return this.el.on('change', 'input[type=file]', (function(_this) {
|
|
|
return function(e) {
|
|
|
_this.editor.uploader.upload(_this.input, {
|
|
|
inline: true,
|
|
|
img: _this.target
|
|
|
});
|
|
|
return createInput();
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
ImagePopover.prototype._resizeImg = function(inputEl, onlySetVal) {
|
|
|
var height, value, width;
|
|
|
if (onlySetVal == null) {
|
|
|
onlySetVal = false;
|
|
|
}
|
|
|
value = inputEl.val() * 1;
|
|
|
if (!($.isNumeric(value) || value < 0)) {
|
|
|
return;
|
|
|
}
|
|
|
if (inputEl.is(this.widthEl)) {
|
|
|
height = this.height * value / this.width;
|
|
|
this.heightEl.val(height);
|
|
|
} else {
|
|
|
width = this.width * value / this.height;
|
|
|
this.widthEl.val(width);
|
|
|
}
|
|
|
if (!onlySetVal) {
|
|
|
return this.target.attr({
|
|
|
width: width || value,
|
|
|
height: height || value
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
|
|
|
ImagePopover.prototype._restoreImg = function() {
|
|
|
var size, _ref;
|
|
|
size = ((_ref = this.target.data('image-size')) != null ? _ref.split(",") : void 0) || [this.width, this.height];
|
|
|
this.target.attr({
|
|
|
width: size[0] * 1,
|
|
|
height: size[1] * 1
|
|
|
});
|
|
|
this.widthEl.val(size[0]);
|
|
|
return this.heightEl.val(size[1]);
|
|
|
};
|
|
|
|
|
|
ImagePopover.prototype.show = function() {
|
|
|
var $img, args;
|
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
|
ImagePopover.__super__.show.apply(this, args);
|
|
|
$img = this.target;
|
|
|
this.width = $img.width();
|
|
|
this.height = $img.height();
|
|
|
if ($img.hasClass('uploading')) {
|
|
|
return this.srcEl.val(this._t('uploading')).prop('disabled', true);
|
|
|
} else {
|
|
|
this.srcEl.val($img.attr('src')).prop('disabled', false);
|
|
|
this.widthEl.val(this.width);
|
|
|
return this.heightEl.val(this.height);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
return ImagePopover;
|
|
|
|
|
|
})(Popover);
|
|
|
|
|
|
Simditor.Toolbar.addButton(ImageButton);
|
|
|
|
|
|
var IndentButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
IndentButton = (function(_super) {
|
|
|
__extends(IndentButton, _super);
|
|
|
|
|
|
function IndentButton() {
|
|
|
return IndentButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
IndentButton.prototype.name = 'indent';
|
|
|
|
|
|
IndentButton.prototype.icon = 'indent';
|
|
|
|
|
|
IndentButton.prototype._init = function() {
|
|
|
this.title = this._t(this.name) + ' (Tab)';
|
|
|
return IndentButton.__super__._init.call(this);
|
|
|
};
|
|
|
|
|
|
IndentButton.prototype.status = function($node) {
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
IndentButton.prototype.command = function() {
|
|
|
return this.editor.util.indent();
|
|
|
};
|
|
|
|
|
|
return IndentButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(IndentButton);
|
|
|
|
|
|
var OutdentButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
OutdentButton = (function(_super) {
|
|
|
__extends(OutdentButton, _super);
|
|
|
|
|
|
function OutdentButton() {
|
|
|
return OutdentButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
OutdentButton.prototype.name = 'outdent';
|
|
|
|
|
|
OutdentButton.prototype.icon = 'outdent';
|
|
|
|
|
|
OutdentButton.prototype._init = function() {
|
|
|
this.title = this._t(this.name) + ' (Shift + Tab)';
|
|
|
return OutdentButton.__super__._init.call(this);
|
|
|
};
|
|
|
|
|
|
OutdentButton.prototype.status = function($node) {
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
OutdentButton.prototype.command = function() {
|
|
|
return this.editor.util.outdent();
|
|
|
};
|
|
|
|
|
|
return OutdentButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(OutdentButton);
|
|
|
|
|
|
var HrButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
HrButton = (function(_super) {
|
|
|
__extends(HrButton, _super);
|
|
|
|
|
|
function HrButton() {
|
|
|
return HrButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
HrButton.prototype.name = 'hr';
|
|
|
|
|
|
HrButton.prototype.icon = 'minus';
|
|
|
|
|
|
HrButton.prototype.htmlTag = 'hr';
|
|
|
|
|
|
HrButton.prototype.status = function($node) {
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
HrButton.prototype.command = function() {
|
|
|
var $hr, $newBlock, $nextBlock, $rootBlock;
|
|
|
$rootBlock = this.editor.util.furthestBlockEl();
|
|
|
$nextBlock = $rootBlock.next();
|
|
|
if ($nextBlock.length > 0) {
|
|
|
this.editor.selection.save();
|
|
|
} else {
|
|
|
$newBlock = $('<p/>').append(this.editor.util.phBr);
|
|
|
}
|
|
|
$hr = $('<hr/>').insertAfter($rootBlock);
|
|
|
if ($newBlock) {
|
|
|
$newBlock.insertAfter($hr);
|
|
|
this.editor.selection.setRangeAtStartOf($newBlock);
|
|
|
} else {
|
|
|
this.editor.selection.restore();
|
|
|
}
|
|
|
return this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
|
|
|
return HrButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(HrButton);
|
|
|
|
|
|
var TableButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
TableButton = (function(_super) {
|
|
|
__extends(TableButton, _super);
|
|
|
|
|
|
function TableButton() {
|
|
|
return TableButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
TableButton.prototype.name = 'table';
|
|
|
|
|
|
TableButton.prototype.icon = 'table';
|
|
|
|
|
|
TableButton.prototype.htmlTag = 'table';
|
|
|
|
|
|
TableButton.prototype.disableTag = 'pre, li, blockquote';
|
|
|
|
|
|
TableButton.prototype.menu = true;
|
|
|
|
|
|
TableButton.prototype._init = function() {
|
|
|
TableButton.__super__._init.call(this);
|
|
|
$.merge(this.editor.formatter._allowedTags, ['tbody', 'tr', 'td', 'colgroup', 'col']);
|
|
|
$.extend(this.editor.formatter._allowedAttributes, {
|
|
|
td: ['rowspan', 'colspan'],
|
|
|
col: ['width']
|
|
|
});
|
|
|
this._initShortcuts();
|
|
|
this.editor.on('decorate', (function(_this) {
|
|
|
return function(e, $el) {
|
|
|
return $el.find('table').each(function(i, table) {
|
|
|
return _this.decorate($(table));
|
|
|
});
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('undecorate', (function(_this) {
|
|
|
return function(e, $el) {
|
|
|
return $el.find('table').each(function(i, table) {
|
|
|
return _this.undecorate($(table));
|
|
|
});
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('selectionchanged.table', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $container, range;
|
|
|
_this.editor.body.find('.simditor-table td').removeClass('active');
|
|
|
range = _this.editor.selection.getRange();
|
|
|
if (range == null) {
|
|
|
return;
|
|
|
}
|
|
|
$container = $(range.commonAncestorContainer);
|
|
|
if (range.collapsed && $container.is('.simditor-table')) {
|
|
|
if (_this.editor.selection.rangeAtStartOf($container)) {
|
|
|
$container = $container.find('td:first');
|
|
|
} else {
|
|
|
$container = $container.find('td:last');
|
|
|
}
|
|
|
_this.editor.selection.setRangeAtEndOf($container);
|
|
|
}
|
|
|
return $container.closest('td', _this.editor.body).addClass('active');
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.on('blur.table', (function(_this) {
|
|
|
return function(e) {
|
|
|
return _this.editor.body.find('.simditor-table td').removeClass('active');
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addKeystrokeHandler('38', 'td', (function(_this) {
|
|
|
return function(e, $node) {
|
|
|
var $prevTr, $tr, index;
|
|
|
$tr = $node.parent('tr');
|
|
|
$prevTr = $tr.prev('tr');
|
|
|
if (!($prevTr.length > 0)) {
|
|
|
return true;
|
|
|
}
|
|
|
index = $tr.find('td').index($node);
|
|
|
_this.editor.selection.setRangeAtEndOf($prevTr.find('td').eq(index));
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
return this.editor.inputManager.addKeystrokeHandler('40', 'td', (function(_this) {
|
|
|
return function(e, $node) {
|
|
|
var $nextTr, $tr, index;
|
|
|
$tr = $node.parent('tr');
|
|
|
$nextTr = $tr.next('tr');
|
|
|
if (!($nextTr.length > 0)) {
|
|
|
return true;
|
|
|
}
|
|
|
index = $tr.find('td').index($node);
|
|
|
_this.editor.selection.setRangeAtEndOf($nextTr.find('td').eq(index));
|
|
|
return true;
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.initResize = function($table) {
|
|
|
var $colgroup, $resizeHandle, $wrapper;
|
|
|
$wrapper = $table.parent('.simditor-table');
|
|
|
$colgroup = $table.find('colgroup');
|
|
|
if ($colgroup.length < 1) {
|
|
|
$colgroup = $('<colgroup/>').prependTo($table);
|
|
|
$table.find('tr:first td').each((function(_this) {
|
|
|
return function(i, td) {
|
|
|
var $col;
|
|
|
return $col = $('<col/>').appendTo($colgroup);
|
|
|
};
|
|
|
})(this));
|
|
|
this.refreshTableWidth($table);
|
|
|
}
|
|
|
$resizeHandle = $('<div class="simditor-resize-handle" contenteditable="false"></div>').appendTo($wrapper);
|
|
|
$wrapper.on('mousemove', 'td', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $col, $td, index, x, _ref, _ref1;
|
|
|
if ($wrapper.hasClass('resizing')) {
|
|
|
return;
|
|
|
}
|
|
|
$td = $(e.currentTarget);
|
|
|
x = e.pageX - $(e.currentTarget).offset().left;
|
|
|
if (x < 5 && $td.prev().length > 0) {
|
|
|
$td = $td.prev();
|
|
|
}
|
|
|
if ($td.next('td').length < 1) {
|
|
|
$resizeHandle.hide();
|
|
|
return;
|
|
|
}
|
|
|
if ((_ref = $resizeHandle.data('td')) != null ? _ref.is($td) : void 0) {
|
|
|
$resizeHandle.show();
|
|
|
return;
|
|
|
}
|
|
|
index = $td.parent().find('td').index($td);
|
|
|
$col = $colgroup.find('col').eq(index);
|
|
|
if ((_ref1 = $resizeHandle.data('col')) != null ? _ref1.is($col) : void 0) {
|
|
|
$resizeHandle.show();
|
|
|
return;
|
|
|
}
|
|
|
return $resizeHandle.css('left', $td.position().left + $td.outerWidth() - 5).data('td', $td).data('col', $col).show();
|
|
|
};
|
|
|
})(this));
|
|
|
$wrapper.on('mouseleave', (function(_this) {
|
|
|
return function(e) {
|
|
|
return $resizeHandle.hide();
|
|
|
};
|
|
|
})(this));
|
|
|
return $wrapper.on('mousedown', '.simditor-resize-handle', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $handle, $leftCol, $leftTd, $rightCol, $rightTd, minWidth, startHandleLeft, startLeftWidth, startRightWidth, startX, tableWidth;
|
|
|
$handle = $(e.currentTarget);
|
|
|
$leftTd = $handle.data('td');
|
|
|
$leftCol = $handle.data('col');
|
|
|
$rightTd = $leftTd.next('td');
|
|
|
$rightCol = $leftCol.next('col');
|
|
|
startX = e.pageX;
|
|
|
startLeftWidth = $leftTd.outerWidth() * 1;
|
|
|
startRightWidth = $rightTd.outerWidth() * 1;
|
|
|
startHandleLeft = parseFloat($handle.css('left'));
|
|
|
tableWidth = $leftTd.closest('table').width();
|
|
|
minWidth = 50;
|
|
|
$(document).on('mousemove.simditor-resize-table', function(e) {
|
|
|
var deltaX, leftWidth, rightWidth;
|
|
|
deltaX = e.pageX - startX;
|
|
|
leftWidth = startLeftWidth + deltaX;
|
|
|
rightWidth = startRightWidth - deltaX;
|
|
|
if (leftWidth < minWidth) {
|
|
|
leftWidth = minWidth;
|
|
|
deltaX = minWidth - startLeftWidth;
|
|
|
rightWidth = startRightWidth - deltaX;
|
|
|
} else if (rightWidth < minWidth) {
|
|
|
rightWidth = minWidth;
|
|
|
deltaX = startRightWidth - minWidth;
|
|
|
leftWidth = startLeftWidth + deltaX;
|
|
|
}
|
|
|
$leftCol.attr('width', (leftWidth / tableWidth * 100) + '%');
|
|
|
$rightCol.attr('width', (rightWidth / tableWidth * 100) + '%');
|
|
|
return $handle.css('left', startHandleLeft + deltaX);
|
|
|
});
|
|
|
$(document).one('mouseup.simditor-resize-table', function(e) {
|
|
|
$(document).off('.simditor-resize-table');
|
|
|
return $wrapper.removeClass('resizing');
|
|
|
});
|
|
|
$wrapper.addClass('resizing');
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
TableButton.prototype._initShortcuts = function() {
|
|
|
this.editor.inputManager.addShortcut('ctrl+alt+up', (function(_this) {
|
|
|
return function(e) {
|
|
|
_this.editMenu.find('.menu-item[data-param=insertRowAbove]').click();
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addShortcut('ctrl+alt+down', (function(_this) {
|
|
|
return function(e) {
|
|
|
_this.editMenu.find('.menu-item[data-param=insertRowBelow]').click();
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
this.editor.inputManager.addShortcut('ctrl+alt+left', (function(_this) {
|
|
|
return function(e) {
|
|
|
_this.editMenu.find('.menu-item[data-param=insertColLeft]').click();
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
return this.editor.inputManager.addShortcut('ctrl+alt+right', (function(_this) {
|
|
|
return function(e) {
|
|
|
_this.editMenu.find('.menu-item[data-param=insertColRight]').click();
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.decorate = function($table) {
|
|
|
if ($table.parent('.simditor-table').length > 0) {
|
|
|
this.undecorate($table);
|
|
|
}
|
|
|
$table.wrap('<div class="simditor-table"></div>');
|
|
|
this.initResize($table);
|
|
|
return $table.parent();
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.undecorate = function($table) {
|
|
|
if (!($table.parent('.simditor-table').length > 0)) {
|
|
|
return;
|
|
|
}
|
|
|
return $table.parent().replaceWith($table);
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.renderMenu = function() {
|
|
|
$("<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')) + " ( Ctrl + Alt + → )</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);
|
|
|
this.createMenu = this.menuWrapper.find('.menu-create-table');
|
|
|
this.editMenu = this.menuWrapper.find('.menu-edit-table');
|
|
|
this.createTable(6, 6).appendTo(this.createMenu);
|
|
|
this.createMenu.on('mouseenter', 'td', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $td, $tr, num;
|
|
|
_this.createMenu.find('td').removeClass('selected');
|
|
|
$td = $(e.currentTarget);
|
|
|
$tr = $td.parent();
|
|
|
num = $tr.find('td').index($td) + 1;
|
|
|
return $tr.prevAll('tr').addBack().find('td:lt(' + num + ')').addClass('selected');
|
|
|
};
|
|
|
})(this));
|
|
|
this.createMenu.on('mouseleave', (function(_this) {
|
|
|
return function(e) {
|
|
|
return $(e.currentTarget).find('td').removeClass('selected');
|
|
|
};
|
|
|
})(this));
|
|
|
return this.createMenu.on('mousedown', 'td', (function(_this) {
|
|
|
return function(e) {
|
|
|
var $closestBlock, $table, $td, $tr, colNum, rowNum;
|
|
|
_this.wrapper.removeClass('menu-on');
|
|
|
if (!_this.editor.inputManager.focused) {
|
|
|
return;
|
|
|
}
|
|
|
$td = $(e.currentTarget);
|
|
|
$tr = $td.parent();
|
|
|
colNum = $tr.find('td').index($td) + 1;
|
|
|
rowNum = $tr.prevAll('tr').length + 1;
|
|
|
$table = _this.createTable(rowNum, colNum, true);
|
|
|
$closestBlock = _this.editor.util.closestBlockEl();
|
|
|
if (_this.editor.util.isEmptyNode($closestBlock)) {
|
|
|
$closestBlock.replaceWith($table);
|
|
|
} else {
|
|
|
$closestBlock.after($table);
|
|
|
}
|
|
|
_this.decorate($table);
|
|
|
_this.editor.selection.setRangeAtStartOf($table.find('td:first'));
|
|
|
_this.editor.trigger('valuechanged');
|
|
|
return false;
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.createTable = function(row, col, phBr) {
|
|
|
var $table, $tbody, $td, $tr, c, r, _i, _j;
|
|
|
$table = $('<table/>');
|
|
|
$tbody = $('<tbody/>').appendTo($table);
|
|
|
for (r = _i = 0; 0 <= row ? _i < row : _i > row; r = 0 <= row ? ++_i : --_i) {
|
|
|
$tr = $('<tr/>').appendTo($tbody);
|
|
|
for (c = _j = 0; 0 <= col ? _j < col : _j > col; c = 0 <= col ? ++_j : --_j) {
|
|
|
$td = $('<td/>').appendTo($tr);
|
|
|
if (phBr) {
|
|
|
$td.append(this.editor.util.phBr);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return $table;
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.refreshTableWidth = function($table) {
|
|
|
var cols, tableWidth;
|
|
|
tableWidth = $table.width();
|
|
|
cols = $table.find('col');
|
|
|
return $table.find('tr:first td').each((function(_this) {
|
|
|
return function(i, td) {
|
|
|
var $col;
|
|
|
$col = cols.eq(i);
|
|
|
return $col.attr('width', ($(td).outerWidth() / tableWidth * 100) + '%');
|
|
|
};
|
|
|
})(this));
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.setActive = function(active) {
|
|
|
TableButton.__super__.setActive.call(this, active);
|
|
|
if (active) {
|
|
|
this.createMenu.hide();
|
|
|
return this.editMenu.show();
|
|
|
} else {
|
|
|
this.createMenu.show();
|
|
|
return this.editMenu.hide();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.deleteRow = function($td) {
|
|
|
var $newTr, $tr, index;
|
|
|
$tr = $td.parent('tr');
|
|
|
if ($tr.siblings('tr').length < 1) {
|
|
|
return this.deleteTable($td);
|
|
|
} else {
|
|
|
$newTr = $tr.next('tr');
|
|
|
if (!($newTr.length > 0)) {
|
|
|
$newTr = $tr.prev('tr');
|
|
|
}
|
|
|
index = $tr.find('td').index($td);
|
|
|
$tr.remove();
|
|
|
return this.editor.selection.setRangeAtEndOf($newTr.find('td').eq(index));
|
|
|
}
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.insertRow = function($td, direction) {
|
|
|
var $newTr, $table, $tr, colNum, i, index, _i;
|
|
|
if (direction == null) {
|
|
|
direction = 'after';
|
|
|
}
|
|
|
$tr = $td.parent('tr');
|
|
|
$table = $tr.closest('table');
|
|
|
colNum = 0;
|
|
|
$table.find('tr').each((function(_this) {
|
|
|
return function(i, tr) {
|
|
|
return colNum = Math.max(colNum, $(tr).find('td').length);
|
|
|
};
|
|
|
})(this));
|
|
|
$newTr = $('<tr/>');
|
|
|
for (i = _i = 1; 1 <= colNum ? _i <= colNum : _i >= colNum; i = 1 <= colNum ? ++_i : --_i) {
|
|
|
$('<td/>').append(this.editor.util.phBr).appendTo($newTr);
|
|
|
}
|
|
|
$tr[direction]($newTr);
|
|
|
index = $tr.find('td').index($td);
|
|
|
return this.editor.selection.setRangeAtStartOf($newTr.find('td').eq(index));
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.deleteCol = function($td) {
|
|
|
var $newTd, $table, $tr, index;
|
|
|
$tr = $td.parent('tr');
|
|
|
if ($tr.siblings('tr').length < 1 && $td.siblings('td').length < 1) {
|
|
|
return this.deleteTable($td);
|
|
|
} else {
|
|
|
index = $tr.find('td').index($td);
|
|
|
$newTd = $td.next('td');
|
|
|
if (!($newTd.length > 0)) {
|
|
|
$newTd = $tr.prev('td');
|
|
|
}
|
|
|
$table = $tr.closest('table');
|
|
|
$table.find('col').eq(index).remove();
|
|
|
$table.find('tr').each((function(_this) {
|
|
|
return function(i, tr) {
|
|
|
return $(tr).find('td').eq(index).remove();
|
|
|
};
|
|
|
})(this));
|
|
|
this.refreshTableWidth($table);
|
|
|
return this.editor.selection.setRangeAtEndOf($newTd);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.insertCol = function($td, direction) {
|
|
|
var $col, $newCol, $newTd, $table, $tr, index, tableWidth, width;
|
|
|
if (direction == null) {
|
|
|
direction = 'after';
|
|
|
}
|
|
|
$tr = $td.parent('tr');
|
|
|
index = $tr.find('td').index($td);
|
|
|
$table = $td.closest('table');
|
|
|
$col = $table.find('col').eq(index);
|
|
|
$table.find('tr').each((function(_this) {
|
|
|
return function(i, tr) {
|
|
|
var $newTd;
|
|
|
$newTd = $('<td/>').append(_this.editor.util.phBr);
|
|
|
return $(tr).find('td').eq(index)[direction]($newTd);
|
|
|
};
|
|
|
})(this));
|
|
|
$newCol = $('<col/>');
|
|
|
$col[direction]($newCol);
|
|
|
tableWidth = $table.width();
|
|
|
width = Math.max(parseFloat($col.attr('width')) / 2, 50 / tableWidth * 100);
|
|
|
$col.attr('width', width + '%');
|
|
|
$newCol.attr('width', width + '%');
|
|
|
this.refreshTableWidth($table);
|
|
|
$newTd = direction === 'after' ? $td.next('td') : $td.prev('td');
|
|
|
return this.editor.selection.setRangeAtStartOf($newTd);
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.deleteTable = function($td) {
|
|
|
var $block, $table;
|
|
|
$table = $td.closest('.simditor-table');
|
|
|
$block = $table.next('p');
|
|
|
$table.remove();
|
|
|
if ($block.length > 0) {
|
|
|
return this.editor.selection.setRangeAtStartOf($block);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
TableButton.prototype.command = function(param) {
|
|
|
var $td, range;
|
|
|
range = this.editor.selection.getRange();
|
|
|
$td = $(range.commonAncestorContainer).closest('td');
|
|
|
if (!($td.length > 0)) {
|
|
|
return;
|
|
|
}
|
|
|
if (param === 'deleteRow') {
|
|
|
this.deleteRow($td);
|
|
|
} else if (param === 'insertRowAbove') {
|
|
|
this.insertRow($td, 'before');
|
|
|
} else if (param === 'insertRowBelow') {
|
|
|
this.insertRow($td);
|
|
|
} else if (param === 'deleteCol') {
|
|
|
this.deleteCol($td);
|
|
|
} else if (param === 'insertColLeft') {
|
|
|
this.insertCol($td, 'before');
|
|
|
} else if (param === 'insertColRight') {
|
|
|
this.insertCol($td);
|
|
|
} else if (param === 'deleteTable') {
|
|
|
this.deleteTable($td);
|
|
|
} else {
|
|
|
return;
|
|
|
}
|
|
|
return this.editor.trigger('valuechanged');
|
|
|
};
|
|
|
|
|
|
return TableButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(TableButton);
|
|
|
|
|
|
var StrikethroughButton,
|
|
|
__hasProp = {}.hasOwnProperty,
|
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
|
|
|
|
StrikethroughButton = (function(_super) {
|
|
|
__extends(StrikethroughButton, _super);
|
|
|
|
|
|
function StrikethroughButton() {
|
|
|
return StrikethroughButton.__super__.constructor.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
StrikethroughButton.prototype.name = 'strikethrough';
|
|
|
|
|
|
StrikethroughButton.prototype.icon = 'strikethrough';
|
|
|
|
|
|
StrikethroughButton.prototype.htmlTag = 'strike';
|
|
|
|
|
|
StrikethroughButton.prototype.disableTag = 'pre';
|
|
|
|
|
|
StrikethroughButton.prototype.status = function($node) {
|
|
|
var active;
|
|
|
if ($node != null) {
|
|
|
this.setDisabled($node.is(this.disableTag));
|
|
|
}
|
|
|
if (this.disabled) {
|
|
|
return true;
|
|
|
}
|
|
|
active = document.queryCommandState('strikethrough') === true;
|
|
|
this.setActive(active);
|
|
|
return active;
|
|
|
};
|
|
|
|
|
|
StrikethroughButton.prototype.command = function() {
|
|
|
document.execCommand('strikethrough');
|
|
|
this.editor.trigger('valuechanged');
|
|
|
return $(document).trigger('selectionchange');
|
|
|
};
|
|
|
|
|
|
return StrikethroughButton;
|
|
|
|
|
|
})(Button);
|
|
|
|
|
|
Simditor.Toolbar.addButton(StrikethroughButton);
|
|
|
|
|
|
return Simditor;
|
|
|
|
|
|
}));
|