Universal search input

This commit is contained in:
eraden 2022-07-30 13:22:07 +02:00
parent 3303d157fa
commit d703ddffdf
5 changed files with 118 additions and 58 deletions

View File

@ -6,6 +6,7 @@ import "./shared/rich-text-editor.js";
import "./shared/form-navigation.js";
import "./shared/image-popup.js";
import "./shared/facebook-button.js";
import "./shared/search-input.js";
import "./shared/nav/ow-nav.js";
import "./shared/nav/ow-path.js";
import "./shared/price/price-input.js";

View File

@ -1,16 +1,13 @@
import { Component } from "../shared";
import { Component } from "../shared.js";
import "../shared/search-input.js";
customElements.define('local-business-list', class extends Component {
static get observedAttributes() {
return ['filter']
}
constructor() {
super(`
<style>
:host { display: block; }
* { font-family: 'Cardo', sans-serif; }
::slotted(local-business[local-business-visible="invisible"]) {
::slotted([search-visible='invisible']) {
display: none;
}
input {
@ -38,62 +35,12 @@ customElements.define('local-business-list', class extends Component {
</style>
<article>
<section>
<input type="text" id="filter" placeholder="Znajdź (wyrażenia regularne są wspierane)" />
<search-input target="local-business"></search-input>
</section>
<section id="items">
<slot name="business"></slot>
</section>
</article>
`);
{
const filter = this.shadowRoot.querySelector('#filter');
let t = null;
filter.addEventListener('change', ev => {
ev.stopPropagation();
this.filter = ev.target.value;
});
filter.addEventListener('keyup', ev => {
ev.stopPropagation();
const value = ev.target.value;
if (t) clearTimeout(t);
t = setTimeout(() => {
this.filter = value;
t = null;
}, 1000 / 3);
});
}
}
connectedCallback() {
this.filter = this.getAttribute('filter');
}
attributeChangedCallback(name, oldV, newV) {
super.attributeChangedCallback(name, oldV, newV);
}
get filter() {
return this.getAttribute('filter');
}
set filter(value) {
if (!value || value === '') {
this.removeAttribute('filter');
for (const el of this.querySelectorAll('local-business')) {
el.removeAttribute('local-business-visible');
}
} else {
this.setAttribute('filter', value);
value = value.split(' ').filter(s => s && s.length).map(s => `(${s})`).join('|');
const businesses = this.querySelectorAll('local-business');
for (const el of businesses) {
if (el.matches(new RegExp(value, 'ig'))) {
el.setAttribute('local-business-visible', 'visible');
} else {
el.setAttribute('local-business-visible', 'invisible');
}
}
}
}
});

View File

@ -1,4 +1,5 @@
import { Component, BUTTON_STYLE } from "../shared";
import { Component, BUTTON_STYLE } from "../shared.js";
import "../shared/search-input.js";
customElements.define('marketplace-offers', class extends Component {
static get observedAttributes() {
@ -28,6 +29,9 @@ customElements.define('marketplace-offers', class extends Component {
::slotted(marketplace-offer), ::slotted(user-edit-offer) {
margin-bottom: 20px;
}
::slotted([search-visible='invisible']) {
display: none;
}
@media only screen and (min-device-width: 1000px) {
#offers {
display: flex;
@ -47,6 +51,9 @@ customElements.define('marketplace-offers', class extends Component {
<button id="publish" class="btn">Dodaj ogłoszenie</button>
</section>
<section><slot></slot></section>
<section>
<search-input target="user-edit-offer, marketplace-offer"></search-input>
</section>
<section id="offers">
<slot name="offer"></slot>
</section>

View File

@ -147,4 +147,8 @@ customElements.define('user-edit-offer', class extends Component {
}
}
}
matches(regex) {
return !!this.description.match(regex)
}
});

View File

@ -0,0 +1,101 @@
import { Component } from "../shared.js";
customElements.define('search-input', class extends Component {
#host;
static get observedAttributes() {
return ['filter', 'target']
}
constructor() {
super(`
<style>
:host { display: block; }
input {
font-size: 1rem;
line-height: 2.6em;
height: 2.6em;
margin: 0;
padding: 0;
width: 100%;
border:none;
outline:none;
display: block;
background: transparent;
border-bottom: 1px solid #ccc;
text-indent: 20px;
}
</style>
<section>
<input type="text" id="filter" placeholder="Znajdź (wyrażenia regularne są wspierane)" />
</section>
`);
const filter = this.shadowRoot.querySelector('#filter');
let t = null;
filter.addEventListener('change', ev => {
ev.stopPropagation();
this.filter = ev.target.value;
});
filter.addEventListener('keyup', ev => {
ev.stopPropagation();
const value = ev.target.value;
if (t) clearTimeout(t);
t = setTimeout(() => {
this.filter = value;
t = null;
}, 1000 / 3);
});
}
connectedCallback() {
super.connectedCallback();
let node = this;
while (node) {
console.warn(node)
if (node == null) return console.warn('no parent node', node);
if (node instanceof ShadowRoot) {
console.warn('node is shadow')
this.#host = node.host;
break;
}
node = node.parentNode;
}
}
get target() {
return this.getAttribute('target');
}
set target(tagName) {
this.setAttribute('target', tagName);
}
get filter() {
return this.getAttribute('filter');
}
set filter(value) {
console.warn(this.#host, value);
if (!this.#host) return;
const v = this.#host.querySelectorAll(this.target);
if (!value || value === '') {
this.removeAttribute('filter');
for (const el of v) {
el.removeAttribute('search-visible');
}
} else {
this.setAttribute('filter', value);
value = value.split(' ').filter(s => s && s.length).map(s => `(${ s })`).join('|');
for (const el of v) {
if (!el.matches) continue;
if (el.matches(new RegExp(value, 'ig'))) {
el.setAttribute('search-visible', 'visible');
} else {
el.setAttribute('search-visible', 'invisible');
}
}
}
}
});