: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* returns whether point is visible (can set cursor) or not.
* @param {BoundaryPoint} point
var isVisiblePoint = function (point) {
if (isText(point.node) || !hasChildren(point.node) || isEmpty(point.node)) {
var leftNode = point.node.childNodes[point.offset - 1];
var rightNode = point.node.childNodes[point.offset];
if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode))) {
* @param {BoundaryPoint} point
* @return {BoundaryPoint}
var prevPointUntil = function (point, pred) {
point = prevPoint(point);
* @param {BoundaryPoint} point
* @return {BoundaryPoint}
var nextPointUntil = function (point, pred) {
point = nextPoint(point);
* returns whether point has character or not.
var isCharPoint = function (point) {
if (!isText(point.node)) {
var ch = point.node.nodeValue.charAt(point.offset - 1);
return ch && (ch !== ' ' && ch !== NBSP_CHAR);
* @param {BoundaryPoint} startPoint
* @param {BoundaryPoint} endPoint
* @param {Function} handler
* @param {Boolean} isSkipInnerOffset
var walkPoint = function (startPoint, endPoint, handler, isSkipInnerOffset) {
if (isSamePoint(point, endPoint)) {
var isSkipOffset = isSkipInnerOffset &&
startPoint.node !== point.node &&
endPoint.node !== point.node;
point = nextPoint(point, isSkipOffset);
* return offsetPath(array of offset) from ancestor
* @param {Node} ancestor - ancestor node
var makeOffsetPath = function (ancestor, node) {
var ancestors = listAncestor(node, func.eq(ancestor));
return ancestors.map(position).reverse();
* return element from offsetPath(array of offset)
* @param {Node} ancestor - ancestor node
* @param {array} offsets - offsetPath
var fromOffsetPath = function (ancestor, offsets) {
for (var i = 0, len = offsets.length; i < len; i++) {
if (current.childNodes.length <= offsets[i]) {
current = current.childNodes[current.childNodes.length - 1];
current = current.childNodes[offsets[i]];
* @param {BoundaryPoint} point
* @param {Object} [options]
* @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
* @param {Boolean} [options.isNotSplitEdgePoint] - default: false
* @return {Node} right node of boundaryPoint
var splitNode = function (point, options) {
var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;
var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;
if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {
if (isLeftEdgePoint(point)) {
} else if (isRightEdgePoint(point)) {
return point.node.nextSibling;
if (isText(point.node)) {
return point.node.splitText(point.offset);
var childNode = point.node.childNodes[point.offset];
var clone = insertAfter(point.node.cloneNode(false), point.node);
appendChildNodes(clone, listNext(childNode));
if (!isSkipPaddingBlankHTML) {
paddingBlankHTML(point.node);
* @param {Node} root - split root
* @param {BoundaryPoint} point
* @param {Object} [options]
* @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
* @param {Boolean} [options.isNotSplitEdgePoint] - default: false
* @return {Node} right node of boundaryPoint
var splitTree = function (root, point, options) {
// ex) [#text, <span>, <p>]
var ancestors = listAncestor(point.node, func.eq(root));
} else if (ancestors.length === 1) {
return splitNode(point, options);
return ancestors.reduce(function (node, parent) {
if (node === point.node) {
node = splitNode(point, options);
offset: node ? dom.position(node) : nodeLength(parent)
* @param {Boolean} isInline
var splitPoint = function (point, isInline) {
// find splitRoot, container
// - inline: splitRoot is a child of paragraph
// - block: splitRoot is a child of bodyContainer
var pred = isInline ? isPara : isBodyContainer;
var ancestors = listAncestor(point.node, pred);
var topAncestor = list.last(ancestors) || point.node;
var splitRoot, container;
splitRoot = ancestors[ancestors.length - 2];
container = splitRoot.parentNode;
// if splitRoot is exists, split with splitTree
var pivot = splitRoot && splitTree(splitRoot, point, {
isSkipPaddingBlankHTML: isInline,
isNotSplitEdgePoint: isInline
// if container is point.node, find pivot with point.offset
if (!pivot && container === point.node) {
pivot = point.node.childNodes[point.offset];
var create = function (nodeName) {
return document.createElement(nodeName);
var createText = function (text) {
return document.createTextNode(text);
* remove node, (isRemoveChild: remove child or not)
* @param {Boolean} isRemoveChild
var remove = function (node, isRemoveChild) {
if (!node || !node.parentNode) { return; }
if (node.removeNode) { return node.removeNode(isRemoveChild); }
var parent = node.parentNode;
for (i = 0, len = node.childNodes.length; i < len; i++) {
nodes.push(node.childNodes[i]);
for (i = 0, len = nodes.length; i < len; i++) {
parent.insertBefore(nodes[i], node);
parent.removeChild(node);
var removeWhile = function (node, pred) {
if (isEditable(node) || !pred(node)) {
var parent = node.parentNode;
* replace node with provided nodeName
* @param {String} nodeName
* @return {Node} - new node
var replace = function (node, nodeName) {
if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {
var newNode = create(nodeName);
if (node.style.cssText) {
newNode.style.cssText = node.style.cssText;
appendChildNodes(newNode, list.from(node.childNodes));
insertAfter(newNode, node);
var isTextarea = makePredByNodeName('TEXTAREA');
* @param {Boolean} [stripLinebreaks] - default: false
var value = function ($node, stripLinebreaks) {
var val = isTextarea($node[0]) ? $node.val() : $node.html();
return val.replace(/[\n\r]/g, '');
* get the HTML contents of node
* @param {Boolean} [isNewlineOnBlock]
var html = function ($node, isNewlineOnBlock) {
var markup = value($node);
var regexTag = /<(\/?)(\b(?!!)[^>\s]*)(.*?)(\s*\/?>)/g;
markup = markup.replace(regexTag, function (match, endSlash, name) {
name = name.toUpperCase();
var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) &&
var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);
return match + ((isEndOfInlineContainer || isBlockNode) ? '\n' : '');
var posFromPlaceholder = function (placeholder) {
var $placeholder = $(placeholder);
var pos = $placeholder.offset();
var height = $placeholder.outerHeight(true); // include margin
var attachEvents = function ($node, events) {
Object.keys(events).forEach(function (key) {
$node.on(key, events[key]);
var detachEvents = function ($node, events) {
Object.keys(events).forEach(function (key) {
$node.off(key, events[key]);
/** @property {String} NBSP_CHAR */
/** @property {String} ZERO_WIDTH_NBSP_CHAR */
ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,
/** @property {String} blank */
/** @property {String} emptyPara */
emptyPara: '<p>' + blankHTML + '</p>',
makePredByNodeName: makePredByNodeName,
isControlSizing: isControlSizing,
isBlock: func.not(isInline),
isBodyInline: isBodyInline,
isParaInline: isParaInline,
isBlockquote: isBlockquote,
isBodyContainer: isBodyContainer,
isDiv: makePredByNodeName('DIV'),
isBR: makePredByNodeName('BR'),
isSpan: makePredByNodeName('SPAN'),
isB: makePredByNodeName('B'),
isU: makePredByNodeName('U'),
isS: makePredByNodeName('S'),
isI: makePredByNodeName('I'),
isImg: makePredByNodeName('IMG'),
isEmptyAnchor: func.and(isAnchor, isEmpty),
isClosestSibling: isClosestSibling,
withClosestSiblings: withClosestSiblings,
isLeftEdgePoint: isLeftEdgePoint,
isRightEdgePoint: isRightEdgePoint,
isEdgePoint: isEdgePoint,
isLeftEdgeOf: isLeftEdgeOf,
isRightEdgeOf: isRightEdgeOf,
isLeftEdgePointOf: isLeftEdgePointOf,
isRightEdgePointOf: isRightEdgePointOf,
isSamePoint: isSamePoint,
isVisiblePoint: isVisiblePoint,
prevPointUntil: prevPointUntil,
nextPointUntil: nextPointUntil,
isCharPoint: isCharPoint,
singleChildAncestor: singleChildAncestor,
listAncestor: listAncestor,
lastAncestor: lastAncestor,
listDescendant: listDescendant,
commonAncestor: commonAncestor,
insertAfter: insertAfter,
appendChildNodes: appendChildNodes,
hasChildren: hasChildren,
makeOffsetPath: makeOffsetPath,
fromOffsetPath: fromOffsetPath,
removeWhile: removeWhile,
posFromPlaceholder: posFromPlaceholder,
attachEvents: attachEvents,
detachEvents: detachEvents
* @param {Object} options
var Context = function ($note, options) {
var ui = $.summernote.ui;
* create layout and initialize modules and other resources