Skip to content

Commit feaa4e2

Browse files
committed
Updates
1 parent 4df9c95 commit feaa4e2

35 files changed

+303
-217
lines changed

example/index.html

+17-13
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,22 @@
1111

1212
<body>
1313
<js-container>
14-
<js-tag transform="uppercase">Provider</js-tag>
15-
<js-provider id="provider"></js-provider>
16-
</js-container>
17-
<js-button textTransform="uppercase">Reload</js-button>
18-
<js-container>
19-
<js-tag transform="uppercase">Table</js-tag>
20-
<js-table-body id="table"></js-table-body>
14+
<js-tag transform="uppercase">Data</js-tag>
15+
<!-- where the data comes from -->
16+
<js-provider id="provider" path="data.json"></js-provider>
17+
18+
<!-- model -->
19+
<js-array id="array" provider="#provider"></js-array>
20+
21+
<!-- view -->
22+
<js-tablebody id="body" data="#array">
23+
<js-tablehead body="#body"></js-tablehead>
24+
</js-tablebody>
2125
</js-container>
2226

2327
<js-container>
24-
<js-tag transform="uppercase"><js-icon size="small">compass</js-icon></js-tag>
25-
<div style="border: 1px solid red; height: 500px;">
28+
<js-tag texttransform="uppercase"><js-icon size="small">compass</js-icon> Map</js-tag>
29+
<div style="height: 500px;">
2630
<js-map id="map"
2731
accessToken="pk.eyJ1IjoiZGp0aG9ycGUiLCJhIjoiY2x5ZnJhZjAzMDJsYTJqcjd6eWQ3cjRvcSJ9.LvoT_wihG5VQtv008P-MPw">
2832
<js-mapsource type="geojson" data="{}"></js-mapsource>
@@ -62,10 +66,10 @@
6266
<js-tag color="black" texttransform="uppercase"><js-icon></js-icon></js-tag>
6367

6468
ICON SIZE
65-
<js-tag color="light" size="small"><js-icon size="small"></js-icon> small</js-tag>
66-
<js-tag color="light" size="medium"><js-icon size="medium"></js-icon> medium</js-tag>
67-
<js-tag color="light" size="large"><js-icon size="large"></js-icon> large</js-tag>
68-
<js-tag color="light" size="xlarge"><js-icon size="xlarge"></js-icon> xlarge</js-tag>
69+
<js-tag color="light" size="small"><js-icon>bootstrap</js-icon> small</js-tag>
70+
<js-tag color="light" size="medium"><js-icon></js-icon> medium</js-tag>
71+
<js-tag color="light" size="large"><js-icon></js-icon> large</js-tag>
72+
<js-tag color="light" size="xlarge"><js-icon></js-icon> xlarge</js-tag>
6973
</js-container>
7074

7175
</body>

example/load.js

-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,4 @@ import { FeatureModel } from '../src/geojson/FeatureModel';
22

33
window.addEventListener('load', () => {
44
const provider = document.querySelector('#provider');
5-
const table = document.querySelector('#table');
6-
table.model = new FeatureModel(provider);
7-
provider.path = 'data.json';
85
});

