-
Notifications
You must be signed in to change notification settings - Fork 805
/
Copy pathmain.js
132 lines (106 loc) · 3.87 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
'use strict';
(function() {
class EditableList extends HTMLElement {
constructor() {
// establish prototype chain
super();
// attaches shadow tree and returns shadow root reference
// https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow
const shadow = this.attachShadow({ mode: 'open' });
// creating a container for the editable-list component
const editableListContainer = document.createElement('div');
// get attribute values from getters
const title = this.title;
const addItemText = this.addItemText;
const listItems = this.items;
// adding a class to our container for the sake of clarity
editableListContainer.classList.add('editable-list');
// creating the inner HTML of the editable list element
editableListContainer.innerHTML = `
<style>
li, div > div {
display: flex;
align-items: center;
justify-content: space-between;
}
.icon {
background-color: #fff;
border: none;
cursor: pointer;
float: right;
font-size: 1.8rem;
}
</style>
<h3>${title}</h3>
<ul class="item-list">
${listItems.map(item => `
<li>${item}
<button class="editable-list-remove-item icon">⊖</button>
</li>
`).join('')}
</ul>
<div>
<label>${addItemText}</label>
<input class="add-new-list-item-input" type="text">
<button class="editable-list-add-item icon">⊕</button>
</div>
`;
// binding methods
this.addListItem = this.addListItem.bind(this);
this.handleRemoveItemListeners = this.handleRemoveItemListeners.bind(this);
this.removeListItem = this.removeListItem.bind(this);
// appending the container to the shadow DOM
shadow.appendChild(editableListContainer);
}
// add items to the list
addListItem(e) {
const textInput = this.shadowRoot.querySelector('.add-new-list-item-input');
if (textInput.value) {
const li = document.createElement('li');
const button = document.createElement('button');
const childrenLength = this.itemList.children.length;
li.textContent = textInput.value;
button.classList.add('editable-list-remove-item', 'icon');
button.innerHTML = '⊖';
this.itemList.appendChild(li);
this.itemList.children[childrenLength].appendChild(button);
this.handleRemoveItemListeners([button]);
textInput.value = '';
}
}
// fires after the element has been attached to the DOM
connectedCallback() {
const removeElementButtons = [...this.shadowRoot.querySelectorAll('.editable-list-remove-item')];
const addElementButton = this.shadowRoot.querySelector('.editable-list-add-item');
this.itemList = this.shadowRoot.querySelector('.item-list');
this.handleRemoveItemListeners(removeElementButtons);
addElementButton.addEventListener('click', this.addListItem, false);
}
// gathering data from element attributes
get title() {
return this.getAttribute('title') || '';
}
get items() {
const items = [];
[...this.attributes].forEach(attr => {
if (attr.name.includes('list-item')) {
items.push(attr.value);
}
});
return items;
}
get addItemText() {
return this.getAttribute('add-item-text') || '';
}
handleRemoveItemListeners(arrayOfElements) {
arrayOfElements.forEach(element => {
element.addEventListener('click', this.removeListItem, false);
});
}
removeListItem(e) {
e.target.parentNode.remove();
}
}
// let the browser know about the custom element
customElements.define('editable-list', EditableList);
})();