diff --git a/dist/embed/iframe.html b/dist/embed/iframe.html index 55ee4b7c9b..6b39ba5cd1 100644 --- a/dist/embed/iframe.html +++ b/dist/embed/iframe.html @@ -21,6 +21,7 @@ .twitter-tweet, .instagram-media { margin: 0px !important; display: inline-flex !important; } .gist-file { margin: 0px !important; } + .cp_embed_iframe { border: 0px !important; } html.align1 .twitter-tweet, body.align1 .instagram-media { justify-content: center; } html.align2 .twitter-tweet, body.align2 .instagram-media { justify-content: flex-end; } diff --git a/electron.js b/electron.js index 1ef0865170..943078ea56 100644 --- a/electron.js +++ b/electron.js @@ -144,8 +144,6 @@ function createWindow () { console.error('[Api] method not defined:', cmd); }; }); - - }; app.on('ready', () => { diff --git a/electron/js/window.js b/electron/js/window.js index 1716c748a3..cb28310aa6 100644 --- a/electron/js/window.js +++ b/electron/js/window.js @@ -62,10 +62,9 @@ class WindowManager { win.on('enter-full-screen', () => Util.send(win, 'enter-full-screen')); win.on('leave-full-screen', () => Util.send(win, 'leave-full-screen')); - win.webContents.on('context-menu', (e, param) => Util.send(win, 'spellcheck', param)); - - Api.setSpellingLang(win, languages); - Api.setZoom(win, zoom); + win.webContents.on('context-menu', (e, param) => { + Util.send(win, 'spellcheck', param.misspelledWord, param.dictionarySuggestions, param.x, param.y, param.selectionRect); + }); if (hideMenuBar) { win.setMenuBarVisibility(false); diff --git a/electron/json/cors.json b/electron/json/cors.json index 5f52ae2f3e..e194015389 100644 --- a/electron/json/cors.json +++ b/electron/json/cors.json @@ -46,7 +46,11 @@ "https://*.fbcdn.net", "https://static.cdninstagram.com", "https://telegram.org", - "https://github.githubassets.com" + "https://github.githubassets.com", + "https://cpwebassets.codepen.io", + "https://cdnjs.cloudflare.com", + "https://*.bilibili.com", + "https://s1.hdslb.com" ], "font-src": [ @@ -99,7 +103,16 @@ "https://*.reddit.com", "https://www.instagram.com", "https://t.me", - "https://gist.github.com" + "https://gist.github.com", + "https://codepen.io", + "https://www.facebook.com", + "https://*.bilibili.com", + "https://*.bilibili.tv", + "https://*.bilivideo.cn:*", + "https://*.bilivideo.com", + "https://*.hdslb.com", + "wss://*.bilibili.com:*", + "wss://*.biliapi.net" ], "script-src-elem": [ @@ -128,7 +141,11 @@ "https://static.cdninstagram.com", "https://telegram.org", "https://oauth.tg.dev", - "https://gist.github.com" + "https://gist.github.com", + "https://cpwebassets.codepen.io", + "https://codepen.io", + "https://cdnjs.cloudflare.com", + "https://*.hdslb.com" ], "frame-src": [ @@ -147,7 +164,10 @@ "https://embed.reddit.com", "https://www.facebook.com", "https://www.instagram.com", - "https://t.me" + "https://t.me", + "https://codepen.io", + "https://cdpn.io", + "https://*.bilibili.com" ], "worker-src": [ diff --git a/src/json/text.json b/src/json/text.json index cac10af606..1e02e48056 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -459,6 +459,8 @@ "blockDataviewCreateNew": "Create new Object", "blockDataviewCreateNewCollection": "Create new Collection", "blockDataviewCreateNewSet": "Create new Set", + "blockDataviewCreateNewTooltipCollection": "Create new Object in this Collection", + "blockDataviewCreateNewTooltipType": "Create new %s object", "blockDataviewShowTemplates": "Show Templates", "blockDataviewSearch": "Search", diff --git a/src/scss/block/bookmark.scss b/src/scss/block/bookmark.scss index a832d777dd..4de3c766e8 100644 --- a/src/scss/block/bookmark.scss +++ b/src/scss/block/bookmark.scss @@ -28,8 +28,8 @@ .archive { position: absolute; right: 10px; top: 10px; z-index: 1; } } - .inner.vertical { display: flex; flex-direction: column-reverse; } - .inner.vertical { + .inner.isVertical { display: flex; flex-direction: column-reverse; } + .inner.isVertical { .side.left { width: 100%; border-radius: 0px; } .side.right { aspect-ratio: 7/3; width: 100%; border-radius: 0px; border-bottom: 0.05em solid $colorShapeSecondary; } } @@ -40,7 +40,7 @@ .side.right { width: 28%; min-height: 90px; display: block; position: relative; overflow: hidden; } } - .inner.withImage.vertical { + .inner.withImage.isVertical { .side.left { width: 100%; } .side.right { width: 100%; } } diff --git a/src/scss/block/dataview.scss b/src/scss/block/dataview.scss index 7977a64328..1989a9c15f 100644 --- a/src/scss/block/dataview.scss +++ b/src/scss/block/dataview.scss @@ -92,7 +92,7 @@ > .sides { gap: 0px 16px; display: flex; flex-direction: row; align-items: center; justify-content: stretch; width: 100%; } > .sides { > .side { padding: 15px 0px; white-space: nowrap; line-height: 28px; display: flex; flex-direction: row; align-items: center; } - > .side.left { flex-grow: 1; padding-left: 14px; } + > .side.left { flex-grow: 1; padding-left: 14px; max-width: 100%; } > .side.right { flex-shrink: 0; gap: 0px 4px; justify-content: flex-end; } > .side.right { .filter { color: $colorTextPrimary; padding: 0px; } @@ -253,11 +253,6 @@ .icon.plus:hover { background-color: transparent; } } .dataviewControls::after { display: none !important; } - .dataviewControls.active { - > .sides { - > .side.right { opacity: 1; } - } - } .dataviewSelection { .side.left { @include text-paragraph; } @@ -268,6 +263,12 @@ } } + .block.blockDataview.isInline.isVertical { + .dataviewControls { + > .sides { flex-direction: column; align-items: flex-start; justify-content: flex-start; } + } + } + .block.blockDataview.showMenu { .dataviewHead { .icon.source { opacity: 1; } diff --git a/src/scss/block/dataview/view/graph.scss b/src/scss/block/dataview/view/graph.scss index 2d521a8e57..9b01a195d9 100644 --- a/src/scss/block/dataview/view/graph.scss +++ b/src/scss/block/dataview/view/graph.scss @@ -11,4 +11,8 @@ canvas.move { cursor: move; } } } + + .block.blockDataview.isInline { + .viewContent.viewGraph { height: 500px; } + } } \ No newline at end of file diff --git a/src/scss/block/featured.scss b/src/scss/block/featured.scss index 30e68e73cb..3a084f2723 100644 --- a/src/scss/block/featured.scss +++ b/src/scss/block/featured.scss @@ -44,7 +44,10 @@ } .cellContent.c-select { - .over { display: inline-flex; gap: 6px; align-items: center; } + .over { display: inline; } + .tagItem { margin: 0px 6px 0px 0px; vertical-align: middle; } + .tagItem:last-child { margin-right: 0px; } + .tagItem.isStatus { line-height: 16px; } .more { margin: 0px; vertical-align: middle; } } diff --git a/src/scss/block/link.scss b/src/scss/block/link.scss index 58df971dea..26bfd06fd6 100644 --- a/src/scss/block/link.scss +++ b/src/scss/block/link.scss @@ -69,7 +69,7 @@ .iconObject { position: absolute; left: 16px; top: 15px; background-color: $colorShapeTertiary; border-radius: 10px; } } - .linkCard.c48.withIcon.withCover.vertical { + .linkCard.c48.withIcon.withCover.isVertical { .sides { min-height: 62px; } .side.left { padding: 24px 16px 16px 16px; z-index: 10; } .iconObject { top: -32px; transform: none; } @@ -81,18 +81,18 @@ .side.right { width: 28%; display: block; border: 1px solid $colorShapeSecondary; border-left: 0px; } } - .linkCard.vertical { display: block; } - .linkCard.vertical { + .linkCard.isVertical { display: block; } + .linkCard.isVertical { .sides { flex-direction: column-reverse; } .side.left { width: 100%; border-right-width: 1px; } .side.right { aspect-ratio: 7/3; width: 100%; border-radius: 12px 12px 0px 0px !important; border: 1px solid $colorShapeSecondary; border-bottom: 0px; } } - .linkCard.withCover.vertical { + .linkCard.withCover.isVertical { .side.left { border-radius: 0px 0px 12px 12px !important; } } - .linkCard.withCover.vertical.text { padding-top: 0px; } + .linkCard.withCover.isVertical.text { padding-top: 0px; } } .block.blockLink.text { diff --git a/src/scss/block/text.scss b/src/scss/block/text.scss index f75ef85beb..12aa687fb7 100644 --- a/src/scss/block/text.scss +++ b/src/scss/block/text.scss @@ -12,47 +12,47 @@ smile * { display: inline; vertical-align: middle; } smile .loaderWrapper { display: inline-block; } - markupCode { + markupcode { display: inline; font-family: 'Plex'; border-radius: 4px; background: $colorShapeSecondary; padding: 2px 4px; } - markupEmoji { display: inline; user-select: all; } - markupEmoji * { user-select: all; } - markupEmoji { + markupemoji { display: inline; user-select: all; } + markupemoji * { user-select: all; } + markupemoji { smile img { vertical-align: top; } } - markupLink { position: relative; } - markupLink, markupObject { color: inherit; text-decoration: none; border-bottom: 0.075em solid; transition: border-color $transitionCommon; cursor: default; } - markupLink.disabled, markupObject.disabled { border-width: 0px; } + markuplink { position: relative; } + markuplink, markupobject { color: inherit; text-decoration: none; border-bottom: 0.075em solid; transition: border-color $transitionCommon; cursor: default; } + markuplink.disabled, markupobject.disabled { border-width: 0px; } - markupMention { display: inline; user-select: all !important; position: relative; cursor: default; } - markupMention * { user-select: text !important; } - markupMention { + markupmention { display: inline; user-select: all !important; position: relative; cursor: default; } + markupmention * { user-select: text !important; } + markupmention { smile { display: none; position: relative; z-index: 1; } .space { width: 6px; height: 20px; margin-top: -4px; vertical-align: middle; display: none; } name { display: inline; white-space: normal; position: relative; border-bottom: 0.075em solid; border-color: inherit; } } - markupMention.disabled { + markupmention.disabled { name { border-width: 0px; } } - markupMention.withImage { + markupmention.withImage { smile { display: inline; } .space { display: inline; } } - markupMention.withImage.c24 name markupBgcolor:first-child { margin-left: -22px; padding-left: 22px; } - markupMention.withImage.c26 name markupBgcolor:first-child { margin-left: -22px; padding-left: 22px; } - markupMention.withImage.c28 name markupBgcolor:first-child { margin-left: -27px; padding-left: 27px; } - markupMention.withImage.c32 name markupBgcolor:first-child { margin-left: -34px; padding-left: 34px; } - markupMention:hover { + markupmention.withImage.c24 name markupBgcolor:first-child { margin-left: -22px; padding-left: 22px; } + markupmention.withImage.c26 name markupBgcolor:first-child { margin-left: -22px; padding-left: 22px; } + markupmention.withImage.c28 name markupBgcolor:first-child { margin-left: -27px; padding-left: 27px; } + markupmention.withImage.c32 name markupBgcolor:first-child { margin-left: -34px; padding-left: 34px; } + markupmention:hover { name::before { border-color: $colorTextPrimary; } } - markupBold { font-weight: 600; } - markupItalic { font-style: italic; } - markupStrike { text-decoration: line-through; } - markupUnderline { border-bottom: 0.05em solid; } + markupbold { font-weight: 600; } + markupitalic { font-style: italic; } + markupstrike { text-decoration: line-through; } + markupunderline { border-bottom: 0.05em solid; } .markers { display: flex; padding: 1px 0px; } .markers { diff --git a/src/scss/menu/block/common.scss b/src/scss/menu/block/common.scss index afe8268731..2fe13d2703 100644 --- a/src/scss/menu/block/common.scss +++ b/src/scss/menu/block/common.scss @@ -24,43 +24,27 @@ .content { padding: 0px; } .wrap { height: 100%; } .items { height: 100%; } - .item.empty { padding: 14px; } .sectionName { padding: 0px 14px 4px 14px; } .sectionName::before { content: ""; display: block; width: 100%; height: 1px; margin: 8px 0px 11px 0px; background: $colorShapeSecondary; } .sectionName.first { padding-top: 4px; } .sectionName.first::before { display: none; } - .item { padding: 4px 16px; } - .item.add { padding: 6px 16px; } - .item.sides { display: flex; padding: 6px 16px; } - .info { width: 154px; @include text-overflow-nw; line-height: 20px; border-radius: 4px; transition: background $transitionCommon; flex-shrink: 0; margin-right: 6px; } - .cell { width: calc(100% - 160px); white-space: nowrap; } - .cell.c-select { - .tagItem { margin-bottom: 0px; vertical-align: middle; } - } + .item { padding: 4px 16px; } + .item.add { padding: 6px 16px; } + .item.sides { display: flex; padding: 6px 16px; } + .item.empty { padding: 16px; } .item { .icon.plus { margin-right: 4px; background-image: url('~img/icon/plus/menu0.svg'); } } - .item * { } .item::before { transition: none; } - .cellContent { overflow: hidden; height: 20px; line-height: 20px; } - .cellContent { - .empty { display: block; } - } - - .cellContent.c-longText { - .name { -webkit-line-clamp: 1; -webkit-box-orient: vertical; display: -webkit-box; } - } - } - .menu.menuBlockAdd { .item.isBig { .iconObject { background-color: $colorShapeTertiary; } } @@ -105,7 +89,19 @@ .icon.collection { background-image: url('~img/icon/menu/action/block/collection1.svg'); } } - .icon.arrow { width: 20px !important; height: 20px !important; background-color: unset !important; left: auto !important; top: 50% !important; } + .cell { width: calc(100% - 160px); white-space: nowrap; } + .cell.c-select { + .tagItem { margin-bottom: 0px; vertical-align: middle; } + } + + .cellContent { overflow: hidden; height: 20px; line-height: 20px; } + .cellContent { + .empty { display: block; } + } + + .cellContent.c-longText { + .name { -webkit-line-clamp: 1; -webkit-box-orient: vertical; display: -webkit-box; } + } } } diff --git a/src/scss/theme/dark/block.scss b/src/scss/theme/dark/block.scss index 623f6c9eb9..18778c1a04 100644 --- a/src/scss/theme/dark/block.scss +++ b/src/scss/theme/dark/block.scss @@ -237,6 +237,10 @@ } } + .viewContent.viewGraph { + canvas { background: $colorBgPrimary; } + } + .content { .scrollWrap { background: $colorBgPrimary; } } diff --git a/src/ts/app.tsx b/src/ts/app.tsx index 6017a2ba55..914a108b9e 100644 --- a/src/ts/app.tsx +++ b/src/ts/app.tsx @@ -512,8 +512,8 @@ class App extends React.Component { }); }; - onSpellcheck (e: any, param: any) { - if (!param.misspelledWord) { + onSpellcheck (e: any, misspelledWord: string, dictionarySuggestions: string[], x: number, y: number, rect: any) { + if (!misspelledWord) { return; }; @@ -522,34 +522,60 @@ class App extends React.Component { const win = $(window); const rootId = keyboard.getRootId(); const { focused, range } = focus.state; - const options: any = param.dictionarySuggestions.map(it => ({ id: it, name: it })); - const obj = Mark.cleanHtml($(`#block-${focused} #value`).html()); - const value = String(obj.get(0).innerText || ''); + const options: any = dictionarySuggestions.map(it => ({ id: it, name: it })); + const element = $(document.elementFromPoint(x, y)); + const isInput = element.is('input'); + const isTextarea = element.is('textarea'); + const isEditable = element.is('.editable'); options.push({ id: 'add-to-dictionary', name: translate('spellcheckAdd') }); menuStore.open('select', { + className: 'fromBlock', + classNameWrap: 'fromPopup', recalcRect: () => { - const rect = UtilCommon.getSelectionRect(); return rect ? { ...rect, y: rect.y + win.scrollTop() } : null; }, - onOpen: () => { menuStore.close('blockContext'); }, - onClose: () => { keyboard.disableContextOpen(false); }, + onOpen: () => menuStore.close('blockContext'), + onClose: () => keyboard.disableContextOpen(false), data: { options, onSelect: (e: any, item: any) => { raf(() => { - focus.apply(); - switch (item.id) { default: { - blockStore.updateContent(rootId, focused, { text: value }); - UtilData.blockInsertText(rootId, focused, item.id, range.from, range.to); + if (focused) { + focus.apply(); + + const obj = Mark.cleanHtml($(`#block-${focused} #value`).html()); + const value = String(obj.get(0).innerText || ''); + + blockStore.updateContent(rootId, focused, { text: value }); + UtilData.blockInsertText(rootId, focused, item.id, range.from, range.to); + } else + if (isInput || isTextarea || isEditable) { + let value = ''; + if (isInput || isTextarea) { + value = String(element.val()); + } else + if (isEditable) { + value = String((element.get(0) as any).innerText || ''); + }; +; + value = value.replace(new RegExp(`${misspelledWord}`, 'g'), item.id); + + if (isInput || isTextarea) { + element.val(value); + } else + if (isEditable) { + element.text(value); + }; + }; break; }; case 'add-to-dictionary': { - Renderer.send('spellcheckAdd', param.misspelledWord); + Renderer.send('spellcheckAdd', misspelledWord); break; }; diff --git a/src/ts/component/block/bookmark.tsx b/src/ts/component/block/bookmark.tsx index f55042c640..2dafecfe3e 100644 --- a/src/ts/component/block/bookmark.tsx +++ b/src/ts/component/block/bookmark.tsx @@ -10,7 +10,6 @@ const BlockBookmark = observer(class BlockBookmark extends React.Component { + window.setTimeout(() => { if (!this._isMounted) { return; }; @@ -274,10 +269,8 @@ const BlockBookmark = observer(class BlockBookmark extends React.Component { + refGraph.setRootId(object.id); + }); + }; + }; + if ([ I.ViewType.Calendar ].includes(view.type)) { UtilObject.openPopup(object); } else { @@ -1334,6 +1343,15 @@ const BlockDataview = observer(class BlockDataview extends React.Component { + const { block, getWrapperWidth } = this.props; + + if (getWrapperWidth) { + const node = $(this.node); + const obj = $(`#block-${block.id}`); + + node.width() <= getWrapperWidth() / 2 ? obj.addClass('isVertical') : obj.removeClass('isVertical'); + }; + if (this.refControls && this.refControls.resize) { this.refControls.resize(); }; diff --git a/src/ts/component/block/dataview/controls.tsx b/src/ts/component/block/dataview/controls.tsx index 9a45d5ea4d..f80e3e5cf9 100644 --- a/src/ts/component/block/dataview/controls.tsx +++ b/src/ts/component/block/dataview/controls.tsx @@ -3,7 +3,7 @@ import $ from 'jquery'; import { observer } from 'mobx-react'; import { observable } from 'mobx'; import { Icon, Button, Filter } from 'Component'; -import { C, I, UtilCommon, analytics, Relation, keyboard, translate, UtilObject, UtilMenu } from 'Lib'; +import { C, I, UtilCommon, analytics, Relation, keyboard, translate, UtilObject, UtilMenu, Dataview } from 'Lib'; import { menuStore, dbStore, blockStore } from 'Store'; import { SortableContainer, SortableElement } from 'react-sortable-hoc'; import Head from './head'; @@ -49,6 +49,7 @@ const Controls = observer(class Controls extends React.Component { const isAllowedObject = this.props.isAllowedObject(); const isAllowedTemplate = UtilObject.isAllowedTemplate(getTypeId()) || (target && UtilObject.isSetLayout(target.layout) && hasSources); const cmd = keyboard.cmdSymbol(); + const tooltip = Dataview.getCreateTooltip(rootId, block.id, target.id, view.id); if (isAllowedTemplate) { buttonWrapCn.push('withSelect'); @@ -163,7 +164,7 @@ const Controls = observer(class Controls extends React.Component { onRecordAdd(e, -1)} /> @@ -263,7 +264,6 @@ const Controls = observer(class Controls extends React.Component { } = this.props; const view = getView(); const obj = $(element); - const node = $(this.node); const param: any = { element, @@ -271,12 +271,12 @@ const Controls = observer(class Controls extends React.Component { offsetY: 10, noFlipY: true, onOpen: () => { - node.addClass('active'); obj.addClass('active'); + this.toggleHoverArea(true); }, onClose: () => { - node.removeClass('active'); obj.removeClass('active'); + this.toggleHoverArea(false); }, onBack: (id) => { menuStore.replace(id, component, { ...param, noAnimation: true }); @@ -416,11 +416,14 @@ const Controls = observer(class Controls extends React.Component { return; }; - const { isPopup, isInline } = this.props; + const { block, isPopup, isInline } = this.props; const container = UtilCommon.getPageContainer(isPopup); const win = $(window); + const obj = $(`#block-${block.id}`); + const hoverArea = obj.find('.hoverArea'); this.refFilter.setActive(true); + this.toggleHoverArea(true); if (!isInline) { this.refFilter.focus(); @@ -453,10 +456,19 @@ const Controls = observer(class Controls extends React.Component { this.refFilter.setActive(false); this.refFilter.setValue(''); this.refFilter.blur(); + this.toggleHoverArea(false); this.props.onFilterChange(''); }; + toggleHoverArea (v: boolean) { + const { block } = this.props; + const obj = $(`#block-${block.id}`); + const hoverArea = obj.find('.hoverArea'); + + v ? hoverArea.addClass('active') : hoverArea.removeClass('active'); + }; + resize () { if (!this._isMounted) { return; diff --git a/src/ts/component/block/dataview/view/board/column.tsx b/src/ts/component/block/dataview/view/board/column.tsx index a24c0e5959..29bc73d8a9 100644 --- a/src/ts/component/block/dataview/view/board/column.tsx +++ b/src/ts/component/block/dataview/view/board/column.tsx @@ -33,8 +33,9 @@ const Column = observer(class Column extends React.Component { }; render () { - const { rootId, block, id, getSubId, getView, getLimit, value, onDragStartColumn } = this.props; + const { rootId, block, id, getSubId, getView, getLimit, value, onDragStartColumn, getTarget } = this.props; const view = getView(); + const target = getTarget(); const subId = getSubId(); const items = this.getItems(); const { total } = dbStore.getMeta(subId, ''); @@ -46,6 +47,7 @@ const Column = observer(class Column extends React.Component { const order = (block.content.groupOrder || []).find(it => it.viewId == view.id); const orderGroup = (order?.groups || []).find(it => it.groupId == id) || {}; const isAllowedObject = this.props.isAllowedObject(); + const tooltip = Dataview.getCreateTooltip(rootId, block.id, target.id, view.id); if (view.groupBackgroundColors) { cn.push('withColor'); @@ -92,7 +94,7 @@ const Column = observer(class Column extends React.Component { - {isAllowedObject ? this.onAdd(e, -1)} /> : ''} + {isAllowedObject ? this.onAdd(e, -1)} /> : ''} diff --git a/src/ts/component/block/dataview/view/graph.tsx b/src/ts/component/block/dataview/view/graph.tsx index a3b8508187..eb69bb9193 100644 --- a/src/ts/component/block/dataview/view/graph.tsx +++ b/src/ts/component/block/dataview/view/graph.tsx @@ -28,7 +28,7 @@ const ViewGraph = observer(class ViewGraph extends React.Component this.refGraph = ref} + id={block.id} rootId="" data={this.data} /> @@ -88,10 +89,15 @@ const ViewGraph = observer(class ViewGraph extends React.Component Dataview.filterMapper(view, it)); + if (searchIds) { + filters.push({ operator: I.FilterOperator.And, relationKey: 'id', condition: I.FilterCondition.In, value: searchIds || [] }); + }; + this.setLoading(true); C.ObjectGraph(commonStore.space, filters, 0, [], Constant.graphRelationKeys, (message: any) => { @@ -143,23 +149,25 @@ const ViewGraph = observer(class ViewGraph extends React.Component { const { rootId, block, readonly } = this.props; const root = blockStore.getLeaf(rootId, rootId); - if (readonly || !block.isSelectable() || (block.isText() && (focused == block.id)) || block.isTable()) { + if (readonly || !block.isSelectable() || (block.isText() && (focused == block.id)) || block.isTable() || block.isDataview()) { return; }; diff --git a/src/ts/component/block/link.tsx b/src/ts/component/block/link.tsx index b5e0fa104f..341290db4f 100644 --- a/src/ts/component/block/link.tsx +++ b/src/ts/component/block/link.tsx @@ -362,7 +362,7 @@ const BlockLink = observer(class BlockLink extends React.Component { + if (menuStore.isAnimating(menuContext.props.id)) { + return; + }; + if (!menuContext) { return; }; diff --git a/src/ts/component/menu/block/add.tsx b/src/ts/component/menu/block/add.tsx index 09a373cc35..26573ad3ea 100644 --- a/src/ts/component/menu/block/add.tsx +++ b/src/ts/component/menu/block/add.tsx @@ -7,7 +7,7 @@ import { I, Mark, keyboard, C, focus, Action, UtilCommon, UtilData, UtilMenu, Ut import { blockStore, commonStore, dbStore, menuStore, detailStore, popupStore } from 'Store'; import Constant from 'json/constant.json'; -const HEIGHT_ITEM = 28; +const HEIGHT_ITEM = 32; const HEIGHT_SECTION = 42; const HEIGHT_DESCRIPTION = 56; const HEIGHT_RELATION = 32; diff --git a/src/ts/component/menu/block/context.tsx b/src/ts/component/menu/block/context.tsx index ccd01f6b5a..99c958091c 100644 --- a/src/ts/component/menu/block/context.tsx +++ b/src/ts/component/menu/block/context.tsx @@ -288,12 +288,10 @@ const MenuBlockContext = observer(class MenuBlockContext extends React.Component menuParam.data = Object.assign(menuParam.data, { value: (mark ? mark.param : ''), onChange: (param: string) => { - if (!mark && !param) { - return; + if (param) { + Storage.set(storageKey, param); }; - Storage.set(storageKey, param); - marks = Mark.toggle(marks, { type, param, range: { from, to } }); menuStore.updateData(this.props.id, { marks }); onChange(marks); diff --git a/src/ts/component/page/auth/setup.tsx b/src/ts/component/page/auth/setup.tsx index 108293f2ce..7cd02b741c 100644 --- a/src/ts/component/page/auth/setup.tsx +++ b/src/ts/component/page/auth/setup.tsx @@ -94,7 +94,7 @@ const PageAuthSetup = observer(class PageAuthSetup extends React.Component this.refGraph = ref} + id="global" rootId={rootId} data={this.data} /> diff --git a/src/ts/component/util/graph.tsx b/src/ts/component/util/graph.tsx index 05674692ca..1d14392a28 100644 --- a/src/ts/component/util/graph.tsx +++ b/src/ts/component/util/graph.tsx @@ -9,6 +9,7 @@ import { commonStore, menuStore } from 'Store'; import Constant from 'json/constant.json'; interface Props { + id?: string; isPopup?: boolean; rootId: string; data: any; @@ -39,19 +40,12 @@ const Graph = observer(class Graph extends React.Component { }; render () { - const { isPopup } = this.props; - const id = [ 'graph' ]; - - if (isPopup) { - id.push('popup'); - }; - return ( this.node = node} id="graphWrapper" > - + ); }; @@ -86,15 +80,28 @@ const Graph = observer(class Graph extends React.Component { $(window).off(events.map(it => `${it}.graph`).join(' ')); }; + getId (): string { + const { id, isPopup } = this.props; + const ret = [ 'graph' ]; + + if (id) { + ret.push(id); + }; + if (isPopup) { + ret.push('popup'); + }; + return ret.join('-'); + }; + init () { - const { data, isPopup, rootId } = this.props; + const { data, rootId } = this.props; const node = $(this.node); const density = window.devicePixelRatio; - const elementId = `#graph${isPopup ? '-popup' : ''}`; + const elementId = `#${this.getId()}`; const width = node.width(); const height = node.height(); - - this.zoom = d3.zoom().scaleExtent([ 1, 6 ]).on('zoom', e => this.onZoom(e)); + + this.zoom = d3.zoom().scaleExtent([ 0.2, 10 ]).on('zoom', e => this.onZoom(e)); this.edges = (data.edges || []).map(this.edgeMapper); this.nodes = (data.nodes || []).map(this.nodeMapper); @@ -393,7 +400,7 @@ const Graph = observer(class Graph extends React.Component { this.edges.push(this.edgeMapper({ type: I.EdgeType.Link, source: sourceId, target: targetId })); this.send('onSetEdges', { edges: this.edges }); } else { - this.addNewNode(targetId, target => this.send('onAddNode', { target, sourceId })); + this.addNewNode(targetId, sourceId, null); }; }, onSelect: (itemId: string) => { @@ -449,12 +456,7 @@ const Graph = observer(class Graph extends React.Component { UtilObject.create('', '', {}, I.BlockPosition.Bottom, '', {}, flags, (message: any) => { UtilObject.openPopup({ id: message.targetId }, { - onClose: () => { - this.addNewNode(message.targetId, target => { - target = Object.assign(target, { x: data.x, y: data.y }); - this.send('onAddNode', { target }); - }); - } + onClose: () => this.addNewNode(message.targetId, '', data), }); analytics.event('CreateObject', { objectType: commonStore.type, route: 'Graph' }); @@ -499,12 +501,20 @@ const Graph = observer(class Graph extends React.Component { UtilObject.openAuto(this.nodes.find(d => d.id == id)); }; - addNewNode (id: string, cb: (target: any) => void) { + addNewNode (id: string, sourceId?: string, param?: any, callBack?: (object: any) => void) { UtilObject.getById(id, (object: any) => { object = this.nodeMapper(object); + if (param) { + object = Object.assign(object, param); + }; + this.nodes.push(object); - cb(object); + this.send('onAddNode', { target: object, sourceId }); + + if (callBack) { + callBack(object); + }; }); }; diff --git a/src/ts/interface/block/embed.ts b/src/ts/interface/block/embed.ts index fef26e5443..d7ae5384f0 100644 --- a/src/ts/interface/block/embed.ts +++ b/src/ts/interface/block/embed.ts @@ -18,6 +18,8 @@ export enum EmbedProcessor { Instagram = 13, Telegram = 14, GithubGist = 15, + Codepen = 16, + Bilibili = 17, }; export interface ContentEmbed { diff --git a/src/ts/lib/dataview.ts b/src/ts/lib/dataview.ts index 88c5a667f9..5efd966e2e 100644 --- a/src/ts/lib/dataview.ts +++ b/src/ts/lib/dataview.ts @@ -328,7 +328,6 @@ class Dataview { getTypeId (rootId: string, blockId: string, objectId: string, viewId?: string) { const view = this.getView(rootId, blockId, viewId); - const types = Relation.getSetOfObjects(rootId, objectId, I.ObjectLayout.Type); const relations = Relation.getSetOfObjects(rootId, objectId, I.ObjectLayout.Relation); const isAllowedDefaultType = this.isCollection(rootId, blockId) || !!Relation.getSetOfObjects(rootId, objectId, I.ObjectLayout.Relation).map(it => it.id).length; @@ -359,6 +358,22 @@ class Dataview { return typeId; }; + getCreateTooltip (rootId: string, blockId: string, objectId: string, viewId: string): string { + const isCollection = this.isCollection(rootId, blockId); + + if (isCollection) { + return translate('blockDataviewCreateNewTooltipCollection'); + } else { + const typeId = this.getTypeId(rootId, blockId, objectId, viewId); + const type = dbStore.getTypeById(typeId); + + if (type) { + return UtilCommon.sprintf(translate('blockDataviewCreateNewTooltipType'), type.name); + }; + }; + return translate('blockDataviewCreateNew'); + }; + }; export default new Dataview(); diff --git a/src/ts/lib/mark.ts b/src/ts/lib/mark.ts index e519fc3562..bd81a4623c 100644 --- a/src/ts/lib/mark.ts +++ b/src/ts/lib/mark.ts @@ -3,19 +3,13 @@ import { I, UtilCommon, analytics } from 'Lib'; import Constant from 'json/constant.json'; const Tags = {}; -Tags[I.MarkType.Strike] = 'markupStrike'; -Tags[I.MarkType.Code] = 'markupCode'; -Tags[I.MarkType.Italic] = 'markupItalic'; -Tags[I.MarkType.Bold] = 'markupBold'; -Tags[I.MarkType.Underline] = 'markupUnderline'; -Tags[I.MarkType.Link] = 'markupLink'; -Tags[I.MarkType.Color] = 'markupColor'; -Tags[I.MarkType.BgColor] = 'markupBgcolor'; -Tags[I.MarkType.Mention] = 'markupMention'; -Tags[I.MarkType.Emoji] = 'markupEmoji'; -Tags[I.MarkType.Object] = 'markupObject'; +for (const i in I.MarkType) { + if (isNaN(Number(i))) { + continue; + }; -const LCTags = Object.values(Tags).map(it => String(it).toLowerCase()); + Tags[i] = `markup${I.MarkType[i].toLowerCase()}`; +}; const Patterns = { '-→': '⟶', @@ -461,7 +455,7 @@ class Mark { const end = p1 == '/'; const offset = Number(text.indexOf(s)) || 0; - const type = LCTags.indexOf(p2); + const type = Object.values(Tags).indexOf(p2); if (type < 0) { return; @@ -531,7 +525,8 @@ class Mark { }; if (check) { - marks = this.adjust(marks, from, -p2.length * 2); + marks = this.adjust(marks, from, -p2.length); + marks = this.adjust(marks, to, -p4.length); marks.push({ type: item.type, range: { from, to }, param: '' }); text = text.replace(s, replace); diff --git a/src/ts/lib/scrollOnMove.ts b/src/ts/lib/scrollOnMove.ts index 608c51ac12..03589c77f2 100644 --- a/src/ts/lib/scrollOnMove.ts +++ b/src/ts/lib/scrollOnMove.ts @@ -66,6 +66,7 @@ class ScrollOnMove { const maxScrollX = this.documentWidth - this.viewportWidth; const maxScrollY = this.documentHeight - this.viewportHeight; + let currentScrollX = 0; let currentScrollY = 0; let container; @@ -85,9 +86,10 @@ class ScrollOnMove { const canScrollDown = (currentScrollY < maxScrollY); const canScrollLeft = (currentScrollX > 0); const canScrollRight = (currentScrollX < maxScrollX); + const maxStep = 10; + let nextScrollX = currentScrollX; let nextScrollY = currentScrollY; - const maxStep = 10; let intensity = 0; if (isInLeftEdge && canScrollLeft) { diff --git a/src/ts/lib/util/data.ts b/src/ts/lib/util/data.ts index 46ed46d2d9..782dc83714 100644 --- a/src/ts/lib/util/data.ts +++ b/src/ts/lib/util/data.ts @@ -421,7 +421,7 @@ class UtilData { const diff = needle.length - (to - from); const text = UtilCommon.stringInsert(block.content.text, needle, from, to); - const marks = Mark.adjust(block.content.marks, 0, diff); + const marks = Mark.adjust(block.content.marks, from, diff); this.blockSetText(rootId, blockId, text, marks, true, callBack); }; diff --git a/src/ts/lib/util/embed.ts b/src/ts/lib/util/embed.ts index b837f97421..c2caecc2d0 100644 --- a/src/ts/lib/util/embed.ts +++ b/src/ts/lib/util/embed.ts @@ -1,7 +1,7 @@ import { I, UtilCommon } from 'Lib'; import Constant from 'json/constant.json'; -const DOMAINS: any = {}; +const DOMAINS: any = {}; DOMAINS[I.EmbedProcessor.Youtube] = [ 'youtube.com', 'youtu.be' ]; DOMAINS[I.EmbedProcessor.Vimeo] = [ 'vimeo.com' ]; DOMAINS[I.EmbedProcessor.GoogleMaps] = [ 'google.[^\/]+/maps' ]; @@ -9,13 +9,15 @@ DOMAINS[I.EmbedProcessor.Miro] = [ 'miro.com' ]; DOMAINS[I.EmbedProcessor.Figma] = [ 'figma.com' ]; DOMAINS[I.EmbedProcessor.OpenStreetMap] = [ 'openstreetmap.org\/\#map' ]; DOMAINS[I.EmbedProcessor.Telegram] = [ 't.me' ]; +DOMAINS[I.EmbedProcessor.Codepen] = [ 'codepen.io' ]; +DOMAINS[I.EmbedProcessor.Bilibili] = [ 'bilibili.com', 'b23.tv']; const IFRAME_PARAM = 'frameborder="0" scrolling="no" allowfullscreen'; class UtilEmbed { getHtml (processor: I.EmbedProcessor, content: any): string { - const fn = UtilCommon.toCamelCase(`get-${I.EmbedProcessor[processor]}-html`) + const fn = UtilCommon.toCamelCase(`get-${I.EmbedProcessor[processor]}-html`); return this[fn] ? this[fn](content) : ''; }; @@ -52,9 +54,24 @@ class UtilEmbed { return ``; }; + getCodepenHtml (content: string): string { + const a = new URL(content); + const p = a.pathname.split('/'); + + if (!p.length) { + return ''; + }; + + return ``; + }; + + getBilibiliHtml (content: string): string { + return ``; + }; + getProcessorByUrl (url: string): I.EmbedProcessor { let p = null; - for (let i in DOMAINS) { + for (const i in DOMAINS) { const reg = new RegExp(DOMAINS[i].join('|'), 'gi'); if (url.match(reg)) { p = Number(i); @@ -132,6 +149,26 @@ class UtilEmbed { break; }; + case I.EmbedProcessor.Bilibili: { + const { pathname, searchParams } = new URL(url); + if (!pathname) { + break; + }; + + const a = pathname.split('/'); + if (a.length < 3) { + return; + }; + + const bvid = pathname.split('/')[2]; + const [ p = 1, t = 0 ] = [ searchParams.get('p'), searchParams.get('t') ]; + + if (bvid) { + url = `https://player.bilibili.com/player.html?bvid=${bvid}&p=${p}&t=${t}&high_quality=1&autoplay=0`; + }; + break; + }; + }; return url; @@ -167,6 +204,11 @@ class UtilEmbed { libs.push('https://www.instagram.com/embed.js'); break; }; + + case I.EmbedProcessor.Codepen: { + libs.push('https://cpwebassets.codepen.io/assets/embed/ei.js'); + break; + }; }; return { @@ -184,6 +226,7 @@ class UtilEmbed { }; }; + // Allow to use same origin in iframe sandbox allowSameOrigin (p: I.EmbedProcessor) { return [ I.EmbedProcessor.Youtube, @@ -196,16 +239,21 @@ class UtilEmbed { I.EmbedProcessor.Reddit, I.EmbedProcessor.Instagram, I.EmbedProcessor.Telegram, + I.EmbedProcessor.Codepen, + I.EmbedProcessor.Bilibili, ].includes(p); }; + // Allow to use presentation mode in iframe sandbox allowPresentation (p: I.EmbedProcessor) { return [ I.EmbedProcessor.Youtube, I.EmbedProcessor.Vimeo, + I.EmbedProcessor.Bilibili ].includes(p); }; + // Allow url embedding allowEmbedUrl (p: I.EmbedProcessor) { return [ I.EmbedProcessor.Youtube, @@ -216,23 +264,29 @@ class UtilEmbed { I.EmbedProcessor.OpenStreetMap, I.EmbedProcessor.Telegram, I.EmbedProcessor.GithubGist, + I.EmbedProcessor.Codepen, + I.EmbedProcessor.Bilibili, ].includes(p); }; + // Pass block data as js code allowJs (p: I.EmbedProcessor) { return [ I.EmbedProcessor.Chart, ].includes(p); }; + // Allow to use popup mode in iframe sandbox allowPopup (p: I.EmbedProcessor) { - return [].includes(p); + return [ I.EmbedProcessor.Bilibili ].includes(p); }; + // Allow block resizing allowBlockResize (p: I.EmbedProcessor) { return ![ I.EmbedProcessor.Latex, I.EmbedProcessor.Mermaid, I.EmbedProcessor.Chart ].includes(p); }; + // Use iframe height instead of fixed aspect ratio allowIframeResize (p: I.EmbedProcessor) { return [ I.EmbedProcessor.Twitter, @@ -241,15 +295,18 @@ class UtilEmbed { I.EmbedProcessor.Instagram, I.EmbedProcessor.Telegram, I.EmbedProcessor.GithubGist, + I.EmbedProcessor.Codepen, ].includes(p); }; + // Render blocks on scroll allowScroll (p: I.EmbedProcessor) { return ![ I.EmbedProcessor.Latex, ].includes(p); }; + // Render blocks on mount allowAutoRender (p: I.EmbedProcessor) { return [ I.EmbedProcessor.Latex, @@ -259,23 +316,29 @@ class UtilEmbed { I.EmbedProcessor.Instagram, I.EmbedProcessor.Telegram, I.EmbedProcessor.GithubGist, + I.EmbedProcessor.Codepen, + I.EmbedProcessor.Bilibili, ].includes(p); }; + // Insert html content before loading libs insertBeforeLoad (p: I.EmbedProcessor) { return [ I.EmbedProcessor.Twitter, I.EmbedProcessor.Reddit, I.EmbedProcessor.Instagram, + I.EmbedProcessor.Codepen, ].includes(p); }; + // Use root height instead of iframe scroll height useRootHeight (p: I.EmbedProcessor) { return [ I.EmbedProcessor.Twitter, I.EmbedProcessor.Telegram, I.EmbedProcessor.Instagram, I.EmbedProcessor.GithubGist, + I.EmbedProcessor.Codepen, ].includes(p); }; diff --git a/src/ts/lib/util/menu.ts b/src/ts/lib/util/menu.ts index 22dd0081ce..66a2dc111c 100644 --- a/src/ts/lib/util/menu.ts +++ b/src/ts/lib/util/menu.ts @@ -30,11 +30,11 @@ class UtilMenu { getBlockText () { return [ { id: I.TextStyle.Paragraph, lang: 'Paragraph' }, - { id: I.TextStyle.Header1, lang: 'Header1', aliases: [ 'h1', 'head1' ] }, - { id: I.TextStyle.Header2, lang: 'Header2', aliases: [ 'h2', 'head2' ] }, - { id: I.TextStyle.Header3, lang: 'Header3', aliases: [ 'h3', 'head3' ] }, - { id: I.TextStyle.Quote, lang: 'Quote' }, - { id: I.TextStyle.Callout, lang: 'Callout' }, + { id: I.TextStyle.Header1, lang: 'Header1', aliases: [ 'h1', 'head1', 'header1' ] }, + { id: I.TextStyle.Header2, lang: 'Header2', aliases: [ 'h2', 'head2', 'header2' ] }, + { id: I.TextStyle.Header3, lang: 'Header3', aliases: [ 'h3', 'head3', 'header3' ] }, + { id: I.TextStyle.Quote, lang: 'Quote', aliases: [ 'quote' ] }, + { id: I.TextStyle.Callout, lang: 'Callout', aliases: [ 'callout' ] }, ].map((it: any) => { it.type = I.BlockType.Text; it.icon = UtilData.blockTextClass(it.id); @@ -44,10 +44,10 @@ class UtilMenu { getBlockList () { return [ - { id: I.TextStyle.Checkbox, lang: 'Checkbox', aliases: [ 'todo' ] }, - { id: I.TextStyle.Bulleted, lang: 'Bulleted' }, - { id: I.TextStyle.Numbered, lang: 'Numbered' }, - { id: I.TextStyle.Toggle, lang: 'Toggle' }, + { id: I.TextStyle.Checkbox, lang: 'Checkbox', aliases: [ 'todo', 'checkbox' ] }, + { id: I.TextStyle.Bulleted, lang: 'Bulleted', aliases: [ 'bulleted list' ] }, + { id: I.TextStyle.Numbered, lang: 'Numbered', aliases: [ 'numbered list' ] }, + { id: I.TextStyle.Toggle, lang: 'Toggle', aliases: [ 'toggle' ] }, ].map((it: any) => { it.type = I.BlockType.Text; it.icon = UtilData.blockTextClass(it.id); @@ -57,13 +57,13 @@ class UtilMenu { getBlockMedia () { return [ - { type: I.BlockType.File, id: I.FileType.File, icon: 'mediaFile', lang: 'File' }, - { type: I.BlockType.File, id: I.FileType.Image, icon: 'mediaImage', lang: 'Image' }, - { type: I.BlockType.File, id: I.FileType.Video, icon: 'mediaVideo', lang: 'Video' }, - { type: I.BlockType.File, id: I.FileType.Audio, icon: 'mediaAudio', lang: 'Audio' }, - { type: I.BlockType.File, id: I.FileType.Pdf, icon: 'mediaPdf', lang: 'Pdf' }, - { type: I.BlockType.Bookmark, id: 'bookmark', icon: 'bookmark', lang: 'Bookmark' }, - { type: I.BlockType.Text, id: I.TextStyle.Code, icon: 'code', lang: 'Code' }, + { type: I.BlockType.File, id: I.FileType.File, icon: 'mediaFile', lang: 'File', aliases: [ 'file' ] }, + { type: I.BlockType.File, id: I.FileType.Image, icon: 'mediaImage', lang: 'Image', aliases: [ 'image', 'picture' ] }, + { type: I.BlockType.File, id: I.FileType.Video, icon: 'mediaVideo', lang: 'Video', aliases: [ 'video' ] }, + { type: I.BlockType.File, id: I.FileType.Audio, icon: 'mediaAudio', lang: 'Audio', aliases: [ 'audio' ] }, + { type: I.BlockType.File, id: I.FileType.Pdf, icon: 'mediaPdf', lang: 'Pdf', aliases: [ 'pdf' ] }, + { type: I.BlockType.Bookmark, id: 'bookmark', icon: 'bookmark', lang: 'Bookmark', aliases: [ 'bookmark' ] }, + { type: I.BlockType.Text, id: I.TextStyle.Code, icon: 'code', lang: 'Code', aliases: [ 'code' ] }, ].map(this.mapperBlock); }; @@ -92,6 +92,8 @@ class UtilMenu { { id: I.EmbedProcessor.Instagram, icon: 'instagram', name: 'Instagram' }, { id: I.EmbedProcessor.Telegram, icon: 'telegram', name: 'Telegram' }, { id: I.EmbedProcessor.GithubGist, icon: 'githubGist', name: 'Github Gist' }, + { id: I.EmbedProcessor.Codepen, icon: 'codepen', name: 'Codepen' }, + { id: I.EmbedProcessor.Bilibili, icon: 'bilibili', name: 'Bilibili' }, ]); }; @@ -127,12 +129,12 @@ class UtilMenu { getBlockOther () { return [ - { type: I.BlockType.Div, id: I.DivStyle.Line, icon: 'divLine', lang: 'Line' }, - { type: I.BlockType.Div, id: I.DivStyle.Dot, icon: 'divDot', lang: 'Dot' }, - { type: I.BlockType.TableOfContents, id: I.BlockType.TableOfContents, icon: 'tableOfContents', lang: 'TableOfContents', aliases: [ 'tc', 'toc' ] }, - { type: I.BlockType.Table, id: I.BlockType.Table, icon: 'table', lang: 'SimpleTable' }, - { type: I.BlockType.Dataview, id: 'collection', icon: 'collection', lang: 'Collection', aliases: [ 'grid', 'table', 'gallery', 'list', 'board', 'kanban' ] }, - { type: I.BlockType.Dataview, id: 'set', icon: 'set', lang: 'Set', aliases: [ 'grid', 'table', 'gallery', 'list', 'board', 'kanban' ] }, + { type: I.BlockType.Div, id: I.DivStyle.Line, icon: 'divLine', lang: 'Line', aliases: [ 'hr', 'line divider' ] }, + { type: I.BlockType.Div, id: I.DivStyle.Dot, icon: 'divDot', lang: 'Dot', aliases: [ 'dot', 'dots divider' ] }, + { type: I.BlockType.TableOfContents, id: I.BlockType.TableOfContents, icon: 'tableOfContents', lang: 'TableOfContents', aliases: [ 'tc', 'toc', 'table of contents'] }, + { type: I.BlockType.Table, id: I.BlockType.Table, icon: 'table', lang: 'SimpleTable', aliases: [ 'table' ] }, + { type: I.BlockType.Dataview, id: 'collection', icon: 'collection', lang: 'Collection', aliases: [ 'grid', 'table', 'gallery', 'list', 'board', 'kanban', 'inline collection' ] }, + { type: I.BlockType.Dataview, id: 'set', icon: 'set', lang: 'Set', aliases: [ 'grid', 'table', 'gallery', 'list', 'board', 'kanban', 'inline set' ] }, ].map(this.mapperBlock); }; diff --git a/src/ts/store/block.ts b/src/ts/store/block.ts index bdc700f634..17e7d9b005 100644 --- a/src/ts/store/block.ts +++ b/src/ts/store/block.ts @@ -422,7 +422,7 @@ class BlockStore { }; updateMarkup (rootId: string) { - const blocks = UtilCommon.objectCopy(this.getBlocks(rootId, it => it.isText())); + const blocks = this.getBlocks(rootId, it => it.isText()); for (const block of blocks) { let marks = block.content.marks || []; @@ -431,6 +431,7 @@ class BlockStore { continue; }; + marks = UtilCommon.objectCopy(marks); marks.sort(Mark.sort); let { text } = block.content; diff --git a/src/ts/store/menu.ts b/src/ts/store/menu.ts index be4d2c8913..d8eb55c2e7 100644 --- a/src/ts/store/menu.ts +++ b/src/ts/store/menu.ts @@ -164,7 +164,7 @@ class MenuStore { }; isAnimating (id: string): boolean { - return this.isAnimatingFlag.get(id); + return !!this.isAnimatingFlag.get(id); }; closeAll (ids?: string[], callBack?: () => void) {