CCM NG: PageModels Editor Alpha finished
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5670 8810af33-2d31-482b-a856-94f89814c4dfccm-docs
parent
1db7d23232
commit
f98d87ea49
|
|
@ -77,7 +77,7 @@ class CategoryTreeComponentEditorDialog
|
||||||
pageModelName={this.props.pageModelName}>
|
pageModelName={this.props.pageModelName}>
|
||||||
|
|
||||||
<label htmlFor={`${idPrefix}showFullTree`}>Show full tree?</label>
|
<label htmlFor={`${idPrefix}showFullTree`}>Show full tree?</label>
|
||||||
<input checked={this.props.component.showFullTree}
|
<input checked={this.state.showFullTree}
|
||||||
id={`${idPrefix}showFullTree`}
|
id={`${idPrefix}showFullTree`}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
type="checkbox" />
|
type="checkbox" />
|
||||||
|
|
@ -637,41 +637,45 @@ interface ItemListComponent extends ComponentModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentModelEditor.registerEditorComponents(
|
ComponentModelEditor.registerEditorComponents(
|
||||||
"org.librecms.pagemodel.CategoryTreeComponent",
|
|
||||||
{
|
{
|
||||||
|
componentTitle: "Category Tree",
|
||||||
|
componentType: "org.librecms.pagemodel.CategoryTreeComponent",
|
||||||
editorDialog:
|
editorDialog:
|
||||||
CategoryTreeComponentEditorDialog as typeof React.Component,
|
CategoryTreeComponentEditorDialog as typeof React.Component,
|
||||||
propertiesList:
|
propertiesList:
|
||||||
CategoryTreeComponentPropertiesList as typeof React.Component,
|
CategoryTreeComponentPropertiesList as typeof React.Component,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
ComponentModelEditor.registerEditorComponents(
|
ComponentModelEditor.registerEditorComponents(
|
||||||
"org.librecms.pagemodel.ItemListComponent",
|
|
||||||
{
|
{
|
||||||
|
componentTitle: "Item List",
|
||||||
|
componentType: "org.librecms.pagemodel.ItemListComponent",
|
||||||
editorDialog:
|
editorDialog:
|
||||||
ItemListComponentEditorDialog as typeof React.Component,
|
ItemListComponentEditorDialog as typeof React.Component,
|
||||||
propertiesList:
|
propertiesList:
|
||||||
ItemListComponentPropertiesList as typeof React.Component,
|
ItemListComponentPropertiesList as typeof React.Component,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
ComponentModelEditor.registerEditorComponents(
|
ComponentModelEditor.registerEditorComponents(
|
||||||
"org.librecms.pagemodel.FixedContentItemComponent",
|
|
||||||
{
|
{
|
||||||
|
componentTitle: "Fixed Content Item",
|
||||||
|
componentType: "org.librecms.pagemodel.FixedContentItemComponent",
|
||||||
editorDialog:
|
editorDialog:
|
||||||
FixedContentItemComponentEditorDialog as typeof React.Component,
|
FixedContentItemComponentEditorDialog as typeof React.Component,
|
||||||
propertiesList:
|
propertiesList:
|
||||||
FixedContentItemComponentPropertiesList as typeof React.Component,
|
FixedContentItemComponentPropertiesList as typeof React.Component,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
ComponentModelEditor.registerEditorComponents(
|
ComponentModelEditor.registerEditorComponents(
|
||||||
"org.librecms.pagemodel.GreetingItemComponent",
|
|
||||||
{
|
{
|
||||||
|
componentTitle: "Greeting Item",
|
||||||
|
componentType: "org.librecms.pagemodel.GreetingItemComponent",
|
||||||
editorDialog:
|
editorDialog:
|
||||||
GreetingItemComponentEditorDialog as typeof React.Component,
|
GreetingItemComponentEditorDialog as typeof React.Component,
|
||||||
propertiesList:
|
propertiesList:
|
||||||
GreetingItemComponentPropertiesList as typeof React.Component
|
GreetingItemComponentPropertiesList as typeof React.Component
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ public class CategoryTreeComponentJsonConverter
|
||||||
|
|
||||||
readBasePropertiesFromJson(jsonObject, categoryTree);
|
readBasePropertiesFromJson(jsonObject, categoryTree);
|
||||||
|
|
||||||
if (!jsonObject.isNull(SHOW_FULL_TREE)) {
|
if (jsonObject.containsKey(SHOW_FULL_TREE)) {
|
||||||
categoryTree.setShowFullTree(jsonObject.getBoolean(SHOW_FULL_TREE));
|
categoryTree.setShowFullTree(jsonObject.getBoolean(SHOW_FULL_TREE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,22 +83,25 @@ public abstract class AbstractComponentModelJsonConverter
|
||||||
Objects.requireNonNull(jsonObject);
|
Objects.requireNonNull(jsonObject);
|
||||||
Objects.requireNonNull(componentModel);
|
Objects.requireNonNull(componentModel);
|
||||||
|
|
||||||
componentModel.setComponentModelId(
|
//UUIDs are solely managed by the server!
|
||||||
jsonObject.getInt("componentModelId"));
|
// if (jsonObject.containsKey("uuid")) {
|
||||||
componentModel.setUuid(jsonObject.getString("uuid"));
|
// componentModel.setUuid(jsonObject.getString("uuid"));
|
||||||
componentModel.setModelUuid(jsonObject.getString("modelUuid"));
|
// }
|
||||||
|
// if (jsonObject.containsKey("modelUuid")) {
|
||||||
|
// componentModel.setModelUuid(jsonObject.getString("modelUuid"));
|
||||||
|
// }
|
||||||
componentModel.setKey(jsonObject.getString("key"));
|
componentModel.setKey(jsonObject.getString("key"));
|
||||||
|
|
||||||
if (jsonObject.getString("idAttribute") != null) {
|
if (jsonObject.getString("idAttribute", null) != null) {
|
||||||
componentModel.setIdAttribute(jsonObject.getString("idAttribute"));
|
componentModel.setIdAttribute(jsonObject.getString("idAttribute"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsonObject.getString("classAttribute") != null) {
|
if (jsonObject.getString("classAttribute", null) != null) {
|
||||||
componentModel
|
componentModel
|
||||||
.setClassAttribute(jsonObject.getString("classAttribute"));
|
.setClassAttribute(jsonObject.getString("classAttribute"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsonObject.getString("styleAttribute") != null) {
|
if (jsonObject.getString("styleAttribute", null) != null) {
|
||||||
componentModel
|
componentModel
|
||||||
.setStyleAttribute(jsonObject.getString("styleAttribute"));
|
.setStyleAttribute(jsonObject.getString("styleAttribute"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
package org.libreccm.pagemodel.rs;
|
package org.libreccm.pagemodel.rs;
|
||||||
|
|
||||||
import org.libreccm.core.CoreConstants;
|
import org.libreccm.core.CoreConstants;
|
||||||
import org.libreccm.core.UnexpectedErrorException;
|
|
||||||
import org.libreccm.pagemodel.ComponentModel;
|
import org.libreccm.pagemodel.ComponentModel;
|
||||||
import org.libreccm.pagemodel.ComponentModelJsonConverter;
|
import org.libreccm.pagemodel.ComponentModelJsonConverter;
|
||||||
import org.libreccm.pagemodel.ComponentModelRepository;
|
import org.libreccm.pagemodel.ComponentModelRepository;
|
||||||
|
|
@ -31,9 +30,6 @@ import org.libreccm.security.AuthorizationRequired;
|
||||||
import org.libreccm.security.RequiresPrivilege;
|
import org.libreccm.security.RequiresPrivilege;
|
||||||
import org.libreccm.web.CcmApplication;
|
import org.libreccm.web.CcmApplication;
|
||||||
|
|
||||||
import java.beans.BeanInfo;
|
|
||||||
import java.beans.IntrospectionException;
|
|
||||||
import java.beans.Introspector;
|
|
||||||
import java.beans.PropertyDescriptor;
|
import java.beans.PropertyDescriptor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
@ -53,7 +49,6 @@ import javax.json.Json;
|
||||||
import javax.json.JsonArray;
|
import javax.json.JsonArray;
|
||||||
import javax.json.JsonArrayBuilder;
|
import javax.json.JsonArrayBuilder;
|
||||||
import javax.json.JsonObject;
|
import javax.json.JsonObject;
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.json.JsonValue;
|
import javax.json.JsonValue;
|
||||||
import javax.transaction.Transactional;
|
import javax.transaction.Transactional;
|
||||||
import javax.ws.rs.BadRequestException;
|
import javax.ws.rs.BadRequestException;
|
||||||
|
|
@ -242,8 +237,10 @@ public class Components {
|
||||||
setComponentPropertiesFromJson(componentModelData, componentModel);
|
setComponentPropertiesFromJson(componentModelData, componentModel);
|
||||||
|
|
||||||
componentRepo.save(componentModel);
|
componentRepo.save(componentModel);
|
||||||
|
|
||||||
return mapComponentModelToJson(componentModel);
|
final ComponentModel saved = controller
|
||||||
|
.findComponentModel(app, pageModel, container, componentKey);
|
||||||
|
return mapComponentModelToJson(saved);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -427,7 +424,7 @@ public class Components {
|
||||||
try {
|
try {
|
||||||
final Class<?> clazz = Class.forName(type);
|
final Class<?> clazz = Class.forName(type);
|
||||||
|
|
||||||
if (clazz.isAssignableFrom(ComponentModel.class)) {
|
if (ComponentModel.class.isAssignableFrom(clazz)) {
|
||||||
return (Class<? extends ComponentModel>) clazz;
|
return (Class<? extends ComponentModel>) clazz;
|
||||||
} else {
|
} else {
|
||||||
throw new BadRequestException(String.format(
|
throw new BadRequestException(String.format(
|
||||||
|
|
|
||||||
|
|
@ -775,6 +775,8 @@ interface ContainerModelComponentProps {
|
||||||
|
|
||||||
interface ContainerModelComponentState {
|
interface ContainerModelComponentState {
|
||||||
|
|
||||||
|
addComponentOfType: string;
|
||||||
|
addComponentWithKey: string;
|
||||||
components: ComponentModel[];
|
components: ComponentModel[];
|
||||||
errorMessages: string[];
|
errorMessages: string[];
|
||||||
}
|
}
|
||||||
|
|
@ -789,9 +791,15 @@ class ContainerModelComponent
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
|
||||||
|
addComponentOfType: "",
|
||||||
|
addComponentWithKey: "",
|
||||||
components: [],
|
components: [],
|
||||||
errorMessages: [],
|
errorMessages: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.handleKeyChange = this.handleKeyChange.bind(this);
|
||||||
|
this.handleTypeSelectChange = this.handleTypeSelectChange.bind(this);
|
||||||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
|
|
@ -812,7 +820,41 @@ class ContainerModelComponent
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{this.state.errorMessages.length > 0
|
||||||
|
&& <div className="errorPanel">
|
||||||
|
<ul>
|
||||||
|
{this.state.errorMessages.map((msg, index) =>
|
||||||
|
<li key={index}>{msg}</li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<div className="components-list">
|
<div className="components-list">
|
||||||
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
<label htmlFor={`${this.props.container.key}_add_component_type`}>
|
||||||
|
Add component of type
|
||||||
|
</label>
|
||||||
|
<select id={`${this.props.container.key}_add_component_type`}
|
||||||
|
onChange={this.handleTypeSelectChange}>
|
||||||
|
<option value=""></option>
|
||||||
|
{ComponentModelEditor.getAvailableComponents()
|
||||||
|
.map((component) =>
|
||||||
|
<option key={component.componentType}
|
||||||
|
value={component.componentType}>
|
||||||
|
{component.componentTitle}
|
||||||
|
</option>
|
||||||
|
)}
|
||||||
|
</select>
|
||||||
|
<label htmlFor={`${this.props.container.key}_add_component_key`}>
|
||||||
|
with key
|
||||||
|
</label>
|
||||||
|
<input id={`${this.props.container.key}_add_component_key`}
|
||||||
|
onChange={this.handleKeyChange}
|
||||||
|
type="text" />
|
||||||
|
<button>
|
||||||
|
Add component
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
<ul>
|
<ul>
|
||||||
{this.state.components.map((component: ComponentModel) =>
|
{this.state.components.map((component: ComponentModel) =>
|
||||||
<ComponentModelEditor
|
<ComponentModelEditor
|
||||||
|
|
@ -829,6 +871,15 @@ class ContainerModelComponent
|
||||||
</li>;
|
</li>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private deleteContainer(
|
||||||
|
event: React.MouseEvent<HTMLButtonElement>,
|
||||||
|
containerKey: string): void {
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.props.deleteContainer(containerKey);
|
||||||
|
}
|
||||||
|
|
||||||
private fetchComponents(): void {
|
private fetchComponents(): void {
|
||||||
|
|
||||||
const componentsUrl = `${this.props.dispatcherPrefix}`
|
const componentsUrl = `${this.props.dispatcherPrefix}`
|
||||||
|
|
@ -893,13 +944,126 @@ class ContainerModelComponent
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private deleteContainer(
|
private handleKeyChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
event: React.MouseEvent<HTMLButtonElement>,
|
|
||||||
containerKey: string): void {
|
const target: HTMLInputElement = event.currentTarget;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
addComponentWithKey: target.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTypeSelectChange(
|
||||||
|
event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||||
|
|
||||||
|
const target: HTMLSelectElement = event.currentTarget;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
|
||||||
|
...this.state,
|
||||||
|
addComponentOfType: target.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSubmit(event: React.FormEvent<HTMLFormElement>): void {
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
this.props.deleteContainer(containerKey);
|
if (this.state.addComponentOfType === ""
|
||||||
|
|| this.state.addComponentWithKey === "") {
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
errorMessages: [
|
||||||
|
...this.state.errorMessages,
|
||||||
|
`Type and key are mandantory!`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers: Headers = new Headers();
|
||||||
|
headers.append("Content-Type", "application/json");
|
||||||
|
|
||||||
|
const init: RequestInit = {
|
||||||
|
|
||||||
|
body: JSON.stringify({
|
||||||
|
type: this.state.addComponentOfType,
|
||||||
|
key: this.state.addComponentWithKey,
|
||||||
|
}),
|
||||||
|
credentials: "same-origin",
|
||||||
|
headers,
|
||||||
|
method: "PUT",
|
||||||
|
}
|
||||||
|
|
||||||
|
const url: string = `${this.props.dispatcherPrefix}`
|
||||||
|
+ `/page-models/${this.props.ccmApplication}/`
|
||||||
|
+ `${this.props.pageModelName}`
|
||||||
|
+ `/containers/`
|
||||||
|
+ `${this.props.container.key}`
|
||||||
|
+ `/components/`
|
||||||
|
+ `${this.state.addComponentWithKey}`;
|
||||||
|
|
||||||
|
fetch(url, init)
|
||||||
|
.then((response: Response) => {
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
|
||||||
|
response
|
||||||
|
.json()
|
||||||
|
.then((newComponent) => {
|
||||||
|
|
||||||
|
const components = [
|
||||||
|
...this.state.components,
|
||||||
|
newComponent,
|
||||||
|
];
|
||||||
|
components.sort((component1, component2) => {
|
||||||
|
const key1: string = component1.key;
|
||||||
|
const key2: string = component2.key;
|
||||||
|
|
||||||
|
return key1.localeCompare(key2);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
addComponentWithKey: "",
|
||||||
|
addComponentOfType: "",
|
||||||
|
components,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
errorMessages: [
|
||||||
|
...this.state.errorMessages,
|
||||||
|
`Failed to parse response: `
|
||||||
|
+ `${error.message}`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
errorMessages: [
|
||||||
|
...this.state.errorMessages,
|
||||||
|
`Failed to add component to container`
|
||||||
|
+ `${response.status} ${response.statusText}`,
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
errorMessages: [
|
||||||
|
...this.state.errorMessages,
|
||||||
|
`Failed to add component to container`
|
||||||
|
+ ` ${this.props.container.key}: ${error.message}`
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1104,6 +1268,8 @@ class BasicComponentModelEditorDialog
|
||||||
|
|
||||||
interface EditorComponents {
|
interface EditorComponents {
|
||||||
|
|
||||||
|
componentType: string;
|
||||||
|
componentTitle: string;
|
||||||
editorDialog: typeof React.Component;
|
editorDialog: typeof React.Component;
|
||||||
propertiesList: typeof React.Component;
|
propertiesList: typeof React.Component;
|
||||||
}
|
}
|
||||||
|
|
@ -1120,10 +1286,30 @@ interface ComponentModelEditorProps {
|
||||||
class ComponentModelEditor
|
class ComponentModelEditor
|
||||||
extends React.Component<ComponentModelEditorProps, {}> {
|
extends React.Component<ComponentModelEditorProps, {}> {
|
||||||
|
|
||||||
public static registerEditorComponents(type: string,
|
public static getAvailableComponents(): EditorComponents[] {
|
||||||
components: EditorComponents) {
|
|
||||||
|
|
||||||
ComponentModelEditor.editorComponents.set(type, components);
|
const components: EditorComponents[] = [];
|
||||||
|
|
||||||
|
for(let editorComponents
|
||||||
|
of ComponentModelEditor.editorComponents.values()) {
|
||||||
|
|
||||||
|
components.push(editorComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
components.sort((component1, component2) => {
|
||||||
|
|
||||||
|
return component1
|
||||||
|
.componentTitle
|
||||||
|
.localeCompare(component2.componentTitle);
|
||||||
|
});
|
||||||
|
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static registerEditorComponents(components: EditorComponents) {
|
||||||
|
|
||||||
|
ComponentModelEditor.editorComponents.set(components.componentType,
|
||||||
|
components);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static editorComponents: Map<string, EditorComponents>
|
private static editorComponents: Map<string, EditorComponents>
|
||||||
|
|
@ -1162,6 +1348,8 @@ class ComponentModelEditor
|
||||||
.editorComponents.get(type) as EditorComponents;
|
.editorComponents.get(type) as EditorComponents;
|
||||||
} else {
|
} else {
|
||||||
const basicComponents: EditorComponents = {
|
const basicComponents: EditorComponents = {
|
||||||
|
componentType: type,
|
||||||
|
componentTitle: "",
|
||||||
editorDialog:
|
editorDialog:
|
||||||
BasicComponentModelEditorDialog as typeof React.Component,
|
BasicComponentModelEditorDialog as typeof React.Component,
|
||||||
propertiesList:
|
propertiesList:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue