Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Feature: Show word count in RichText
Show word count as last element of the overflow menu,
which now will be always shown. The word count
is updated when the menu is openend as the
tiptap word count is not reactive.

Modified ActionList: Added a named slot for adding
elements that should always shown as the last elements.

Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux committed Jul 2, 2022
commit 4701e0078ac91cbfda3f1f3f19f032620b08c890
64 changes: 64 additions & 0 deletions cypress/e2e/MenuBar.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { initUserAndFiles, randHash } from '../utils/index.js'

const randUser = randHash()
const fileName = 'test.md'

describe('Test the rich text editor menu bar', function() {
before(() => initUserAndFiles(randUser, fileName))

beforeEach(function() {
cy.login(randUser, 'password', {
onBeforeLoad(win) {
cy.stub(win, 'open')
.as('winOpen')

},
})

cy.openFile(fileName)
})

describe('word count', function() {
/**
*
*/
function getWordCount() {
return cy.get('.popover .open').get('[data-text-action-entry="word-count"]')
}

beforeEach(cy.clearContent)
it('empty file', () => {
cy.getFile(fileName)
.then($el => {
cy.getActionEntry('remain')
.click()
getWordCount()
.should('include.text', '0 words')
})
})

it('single word', () => {
cy.getFile(fileName)
.then($el => {
cy.getContent()
.type(' Hello ')
cy.getActionEntry('remain')
.click()
getWordCount()
.should('include.text', '1 word')
})
})

it('multiple words', () => {
cy.getFile(fileName)
.then($el => {
cy.getContent()
.type('Hello \nworld')
cy.getActionEntry('remain')
.click()
getWordCount()
.should('include.text', '2 word')
})
})
})
})
26 changes: 26 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@tiptap/extension-blockquote": "^2.0.0-beta.29",
"@tiptap/extension-bold": "^2.0.0-beta.28",
"@tiptap/extension-bullet-list": "^2.0.0-beta.29",
"@tiptap/extension-character-count": "^2.0.0-beta.30",
"@tiptap/extension-code": "^2.0.0-beta.28",
"@tiptap/extension-code-block": "^2.0.0-beta.41",
"@tiptap/extension-code-block-lowlight": "^2.0.0-beta.72",
Expand Down
5 changes: 4 additions & 1 deletion src/components/Menu/ActionList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
<Actions v-tooltip="tooltip"
class="entry-list-action entry-action"
v-bind="state"
:force-menu="true"
:title="actionEntry.label"
:data-text-action-entry="actionEntry.key"
:data-text-action-active="activeKey">
:data-text-action-active="activeKey"
@update:open="(o) => $emit('update:open', o)">
<template #icon>
<component :is="icon" :key="iconKey" />
</template>
Expand All @@ -35,6 +37,7 @@
is-item
:action-entry="child"
@trigged="onTrigger" />
<slot name="lastAction" />
</Actions>
</template>

Expand Down
50 changes: 29 additions & 21 deletions src/components/Menu/MenuBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@
v-bind="{ actionEntry }"
:key="`text-action--${actionEntry.key}`"
@call:help="showHelp" />
<ActionList key="text-action--remain"
:action-entry="hiddenEntries"
@update:open="refreshWordCount"
@call:help="showHelp">
<template #lastAction>
<ActionCaption :title="wordCountString"
data-text-action-entry="word-count" />
</template>
</ActionList>
</div>
<div class="text-menubar__slot">
<slot />
Expand All @@ -45,12 +54,16 @@
</template>

<script>
import ActionCaption from '@nextcloud/vue/dist/Components/ActionCaption'

import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { translatePlural as n } from '@nextcloud/l10n'
import debounce from 'debounce'

import HelpModal from '../HelpModal.vue'
import actionsFullEntries from './entries.js'
import ActionEntry from './ActionEntry.js'
import ActionList from './ActionList.vue'
import { DotsHorizontal } from '../icons.js'
import {
useEditorMixin,
Expand All @@ -60,7 +73,7 @@ import {

export default {
name: 'MenuBar',
components: { ActionEntry, HelpModal },
components: { ActionEntry, ActionList, ActionCaption, HelpModal },
mixins: [
useEditorMixin,
useIsRichEditorMixin,
Expand All @@ -79,6 +92,7 @@ export default {
isReady: false,
isVisible: this.$editor.isFocused,
windowWidth: 0,
wordCount: 0,
}
},
computed: {
Expand All @@ -102,40 +116,27 @@ export default {
return slots - 1
},
visibleEntries() {
const { hiddenEntries, remainAction } = this
const list = [...actionsFullEntries].filter(({ priority }) => {
// if entry do not have priority, we assume it aways will be visible
return priority === undefined || priority <= this.iconsLimit
})

if (hiddenEntries.length === 0) {
return list
}

if (hiddenEntries.length === 1) {
// put only one entry
list.push(hiddenEntries[0])
} else {
// add all hidden entries as list of actions
list.push(remainAction)
}

return list
},
hiddenEntries() {
return [...actionsFullEntries].filter(({ priority }) => {
// reverse logic from visibleEntries
return priority !== undefined && priority > this.iconsLimit
})
},
remainAction() {
return {
key: 'remain',
label: this.t('text', 'Remaining Actions'),
icon: DotsHorizontal,
children: this.hiddenEntries,
children: [...actionsFullEntries].filter(({ priority }) => {
// reverse logic from visibleEntries
return priority !== undefined && priority > this.iconsLimit
}),
}
},
wordCountString() {
return n('text', '%n word', '%n words', this.wordCount)
},
},
mounted() {
window.addEventListener('resize', this.getWindowWidth)
Expand Down Expand Up @@ -205,6 +206,13 @@ export default {
hideHelp() {
this.displayHelp = false
},

refreshWordCount(open) {
// characterCount is not reactive so we need this workaround
if (open) {
this.wordCount = this.$editor.storage.characterCount.words()
}
},
},
}
</script>
Expand Down
24 changes: 13 additions & 11 deletions src/extensions/RichText.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,25 @@
import { Extension } from '@tiptap/core'

/* eslint-disable import/no-named-as-default */
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import Blockquote from '@tiptap/extension-blockquote'
import OrderedList from '@tiptap/extension-ordered-list'
import ListItem from '@tiptap/extension-list-item'
import CharacterCount from '@tiptap/extension-character-count'
import Code from '@tiptap/extension-code'
import CodeBlock from '@tiptap/extension-code-block'
import HorizontalRule from '@tiptap/extension-horizontal-rule'
import Document from '@tiptap/extension-document'
import Dropcursor from '@tiptap/extension-dropcursor'
import HorizontalRule from '@tiptap/extension-horizontal-rule'
import ListItem from '@tiptap/extension-list-item'
import OrderedList from '@tiptap/extension-ordered-list'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import BulletList from './../nodes/BulletList.js'
import Callout from './../nodes/Callouts.js'
import HardBreak from './HardBreak.js'
import Table from './../nodes/Table.js'
import Image from './../nodes/Image.js'
import Heading from './../nodes/Heading.js'
import BulletList from './../nodes/BulletList.js'
import TaskList from './../nodes/TaskList.js'
import Image from './../nodes/Image.js'
import Table from './../nodes/Table.js'
import TaskItem from './../nodes/TaskItem.js'
import Callout from './../nodes/Callouts.js'
import TaskList from './../nodes/TaskList.js'
/* eslint-enable import/no-named-as-default */

import { Strong, Italic, Strike, Link, Underline } from './../marks/index.js'
Expand All @@ -66,6 +67,7 @@ export default Extension.create({
Italic,
Strike,
Blockquote,
CharacterCount,
Code,
CodeBlock,
BulletList,
Expand Down