Move search results to react components
This commit is contained in:
parent
6058a512c4
commit
de54dc636a
9 changed files with 515 additions and 771 deletions
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -3010,6 +3010,11 @@
|
||||||
"version": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
"version": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
||||||
"integrity": "sha512-5rjszPzcjFVoDEOarszcbax2WIGT3+fO+W212ZWg9+ylGJgxG1IIcCFjnnBbSdM0lNeIfmMGhhEGovIlr+1yBg=="
|
"integrity": "sha512-5rjszPzcjFVoDEOarszcbax2WIGT3+fO+W212ZWg9+ylGJgxG1IIcCFjnnBbSdM0lNeIfmMGhhEGovIlr+1yBg=="
|
||||||
},
|
},
|
||||||
|
"classnames": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
|
||||||
|
},
|
||||||
"clean-css": {
|
"clean-css": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
"@fontsource/noto-sans-sc": "^4.2.1",
|
"@fontsource/noto-sans-sc": "^4.2.1",
|
||||||
"blurhash": "^1.1.3",
|
"blurhash": "^1.1.3",
|
||||||
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
||||||
|
"classnames": "^2.3.1",
|
||||||
"core-js": "^3.11.2",
|
"core-js": "^3.11.2",
|
||||||
"date-fns": "^2.21.1",
|
"date-fns": "^2.21.1",
|
||||||
"epubjs": "^0.3.85",
|
"epubjs": "^0.3.85",
|
||||||
|
|
|
@ -2,8 +2,9 @@ import PropTypes from 'prop-types';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import SearchFields from '../search/SearchFields';
|
import SearchFields from '../search/SearchFields';
|
||||||
import SearchResults from '../search/SearchResultsComponent';
|
import SearchResults from '../search/SearchResults';
|
||||||
import SearchSuggestions from '../search/SearchSuggestions';
|
import SearchSuggestions from '../search/SearchSuggestions';
|
||||||
|
import LiveTVSearchResults from '../search/LiveTVSearchResults';
|
||||||
|
|
||||||
const SearchPage = ({ serverId, parentId, collectionType }) => {
|
const SearchPage = ({ serverId, parentId, collectionType }) => {
|
||||||
const [ query, setQuery ] = useState(null);
|
const [ query, setQuery ] = useState(null);
|
||||||
|
@ -23,6 +24,12 @@ const SearchPage = ({ serverId, parentId, collectionType }) => {
|
||||||
collectionType={collectionType}
|
collectionType={collectionType}
|
||||||
query={query}
|
query={query}
|
||||||
/>
|
/>
|
||||||
|
<LiveTVSearchResults
|
||||||
|
serverId={serverId || ApiClient.serverId()}
|
||||||
|
parentId={parentId}
|
||||||
|
collectionType={collectionType}
|
||||||
|
query={query}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
195
src/components/search/LiveTVSearchResults.js
Normal file
195
src/components/search/LiveTVSearchResults.js
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import globalize from '../../scripts/globalize';
|
||||||
|
import ServerConnections from '../ServerConnections';
|
||||||
|
import SearchResultsRow from './SearchResultsRow';
|
||||||
|
|
||||||
|
const CARD_OPTIONS = {
|
||||||
|
preferThumb: true,
|
||||||
|
inheritThumb: false,
|
||||||
|
showParentTitleOrTitle: true,
|
||||||
|
showTitle: false,
|
||||||
|
coverImage: true,
|
||||||
|
overlayMoreButton: true,
|
||||||
|
showAirTime: true,
|
||||||
|
showAirDateTime: true,
|
||||||
|
showChannelName: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const LiveTVSearchResults = ({ serverId, parentId, collectionType, query }) => {
|
||||||
|
const [ apiClient, setApiClient ] = useState();
|
||||||
|
const [ movies, setMovies ] = useState([]);
|
||||||
|
const [ episodes, setEpisodes ] = useState([]);
|
||||||
|
const [ sports, setSports ] = useState([]);
|
||||||
|
const [ kids, setKids ] = useState([]);
|
||||||
|
const [ news, setNews ] = useState([]);
|
||||||
|
const [ programs, setPrograms ] = useState([]);
|
||||||
|
const [ videos, setVideos ] = useState([]);
|
||||||
|
|
||||||
|
const getDefaultParameters = () => ({
|
||||||
|
ParentId: parentId,
|
||||||
|
searchTerm: query,
|
||||||
|
Limit: 24,
|
||||||
|
Fields: 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount',
|
||||||
|
Recursive: true,
|
||||||
|
EnableTotalRecordCount: false,
|
||||||
|
ImageTypeLimit: 1,
|
||||||
|
IncludePeople: false,
|
||||||
|
IncludeMedia: false,
|
||||||
|
IncludeGenres: false,
|
||||||
|
IncludeStudios: false,
|
||||||
|
IncludeArtists: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: This query does not support Live TV filters
|
||||||
|
const fetchItems = (apiClient, params = {}) => apiClient?.getItems(
|
||||||
|
apiClient?.getCurrentUserId(),
|
||||||
|
{
|
||||||
|
...getDefaultParameters(),
|
||||||
|
IncludeMedia: true,
|
||||||
|
...params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const isLiveTV = () => collectionType === 'livetv';
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (serverId) setApiClient(ServerConnections.getApiClient(serverId));
|
||||||
|
}, [ serverId ]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Reset state
|
||||||
|
setMovies([]);
|
||||||
|
setEpisodes([]);
|
||||||
|
setSports([]);
|
||||||
|
setKids([]);
|
||||||
|
setNews([]);
|
||||||
|
setPrograms([]);
|
||||||
|
setVideos([]);
|
||||||
|
|
||||||
|
if (query && isLiveTV()) {
|
||||||
|
// Movies row
|
||||||
|
fetchItems(apiClient, {
|
||||||
|
IncludeItemTypes: 'LiveTvProgram',
|
||||||
|
IsMovie: true,
|
||||||
|
IsSeries: false,
|
||||||
|
IsSports: false,
|
||||||
|
IsKids: false,
|
||||||
|
IsNews: false
|
||||||
|
}).then(result => setMovies(result.Items));
|
||||||
|
// Episodes row
|
||||||
|
fetchItems(apiClient, {
|
||||||
|
IncludeItemTypes: 'LiveTvProgram',
|
||||||
|
IsMovie: false,
|
||||||
|
IsSeries: true,
|
||||||
|
IsSports: false,
|
||||||
|
IsKids: false,
|
||||||
|
IsNews: false
|
||||||
|
}).then(result => setEpisodes(result.Items));
|
||||||
|
// Sports row
|
||||||
|
fetchItems(apiClient, {
|
||||||
|
IncludeItemTypes: 'LiveTvProgram',
|
||||||
|
IsMovie: false,
|
||||||
|
IsSeries: false,
|
||||||
|
IsSports: true,
|
||||||
|
IsKids: false,
|
||||||
|
IsNews: false
|
||||||
|
}).then(result => setSports(result.Items));
|
||||||
|
// Kids row
|
||||||
|
fetchItems(apiClient, {
|
||||||
|
IncludeItemTypes: 'LiveTvProgram',
|
||||||
|
IsMovie: false,
|
||||||
|
IsSeries: false,
|
||||||
|
IsSports: false,
|
||||||
|
IsKids: true,
|
||||||
|
IsNews: false
|
||||||
|
}).then(result => setKids(result.Items));
|
||||||
|
// News row
|
||||||
|
fetchItems(apiClient, {
|
||||||
|
IncludeItemTypes: 'LiveTvProgram',
|
||||||
|
IsMovie: false,
|
||||||
|
IsSeries: false,
|
||||||
|
IsSports: false,
|
||||||
|
IsKids: false,
|
||||||
|
IsNews: true
|
||||||
|
}).then(result => setNews(result.Items));
|
||||||
|
// Programs row
|
||||||
|
fetchItems(apiClient, {
|
||||||
|
IncludeItemTypes: 'LiveTvProgram',
|
||||||
|
IsMovie: false,
|
||||||
|
IsSeries: false,
|
||||||
|
IsSports: false,
|
||||||
|
IsKids: false,
|
||||||
|
IsNews: false
|
||||||
|
}).then(result => setPrograms(result.Items));
|
||||||
|
// NOTE: I believe this is supposed to be home videos, but it
|
||||||
|
// includes TV channels so it should probably be included for Live TV
|
||||||
|
// Videos row
|
||||||
|
fetchItems(apiClient, {
|
||||||
|
MediaTypes: 'Video',
|
||||||
|
ExcludeItemTypes: 'Movie,Episode'
|
||||||
|
}).then(result => setVideos(result.Items));
|
||||||
|
}
|
||||||
|
}, [ query ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'searchResults',
|
||||||
|
'padded-bottom-page',
|
||||||
|
'padded-top',
|
||||||
|
{ 'hide': !query || !isLiveTV() }
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Movies')}
|
||||||
|
items={movies}
|
||||||
|
cardOptions={{
|
||||||
|
...CARD_OPTIONS,
|
||||||
|
shape: 'overflowPortrait'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Episodes')}
|
||||||
|
items={episodes}
|
||||||
|
cardOptions={CARD_OPTIONS}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Sports')}
|
||||||
|
items={sports}
|
||||||
|
cardOptions={CARD_OPTIONS}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Kids')}
|
||||||
|
items={kids}
|
||||||
|
cardOptions={CARD_OPTIONS}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('News')}
|
||||||
|
items={news}
|
||||||
|
cardOptions={CARD_OPTIONS}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Programs')}
|
||||||
|
items={programs}
|
||||||
|
cardOptions={CARD_OPTIONS}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Videos')}
|
||||||
|
items={videos}
|
||||||
|
cardOptions={{ showParentTitle: true }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
LiveTVSearchResults.propTypes = {
|
||||||
|
serverId: PropTypes.string,
|
||||||
|
parentId: PropTypes.string,
|
||||||
|
collectionType: PropTypes.string,
|
||||||
|
query: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LiveTVSearchResults;
|
258
src/components/search/SearchResults.js
Normal file
258
src/components/search/SearchResults.js
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import globalize from '../../scripts/globalize';
|
||||||
|
import ServerConnections from '../ServerConnections';
|
||||||
|
import SearchResultsRow from './SearchResultsRow';
|
||||||
|
|
||||||
|
const SearchResultsComponent = ({ serverId, parentId, collectionType, query }) => {
|
||||||
|
const [ apiClient, setApiClient ] = useState();
|
||||||
|
const [ movies, setMovies ] = useState([]);
|
||||||
|
const [ shows, setShows ] = useState([]);
|
||||||
|
const [ episodes, setEpisodes ] = useState([]);
|
||||||
|
const [ programs, setPrograms ] = useState([]);
|
||||||
|
const [ videos, setVideos ] = useState([]);
|
||||||
|
const [ playlists, setPlaylists ] = useState([]);
|
||||||
|
const [ artists, setArtists ] = useState([]);
|
||||||
|
const [ albums, setAlbums ] = useState([]);
|
||||||
|
const [ songs, setSongs ] = useState([]);
|
||||||
|
const [ photoAlbums, setPhotoAlbums ] = useState([]);
|
||||||
|
const [ photos, setPhotos ] = useState([]);
|
||||||
|
const [ audioBooks, setAudioBooks ] = useState([]);
|
||||||
|
const [ books, setBooks ] = useState([]);
|
||||||
|
const [ people, setPeople ] = useState([]);
|
||||||
|
|
||||||
|
const getDefaultParameters = () => ({
|
||||||
|
ParentId: parentId,
|
||||||
|
searchTerm: query,
|
||||||
|
Limit: 24,
|
||||||
|
Fields: 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount',
|
||||||
|
Recursive: true,
|
||||||
|
EnableTotalRecordCount: false,
|
||||||
|
ImageTypeLimit: 1,
|
||||||
|
IncludePeople: false,
|
||||||
|
IncludeMedia: false,
|
||||||
|
IncludeGenres: false,
|
||||||
|
IncludeStudios: false,
|
||||||
|
IncludeArtists: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchArtists = (apiClient, params = {}) => apiClient?.getArtists(
|
||||||
|
apiClient?.getCurrentUserId(),
|
||||||
|
{
|
||||||
|
...getDefaultParameters(),
|
||||||
|
IncludeArtists: true,
|
||||||
|
...params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const fetchItems = (apiClient, params = {}) => apiClient?.getItems(
|
||||||
|
apiClient?.getCurrentUserId(),
|
||||||
|
{
|
||||||
|
...getDefaultParameters(),
|
||||||
|
IncludeMedia: true,
|
||||||
|
...params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const fetchPeople = (apiClient, params = {}) => apiClient?.getPeople(
|
||||||
|
apiClient?.getCurrentUserId(),
|
||||||
|
{
|
||||||
|
...getDefaultParameters(),
|
||||||
|
IncludePeople: true,
|
||||||
|
...params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const isMovies = () => collectionType === 'movies';
|
||||||
|
|
||||||
|
const isMusic = () => collectionType === 'music';
|
||||||
|
|
||||||
|
const isTVShows = () => collectionType === 'tvshows' || collectionType === 'tv';
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (serverId) setApiClient(ServerConnections.getApiClient(serverId));
|
||||||
|
}, [ serverId ]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Reset state
|
||||||
|
setMovies([]);
|
||||||
|
setShows([]);
|
||||||
|
setEpisodes([]);
|
||||||
|
setPrograms([]);
|
||||||
|
setVideos([]);
|
||||||
|
setPlaylists([]);
|
||||||
|
setArtists([]);
|
||||||
|
setAlbums([]);
|
||||||
|
setSongs([]);
|
||||||
|
setPhotoAlbums([]);
|
||||||
|
setPhotos([]);
|
||||||
|
setAudioBooks([]);
|
||||||
|
setBooks([]);
|
||||||
|
setPeople([]);
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
// Movie libraries
|
||||||
|
if (!collectionType || isMovies()) {
|
||||||
|
// Movies row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'Movie' })
|
||||||
|
.then(result => setMovies(result.Items));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TV Show libraries
|
||||||
|
if (!collectionType || isTVShows()) {
|
||||||
|
// Shows row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'Series' })
|
||||||
|
.then(result => setShows(result.Items));
|
||||||
|
// Episodes row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'Episode' })
|
||||||
|
.then(result => setEpisodes(result.Items));
|
||||||
|
}
|
||||||
|
|
||||||
|
// People are included for Movies and TV Shows
|
||||||
|
if (!collectionType || isMovies() || isTVShows()) {
|
||||||
|
// People row
|
||||||
|
fetchPeople(apiClient).then(result => setPeople(result.Items));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Music libraries
|
||||||
|
if (!collectionType || isMusic()) {
|
||||||
|
// Playlists row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'Playlist' })
|
||||||
|
.then(results => setPlaylists(results.Items));
|
||||||
|
// Artists row
|
||||||
|
fetchArtists(apiClient).then(result => setArtists(result.Items));
|
||||||
|
// Albums row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'MusicAlbum' })
|
||||||
|
.then(result => setAlbums(result.Items));
|
||||||
|
// Songs row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'Audio' })
|
||||||
|
.then(result => setSongs(result.Items));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other libraries do not support in-library search currently
|
||||||
|
if (!collectionType) {
|
||||||
|
// Programs row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'LiveTvProgram' })
|
||||||
|
.then(result => setPrograms(result.Items));
|
||||||
|
// Videos row
|
||||||
|
fetchItems(apiClient, {
|
||||||
|
MediaTypes: 'Video',
|
||||||
|
ExcludeItemTypes: 'Movie,Episode'
|
||||||
|
}).then(result => setVideos(result.Items));
|
||||||
|
// Photo Albums row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'PhotoAlbum' })
|
||||||
|
.then(results => setPhotoAlbums(results.Items));
|
||||||
|
// Photos row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'Photo' })
|
||||||
|
.then(results => setPhotos(results.Items));
|
||||||
|
// Audio Books row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'AudioBook' })
|
||||||
|
.then(results => setAudioBooks(results.Items));
|
||||||
|
// Books row
|
||||||
|
fetchItems(apiClient, { IncludeItemTypes: 'Book' })
|
||||||
|
.then(results => setBooks(results.Items));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [ query ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'searchResults',
|
||||||
|
'padded-bottom-page',
|
||||||
|
'padded-top',
|
||||||
|
{ 'hide': !query || collectionType === 'livetv' }
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Movies')}
|
||||||
|
items={movies}
|
||||||
|
cardOptions={{ showYear: true }}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Shows')}
|
||||||
|
items={shows}
|
||||||
|
cardOptions={{ showYear: true }}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Episodes')}
|
||||||
|
items={episodes}
|
||||||
|
cardOptions={{
|
||||||
|
coverImage: true,
|
||||||
|
showParentTitle: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Programs')}
|
||||||
|
items={programs}
|
||||||
|
cardOptions={{
|
||||||
|
preferThumb: true,
|
||||||
|
inheritThumb: false,
|
||||||
|
showParentTitleOrTitle: true,
|
||||||
|
showTitle: false,
|
||||||
|
coverImage: true,
|
||||||
|
overlayMoreButton: true,
|
||||||
|
showAirTime: true,
|
||||||
|
showAirDateTime: true,
|
||||||
|
showChannelName: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Videos')}
|
||||||
|
items={videos}
|
||||||
|
cardOptions={{ showParentTitle: true }}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Playlists')}
|
||||||
|
items={playlists}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Artists')}
|
||||||
|
items={artists}
|
||||||
|
cardOptions={{ coverImage: true }}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Albums')}
|
||||||
|
items={albums}
|
||||||
|
cardOptions={{ showParentTitle: true }}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Songs')}
|
||||||
|
items={songs}
|
||||||
|
cardOptions={{ showParentTitle: true }}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('HeaderPhotoAlbums')}
|
||||||
|
items={photoAlbums}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Photos')}
|
||||||
|
items={photos}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('HeaderAudioBooks')}
|
||||||
|
items={audioBooks}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('Books')}
|
||||||
|
items={books}
|
||||||
|
/>
|
||||||
|
<SearchResultsRow
|
||||||
|
title={globalize.translate('People')}
|
||||||
|
items={people}
|
||||||
|
cardOptions={{ coverImage: true }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SearchResultsComponent.propTypes = {
|
||||||
|
serverId: PropTypes.string,
|
||||||
|
parentId: PropTypes.string,
|
||||||
|
collectionType: PropTypes.string,
|
||||||
|
query: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SearchResultsComponent;
|
|
@ -1,44 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
import SearchResults from './searchresults';
|
|
||||||
|
|
||||||
const SearchResultsComponent = ({ serverId, parentId, collectionType, query }) => {
|
|
||||||
const [ searchResults, setSearchResults ] = useState(null);
|
|
||||||
const searchResultsElement = useRef(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setSearchResults(
|
|
||||||
new SearchResults({
|
|
||||||
element: searchResultsElement.current,
|
|
||||||
serverId: serverId || ApiClient.serverId(),
|
|
||||||
parentId,
|
|
||||||
collectionType
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
searchResults?.destroy();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
searchResults?.search(query);
|
|
||||||
}, [ query ]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className='searchResults padded-bottom-page padded-top'
|
|
||||||
ref={searchResultsElement}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
SearchResultsComponent.propTypes = {
|
|
||||||
serverId: PropTypes.string,
|
|
||||||
parentId: PropTypes.string,
|
|
||||||
collectionType: PropTypes.string,
|
|
||||||
query: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SearchResultsComponent;
|
|
48
src/components/search/SearchResultsRow.js
Normal file
48
src/components/search/SearchResultsRow.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
import cardBuilder from '../cardbuilder/cardBuilder';
|
||||||
|
|
||||||
|
// There seems to be some compatibility issues here between
|
||||||
|
// React and our legacy web components, so we need to inject
|
||||||
|
// them as an html string for now =/
|
||||||
|
const createScroller = ({ title = '' }) => ({
|
||||||
|
__html: `<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${title}</h2>
|
||||||
|
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
||||||
|
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
||||||
|
</div>`
|
||||||
|
});
|
||||||
|
|
||||||
|
const SearchResultsRow = ({ title, items = [], cardOptions = {} }) => {
|
||||||
|
const element = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
cardBuilder.buildCards(items, {
|
||||||
|
itemsContainer: element.current?.querySelector('.itemsContainer'),
|
||||||
|
parentContainer: element.current,
|
||||||
|
shape: 'autooverflow',
|
||||||
|
scalable: true,
|
||||||
|
showTitle: true,
|
||||||
|
overlayText: false,
|
||||||
|
centerText: true,
|
||||||
|
allowBottomPadding: false,
|
||||||
|
...cardOptions
|
||||||
|
});
|
||||||
|
}, [ items ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={element}
|
||||||
|
className='verticalSection'
|
||||||
|
dangerouslySetInnerHTML={createScroller({ title })}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SearchResultsRow.propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
items: PropTypes.array,
|
||||||
|
cardOptions: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SearchResultsRow;
|
|
@ -1,581 +0,0 @@
|
||||||
import layoutManager from '../layoutManager';
|
|
||||||
import globalize from '../../scripts/globalize';
|
|
||||||
import cardBuilder from '../cardbuilder/cardBuilder';
|
|
||||||
import '../../elements/emby-scroller/emby-scroller';
|
|
||||||
import '../../elements/emby-itemscontainer/emby-itemscontainer';
|
|
||||||
import '../../elements/emby-button/emby-button';
|
|
||||||
import ServerConnections from '../ServerConnections';
|
|
||||||
import template from './searchresults.template.html';
|
|
||||||
|
|
||||||
function getSearchHints(instance, apiClient, query) {
|
|
||||||
if (!query.searchTerm) {
|
|
||||||
return Promise.resolve({
|
|
||||||
SearchHints: []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let allowSearch = true;
|
|
||||||
|
|
||||||
const queryIncludeItemTypes = query.IncludeItemTypes;
|
|
||||||
|
|
||||||
if (instance.options.collectionType === 'tvshows') {
|
|
||||||
if (query.IncludeArtists) {
|
|
||||||
allowSearch = false;
|
|
||||||
} else if (queryIncludeItemTypes === 'Movie' ||
|
|
||||||
queryIncludeItemTypes === 'LiveTvProgram' ||
|
|
||||||
queryIncludeItemTypes === 'MusicAlbum' ||
|
|
||||||
queryIncludeItemTypes === 'Audio' ||
|
|
||||||
queryIncludeItemTypes === 'Book' ||
|
|
||||||
queryIncludeItemTypes === 'AudioBook' ||
|
|
||||||
queryIncludeItemTypes === 'Playlist' ||
|
|
||||||
queryIncludeItemTypes === 'PhotoAlbum' ||
|
|
||||||
query.MediaTypes === 'Video' ||
|
|
||||||
query.MediaTypes === 'Photo') {
|
|
||||||
allowSearch = false;
|
|
||||||
}
|
|
||||||
} else if (instance.options.collectionType === 'movies') {
|
|
||||||
if (query.IncludeArtists) {
|
|
||||||
allowSearch = false;
|
|
||||||
} else if (queryIncludeItemTypes === 'Series' ||
|
|
||||||
queryIncludeItemTypes === 'Episode' ||
|
|
||||||
queryIncludeItemTypes === 'LiveTvProgram' ||
|
|
||||||
queryIncludeItemTypes === 'MusicAlbum' ||
|
|
||||||
queryIncludeItemTypes === 'Audio' ||
|
|
||||||
queryIncludeItemTypes === 'Book' ||
|
|
||||||
queryIncludeItemTypes === 'AudioBook' ||
|
|
||||||
queryIncludeItemTypes === 'Playlist' ||
|
|
||||||
queryIncludeItemTypes === 'PhotoAlbum' ||
|
|
||||||
query.MediaTypes === 'Video' ||
|
|
||||||
query.MediaTypes === 'Photo') {
|
|
||||||
allowSearch = false;
|
|
||||||
}
|
|
||||||
} else if (instance.options.collectionType === 'music') {
|
|
||||||
if (query.People) {
|
|
||||||
allowSearch = false;
|
|
||||||
} else if (queryIncludeItemTypes === 'Series' ||
|
|
||||||
queryIncludeItemTypes === 'Episode' ||
|
|
||||||
queryIncludeItemTypes === 'LiveTvProgram' ||
|
|
||||||
queryIncludeItemTypes === 'Movie') {
|
|
||||||
allowSearch = false;
|
|
||||||
}
|
|
||||||
} else if (instance.options.collectionType === 'livetv') {
|
|
||||||
if (query.IncludeArtists || query.IncludePeople) {
|
|
||||||
allowSearch = false;
|
|
||||||
} else if (queryIncludeItemTypes === 'Series' ||
|
|
||||||
queryIncludeItemTypes === 'Episode' ||
|
|
||||||
queryIncludeItemTypes === 'MusicAlbum' ||
|
|
||||||
queryIncludeItemTypes === 'Audio' ||
|
|
||||||
queryIncludeItemTypes === 'Book' ||
|
|
||||||
queryIncludeItemTypes === 'AudioBook' ||
|
|
||||||
queryIncludeItemTypes === 'PhotoAlbum' ||
|
|
||||||
queryIncludeItemTypes === 'Movie' ||
|
|
||||||
query.MediaTypes === 'Video' ||
|
|
||||||
query.MediaTypes === 'Photo') {
|
|
||||||
allowSearch = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (queryIncludeItemTypes === 'NullType') {
|
|
||||||
allowSearch = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allowSearch) {
|
|
||||||
return Promise.resolve({
|
|
||||||
SearchHints: []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the search hint query to a regular item query
|
|
||||||
if (apiClient.isMinServerVersion('3.4.1.31')) {
|
|
||||||
query.Fields = 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount';
|
|
||||||
query.Recursive = true;
|
|
||||||
query.EnableTotalRecordCount = false;
|
|
||||||
query.ImageTypeLimit = 1;
|
|
||||||
|
|
||||||
let methodName = 'getItems';
|
|
||||||
|
|
||||||
if (!query.IncludeMedia) {
|
|
||||||
if (query.IncludePeople) {
|
|
||||||
methodName = 'getPeople';
|
|
||||||
} else if (query.IncludeArtists) {
|
|
||||||
methodName = 'getArtists';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiClient[methodName](apiClient.getCurrentUserId(), query);
|
|
||||||
}
|
|
||||||
|
|
||||||
query.UserId = apiClient.getCurrentUserId();
|
|
||||||
|
|
||||||
return apiClient.getSearchHints(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
function search(instance, apiClient, context, value) {
|
|
||||||
if (value || layoutManager.tv) {
|
|
||||||
instance.mode = 'search';
|
|
||||||
} else {
|
|
||||||
instance.mode = 'suggestions';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instance.options.collectionType === 'livetv') {
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'LiveTvProgram',
|
|
||||||
IsMovie: true,
|
|
||||||
IsKids: false,
|
|
||||||
IsNews: false
|
|
||||||
|
|
||||||
}, context, '.movieResults', {
|
|
||||||
|
|
||||||
preferThumb: true,
|
|
||||||
inheritThumb: false,
|
|
||||||
shape: (enableScrollX() ? 'overflowPortrait' : 'portrait'),
|
|
||||||
showParentTitleOrTitle: true,
|
|
||||||
showTitle: false,
|
|
||||||
centerText: true,
|
|
||||||
coverImage: true,
|
|
||||||
overlayText: false,
|
|
||||||
overlayMoreButton: true,
|
|
||||||
showAirTime: true,
|
|
||||||
showAirDateTime: true,
|
|
||||||
showChannelName: true
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'Movie'
|
|
||||||
|
|
||||||
}, context, '.movieResults', {
|
|
||||||
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true,
|
|
||||||
showYear: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'Series'
|
|
||||||
|
|
||||||
}, context, '.seriesResults', {
|
|
||||||
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true,
|
|
||||||
showYear: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (instance.options.collectionType === 'livetv') {
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'LiveTvProgram',
|
|
||||||
IsSeries: true,
|
|
||||||
IsSports: false,
|
|
||||||
IsKids: false,
|
|
||||||
IsNews: false
|
|
||||||
|
|
||||||
}, context, '.episodeResults', {
|
|
||||||
|
|
||||||
preferThumb: true,
|
|
||||||
inheritThumb: false,
|
|
||||||
shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'),
|
|
||||||
showParentTitleOrTitle: true,
|
|
||||||
showTitle: false,
|
|
||||||
centerText: true,
|
|
||||||
coverImage: true,
|
|
||||||
overlayText: false,
|
|
||||||
overlayMoreButton: true,
|
|
||||||
showAirTime: true,
|
|
||||||
showAirDateTime: true,
|
|
||||||
showChannelName: true
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'Episode'
|
|
||||||
|
|
||||||
}, context, '.episodeResults', {
|
|
||||||
|
|
||||||
coverImage: true,
|
|
||||||
showTitle: true,
|
|
||||||
showParentTitle: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
// NullType to hide
|
|
||||||
IncludeItemTypes: instance.options.collectionType === 'livetv' ? 'LiveTvProgram' : 'NullType',
|
|
||||||
IsSports: true
|
|
||||||
|
|
||||||
}, context, '.sportsResults', {
|
|
||||||
|
|
||||||
preferThumb: true,
|
|
||||||
inheritThumb: false,
|
|
||||||
shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'),
|
|
||||||
showParentTitleOrTitle: true,
|
|
||||||
showTitle: false,
|
|
||||||
centerText: true,
|
|
||||||
coverImage: true,
|
|
||||||
overlayText: false,
|
|
||||||
overlayMoreButton: true,
|
|
||||||
showAirTime: true,
|
|
||||||
showAirDateTime: true,
|
|
||||||
showChannelName: true
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
// NullType to hide
|
|
||||||
IncludeItemTypes: instance.options.collectionType === 'livetv' ? 'LiveTvProgram' : 'NullType',
|
|
||||||
IsKids: true
|
|
||||||
|
|
||||||
}, context, '.kidsResults', {
|
|
||||||
|
|
||||||
preferThumb: true,
|
|
||||||
inheritThumb: false,
|
|
||||||
shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'),
|
|
||||||
showParentTitleOrTitle: true,
|
|
||||||
showTitle: false,
|
|
||||||
centerText: true,
|
|
||||||
coverImage: true,
|
|
||||||
overlayText: false,
|
|
||||||
overlayMoreButton: true,
|
|
||||||
showAirTime: true,
|
|
||||||
showAirDateTime: true,
|
|
||||||
showChannelName: true
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
// NullType to hide
|
|
||||||
IncludeItemTypes: instance.options.collectionType === 'livetv' ? 'LiveTvProgram' : 'NullType',
|
|
||||||
IsNews: true
|
|
||||||
|
|
||||||
}, context, '.newsResults', {
|
|
||||||
|
|
||||||
preferThumb: true,
|
|
||||||
inheritThumb: false,
|
|
||||||
shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'),
|
|
||||||
showParentTitleOrTitle: true,
|
|
||||||
showTitle: false,
|
|
||||||
centerText: true,
|
|
||||||
coverImage: true,
|
|
||||||
overlayText: false,
|
|
||||||
overlayMoreButton: true,
|
|
||||||
showAirTime: true,
|
|
||||||
showAirDateTime: true,
|
|
||||||
showChannelName: true
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'LiveTvProgram',
|
|
||||||
IsMovie: instance.options.collectionType === 'livetv' ? false : null,
|
|
||||||
IsSeries: instance.options.collectionType === 'livetv' ? false : null,
|
|
||||||
IsSports: instance.options.collectionType === 'livetv' ? false : null,
|
|
||||||
IsKids: instance.options.collectionType === 'livetv' ? false : null,
|
|
||||||
IsNews: instance.options.collectionType === 'livetv' ? false : null
|
|
||||||
|
|
||||||
}, context, '.programResults', {
|
|
||||||
|
|
||||||
preferThumb: true,
|
|
||||||
inheritThumb: false,
|
|
||||||
shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'),
|
|
||||||
showParentTitleOrTitle: true,
|
|
||||||
showTitle: false,
|
|
||||||
centerText: true,
|
|
||||||
coverImage: true,
|
|
||||||
overlayText: false,
|
|
||||||
overlayMoreButton: true,
|
|
||||||
showAirTime: true,
|
|
||||||
showAirDateTime: true,
|
|
||||||
showChannelName: true
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
MediaTypes: 'Video',
|
|
||||||
ExcludeItemTypes: 'Movie,Episode'
|
|
||||||
|
|
||||||
}, context, '.videoResults', {
|
|
||||||
|
|
||||||
showParentTitle: true,
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: true,
|
|
||||||
IncludeMedia: false,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false
|
|
||||||
|
|
||||||
}, context, '.peopleResults', {
|
|
||||||
|
|
||||||
coverImage: true,
|
|
||||||
showTitle: true
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: false,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: true
|
|
||||||
|
|
||||||
}, context, '.artistResults', {
|
|
||||||
coverImage: true,
|
|
||||||
showTitle: true
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'MusicAlbum'
|
|
||||||
|
|
||||||
}, context, '.albumResults', {
|
|
||||||
|
|
||||||
showParentTitle: true,
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'Audio'
|
|
||||||
|
|
||||||
}, context, '.songResults', {
|
|
||||||
|
|
||||||
showParentTitle: true,
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true,
|
|
||||||
overlayPlayButton: true
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
MediaTypes: 'Photo'
|
|
||||||
|
|
||||||
}, context, '.photoResults', {
|
|
||||||
|
|
||||||
showParentTitle: false,
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'PhotoAlbum'
|
|
||||||
|
|
||||||
}, context, '.photoAlbumResults', {
|
|
||||||
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'Book'
|
|
||||||
|
|
||||||
}, context, '.bookResults', {
|
|
||||||
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'AudioBook'
|
|
||||||
|
|
||||||
}, context, '.audioBookResults', {
|
|
||||||
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true
|
|
||||||
});
|
|
||||||
|
|
||||||
searchType(instance, apiClient, {
|
|
||||||
searchTerm: value,
|
|
||||||
IncludePeople: false,
|
|
||||||
IncludeMedia: true,
|
|
||||||
IncludeGenres: false,
|
|
||||||
IncludeStudios: false,
|
|
||||||
IncludeArtists: false,
|
|
||||||
IncludeItemTypes: 'Playlist'
|
|
||||||
|
|
||||||
}, context, '.playlistResults', {
|
|
||||||
|
|
||||||
showTitle: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchType(instance, apiClient, query, context, section, cardOptions) {
|
|
||||||
query.Limit = enableScrollX() ? 24 : 16;
|
|
||||||
query.ParentId = instance.options.parentId;
|
|
||||||
|
|
||||||
getSearchHints(instance, apiClient, query).then(function (result) {
|
|
||||||
populateResults(result, context, section, cardOptions);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateResults(result, context, section, cardOptions) {
|
|
||||||
section = context.querySelector(section);
|
|
||||||
|
|
||||||
const items = result.Items || result.SearchHints;
|
|
||||||
|
|
||||||
const itemsContainer = section.querySelector('.itemsContainer');
|
|
||||||
|
|
||||||
cardBuilder.buildCards(items, Object.assign({
|
|
||||||
|
|
||||||
itemsContainer: itemsContainer,
|
|
||||||
parentContainer: section,
|
|
||||||
shape: enableScrollX() ? 'autooverflow' : 'auto',
|
|
||||||
scalable: true,
|
|
||||||
overlayText: false,
|
|
||||||
centerText: true,
|
|
||||||
allowBottomPadding: !enableScrollX()
|
|
||||||
|
|
||||||
}, cardOptions || {}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function enableScrollX() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function replaceAll(originalString, strReplace, strWith) {
|
|
||||||
const reg = new RegExp(strReplace, 'ig');
|
|
||||||
return originalString.replace(reg, strWith);
|
|
||||||
}
|
|
||||||
|
|
||||||
function embed(elem, instance) {
|
|
||||||
let workingTemplate = template;
|
|
||||||
if (!enableScrollX()) {
|
|
||||||
workingTemplate = replaceAll(workingTemplate, 'data-horizontal="true"', 'data-horizontal="false"');
|
|
||||||
workingTemplate = replaceAll(workingTemplate, 'itemsContainer scrollSlider', 'itemsContainer scrollSlider vertical-wrap');
|
|
||||||
}
|
|
||||||
|
|
||||||
const html = globalize.translateHtml(workingTemplate, 'core');
|
|
||||||
|
|
||||||
elem.innerHTML = html;
|
|
||||||
|
|
||||||
elem.classList.add('searchResults');
|
|
||||||
instance.search('');
|
|
||||||
}
|
|
||||||
|
|
||||||
class SearchResults {
|
|
||||||
constructor(options) {
|
|
||||||
this.options = options;
|
|
||||||
embed(options.element, this);
|
|
||||||
}
|
|
||||||
search(value) {
|
|
||||||
const apiClient = ServerConnections.getApiClient(this.options.serverId);
|
|
||||||
|
|
||||||
search(this, apiClient, this.options.element, value);
|
|
||||||
}
|
|
||||||
destroy() {
|
|
||||||
const options = this.options;
|
|
||||||
if (options) {
|
|
||||||
options.element.classList.remove('searchFields');
|
|
||||||
}
|
|
||||||
this.options = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SearchResults;
|
|
|
@ -1,145 +0,0 @@
|
||||||
<div class="hide verticalSection searchSuggestions" style="text-align:center;">
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h2 class="sectionTitle padded-left padded-right">${Suggestions}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="searchSuggestionsList padded-left padded-right">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection movieResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Movies}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection seriesResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Shows}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection episodeResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Episodes}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection sportsResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Sports}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection kidsResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Kids}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection newsResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${News}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection programResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Programs}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection videoResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Videos}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection playlistResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Playlists}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection artistResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Artists}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection albumResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Albums}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection songResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Songs}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection photoAlbumResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${HeaderPhotoAlbums}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection photoResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Photos}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection audioBookResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${HeaderAudioBooks}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection bookResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${Books}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hide verticalSection peopleResults">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards focuscontainer-x padded-left padded-right">${People}</h2>
|
|
||||||
|
|
||||||
<div is="emby-scroller" data-horizontal="true" data-centerfocus="card" class="padded-top-focusscale padded-bottom-focusscale">
|
|
||||||
<div is="emby-itemscontainer" class="focuscontainer-x itemsContainer scrollSlider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
Loading…
Add table
Add a link
Reference in a new issue