Skip to content

Commit

Permalink
Sticky toolbar
Browse files Browse the repository at this point in the history
  • Loading branch information
muratcakir committed Dec 11, 2024
1 parent 8bc92b1 commit 72e8f96
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 40 deletions.
5 changes: 4 additions & 1 deletion examples/summernote-sm.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@
<link rel="stylesheet" href="/src/styles/sm/css/admin-theme.css" />
<link rel="stylesheet" href="/src/styles/sm/css/codemirror-custom.css" />
</head>
<body>
<body style="height: 2000px; xpadding-top: 80px">
<div class="d-none bg-white d-flex align-items-center justify-content-center" style="z-index: 1070; position: fixed; height: 80px; top: 0; width: 100%; border-bottom: 1px solid #e9e9e9;">
<h3 class="m-0">Sticky Header</h3>
</div>
<div class="container py-4">
<h1>Summernote with Smartstore Bootstrap & CodeMirror</h1>
<p>
Expand Down
2 changes: 1 addition & 1 deletion src/js/editing/Selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ export default class Selection {
let endContainer = rng.endContainer;
let node = rng.commonAncestorContainer;

// Handle selection a image or other control like element such as anchors
// Handle selection an image or other control like element such as anchors
if (!rng.collapsed) {
if (startContainer === endContainer) {
if (endOffset - startOffset < 2) {
Expand Down
41 changes: 28 additions & 13 deletions src/js/fmt/MatchFormat2.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const matchesUnInheritedFormatSelector = (editor, node, name) => {
for (let i = 0; i < formatList.length; i++) {
const format = formatList[i];
if (FormatUtils.isSelectorFormat(format) && format.inherit === false && dom.matches(node, format.selector)) {
return true;
return { node, format };
}
}
}
Expand All @@ -20,15 +20,24 @@ const matchesUnInheritedFormatSelector = (editor, node, name) => {

const matchParents = (editor, node, name, vars = null) => {
// Find first node with similar format settings
const matchedNode = dom.closest(node, (elm) => {
if (matchesUnInheritedFormatSelector(editor, elm, name)) {
let matchedFormat;
let matchedNode = dom.closest(node, (elm) => {
let match = matchesUnInheritedFormatSelector(editor, elm, name);
if (match) {
matchedFormat = match.format;
return true;
}

return !!matchNode(editor, elm, name, vars);
match = matchNode(editor, elm, name, vars);
if (match) {
matchedFormat = match.format;
return true;
}

return false;
});

return matchedNode;
return !!matchedNode ? { node: matchedNode, format: matchedFormat } : undefined;
};

const matchName = (node, format) => {
Expand Down Expand Up @@ -104,23 +113,26 @@ const matchNode = (editor, node, name, vars = null) => {
};

if (formatList && dom.isElement(node)) {
let isMatch;

// Check each format in list
for (let i = 0; i < formatList.length; i++) {
const format = formatList[i];

// Custom match
if (Type.isFunction(format.onmatch)) {
// onmatch is generic in a way that we can't really express without casting
return format.onmatch(node, format);
isMatch = format.onmatch(node, format);
return isMatch ? { node, format } : undefined;
}

// Match name, attributes, styles and classes
if (matchName(node, format) && matchItems(node, format, 'attributes', vars)) {
const stylesMatch = matchItems(node, format, 'styles', vars);
const isMatch = format.compound ? stylesMatch && classesMatch(format) : stylesMatch || classesMatch(format);
isMatch = format.compound ? stylesMatch && classesMatch(format) : stylesMatch || classesMatch(format);

if (isMatch) {
return format;
return { node, format };
}
}
}
Expand All @@ -135,11 +147,14 @@ const match = (editor, node, name, vars = null) => {
return matchParents(editor, node, name, vars);
}

// // Check selected node
// node = editor.selection.getNode();
// if (matchParents(editor, node, name, vars)) {
// return true;
// }
// Check selected start node
//node = editor.selection.getNode();
node = editor.selection.getRange().startContainer;

let match = matchParents(editor, node, name, vars);
if (match) {
return match;
}

// // Check start node if it's different
// const startNode = editor.selection.getStart();
Expand Down
40 changes: 15 additions & 25 deletions src/js/module/Toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,46 +68,36 @@ export default class Toolbar {

const editorHeight = this.$editor.outerHeight();
const editorWidth = this.$editor.width();
const toolbarHeight = this.$toolbar.height();
const statusbarHeight = this.$statusbar.height();
// const toolbarHeight = this.$toolbar.outerHeight();
// const statusbarHeight = this.$statusbar.outerHeight();

// check if the web app is currently using another static bar
let otherBarHeight = 0;
if (this.options.otherStaticBar) {
otherBarHeight = $(this.options.otherStaticBar).outerHeight();
}

let stickyOffset = parseInt(window.getComputedStyle(document.body).getPropertyValue('--content-offset') || 0);

const currentOffset = this.$document.scrollTop();
const editorOffsetTop = this.$editor.offset().top;
const editorOffsetBottom = editorOffsetTop + editorHeight;
const activateOffset = editorOffsetTop - otherBarHeight;
const deactivateOffsetBottom = editorOffsetBottom - otherBarHeight - toolbarHeight - statusbarHeight;
const activateOffset = editorOffsetTop - otherBarHeight - stickyOffset;
const deactivateOffsetBottom = editorOffsetBottom - otherBarHeight - stickyOffset;

if (!this.isFollowing &&
(currentOffset > activateOffset && currentOffset < deactivateOffsetBottom)) {

if (!this.isFollowing &&
(currentOffset > activateOffset) && (currentOffset < deactivateOffsetBottom - toolbarHeight)) {
this.isFollowing = true;
this.$editable.css({
marginTop: this.$toolbar.outerHeight(),
});
this.$toolbar.css({
//position: 'fixed',
position: 'sticky',
top: otherBarHeight,
//width: editorWidth,
zIndex: 1000,
this.$toolbar.addClass('note-toolbar-sticky').css({
top: stickyOffset,
width: editorWidth
});
} else if (this.isFollowing &&
}
else if (this.isFollowing &&
((currentOffset < activateOffset) || (currentOffset > deactivateOffsetBottom))) {
this.isFollowing = false;
this.$toolbar.css({
position: 'relative',
top: 0,
//width: '100%',
zIndex: 'auto',
});
this.$editable.css({
marginTop: '',
});
this.$toolbar.removeClass('note-toolbar-sticky').css({ top: '', bottom: '', width: '' });
}
}

Expand Down
15 changes: 15 additions & 0 deletions src/styles/sm/summernote-sm.scss
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ $img-margin-right: 10px;
@include border-top-radius($input-border-radius);
@include border-bottom-radius($input-border-radius);

--note-sticky-toolbar-zindex: #{$zindex-sticky - 1};

&:focus-within,
&:focus,
&.focus {
Expand Down Expand Up @@ -200,6 +202,13 @@ $img-margin-right: 10px;
border-color: $note-border-color !important;
z-index: $zindex-tooltip !important;

> .note-toolbar {
position: relative !important;
z-index: auto !important;
top: 0 !important;
width: 100% !important;
}

.note-resizebar {
display: none;
}
Expand Down Expand Up @@ -586,6 +595,12 @@ $img-margin-right: 10px;
}
}

&.note-toolbar-sticky {
// Main toolbar
position: sticky;
z-index: var(--note-sticky-toolbar-zindex);
}

&:not(.dropdown-menu) {
display: flex;
}
Expand Down

0 comments on commit 72e8f96

Please sign in to comment.