Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use NcSelect in NcRichtext #4247

Merged
merged 4 commits into from Jun 23, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions l10n/messages.pot
Expand Up @@ -164,6 +164,9 @@ msgstr ""
msgid "Previous"
msgstr ""

msgid "Provider icon"
msgstr ""

msgid "Raw link {options}"
msgstr ""

Expand Down
37 changes: 21 additions & 16 deletions src/components/NcRichText/NcReferencePicker/NcProviderList.vue
@@ -1,32 +1,33 @@
<template>
<div class="provider-list">
<NcMultiselect ref="provider-select"
<NcSelect ref="provider-select"
v-model="selectedProvider"
class="provider-list--select"
track-by="id"
input-id="provider-select-input"
label="title"
:placeholder="multiselectPlaceholder"
:options="options"
:internal-search="false"
:clear-on-select="true"
:preserve-search="true"
:option-height="44"
@search-change="query = $event"
:append-to-body="false"
:clear-search-on-select="true"
:clear-search-on-blur="() => false"
:filterable="false"
@search="onSearch"
@input="onProviderSelected">
<template #option="{option}">
<template #option="option">
<div v-if="option.isLink" class="provider">
<LinkVariantIcon class="link-icon" :size="20" />
<span>{{ option.title }}</span>
</div>
<div v-else class="provider">
<img class="provider-icon"
:src="option.icon_url">
:src="option.icon_url"
:alt="providerIconAlt">
<NcHighlight class="option-text"
:search="query"
:text="option.title" />
</div>
</template>
</NcMultiselect>
</NcSelect>
<NcEmptyContent class="provider-list--empty-content">
<template #icon>
<LinkVariantIcon />
Expand All @@ -40,15 +41,15 @@ import { searchProvider } from './providerHelper.js'
import { isUrl } from './utils.js'
import NcEmptyContent from '../../NcEmptyContent/index.js'
import NcHighlight from '../../NcHighlight/index.js'
import NcMultiselect from '../../NcMultiselect/index.js'
import NcSelect from '../../NcSelect/index.js'
import { t } from '../../../l10n.js'

import LinkVariantIcon from 'vue-material-design-icons/LinkVariant.vue'

