Skip to content

Commit

Permalink
✨ Add initial reactive variable support
Browse files Browse the repository at this point in the history
  • Loading branch information
skerit committed Apr 29, 2024
1 parent 488a168 commit 765c458
Show file tree
Hide file tree
Showing 15 changed files with 581 additions and 136 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Only clone certain variables once, when they are initially set
* Prepare text nodes during compiling
* Clean up custom element `renderCustomTemplate` function
* Add initial reactive variable support

## 2.3.19 (2024-04-13)

Expand Down
1 change: 1 addition & 0 deletions lib/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Blast.requireAll([
['parser', 'marked'],
['parser', 'markdown_parser'],
['parser', 'builder'],
['parser', 'function_body'],
['parser', 'subroutine']
], options);

Expand Down
2 changes: 2 additions & 0 deletions lib/core/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,10 @@ function logLog(type, args) {
}

// Some Symbols
Hawkejs.RENDER_INSTRUCTION = Symbol('render_instruction');
Hawkejs.DELAY_SYNC_RENDER = Symbol('delay_sync_render');
Hawkejs.CREATED_MANUALLY = Symbol('created_manually');
Hawkejs.REACTIVE_VALUES = Symbol('reactive_values');
Hawkejs.APPLIED_OPTIONS = Symbol('applied_options');
Hawkejs.RENDER_CONTENT = Symbol('render_hawkejs_content');
Hawkejs.SERIALIZE_FORM = Symbol('serialize_form');
Expand Down
8 changes: 5 additions & 3 deletions lib/core/hawkejs.js
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ Main.setMethod(function createElement(name, xml) {
*
* @author Jelle De Loecker <[email protected]>
* @since 1.0.0
* @version 2.2.0
* @version 2.4.0
*
* @param {Object} options
* @param {String} options.template_name
Expand All @@ -430,13 +430,15 @@ Main.setMethod(function compile(options) {
if (arguments.length == 2) {
options = {
template_name : options,
template : arguments[1]
template : arguments[1],
is_inline : true,
};
} else {
options = {
template_name : 'inline_' + (counter++),
template : options,
cache : false
cache : false,
is_inline : true,
};
}
} else if (!options) {
Expand Down
104 changes: 104 additions & 0 deletions lib/core/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,44 @@ Renderer.enforceSingletonElement('html');
Renderer.enforceSingletonElement('head');
Renderer.enforceSingletonElement('body');

/**
* Split the input into keys & vlaues
*
* @author Jelle De Loecker <[email protected]>
* @since 2.4.0
* @version 2.4.0
*
* @param {HTMLElement} element
* @param {Develry.Optional[]} values
*/
Renderer.setStatic(function attachReactiveListeners(element, values) {

if (!element || !values?.length) {
return;
}

values.forEach(optional => optional.onChange(() => reactiveRerender(element)));
});

/**
* Rerender the given element
*
* @author Jelle De Loecker <[email protected]>
* @since 2.4.0
* @version 2.4.0
*
* @param {HTMLElement} element
*/
function reactiveRerender(element) {

// Make sure we have all the required info for a rerender
if (!element.is_custom_hawkejs_element && !element[Hawkejs.RENDER_INSTRUCTION]) {
return;
}

return Hawkejs.Element.Element.prototype.rerender.call(element);
}

/**
* The variables to use when rendering
*
Expand Down Expand Up @@ -2282,6 +2320,72 @@ Renderer.setMethod(function applyElementOptions(element, options, for_sync_rende
}
}
}

// If the element body is rendered using reference variables,
// the element has to be registered so the browser knows about it
if (options.reference_count > 0 && options.references?.length) {

let values = [];

for (let name of options.references) {
let value = this.active_variables.get(name);

if (!value || !(value instanceof Classes.Develry.Optional)) {
continue;
}

values.push(value);
}

if (this.attachReactiveReferences(element, values)) {

if (options.variables && element[Hawkejs.VARIABLES]) {
let new_variables = this.active_variables.overlay(element[Hawkejs.VARIABLES]);
element[Hawkejs.VARIABLES] = new_variables;
} else if (!element[Hawkejs.VARIABLES]) {
element[Hawkejs.VARIABLES] = this.active_variables;
}

if (!element.is_custom_hawkejs_element && options.body) {
let instruction = {};

if (options.body.source_name) {
instruction.template = options.body.source_name;
instruction.function = options.body.name;
} else {
instruction.source = options.body.source_code;
}

element[Hawkejs.RENDER_INSTRUCTION] = instruction;
}
}
}
});

/**
* Attach reactive references
*
* @author Jelle De Loecker <[email protected]>
* @since 2.4.0
* @version 2.4.0
*
* @param {HTMLElement} element
* @param {Develry.Optional[]} values
*/
Renderer.setMethod(function attachReactiveReferences(element, values) {

// Only bother registering the element if there are values
if (!element || !values?.length) {
return;
}

element[Hawkejs.REACTIVE_VALUES] = values;

this.registerElementInstance(element);

Hawkejs.Renderer.attachReactiveListeners(element, values);

return true;
});

/**
Expand Down
86 changes: 77 additions & 9 deletions lib/core/template.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const TARGET_NAME = Symbol('target_block_name'),
RENDERER = Symbol('renderer');
RENDERER = Symbol('renderer'),
COMPILED = Symbol('compiled');

/**
* The Template class
Expand All @@ -23,13 +24,12 @@ const Template = Fn.inherits('Hawkejs.Base', function Template(templates, name,
// Are we switching out this template?
this.switching_template = false;

// Set the name
// Do we want to use a specific subroutine?
// (If not set, the main "compiledView" function will be used)
this.wanted_subroutine = null;

if (name) {
if (typeof name == 'function') {
this.fnc = name;
} else {
this.name = name;
}
this.setTemplateInfo(name);
}
});

Expand Down Expand Up @@ -440,6 +440,46 @@ Template.setStatic(function unDry(obj) {
return result;
});

/**
* Set the wanted template info
*
* @author Jelle De Loecker <[email protected]>
* @since 2.4.0
* @version 2.4.0
*
* @param {string|Function|Object} info
*/
Template.setMethod(function setTemplateInfo(info) {

if (!info) {
return;
}

let type = typeof info;

if (type == 'string') {
this.name = info;
} else if (type == 'function') {
this.fnc = info;
} else if (type == 'object') {

if (info.template) {
this.name = info.template;
}

if (info.function) {
this.wanted_subroutine = info.function;
}

if (info[COMPILED]) {
this.fnc = info[COMPILED];
} else if (info.source) {
this.fnc = this.hawkejs.compile(info.source);
info[COMPILED] = this.fnc;
}
}
});

/**
* Return an object for json-drying this object
*
Expand Down Expand Up @@ -544,12 +584,40 @@ Template.setMethod(Blast.checksumSymbol, function checksum() {
return Obj.checksum([this.name, this.theme, this.source_name, this.fnc]);
});

/**
* Get a subroutine function by name
*
* @author Jelle De Loecker <[email protected]>
* @since 2.4.0
* @version 2.4.0
*
* @param {string} name
*
* @return {Function}
*/
Template.setMethod(function getSubroutineFunction(name) {

if (!this.fnc) {
return;
}

if (arguments.length == 0) {
if (!this.wanted_subroutine) {
return this.fnc;
}

name = this.wanted_subroutine;
}

return this.fnc.compiled?.[name];
});

/**
* Execute the compiled code
*
* @author Jelle De Loecker <[email protected]>
* @since 2.1.0
* @version 2.3.7
* @version 2.4.0
*
* @param {Object} variables
*/
Expand Down Expand Up @@ -582,7 +650,7 @@ Template.setMethod(function evaluate(variables) {
renderer.active_variables = variables

// Actually call the compiled function
this.fnc.call(renderer, renderer, this, variables, renderer.helpers);
this.getSubroutineFunction().call(renderer, renderer, this, variables, renderer.helpers);

// End the template's main block
renderer.end(this.main_block_name);
Expand Down
8 changes: 4 additions & 4 deletions lib/core/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ Templates.setProperty(function name() {
*
* @author Jelle De Loecker <[email protected]>
* @since 1.0.0
* @version 2.2.20
* @version 2.4.0
*
* @type {Array}
*/
Expand Down Expand Up @@ -208,7 +208,7 @@ Templates.enforceProperty(function templates(names) {
names[i].main_name_modifier = this.main_name_modifier;
}

if (i == 0 && names[i].fnc) {
if (i == 0 && names[i].getSubroutineFunction()) {
this.active = names[i];
}
}
Expand Down Expand Up @@ -335,13 +335,13 @@ Templates.setMethod(function toString() {
*
* @author Jelle De Loecker <[email protected]>
* @since 1.0.0
* @version 2.3.15
* @version 2.4.0
*
* @param {Function} callback
*/
Templates.setMethod(function getCompiled(callback) {

if (this.active && this.active.fnc) {
if (this.active && this.active.getSubroutineFunction()) {
return callback(null, this.active);
}

Expand Down
Loading

0 comments on commit 765c458

Please sign in to comment.