CCM NG: Changed structure for PageModelEditor Components from Inhertience to Composition. Warning: ccm-cms-js is not yet compatible with these changes and fails to build.

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5616 8810af33-2d31-482b-a856-94f89814c4df
ccm-docs
jensp 2018-07-26 13:21:51 +00:00
parent e4e902ac6a
commit 81e92939e0
1 changed files with 478 additions and 181 deletions

View File

@ -9,10 +9,10 @@ import {
} from "./datatypes"; } from "./datatypes";
export { export {
AbstractComponentModelEditor, // OldAbstractComponentModelEditor,
ComponentModel, ComponentModel,
ComponentModelEditorProps, // OldComponentModelEditorProps,
ComponentModelEditorState, // OldComponentModelEditorState,
ComponentInfo, ComponentInfo,
PageModelEditor, PageModelEditor,
PageModelEditorState, PageModelEditorState,
@ -804,7 +804,13 @@ class ContainerModelComponent
<div className="components-list"> <div className="components-list">
<ul> <ul>
{this.state.components.map((component: ComponentModel) => {this.state.components.map((component: ComponentModel) =>
this.getComponentModelEditor(component), <ComponentModelEditor
ccmApplication={this.props.ccmApplication}
component={component}
containerKey={this.props.container.key}
dispatcherPrefix={this.props.dispatcherPrefix}
pageModelName={this.props.pageModelName} />
// this.getComponentModelEditor(component),
)} )}
</ul> </ul>
</div> </div>
@ -874,38 +880,38 @@ class ContainerModelComponent
}); });
}); });
} }
//
private getComponentModelEditor( // private getComponentModelEditor(
component: ComponentModel): React.ReactNode { // component: ComponentModel): React.ReactNode {
//
console.log(`Trying to find editor for ${component.type}`); // console.log(`Trying to find editor for ${component.type}`);
// console.log("Available editors:"); // // console.log("Available editors:");
// for(let key of Object.keys(PageModelEditor.getAvailableComponents())) { // // for(let key of Object.keys(PageModelEditor.getAvailableComponents())) {
// // //
// console.log(`${key} -> ${PageModelEditor.getAvailableComponents()[key]}`); // // console.log(`${key} -> ${PageModelEditor.getAvailableComponents()[key]}`);
// } // // }
//
if (PageModelEditor.getAvailableComponents()[component.type]) { // if (PageModelEditor.getAvailableComponents()[component.type]) {
console.log(`Found a editor generator for ${component.type} `); // console.log(`Found a editor generator for ${component.type} `);
return PageModelEditor // return PageModelEditor
.getAvailableComponents()[component.type]({ // .getAvailableComponents()[component.type]({
ccmApplication: this.props.ccmApplication, // ccmApplication: this.props.ccmApplication,
component, // component,
containerKey: this.props.container.key, // containerKey: this.props.container.key,
dispatcherPrefix: this.props.dispatcherPrefix, // dispatcherPrefix: this.props.dispatcherPrefix,
pageModelName: this.props.pageModelName, // pageModelName: this.props.pageModelName,
}); // });
} else { // } else {
console.warn(`No editor for type ${component.type} found. ` // console.warn(`No editor for type ${component.type} found. `
+ `Using default editor.`); // + `Using default editor.`);
return <DefaultComponentModelEditor // return <OldDefaultComponentModelEditor
ccmApplication={this.props.ccmApplication} // ccmApplication={this.props.ccmApplication}
component={component} // component={component}
containerKey={this.props.container.key} // containerKey={this.props.container.key}
dispatcherPrefix={this.props.dispatcherPrefix} // dispatcherPrefix={this.props.dispatcherPrefix}
pageModelName={this.props.pageModelName} />; // pageModelName={this.props.pageModelName} />;
} // }
} // }
private deleteContainer( private deleteContainer(
event: React.MouseEvent<HTMLButtonElement>, event: React.MouseEvent<HTMLButtonElement>,
@ -917,7 +923,12 @@ class ContainerModelComponent
} }
} }
interface ComponentModelEditorProps<C extends ComponentModel> { interface BasicComponentModelPropertiesListProps<C extends ComponentModel> {
component: C;
}
interface ComponentModelEditorDialogProps<C extends ComponentModel> {
ccmApplication: string; ccmApplication: string;
component: C; component: C;
@ -926,29 +937,54 @@ interface ComponentModelEditorProps<C extends ComponentModel> {
pageModelName: string; pageModelName: string;
} }
interface ComponentModelEditorState { interface BasicComponentModelEditorDialogProps<C extends ComponentModel>
extends ComponentModelEditorDialogProps<C> {
componentKey: string; getComponentModelProperties(): {[name: string]: any};
dialogExpanded: string;
dialogOpened: boolean | undefined;
errorMsg: string;
} }
abstract class AbstractComponentModelEditor< interface BasicComponentModelEditorDialogState {
C extends ComponentModel,
P extends ComponentModelEditorProps<C>,
S extends ComponentModelEditorState>
extends React.Component<P, S> { componentKey: string;
dialogOpen: boolean;
errorMsg: string | null;
}
constructor(props: ComponentModelEditorProps<C>) {
super(props as any);
class BasicComponentModelPropertiesList
extends React.Component<
BasicComponentModelPropertiesListProps<ComponentModel>, {}> {
// constructor(props: BasicComponentModelPropertiesListProps<ComponentModel>) {
//
// super(props);
// }
public render(): React.ReactNode {
return <dl>
<dt>Key</dt>
<dd>{this.props.component.key}</dd>
<dt>Type</dt>
<dd>{this.props.component.type}</dd>
{this.props.children}
</dl>
}
}
class BasicComponentModelEditorDialog
extends React.Component<
BasicComponentModelEditorDialogProps<ComponentModel>,
BasicComponentModelEditorDialogState> {
constructor(props: BasicComponentModelEditorDialogProps<ComponentModel>) {
super(props);
this.state = { this.state = {
...this.state as any, componentKey: this.props.component.key,
dialogExpanded: "dialogClosed", dialogOpen: false,
dialogOpened: false,
errorMsg: null, errorMsg: null,
}; };
@ -956,30 +992,41 @@ abstract class AbstractComponentModelEditor<
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
} }
public handleChange(event: React.ChangeEvent<HTMLElement>): void { public handleChange(event: React.ChangeEvent<HTMLInputElement>): void {
if (event.currentTarget.id === this.props.component.key + "_componentKey") { const target: HTMLInputElement = event.currentTarget;
const target: HTMLInputElement const idPrefix: string
= event.currentTarget as HTMLInputElement; = `${this.props.containerKey}_${this.props.component.key}_`;
this.setState({ switch(target.id) {
...this.state as any, case `${idPrefix}componentKey`: {
componentKey: target.value,
}); const componentKey: string = target.value;
this.setState({
...this.state,
componentKey,
});
break;
}
} }
} }
public handleSubmit(event: React.FormEvent<HTMLFormElement>): void { public handleSubmit(event: React.FormEvent<HTMLFormElement>): void {
const componentData: any = this.getComponentData(); const componentProperties: {[name: string]: any}
= this.props.getComponentModelProperties();
const data: {[name: string]: any} = {
...componentProperties,
componentKey: this.state.componentKey,
};
const headers: Headers = new Headers(); const headers: Headers = new Headers();
headers.append("Content-Type", "application/json"); headers.append("Content-Type", "application/json");
const init: RequestInit = { const init: RequestInit = {
body: JSON.stringify(componentData), body: JSON.stringify(data),
credentials: "same-origin", credentials: "same-origin",
headers, headers,
method: "PUT", method: "PUT",
@ -1012,136 +1059,386 @@ abstract class AbstractComponentModelEditor<
}); });
} }
public getComponentData(): any {
return {
key: this.state.componentKey,
};
}
public abstract renderPropertyList(): React.ReactFragment;
public abstract renderEditorDialog(): React.ReactFragment;
public render(): React.ReactNode { public render(): React.ReactNode {
return <li className="componentModelEditor"> const idPrefix
<dl> = `${this.props.containerKey}_${this.props.component.key}_`;
<dt>Key</dt>
<dd>{this.props.component.key}</dd> return <React.Fragment>
<dt>Type</dt> <button onClick={(event) => this.openCloseOnButton(event)}>
<dd>{this.props.component.type}</dd>
{this.renderPropertyList()}
</dl>
<button onClick={(event) => this.closeOnButton(event)}>
Edit Edit
</button> </button>
<dialog aria-labelledby={this.props.component.key <dialog aria-labelledby={`${idPrefix}editDialogHeading`}
+ "_editDialogHeading"} className=""
className={this.state.dialogExpanded} open={this.state.dialogOpen}
onKeyPress={(event) => this.closeOnEsc(event)} tabIndex={0}>
open={this.state.dialogOpened}
tabIndex={0}>
<button className="closeButton" <button className="closeButton"
onClick={(event) => this.closeOnButton(event)}> onClick={(event) => this.openCloseOnButton(event)}>
<span className="screenreader">Close</span> <span className="screenreader">Close</span>
<span className="fa fa-times-circle"></span> <span className="fa fa-times-circle"></span>
</button> </button>
<h1 id={this.props.component.key + "_editDialogHeading"}> <h1 id={`${idPrefix}editDialogHeading`}>
Edit component {this.props.component.key} Edit component {this.props.component.key}
</h1> </h1>
<form onSubmit={this.handleSubmit}> <form onSubmit={this.handleSubmit}>
<label htmlFor={this.props.component.key + "_componentKey"}>
Key
</label>
<input id={this.props.component.key + "_componentKey"}
onChange={this.handleChange}
required={true}
type="text"
value={this.state.componentKey} />
{this.renderEditorDialog()}
{this.state.errorMsg !== null && {this.state.errorMsg !== null &&
<div className="errorPanel"> <div className="errorPanel">
{this.state.errorMsg} {this.state.errorMsg}
</div> </div>
} }
<label htmlFor={`${idPrefix}componentKey`}>
Key
</label>
<input id={`${idPrefix}componentKey`}
onChange={this.handleChange}
required={true}
type="text"
value={this.state.componentKey} />
{this.props.children}
<div className="dialogButtonBar"> <div className="dialogButtonBar">
<button type="submit">Save</button> <button type="submit">Save</button>
<button onClick={(event) => this.closeOnButton(event)}> <button onClick={(event) => this.openCloseOnButton(event)}>
Cancel Cancel
</button> </button>
</div> </div>
</form> </form>
</dialog> </dialog>
</li>; </React.Fragment>;
} }
private closeOnButton(event: React.MouseEvent<HTMLButtonElement>): void { private openCloseOnButton(
event: React.MouseEvent<HTMLButtonElement>): void {
event.preventDefault(); event.preventDefault();
this.toggleEditorDialog(); this.toggleEditorDialog();
} }
private closeOnEsc(event: React.KeyboardEvent<HTMLElement>): void {
console.log(`Key press detected: ${event.key}`);
if (event.key === "27") {
this.toggleEditorDialog();
}
}
private toggleEditorDialog(): void { private toggleEditorDialog(): void {
this.setState({
if (this.state.dialogExpanded === "dialogExpanded") { ...this.state,
this.setState({ dialogOpen: !this.state.dialogOpen,
...this.state as any, });
dialogExpanded: "dialogClosed",
dialogOpened: false,
});
} else {
this.setState({
...this.state as any,
dialogExpanded: "dialogExpanded",
dialogOpened: true,
});
}
} }
} }
class DefaultComponentModelEditor interface EditorComponents {
extends AbstractComponentModelEditor<
ComponentModel,
ComponentModelEditorProps<ComponentModel>,
ComponentModelEditorState> {
constructor(props: ComponentModelEditorProps<ComponentModel>) { propertiesList: typeof React.Component;
editorDialog: typeof React.Component;
}
interface ComponentModelEditorProps {
ccmApplication: string;
component: ComponentModel;
containerKey: string;
dispatcherPrefix: string;
pageModelName: string;
}
class ComponentModelEditor
extends React.Component<ComponentModelEditorProps, {}> {
private editorComponents: {[type: string]: EditorComponents};
private propertiesListComponents: {[type: string]: typeof React.Component};
private editorDialogComponents: {[type: string]: typeof React.Component};
constructor(props: ComponentModelEditorProps) {
super(props); super(props);
this.setState({ this.editorComponents = {};
dialogExpanded: "dialogClosed", this.propertiesListComponents = {};
}); this.editorDialogComponents = {};
} }
public renderPropertyList(): React.ReactFragment { public registerEditorComponents(type: string,
components: EditorComponents) {
return <React.Fragment />; this.editorComponents = {
} ...this.editorComponents,
type: components,
};
public renderEditorDialog(): React.ReactFragment { this.propertiesListComponents = {
...this.propertiesListComponents,
type: components.propertiesList,
};
return <React.Fragment />; this.editorDialogComponents = {
...this.editorDialogComponents,
type: components.editorDialog,
}
} }
public render(): React.ReactNode { public render(): React.ReactNode {
return super.render();
const components: EditorComponents
= this.editorComponents[this.props.component.type];
const PropertiesList: typeof React.Component
= components.propertiesList;
const EditorDialog: typeof React.Component
= components.propertiesList;
return <li className="componentModelEditor">
<PropertiesList component={this.props.component} />
<EditorDialog
ccmApplication={this.props.ccmApplication}
component={this.props.component}
containerKey={this.props.containerKey}
dispatcherPrefix={this.props.dispatcherPrefix}
pageModelName={this.props.pageModelName} />
</li>
} }
private getEditorComponents(type: string): EditorComponents {
if (this.editorComponents.hasOwnProperty(type)) {
return this.editorComponents[type];
} else {
const basicComponents: EditorComponents = {
propertiesList:
BasicComponentModelPropertiesList as typeof React.Component,
editorDialog:
BasicComponentModelEditorDialog as typeof React.Component,
};
return basicComponents;
}
}
} }
// interface OldComponentModelEditorProps<C extends ComponentModel> {
//
// ccmApplication: string;
// component: C;
// containerKey: string;
// dispatcherPrefix: string;
// pageModelName: string;
// }
//
// interface OldComponentModelEditorState {
//
// componentKey: string;
// dialogExpanded: string;
// dialogOpened: boolean | undefined;
// errorMsg: string;
// }
//
// abstract class OldAbstractComponentModelEditor<
// C extends ComponentModel,
// P extends OldComponentModelEditorProps<C>,
// S extends OldComponentModelEditorState>
//
// extends React.Component<P, S> {
//
// constructor(props: OldComponentModelEditorProps<C>) {
//
// super(props as any);
//
// this.state = {
// ...this.state as any,
// dialogExpanded: "dialogClosed",
// dialogOpened: false,
// errorMsg: null,
// };
//
// this.handleChange = this.handleChange.bind(this);
// this.handleSubmit = this.handleSubmit.bind(this);
// }
//
// public handleChange(event: React.ChangeEvent<HTMLElement>): void {
//
// if (event.currentTarget.id === this.props.component.key + "_componentKey") {
//
// const target: HTMLInputElement
// = event.currentTarget as HTMLInputElement;
//
// this.setState({
// ...this.state as any,
// componentKey: target.value,
// });
// }
//
// }
//
// public handleSubmit(event: React.FormEvent<HTMLFormElement>): void {
//
// const componentData: any = this.getComponentData();
//
// const headers: Headers = new Headers();
// headers.append("Content-Type", "application/json");
//
// const init: RequestInit = {
// body: JSON.stringify(componentData),
// credentials: "same-origin",
// headers,
// method: "PUT",
// };
//
// const componentUrl = `${this.props.dispatcherPrefix}`
// + `/page-models/${this.props.ccmApplication}`
// + `/${this.props.pageModelName}`
// + `/containers/${this.props.containerKey}`
// + `/components/${this.state.componentKey}`;
//
// fetch(componentUrl, init)
// .then((response: Response) => {
// if (response.ok) {
// this.toggleEditorDialog();
// } else {
// this.setState({
// ...this.state as any,
// errorMsg: `Failed to update/create ComponentModel: `
// + ` ${response.status} ${response.statusText}`,
// });
// }
// })
// .catch((error) => {
// this.setState({
// ...this.state as any,
// errorMsg: `Failed to update/create ComponentModel: `
// + `${error.message}`,
// })
// });
// }
//
// public getComponentData(): any {
//
// return {
// key: this.state.componentKey,
// };
// }
//
// public abstract renderPropertyList(): React.ReactFragment;
//
// public abstract renderEditorDialog(): React.ReactFragment;
//
// public render(): React.ReactNode {
//
// return <li className="componentModelEditor">
// <dl>
// <dt>Key</dt>
// <dd>{this.props.component.key}</dd>
// <dt>Type</dt>
// <dd>{this.props.component.type}</dd>
// {this.renderPropertyList()}
// </dl>
// <button onClick={(event) => this.closeOnButton(event)}>
// Edit
// </button>
// <dialog aria-labelledby={this.props.component.key
// + "_editDialogHeading"}
// className={this.state.dialogExpanded}
// onKeyPress={(event) => this.closeOnEsc(event)}
// open={this.state.dialogOpened}
// tabIndex={0}>
// <button className="closeButton"
// onClick={(event) => this.closeOnButton(event)}>
// <span className="screenreader">Close</span>
// <span className="fa fa-times-circle"></span>
// </button>
// <h1 id={this.props.component.key + "_editDialogHeading"}>
// Edit component {this.props.component.key}
// </h1>
// <form onSubmit={this.handleSubmit}>
// <label htmlFor={this.props.component.key + "_componentKey"}>
// Key
// </label>
// <input id={this.props.component.key + "_componentKey"}
// onChange={this.handleChange}
// required={true}
// type="text"
// value={this.state.componentKey} />
// {this.renderEditorDialog()}
//
// {this.state.errorMsg !== null &&
// <div className="errorPanel">
// {this.state.errorMsg}
// </div>
// }
// <div className="dialogButtonBar">
// <button type="submit">Save</button>
// <button onClick={(event) => this.closeOnButton(event)}>
// Cancel
// </button>
// </div>
// </form>
// </dialog>
// </li>;
// }
//
// private closeOnButton(event: React.MouseEvent<HTMLButtonElement>): void {
//
// event.preventDefault();
//
// this.toggleEditorDialog();
// }
//
// private closeOnEsc(event: React.KeyboardEvent<HTMLElement>): void {
//
// console.log(`Key press detected: ${event.key}`);
//
// if (event.key === "27") {
// this.toggleEditorDialog();
// }
// }
//
// private toggleEditorDialog(): void {
//
// if (this.state.dialogExpanded === "dialogExpanded") {
// this.setState({
// ...this.state as any,
// dialogExpanded: "dialogClosed",
// dialogOpened: false,
// });
// } else {
// this.setState({
// ...this.state as any,
// dialogExpanded: "dialogExpanded",
// dialogOpened: true,
// });
// }
// }
// }
//
// class OldDefaultComponentModelEditor
// extends OldAbstractComponentModelEditor<
// ComponentModel,
// OldComponentModelEditorProps<ComponentModel>,
// OldComponentModelEditorState> {
//
// constructor(props: OldComponentModelEditorProps<ComponentModel>) {
//
// super(props);
//
// this.setState({
// dialogExpanded: "dialogClosed",
// });
// }
//
// public renderPropertyList(): React.ReactFragment {
//
// return <React.Fragment />;
// }
//
// public renderEditorDialog(): React.ReactFragment {
//
// return <React.Fragment />;
// }
//
// public render(): React.ReactNode {
// return super.render();
// }
//
// }
// interface PageModelEditorProps { // interface PageModelEditorProps {
// //
// } // }
@ -1169,47 +1466,47 @@ interface ComponentInfo {
class PageModelEditor class PageModelEditor
extends React.Component<{}, PageModelEditorState> { extends React.Component<{}, PageModelEditorState> {
public static getAvailableComponents(): { // public static getAvailableComponents(): {
[type: string]: (props: ComponentModelEditorProps<ComponentModel>) // [type: string]: (props: OldComponentModelEditorProps<ComponentModel>)
=> React.ReactFragment} { // => React.ReactFragment} {
//
// console.log("Available editors:");
// for(let key of Object.keys(PageModelEditor.componentModelEditors)) {
//
// console.log(`${key} -> ${PageModelEditor.componentModelEditors}`);
// }
//
// return {
// ...PageModelEditor.componentModelEditors,
// };
// }
console.log("Available editors:"); // public static registerComponentModelEditor(
for(let key of Object.keys(PageModelEditor.componentModelEditors)) { // type: string,
// generator: ((props: OldComponentModelEditorProps<ComponentModel>)
console.log(`${key} -> ${PageModelEditor.componentModelEditors}`); // => React.ReactFragment)): void {
} //
// console.log(`Registering editor for type ${type}...`);
return { //
...PageModelEditor.componentModelEditors, // const editors = {
}; // ...PageModelEditor.componentModelEditors,
} // };
//
public static registerComponentModelEditor( // editors[type] = generator;
type: string, // PageModelEditor.componentModelEditors = editors;
generator: ((props: ComponentModelEditorProps<ComponentModel>) //
=> React.ReactFragment)): void { // console.log("The following editors are now available:");
// for(let key of Object.keys(PageModelEditor.componentModelEditors)) {
console.log(`Registering editor for type ${type}...`); //
// console.log(`${key} -> ${PageModelEditor.componentModelEditors}`);
const editors = { // }
...PageModelEditor.componentModelEditors, // console.log("-----------------------");
}; // }
//
editors[type] = generator; // private static componentModelEditors: {
PageModelEditor.componentModelEditors = editors; // [type: string]: <C extends ComponentModel>(
// props: OldComponentModelEditorProps<C>) => React.ReactFragment;
console.log("The following editors are now available:"); // };
for(let key of Object.keys(PageModelEditor.componentModelEditors)) {
console.log(`${key} -> ${PageModelEditor.componentModelEditors}`);
}
console.log("-----------------------");
}
private static componentModelEditors: {
[type: string]: <C extends ComponentModel>(
props: ComponentModelEditorProps<C>) => React.ReactFragment;
};
private static getDispatcherPrefix(): string { private static getDispatcherPrefix(): string {