src/core/ArrayElement.js

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { LitElement, html } from 'lit';
2+
import { EventType } from './EventType';
3+
4+
/**
5+
* @class ArrayElement
6+
*
7+
* This class is a store of arrays of objects of one type.
8+
*
9+
* @property {String} provider - The provider for data
10+
*
11+
* @example
12+
* <js-array provider="provider"></js-array>
13+
*/
14+
export class ArrayElement extends LitElement {
15+
#data = new Array();
16+
#newdata = null;
17+
#provider = null;
18+
19+
static get localName() {
20+
return 'js-array';
21+
}
22+
23+
static get properties() {
24+
return {
25+
provider: { type: String, reflect: true },
26+
};
27+
}
28+
29+
firstUpdated() {
30+
// Set up a listener for data changes
31+
this.addEventListener(EventType.CHANGE, () => {
32+
this.requestUpdate();
33+
});
34+
}
35+
36+
render() {
37+
return html`<div>Array contains ${this.length} elements, provider=${this.provider}</div>`;
38+
}
39+
40+
attributeChangedCallback(name, oldVal, newVal) {
41+
super.attributeChangedCallback(name, oldVal, newVal);
42+
if (name === 'provider') {
43+
this.#providerChanged(newVal, oldVal);
44+
}
45+
}
46+
47+
get length() {
48+
return this.#data.length;
49+
}
50+
51+
at(index) {
52+
return this.#data[index];
53+
}
54+
55+
#providerChanged(newVal, oldVal) {
56+
if (oldVal != null && this.#provider && newVal !== oldVal) {
57+
this.#provider.removeEventListener(EventType.OBJECT, this.#providerFetch.bind(this));
58+
this.#provider.removeEventListener(EventType.OBJECT, this.#providerObject.bind(this));
59+
this.#provider.removeEventListener(EventType.OBJECT, this.#providerDone.bind(this));
60+
this.#provider = null;
61+
}
62+
if (newVal != null && newVal !== oldVal) {
63+
this.#provider = document.querySelector(newVal);
64+
if (this.#provider) {
65+
this.#provider.addEventListener(EventType.OBJECT, this.#providerFetch.bind(this));
66+
this.#provider.addEventListener(EventType.OBJECT, this.#providerObject.bind(this));
67+
this.#provider.addEventListener(EventType.OBJECT, this.#providerDone.bind(this));
68+
} else {
69+
throw new Error(`Provider "${newVal}" not found`);
70+
}
71+
}
72+
}
73+
74+
#providerFetch(event) {
75+
// Reset the data container
76+
this.#newdata = new Array();
77+
}
78+
79+
#providerObject(event) {
80+
// Add the object to the data container
81+
this.#newdata.push(event.detail);
82+
}
83+
84+
#providerDone(event) {
85+
let modified = false;
86+
if (this.#newdata.length !== this.#data.length) {
87+
modified = true;
88+
} else {
89+
for (let i = 0; i < this.#newdata.length; i++) {
90+
if (this.#newdata[i] !== this.#data[i]) {
91+
modified = true;
92+
break;
93+
}
94+
}
95+
}
96+
97+
// Copy over the data
98+
this.#data = this.#newdata;
99+
100+
// Emit a change event if the data was modified
101+
if (modified) {
102+
this.dispatchEvent(new CustomEvent(EventType.CHANGE, {
103+
detail: this
104+
}));
105+
}
106+
107+
}
108+
}

src/core/core.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { ProviderElement } from './ProviderElement';
2+
import { ArrayElement } from './ArrayElement';
23

34
// Define Web Components
45
customElements.define(ProviderElement.localName, ProviderElement); // js-provider
6+
customElements.define(ArrayElement.localName, ArrayElement); // js-array

src/element/TableBodyElement.js

+104-34
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,136 @@
1-
import { LitElement, html } from 'lit';
1+
import { LitElement, html, css } from 'lit';
22
import { Model } from '../core/Model';
33
import { EventType } from '../core/EventType';
4+
import { TableHeadElement } from './TableHeadElement';
45

