Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
97 changes: 70 additions & 27 deletions cypress/e2e/MenuBar.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,18 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { initUserAndFiles, randUser } from '../utils/index.js'
import { randUser } from '../utils/index.js'

const user = randUser()
const fileName = 'empty.md'

describe('Test the rich text editor menu bar', function () {
before(() => initUserAndFiles(user, fileName))
before(function () {
cy.createUser(user)
})

beforeEach(function () {
cy.login(user)
cy.visit('/apps/files', {
onBeforeLoad(win) {
cy.stub(win, 'open').as('winOpen')
},
})

cy.openFile(fileName)
cy.uploadTestFile()
})

describe('word count', function () {
Expand All @@ -32,30 +27,78 @@ describe('Test the rich text editor menu bar', function () {
.get('[data-text-action-entry="character-count"]')
}

beforeEach(cy.clearContent)
beforeEach(function () {
cy.visit('/apps/files')
cy.openTestFile()
})

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

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

it('multiple words', () => {
cy.getFile(fileName).then(($el) => {
cy.clearContent()
cy.getContent().type('Hello \nworld')
cy.getActionEntry('remain').click()
getWordCount().should('include.text', '2 words, 11 chars')
})
cy.getContent().type('Hello \nworld')
cy.getActionEntry('remain').click()
getWordCount().should('include.text', '2 words, 11 chars')
})
})

describe('text width toggle', function () {
beforeEach(() => {
cy.configureText('is_full_width_editor', 0)
cy.visit('/apps/files')
cy.window()
.its('document.documentElement.style')
.invoke('getPropertyValue', '--text-editor-max-width')
.as('maxWidth')
})

it('applys default', function () {
cy.openTestFile()
cy.get('@maxWidth').should('equal', '80ch')
})

it('toggles value', function () {
cy.openTestFile()
cy.getActionEntry('remain').click()
cy.contains('Full width editor').click()
cy.get('@maxWidth').should('equal', '100%')
})

it('preserves on reopen', function () {
cy.openTestFile()
cy.getActionEntry('remain').click()
cy.contains('Full width editor').click()
cy.closeFile()
cy.openTestFile()
cy.get('@maxWidth').should('equal', '100%')
})

it('preserves on reload', function () {
cy.openTestFile()
cy.getActionEntry('remain').click()
cy.contains('Full width editor').click()
cy.visit('/apps/files')
cy.openTestFile()
cy.get('@maxWidth').should('equal', '100%')
})

it('does not interfere if width is already set', function () {
cy.window()
.its('document.body.style')
.invoke('setProperty', '--text-editor-max-width', '987px')
cy.openTestFile()
cy.getActionEntry('remain').click()
cy.contains('Full width editor').should('not.exist')
cy.get('@maxWidth').should('equal', '')
})
})
})
32 changes: 5 additions & 27 deletions src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@
:dirty="dirty"
:sessions="filteredSessions"
:sync-error="syncError"
:has-connection-issue="requireReconnect"
@editor-width-change="handleEditorWidthChange" />
:has-connection-issue="requireReconnect" />
<slot name="header" />
</MenuBar>
<div v-else class="menubar-placeholder" />
Expand Down Expand Up @@ -84,7 +83,6 @@
import { getCurrentUser } from '@nextcloud/auth'
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
import { File } from '@nextcloud/files'
import { loadState } from '@nextcloud/initial-state'
import { Collaboration } from '@tiptap/extension-collaboration'
import { useElementSize } from '@vueuse/core'
import Vue, { defineComponent, ref, set, shallowRef, watch } from 'vue'
Expand All @@ -101,6 +99,7 @@ import { generateRemoteUrl } from '@nextcloud/router'
import { Awareness } from 'y-protocols/awareness.js'
import { provideConnection } from '../composables/useConnection.ts'
import { useEditorMethods } from '../composables/useEditorMethods.ts'
import { provideEditorWidth } from '../composables/useEditorWidth.ts'
import { provideSaveService } from '../composables/useSaveService.ts'
import { provideSyncService } from '../composables/useSyncService.ts'
import { useSyntaxHighlighting } from '../composables/useSyntaxHighlighting.ts'
Expand Down Expand Up @@ -257,6 +256,9 @@ export default defineComponent({
: createPlainEditor({ language, extensions })
provideEditor(editor)

const { applyEditorWidth } = provideEditorWidth()
applyEditorWidth()

const { setEditable } = useEditorMethods(editor)

const serialize = isRichEditor
Expand Down Expand Up @@ -371,22 +373,13 @@ export default defineComponent({
},
}
},
editorMaxWidth() {
return loadState('text', 'is_full_width_editor', false) ? '100%' : '80ch'
},
},
watch: {
displayed() {
this.$nextTick(() => {
this.contentWrapper = this.$refs.contentWrapper
})
},
editorMaxWidth: {
immediate: true,
handler(newWidth) {
this.updateEditorWidth(newWidth)
},
},
dirty(val) {
if (val) {
window.addEventListener('beforeunload', this.saveBeforeUnload)
Expand Down Expand Up @@ -875,20 +868,6 @@ export default defineComponent({
this.translateModal = false
},

handleEditorWidthChange(newWidth) {
this.updateEditorWidth(newWidth)
this.$nextTick(() => {
this.editor.view.updateState(this.editor.view.state)
this.editor.commands.focus()
})
},
updateEditorWidth(newWidth) {
document.documentElement.style.setProperty(
'--text-editor-max-width',
newWidth,
)
},

saveBeforeUnload() {
this.saveService.saveViaSendBeacon()
},
Expand Down Expand Up @@ -976,7 +955,6 @@ export default defineComponent({
</style>

<style lang="scss">
@import './../css/variables';
@import './../css/style';
@import './../css/print';

Expand Down
28 changes: 4 additions & 24 deletions src/components/Editor/SessionList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
-->

<template>
<NcPopover class="session-list" placement="bottom">
<NcPopover
:no-focus-trap="!$slots.default"
class="session-list"
placement="bottom">
<template #trigger="{ attrs }">
<div>
<NcButton
Expand Down Expand Up @@ -47,26 +50,15 @@
>({{ t('text', 'guest') }})</span
>
</li>
<li>
<NcCheckboxRadioSwitch
:checked="isFullWidth"
@update:checked="onWidthToggle">
{{ t('text', 'Full width editor') }}
</NcCheckboxRadioSwitch>
</li>
</ul>
</div>
</template>
</NcPopover>
</template>

<script>
import axios from '@nextcloud/axios'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { generateUrl } from '@nextcloud/router'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
import NcPopover from '@nextcloud/vue/components/NcPopover'
import AccountMultipleOutlineIcon from 'vue-material-design-icons/AccountMultipleOutline.vue'
import {
Expand All @@ -82,7 +74,6 @@ export default {
AvatarWrapper,
NcButton,
NcPopover,
NcCheckboxRadioSwitch,
},
props: {
sessions: {
Expand All @@ -93,10 +84,8 @@ export default {
},
},
data() {
const isFullWidth = loadState('text', 'is_full_width_editor', false)
return {
myName: '',
isFullWidth,
}
},
computed: {
Expand Down Expand Up @@ -141,15 +130,6 @@ export default {
},
},
methods: {
onWidthToggle(checked) {
this.isFullWidth = checked
this.$emit('editor-width-change', checked ? '100%' : '80ch')

axios.post(generateUrl('/apps/text/settings'), {
key: 'is_full_width_editor',
value: checked ? '1' : '0',
})
},
t,
},
}
Expand Down
5 changes: 1 addition & 4 deletions src/components/Editor/Status.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</template>
</NcButton>
</div>
<SessionList :sessions="sessions" @editor-width-change="onEditorWidthChange">
<SessionList :sessions="sessions">
<p slot="lastSaved" class="last-saved">
{{ t('text', 'Last saved') }}: {{ lastSavedString }}
</p>
Expand Down Expand Up @@ -145,9 +145,6 @@ export default {
this.saveService.forceSave()
}
},
onEditorWidthChange(newWidth) {
this.$emit('editor-width-change', newWidth)
},
t,
},
}
Expand Down
40 changes: 7 additions & 33 deletions src/components/Menu/MenuBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,8 @@
:force-enabled="true"
@click="activeMenuEntry = 'remain'">
<template #lastAction="{ visible }">
<NcActionButton
v-if="canTranslate"
close-after-click
@click="showTranslate">
<template #icon>
<TranslateVariant />
</template>
{{ t('text', 'Translate') }}
</NcActionButton>
<TranslateButton />
<WidthToggle />
<ActionFormattingHelp @click="showHelp" />
<NcActionSeparator />
<CharacterCount v-bind="{ visible }" />
Expand All @@ -73,9 +66,6 @@
</template>

<script>
import { emit } from '@nextcloud/event-bus'
import { loadState } from '@nextcloud/initial-state'
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
import NcActionSeparator from '@nextcloud/vue/components/NcActionSeparator'
import { useElementSize } from '@vueuse/core'
import { ref } from 'vue'
Expand All @@ -85,14 +75,16 @@ import { useEditor } from '../../composables/useEditor.ts'
import { useEditorFlags } from '../../composables/useEditorFlags.ts'
import { useIsMobileMixin } from '../Editor.provider.ts'
import HelpModal from '../HelpModal.vue'
import { DotsHorizontal, TranslateVariant } from '../icons.js'
import { DotsHorizontal } from '../icons.js'
import ActionFormattingHelp from './ActionFormattingHelp.vue'
import ActionList from './ActionList.vue'
import ActionSingle from './ActionSingle.vue'
import CharacterCount from './CharacterCount.vue'
import { MenuEntries, ReadOnlyDoneEntries } from './entries.js'
import { MENU_ID } from './MenuBar.provider.js'
import ToolBarLogic from './ToolBarLogic.js'
import TranslateButton from './TranslateButton.vue'
import WidthToggle from './WidthToggle.vue'

export default {
name: 'MenuBar',
Expand All @@ -102,9 +94,9 @@ export default {
ActionSingle,
HelpModal,
NcActionSeparator,
NcActionButton,
CharacterCount,
TranslateVariant,
TranslateButton,
WidthToggle,
},
extends: ToolBarLogic,
mixins: [useIsMobileMixin],
Expand Down Expand Up @@ -146,8 +138,6 @@ export default {
randomID: `menu-bar-${Math.ceil(Math.random() * 10000 + 500).toString(16)}`,
displayHelp: false,
isReady: false,
canTranslate:
loadState('text', 'translation_languages', []).from?.length > 0,
resize: null,
}
},
Expand Down Expand Up @@ -230,22 +220,6 @@ export default {
hideHelp() {
this.displayHelp = false
},
showTranslate() {
const {
commands,
view: { state },
} = this.editor
const { from, to } = state.selection
let selectedText = state.doc.textBetween(from, to, ' ')

if (!selectedText.trim().length) {
commands.selectAll()
selectedText = state.doc.textContent
}

console.debug('translation click', state.selection, selectedText)
emit('text:translate-modal:show', { content: selectedText })
},
t,
},
}
Expand Down
Loading
Loading