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">
|
||||
<article>
|
||||
<header>
|
||||
<h2>Select csv data</h2>
|
||||
<h2>Select CSV data</h2>
|
||||
</header>
|
||||
<form id="select-data-form">
|
||||
<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>
|
||||
<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
|
||||
comma(,) seperated.</small>
|
||||
<small id="fileHelp">Please upload a CSV file, where the first row is the header. And the values are
|
||||
comma(,) separated.</small>
|
||||
</form>
|
||||
</article>
|
||||
|
||||
@@ -38,14 +38,32 @@
|
||||
<header>
|
||||
<h2>Data infos</h2>
|
||||
</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>
|
||||
<header>
|
||||
<h2>Selected column infos</h2>
|
||||
</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>
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import {
|
||||
CSV_Data
|
||||
} from './types';
|
||||
import {
|
||||
csv2json
|
||||
} from 'json-2-csv';
|
||||
|
||||
export type CSV_Data = Array<Record<string, unknown>>;
|
||||
|
||||
const convertCSVtoJSON = async ( csvText: string ) => {
|
||||
// Type cast OK, as the typing of the external library is not perfect.
|
||||
// NOTE: On transpilation to JS, it will be (more or less) disregarded anyway
|
||||
// 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.
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
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