diff options
| author | Christophe Matthieu <chm@odoo.com> | 2014-12-10 15:59:48 +0100 |
|---|---|---|
| committer | Christophe Matthieu <chm@odoo.com> | 2015-01-05 10:17:10 +0100 |
| commit | 1596e45e8174cd736d4f7c78f85ec76a8e34888d (patch) | |
| tree | 4ff318ee78bccc6c0bb6253670e85977f8f5a643 /addons/website/static/lib/summernote/src/js/editing | |
| parent | f9a7ed6b9406d657fda33ec55c4e237576b77a42 (diff) | |
[IMP] website: add summernote lib
Diffstat (limited to 'addons/website/static/lib/summernote/src/js/editing')
6 files changed, 926 insertions, 0 deletions
diff --git a/addons/website/static/lib/summernote/src/js/editing/Bullet.js b/addons/website/static/lib/summernote/src/js/editing/Bullet.js new file mode 100644 index 00000000000..d0b0f2e9169 --- /dev/null +++ b/addons/website/static/lib/summernote/src/js/editing/Bullet.js @@ -0,0 +1,201 @@ +define([ + 'summernote/core/list', + 'summernote/core/func', + 'summernote/core/dom', + 'summernote/core/range' +], function (list, func, dom, range) { + + var Bullet = function () { + /** + * toggle ordered list + * @type command + */ + this.insertOrderedList = function () { + this.toggleList('OL'); + }; + + /** + * toggle unordered list + * @type command + */ + this.insertUnorderedList = function () { + this.toggleList('UL'); + }; + + /** + * indent + * @type command + */ + this.indent = function () { + var self = this; + var rng = range.create().wrapBodyInlineWithPara(); + + var paras = rng.nodes(dom.isPara, { includeAncestor: true }); + var clustereds = list.clusterBy(paras, func.peq2('parentNode')); + + $.each(clustereds, function (idx, paras) { + var head = list.head(paras); + if (dom.isLi(head)) { + self.wrapList(paras, head.parentNode.nodeName); + } else { + $.each(paras, function (idx, para) { + $(para).css('marginLeft', function (idx, val) { + return (parseInt(val, 10) || 0) + 25; + }); + }); + } + }); + + rng.select(); + }; + + /** + * outdent + * @type command + */ + this.outdent = function () { + var self = this; + var rng = range.create().wrapBodyInlineWithPara(); + + var paras = rng.nodes(dom.isPara, { includeAncestor: true }); + var clustereds = list.clusterBy(paras, func.peq2('parentNode')); + + $.each(clustereds, function (idx, paras) { + var head = list.head(paras); + if (dom.isLi(head)) { + self.releaseList([paras]); + } else { + $.each(paras, function (idx, para) { + $(para).css('marginLeft', function (idx, val) { + val = (parseInt(val, 10) || 0); + return val > 25 ? val - 25 : ''; + }); + }); + } + }); + + rng.select(); + }; + + /** + * toggle list + * @param {String} listName - OL or UL + */ + this.toggleList = function (listName) { + var self = this; + var rng = range.create().wrapBodyInlineWithPara(); + + var paras = rng.nodes(dom.isPara, { includeAncestor: true }); + var clustereds = list.clusterBy(paras, func.peq2('parentNode')); + + // paragraph to list + if (list.find(paras, dom.isPurePara)) { + $.each(clustereds, function (idx, paras) { + self.wrapList(paras, listName); + }); + // list to paragraph or change list style + } else { + var diffLists = rng.nodes(dom.isList, { + includeAncestor: true + }).filter(function (listNode) { + return !$.nodeName(listNode, listName); + }); + + if (diffLists.length) { + $.each(diffLists, function (idx, listNode) { + dom.replace(listNode, listName); + }); + } else { + this.releaseList(clustereds, true); + } + } + + rng.select(); + }; + + /** + * @param {Node[]} paras + * @param {String} listName + */ + this.wrapList = function (paras, listName) { + var head = list.head(paras); + var last = list.last(paras); + + var prevList = dom.isList(head.previousSibling) && head.previousSibling; + var nextList = dom.isList(last.nextSibling) && last.nextSibling; + + var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last); + + // P to LI + paras = $.map(paras, function (para) { + return dom.isPurePara(para) ? dom.replace(para, 'LI') : para; + }); + + // append to list(<ul>, <ol>) + dom.appendChildNodes(listNode, paras); + + if (nextList) { + dom.appendChildNodes(listNode, list.from(nextList.childNodes)); + dom.remove(nextList); + } + }; + + /** + * @param {Array[]} clustereds + * @param {Boolean} isEscapseToBody + * @return {Node[]} + */ + this.releaseList = function (clustereds, isEscapseToBody) { + var releasedParas = []; + + $.each(clustereds, function (idx, paras) { + var head = list.head(paras); + var last = list.last(paras); + + var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) : + head.parentNode; + var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, { + node: last.parentNode, + offset: dom.position(last) + 1 + }, true) : null; + + var middleList = dom.splitTree(headList, { + node: head.parentNode, + offset: dom.position(head) + }, true); + + paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) : + list.from(middleList.childNodes).filter(dom.isLi); + + // LI to P + if (isEscapseToBody || !dom.isList(headList.parentNode)) { + paras = $.map(paras, function (para) { + return dom.replace(para, 'P'); + }); + } + + $.each(list.from(paras).reverse(), function (idx, para) { + dom.insertAfter(para, headList); + }); + + // remove empty lists + var rootLists = list.compact([headList, middleList, lastList]); + $.each(rootLists, function (idx, rootList) { + var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList)); + $.each(listNodes.reverse(), function (idx, listNode) { + if (!dom.nodeLength(listNode)) { + dom.remove(listNode, true); + } + }); + }); + + releasedParas = releasedParas.concat(paras); + }); + + return releasedParas; + }; + }; + + return Bullet; +}); + diff --git a/addons/website/static/lib/summernote/src/js/editing/Editor.js b/addons/website/static/lib/summernote/src/js/editing/Editor.js new file mode 100644 index 00000000000..35af842afe8 --- /dev/null +++ b/addons/website/static/lib/summernote/src/js/editing/Editor.js @@ -0,0 +1,457 @@ +define([ + 'summernote/core/agent', + 'summernote/core/func', + 'summernote/core/list', + 'summernote/core/dom', + 'summernote/core/range', + 'summernote/core/async', + 'summernote/editing/Style', + 'summernote/editing/Typing', + 'summernote/editing/Table', + 'summernote/editing/Bullet' +], function (agent, func, list, dom, range, async, + Style, Typing, Table, Bullet) { + /** + * Editor + * @class + */ + var Editor = function () { + + var style = new Style(); + var table = new Table(); + var typing = new Typing(); + var bullet = new Bullet(); + + /** + * create range + */ + this.createRange = function ($editable) { + $editable.focus(); + return range.create(); + }; + + /** + * save current range + * + * @param {jQuery} $editable + */ + this.saveRange = function ($editable, thenCollapse) { + $editable.focus(); + $editable.data('range', range.create()); + if (thenCollapse) { + range.create().collapse().select(); + } + }; + + /** + * restore lately range + * + * @param {jQuery} $editable + */ + this.restoreRange = function ($editable) { + var rng = $editable.data('range'); + if (rng) { + rng.select(); + $editable.focus(); + } + }; + + /** + * current style + * @param {Node} target + */ + this.currentStyle = function (target) { + var rng = range.create(); + return rng ? rng.isOnEditable() && style.current(rng, target) : false; + }; + + var triggerOnChange = this.triggerOnChange = function ($editable) { + var onChange = $editable.data('callbacks').onChange; + if (onChange) { + onChange($editable.html(), $editable); + } + }; + + /** + * undo + * @param {jQuery} $editable + */ + this.undo = function ($editable) { + $editable.data('NoteHistory').undo(); + triggerOnChange($editable); + }; + + /** + * redo + * @param {jQuery} $editable + */ + this.redo = function ($editable) { + $editable.data('NoteHistory').redo(); + triggerOnChange($editable); + }; + + /** + * after command + * @param {jQuery} $editable + */ + var afterCommand = this.afterCommand = function ($editable) { + $editable.data('NoteHistory').recordUndo(); + triggerOnChange($editable); + }; + + /* jshint ignore:start */ + // native commands(with execCommand), generate function for execCommand + var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', + 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull', + 'formatBlock', 'removeFormat', + 'backColor', 'foreColor', 'insertHorizontalRule', 'fontName']; + + for (var idx = 0, len = commands.length; idx < len; idx ++) { + this[commands[idx]] = (function (sCmd) { + return function ($editable, value) { + document.execCommand(sCmd, false, value); + + afterCommand($editable); + }; + })(commands[idx]); + } + /* jshint ignore:end */ + + /** + * handle tab key + * + * @param {jQuery} $editable + * @param {Object} options + */ + this.tab = function ($editable, options) { + var rng = range.create(); + if (rng.isCollapsed() && rng.isOnCell()) { + table.tab(rng); + } else { + typing.insertTab($editable, rng, options.tabsize); + afterCommand($editable); + } + }; + + /** + * handle shift+tab key + */ + this.untab = function () { + var rng = range.create(); + if (rng.isCollapsed() && rng.isOnCell()) { + table.tab(rng, true); + } + }; + + /** + * insert paragraph + * + * @param {Node} $editable + */ + this.insertParagraph = function ($editable) { + typing.insertParagraph($editable); + afterCommand($editable); + }; + + /** + * @param {jQuery} $editable + */ + this.insertOrderedList = function ($editable) { + bullet.insertOrderedList($editable); + afterCommand($editable); + }; + + /** + * @param {jQuery} $editable + */ + this.insertUnorderedList = function ($editable) { + bullet.insertUnorderedList($editable); + afterCommand($editable); + }; + + /** + * @param {jQuery} $editable + */ + this.indent = function ($editable) { + bullet.indent($editable); + afterCommand($editable); + }; + + /** + * @param {jQuery} $editable + */ + this.outdent = function ($editable) { + bullet.outdent($editable); + afterCommand($editable); + }; + + /** + * insert image + * + * @param {jQuery} $editable + * @param {String} sUrl + */ + this.insertImage = function ($editable, sUrl, filename) { + async.createImage(sUrl, filename).then(function ($image) { + $image.css({ + display: '', + width: Math.min($editable.width(), $image.width()) + }); + range.create().insertNode($image[0]); + afterCommand($editable); + }).fail(function () { + var callbacks = $editable.data('callbacks'); + if (callbacks.onImageUploadError) { + callbacks.onImageUploadError(); + } + }); + }; + + /** + * insert node + * @param {Node} $editable + * @param {Node} node + * @param {Boolean} [isInline] + */ + this.insertNode = function ($editable, node, isInline) { + range.create().insertNode(node, isInline); + afterCommand($editable); + }; + + /** + * insert text + * @param {Node} $editable + * @param {String} text + */ + this.insertText = function ($editable, text) { + var textNode = this.createRange($editable).insertNode(dom.createText(text), true); + range.create(textNode, dom.nodeLength(textNode)).select(); + afterCommand($editable); + }; + + /** + * formatBlock + * + * @param {jQuery} $editable + * @param {String} tagName + */ + this.formatBlock = function ($editable, tagName) { + tagName = agent.isMSIE ? '<' + tagName + '>' : tagName; + document.execCommand('FormatBlock', false, tagName); + afterCommand($editable); + }; + + this.formatPara = function ($editable) { + this.formatBlock($editable, 'P'); + afterCommand($editable); + }; + + /* jshint ignore:start */ + for (var idx = 1; idx <= 6; idx ++) { + this['formatH' + idx] = function (idx) { + return function ($editable) { + this.formatBlock($editable, 'H' + idx); + }; + }(idx); + }; + /* jshint ignore:end */ + + /** + * fontsize + * FIXME: Still buggy + * + * @param {jQuery} $editable + * @param {String} value - px + */ + this.fontSize = function ($editable, value) { + document.execCommand('fontSize', false, 3); + if (agent.isFF) { + // firefox: <font size="3"> to <span style='font-size={value}px;'>, buggy + $editable.find('font[size=3]').removeAttr('size').css('font-size', value + 'px'); + } else { + // chrome: <span style="font-size: medium"> to <span style='font-size={value}px;'> + $editable.find('span').filter(function () { + return this.style.fontSize === 'medium'; + }).css('font-size', value + 'px'); + } + + afterCommand($editable); + }; + + /** + * lineHeight + * @param {jQuery} $editable + * @param {String} value + */ + this.lineHeight = function ($editable, value) { + style.stylePara(range.create(), { + lineHeight: value + }); + afterCommand($editable); + }; + + /** + * unlink + * + * @type command + * + * @param {jQuery} $editable + */ + this.unlink = function ($editable) { + var rng = range.create(); + if (rng.isOnAnchor()) { + var anchor = dom.ancestor(rng.sc, dom.isAnchor); + rng = range.createFromNode(anchor); + rng.select(); + document.execCommand('unlink'); + + afterCommand($editable); + } + }; + + /** + * create link + * + * @type command + * + * @param {jQuery} $editable + * @param {Object} linkInfo + * @param {Object} options + */ + this.createLink = function ($editable, linkInfo, options) { + var linkUrl = linkInfo.url; + var linkText = linkInfo.text; + var isNewWindow = linkInfo.newWindow; + var rng = linkInfo.range; + + if (options.onCreateLink) { + linkUrl = options.onCreateLink(linkUrl); + } + + rng = rng.deleteContents(); + + // Create a new link when there is no anchor on range. + var anchor = rng.insertNode($('<A>' + linkText + '</A>')[0], true); + $(anchor).attr({ + href: linkUrl, + target: isNewWindow ? '_blank' : '' + }); + + range.createFromNode(anchor).select(); + afterCommand($editable); + }; + + /** + * returns link info + * + * @return {Object} + */ + this.getLinkInfo = function ($editable) { + $editable.focus(); + + var rng = range.create().expand(dom.isAnchor); + + // Get the first anchor on range(for edit). + var $anchor = $(list.head(rng.nodes(dom.isAnchor))); + + return { + range: rng, + text: rng.toString(), + isNewWindow: $anchor.length ? $anchor.attr('target') === '_blank' : true, + url: $anchor.length ? $anchor.attr('href') : '' + }; + }; + + this.color = function ($editable, sObjColor) { + var oColor = JSON.parse(sObjColor); + var foreColor = oColor.foreColor, backColor = oColor.backColor; + + if (foreColor) { document.execCommand('foreColor', false, foreColor); } + if (backColor) { document.execCommand('backColor', false, backColor); } + + afterCommand($editable); + }; + + this.insertTable = function ($editable, sDim) { + var dimension = sDim.split('x'); + var rng = range.create(); + rng = rng.deleteContents(); + rng.insertNode(table.createTable(dimension[0], dimension[1])); + afterCommand($editable); + }; + + /** + * @param {jQuery} $editable + * @param {String} value + * @param {jQuery} $target + */ + this.floatMe = function ($editable, value, $target) { + $target.css('float', value); + afterCommand($editable); + }; + + this.imageShape = function ($editable, value, $target) { + $target.removeClass('img-rounded img-circle img-thumbnail'); + + if (value) { + $target.addClass(value); + } + + afterCommand($editable); + }; + + /** + * resize overlay element + * @param {jQuery} $editable + * @param {String} value + * @param {jQuery} $target - target element + */ + this.resize = function ($editable, value, $target) { + $target.css({ + width: value * 100 + '%', + height: '' + }); + + afterCommand($editable); + }; + + /** + * @param {Position} pos + * @param {jQuery} $target - target element + * @param {Boolean} [bKeepRatio] - keep ratio + */ + this.resizeTo = function (pos, $target, bKeepRatio) { + var imageSize; + if (bKeepRatio) { + var newRatio = pos.y / pos.x; + var ratio = $target.data('ratio'); + imageSize = { + width: ratio > newRatio ? pos.x : pos.y / ratio, + height: ratio > newRatio ? pos.x * ratio : pos.y + }; + } else { + imageSize = { + width: pos.x, + height: pos.y + }; + } + + $target.css(imageSize); + }; + + /** + * remove media object + * + * @param {jQuery} $editable + * @param {String} value - dummy argument (for keep interface) + * @param {jQuery} $target - target element + */ + this.removeMedia = function ($editable, value, $target) { + $target.detach(); + + afterCommand($editable); + }; + }; + + return Editor; +}); diff --git a/addons/website/static/lib/summernote/src/js/editing/History.js b/addons/website/static/lib/summernote/src/js/editing/History.js new file mode 100644 index 00000000000..ef8dd6016f1 --- /dev/null +++ b/addons/website/static/lib/summernote/src/js/editing/History.js @@ -0,0 +1,60 @@ +define(['summernote/core/range'], function (range) { + /** + * History + * @class + */ + var History = function ($editable) { + var stack = [], stackOffset = -1; + var editable = $editable[0]; + + var makeSnapshot = function () { + var rng = range.create(); + var emptyBookmark = {s: {path: [0], offset: 0}, e: {path: [0], offset: 0}}; + + return { + contents: $editable.html(), + bookmark: (rng ? rng.bookmark(editable) : emptyBookmark) + }; + }; + + var applySnapshot = function (snapshot) { + if (snapshot.contents !== null) { + $editable.html(snapshot.contents); + } + if (snapshot.bookmark !== null) { + range.createFromBookmark(editable, snapshot.bookmark).select(); + } + }; + + this.undo = function () { + if (0 < stackOffset) { + stackOffset--; + applySnapshot(stack[stackOffset]); + } + }; + + this.redo = function () { + if (stack.length - 1 > stackOffset) { + stackOffset++; + applySnapshot(stack[stackOffset]); + } + }; + + this.recordUndo = function () { + stackOffset++; + + // Wash out stack after stackOffset + if (stack.length > stackOffset) { + stack = stack.slice(0, stackOffset); + } + + // Create new snapshot and push it to the end + stack.push(makeSnapshot()); + }; + + // Create first undo stack + this.recordUndo(); + }; + + return History; +}); diff --git a/addons/website/static/lib/summernote/src/js/editing/Style.js b/addons/website/static/lib/summernote/src/js/editing/Style.js new file mode 100644 index 00000000000..ec0260c0317 --- /dev/null +++ b/addons/website/static/lib/summernote/src/js/editing/Style.js @@ -0,0 +1,93 @@ +define([ + 'summernote/core/agent', + 'summernote/core/dom' +], function (agent, dom) { + /** + * Style + * @class + */ + var Style = function () { + /** + * passing an array of style properties to .css() + * will result in an object of property-value pairs. + * (compability with version < 1.9) + * + * @param {jQuery} $obj + * @param {Array} propertyNames - An array of one or more CSS properties. + * @returns {Object} + */ + var jQueryCSS = function ($obj, propertyNames) { + if (agent.jqueryVersion < 1.9) { + var result = {}; + $.each(propertyNames, function (idx, propertyName) { + result[propertyName] = $obj.css(propertyName); + }); + return result; + } + return $obj.css.call($obj, propertyNames); + }; + + /** + * paragraph level style + * + * @param {WrappedRange} rng + * @param {Object} styleInfo + */ + this.stylePara = function (rng, styleInfo) { + $.each(rng.nodes(dom.isPara, { + includeAncestor: true + }), function (idx, para) { + $(para).css(styleInfo); + }); + }; + + /** + * get current style on cursor + * + * @param {WrappedRange} rng + * @param {Node} target - target element on event + * @return {Object} - object contains style properties. + */ + this.current = function (rng, target) { + var $cont = $(dom.isText(rng.sc) ? rng.sc.parentNode : rng.sc); + var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height']; + var styleInfo = jQueryCSS($cont, properties) || {}; + + styleInfo['font-size'] = parseInt(styleInfo['font-size'], 10); + + // document.queryCommandState for toggle state + styleInfo['font-bold'] = document.queryCommandState('bold') ? 'bold' : 'normal'; + styleInfo['font-italic'] = document.queryCommandState('italic') ? 'italic' : 'normal'; + styleInfo['font-underline'] = document.queryCommandState('underline') ? 'underline' : 'normal'; + styleInfo['font-strikethrough'] = document.queryCommandState('strikeThrough') ? 'strikethrough' : 'normal'; + styleInfo['font-superscript'] = document.queryCommandState('superscript') ? 'superscript' : 'normal'; + styleInfo['font-subscript'] = document.queryCommandState('subscript') ? 'subscript' : 'normal'; + + // list-style-type to list-style(unordered, ordered) + if (!rng.isOnList()) { + styleInfo['list-style'] = 'none'; + } else { + var aOrderedType = ['circle', 'disc', 'disc-leading-zero', 'square']; + var isUnordered = $.inArray(styleInfo['list-style-type'], aOrderedType) > -1; + styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered'; + } + + var para = dom.ancestor(rng.sc, dom.isPara); + if (para && para.style['line-height']) { + styleInfo['line-height'] = para.style.lineHeight; + } else { + var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10); + styleInfo['line-height'] = lineHeight.toFixed(1); + } + + styleInfo.image = dom.isImg(target) && target; + styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor); + styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable); + styleInfo.range = rng; + + return styleInfo; + }; + }; + + return Style; +}); diff --git a/addons/website/static/lib/summernote/src/js/editing/Table.js b/addons/website/static/lib/summernote/src/js/editing/Table.js new file mode 100644 index 00000000000..291f85128e5 --- /dev/null +++ b/addons/website/static/lib/summernote/src/js/editing/Table.js @@ -0,0 +1,50 @@ +define([ + 'summernote/core/dom', 'summernote/core/range', 'summernote/core/list' +], function (dom, range, list) { + /** + * Table + * @class + */ + var Table = function () { + /** + * handle tab key + * + * @param {WrappedRange} rng + * @param {Boolean} isShift + */ + this.tab = function (rng, isShift) { + var cell = dom.ancestor(rng.commonAncestor(), dom.isCell); + var table = dom.ancestor(cell, dom.isTable); + var cells = dom.listDescendant(table, dom.isCell); + + var nextCell = list[isShift ? 'prev' : 'next'](cells, cell); + if (nextCell) { + range.create(nextCell, 0).select(); + } + }; + + /** + * create empty table element + * + * @param {Number} rowCount + * @param {Number} colCount + * @return {Node} + */ + this.createTable = function (colCount, rowCount) { + var tds = [], tdHTML; + for (var idxCol = 0; idxCol < colCount; idxCol++) { + tds.push('<td>' + dom.blank + '</td>'); + } + tdHTML = tds.join(''); + + var trs = [], trHTML; + for (var idxRow = 0; idxRow < rowCount; idxRow++) { + trs.push('<tr>' + tdHTML + '</tr>'); + } + trHTML = trs.join(''); + return $('<table class="table table-bordered">' + trHTML + '</table>')[0]; + }; + }; + return Table; +}); + diff --git a/addons/website/static/lib/summernote/src/js/editing/Typing.js b/addons/website/static/lib/summernote/src/js/editing/Typing.js new file mode 100644 index 00000000000..2a094cafa22 --- /dev/null +++ b/addons/website/static/lib/summernote/src/js/editing/Typing.js @@ -0,0 +1,65 @@ +define([ + 'summernote/core/dom', + 'summernote/core/range' +], function (dom, range) { + + var Typing = function () { + + /** + * @param {jQuery} $editable + * @param {WrappedRange} rng + * @param {Number} tabsize + */ + this.insertTab = function ($editable, rng, tabsize) { + var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR)); + rng = rng.deleteContents(); + rng.insertNode(tab, true); + + rng = range.create(tab, tabsize); + rng.select(); + }; + + /** + * insert paragraph + */ + this.insertParagraph = function () { + var rng = range.create(); + + // deleteContents on range. + rng = rng.deleteContents(); + + // Wrap range if it needs to be wrapped by paragraph + rng = rng.wrapBodyInlineWithPara(); + + // finding paragraph + var splitRoot = dom.ancestor(rng.sc, dom.isPara); + + var nextPara; + // on paragraph: split paragraph + if (splitRoot) { + nextPara = dom.splitTree(splitRoot, rng.getStartPoint()); + + var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor); + emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor)); + + $.each(emptyAnchors, function (idx, anchor) { + dom.remove(anchor); + }); + // no paragraph: insert empty paragraph + } else { + var next = rng.sc.childNodes[rng.so]; + nextPara = $(dom.emptyPara)[0]; + if (next) { + rng.sc.insertBefore(nextPara, next); + } else { + rng.sc.appendChild(nextPara); + } + } + + range.create(nextPara, 0).normalize().select(); + }; + + }; + + return Typing; +}); |