export default {
name: 'NcProviderList',
components: {
NcMultiselect,
NcSelect,
NcHighlight,
NcEmptyContent,
LinkVariantIcon,
Expand All @@ -62,6 +63,7 @@ export default {
selectedProvider: null,
query: '',
multiselectPlaceholder: t('Select provider'),
providerIconAlt: t('Provider icon'),
}
},
computed: {
Expand All @@ -80,9 +82,9 @@ export default {
},
methods: {
focus() {
this.$nextTick(() => {
this.$refs['provider-select']?.$el?.focus()
})
setTimeout(() => {
raimund-schluessler marked this conversation as resolved.
Show resolved Hide resolved
this.$refs['provider-select']?.$el?.querySelector('#provider-select-input')?.focus()
}, 300)
},
onProviderSelected(p) {
if (p !== null) {
Expand All @@ -94,14 +96,17 @@ export default {
this.selectedProvider = null
}
},
onSearch(query, loading) {
this.query = query
},
},
}
</script>

<style lang="scss" scoped>
.provider-list {
width: 100%;
min-height: 350px;
min-height: 400px;
padding: 0 16px 16px 16px;
display: flex;
flex-direction: column;
Expand Down
77 changes: 41 additions & 36 deletions src/components/NcRichText/NcReferencePicker/NcSearch.vue
@@ -1,21 +1,24 @@
<template>
<div class="smart-picker-search" :class="{ 'with-empty-content': showEmptyContent }">
<NcMultiselect ref="search-select"
<NcSelect ref="search-select"
v-model="selectedResult"
class="smart-picker-search--select"
track-by="resourceUrl"
input-id="search-select-input"
label="name"
:placeholder="mySearchPlaceholder"
:options="options"
:internal-search="false"
:clear-on-select="false"
:append-to-body="false"
:close-on-select="false"
:preserve-search="true"
:clear-search-on-select="false"
:clear-search-on-blur="() => false"
:reset-focus-on-options-change="false"
:filterable="false"
:autoscroll="true"
:reset-on-options-change="false"
:loading="searching"
:multiple="false"
:option-height="60"
@search-change="onSearchInput"
@search="onSearchInput"
@input="onSelectResultSelected">
<template #option="{option}">
<template #option="option">
<div v-if="option.isRawLink" class="custom-option">
<LinkVariantIcon class="option-simple-icon" :size="20" />
<span class="option-text">
Expand All @@ -42,20 +45,16 @@
</span>
</span>
</template>
<template #noOptions>
<MagnifyIcon class="option-simple-icon" :size="20" />
{{ t('Start typing to search') }}
<template #no-options>
{{ noOptionsText }}
</template>
<template #noResult>
<MagnifyIcon class="option-simple-icon" :size="20" />
{{ t('Start typing to search') }}
</template>
</NcMultiselect>
</NcSelect>
<NcEmptyContent v-if="showEmptyContent"
class="smart-picker-search--empty-content">
<template #icon>
<img v-if="provider.icon_url"
class="provider-icon"
:alt="providerIconAlt"
:src="provider.icon_url">
<LinkVariantIcon v-else />
</template>
Expand All @@ -67,7 +66,7 @@
import NcSearchResult from './NcSearchResult.vue'
import { isUrl, delay } from './utils.js'
import NcEmptyContent from '../../NcEmptyContent/index.js'
import NcMultiselect from '../../NcMultiselect/index.js'
import NcSelect from '../../NcSelect/index.js'

import { t } from '../../../l10n.js'

Expand All @@ -76,7 +75,6 @@ import { generateOcsUrl } from '@nextcloud/router'

import DotsHorizontalIcon from 'vue-material-design-icons/DotsHorizontal.vue'
import LinkVariantIcon from 'vue-material-design-icons/LinkVariant.vue'
import MagnifyIcon from 'vue-material-design-icons/Magnify.vue'

const LIMIT = 5

Expand All @@ -85,9 +83,8 @@ export default {
components: {
LinkVariantIcon,
DotsHorizontalIcon,
MagnifyIcon,
NcEmptyContent,
NcMultiselect,
NcSelect,
NcSearchResult,
},
props: {
Expand Down Expand Up @@ -118,6 +115,8 @@ export default {
searching: false,
searchingMoreOf: null,
abortController: null,
noOptionsText: t('Start typing to search'),
providerIconAlt: t('Provider icon'),
}
},
computed: {
Expand All @@ -141,6 +140,7 @@ export default {
},
rawLinkEntry() {
return {
id: 'rawLinkEntry',
resourceUrl: this.searchQuery,
isRawLink: true,
}
Expand All @@ -152,14 +152,22 @@ export default {
// don't show group name entry if there is only one search provider and one result
if (this.searchProviderIds.length > 1 || this.resultsBySearchProvider[pid].entries.length > 1) {
results.push({
id: 'groupTitle-' + pid,
name: this.resultsBySearchProvider[pid].name,
isCustomGroupTitle: true,
providerId: pid,
})
}
results.push(...this.resultsBySearchProvider[pid].entries)
const providerEntriesWithId = this.resultsBySearchProvider[pid].entries.map((entry, index) => {
return {
id: 'provider-' + pid + '-entry-' + index,
...entry,
}
})
results.push(...providerEntriesWithId)
if (this.resultsBySearchProvider[pid].isPaginated) {
results.push({
id: 'moreOf-' + pid,
name: this.resultsBySearchProvider[pid].name,
isMore: true,
providerId: pid,
Expand Down Expand Up @@ -189,14 +197,16 @@ export default {
this.resultsBySearchProvider = resultsBySearchProvider
},
focus() {
this.$refs['search-select']?.$el?.focus()
setTimeout(() => {
raimund-schluessler marked this conversation as resolved.
Show resolved Hide resolved
this.$refs['search-select']?.$el?.querySelector('#search-select-input')?.focus()
}, 300)
},
cancelSearchRequests() {
if (this.abortController) {
this.abortController.abort()
}
},
onSearchInput(query) {
onSearchInput(query, loading) {
this.searchQuery = query
delay(() => {
this.updateSearch()
Expand All @@ -208,16 +218,17 @@ export default {
this.cancelSearchRequests()
this.$emit('submit', item.resourceUrl)
} else if (item.isMore) {
this.searchMoreOf(item.providerId)
this.searchMoreOf(item.providerId).then(() => {
// allow clicking twice on the same "more" item
this.selectedResult = null
})
}
}
// avoid showing something in the singleLabel slot (selected item)
this.selectedResult = null
},
searchMoreOf(searchProviderId) {
this.searchingMoreOf = searchProviderId
this.cancelSearchRequests()
this.searchProviders(searchProviderId)
return this.searchProviders(searchProviderId)
},
updateSearch() {
this.cancelSearchRequests()
Expand All @@ -227,7 +238,7 @@ export default {
return
}

this.searchProviders()
return this.searchProviders()
},
searchProviders(searchProviderId = null) {
this.abortController = new AbortController()
Expand Down Expand Up @@ -279,7 +290,7 @@ export default {
flex-direction: column;
padding: 0 16px 16px 16px;
&.with-empty-content {
min-height: 350px;
min-height: 400px;
}

&--empty-content {
Expand Down Expand Up @@ -320,12 +331,6 @@ export default {
text-overflow: ellipsis;
white-space: nowrap;
}

// multiselect dropdown is wider than the select input
// this avoids overflow
:deep(.multiselect__content-wrapper) {
width: calc(100% - 4px) !important;
}
}
}
</style>