release: WRNexusJS 0.6.0
This commit is contained in:
@@ -24,6 +24,7 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
var pendingUpdateHooks = new Map();
|
||||
var updateHooksScheduled = false;
|
||||
var behaviorObserver;
|
||||
var clientModuleCache = new Map();
|
||||
|
||||
function reportDiagnostic(code, message, element, detail) {
|
||||
var payload = {
|
||||
@@ -478,6 +479,21 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
}
|
||||
}
|
||||
|
||||
function loadClientModule(element) {
|
||||
var url = element.getAttribute("data-wrn-client-module");
|
||||
if (!url) return Promise.resolve(null);
|
||||
var promise = clientModuleCache.get(url);
|
||||
if (!promise) {
|
||||
promise = import(url).catch(function (error) {
|
||||
clientModuleCache.delete(url);
|
||||
reportDiagnostic("WRN-CLIENT-MODULE", "Failed to load browser function module '" + url + "'.", element, error);
|
||||
return null;
|
||||
});
|
||||
clientModuleCache.set(url, promise);
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
function setupScope(el) {
|
||||
if (el.__wrnexusScope) return;
|
||||
|
||||
@@ -677,13 +693,39 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
}
|
||||
|
||||
var behaviorFunctions = {};
|
||||
var componentEventTarget = el.querySelector("[data-wrn-events]") || el;
|
||||
var moduleBindings = {};
|
||||
var componentEventTarget = el.hasAttribute("data-wrn-events")
|
||||
? el
|
||||
: el.querySelector("[data-wrn-events]") || el;
|
||||
var declaredEvents = new Set(
|
||||
String(componentEventTarget.getAttribute("data-wrn-events") || "")
|
||||
.split(",")
|
||||
.map(function (name) { return name.trim(); })
|
||||
.filter(Boolean),
|
||||
);
|
||||
var outputHandlers = componentEventTarget.__wrnexusOutputHandlers || (componentEventTarget.__wrnexusOutputHandlers = {});
|
||||
var outputProxy = new Proxy({}, {
|
||||
get: function (_target, property) {
|
||||
return function (payload) {
|
||||
return invokeComponentOutput(componentEventTarget, String(property), payload);
|
||||
};
|
||||
},
|
||||
});
|
||||
var componentRpcName = componentEventTarget.getAttribute("data-wrn-component") || componentEventTarget.getAttribute("data-wrn-hydration") || "component";
|
||||
var serverProxy = new Proxy({}, {
|
||||
get: function (_target, property) {
|
||||
return function () {
|
||||
return callServerFunction(componentRpcName, String(property), Array.prototype.slice.call(arguments));
|
||||
};
|
||||
},
|
||||
});
|
||||
var propsProxy = new Proxy({}, {
|
||||
get: function (_target, property) { return peekScope(String(property)); },
|
||||
set: function () { throw new TypeError("WRN-PROP-READONLY: props are readonly"); },
|
||||
});
|
||||
var refsProxy = new Proxy({}, {
|
||||
get: function (_target, property) { return el.querySelector('[data-ref="' + String(property).replace(/"/g, '\"') + '"]'); },
|
||||
});
|
||||
var stateWatchers = {};
|
||||
var anyStateListeners = new Set();
|
||||
var cleanupCallbacks = [];
|
||||
@@ -695,6 +737,11 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
return dispatchComponentEvent(componentEventTarget, name, detail);
|
||||
};
|
||||
}
|
||||
if (name === "output") return outputProxy;
|
||||
if (name === "server") return serverProxy;
|
||||
if (name === "props") return propsProxy;
|
||||
if (name === "refs") return refsProxy;
|
||||
if (Object.prototype.hasOwnProperty.call(moduleBindings, name)) return moduleBindings[name];
|
||||
if (name === "$emit") {
|
||||
return function (eventName, detail) {
|
||||
return dispatchComponentEvent(componentEventTarget, eventName, detail);
|
||||
@@ -919,6 +966,42 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
});
|
||||
}
|
||||
|
||||
function installClientModule(module) {
|
||||
if (!module) return;
|
||||
var stateProxy = new Proxy({}, {
|
||||
get: function (_target, property) { return readScope(String(property)); },
|
||||
set: function (_target, property, value) { writeScope(String(property), value); return true; },
|
||||
ownKeys: function () { return Object.keys(signals); },
|
||||
getOwnPropertyDescriptor: function () { return { enumerable: true, configurable: true }; },
|
||||
});
|
||||
var context = {
|
||||
state: stateProxy,
|
||||
output: outputProxy,
|
||||
server: serverProxy,
|
||||
props: propsProxy,
|
||||
refs: refsProxy,
|
||||
};
|
||||
var importedBindings = module.__wrnexusImportedBindings;
|
||||
if (importedBindings && typeof importedBindings === "object") {
|
||||
Object.keys(importedBindings).forEach(function (name) {
|
||||
var binding = importedBindings[name];
|
||||
moduleBindings[name] = binding;
|
||||
if (binding && typeof binding.subscribe === "function") {
|
||||
cleanupCallbacks.push(binding.subscribe(function () { renderAll(); }));
|
||||
}
|
||||
});
|
||||
}
|
||||
var functions = typeof module.bindClientScope === "function"
|
||||
? module.bindClientScope(context)
|
||||
: module.__wrnexusClientFunctions;
|
||||
if (!functions || typeof functions !== "object") return;
|
||||
Object.keys(functions).forEach(function (name) {
|
||||
if (typeof functions[name] === "function") behaviorFunctions[name] = functions[name];
|
||||
});
|
||||
}
|
||||
|
||||
installClientModule(el.__wrnexusClientModule);
|
||||
|
||||
// A binding belongs to THIS scope only when el is the node's nearest
|
||||
// [data-scope] ancestor. Otherwise a nested scope owns it and we skip it,
|
||||
// so an outer scope never clobbers an inner one's values.
|
||||
@@ -1233,6 +1316,7 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
|
||||
eventLocals.event = event;
|
||||
eventLocals.$event = event;
|
||||
eventLocals.payload = event && Object.prototype.hasOwnProperty.call(event, "detail") ? event.detail : undefined;
|
||||
|
||||
try {
|
||||
runStmt(
|
||||
@@ -1773,6 +1857,7 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
|
||||
locals.event = event;
|
||||
locals.$event = event;
|
||||
locals.payload = event && Object.prototype.hasOwnProperty.call(event, "detail") ? event.detail : undefined;
|
||||
|
||||
try {
|
||||
runStmt(
|
||||
@@ -1794,6 +1879,19 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
? { passive: true }
|
||||
: undefined;
|
||||
|
||||
if (target === componentEventTarget && declaredEvents.has(evt)) {
|
||||
var directHandler = function (payload) {
|
||||
var locals = decodeLoopLocals(node);
|
||||
locals.payload = payload;
|
||||
locals.event = undefined;
|
||||
locals.$event = undefined;
|
||||
return runStmt(stmt, locals);
|
||||
};
|
||||
(outputHandlers[evt] || (outputHandlers[evt] = new Set())).add(directHandler);
|
||||
cleanupCallbacks.push(function () {
|
||||
if (outputHandlers[evt]) outputHandlers[evt].delete(directHandler);
|
||||
});
|
||||
}
|
||||
target.addEventListener(evt, listener, options);
|
||||
cleanupCallbacks.push(function () {
|
||||
target.removeEventListener(evt, listener, options);
|
||||
@@ -1932,7 +2030,16 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
|
||||
function hydrate() {
|
||||
if (element.__wrnexusScope || !element.isConnected) return;
|
||||
setupScope(element);
|
||||
var moduleUrl = element.getAttribute("data-wrn-client-module");
|
||||
if (!moduleUrl || moduleUrl === "__WRNEXUS_CLIENT_MODULE__") {
|
||||
setupScope(element);
|
||||
return;
|
||||
}
|
||||
loadClientModule(element).then(function (module) {
|
||||
if (element.__wrnexusScope || !element.isConnected) return;
|
||||
element.__wrnexusClientModule = module;
|
||||
setupScope(element);
|
||||
});
|
||||
}
|
||||
|
||||
if (strategy === "load") {
|
||||
@@ -2616,6 +2723,43 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
}
|
||||
}
|
||||
|
||||
function invokeComponentOutput(root, name, payload) {
|
||||
if (!root || !name) return undefined;
|
||||
var registry = root.__wrnexusOutputHandlers;
|
||||
var handlers = registry && registry[name];
|
||||
if (handlers && handlers.size) {
|
||||
var values = [];
|
||||
handlers.forEach(function (handler) { values.push(handler(payload)); });
|
||||
return values.some(function (value) { return value && typeof value.then === "function"; })
|
||||
? Promise.all(values)
|
||||
: values[values.length - 1];
|
||||
}
|
||||
return dispatchComponentEvent(root, name, payload);
|
||||
}
|
||||
|
||||
function callServerFunction(component, functionName, args) {
|
||||
var csrf = document.querySelector('meta[name="wrnexus-csrf"]');
|
||||
return fetch("/__wrnexus/rpc", {
|
||||
method: "POST",
|
||||
credentials: "same-origin",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"x-wrnexus-csrf": csrf ? csrf.getAttribute("content") || "" : "",
|
||||
},
|
||||
body: JSON.stringify({ component: component, function: functionName, args: args || [] }),
|
||||
}).then(function (response) {
|
||||
return response.json().catch(function () { return null; }).then(function (payload) {
|
||||
if (!response.ok || !payload || !payload.ok) {
|
||||
var error = new Error(payload && payload.error && payload.error.message || "Server function call failed");
|
||||
error.code = payload && payload.error && payload.error.code || "WRN-RPC-FAILED";
|
||||
error.status = response.status;
|
||||
throw error;
|
||||
}
|
||||
return payload.value;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function dispatchComponentEvent(root, name, detail) {
|
||||
if (!root || !name) return null;
|
||||
var EventConstructor =
|
||||
@@ -3789,6 +3933,7 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
}
|
||||
|
||||
window.__wrnexusHydrateScopes = hydrateScopes;
|
||||
window.__wrnexusInvalidateClientModule = function (url) { clientModuleCache.delete(url); };
|
||||
window.__wrnexusHydrateCsrFetches = hydrateCsrFetches;
|
||||
window.__wrnexusDisposeBehaviors = disposeBehaviors;
|
||||
if (document.readyState === "loading") {
|
||||
|
||||
Reference in New Issue
Block a user