1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

update search

This commit is contained in:
Luke Pulverenti 2016-06-27 13:28:36 -04:00
parent a66d44127f
commit 036319e68b
8 changed files with 183 additions and 562 deletions

View file

@ -1,193 +0,0 @@
.searchHints {
margin-top: 1em;
}
.searchHint {
display: block;
text-decoration: none;
color: #fff;
border-bottom: 1px solid #444;
}
.searchHint:hover {
background-color: #444;
}
.searchHint:focus {
background-color: #444;
}
.searchHintImage {
display: inline-block;
width: 20%;
vertical-align: middle;
margin: 4px 0;
}
.searchHintContent {
vertical-align: top;
display: inline-block;
width: 80%;
}
.searchHintName {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color: #fff;
font-weight: normal !important;
}
.searchHintSecondaryText {
color: #fff;
margin-top: 3px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-weight: 300;
}
.searchHintContentInner {
padding: 2px 5px;
}
@-moz-keyframes spinPulse {
0% {
-moz-transform: rotate(160deg);
opacity: 0;
box-shadow: 0 0 1px #2187e7;
}
50% {
-moz-transform: rotate(145deg);
opacity: 1;
}
100% {
-moz-transform: rotate(-320deg);
opacity: 0;
}
}
@-moz-keyframes spinoffPulse {
0% {
-moz-transform: rotate(0deg);
}
100% {
-moz-transform: rotate(360deg);
}
}
@-webkit-keyframes spinPulse {
0% {
-webkit-transform: rotate(160deg);
opacity: 0;
box-shadow: 0 0 1px #2187e7;
}
50% {
-webkit-transform: rotate(145deg);
opacity: 1;
}
100% {
-webkit-transform: rotate(-320deg);
opacity: 0;
}
}
@-webkit-keyframes spinoffPulse {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
.headerSearchInput {
margin: 0 !important;
background: #222 !important;
border: 0 !important;
color: #eee !important;
border-radius: 0 !important;
padding: 7px 0 6px 0 !important;
text-indent: 10px !important;
font-family: inherit;
outline: none;
vertical-align: middle;
width: 85% !important;
display: inline-block !important;
height: 100%!important;
}
.viewMenuSearch {
position: fixed;
top: 0;
left: 0%;
right: 0;
background: #000000;
z-index: 1000;
}
@media all and (min-width: 600px) {
.headerSearchInput {
width: 90% !important;
}
}
@media all and (min-width: 800px) {
.headerSearchInput {
width: 93% !important;
}
}
@media all and (min-width: 1200px) {
.headerSearchInput {
width: 96% !important;
}
}
.viewMenuSearch:not(.hide) {
display: inline-block;
}
.viewMenuSearchForm {
max-width: none;
padding: 5px;
}
.searchResultsOverlay {
position: fixed;
top: 50px;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
border: 0 !important;
}
.searchResultsContainer {
padding: .5em;
}
@media all and (min-width: 800px) {
.searchResultsContainer {
padding-left: 1em;
padding-right: 1em;
}
}
@media all and (min-height: 800px) {
.searchResultsContainer {
padding-top: 1em;
padding-bottom: 1em;
}
}
.btnCloseSearch {
padding-top: 0;
padding-bottom: 0;
}

View file

@ -135,10 +135,6 @@ h1, h1 a {
border-radius: 10px;
}
.viewMenuSearch {
background: #1c1c1c;
}
.bottomFab {
bottom: 120px !important;
}

View file

@ -24,13 +24,7 @@
html += '<button is="paper-icon-button-light" class="btnCast headerButton headerButtonRight hide autoSize"><i class="md-icon">cast</i></button>';
if (AppInfo.enableSearchInTopMenu) {
html += '<button type="button" is="paper-icon-button-light" class=headerButton headerButtonRight headerSearchButton hide autoSize" onclick="Search.showSearchPanel();"><i class="md-icon">search</i></button>';
html += '<div class="viewMenuSearch hide">';
html += '<form class="viewMenuSearchForm">';
html += '<input type="text" class="headerSearchInput" autocomplete="off" />';
html += '<button type="button" is="paper-icon-button-light" class="btnCloseSearch autoSize"><i class="md-icon">close</i></button>';
html += '</form>';
html += '</div>';
html += '<button type="button" is="paper-icon-button-light" class="headerButton headerButtonRight headerSearchButton hide autoSize"><i class="md-icon">search</i></button>';
}
html += '<button is="paper-icon-button-light" class="headerButton headerButtonRight headerVoiceButton hide autoSize"><i class="md-icon">mic</i></button>';
@ -175,6 +169,10 @@
});
}
function showSearch() {
Dashboard.navigate('search.html');
}
function onHeaderUserButtonClick(e) {
Dashboard.showUserFlyout(e.target);
}
@ -252,6 +250,11 @@
headerVoiceButton.addEventListener('click', showVoice);
}
var headerSearchButton = document.querySelector('.headerSearchButton');
if (headerSearchButton) {
headerSearchButton.addEventListener('click', showSearch);
}
var headerUserButton = document.querySelector('.headerUserButton');
if (headerUserButton) {
headerUserButton.addEventListener('click', onHeaderUserButtonClick);

View file

@ -1,266 +0,0 @@
define(['libraryBrowser', 'events', 'scrollStyles', 'scripts/librarymenu'], function (libraryBrowser, events) {
var searchHintTimeout;
function clearSearchHintTimeout() {
if (searchHintTimeout) {
clearTimeout(searchHintTimeout);
searchHintTimeout = null;
}
}
function getAdditionalTextLines(hint) {
if (hint.Type == "Audio") {
return [[hint.AlbumArtist, hint.Album].join(" - ")];
}
else if (hint.Type == "MusicAlbum") {
return [hint.AlbumArtist];
}
else if (hint.Type == "MusicArtist") {
return [Globalize.translate('LabelArtist')];
}
else if (hint.Type == "Movie") {
return [Globalize.translate('LabelMovie')];
}
else if (hint.Type == "MusicVideo") {
return [Globalize.translate('LabelMusicVideo')];
}
else if (hint.Type == "Episode") {
return [Globalize.translate('LabelEpisode')];
}
else if (hint.Type == "Series") {
return [Globalize.translate('Series')];
}
else if (hint.Type == "BoxSet") {
return [Globalize.translate('LabelCollection')];
}
else if (hint.ChannelName) {
return [hint.ChannelName];
}
return [hint.Type];
}
function search() {
var self = this;
self.showSearchPanel = function () {
showSearchMenu();
};
}
window.Search = new search();
function renderSearchResultsInOverlay(elem, hints) {
// Massage the objects to look like regular items
hints = hints.map(function (i) {
i.Id = i.ItemId;
i.ImageTags = {};
i.UserData = {};
if (i.PrimaryImageTag) {
i.ImageTags.Primary = i.PrimaryImageTag;
}
return i;
});
var html = libraryBrowser.getPosterViewHtml({
items: hints,
shape: "auto",
lazy: true,
overlayText: false,
showTitle: true,
centerImage: true,
centerText: true,
textLines: getAdditionalTextLines,
overlayPlayButton: true
});
var itemsContainer = elem.querySelector('.itemsContainer');
itemsContainer.innerHTML = html;
ImageLoader.lazyChildren(itemsContainer);
}
function requestSearchHintsForOverlay(elem, searchTerm) {
var currentTimeout = searchHintTimeout;
Dashboard.showLoadingMsg();
ApiClient.getSearchHints({
userId: Dashboard.getCurrentUserId(),
searchTerm: (searchTerm || '').trim(),
limit: 30
}).then(function (result) {
if (currentTimeout == searchHintTimeout) {
renderSearchResultsInOverlay(elem, result.SearchHints);
}
Dashboard.hideLoadingMsg();
}, function () {
Dashboard.hideLoadingMsg();
});
}
function updateSearchOverlay(elem, searchTerm) {
if (!searchTerm) {
var itemsContainer = elem.querySelector('.itemsContainer');
if (itemsContainer) {
itemsContainer.innerHTML = '';
}
clearSearchHintTimeout();
return;
}
clearSearchHintTimeout();
searchHintTimeout = setTimeout(function () {
requestSearchHintsForOverlay(elem, searchTerm);
}, 300);
}
function getSearchOverlay(createIfNeeded) {
var elem = document.querySelector('.searchResultsOverlay');
if (createIfNeeded && !elem) {
var div = document.createElement('div');
div.className = 'searchResultsOverlay ui-body-b smoothScrollY background-theme-b';
div.innerHTML = '<div class="searchResultsContainer"><div class="itemsContainer"></div></div></div>';
document.body.appendChild(div);
libraryBrowser.createCardMenus(div);
elem = div;
}
return elem;
}
var isVisible;
function onHeaderSearchChange(val) {
var elem;
if (val) {
elem = getSearchOverlay(true);
if (!isVisible) {
fadeIn(elem, 1);
}
isVisible = true;
document.body.classList.add('bodyWithPopupOpen');
updateSearchOverlay(elem, val);
} else {
elem = getSearchOverlay(false);
if (elem) {
updateSearchOverlay(elem, '');
if (isVisible) {
fadeOut(elem, 1);
isVisible = false;
}
document.body.classList.remove('bodyWithPopupOpen');
}
}
}
function fadeIn(elem, iterations) {
var keyframes = [
{ opacity: '0', offset: 0 },
{ opacity: '1', offset: 1 }];
var timing = { duration: 200, iterations: iterations, fill: 'both' };
if (elem.animate) {
elem.animate(keyframes, timing);
}
}
function fadeOut(elem, iterations) {
var keyframes = [
{ opacity: '1', offset: 0 },
{ opacity: '0', offset: 1 }];
var timing = { duration: 600, iterations: iterations, fill: 'both' };
var onfinish = function () {
elem.parentNode.removeChild(elem);
};
if (elem.animate) {
elem.animate(keyframes, timing).onfinish = onfinish;
} else {
onfinish();
}
}
function bindSearchEvents() {
require(['searchmenu'], function (searchmenu) {
events.on(window.SearchMenu, 'closed', closeSearchResults);
events.on(window.SearchMenu, 'change', function (e, value) {
onHeaderSearchChange(value);
});
});
}
function closeSearchResults() {
onHeaderSearchChange('');
hideSearchMenu();
}
function showSearchMenu() {
require(['searchmenu'], function (searchmenu) {
window.SearchMenu.show();
});
}
function hideSearchMenu() {
require(['searchmenu'], function (searchmenu) {
window.SearchMenu.hide();
});
}
document.addEventListener('viewbeforehide', closeSearchResults);
bindSearchEvents();
// dismiss search UI if user clicks a play button on a search result
events.on(MediaController, 'beforeplaybackstart', closeSearchResults);
});

View file

@ -1,73 +0,0 @@
define([], function () {
function fadeIn(elem, iterations) {
var keyframes = [
{ opacity: '0', offset: 0 },
{ opacity: '1', offset: 1 }];
var timing = { duration: 200, iterations: iterations };
return elem.animate(keyframes, timing);
}
function searchMenu() {
var self = this;
var headerSearchInput = document.querySelector('.headerSearchInput');
self.show = function () {
require(['css!css/search.css'], function () {
headerSearchInput.value = '';
document.querySelector('.btnCloseSearch').classList.add('hide');
var elem = document.querySelector('.viewMenuSearch');
elem.classList.remove('hide');
var onFinish = function() {
headerSearchInput.focus();
document.querySelector('.btnCloseSearch').classList.remove('hide');
};
if (elem.animate) {
fadeIn(elem, 1).onfinish = onFinish;
} else {
onFinish();
}
});
};
self.hide = function () {
var viewMenuSearch = document.querySelector('.viewMenuSearch');
if (!viewMenuSearch) {
return;
}
if (!viewMenuSearch.classList.contains('hide')) {
document.querySelector('.btnCloseSearch').classList.add('hide');
viewMenuSearch.classList.add('hide');
}
};
document.querySelector('.viewMenuSearchForm').addEventListener('submit', function (e) {
e.preventDefault();
return false;
});
document.querySelector('.btnCloseSearch').addEventListener('click', function () {
self.hide();
Events.trigger(self, 'closed');
});
headerSearchInput.addEventListener('input', function (e) {
Events.trigger(self, 'change', [this.value]);
});
}
window.SearchMenu = new searchMenu();
return Window.SearchMenu;
});

View file

@ -1,4 +1,4 @@
define([], function () {
define(['libraryBrowser', 'focusManager', 'emby-input', 'paper-icon-button-light', 'material-icons'], function (libraryBrowser, focusManager) {
function loadSuggestions(page) {
@ -29,13 +29,160 @@
});
}
pageIdOn('pageshow', "searchPage", function () {
return function (view, params) {
var page = this;
loadSuggestions(page);
var textSuggestions = view.querySelector('.textSuggestions');
var searchResults = view.querySelector('.searchResults');
var searchHintTimeout;
Search.showSearchPanel();
function clearSearchHintTimeout() {
if (searchHintTimeout) {
clearTimeout(searchHintTimeout);
searchHintTimeout = null;
}
}
function showTextSuggestions() {
if (AppInfo.enableAppLayouts) {
textSuggestions.classList.remove('hide');
}
}
function getAdditionalTextLines(hint) {
if (hint.Type == "Audio") {
return [[hint.AlbumArtist, hint.Album].join(" - ")];
}
else if (hint.Type == "MusicAlbum") {
return [hint.AlbumArtist];
}
else if (hint.Type == "MusicArtist") {
return [Globalize.translate('LabelArtist')];
}
else if (hint.Type == "Movie") {
return [Globalize.translate('LabelMovie')];
}
else if (hint.Type == "MusicVideo") {
return [Globalize.translate('LabelMusicVideo')];
}
else if (hint.Type == "Episode") {
return [Globalize.translate('LabelEpisode')];
}
else if (hint.Type == "Series") {
return [Globalize.translate('Series')];
}
else if (hint.Type == "BoxSet") {
return [Globalize.translate('LabelCollection')];
}
else if (hint.ChannelName) {
return [hint.ChannelName];
}
return [hint.Type];
}
function renderSearchResultsInOverlay(hints) {
// Massage the objects to look like regular items
hints = hints.map(function (i) {
i.Id = i.ItemId;
i.ImageTags = {};
i.UserData = {};
if (i.PrimaryImageTag) {
i.ImageTags.Primary = i.PrimaryImageTag;
}
return i;
});
var html = libraryBrowser.getPosterViewHtml({
items: hints,
shape: "auto",
lazy: true,
overlayText: false,
showTitle: true,
centerImage: true,
centerText: true,
textLines: getAdditionalTextLines,
overlayPlayButton: true
});
var itemsContainer = searchResults;
itemsContainer.innerHTML = html;
searchResults.classList.remove('hide');
textSuggestions.classList.add('hide');
ImageLoader.lazyChildren(itemsContainer);
}
function requestSearchHintsForOverlay(searchTerm) {
var currentTimeout = searchHintTimeout;
Dashboard.showLoadingMsg();
ApiClient.getSearchHints({
userId: Dashboard.getCurrentUserId(),
searchTerm: (searchTerm || '').trim(),
limit: 30
}).then(function (result) {
if (currentTimeout == searchHintTimeout) {
renderSearchResultsInOverlay(result.SearchHints);
}
Dashboard.hideLoadingMsg();
}, function () {
Dashboard.hideLoadingMsg();
});
}
function onSearchChange(val) {
if (!val) {
clearSearchHintTimeout();
searchResults.classList.add('hide');
searchResults.innerHTML = '';
showTextSuggestions();
return;
}
clearSearchHintTimeout();
searchHintTimeout = setTimeout(function () {
requestSearchHintsForOverlay(val);
}, 300);
}
if (AppInfo.enableAppLayouts) {
showTextSuggestions();
loadSuggestions(view);
}
view.addEventListener('viewshow', function () {
focusManager.focus(view.querySelector('.txtSearch'));
});
view.querySelector('.txtSearch').addEventListener('input', function () {
onSearchChange(this.value);
});
};
});

View file

@ -830,7 +830,7 @@ var Dashboard = {
Dashboard.onBrowseCommand(cmd.Arguments);
break;
case 'GoToSearch':
Search.showSearchPanel();
Dashboard.navigate('search.html');
break;
case 'DisplayMessage':
{
@ -2212,12 +2212,6 @@ var AppInfo = {};
define("detailtablecss", ['css!css/detailtable.css']);
define("tileitemcss", ['css!css/tileitem.css']);
if (Dashboard.isRunningInCordova() && browserInfo.safari) {
define("searchmenu", ["cordova/searchmenu"]);
} else {
define("searchmenu", ["scripts/searchmenu"]);
}
define("buttonenabled", ["legacy/buttonenabled"]);
var deps = [];
@ -2902,7 +2896,8 @@ var AppInfo = {};
defineRoute({
path: '/search.html',
dependencies: [],
autoFocus: false
autoFocus: false,
controller: 'scripts/searchpage'
});
defineRoute({
@ -3159,7 +3154,6 @@ var AppInfo = {};
deps.push('devices/ie/ie');
}
deps.push('scripts/search');
deps.push('scripts/librarylist');
deps.push('scripts/librarymenu');

View file

@ -1,12 +1,25 @@
<div id="searchPage" data-role="page" class="page homePage libraryPage allLibraryPage noSecondaryNavPage" data-title="${ButtonSearch}" data-require="scripts/searchpage">
<div id="searchPage" data-role="page" class="page libraryPage allLibraryPage noSecondaryNavPage" data-title="${ButtonSearch}" data-backbutton="true">
<div data-role="content">
<div style="text-align:center;">
<div class="readOnlyContent" style="text-align: center;margin: 0 auto;">
<div class="inputContainer">
<div style="display: flex; align-items: center;">
<i class="md-icon" style="width:28px;height:28px;font-size:28px;color:#ccc;">search</i>
<div style="flex-grow:1;">
<input is="emby-input" class="txtSearch" autocomplete="off" autofocus />
</div>
</div>
</div>
<div class="textSuggestions hide">
<h1>${TabSuggestions}</h1>
<div class="searchSuggestions">
</div>
</div>
</div>
<div class="searchResults hide"></div>
</div>
</div>