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
3 changes: 3 additions & 0 deletions l10n/messages.pot
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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(() => {
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
Original file line number Diff line number Diff line change
@@ -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(() => {
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>