Skip to content

Commit

Permalink
Merge pull request #1297 from nextcloud-libraries/feat/provide-generi…
Browse files Browse the repository at this point in the history
…c-dialogs

feat: Provide generic dialogs previously provided by `OC.dialogs`
  • Loading branch information
susnux committed Apr 10, 2024
2 parents d3131f1 + 27994f5 commit b6c2c17
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 1 deletion.
66 changes: 66 additions & 0 deletions lib/components/GenericDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<template>
<NcDialog dialog-classes="nc-generic-dialog"
:buttons="buttons"
:name="name"
:message="text"
@update:open="$emit('close')">
<NcNoteCard v-if="severity" :type="severity">
<p v-text="text" />
</NcNoteCard>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-if="html" v-html="html" />
</NcDialog>
</template>

<script setup lang="ts">
import type { ISeverity } from './types.d.ts'
import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js'
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
import type { IDialogButton } from './types'
import { onMounted, onUnmounted } from 'vue'
const props = defineProps<{
/**
* Headline of the dialog
*/
name: string
/**
* Main text of the dialog
*/
text: string
/**
* HTML content
* @deprecated DO NOT USE! This is just for backwards compatibility and will be removed in the near future!
*/
html?: string
/**
* Buttons on the dialog
*/
buttons?: IDialogButton[]
/**
* Severity of the dialog - if a notecard is used
*/
severity?: ISeverity
}>()
/**
* Handler used to ensure the message is also shown when the page is unloaded
* This is for backwards compatibility with OC.dialogs
*/
const handleUnload = () => `${props.name}: ${props.text}`
onMounted(() => window.addEventListener('unload', handleUnload))
onUnmounted(() => window.removeEventListener('unload', handleUnload))
</script>

<style>
.nc-generic-dialog .dialog__actions {
justify-content: space-between;
min-width: calc(100% - 12px);
}
</style>
2 changes: 2 additions & 0 deletions lib/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

import type { Node } from '@nextcloud/files'

export type ISeverity = 'info' | 'warning' | 'error'

/**
* Interface for defining buttons passed to the Dialog component
* See NcDialogButton
Expand Down
167 changes: 167 additions & 0 deletions lib/dialogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/**
* @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de>
*
* @author Ferdinand Thiessen <opensource@fthiessen.de>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import type { IDialogButton, ISeverity } from './components/types'
import type Vue from 'vue'

import GenericDialog from './components/GenericDialog.vue'
import { spawnDialog } from './utils/dialogs'

/**
* This class provides generic Nextcloud themed dialogs
*/
export class Dialog {

#name: string
#text: string
#buttons: IDialogButton[]
#severity?: ISeverity
#dialog?: Vue

/** @deprecated */
#html?: string

constructor(
name: string,
text: string,
buttons: IDialogButton[] = [],
severity?: ISeverity,
) {
this.#name = name
this.#text = text
this.#buttons = buttons
this.#severity = severity
this.#dialog = undefined
this.#html = undefined
}

/**
* @deprecated DO NOT USE! It will be removed in the near future!
* @param html HTML content
*/
setHTML(html: string) {
this.#html = html
return this
}

/**
* Spawn and show the dialog - if already open the previous instance will be destroyed
* @return Promise that resolves when the dialog is answered successfully and rejects on close
*/
show() {
if (this.#dialog) {
this.#dialog.$destroy()
}

return new Promise((resolve) => {
this.#dialog = spawnDialog(GenericDialog,
{
buttons: this.#buttons,
name: this.#name,
text: this.#text,
severity: this.#severity,
html: this.#html,
},
resolve,
)
})
}

/**
* Hide and destroy the current dialog instance
*/
hide() {
this.#dialog?.$destroy()
}

}

/**
* The DialogBuilder provides an easy to use interface for creating simple dialogs in consistent Nextcloud design
*/
export class DialogBuilder {

#severity?: ISeverity
#text: string
#name: string
#buttons: IDialogButton[]

constructor() {
this.#severity = undefined
this.#text = ''
this.#name = ''
this.#buttons = []
}

/**
* Set dialog name
* @param name The name or headline of the dialog
*/
setName(name: string) {
this.#name = name
return this
}

/**
* Set the dialog text
* @param text Main text of the dialog
*/
setText(text: string) {
this.#text = text
return this
}

/**
* Set the severity of the dialog
* @param severity Severity of the dialog
*/
setSeverity(severity: ISeverity) {
this.#severity = severity
return this
}

/**
* Set buttons from array
* @param buttons Either an array of dialog buttons
*/
setButtons(buttons: IDialogButton[]) {
if (this.#buttons.length > 0) {
console.warn('[@nextcloud/dialogs] Dialog buttons are already set - this overrides previous buttons.')
}
this.#buttons = buttons
return this
}

/**
* Add a single button
* @param button Button to add
*/
addButton(button: IDialogButton) {
this.#buttons.push(button)
return this
}

build() {
return new Dialog(this.#name, this.#text, this.#buttons, this.#severity)
}

}
27 changes: 27 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
/**
* @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de>
*
* @author Ferdinand Thiessen <opensource@fthiessen.de>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

export {
FilePicker,
FilePickerClosed,
Expand Down Expand Up @@ -29,4 +51,9 @@ export type {

export { spawnDialog } from './utils/dialogs.js'

export {
Dialog,
DialogBuilder,
} from './dialogs'

export type { IFilePickerButton, IFilePickerFilter } from './components/types.js'
3 changes: 2 additions & 1 deletion lib/utils/dialogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Vue, { toRaw } from 'vue'
* @param props Properties to pass to the dialog
* @param onClose Callback when the dialog is closed
*/
export const spawnDialog = (dialog: Component | AsyncComponent, props: any, onClose: (...rest: unknown[]) => void = () => {}) => {
export const spawnDialog = (dialog: Component | AsyncComponent, props: any, onClose: (...rest: unknown[]) => void = () => {}): Vue => {
const el = document.createElement('div')

const container: HTMLElement = document.querySelector(props?.container) || document.body
Expand All @@ -50,4 +50,5 @@ export const spawnDialog = (dialog: Component | AsyncComponent, props: any, onCl
},
}),
})
return vue
}

0 comments on commit b6c2c17

Please sign in to comment.