mirror of
https://github.com/janishutz/fundamentals-of-webengineering.git
synced 2025-11-25 05:44:24 +00:00
Framework rendering fixes
This commit is contained in:
@@ -26,9 +26,9 @@ const renderer = <T extends StringIndexedObject>( data: T, template: RenderTempl
|
|||||||
|
|
||||||
if ( template.children.length === 0 ) {
|
if ( template.children.length === 0 ) {
|
||||||
if ( template.attribute ) {
|
if ( template.attribute ) {
|
||||||
parent.innerText = String( data[ template.attribute ] );
|
parent.textContent = String( data[ template.attribute ] );
|
||||||
} else {
|
} else {
|
||||||
parent.innerText = String( data );
|
parent.textContent = String( data );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const listRef = <T>( parent: HTMLElement, data: T[], name: string, templa
|
|||||||
// Yes, I know, really bad performance, etc, but it's not needed for any other use case
|
// Yes, I know, really bad performance, etc, but it's not needed for any other use case
|
||||||
// here, other than a full replace of the data (no dynamic updates)
|
// here, other than a full replace of the data (no dynamic updates)
|
||||||
list = data;
|
list = data;
|
||||||
console.log( data );
|
parent.textContent = '';
|
||||||
|
|
||||||
// Render the list based on template
|
// Render the list based on template
|
||||||
for ( let i = 0; i < data.length; i++ ) {
|
for ( let i = 0; i < data.length; i++ ) {
|
||||||
@@ -92,6 +92,7 @@ export const listRef = <T>( parent: HTMLElement, data: T[], name: string, templa
|
|||||||
if ( !evaluation && rendered[ index ] ) {
|
if ( !evaluation && rendered[ index ] ) {
|
||||||
// can use ! here, as semantics of program tell us that this index will exist
|
// can use ! here, as semantics of program tell us that this index will exist
|
||||||
nodes[ index ]!.remove();
|
nodes[ index ]!.remove();
|
||||||
|
rendered[ index ] = false;
|
||||||
} else if ( evaluation && !rendered[ index ] ) {
|
} else if ( evaluation && !rendered[ index ] ) {
|
||||||
currentIndexInChildrenList++;
|
currentIndexInChildrenList++;
|
||||||
parent.insertBefore( nodes[ index ]!, children[ currentIndexInChildrenList ]! );
|
parent.insertBefore( nodes[ index ]!, children[ currentIndexInChildrenList ]! );
|
||||||
|
|||||||
@@ -2,6 +2,17 @@ import {
|
|||||||
Ref
|
Ref
|
||||||
} from './rendering';
|
} from './rendering';
|
||||||
|
|
||||||
|
interface ConditionalElement<T> {
|
||||||
|
'element': HTMLElement;
|
||||||
|
'predicate': ( value: T ) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConditionalClass {
|
||||||
|
'element': HTMLElement,
|
||||||
|
'onTrue': string,
|
||||||
|
'onFalse': string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsive data (similar behaviour as in Vue.js)
|
* 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)
|
* @template T - The data type you wish to use (as long as you don't want it to be a list)
|
||||||
@@ -10,34 +21,44 @@ import {
|
|||||||
*/
|
*/
|
||||||
export const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
|
export const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
|
||||||
let value: T = data;
|
let value: T = data;
|
||||||
let conditionalElements: HTMLElement[] = [];
|
|
||||||
|
|
||||||
|
const conditionalElements: ConditionalElement<T>[] = [];
|
||||||
const onChangeFunctions: ( () => Promise<void> )[] = [];
|
const onChangeFunctions: ( () => Promise<void> )[] = [];
|
||||||
const conditionalClasses: {
|
const conditionalClasses: ConditionalClass[] = [];
|
||||||
'element': HTMLElement,
|
|
||||||
'onTrue': string,
|
|
||||||
'onFalse': string
|
|
||||||
}[] = [];
|
|
||||||
const boundElements: HTMLInputElement[] = [];
|
const boundElements: HTMLInputElement[] = [];
|
||||||
|
|
||||||
// ───────────────────────────────────────────────────────────────────
|
|
||||||
|
/**
|
||||||
|
* Bind to a further element (DOM text is updated for it)
|
||||||
|
* @param element - The element to add
|
||||||
|
*/
|
||||||
|
const addAdditionalElement = ( element: HTMLElement ) => {
|
||||||
|
elements.push( element );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The value the ref currently holds
|
||||||
|
*/
|
||||||
const get = (): T => {
|
const get = (): T => {
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ───────────────────────────────────────────────────────────────────
|
|
||||||
|
/**
|
||||||
|
* @param data - The new value of the
|
||||||
|
*/
|
||||||
const set = ( data: T ): void => {
|
const set = ( data: T ): void => {
|
||||||
value = data;
|
value = data;
|
||||||
|
|
||||||
// Update normal ref elements
|
// Update normal ref elements
|
||||||
elements.forEach( el => {
|
elements.forEach( el => {
|
||||||
el.innerText = String( data );
|
el.textContent = String( data );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Update conditional elements
|
// Update conditional elements
|
||||||
conditionalElements.forEach( el => {
|
conditionalElements.forEach( el => {
|
||||||
// convert to boolean (explicitly)
|
// convert to boolean (explicitly)
|
||||||
el.hidden = Boolean( data );
|
el.element.hidden = !el.predicate( data );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
conditionalClasses.forEach( el => {
|
conditionalClasses.forEach( el => {
|
||||||
@@ -54,6 +75,7 @@ export const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind to input change of an HTMLInputElement (two way bind)
|
* Bind to input change of an HTMLInputElement (two way bind)
|
||||||
* @param element - The element to bind to (i.e. add a two-way bind to)
|
* @param element - The element to bind to (i.e. add a two-way bind to)
|
||||||
@@ -63,17 +85,25 @@ export const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
|
|||||||
element.addEventListener( 'change', () => {
|
element.addEventListener( 'change', () => {
|
||||||
set( castFunction( element.value ) );
|
set( castFunction( element.value ) );
|
||||||
} );
|
} );
|
||||||
|
element.value = String( value );
|
||||||
boundElements.push( element );
|
boundElements.push( element );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add elements to be rendered conditionally on this ref. Treats type as booleanish
|
* Add elements to be rendered conditionally on this ref. Treats type as booleanish
|
||||||
* @param elements - The elements that are rendered consistently
|
* @param element - The element that will be affected by predicate
|
||||||
|
* @param predicate - The predicate to evaluate when value is changed
|
||||||
*/
|
*/
|
||||||
const setConditionalElements = ( elements: HTMLElement[] ): void => {
|
const addConditionalElementBind = ( element: HTMLElement, predicate: ( value: T ) => boolean ): void => {
|
||||||
conditionalElements = elements;
|
conditionalElements.push( {
|
||||||
|
'element': element,
|
||||||
|
'predicate': predicate
|
||||||
|
} );
|
||||||
|
element.hidden = !predicate( value );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param element - The element to do the operation on
|
* @param element - The element to do the operation on
|
||||||
* @param onTrue - The classes (as strings) to set if true(ish)
|
* @param onTrue - The classes (as strings) to set if true(ish)
|
||||||
@@ -107,7 +137,8 @@ export const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
|
|||||||
return {
|
return {
|
||||||
set,
|
set,
|
||||||
get,
|
get,
|
||||||
setConditionalElements,
|
addAdditionalElement,
|
||||||
|
addConditionalElementBind,
|
||||||
addConditionalClasses,
|
addConditionalClasses,
|
||||||
bind,
|
bind,
|
||||||
onChange
|
onChange
|
||||||
|
|||||||
3
task_2_ts/ts/rendering/rendering.d.ts
vendored
3
task_2_ts/ts/rendering/rendering.d.ts
vendored
@@ -1,7 +1,8 @@
|
|||||||
export interface Ref<T> {
|
export interface Ref<T> {
|
||||||
'set': ( data: T ) => void;
|
'set': ( data: T ) => void;
|
||||||
'get': () => T;
|
'get': () => T;
|
||||||
'setConditionalElements': ( elements: HTMLElement[] ) => void;
|
'addAdditionalElement': ( elements: HTMLElement, predicate: ( value: T ) => boolean ) => void;
|
||||||
|
'addConditionalElementBind': ( elements: HTMLElement, predicate: ( value: T ) => boolean ) => void;
|
||||||
'addConditionalClasses': ( element: HTMLElement, onTrue: string, onFalse: string ) => void;
|
'addConditionalClasses': ( element: HTMLElement, onTrue: string, onFalse: string ) => void;
|
||||||
'bind': ( element: HTMLInputElement, castFunction: ( val: string ) => T ) => void;
|
'bind': ( element: HTMLInputElement, castFunction: ( val: string ) => T ) => void;
|
||||||
'onChange': ( callback: () => void ) => void;
|
'onChange': ( callback: () => void ) => void;
|
||||||
|
|||||||
Reference in New Issue
Block a user