mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Updated loot-search (now loot-search-toolbar)
Decoupled it from external code, which can now be run by handling events.
This commit is contained in:
@@ -66,6 +66,7 @@ function vulcanizeTests(releasePath) {
|
||||
'test_loot-dropdown-menu.html',
|
||||
'test_loot-message-dialog.html',
|
||||
'test_loot-plugin-item.html',
|
||||
'test_loot-search-toolbar.html',
|
||||
];
|
||||
|
||||
tests.forEach((test) => {
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
<link rel="import" href="../../../../bower_components/polymer/polymer.html">
|
||||
|
||||
<link rel="import" href="../../../../bower_components/iron-icons/iron-icons.html">
|
||||
<link rel="import" href="../../../../bower_components/iron-flex-layout/iron-flex-layout.html">
|
||||
|
||||
<link rel="import" href="../../../../bower_components/paper-icon-button/paper-icon-button.html">
|
||||
<link rel="import" href="../../../../bower_components/paper-input/paper-input.html">
|
||||
<link rel="import" href="../../../../bower_components/paper-toolbar/paper-toolbar.html">
|
||||
<link rel="import" href="../../../../bower_components/paper-tooltip/paper-tooltip.html">
|
||||
|
||||
<!-- events
|
||||
|
||||
loot-search-begin: Fired when a search begins.
|
||||
loot-search-change-selection: Fired when the selected result changes.
|
||||
loot-search-end: Fired when the close button is clicked.
|
||||
|
||||
-->
|
||||
<dom-module id="loot-search-toolbar">
|
||||
<template>
|
||||
<style>
|
||||
paper-input {
|
||||
@apply(--layout-horizontal);
|
||||
@apply(--layout-flex);
|
||||
--paper-input-container: {
|
||||
@apply(--layout-flex);
|
||||
};
|
||||
--paper-input-container-input-color: var(--loot-dark-theme-text-color);
|
||||
--paper-input-container-label: {
|
||||
color: var(--loot-dark-theme-disabled-color);
|
||||
}
|
||||
--paper-input-container-underline: {
|
||||
background-color: var(--loot-dark-theme-divider-color);
|
||||
};
|
||||
}
|
||||
#count {
|
||||
font-weight: 400;
|
||||
font-size: 0.857rem;
|
||||
color: var(--loot-dark-theme-secondary-color);
|
||||
}
|
||||
</style>
|
||||
<paper-toolbar>
|
||||
<paper-input id="search" label="Search cards" no-label-float></paper-input>
|
||||
<div id="count">
|
||||
<span>[[_computeResultNum(_currentResult)]]</span>
|
||||
/
|
||||
<span><!-- number of results --></span>
|
||||
</div>
|
||||
<paper-icon-button id="prev" icon="expand-less" disabled></paper-icon-button>
|
||||
<paper-icon-button id="next" icon="expand-more" disabled></paper-icon-button>
|
||||
<paper-icon-button id="close" icon="close"></paper-icon-button>
|
||||
</paper-toolbar>
|
||||
</template>
|
||||
<script>
|
||||
'use strict';
|
||||
Polymer({ // eslint-disable-line new-cap, no-undef
|
||||
is: 'loot-search-toolbar',
|
||||
properties: {
|
||||
_currentResult: {
|
||||
type: Number,
|
||||
value: -1,
|
||||
observer: '_currentResultChanged',
|
||||
},
|
||||
results: {
|
||||
type: Array,
|
||||
value: () => { return []; },
|
||||
observer: '_resultsChanged',
|
||||
},
|
||||
},
|
||||
|
||||
_currentResultChanged(newValue) {
|
||||
if (this.results && this.results.length > 0) {
|
||||
if (this.results.length === 1) {
|
||||
this.$.prev.disabled = true;
|
||||
this.$.next.disabled = true;
|
||||
} else if (newValue === 0) {
|
||||
this.$.prev.disabled = true;
|
||||
this.$.next.disabled = false;
|
||||
} else if (newValue === this.results.length - 1) {
|
||||
this.$.prev.disabled = false;
|
||||
this.$.next.disabled = true;
|
||||
} else {
|
||||
this.$.prev.disabled = false;
|
||||
this.$.next.disabled = false;
|
||||
}
|
||||
}
|
||||
if (newValue > -1) {
|
||||
this.dispatchEvent(new CustomEvent('loot-search-change-selection', {
|
||||
detail: { selection: this.results[newValue] },
|
||||
bubbles: true,
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
_resultsChanged(newValue) {
|
||||
this.$.count.lastElementChild.textContent = newValue.length;
|
||||
if (newValue.length > 0) {
|
||||
this._currentResult = 0;
|
||||
}
|
||||
},
|
||||
|
||||
attached() {
|
||||
this.$.search.addEventListener('input', this._onSearch);
|
||||
this.$.search.addEventListener('keyup', this._onEnter);
|
||||
this.$.prev.addEventListener('click', this._onPrev);
|
||||
this.$.next.addEventListener('click', this._onNext);
|
||||
this.$.close.addEventListener('click', this._onClose);
|
||||
},
|
||||
|
||||
detached() {
|
||||
this.$.search.removeEventListener('input', this._onSearch);
|
||||
this.$.search.removeEventListener('keyup', this._onEnter);
|
||||
this.$.prev.removeEventListener('click', this._onPrev);
|
||||
this.$.next.removeEventListener('click', this._onNext);
|
||||
this.$.close.removeEventListener('change', this._onClose);
|
||||
},
|
||||
|
||||
_onEnter(evt) {
|
||||
const host = evt.target.parentElement.parentNode.host;
|
||||
if (evt.keyCode !== 13 || host.results.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (host._currentResult === host.results.length - 1) {
|
||||
host._currentResult = 0;
|
||||
} else {
|
||||
++host._currentResult;
|
||||
}
|
||||
},
|
||||
|
||||
focusInput() {
|
||||
this.$.search.focus();
|
||||
},
|
||||
|
||||
_resetResults() {
|
||||
this.results = [];
|
||||
this._currentResult = -1;
|
||||
this.$.prev.setAttribute('disabled', '');
|
||||
this.$.next.setAttribute('disabled', '');
|
||||
},
|
||||
|
||||
search() {
|
||||
this.$.search.dispatchEvent(new Event('input'));
|
||||
},
|
||||
|
||||
_onSearch(evt) {
|
||||
evt.target.parentElement.parentNode.host._resetResults();
|
||||
|
||||
const needle = evt.target.value.toLowerCase();
|
||||
evt.target.dispatchEvent(new CustomEvent('loot-search-begin', {
|
||||
detail: { needle },
|
||||
bubbles: true,
|
||||
}));
|
||||
},
|
||||
|
||||
_onPrev(evt) {
|
||||
--evt.target.parentElement.parentNode.host._currentResult;
|
||||
},
|
||||
|
||||
_onNext(evt) {
|
||||
++evt.target.parentElement.parentNode.host._currentResult;
|
||||
},
|
||||
|
||||
_onClose(evt) {
|
||||
const host = evt.target.parentElement.parentNode.host;
|
||||
host._resetResults();
|
||||
host.$.search.value = '';
|
||||
host.$.count.classList.toggle('hidden', true);
|
||||
evt.target.dispatchEvent(new CustomEvent('loot-search-end', {
|
||||
bubbles: true,
|
||||
}));
|
||||
},
|
||||
|
||||
_computeResultNum(currentResult) {
|
||||
return currentResult + 1;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
@@ -1,170 +0,0 @@
|
||||
<link rel="import" href="../../../../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../../../../bower_components/core-toolbar/core-toolbar.html">
|
||||
<link rel="import" href="../../../../bower_components/core-tooltip/core-tooltip.html">
|
||||
<link rel="import" href="../../../../bower_components/paper-icon-button/paper-icon-button.html">
|
||||
|
||||
<!--
|
||||
searchTarget is the ID of the core-list element to search the elements of.
|
||||
-->
|
||||
<polymer-element name="loot-search" attributes="searchTarget">
|
||||
<template>
|
||||
<style>
|
||||
core-toolbar {
|
||||
background: #3F51B5;
|
||||
color: white;
|
||||
height: 56px;
|
||||
}
|
||||
core-toolbar > * {
|
||||
top: -3px;
|
||||
}
|
||||
paper-input {
|
||||
position: relative;
|
||||
}
|
||||
paper-input /deep/ paper-input-decorator::shadow .label-text,
|
||||
paper-input /deep/ input::-webkit-input-placeholder {
|
||||
color: rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
.caption {
|
||||
font-weight: 400;
|
||||
font-size: 0.857rem;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
</style>
|
||||
<core-toolbar>
|
||||
<paper-input id="search" label="Search cards" flex></paper-input>
|
||||
<div id="count" class="caption" hidden>
|
||||
{{currentResult + 1}}/{{numResults}}
|
||||
</div>
|
||||
<paper-icon-button id="prev" icon="expand-less" disabled></paper-icon-button>
|
||||
<paper-icon-button id="next" icon="expand-more" disabled></paper-icon-button>
|
||||
<paper-icon-button id="close" icon="close"></paper-icon-button>
|
||||
</core-toolbar>
|
||||
</template>
|
||||
<script>
|
||||
Polymer({
|
||||
currentResult: -1,
|
||||
results: [],
|
||||
numResults: 0,
|
||||
searchTarget: undefined,
|
||||
|
||||
resultsChanged: function(oldValue, newValue) {
|
||||
this.numResults = newValue.length;
|
||||
},
|
||||
|
||||
currentResultChanged: function(oldValue, newValue) {
|
||||
if (this.results.length > 0) {
|
||||
if (this.results.length == 1) {
|
||||
this.shadowRoot.getElementById('prev').setAttribute('disabled', '');
|
||||
this.shadowRoot.getElementById('next').setAttribute('disabled', '');
|
||||
} else if (newValue == 0) {
|
||||
this.shadowRoot.getElementById('prev').setAttribute('disabled', '');
|
||||
this.shadowRoot.getElementById('next').removeAttribute('disabled');
|
||||
} else if (newValue == this.results.length - 1) {
|
||||
this.shadowRoot.getElementById('prev').removeAttribute('disabled');
|
||||
this.shadowRoot.getElementById('next').setAttribute('disabled', '');
|
||||
} else {
|
||||
this.shadowRoot.getElementById('prev').removeAttribute('disabled');
|
||||
this.shadowRoot.getElementById('next').removeAttribute('disabled');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
attached: function() {
|
||||
this.shadowRoot.getElementById('search').addEventListener('input', this.onSearch, false);
|
||||
this.shadowRoot.getElementById('search').addEventListener('keyup', this.onEnter, false);
|
||||
this.shadowRoot.getElementById('prev').addEventListener('click', this.onPrev, false);
|
||||
this.shadowRoot.getElementById('next').addEventListener('click', this.onNext, false);
|
||||
this.shadowRoot.getElementById('close').addEventListener('click', this.onClose, false);
|
||||
},
|
||||
|
||||
detached: function() {
|
||||
this.shadowRoot.getElementById('search').removeEventListener('input', this.onSearch, false);
|
||||
this.shadowRoot.getElementById('search').removeEventListener('keyup', this.onEnter, false);
|
||||
this.shadowRoot.getElementById('prev').removeEventListener('click', this.onPrev, false);
|
||||
this.shadowRoot.getElementById('next').removeEventListener('click', this.onNext, false);
|
||||
this.shadowRoot.getElementById('close').removeEventListener('change', this.onClose, false);
|
||||
},
|
||||
|
||||
resetResults: function() {
|
||||
loot.game.plugins.forEach(function(plugin){
|
||||
plugin.isSearchResult = false;
|
||||
});
|
||||
this.results = [];
|
||||
this.currentResult = -1;
|
||||
this.shadowRoot.getElementById('prev').setAttribute('disabled', '');
|
||||
this.shadowRoot.getElementById('next').setAttribute('disabled', '');
|
||||
},
|
||||
|
||||
onEnter: function(evt) {
|
||||
var host = evt.target.parentElement.parentNode.host;
|
||||
if (evt.keyCode != 13 || host.results.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (host.currentResult == host.results.length - 1) {
|
||||
host.currentResult = 0;
|
||||
} else {
|
||||
++host.currentResult;
|
||||
}
|
||||
document.getElementById(host.searchTarget).scrollToItem(host.results[host.currentResult]);
|
||||
},
|
||||
|
||||
focusInput: function() {
|
||||
this.shadowRoot.getElementById('search').focus();
|
||||
},
|
||||
|
||||
search: function() {
|
||||
this.shadowRoot.getElementById('search').dispatchEvent(new Event('input'));
|
||||
},
|
||||
|
||||
onSearch: function(evt) {
|
||||
var needle = evt.target.value.toLowerCase();
|
||||
var host = evt.target.parentElement.parentNode.host;
|
||||
|
||||
host.resetResults();
|
||||
host.shadowRoot.getElementById('count').hidden = !evt.target.value;
|
||||
|
||||
if (!evt.target.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
var versionHidden = document.getElementById('hideVersionNumbers').checked;
|
||||
var crcHidden = document.getElementById('hideCRCs').checked;
|
||||
var bashTagHidden = document.getElementById('hideBashTags').checked;
|
||||
document.getElementById(host.searchTarget).data.forEach(function(plugin, index){
|
||||
if (plugin.getCardContent(loot.filters).containsText(needle)) {
|
||||
host.results.push(index);
|
||||
plugin.isSearchResult = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (host.results.length > 0) {
|
||||
host.currentResult = 0;
|
||||
// For some reason change watcher doesn't run, call it manually.
|
||||
host.currentResultChanged(-1, 0);
|
||||
document.getElementById(host.searchTarget).scrollToItem(host.results[host.currentResult]);
|
||||
}
|
||||
},
|
||||
|
||||
onPrev: function(evt) {
|
||||
var host = evt.target.parentElement.parentNode.host;
|
||||
--host.currentResult;
|
||||
document.getElementById(host.searchTarget).scrollToItem(host.results[host.currentResult]);
|
||||
},
|
||||
|
||||
onNext: function(evt) {
|
||||
var host = evt.target.parentElement.parentNode.host;
|
||||
++host.currentResult;
|
||||
document.getElementById(host.searchTarget).scrollToItem(host.results[host.currentResult]);
|
||||
},
|
||||
|
||||
onClose: function(evt) {
|
||||
evt.target.parentElement.parentNode.host.resetResults();
|
||||
evt.target.parentElement.parentNode.getElementById('search').value = '';
|
||||
evt.target.parentElement.parentNode.getElementById('count').hidden = true;
|
||||
evt.target.dispatchEvent(new CustomEvent('loot-search-close'));
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</polymer-element>
|
||||
@@ -0,0 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>test_loot-search-toolbar.html</title>
|
||||
|
||||
<link rel="import" href="../../../../gui/html/native-shadow-dom.html">
|
||||
|
||||
<link rel="import" href="../../../../../bower_components/iron-icon/iron-icon.html">
|
||||
<link rel="import" href="../../../../../bower_components/iron-list/iron-list.html">
|
||||
|
||||
<link rel="import" href="../../../../gui/html/elements/loot-search-toolbar.html">
|
||||
|
||||
<script src="../../../../gui/html/js/plugin.js"></script>
|
||||
<script src="../../../../gui/html/js/translator.js"></script>
|
||||
<script src="../../../../gui/html/js/filters.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<loot-search-toolbar id="searchBar"></loot-search-toolbar>
|
||||
|
||||
<iron-list id="pluginList" style="height: 500px;">
|
||||
<template>
|
||||
<div style="height: 300px;">[[item.name]]</div>
|
||||
</template>
|
||||
</iron-list>
|
||||
|
||||
<script>
|
||||
'use strict';
|
||||
const filters = new loot.Filters(new loot.Translator());
|
||||
const plugins = [
|
||||
new loot.Plugin({
|
||||
name: 'Skyrim.esm',
|
||||
}),
|
||||
new loot.Plugin({
|
||||
name: 'Hearthfires.esm',
|
||||
}),
|
||||
new loot.Plugin({
|
||||
name: 'Dawnguard.esm',
|
||||
}),
|
||||
new loot.Plugin({
|
||||
name: 'Dragonborn.esm',
|
||||
}),
|
||||
];
|
||||
|
||||
function onSearchEnd() {
|
||||
plugins.forEach((plugin) => {
|
||||
plugin.isSearchResult = false;
|
||||
});
|
||||
}
|
||||
|
||||
function onSearchBegin(evt) {
|
||||
onSearchEnd();
|
||||
|
||||
if (!evt.detail.needle) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't push to the target's results property directly, as the
|
||||
// change observer doesn't work correctly unless special Polymer APIs
|
||||
// are used, which I don't want to get into.
|
||||
const results = [];
|
||||
plugins.forEach((plugin, index) => {
|
||||
if (plugin.getCardContent(filters).containsText(evt.detail.needle)) {
|
||||
results.push(index);
|
||||
plugin.isSearchResult = true;
|
||||
}
|
||||
});
|
||||
|
||||
evt.target.results = results;
|
||||
}
|
||||
|
||||
function onSearchChangeSelection(evt) {
|
||||
document.getElementById('pluginList').scrollToIndex(evt.detail.selection);
|
||||
}
|
||||
|
||||
document.addEventListener('loot-search-begin', onSearchBegin);
|
||||
document.addEventListener('loot-search-change-selection', onSearchChangeSelection);
|
||||
document.addEventListener('loot-search-end', onSearchEnd);
|
||||
document.getElementById('pluginList').items = plugins;
|
||||
</script>
|
||||
</body>
|
||||
Reference in New Issue
Block a user