Skip to content
Snippets Groups Projects
SearchBar.vue 7.73 KiB
Newer Older
<template>
  <div class="ui fluid category search">
Georg Krause's avatar
Georg Krause committed
    <slot /><div class="ui icon input">
      <input
        ref="search"
        :aria-label="labels.searchContent"
        type="search"
        class="prompt"
        name="search"
        :placeholder="labels.placeholder"
        @keydown.esc="$event.target.blur()"
      >
      <i class="search icon" />
Georg Krause's avatar
Georg Krause committed
    <div class="results" />
    <slot name="after" />
    <GlobalEvents
      @keydown.shift.f.prevent.exact="focusSearch"
    />
  </div>
</template>

<script>
import jQuery from 'jquery'
import router from '@/router'
import lodash from '@/lodash'
Ciaran Ainsworth's avatar
Ciaran Ainsworth committed
import GlobalEvents from '@/components/utils/global-events.vue'
Georg Krause's avatar
Georg Krause committed
    GlobalEvents
Eliot Berriot's avatar
Eliot Berriot committed
  computed: {
    labels () {
      return {
        placeholder: this.$pgettext('Sidebar/Search/Input.Placeholder', 'Search for artists, albums, tracks…'),
        searchContent: this.$pgettext('Sidebar/Search/Input.Label', 'Search for content')
Georg Krause's avatar
Georg Krause committed
    const artistLabel = this.$pgettext('*/*/*/Noun', 'Artist')
    const albumLabel = this.$pgettext('*/*/*', 'Album')
    const trackLabel = this.$pgettext('*/*/*/Noun', 'Track')
    const tagLabel = this.$pgettext('*/*/*/Noun', 'Tag')
    const self = this
    let searchQuery
Georg Krause's avatar
Georg Krause committed
    jQuery(this.$el).keypress(function (e) {
      if (e.which === 13) {
        // Cancel any API search request to backend…
Georg Krause's avatar
Georg Krause committed
        jQuery(this.$el).search('cancel query')
        // Go direct to the artist page…
Georg Krause's avatar
Georg Krause committed
        router.push(`/search?q=${searchQuery}&type=artists`)
      }
    })
    jQuery(this.$el).search({
      type: 'category',
      minCharacters: 3,
      showNoResults: true,
      error: {
        noResultsHeader: this.$pgettext('Sidebar/Search/Error', 'No matches found'),
        noResults: this.$pgettext('Sidebar/Search/Error.Label', 'Sorry, there are no results for this search')
      },
Georg Krause's avatar
Georg Krause committed
        jQuery(self.$el).search('set value', searchQuery)
Georg Krause's avatar
Georg Krause committed
        jQuery(self.$el).search('hide results')
        return false
      onSearchQuery (query) {
        self.$emit('search')
      apiSettings: {
        beforeXHR: function (xhrObject) {
          if (!self.$store.state.auth.authenticated) {
            return xhrObject
          }

          if (self.$store.state.auth.oauth.accessToken) {
            xhrObject.setRequestHeader('Authorization', self.$store.getters['auth/header'])
          }
          return xhrObject
        },
        onResponse: function (initialResponse) {
Georg Krause's avatar
Georg Krause committed
          const objId = self.extractObjId(searchQuery)
          const results = {}
          let isEmptyResults = true
Georg Krause's avatar
Georg Krause committed
          const categories = [
            {
              code: 'federation',
Georg Krause's avatar
Georg Krause committed
              name: self.$pgettext('*/*/*', 'Federation')
Georg Krause's avatar
Georg Krause committed
              name: self.$pgettext('*/*/*', 'Podcasts')
              route: 'library.artists.detail',
Eliot Berriot's avatar
Eliot Berriot committed
              name: artistLabel,
              getTitle (r) {
                return r.name
              },
              getDescription (r) {
                return ''
              },
              getId (t) {
                return t.id
              route: 'library.albums.detail',
Eliot Berriot's avatar
Eliot Berriot committed
              name: albumLabel,
              getTitle (r) {
                return r.title
              },
              getDescription (r) {
              },
              getId (t) {
                return t.id
              route: 'library.tracks.detail',
Eliot Berriot's avatar
Eliot Berriot committed
              name: trackLabel,
              getTitle (r) {
                return r.title
              },
              getDescription (r) {
                if (r.album) {
                  return `${r.album.artist.name} - ${r.album.title}`
                } else {
                  return r.artist.name
                }
              },
              getId (t) {
                return t.id
              }
            },
            {
              code: 'tags',
              route: 'library.tags.detail',
              name: tagLabel,
              getTitle (r) {
              },
              getDescription (r) {
                return ''
              },
              getId (t) {
                return t.name
Agate's avatar
Agate committed
            },
            {
              code: 'more',
Georg Krause's avatar
Georg Krause committed
              name: ''
            }
          ]
          categories.forEach(category => {
            results[category.code] = {
              name: category.name,
              results: []
            }
            if (category.code === 'federation') {
              if (objId) {
                isEmptyResults = false
Georg Krause's avatar
Georg Krause committed
                const searchMessage = self.$pgettext('Search/*/*', 'Search on the fediverse')
                results.federation = {
                  name: self.$pgettext('*/*/*', 'Federation'),
                  results: [{
                    title: searchMessage,
                    routerUrl: {
                      name: 'search',
                      query: {
Georg Krause's avatar
Georg Krause committed
                        id: objId
Georg Krause's avatar
Georg Krause committed
            } else if (category.code === 'podcasts') {
              if (objId) {
                isEmptyResults = false
Georg Krause's avatar
Georg Krause committed
                const searchMessage = self.$pgettext('Search/*/*', 'Subscribe to podcast via RSS')
                results.podcasts = {
                  name: self.$pgettext('*/*/*', 'Podcasts'),
                  results: [{
                    title: searchMessage,
                    routerUrl: {
                      name: 'search',
                      query: {
                        id: objId,
Georg Krause's avatar
Georg Krause committed
                        type: 'rss'
Georg Krause's avatar
Georg Krause committed
            } else if (category.code === 'more') {
              const searchMessage = self.$pgettext('Search/*/*', 'More results 🡒')
              results.more = {
Agate's avatar
Agate committed
                name: '',
                results: [{
                  title: searchMessage,
                  routerUrl: {
                    name: 'search',
                    query: {
Georg Krause's avatar
Georg Krause committed
                      type: 'artists',
Agate's avatar
Agate committed
                      q: searchQuery
                    }
                  }
                }]
              }
Georg Krause's avatar
Georg Krause committed
            } else {
              initialResponse[category.code].forEach(result => {
                isEmptyResults = false
Georg Krause's avatar
Georg Krause committed
                const id = category.getId(result)
                results[category.code].results.push({
                  title: category.getTitle(result),
                  id,
                  routerUrl: {
                    name: category.route,
                    params: {
                      id
                    }
                  },
                  description: category.getDescription(result)
                })
            results: isEmptyResults ? {} : results
          }
        url: this.$store.getters['instance/absoluteUrl']('api/v1/search?query={query}')
  },
  methods: {
    focusSearch () {
      this.$refs.search.focus()
    },
    extractObjId (query) {
      query = lodash.trim(query)
      query = lodash.trim(query, '@')
      if (query.indexOf(' ') > -1) {
        return
      }
      if (query.startsWith('http://') || query.startsWith('https://')) {
        return query
      }
      if (query.split('@').length > 1) {
        return query
      }
    }