Skip to content

Commit

Permalink
Unit tests & fixing
Browse files Browse the repository at this point in the history
  • Loading branch information
muratcakir committed Nov 28, 2024
1 parent f29b591 commit 971a522
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 82 deletions.
6 changes: 6 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
<body>
<h1>Summernote</h1>
<div class="summernote">
<ul>
<li>Lorem ipsum dolor</li>
<li>justo duo dolores et ea rebum. Stet clita kasd gubergren</li>
<li>sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua</li>
<li>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren</li>
</ul>
<p>Summernote is a JavaScript library that helps you create WYSIWYG editors with a simple and easy-to-use interface.</p>
<p>Summernote is licensed under MIT and maintained by the community.</p>
</div>
Expand Down
9 changes: 6 additions & 3 deletions src/js/core/Point.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,9 @@ const splitNode = (point, options) => {
const childNode = point.node.childNodes[point.offset];
let childNodes = dom.nextSiblings(childNode);
// Remove empty nodes
childNodes = childNodes.filter(func.not(dom.isEmpty));
//console.log('--- childNodes before', childNodes.length);
//childNodes = lists.filter(childNodes, func.not(dom.isEmpty));
//console.log('--- childNodes after', childNodes.length);

const clone = dom.insertAfter(point.node, point.node.cloneNode(false));
dom.appendChildNodes(clone, childNodes);
Expand Down Expand Up @@ -345,6 +347,7 @@ const splitTree = (root, point, options) => {
const rootPred = dom.matchSelector(root);
let parents = dom.parents(point.node, rootPred);
//console.log('splitTree', root.nodeName, point.node.nodeName, parents.length);

if (!parents.length) {
return null;
} else if (parents.length === 1) {
Expand All @@ -357,12 +360,12 @@ const splitTree = (root, point, options) => {
if (ifHasNextSibling && point.offset != 0 && isRightEdgePoint(point)) {
let nestSibling = ifHasNextSibling.nextSibling;
let textNode;
if (nestSibling.nodeType == 1) {
if (dom.isElement(nestSibling)) {
textNode = nestSibling.childNodes[0];
parents = dom.parents(textNode, rootPred);
point = { node: textNode, offset: 0 };
}
else if (nestSibling.nodeType == 3 && !nestSibling.data.match(/[\n\r]/g)) {
else if (dom.isText(nestSibling) && !nestSibling.data.match(/[\n\r]/g)) {
textNode = nestSibling;
parents = dom.parents(textNode, rootPred);
point = { node: textNode, offset: 0 };
Expand Down
10 changes: 8 additions & 2 deletions src/js/core/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,14 @@ const isCellOrCaption = matchNodeNames(['TD', 'TH', 'CAPTION']);
const isMedia = matchNodeNames(['VIDEO', 'AUDIO', 'OBJECT', 'EMBED']);
const isHeading = matchSchemaMap(schema.getHeadingElements());
const isPara = (node) => Obj.has(schema.getTextBlockElements(), node.nodeName) && !isEditableRoot(node);
const isPurePara = (node) => isPara(node) && !isLi(node);
const isParaNoBlockquote = (node) => isPara(node) && !isBlockquote(node);
const isPurePara = (node) => isParaNoBlockquote(node) && !isLi(node);
const isInline = (node) => schema.isInline(node.nodeName);
const isBlock = (node) => schema.isBlock(node.nodeName);
const isParaInline = (node) => (isText(node) || isInline(node)) && !!closest(node, isPara);
const isParaInlineNoBlockQuote = (node) => (isText(node) || isInline(node)) && !!closest(node, isParaNoBlockquote);
const isBodyInline = (node) => (isText(node) || isInline(node)) && !closest(node, isPara);
const isBodyInlineNoBlockQuote = (node) => (isText(node) || isInline(node)) && !closest(node, isParaNoBlockquote);
const isBodyContainer = (node) => isCell(node) || isBlockquote(node) || isEditableRoot(node);

const isBookmarkNode = func.and(matchNodeName('SPAN'), matchAttributeValue('data-note-type', 'bookmark'))
Expand Down Expand Up @@ -700,7 +703,7 @@ const select = (node, selector) => {
* @param {Function|String} selector - Selector function, string or node.
* @param {boolean} [includeSelf] - Whether to start bubbling with given `node`. Default is true.
*/
const closest = (node, selector, includeSelf = true, parentSelector = null) => {
const closest = (node, selector, includeSelf = true) => {
node = getNode(includeSelf ? node : node.parentNode);
if (node) {
const pred = matchSelector(selector);
Expand Down Expand Up @@ -1189,13 +1192,16 @@ export default {
isWhiteSpace,
findPara,
isPurePara,
isParaNoBlockquote,
isHeading,
isInline,
isInlineOrText: func.or(isInline, isText),
isBlock,
isBodyInline,
isBodyInlineNoBlockQuote,
isBody,
isParaInline,
isParaInlineNoBlockQuote,
isPre,
isList,
isTable,
Expand Down
1 change: 0 additions & 1 deletion src/js/core/key.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import lists from './lists';
import func from './func';
import Obj from './Obj';

const KEY_MAP = {
Expand Down
9 changes: 4 additions & 5 deletions src/js/core/range.js
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ class WrappedRange {
const endContainer = inline ? dom.getRangeNode(this.endContainer, endOffset - 1) : this.endContainer;

/**
* Excludes start/end text node if they are out side the range
* Excludes start/end text node if they are outside the range
*
* @private
* @param {Array} nodes Nodes to exclude items from.
Expand Down Expand Up @@ -993,7 +993,7 @@ class WrappedRange {
* - chrome: <p>|text|</p>
*/
const rng = this.normalize();
if (dom.isParaInline(this.sc) || dom.isPara(this.sc)) {
if (dom.isParaInlineNoBlockQuote(this.sc) || dom.isParaNoBlockquote(this.sc)) {
return rng;
}

Expand All @@ -1004,16 +1004,15 @@ class WrappedRange {
topAncestor = lists.last(ancestors);
if (dom.isBlock(topAncestor)) {
topAncestor = ancestors[ancestors.length - 2] || rng.sc.childNodes[rng.so];
//console.log('wrapBodyInlineWithPara topAncestor', topAncestor);
}
} else {
topAncestor = rng.sc.childNodes[rng.so > 0 ? rng.so - 1 : 0];
}

if (topAncestor) {
// siblings not in paragraph
let inlineSiblings = dom.prevSiblings(topAncestor, dom.isParaInline).reverse();
inlineSiblings = inlineSiblings.concat(dom.nextSiblings(topAncestor.nextSibling, dom.isParaInline));
let inlineSiblings = dom.prevSiblings(topAncestor, dom.isParaInlineNoBlockQuote).reverse();
inlineSiblings = inlineSiblings.concat(dom.nextSiblings(topAncestor.nextSibling, dom.isParaInlineNoBlockQuote));

// wrap with paragraph
if (inlineSiblings.length) {
Expand Down
1 change: 1 addition & 0 deletions src/js/core/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ const headings = 'h1 h2 h3 h4 h5 h6';
const headingElementsMap = createLookupTable('heading_elements', headings);
const textBlockElementsMap = createLookupTable('text_block_elements', headings + ' p div li address pre form ' +
'blockquote center dir fieldset header footer article section hgroup aside main nav figure');
//const textBlockElementsMap = createLookupTable('text_block_elements', headings + ' p div li');
const blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' +
'th tr td li ol ul caption dl dt dd noscript menu isindex option ' +
'datalist select optgroup figcaption details summary html body multicol listing', textBlockElementsMap);
Expand Down
6 changes: 3 additions & 3 deletions src/js/editing/Bullet.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default class Bullet {
rng = rng || this.selection.getRange();
rng = rng.wrapBodyInlineWithPara();

const paras = rng.nodes(dom.isPara, { includeAncestor: true });
const paras = rng.nodes(dom.isParaNoBlockquote, { includeAncestor: true });
const clustereds = lists.clusterBy(paras, 'parentNode');

lists.each(clustereds, (paras) => {
Expand Down Expand Up @@ -69,7 +69,7 @@ export default class Bullet {
rng = rng || this.selection.getRange();
rng = rng.wrapBodyInlineWithPara();

const paras = rng.nodes(dom.isPara, { includeAncestor: true });
const paras = rng.nodes(dom.isParaNoBlockquote, { includeAncestor: true });
const clustereds = lists.clusterBy(paras, 'parentNode');

lists.each(clustereds, (paras) => {
Expand Down Expand Up @@ -98,7 +98,7 @@ export default class Bullet {
rng = rng || this.selection.getRange();
rng = rng.wrapBodyInlineWithPara();

let paras = rng.nodes(dom.isPara, { includeAncestor: true });
let paras = rng.nodes(dom.isParaNoBlockquote, { includeAncestor: true });
const bookmark = rng.createParaBookmark(paras);
const clustereds = lists.clusterBy(paras, 'parentNode');

Expand Down
10 changes: 6 additions & 4 deletions src/js/editing/Typing.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import $ from 'jquery';
import dom from '../core/dom';
import lists from '../core/lists';
import func from '../core/func';
import range from '../core/range';
import Point from '../core/Point';
import Bullet from '../editing/Bullet';
Expand Down Expand Up @@ -55,9 +57,9 @@ export default class Typing {

// Wrap range if it needs to be wrapped by paragraph
rng = rng.wrapBodyInlineWithPara();

// finding paragraph
const splitRoot = dom.closest(rng.sc, dom.isPara);
const splitRoot = dom.closest(rng.sc, dom.isParaNoBlockquote);

let nextPara;
// on paragraph: split paragraph
Expand All @@ -71,7 +73,7 @@ export default class Typing {
else {
let blockquote = null;
if (this.options.blockquoteBreakingLevel === 1) {
blockquote = dom.ancestor(splitRoot, dom.isBlockquote);
blockquote = dom.closest(splitRoot, dom.isBlockquote);
} else if (this.options.blockquoteBreakingLevel === 2) {
blockquote = dom.farthestParent(splitRoot, dom.isBlockquote);
}
Expand Down Expand Up @@ -99,7 +101,7 @@ export default class Typing {
let emptyAnchors = dom.children(splitRoot, dom.isEmptyAnchor);
emptyAnchors = emptyAnchors.concat(dom.children(nextPara, dom.isEmptyAnchor));

$.each(emptyAnchors, (idx, anchor) => {
lists.each(emptyAnchors, (anchor) => {
dom.remove(anchor);
});

Expand Down
4 changes: 2 additions & 2 deletions src/js/module/Buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export default class Buttons {
colorsName: this.options.colorsName,
eventName: $holder.data('event'),
container: this.options.container,
tooltip: this.options.tooltip,
//tooltip: this.options.tooltip,
}).render());
});
/* TODO: do we have to record recent custom colors within cookies? */
Expand All @@ -173,7 +173,7 @@ export default class Buttons {
colorsName: customColors,
eventName: $holder.data('event'),
container: this.options.container,
tooltip: this.options.tooltip,
//tooltip: this.options.tooltip,
}).render());
});
$dropdown.find('input[type=color]').each((idx, item) => {
Expand Down
16 changes: 12 additions & 4 deletions src/js/module/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -722,9 +722,13 @@ export default class Editor {
*/
tab() {
const rng = this.selection.getRange();
if (rng.collapsed && rng.isOnCell()) {
if (rng.isOnList()) {
this.indent(rng);
}
else if (rng.collapsed && rng.isOnCell()) {
this.table.tab(rng);
} else {
}
else {
if (this.options.tabSize === 0) {
return false;
}
Expand All @@ -742,9 +746,13 @@ export default class Editor {
*/
untab() {
const rng = this.selection.getRange();
if (rng.collapsed && rng.isOnCell()) {
if (rng.isOnList()) {
this.outdent(rng);
}
else if (rng.collapsed && rng.isOnCell()) {
this.table.tab(rng, true);
} else {
}
else {
if (this.options.tabSize === 0) {
return false;
}
Expand Down
34 changes: 21 additions & 13 deletions src/styles/sm/summernote-sm.scss
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ $img-margin-right: 10px;
flex-direction: column;
row-gap: 8px;
margin: 0;
width: 160px;
//width: 160px;
}

.note-palette-title {
Expand All @@ -288,10 +288,6 @@ $img-margin-right: 10px;
width: 100%;
}

.note-color-row {
height: 20px;
}

.note-color-select-btn {
display: none;
}
Expand All @@ -301,11 +297,21 @@ $img-margin-right: 10px;
}

.note-color-palette {
--note-color-gap: 4px;
--note-color-size: 16px;
line-height: 1;
display: flex;
flex-flow: column;
row-gap: var(--note-color-gap);

.note-color-row {
display: flex;
column-gap: var(--note-color-gap);
}

.note-color-btn {
width: 20px;
height: 20px;
width: var(--note-color-size);
height: var(--note-color-size);
padding: 0;
margin: 0;
border: 0;
Expand Down Expand Up @@ -548,8 +554,9 @@ $img-margin-right: 10px;

.note-toolbar {
$btn-height: calc((#{$btn-line-height-sm} * 1em) + (#{$btn-padding-y-sm} * 2) + (#{$btn-border-width} * 2));
$btn-height: 32.56px;
--note-toolbar-gap: 5px;
--note-toolbar-rowheight: calc(#{$btn-height} + (var(--note-toolbar-gap) * 2) - 1px);
--note-toolbar-rowheight: calc(#{$btn-height} + (var(--note-toolbar-gap) * 2));

margin: 0;
flex-direction: row;
Expand Down Expand Up @@ -626,11 +633,12 @@ $img-margin-right: 10px;
--btn-active-color: var(--primary-text-emphasis);
--btn-active-border-color: transparent;
--btn-active-shadow: none;
}

&:active {
--btn-active-bg: var(--primary-bg-subtle);
--btn-active-border-color: rgba(var(--primary-rgb), 0.3);
}
.note-btn:active,
.note-btn-group.show>.note-btn {
--btn-active-bg: var(--primary-bg-subtle) !important;
--btn-active-border-color: rgba(var(--primary-rgb), 0.3) !important;
}
}

Expand Down Expand Up @@ -687,7 +695,7 @@ $img-margin-right: 10px;
.note-color-all>.note-dropdown-menu {
min-width: auto;
padding: 12px;
column-gap: 8px;
column-gap: 16px;

&.show {
display: flex;
Expand Down
4 changes: 2 additions & 2 deletions test/base/core/dom.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ describe('base:core.dom', () => {
});

it('should return [$b, $u, $s, $i] from b to i', () => {
let result = dom.parentsWhile($b[0], (node) => {
let result = dom.parents($b[0], (node) => {
return node === $i[0];
});
expect(result).to.deep.equal([$b[0], $u[0], $s[0], $i[0]]);
});

it('should return [$u, $s] from u to s', () => {
let result = dom.parentsWhile($u[0], (node) => {
let result = dom.parents($u[0], (node) => {
return node === $s[0];
});
expect(result).to.deep.equal([$u[0], $s[0]]);
Expand Down
12 changes: 9 additions & 3 deletions test/base/module/Buttons.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ import Context from '@/js/Context';
import '@/styles/lite/summernote-lite';

describe('Buttons', () => {
var context, $toolbar, $editable;
var context, selection, $toolbar, $editable;

beforeEach(() => {
$('body').empty(); // important !
document.getSelection()?.removeAllRanges();

var $note = $('<div><p>hello</p></div>').appendTo('body');

var options = $.extend({}, $.summernote.options);
options.icons.eraser = 'note-icon-eraser';
options.toolbar = [
['font1', ['style', 'clear']],
['font2', ['bold', 'underline', 'italic', 'superscript', 'subscript', 'strikethrough']],
Expand All @@ -31,13 +34,16 @@ describe('Buttons', () => {
['view', ['fullscreen', 'codeview', 'help']],
];
context = new Context($note, options);
context.initialize();
//context.initialize();

$toolbar = context.layoutInfo.toolbar;
$editable = context.layoutInfo.editable;

selection = context.modules.editor.selection;

// Select the first paragraph
range.createFromNode($editable.find('p')[0]).normalize().select();
//range.createFromNode($editable.find('p')[0]).normalize().select();
selection.setRange(range.createFromNode($editable.find('p')[0]).normalize());

// [workaround]
// - IE8~11 can't create range in headless mode
Expand Down
Loading

0 comments on commit 971a522

Please sign in to comment.