vendor/assets/javascripts/simditor/simditor.js in simditor-2.1.13.0 vs vendor/assets/javascripts/simditor/simditor.js in simditor-2.1.14

- old
+ new

@@ -1,9 +1,9 @@ /*! * Simditor v2.1.13 * http://simditor.tower.im/ -* 2015-09-06 +* 2015-06-23 */ (function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module unless amdModuleId is set define('simditor', ["jquery","simple-module","simple-hotkeys","simple-uploader"], function ($, SimpleModule, simpleHotkeys, simpleUploader) { @@ -322,26 +322,25 @@ Formatter.prototype._init = function() { this.editor = this._module; this._allowedTags = this.opts.allowedTags || ['br', 'a', 'img', 'b', 'strong', 'i', 'u', 'font', 'p', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'h1', 'h2', 'h3', 'h4', 'hr']; this._allowedAttributes = this.opts.allowedAttributes || { - img: ['src', 'alt', 'width', 'height', 'data-image-src', 'data-image-size', 'data-image-name', 'data-non-image'], + img: ['src', 'alt', 'width', 'height', 'data-non-image'], a: ['href', 'target'], font: ['color'], - pre: ['data-lang'], - code: ['class'], - p: ['data-indent', 'data-align'], - h1: ['data-indent'], - h2: ['data-indent'], - h3: ['data-indent'], - h4: ['data-indent'] + code: ['class'] }; - return this.editor.body.on('click', 'a', (function(_this) { - return function(e) { - return false; - }; - })(this)); + this._allowedStyles = this.opts.allowedStyles || { + p: ['margin-left', 'text-align'], + h1: ['margin-left'], + h2: ['margin-left'], + h3: ['margin-left'], + h4: ['margin-left'] + }; + return this.editor.body.on('click', 'a', function(e) { + return false; + }); }; Formatter.prototype.decorate = function($el) { if ($el == null) { $el = this.editor.body; @@ -356,11 +355,11 @@ this.editor.trigger('undecorate', [$el]); return $.trim($el.html()); }; Formatter.prototype.autolink = function($el) { - var $node, findLinkNode, j, lastIndex, len, linkNodes, match, re, replaceEls, text, uri; + var $link, $node, findLinkNode, j, lastIndex, len, linkNodes, match, re, replaceEls, subStr, text, uri; if ($el == null) { $el = this.editor.body; } linkNodes = []; findLinkNode = function($parentNode) { @@ -384,14 +383,16 @@ text = $node.text(); replaceEls = []; match = null; lastIndex = 0; while ((match = re.exec(text)) !== null) { - replaceEls.push(document.createTextNode(text.substring(lastIndex, match.index))); + subStr = text.substring(lastIndex, match.index); + replaceEls.push(document.createTextNode(subStr)); 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]); + $link = $("<a href=\"" + uri + "\" rel=\"nofollow\"></a>").text(match[0]); + replaceEls.push($link[0]); } replaceEls.push(document.createTextNode(text.substring(lastIndex))); $node.replaceWith($(replaceEls)); } return $el; @@ -471,26 +472,28 @@ if (!isDecoration) { allowedAttributes = this._allowedAttributes[$node[0].tagName.toLowerCase()]; ref = $.makeArray($node[0].attributes); for (j = 0, len = ref.length; j < len; j++) { attr = ref[j]; + if (attr.name === 'style') { + continue; + } if (!((allowedAttributes != null) && (ref1 = attr.name, indexOf.call(allowedAttributes, ref1) >= 0))) { $node.removeAttr(attr.name); } + this._cleanNodeStyles($node); } } } 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.find('tr').each(function(i, tr) { + return $p.append($(tr).text() + '<br/>'); + }); $node.replaceWith($p); contents = null; } else if ($node.is('thead, tfoot')) { $node.remove(); contents = null; @@ -511,10 +514,40 @@ } } return null; }; + Formatter.prototype._cleanNodeStyles = function($node) { + var allowedStyles, j, len, pair, ref, ref1, style, styleStr, styles; + styleStr = $node.attr('style'); + if (!styleStr) { + return; + } + $node.removeAttr('style'); + allowedStyles = this._allowedStyles[$node[0].tagName.toLowerCase()]; + if (!(allowedStyles && allowedStyles.length > 0)) { + return $node; + } + styles = {}; + ref = styleStr.split(';'); + for (j = 0, len = ref.length; j < len; j++) { + style = ref[j]; + style = $.trim(style); + pair = style.split(':'); + if (!(pair.length = 2)) { + continue; + } + if (ref1 = pair[0], indexOf.call(allowedStyles, ref1) >= 0) { + styles[$.trim(pair[0])] = $trim(pair[1]); + } + } + if (Object.keys(styles).length > 0) { + $node.css(styles); + } + return $node; + }; + Formatter.prototype.clearHtml = function(html, lineBreak) { var container, contents, result; if (lineBreak == null) { lineBreak = true; } @@ -530,11 +563,11 @@ $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')) { + 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)); @@ -544,23 +577,19 @@ 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 $contents.each(function(i, el) { + var $el, invalid; + $el = $(el); + invalid = $el.is(':not(img, br, col, td, hr, [class^="simditor-"]):empty'); + if (invalid || uselessP($el)) { + $el.remove(); + } + return $el.find(':not(img, br, col, td, hr, [class^="simditor-"]):empty').remove(); + }); }; return Formatter; })(SimpleModule); @@ -1658,21 +1687,19 @@ $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)); + blockEl = blockEl.filter(function(i) { + var $n; + $n = blockEl.eq(i); + if ($.isFunction(filter)) { + return filter($n); + } else { + return $n.is(filter); + } + }); if (blockEl.length) { return blockEl.first(); } else { return null; } @@ -1718,11 +1745,11 @@ } return results1; }; Util.prototype.dataURLtoBlob = function(dataURL) { - var BlobBuilder, arrayBuffer, bb, byteString, hasArrayBufferViewSupport, hasBlobConstructor, i, intArray, j, mimeString, ref; + var BlobBuilder, arrayBuffer, bb, blobArray, byteString, hasArrayBufferViewSupport, hasBlobConstructor, i, intArray, j, mimeString, ref, supportBlob; hasBlobConstructor = window.Blob && (function() { var e; try { return Boolean(new Blob()); } catch (_error) { @@ -1738,11 +1765,12 @@ e = _error; return false; } })(); BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; - if (!((hasBlobConstructor || BlobBuilder) && window.atob && window.ArrayBuffer && window.Uint8Array)) { + supportBlob = hasBlobConstructor || BlobBuilder; + if (!(supportBlob && window.atob && window.ArrayBuffer && window.Uint8Array)) { return false; } if (dataURL.split(',')[0].indexOf('base64') >= 0) { byteString = atob(dataURL.split(',')[1]); } else { @@ -1753,11 +1781,12 @@ for (i = j = 0, ref = byteString.length; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) { intArray[i] = byteString.charCodeAt(i); } mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0]; if (hasBlobConstructor) { - return new Blob([hasArrayBufferViewSupport ? intArray : arrayBuffer], { + blobArray = hasArrayBufferViewSupport ? intArray : arrayBuffer; + return new Blob(blobArray, { type: mimeString }); } bb = new BlobBuilder(); bb.append(arrayBuffer); @@ -2065,11 +2094,11 @@ })(this)); return result; }; Indentation.prototype.indentBlock = function(blockEl) { - var $blockEl, $childList, $nextTd, $nextTr, $parentLi, $pre, $td, $tr, indentLevel, range, tagName; + var $blockEl, $childList, $nextTd, $nextTr, $parentLi, $pre, $td, $tr, marginLeft, range, tagName; $blockEl = $(blockEl); if (!$blockEl.length) { return; } if ($blockEl.is('pre')) { @@ -2092,13 +2121,13 @@ } else { $('<' + tagName + '/>').append($blockEl).appendTo($parentLi); } this.editor.selection.restore(); } else if ($blockEl.is('p, h1, h2, h3, h4')) { - indentLevel = $blockEl.attr('data-indent') || 0; - indentLevel = Math.min(indentLevel * 1 + 1, 10); - $blockEl.attr('data-indent', indentLevel); + marginLeft = parseInt($blockEl.css('margin-left')) || 0; + marginLeft = (Math.round(marginLeft / this.opts.indentWidth) + 1) * this.opts.indentWidth; + $blockEl.css('margin-left', marginLeft); } else if ($blockEl.is('table') || $blockEl.is('.simditor-table')) { range = this.editor.selection.getRange(); $td = $(range.commonAncestorContainer).closest('td, th'); $nextTd = $td.next('td, th'); if (!($nextTd.length > 0)) { @@ -2130,11 +2159,11 @@ return this.editor.selection.setRangeAfter(textNode); } }; Indentation.prototype.outdentBlock = function(blockEl) { - var $blockEl, $parent, $parentLi, $pre, $prevTd, $prevTr, $td, $tr, button, indentLevel, range, ref; + var $blockEl, $parent, $parentLi, $pre, $prevTd, $prevTr, $td, $tr, button, marginLeft, range; $blockEl = $(blockEl); if (!($blockEl && $blockEl.length > 0)) { return; } if ($blockEl.is('pre')) { @@ -2162,16 +2191,13 @@ 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); + marginLeft = parseInt($blockEl.css('margin-left')) || 0; + marginLeft = Math.max(Math.round(marginLeft / this.opts.indentWidth) - 1, 0) * this.opts.indentWidth; + $blockEl.css('margin-left', marginLeft === 0 ? '' : marginLeft); } else if ($blockEl.is('table') || $blockEl.is('.simditor-table')) { range = this.editor.selection.getRange(); $td = $(range.commonAncestorContainer).closest('td, th'); $prevTd = $td.prev('td, th'); if (!($prevTd.length > 0)) { @@ -2224,11 +2250,12 @@ Simditor.prototype.opts = { textarea: null, placeholder: '', defaultImage: 'images/image.png', params: {}, - upload: false + upload: false, + indentWidth: 40 }; Simditor.prototype._init = function() { var e, editor, form, uploadOpts; this.textarea = $(this.opts.textarea); @@ -2315,13 +2342,13 @@ return results1; } }; Simditor.prototype._placeholder = function() { - var children, ref; + var children; children = this.body.children(); - if (children.length === 0 || (children.length === 1 && this.util.isEmptyNode(children) && ((ref = children.data('indent')) != null ? ref : 0) < 1)) { + if (children.length === 0 || (children.length === 1 && this.util.isEmptyNode(children) && parseInt(children.css('margin-left') || 0) < this.opts.indentWidth)) { return this.placeholderEl.show(); } else { return this.placeholderEl.hide(); } }; @@ -2392,18 +2419,16 @@ return this.body.find('textarea:visible').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)); + return this.el.find('.simditor-popover').each(function(i, popover) { + popover = $(popover).data('popover'); + if (popover.active) { + return popover.hide(); + } + }); }; Simditor.prototype.destroy = function() { this.triggerHandler('destroy'); this.textarea.closest('form').off('.simditor .simditor-' + this.id); @@ -2735,10 +2760,13 @@ if (popover.active) { return popover.hide(); } }; })(this)); + if (this.active && this.target) { + this.target.removeClass('selected'); + } this.target = $target.addClass('selected'); if (this.active) { this.refresh(position); return this.trigger('popovershow'); } else { @@ -3596,25 +3624,98 @@ function CodePopover() { return CodePopover.__super__.constructor.apply(this, arguments); } CodePopover.prototype.render = function() { - this._tpl = "<div class=\"code-settings\">\n <div class=\"settings-field\">\n <select class=\"select-lang\">\n <option value=\"-1\">" + (this._t('selectLanguage')) + "</option>\n <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>"; + var $option, j, lang, len, ref; + this._tpl = "<div class=\"code-settings\">\n <div class=\"settings-field\">\n <select class=\"select-lang\">\n <option value=\"-1\">" + (this._t('selectLanguage')) + "</option>\n </select>\n </div>\n</div>"; + this.langs = this.editor.opts.codeLanguages || [ + { + name: 'Bash', + value: 'bash' + }, { + name: 'C++', + value: 'c++' + }, { + name: 'C#', + value: 'cs' + }, { + name: 'CSS', + value: 'css' + }, { + name: 'Erlang', + value: 'erlang' + }, { + name: 'Less', + value: 'less' + }, { + name: 'Sass', + value: 'sass' + }, { + name: 'Diff', + value: 'diff' + }, { + name: 'CoffeeScript', + value: 'coffeescript' + }, { + name: 'HTML,XML', + value: 'html' + }, { + name: 'JSON', + value: 'json' + }, { + name: 'Java', + value: 'java' + }, { + name: 'JavaScript', + value: 'js' + }, { + name: 'Markdown', + value: 'markdown' + }, { + name: 'Objective C', + value: 'oc' + }, { + name: 'PHP', + value: 'php' + }, { + name: 'Perl', + value: 'parl' + }, { + name: 'Python', + value: 'python' + }, { + name: 'Ruby', + value: 'ruby' + }, { + name: 'SQL', + value: 'sql' + } + ]; this.el.addClass('code-popover').append(this._tpl); this.selectEl = this.el.find('.select-lang'); + ref = this.langs; + for (j = 0, len = ref.length; j < len; j++) { + lang = ref[j]; + $option = $('<option/>', { + text: lang.name, + value: lang.value + }).appendTo(this.selectEl); + } 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.attr('data-lang', _this.lang); } if (selected) { - return _this.target.addClass('selected'); + _this.target.addClass('selected'); } + return _this.editor.trigger('valuechanged'); }; })(this)); return this.editor.on('valuechanged', (function(_this) { return function(e) { if (_this.active) { @@ -5164,10 +5265,13 @@ AlignmentButton.prototype.setActive = function(active, align) { if (align == null) { align = 'left'; } + if (align !== 'left' && align !== 'center' && align !== 'right') { + align = 'left'; + } if (align === 'left') { AlignmentButton.__super__.setActive.call(this, false); } else { AlignmentButton.__super__.setActive.call(this, active); } @@ -5189,18 +5293,18 @@ this.setDisabled(!$node.is(this.htmlTag)); if (this.disabled) { this.setActive(false); return true; } - this.setActive(true, $node.data("align")); + this.setActive(true, $node.css('text-align')); return this.active; }; AlignmentButton.prototype.command = function(align) { var $blockEls, $endBlock, $startBlock, block, endNode, j, len, range, ref, startNode; if (['left', 'center', 'right'].indexOf(align) < 0) { - throw "invalid " + align; + throw new Error("invalid " + align); } range = this.editor.selection.getRange(); startNode = range.startContainer; endNode = range.endContainer; $startBlock = this.editor.util.closestBlockEl(startNode); @@ -5208,10 +5312,10 @@ this.editor.selection.save(); $blockEls = $startBlock.is($endBlock) ? $startBlock : $startBlock.nextUntil($endBlock).addBack().add($endBlock); ref = $blockEls.filter(this.htmlTag); for (j = 0, len = ref.length; j < len; j++) { block = ref[j]; - $(block).attr('data-align', align).data('align', align); + $(block).css('text-align', align === 'left' ? '' : align); } this.editor.selection.restore(); return this.editor.trigger('valuechanged'); };