Clean up how JS functions are registered and located for invocation from .NET
This commit is contained in:
parent
7bbf2b54aa
commit
0187384638
|
|
@ -1,13 +1,11 @@
|
|||
import { platform } from './Environment'
|
||||
import { registerFunction } from './RegisteredFunction';
|
||||
|
||||
// This file defines an export that, when the library is loaded in a browser via a
|
||||
// <script> element, will be attached to the global namespace
|
||||
const blazorInstance = {
|
||||
platform: platform,
|
||||
registerFunction: registerFunction
|
||||
};
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['Blazor'] = blazorInstance;
|
||||
// When the library is loaded in a browser via a <script> element, make the
|
||||
// following APIs available in global scope for invocation from JS
|
||||
window['Blazor'] = {
|
||||
platform,
|
||||
registerFunction,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
import { invokeWithJsonMarshalling } from './RegisteredFunction';
|
||||
import { attachComponentToElement, renderRenderTree } from './Rendering/Renderer';
|
||||
|
||||
/**
|
||||
* The definitive list of internal functions invokable from .NET code.
|
||||
* These function names are treated as 'reserved' and cannot be passed to registerFunction.
|
||||
*/
|
||||
export const internalRegisteredFunctions = {
|
||||
attachComponentToElement,
|
||||
invokeWithJsonMarshalling,
|
||||
renderRenderTree,
|
||||
};
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { MethodHandle, System_Object, System_String, System_Array, Pointer, Platform } from '../Platform';
|
||||
import { getAssemblyNameFromUrl } from '../DotNet';
|
||||
import { getRegisteredFunction } from '../../RegisteredFunction';
|
||||
|
||||
let assembly_load: (assemblyName: string) => number;
|
||||
let find_class: (assemblyHandle: number, namespace: string, className: string) => number;
|
||||
|
|
@ -120,6 +121,10 @@ export const monoPlatform: Platform = {
|
|||
},
|
||||
};
|
||||
|
||||
// Bypass normal type checking to add this extra function. It's only intended to be called from
|
||||
// the JS code in Mono's driver.c. It's never intended to be called from TypeScript.
|
||||
(monoPlatform as any).monoGetRegisteredFunction = getRegisteredFunction;
|
||||
|
||||
function addScriptTagsToDocument() {
|
||||
// Load either the wasm or asm.js version of the Mono runtime
|
||||
const browserSupportsNativeWebAssembly = typeof WebAssembly !== 'undefined' && WebAssembly.validate;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import { System_String } from './Platform/Platform';
|
||||
import { platform } from './Environment';
|
||||
import { internalRegisteredFunctions } from './InternalRegisteredFunction';
|
||||
|
||||
const registeredFunctions: { [identifier: string]: Function } = {};
|
||||
|
||||
// Code in Mono 'driver.c' looks for the registered functions here
|
||||
window['__blazorRegisteredFunctions'] = registeredFunctions;
|
||||
const registeredFunctions: { [identifier: string]: Function | undefined } = {};
|
||||
|
||||
export function registerFunction(identifier: string, implementation: Function) {
|
||||
if (internalRegisteredFunctions.hasOwnProperty(identifier)) {
|
||||
throw new Error(`The function identifier '${identifier}' is reserved and cannot be registered.`);
|
||||
}
|
||||
|
||||
if (registeredFunctions.hasOwnProperty(identifier)) {
|
||||
throw new Error(`A function with the identifier '${identifier}' has already been registered.`);
|
||||
}
|
||||
|
|
@ -14,13 +16,19 @@ export function registerFunction(identifier: string, implementation: Function) {
|
|||
registeredFunctions[identifier] = implementation;
|
||||
}
|
||||
|
||||
// Handle the JSON-marshalled RegisteredFunction.Invoke calls
|
||||
registerFunction('__blazor_InvokeJson', (identifier: System_String, ...argsJson: System_String[]) => {
|
||||
const identifierJsString = platform.toJavaScriptString(identifier);
|
||||
if (!(registeredFunctions && registeredFunctions.hasOwnProperty(identifierJsString))) {
|
||||
throw new Error(`Could not find registered function with name "${identifierJsString}".`);
|
||||
export function getRegisteredFunction(identifier: string): Function {
|
||||
// By prioritising the internal ones, we ensure you can't override them
|
||||
const result = internalRegisteredFunctions[identifier] || registeredFunctions[identifier];
|
||||
if (result) {
|
||||
return result;
|
||||
} else {
|
||||
throw new Error(`Could not find registered function with name '${identifier}'.`);
|
||||
}
|
||||
const funcInstance = registeredFunctions[identifierJsString];
|
||||
}
|
||||
|
||||
export function invokeWithJsonMarshalling(identifier: System_String, ...argsJson: System_String[]) {
|
||||
const identifierJsString = platform.toJavaScriptString(identifier);
|
||||
const funcInstance = getRegisteredFunction(identifierJsString);
|
||||
const args = argsJson.map(json => JSON.parse(platform.toJavaScriptString(json)));
|
||||
const result = funcInstance.apply(null, args);
|
||||
if (result !== null && result !== undefined) {
|
||||
|
|
@ -29,4 +37,4 @@ registerFunction('__blazor_InvokeJson', (identifier: System_String, ...argsJson:
|
|||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { registerFunction } from '../RegisteredFunction';
|
||||
import { System_Object, System_String, System_Array, MethodHandle, Pointer } from '../Platform/Platform';
|
||||
import { System_Object, System_String, System_Array, MethodHandle, Pointer } from '../Platform/Platform';
|
||||
import { platform } from '../Environment';
|
||||
import { getTreeNodePtr, renderTreeNode, NodeType, RenderTreeNodePointer } from './RenderTreeNode';
|
||||
let raiseEventMethod: MethodHandle;
|
||||
|
|
@ -14,10 +13,7 @@ type ComponentIdToParentElement = { [componentId: number]: Element };
|
|||
type BrowserRendererRegistry = { [browserRendererId: number]: ComponentIdToParentElement };
|
||||
const browserRenderers: BrowserRendererRegistry = {};
|
||||
|
||||
registerFunction('_blazorAttachComponentToElement', attachComponentToElement);
|
||||
registerFunction('_blazorRender', renderRenderTree);
|
||||
|
||||
function attachComponentToElement(browserRendererId: number, elementSelector: System_String, componentId: number) {
|
||||
export function attachComponentToElement(browserRendererId: number, elementSelector: System_String, componentId: number) {
|
||||
const elementSelectorJs = platform.toJavaScriptString(elementSelector);
|
||||
const element = document.querySelector(elementSelectorJs);
|
||||
if (!element) {
|
||||
|
|
@ -28,7 +24,7 @@ function attachComponentToElement(browserRendererId: number, elementSelector: Sy
|
|||
browserRenderers[browserRendererId][componentId] = element;
|
||||
}
|
||||
|
||||
function renderRenderTree(renderComponentArgs: Pointer) {
|
||||
export function renderRenderTree(renderComponentArgs: Pointer) {
|
||||
const browserRendererId = platform.readHeapInt32(renderComponentArgs, 0);
|
||||
const browserRenderer = browserRenderers[browserRendererId];
|
||||
if (!browserRenderer) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.Blazor.Browser.Interop
|
|||
// This is a low-perf convenience method that bypasses the need to deal with
|
||||
// .NET memory and data structures on the JS side
|
||||
var argsJson = args.Select(Json.Serialize);
|
||||
var resultJson = InvokeUnmarshalled<string>("__blazor_InvokeJson",
|
||||
var resultJson = InvokeUnmarshalled<string>("invokeWithJsonMarshalling",
|
||||
argsJson.Prepend(identifier).ToArray());
|
||||
return Json.Deserialize<TRes>(resultJson);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.Blazor.Browser.Rendering
|
|||
{
|
||||
var componentId = AssignComponentId(component);
|
||||
RegisteredFunction.InvokeUnmarshalled<int, string, int, object>(
|
||||
"_blazorAttachComponentToElement",
|
||||
"attachComponentToElement",
|
||||
_browserRendererId,
|
||||
domElementSelector,
|
||||
componentId);
|
||||
|
|
@ -71,7 +71,7 @@ namespace Microsoft.Blazor.Browser.Rendering
|
|||
ArraySegment<RenderTreeNode> renderTree)
|
||||
{
|
||||
RegisteredFunction.InvokeUnmarshalled<RenderComponentArgs, object>(
|
||||
"_blazorRender",
|
||||
"renderRenderTree",
|
||||
new RenderComponentArgs
|
||||
{
|
||||
BrowserRendererId = _browserRendererId,
|
||||
|
|
|
|||
Loading…
Reference in New Issue