Skip to content

Commit 66787aa

Browse files
committed
Finalize new activity for lesson 1
1 parent 33e764a commit 66787aa

File tree

5 files changed

+177
-1
lines changed

5 files changed

+177
-1
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<html>
2+
<head>
3+
<link rel="stylesheet" type="text/css" href="../css/semantic.min.css" />
4+
<link rel="stylesheet" type="text/css" href="../css/store_with_header.css" />
5+
</head>
6+
<body>
7+
<div id="content">
8+
<section class="header">
9+
<h1 class="title">Welcome to Fresh Products Store!</h1>
10+
11+
<div class="ui menu">
12+
<tags-holder class="item"></tags-holder>
13+
<div class="right item">
14+
<search-box></search-box>>
15+
</div>
16+
</div>
17+
</section>
18+
19+
<div class="ui items"></div>
20+
</div>
21+
22+
<script src="search_box.js"></script>
23+
<script src="tags_holder.js"></script>
24+
<script src="../data/products.js"></script>
25+
<script src="../sample_003/create_elements.js"></script>
26+
<script src="filter_and_search.js"></script>
27+
</body>
28+
</html>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const filterByTagElement = document.querySelector('tags-holder');
2+
filterByTagElement.addEventListener('tag-clicked', (e) => filterByTagElement.removeTag(e.detail.tag));
3+
filterByTagElement.addEventListener('changed', () => applyFilters());
4+
5+
const searchBoxElement = document.querySelector('search-box');
6+
searchBoxElement.addEventListener('changed', (e) => applyFilters());
7+
8+
function addTagFilter() {
9+
Array.from(document.querySelectorAll('.extra .label'))
10+
.forEach(tagEl => tagEl.addEventListener('click', () => {
11+
filterByTagElement.addTag(tagEl.innerHTML);
12+
applyFilters();
13+
}));
14+
}
15+
16+
function applyFilters() {
17+
createListForProducts(filterByText(filterByTags(products)));
18+
addTagFilter();
19+
}
20+
21+
function filterByTags(products) {
22+
let filtered = products;
23+
filterByTagElement.selectedTags
24+
.forEach((t) => filtered = filtered.filter(p => p.tags.includes(t)));
25+
return filtered;
26+
}
27+
28+
function filterByText(products) {
29+
const txt = searchBoxElement.searchText.toLowerCase();
30+
return products.filter((p) => {
31+
return p.name.toLowerCase().includes(txt)
32+
|| p.description.toLowerCase().includes(txt);
33+
});
34+
}
35+
36+
applyFilters();
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
class SearchBox extends HTMLElement {
2+
constructor() {
3+
super();
4+
this.attachShadow({ mode: 'open' });
5+
this._searchText = '';
6+
7+
this.render();
8+
this.shadowRoot.querySelector('input').addEventListener('keyup', (e) => {
9+
this._searchText = e.target.value;
10+
this.triggerTextChanged(this._searchText);
11+
});
12+
}
13+
14+
get searchText() {
15+
return this._searchText;
16+
}
17+
18+
render() {
19+
this.shadowRoot.innerHTML = `
20+
<link rel="stylesheet" type="text/css" href="../css/semantic.min.css" />
21+
<div class="ui icon input">
22+
<input type="text" placeholder="Search..." />
23+
<i class="search icon"></i>
24+
</div>
25+
`;
26+
}
27+
28+
triggerTextChanged(text) {
29+
const event = new CustomEvent('changed', {
30+
bubbles: true,
31+
detail: { text },
32+
});
33+
this.dispatchEvent(event);
34+
}
35+
}
36+
37+
customElements.define('search-box', SearchBox);
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
class TagsHolder extends HTMLElement {
2+
constructor() {
3+
super();
4+
this.attachShadow({ mode: 'open' });
5+
this._selectedTags = [];
6+
this.render();
7+
this.renderTagList();
8+
}
9+
10+
addTag(tag) {
11+
if (!this._selectedTags.includes(tag)) {
12+
this._selectedTags.push(tag);
13+
this._selectedTags.sort();
14+
this.renderTagList();
15+
this.triggerChanged();
16+
}
17+
}
18+
19+
get selectedTags() {
20+
return this._selectedTags.slice(0);
21+
}
22+
23+
removeTag(tag) {
24+
const index = this._selectedTags.indexOf(tag);
25+
if (index >= 0) {
26+
this._selectedTags.splice(index, 1);
27+
this.renderTagList();
28+
this.triggerChanged();
29+
}
30+
}
31+
32+
render() {
33+
this.shadowRoot.innerHTML = `
34+
<link rel="stylesheet" type="text/css" href="../css/semantic.min.css" />
35+
<div>
36+
Filtered by tags:
37+
<span class="tags"></span>
38+
</div>`;
39+
}
40+
41+
renderTagList() {
42+
const tagsHolderElement = this.shadowRoot.querySelector('.tags');
43+
tagsHolderElement.innerHTML = '';
44+
45+
const tags = this._selectedTags;
46+
47+
if (tags.length == 0) {
48+
tagsHolderElement.innerHTML = 'No filters';
49+
return;
50+
}
51+
52+
tags.forEach(tag => {
53+
const tagEl = document.createElement('span');
54+
tagEl.className = "ui label orange";
55+
tagEl.addEventListener('click', () => this.triggerTagClicked(tag));
56+
tagEl.innerHTML = tag;
57+
tagsHolderElement.appendChild(tagEl);
58+
});
59+
}
60+
61+
triggerChanged(tag) {
62+
const event = new CustomEvent('changed', { bubbles: true });
63+
this.dispatchEvent(event);
64+
}
65+
66+
triggerTagClicked(tag) {
67+
const event = new CustomEvent('tag-clicked', {
68+
bubbles: true,
69+
detail: { tag },
70+
});
71+
this.dispatchEvent(event);
72+
}
73+
}
74+
75+
customElements.define('tags-holder', TagsHolder);

Lesson01/exercise_007/dynamic_storefront.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ <h1 class="title">Welcome to Fresh Products Store!</h1>
1313
Filtered by tags: <span class="tags"></span>
1414
</div>
1515
<div class="right item">
16-
<search-box value="" />
16+
<search-box></search-box>>
1717
</div>
1818
</div>
1919
</section>

0 commit comments

Comments
 (0)