56
/**
67
* @class TableBodyElement
78
*
89
* This class provides a table body element.
910
*
1011
* @example
11-
* <js-table-body></js-table-body>
12+
* <js-tablebody data="#data-source-id"></js-tablebody>
1213
*/
1314
export class TableBodyElement extends LitElement {
15+
#data = null;
16+
#head = null;
17+
1418
static get localName() {
15-
return 'js-table-body';
19+
return 'js-tablebody';
1620
}
1721

1822
static get properties() {
1923
return {
20-
model: {
21-
type: Model, reflect: true, converter: {
22-
fromAttribute: (value, type) => {
23-
console.log(`TableBodyElement.model.fromAttribute(${value}, ${type})`);
24-
return value;
25-
},
26-
toAttribute: (value, type) => {
27-
console.log(value);
28-
return value.data;
29-
}
30-
}
31-
}
24+
data: { type: String, reflect: true },
25+
columns: { type: Array, reflect: true },
3226
};
3327
}
3428

35-
render() {
36-
console.log(`TableBodyElement.render() ${this.model ? this.model.data : '(not a model)'}`);
37-
return html`
38-
<tbody>
39-
<tr>
40-
<td>A</td>
41-
<td>B</td>
42-
</tr>
43-
</tbody>
29+
static get styles() {
30+
return css`
31+
:host {
32+
display: block;
33+
}
34+
table {
35+
border-spacing: 0;
36+
}
37+
td, th {
38+
vertical-align: top;
39+
border-left: 1px solid #aaa;
40+
border-top: 1px solid #aaa;
41+
}
42+
td:last-child, th:last-child {
43+
border-right: 1px solid #aaa;
44+
}
45+
tr:last-child td {
46+
border-bottom: 1px solid #aaa;
47+
}
48+
th {
49+
text-transform: capitalize;
50+
}
51+
.wrap {
52+
max-height: 40px;
53+
overflow: hidden;
54+
}
4455
`;
4556
}
4657

47-
updated(changedProperties) {
48-
if (changedProperties.has('model')) {
49-
this.#modelChangedSetListeners(this.model, changedProperties.get('model'));
58+
attributeChangedCallback(name, oldVal, newVal) {
59+
super.attributeChangedCallback(name, oldVal, newVal);
60+
if (name === 'data') {
61+
this.#dataChanged(newVal, oldVal);
5062
}
5163
}
5264

53-
#modelChangedSetListeners(newVal, oldVal) {
54-
if (oldVal) {
55-
oldVal.removeEventListener(EventType.CHANGE, this.#modelChanged.bind(this));
65+
#dataChanged(newVal, oldVal) {
66+
if (oldVal != null && this.#data && newVal !== oldVal) {
67+
this.#data.removeEventListener(EventType.CHANGE, this.#dataUpdate.bind(this));
68+
this.#data = null;
69+
this.columns = null;
5670
}
57-
if (newVal) {
58-
newVal.addEventListener(EventType.CHANGE, this.#modelChanged.bind(this));
71+
if (newVal != null && newVal !== oldVal) {
72+
this.#data = document.querySelector(newVal);
73+
this.columns = new Array();
74+
if (this.#data) {
75+
this.#data.addEventListener(EventType.CHANGE, this.#dataUpdate.bind(this));
76+
} else {
77+
throw new Error(`Data Source "${newVal}" not found`);
78+
}
5979
}
6080
}
6181

62-
#modelChanged() {
63-
console.log(`TableBodyElement.#modelChanged`);
82+
#dataUpdate() {
6483
this.requestUpdate();
84+
this.dispatchEvent(new CustomEvent(EventType.CHANGE, {
85+
detail: this
86+
}));
87+
}
88+
89+
firstUpdated() {
90+
// Set the table header
91+
this.#head = this.querySelector(TableHeadElement.localName);
92+
}
93+
94+
render() {
95+
const rows = this.#renderRows();
96+
const head = this.#head ? this.#head.render() : html``;
97+
return [html`<table>${head}<tbody>${rows}</tbody></table>`];
98+
}
99+
100+
#renderRows() {
101+
if (!this.#data) {
102+
return html``;
103+
}
104+
let rows = [];
105+
for (let i = 0; i < this.#data.length; i++) {
106+
rows.push(html`<tr>${this.#renderColumns(this.#data.at(i))}</tr>`);
107+
}
108+
return rows;
109+
}
110+
111+
#renderColumns(row) {
112+
if (!row) {
113+
return html``;
114+
}
115+
if (row instanceof Object) {
116+
let columns = [];
117+
for (let key in row) {
118+
if (this.columns.indexOf(key) === -1) {
119+
this.columns.push(key);
120+
}
121+
columns.push(html`<td><div class="wrap">${this.#renderCell(row[key])}</div></td>`);
122+
}
123+
return columns;
124+
}
125+
126+
// TODO: Other types
127+
return html``;
128+
}
129+
130+
#renderCell(cell) {
131+
if (cell instanceof Object) {
132+
return html`<code>${JSON.stringify(cell)}</code>`;
133+
}
134+
return html`${cell}`;
65135
}
66136
}

0 commit comments

Comments
 (0)