mirror of
https://github.com/janishutz/fundamentals-of-webengineering.git
synced 2025-11-25 05:44:24 +00:00
Rendering engine, simple refs almost complete, list refs start
This commit is contained in:
@@ -22,15 +22,15 @@
|
|||||||
<main class="container-fluid">
|
<main class="container-fluid">
|
||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
<h2>Select csv data</h2>
|
<h2>Select CSV data</h2>
|
||||||
</header>
|
</header>
|
||||||
<form id="select-data-form">
|
<form id="select-data-form">
|
||||||
<label for="file-input" class="custom-file-upload">
|
<label for="file-input" class="custom-file-upload">
|
||||||
<i class="fa fa-file-csv"></i> Select csv file to explore
|
<i class="fa fa-file-csv"></i> Select CSV file to explore
|
||||||
</label>
|
</label>
|
||||||
<input id="file-input" type="file" aria-describedby="fileHelp" accept="text/csv" />
|
<input id="file-input" type="file" aria-describedby="fileHelp" accept="text/csv" />
|
||||||
<small id="fileHelp">Please upload a csv file, where the first row is the header. And the values are
|
<small id="fileHelp">Please upload a CSV file, where the first row is the header. And the values are
|
||||||
comma(,) seperated.</small>
|
comma(,) separated.</small>
|
||||||
</form>
|
</form>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
@@ -38,14 +38,32 @@
|
|||||||
<header>
|
<header>
|
||||||
<h2>Data infos</h2>
|
<h2>Data infos</h2>
|
||||||
</header>
|
</header>
|
||||||
<div id="data-info"></div>
|
<div id="data-info">
|
||||||
|
<h4>Filename</h4>
|
||||||
|
<p id="data-filename"></p>
|
||||||
|
<h4>File type</h4>
|
||||||
|
<p id="data-filetype"></p>
|
||||||
|
<h4>File size</h4>
|
||||||
|
<p id="data-filesize"></p>
|
||||||
|
<h4>Number of rows</h4>
|
||||||
|
<p id="data-rowcount"></p>
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
<h2>Selected column infos</h2>
|
<h2>Selected column infos</h2>
|
||||||
</header>
|
</header>
|
||||||
<div id="column-info"></div>
|
<div id="column-info">
|
||||||
|
<h4>Filename</h4>
|
||||||
|
<p id="data-filename"></p>
|
||||||
|
<h4>File type</h4>
|
||||||
|
<p id="data-filetype"></p>
|
||||||
|
<h4>File size</h4>
|
||||||
|
<p id="data-filesize"></p>
|
||||||
|
<h4>Number of rows</h4>
|
||||||
|
<p id="data-rowcount"></p>
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article>
|
<article>
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
|
import {
|
||||||
|
CSV_Data
|
||||||
|
} from './types';
|
||||||
import {
|
import {
|
||||||
csv2json
|
csv2json
|
||||||
} from 'json-2-csv';
|
} from 'json-2-csv';
|
||||||
|
|
||||||
export type CSV_Data = Array<Record<string, unknown>>;
|
|
||||||
|
|
||||||
const convertCSVtoJSON = async ( csvText: string ) => {
|
const convertCSVtoJSON = async ( csvText: string ) => {
|
||||||
// Type cast OK, as the typing of the external library is not perfect.
|
// Type cast OK, as the typing of the external library is not perfect -> Actually it is.
|
||||||
// NOTE: On transpilation to JS, it will be (more or less) disregarded anyway
|
// NOTE: On transpilation to JS, it will be (more or less) disregarded anyway.
|
||||||
|
// If you claim it isn't good typing, it's the same as expecting it to guess the typing,
|
||||||
|
// which is literally impossible in TS. But sure...
|
||||||
return ( await csv2json( csvText ) ) as CSV_Data;
|
return ( await csv2json( csvText ) ) as CSV_Data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
140
task_2_ts/ts/framework.ts
Normal file
140
task_2_ts/ts/framework.ts
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// Yes, I could not be arsed to keep track of state manually, so wrote a framework real quick that
|
||||||
|
// does that for me. I am well aware that this is well over engineered, but it was a lot of fun
|
||||||
|
// and no, this is *NOT* AI generated (I know Claude likes to hallucinate that kinda stuff)
|
||||||
|
// I will be trying to somewhat follow Vue naming here, as that is what I am familiar with
|
||||||
|
//
|
||||||
|
// It was also a nice exercise to get familiar with Generics in TypeScript, something I haven't
|
||||||
|
// really used before
|
||||||
|
|
||||||
|
export interface Ref<T> {
|
||||||
|
'set': ( data: T ) => void;
|
||||||
|
'get': () => T;
|
||||||
|
'addConditionalElements': ( elements: HTMLElement[] ) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListRef<T> {
|
||||||
|
'set': ( data: T[] ) => void;
|
||||||
|
'get': () => T[];
|
||||||
|
'sort': ( compare: ( a: T, b: T ) => number ) => void;
|
||||||
|
'filter': ( predicate: ( value: T ) => boolean ) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsive data (similar behaviour as in Vue.js)
|
||||||
|
* @template T - The data type you wish to use (as long as you don't want it to be a list)
|
||||||
|
* @param data - The data stored in this ref
|
||||||
|
* @param elements - The elements to bind to
|
||||||
|
*/
|
||||||
|
const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
|
||||||
|
let value: T = data;
|
||||||
|
let conditionalElements: HTMLElement[] = [];
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
const get = (): T => {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
const set = ( data: T ): void => {
|
||||||
|
value = data;
|
||||||
|
|
||||||
|
// Update normal ref elements
|
||||||
|
elements.forEach( el => {
|
||||||
|
el.innerHTML = String( data );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Update conditional elements
|
||||||
|
conditionalElements.forEach( el => {
|
||||||
|
// convert to boolean (explicitly)
|
||||||
|
el.hidden = Boolean( data );
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add elements to be rendered conditionally on this ref. Treats type as booleanish
|
||||||
|
* @param elements - The elements that are rendered consistently
|
||||||
|
*/
|
||||||
|
const addConditionalElements = ( elements: HTMLElement[] ): void => {
|
||||||
|
conditionalElements = elements;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
set,
|
||||||
|
get,
|
||||||
|
addConditionalElements
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
// ╭───────────────────────────────────────────────╮
|
||||||
|
// │ List ref, dynamic list rendering │
|
||||||
|
// ╰───────────────────────────────────────────────╯
|
||||||
|
export type HTMLTagNames = 'div' | 'button' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'span';
|
||||||
|
|
||||||
|
export interface RenderTemplate {
|
||||||
|
[name: string]: {
|
||||||
|
'type': HTMLTagNames;
|
||||||
|
'attribute': string;
|
||||||
|
'cssClasses': string[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DiffList<T> {
|
||||||
|
'modified': T[];
|
||||||
|
'added': T[];
|
||||||
|
'removed': T[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const listRef = <T>( parent: HTMLElement, data: T[] ): ListRef<T> => {
|
||||||
|
let value: T[] = data;
|
||||||
|
let rendered: T[] = [];
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
const get = (): T[] => {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
const set = ( data: T[] ): void => {
|
||||||
|
const diffList: DiffList<T> = {
|
||||||
|
'modified': [],
|
||||||
|
'added': [],
|
||||||
|
'removed': []
|
||||||
|
};
|
||||||
|
|
||||||
|
value = data;
|
||||||
|
rendered = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sort = ( compare: ( a: T, b: T ) => number ): void => {
|
||||||
|
// Re-render based on compare function
|
||||||
|
};
|
||||||
|
|
||||||
|
const filter = ( predicate: ( value: T ) => boolean ): void => {
|
||||||
|
const diffList: DiffList<T> = {
|
||||||
|
'modified': [],
|
||||||
|
'added': [],
|
||||||
|
'removed': []
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
get,
|
||||||
|
set,
|
||||||
|
sort,
|
||||||
|
filter
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// The list renderer using a DiffList
|
||||||
|
const renderList = <T>( diffList: DiffList<T> ) => {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
ref,
|
||||||
|
listRef
|
||||||
|
};
|
||||||
1
task_2_ts/ts/types.d.ts
vendored
Normal file
1
task_2_ts/ts/types.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export type CSV_Data = Array<Record<string, unknown>>;
|
||||||
Reference in New Issue
Block a user