Refactor codebase. Functioning item list
This commit is contained in:
parent
a9eaa5dbde
commit
37401a85c8
20
index.html
20
index.html
|
|
@ -8,8 +8,24 @@
|
|||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="src/main.js" defer></script>
|
||||
<main id="root"></main>
|
||||
<script type="module" src="src/components/app-base.js" defer></script>
|
||||
<script type="module" src="src/components/main-window.js" defer></script>
|
||||
<script type="module" src="src/components/custom-button.js" defer></script>
|
||||
<script type="module" src="src/components/item-list.js" defer></script>
|
||||
<style>
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background: transparent linear-gradient(135deg, #A1C4FD 0%, #C2E9FB 100%) 0% 0% no-repeat padding-box;
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100%;
|
||||
}
|
||||
</style>
|
||||
<app-base></app-base>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ import Store from '../modules/store.js';
|
|||
import text from '../modules/text.js';
|
||||
|
||||
class AppBase extends HTMLElement {
|
||||
static observedAttributes = ['title', 'description'];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
|
|
@ -14,25 +12,18 @@ class AppBase extends HTMLElement {
|
|||
connectedCallback() {
|
||||
this.store.subscribe(this.render.bind(this));
|
||||
this.render();
|
||||
|
||||
console.log('Component constructed', this);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
console.log('Component disconnected', this);
|
||||
}
|
||||
|
||||
attributeChangedCallback() {
|
||||
this.render();
|
||||
}
|
||||
|
||||
renderText() {
|
||||
const textList = this.store.getRecords();
|
||||
const selected = this.store.getSelected();
|
||||
return textList.map((item) => `<option value=${item.id} ${selected.includes(item.id) && "selected"}>${item.text}</option>`).join('\n');
|
||||
return textList.map((item) => `<option value=${item.id}>${item.text}</option>`).join('\n');
|
||||
}
|
||||
|
||||
render() {
|
||||
render(action = 'INITIAL') {
|
||||
if (![Store.actions.ADD_LINE, Store.actions.REMOVE_LINE, Store.actions.UNDO, 'INITIAL'].includes(action)) {
|
||||
return; // Only render if content changed
|
||||
}
|
||||
|
||||
this.shadowRoot.innerHTML = `
|
||||
<main-window title="${this.text.title}" description="${this.text.description}">
|
||||
<select multiple is="item-list">
|
||||
|
|
|
|||
|
|
@ -16,14 +16,10 @@ class CustomButton extends HTMLElement {
|
|||
connectedCallback() {
|
||||
this.render();
|
||||
this.shadowRoot.getElementById('button').addEventListener('click', this.onClick.bind(this));
|
||||
|
||||
console.log('Component constructed', this);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.shadowRoot.getElementById('button').removeEventListener('click', this.onClick);
|
||||
|
||||
console.log('Component disconnected', this);
|
||||
}
|
||||
|
||||
attributeChangedCallback() {
|
||||
|
|
@ -52,7 +48,9 @@ class CustomButton extends HTMLElement {
|
|||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
||||
<button id="button"><slot></slot></button>
|
||||
<button id="button">
|
||||
<slot></slot>
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,23 +9,15 @@ class ItemList extends HTMLSelectElement {
|
|||
connectedCallback() {
|
||||
this.addEventListener('click', this.onChange.bind(this));
|
||||
this.updateStyle();
|
||||
|
||||
console.log('Component constructed', this);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
const selectedIds = Array.from(this.selectedOptions).map((option) => option.value);
|
||||
const selectedIds = Array.from(this.selectedOptions).map((option) => +option.value);
|
||||
this.publish(Store.actions.SELECT, selectedIds);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.removeEventListener('change', this.onChange.bind(this));
|
||||
|
||||
console.log('Component disconnected', this);
|
||||
}
|
||||
|
||||
attributeChangedCallback() {
|
||||
this.updateStyle();
|
||||
this.removeEventListener('click', this.onChange.bind(this));
|
||||
}
|
||||
|
||||
updateStyle() {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,6 @@ class MainWindow extends HTMLElement {
|
|||
|
||||
connectedCallback() {
|
||||
this.render();
|
||||
console.log('Component constructed', this);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
console.log('Component disconnected', this);
|
||||
}
|
||||
|
||||
attributeChangedCallback() {
|
||||
|
|
@ -25,7 +20,7 @@ class MainWindow extends HTMLElement {
|
|||
|
||||
this.shadowRoot.innerHTML = `
|
||||
<style>
|
||||
div {
|
||||
#window {
|
||||
width: 900px;
|
||||
height: 577px;
|
||||
background: #FFFFFF 0% 0% no-repeat padding-box;
|
||||
|
|
@ -33,12 +28,10 @@ class MainWindow extends HTMLElement {
|
|||
border-radius: 20px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
span {
|
||||
#content {
|
||||
width: 800px;
|
||||
margin: 0 50px 13px 50px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
top: 221px;
|
||||
margin: 50px 50px 13px 50px;
|
||||
|
|
@ -66,14 +59,13 @@ class MainWindow extends HTMLElement {
|
|||
color: #333333;
|
||||
opacity: 1;
|
||||
}
|
||||
slot {
|
||||
margin: 0 50px 0 50px;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
<div id="window">
|
||||
<h1>${title}</h1>
|
||||
<p>${description}</p>
|
||||
<span><slot></slot></span>
|
||||
<div id="content" >
|
||||
<slot></slot>
|
||||
<div/>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
|
|
|||
29
src/main.js
29
src/main.js
|
|
@ -3,32 +3,3 @@ import './components/main-window.js';
|
|||
import './components/custom-button.js';
|
||||
import './components/item-list.js';
|
||||
|
||||
class App {
|
||||
constructor(root, text, store) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
start() {
|
||||
this.root.innerHTML = `
|
||||
<style>
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background: transparent linear-gradient(135deg, #A1C4FD 0%, #C2E9FB 100%) 0% 0% no-repeat padding-box;
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100%;
|
||||
}
|
||||
</style>
|
||||
<app-base></app-base>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
const app = new App(document.getElementById('root'));
|
||||
|
||||
app.start();
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export default class Store {
|
|||
records: [],
|
||||
selected: [],
|
||||
};
|
||||
this.callbacks = [];
|
||||
this.callbacks = [() => console.log(this.state)];
|
||||
|
||||
Object.values(this.constructor.actions).forEach(action => document.addEventListener(action, this.eventHandler.bind(this), false));
|
||||
}
|
||||
|
|
@ -48,12 +48,15 @@ export default class Store {
|
|||
};
|
||||
break;
|
||||
case this.constructor.actions.REMOVE_LINE:
|
||||
const linesToRemove = this.state.selected.map((id, index) => ({
|
||||
id: this.state.records.length + index,
|
||||
targetId: id,
|
||||
action: 'remove',
|
||||
}));
|
||||
this.state = {
|
||||
...this.state,
|
||||
records: this.records.concat({
|
||||
id: this.state.records.length,
|
||||
action: 'remove',
|
||||
}),
|
||||
records: [ ...this.state.records, ...linesToRemove],
|
||||
selected: [],
|
||||
};
|
||||
break;
|
||||
case this.constructor.actions.UNDO:
|
||||
|
|
@ -73,11 +76,11 @@ export default class Store {
|
|||
return;
|
||||
}
|
||||
|
||||
this.callbacks.forEach((cb) => cb());
|
||||
this.callbacks.forEach((cb) => cb(event.type));
|
||||
}
|
||||
|
||||
getRecords() {
|
||||
return this.state.records.reduce((acc, current) => {
|
||||
const result = this.state.records.reduce((acc, current) => {
|
||||
if (current.action === "add") {
|
||||
return acc.concat({id: current.id, text: current.text});
|
||||
}
|
||||
|
|
@ -86,6 +89,7 @@ export default class Store {
|
|||
}
|
||||
console.error(`Action ${current.action} not valid`);
|
||||
}, []);
|
||||
return result;
|
||||
}
|
||||
|
||||
getSelected() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue