mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-24 01:15:25 +01:00
action service typesafety
This commit is contained in:
parent
1cc881db15
commit
6f12c81688
2 changed files with 165 additions and 94 deletions
|
|
@ -1,94 +0,0 @@
|
|||
import {enableAnonymousActionHint} from './anonHint';
|
||||
import * as stream from 'lstream';
|
||||
import {LOG_FLAGS} from '../logFlags';
|
||||
|
||||
export function activate(context) {
|
||||
|
||||
let {streams} = context;
|
||||
|
||||
streams.action = {
|
||||
appearance: {},
|
||||
state: {},
|
||||
hint: stream.state(null)
|
||||
};
|
||||
|
||||
let runners = {};
|
||||
|
||||
let showAnonymousActionHint = enableAnonymousActionHint(context);
|
||||
|
||||
function run(id, data) {
|
||||
let state = streams.action.state[id].value;
|
||||
let runner = runners[id];
|
||||
if (!state||!runner) {
|
||||
console.warn('request to run nonexistent action')
|
||||
return;
|
||||
}
|
||||
if (state.enabled) {
|
||||
if (LOG_FLAGS.ACTION_RUN) {
|
||||
console.log("RUNNING ACTION: " + id);
|
||||
}
|
||||
runner(context, data);
|
||||
} else {
|
||||
showAnonymousActionHint(id);
|
||||
}
|
||||
}
|
||||
|
||||
function register(action) {
|
||||
streams.action.appearance[action.id] = stream.state(action.appearance);
|
||||
|
||||
runners[action.id] = action.invoke;
|
||||
|
||||
let initialState = {
|
||||
hint: '',
|
||||
enabled: true,
|
||||
visible: true
|
||||
};
|
||||
|
||||
let actionStateStream = stream.state(initialState);
|
||||
streams.action.state[action.id] = actionStateStream;
|
||||
|
||||
if (action.update && action.listens) {
|
||||
|
||||
action.listens(streams).attach(data => {
|
||||
actionStateStream.mutate(v => {
|
||||
v.hint = '';
|
||||
v.enabled = true;
|
||||
v.visible = true;
|
||||
action.update(v, data, context)
|
||||
return v;
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function registerAction(action) {
|
||||
register(action);
|
||||
}
|
||||
|
||||
function registerActions(actions) {
|
||||
actions.forEach(action => register(action));
|
||||
}
|
||||
|
||||
function showHintFor(request) {
|
||||
if (request) {
|
||||
let {actionId, x, y, requester} = request;
|
||||
let actionState = streams.action.state[actionId].value;
|
||||
let actionAppearance = streams.action.appearance[actionId].value;
|
||||
if (actionState && actionAppearance) {
|
||||
streams.action.hint.value = {
|
||||
actionId, x, y, requester,
|
||||
info: actionAppearance.info,
|
||||
hint: actionState.hint
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (streams.action.hint.value !== null) {
|
||||
streams.action.hint.value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.services.action = {run, registerAction, registerActions, showHintFor}
|
||||
}
|
||||
|
||||
|
||||
165
web/app/cad/actions/actionSystemPlugin.ts
Normal file
165
web/app/cad/actions/actionSystemPlugin.ts
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
import {enableAnonymousActionHint} from './anonHint';
|
||||
import * as stream from 'lstream';
|
||||
import {state, StateStream, Stream} from 'lstream';
|
||||
import {LOG_FLAGS} from '../logFlags';
|
||||
import {ApplicationContext} from "context";
|
||||
import {IconType} from "react-icons";
|
||||
|
||||
export function activate(context: ApplicationContext) {
|
||||
|
||||
let {streams} = context;
|
||||
|
||||
|
||||
const appearanceStreams: ActionAppearanceStreams = {};
|
||||
const stateStreams: ActionStateStreams = {};
|
||||
const hint$: StateStream<Hint> = state(null);
|
||||
|
||||
streams.action = {
|
||||
appearance: appearanceStreams,
|
||||
state: stateStreams,
|
||||
hint: hint$
|
||||
};
|
||||
|
||||
let runners = {};
|
||||
|
||||
let showAnonymousActionHint = enableAnonymousActionHint(context);
|
||||
|
||||
function run(id: string, data: any): void {
|
||||
let state = streams.action.state[id].value;
|
||||
let runner = runners[id];
|
||||
if (!state||!runner) {
|
||||
console.warn('request to run nonexistent action');
|
||||
return;
|
||||
}
|
||||
if (state.enabled) {
|
||||
if (LOG_FLAGS.ACTION_RUN) {
|
||||
console.log("RUNNING ACTION: " + id);
|
||||
}
|
||||
runner(context, data);
|
||||
} else {
|
||||
showAnonymousActionHint(id);
|
||||
}
|
||||
}
|
||||
|
||||
function register(action: ActionDefinition): void {
|
||||
streams.action.appearance[action.id] = stream.state(action.appearance);
|
||||
|
||||
runners[action.id] = action.invoke;
|
||||
|
||||
let initialState = {
|
||||
hint: '',
|
||||
enabled: true,
|
||||
visible: true
|
||||
};
|
||||
|
||||
let actionStateStream = stream.state(initialState);
|
||||
streams.action.state[action.id] = actionStateStream;
|
||||
|
||||
if (action.update && action.listens) {
|
||||
|
||||
action.listens(context).attach(data => {
|
||||
actionStateStream.mutate(v => {
|
||||
v.hint = '';
|
||||
v.enabled = true;
|
||||
v.visible = true;
|
||||
action.update(v, data, context);
|
||||
return v;
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function registerAction(action: ActionDefinition): void {
|
||||
register(action);
|
||||
}
|
||||
|
||||
function registerActions(actions: ActionDefinition[]): void {
|
||||
actions.forEach(action => register(action));
|
||||
}
|
||||
|
||||
function showHintFor(request: HintRequest) {
|
||||
if (request) {
|
||||
let {actionId, x, y, requester} = request;
|
||||
let actionState = streams.action.state[actionId].value;
|
||||
let actionAppearance = streams.action.appearance[actionId].value;
|
||||
if (actionState && actionAppearance) {
|
||||
streams.action.hint.value = {
|
||||
actionId, x, y, requester,
|
||||
info: actionAppearance.info,
|
||||
hint: actionState.hint
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (streams.action.hint.value !== null) {
|
||||
streams.action.hint.value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.actionService = {run, registerAction, registerActions, showHintFor, appearanceStreams, stateStreams, hint$};
|
||||
|
||||
context.services.action = context.actionService;
|
||||
}
|
||||
|
||||
|
||||
export interface ActionAppearanceStreams {
|
||||
[actionId: string]: StateStream<ActionAppearance>
|
||||
}
|
||||
|
||||
export interface ActionStateStreams {
|
||||
[actionId: string]: StateStream<ActionState>
|
||||
}
|
||||
|
||||
export interface ActionState {
|
||||
hint: string,
|
||||
enabled: boolean,
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
export interface HintRequest {
|
||||
actionId: string;
|
||||
x: number;
|
||||
y: number;
|
||||
requester: any;
|
||||
}
|
||||
|
||||
export interface Hint extends HintRequest {
|
||||
info: string;
|
||||
hint: string;
|
||||
}
|
||||
|
||||
export interface ActionAppearance {
|
||||
info: string,
|
||||
label: string,
|
||||
icon32?: string,
|
||||
icon96?: string,
|
||||
icon?: IconType
|
||||
}
|
||||
|
||||
export interface ActionDefinition<T = void> {
|
||||
id: string,
|
||||
appearance: ActionAppearance,
|
||||
invoke: (ApplicationContext, any) => void;
|
||||
update?: (ActionState, T, ApplicationContext) => void;
|
||||
listens?: (ApplicationContext) => Stream<T>;
|
||||
}
|
||||
|
||||
export interface ActionService {
|
||||
|
||||
run(id: string, data: any): void;
|
||||
registerAction(action: ActionDefinition): void;
|
||||
registerActions(actions: ActionDefinition[]): void;
|
||||
showHintFor(request: HintRequest): void;
|
||||
|
||||
appearanceStreams: ActionAppearanceStreams;
|
||||
stateStreams: ActionStateStreams;
|
||||
hint$: StateStream<Hint>;
|
||||
}
|
||||
|
||||
declare module 'context' {
|
||||
interface ApplicationContext {
|
||||
|
||||
actionService: ActionService;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue