mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
style: format Location component boundary
This commit is contained in:
1 parent
ea77b49482
commit
82d922ae87
7 files changed
+557
-275
No files matched your search
@@ -5,40 +5,145 @@ import { LocationControls } from './locationControls.js';
|
||||
function node() {
|
||||
const classes = new Set();
|
||||
return {
|
||||
children: [], dataset: {}, listeners: new Map(), className: '', textContent: '',
|
||||
classList: { add: (...names) => names.forEach(name => classes.add(name)), remove: (...names) => names.forEach(name => classes.delete(name)), contains: name => classes.has(name), toggle(name, enabled = !classes.has(name)) { if(enabled) classes.add(name); else classes.delete(name); } },
|
||||
addEventListener(name, callback) { if(!this.listeners.has(name)) this.listeners.set(name,new Set()); this.listeners.get(name).add(callback); },
|
||||
removeEventListener(name, callback) { this.listeners.get(name)?.delete(callback); },
|
||||
fire(name,event={}) { for(const callback of this.listeners.get(name)||[]) callback(event); },
|
||||
appendChild(child) { this.children.push(child); child.parent=this; },
|
||||
append(...children) { for(const child of children) if(typeof child!=='string') this.appendChild(child); },
|
||||
replaceChildren() { this.children=[]; },
|
||||
remove() { if(this.parent) this.parent.children=this.parent.children.filter(child=>child!==this); },
|
||||
querySelectorAll(selector) { return this.children.flatMap(child=>[...(child.className===selector.slice(1)?[child]:[]),...child.querySelectorAll(selector)]); },
|
||||
focus() { this.focused=true; },
|
||||
children: [],
|
||||
dataset: {},
|
||||
listeners: new Map(),
|
||||
className: '',
|
||||
textContent: '',
|
||||
classList: {
|
||||
add: (...names) => names.forEach((name) => classes.add(name)),
|
||||
remove: (...names) => names.forEach((name) => classes.delete(name)),
|
||||
contains: (name) => classes.has(name),
|
||||
toggle(name, enabled = !classes.has(name)) {
|
||||
if (enabled) classes.add(name);
|
||||
else classes.delete(name);
|
||||
},
|
||||
},
|
||||
addEventListener(name, callback) {
|
||||
if (!this.listeners.has(name)) this.listeners.set(name, new Set());
|
||||
this.listeners.get(name).add(callback);
|
||||
},
|
||||
removeEventListener(name, callback) {
|
||||
this.listeners.get(name)?.delete(callback);
|
||||
},
|
||||
fire(name, event = {}) {
|
||||
for (const callback of this.listeners.get(name) || []) callback(event);
|
||||
},
|
||||
appendChild(child) {
|
||||
this.children.push(child);
|
||||
child.parent = this;
|
||||
},
|
||||
append(...children) {
|
||||
for (const child of children)
|
||||
if (typeof child !== 'string') this.appendChild(child);
|
||||
},
|
||||
replaceChildren() {
|
||||
this.children = [];
|
||||
},
|
||||
remove() {
|
||||
if (this.parent)
|
||||
this.parent.children = this.parent.children.filter(
|
||||
(child) => child !== this,
|
||||
);
|
||||
},
|
||||
querySelectorAll(selector) {
|
||||
return this.children.flatMap((child) => [
|
||||
...(child.className === selector.slice(1) ? [child] : []),
|
||||
...child.querySelectorAll(selector),
|
||||
]);
|
||||
},
|
||||
focus() {
|
||||
this.focused = true;
|
||||
},
|
||||
};
|
||||
}
|
||||
function fixture() {
|
||||
const elements={pills:node(),poiRow:node(),divider:node(),search:node(),searchToggle:node(),resetButtons:[node(),node()],statusCity:node(),statusPoi:node()};
|
||||
const doc=node();doc.createElement=node;doc.body=node();
|
||||
const cities={a:{name:'City A',pois:[{name:'First'},{name:'Second'}]},b:{name:'City B',pois:[{name:'Elsewhere'}]}};
|
||||
const calls=[];const frames=new Map();const cancelled=[];let next=0;
|
||||
const controls=new LocationControls({elements,cities,getExpandedCity:()=> 'a',onCity:id=>calls.push(['city',id]),onPoi:(id,index)=>calls.push(['poi',id,index]),onSearch:query=>calls.push(['search',query]),onReset:()=>calls.push(['reset']),doc,requestFrame:fn=>{const id=next++;frames.set(id,fn);return id},cancelFrame:id=>cancelled.push(id)});
|
||||
return {elements,doc,controls,calls,frames,cancelled};
|
||||
const elements = {
|
||||
pills: node(),
|
||||
poiRow: node(),
|
||||
divider: node(),
|
||||
search: node(),
|
||||
searchToggle: node(),
|
||||
resetButtons: [node(), node()],
|
||||
statusCity: node(),
|
||||
statusPoi: node(),
|
||||
};
|
||||
const doc = node();
|
||||
doc.createElement = node;
|
||||
doc.body = node();
|
||||
const cities = {
|
||||
a: { name: 'City A', pois: [{ name: 'First' }, { name: 'Second' }] },
|
||||
b: { name: 'City B', pois: [{ name: 'Elsewhere' }] },
|
||||
};
|
||||
const calls = [];
|
||||
const frames = new Map();
|
||||
const cancelled = [];
|
||||
let next = 0;
|
||||
const controls = new LocationControls({
|
||||
elements,
|
||||
cities,
|
||||
getExpandedCity: () => 'a',
|
||||
onCity: (id) => calls.push(['city', id]),
|
||||
onPoi: (id, index) => calls.push(['poi', id, index]),
|
||||
onSearch: (query) => calls.push(['search', query]),
|
||||
onReset: () => calls.push(['reset']),
|
||||
doc,
|
||||
requestFrame: (fn) => {
|
||||
const id = next++;
|
||||
frames.set(id, fn);
|
||||
return id;
|
||||
},
|
||||
cancelFrame: (id) => cancelled.push(id),
|
||||
});
|
||||
return { elements, doc, controls, calls, frames, cancelled };
|
||||
}
|
||||
test('hiding a POI row cancels frame zero and rejects an already queued expansion', () => {
|
||||
const f=fixture();f.controls.showPois('a');const callback=f.frames.get(0);f.controls.hidePois();callback();
|
||||
assert.deepEqual(f.cancelled,[0]);assert.equal(f.elements.poiRow.classList.contains('expanded'),false);assert.equal(f.elements.divider.classList.contains('visible'),false);
|
||||
const f = fixture();
|
||||
f.controls.showPois('a');
|
||||
const callback = f.frames.get(0);
|
||||
f.controls.hidePois();
|
||||
callback();
|
||||
assert.deepEqual(f.cancelled, [0]);
|
||||
assert.equal(f.elements.poiRow.classList.contains('expanded'), false);
|
||||
assert.equal(f.elements.divider.classList.contains('visible'), false);
|
||||
});
|
||||
test('replacing POIs removes old click actions and presents the final row', () => {
|
||||
const f=fixture();f.controls.showPois('a');const old=f.elements.poiRow.children[0];f.controls.showPois('b');old.fire('click');
|
||||
assert.deepEqual(f.calls,[]);f.elements.poiRow.children[0].fire('click');assert.deepEqual(f.calls,[['poi','b',0]]);
|
||||
f.frames.get(0)();assert.equal(f.elements.poiRow.classList.contains('expanded'),false);f.frames.get(1)();assert.equal(f.elements.poiRow.classList.contains('expanded'),true);
|
||||
const f = fixture();
|
||||
f.controls.showPois('a');
|
||||
const old = f.elements.poiRow.children[0];
|
||||
f.controls.showPois('b');
|
||||
old.fire('click');
|
||||
assert.deepEqual(f.calls, []);
|
||||
f.elements.poiRow.children[0].fire('click');
|
||||
assert.deepEqual(f.calls, [['poi', 'b', 0]]);
|
||||
f.frames.get(0)();
|
||||
assert.equal(f.elements.poiRow.classList.contains('expanded'), false);
|
||||
f.frames.get(1)();
|
||||
assert.equal(f.elements.poiRow.classList.contains('expanded'), true);
|
||||
});
|
||||
test('destruction revokes document, search, reset, city and POI actions and removes orbit UI', () => {
|
||||
const f=fixture();f.controls.showPois('a');f.controls.createOrbitIndicator();assert.equal(f.doc.body.children.length,1);const city=f.elements.pills.children[0];const poi=f.elements.poiRow.children[0];f.controls.destroy();f.controls.destroy();
|
||||
city.fire('click');poi.fire('click');f.elements.search.value='Place';f.elements.search.fire('keydown',{key:'Enter'});f.doc.fire('keydown',{key:'Q'});f.elements.resetButtons[0].fire('click');f.frames.get(0)();assert.deepEqual(f.calls,[]);assert.equal(f.doc.body.children.length,0);
|
||||
const f = fixture();
|
||||
f.controls.showPois('a');
|
||||
f.controls.createOrbitIndicator();
|
||||
assert.equal(f.doc.body.children.length, 1);
|
||||
const city = f.elements.pills.children[0];
|
||||
const poi = f.elements.poiRow.children[0];
|
||||
f.controls.destroy();
|
||||
f.controls.destroy();
|
||||
city.fire('click');
|
||||
poi.fire('click');
|
||||
f.elements.search.value = 'Place';
|
||||
f.elements.search.fire('keydown', { key: 'Enter' });
|
||||
f.doc.fire('keydown', { key: 'Q' });
|
||||
f.elements.resetButtons[0].fire('click');
|
||||
f.frames.get(0)();
|
||||
assert.deepEqual(f.calls, []);
|
||||
assert.equal(f.doc.body.children.length, 0);
|
||||
});
|
||||
test('location and POI keys route once while form controls retain typing', () => {
|
||||
const f=fixture();f.doc.fire('keydown',{key:'W',target:{matches:()=>false}});f.doc.fire('keydown',{key:'Q',target:{matches:()=>true}});f.elements.resetButtons[1].fire('click');assert.deepEqual(f.calls,[['poi','a',1],['reset']]);
|
||||
const f = fixture();
|
||||
f.doc.fire('keydown', { key: 'W', target: { matches: () => false } });
|
||||
f.doc.fire('keydown', { key: 'Q', target: { matches: () => true } });
|
||||
f.elements.resetButtons[1].fire('click');
|
||||
assert.deepEqual(f.calls, [['poi', 'a', 1], ['reset']]);
|
||||
});
|
||||
Reference in new issue
Block a user