From b7771f9f7ed1b6548be12f14034257139a93a580 Mon Sep 17 00:00:00 2001 From: activey Date: Tue, 8 Nov 2016 19:00:24 +0100 Subject: [PATCH] #8 - first version of modal component with form inside! :D all stuff finally migrated onto vue.js, lots of changes, new stuff introduced, yummy ;} --- .../java/org/licket/core/id/CompositeId.java | 10 + .../demo/licket/LicketConfiguration.java | 18 +- .../org/licket/demo/view/AddContactForm.java | 2 +- .../org/licket/demo/view/AddContactPanel.java | 91 ++++++ .../org/licket/demo/view/ContactsAppRoot.java | 18 +- .../org/licket/demo/view/ContactsPanel.java | 26 +- .../modal/AddContactFormModalSection.java | 18 ++ .../org/licket/demo/view/AddContactForm.html | 17 - .../org/licket/demo/view/ContactsAppRoot.html | 7 +- .../modal/AddContactFormModalSection.html | 19 ++ .../org/licket/surface/SurfaceContext.java | 26 +- .../surface/SurfaceIntegrationTest.java | 24 -- .../licket/core/resource/ResourceStorage.java | 3 + .../core/view/AbstractLicketComponent.java | 300 +++++++++--------- .../AbstractLicketMonoContainer.java | 36 +-- .../AbstractLicketMultiContainer.java | 6 +- .../view/container/LicketInlineContainer.java | 16 + .../core/view/form/AbstractLicketForm.java | 10 + .../licket/core/view/form/LicketInput.java | 3 +- .../view/hippo/ComponentModelDecorator.java | 14 +- .../view/link/ComponentActionCallback.java | 2 +- .../modal/AbstractSemanticUIModal.java | 22 +- .../component/modal/ModalSection.java | 4 +- .../modal/AbstractSemanticUIModal.html | 10 +- .../resource/SpringResourceStorage.java | 117 ++++--- .../element/html/DefaultHtmlElement.java | 71 +++-- .../compiler/ComponentTemplateCompiler.java | 41 +++ .../spring/web/LicketRootController.java | 62 ++-- 28 files changed, 609 insertions(+), 384 deletions(-) create mode 100644 licket-demo/src/main/java/org/licket/demo/view/AddContactPanel.java create mode 100644 licket-demo/src/main/java/org/licket/demo/view/modal/AddContactFormModalSection.java delete mode 100644 licket-demo/src/main/resources/org/licket/demo/view/AddContactForm.html create mode 100644 licket-demo/src/main/resources/org/licket/demo/view/modal/AddContactFormModalSection.html delete mode 100644 licket-framework-surface/src/test/java/org/licket/surface/SurfaceIntegrationTest.java create mode 100644 licket-framework/src/main/java/org/licket/core/view/container/LicketInlineContainer.java create mode 100644 licket-spring-autoconfigure/src/main/java/org/licket/spring/surface/element/html/compiler/ComponentTemplateCompiler.java diff --git a/licket-common/src/main/java/org/licket/core/id/CompositeId.java b/licket-common/src/main/java/org/licket/core/id/CompositeId.java index 6ea6453..0322d84 100644 --- a/licket-common/src/main/java/org/licket/core/id/CompositeId.java +++ b/licket-common/src/main/java/org/licket/core/id/CompositeId.java @@ -9,6 +9,9 @@ import com.google.common.base.CaseFormat; import com.google.common.base.Splitter; +import com.google.common.collect.ObjectArrays; + +import java.util.Arrays; /** * @author activey @@ -57,4 +60,11 @@ public void forward() { public String current() { return idParts[index]; } + + public final CompositeId join(CompositeId compositeId) { + if (compositeId == null) { + return new CompositeId(idParts); + } + return new CompositeId(concat(idParts, compositeId.idParts, String.class)); + } } diff --git a/licket-demo/src/main/java/org/licket/demo/licket/LicketConfiguration.java b/licket-demo/src/main/java/org/licket/demo/licket/LicketConfiguration.java index 478f528..3e078be 100644 --- a/licket-demo/src/main/java/org/licket/demo/licket/LicketConfiguration.java +++ b/licket-demo/src/main/java/org/licket/demo/licket/LicketConfiguration.java @@ -1,26 +1,40 @@ package org.licket.demo.licket; import org.licket.core.module.application.LicketComponentModelReloader; +import org.licket.demo.view.AddContactPanel; import org.licket.demo.view.ContactsAppRoot; import org.licket.demo.view.ContactsPanel; import org.licket.semantic.SemanticUIPluginConfiguration; +import org.licket.semantic.component.modal.ModalSettings; +import org.licket.semantic.component.modal.ModalSettingsBuilder; import org.licket.spring.annotation.LicketComponent; import org.licket.spring.annotation.LicketRootContainer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import static org.licket.semantic.component.modal.ModalSettingsBuilder.builder; + @Configuration @Import(SemanticUIPluginConfiguration.class) public class LicketConfiguration { @LicketRootContainer public ContactsAppRoot root(@Autowired LicketComponentModelReloader modelReloader) { - return new ContactsAppRoot("contacts-page", contactsPanel(modelReloader), modelReloader); + return new ContactsAppRoot("contacts-page", modelReloader); } @LicketComponent - public ContactsPanel contactsPanel(LicketComponentModelReloader modelReloader) { + public ContactsPanel contactsPanel(@Autowired LicketComponentModelReloader modelReloader) { return new ContactsPanel("contacts-panel", modelReloader); } + + private ModalSettings modalDialogSettings() { + return builder().build(); + } + + @LicketComponent + public AddContactPanel addContactPanel(@Autowired LicketComponentModelReloader modelReloader) { + return new AddContactPanel("add-contact-panel", modelReloader, modalDialogSettings()); + } } diff --git a/licket-demo/src/main/java/org/licket/demo/view/AddContactForm.java b/licket-demo/src/main/java/org/licket/demo/view/AddContactForm.java index fdd669b..32b23be 100644 --- a/licket-demo/src/main/java/org/licket/demo/view/AddContactForm.java +++ b/licket-demo/src/main/java/org/licket/demo/view/AddContactForm.java @@ -22,7 +22,7 @@ public class AddContactForm extends AbstractLicketForm { public AddContactForm(String id, ContactsService contactsService, LicketRemote remoteCommunication, LicketComponentModelReloader modelReloader) { - super(id, Contact.class, ofModelObject(new Contact()), fromComponentClass(AddContactForm.class), remoteCommunication, modelReloader); + super(id, Contact.class, ofModelObject(new Contact()), internalTemplateView(), remoteCommunication, modelReloader); this.contactsService = checkNotNull(contactsService, "Contacts service has to be not null!"); add(new LicketInput("name")); diff --git a/licket-demo/src/main/java/org/licket/demo/view/AddContactPanel.java b/licket-demo/src/main/java/org/licket/demo/view/AddContactPanel.java new file mode 100644 index 0000000..184cbd4 --- /dev/null +++ b/licket-demo/src/main/java/org/licket/demo/view/AddContactPanel.java @@ -0,0 +1,91 @@ +package org.licket.demo.view; + +import org.licket.core.module.application.LicketComponentModelReloader; +import org.licket.core.module.application.LicketRemote; +import org.licket.core.view.container.AbstractLicketMultiContainer; +import org.licket.core.view.container.LicketInlineContainer; +import org.licket.core.view.link.AbstractLicketLink; +import org.licket.core.view.link.ComponentActionCallback; +import org.licket.core.view.link.ComponentFunctionCallback; +import org.licket.demo.model.Contact; +import org.licket.demo.service.ContactsService; +import org.licket.demo.view.modal.AddContactFormModalSection; +import org.licket.semantic.component.modal.AbstractSemanticUIModal; +import org.licket.semantic.component.modal.ModalSection; +import org.licket.semantic.component.modal.ModalSettings; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import static org.licket.core.model.LicketComponentModel.emptyComponentModel; +import static org.licket.core.view.LicketComponentView.internalTemplateView; + +/** + * @author grabslu + */ +public class AddContactPanel extends AbstractLicketMultiContainer { + + @Autowired + private ContactsService contactsService; + + @Autowired + private LicketRemote remoteCommunication; + + private final ModalSettings modalSettings; + private AbstractSemanticUIModal modal; + private BiConsumer callback; + + public AddContactPanel(String id, LicketComponentModelReloader modelReloader, ModalSettings modalSettings) { + super(id, Void.class, emptyComponentModel(), internalTemplateView(), modelReloader); + this.modalSettings = modalSettings; + } + + public final void onContactAdded(BiConsumer callback) { + this.callback = callback; + } + + @Override + protected void onInitializeContainer() { + add(new AbstractLicketLink("add-contact") { + @Override + protected void onClick(ComponentFunctionCallback callback) { + callback.call(modal.callShow(this)); + } + }); + + add(modal = new AbstractSemanticUIModal("form-modal", modalSettings, modelReloader()) { + + @Override + protected void onInitializeBody(ModalSection bodySection, String contentId) { + bodySection.add(new AddContactFormModalSection(contentId, modelReloader()) { + @Override + protected void onInitializeContainer() { + add(new AddContactForm("new-contact-form", contactsService, remoteCommunication, modelReloader()) { + + @Override + protected void onAfterSubmit(ComponentActionCallback componentActionCallback) { + if (callback != null) { + callback.accept(getComponentModel().get(), componentActionCallback); + } + onAfterContactAdded(componentActionCallback); + } + }); + } + }); + } + + @Override + protected void onInitializeActions(ModalSection content, String contentId) { + content.add(new LicketInlineContainer(contentId, Void.class, modelReloader()) { + @Override + protected void onInitializeContainer() { + } + }); + } + }); + + } + + protected void onAfterContactAdded(ComponentActionCallback componentActionCallback) {} +} diff --git a/licket-demo/src/main/java/org/licket/demo/view/ContactsAppRoot.java b/licket-demo/src/main/java/org/licket/demo/view/ContactsAppRoot.java index 46ec6ae..e474aac 100644 --- a/licket-demo/src/main/java/org/licket/demo/view/ContactsAppRoot.java +++ b/licket-demo/src/main/java/org/licket/demo/view/ContactsAppRoot.java @@ -5,13 +5,27 @@ import org.licket.core.module.application.LicketComponentModelReloader; import org.licket.core.view.container.AbstractLicketMultiContainer; -import org.licket.core.view.container.LicketComponentContainer; +import org.springframework.beans.factory.annotation.Autowired; public class ContactsAppRoot extends AbstractLicketMultiContainer { - public ContactsAppRoot(String id, LicketComponentContainer contactsPanel, LicketComponentModelReloader modelReloader) { + @Autowired + private ContactsPanel contactsPanel; + + @Autowired + private AddContactPanel addContactPanel; + + public ContactsAppRoot(String id, LicketComponentModelReloader modelReloader) { super(id, Void.class, emptyComponentModel(), fromComponentClass(ContactsAppRoot.class), modelReloader); + } + @Override + protected void onInitializeContainer() { + addContactPanel.onContactAdded((contact, componentActionCallback) -> { + contactsPanel.reloadList(); + componentActionCallback.reload(contactsPanel); + }); add(contactsPanel); + add(addContactPanel); } } diff --git a/licket-demo/src/main/java/org/licket/demo/view/ContactsPanel.java b/licket-demo/src/main/java/org/licket/demo/view/ContactsPanel.java index 491b799..89fec09 100644 --- a/licket-demo/src/main/java/org/licket/demo/view/ContactsPanel.java +++ b/licket-demo/src/main/java/org/licket/demo/view/ContactsPanel.java @@ -9,12 +9,14 @@ import org.licket.core.module.application.LicketComponentModelReloader; import org.licket.core.module.application.LicketRemote; import org.licket.core.view.container.AbstractLicketMultiContainer; +import org.licket.core.view.container.LicketInlineContainer; import org.licket.core.view.link.AbstractLicketActionLink; import org.licket.core.view.link.AbstractLicketLink; import org.licket.core.view.link.ComponentActionCallback; import org.licket.core.view.link.ComponentFunctionCallback; import org.licket.demo.model.Contacts; import org.licket.demo.service.ContactsService; +import org.licket.demo.view.modal.AddContactFormModalSection; import org.licket.semantic.component.modal.AbstractSemanticUIModal; import org.licket.semantic.component.modal.ModalSection; import org.licket.semantic.component.modal.ModalSettings; @@ -32,7 +34,6 @@ public class ContactsPanel extends AbstractLicketMultiContainer { private LicketRemote remoteCommunication; private LicketComponentModelReloader modelReloader; - private AbstractSemanticUIModal modal; public ContactsPanel(String id, LicketComponentModelReloader modelReloader) { super(id, Contacts.class, emptyComponentModel(), internalTemplateView(), modelReloader); @@ -41,29 +42,6 @@ public ContactsPanel(String id, LicketComponentModelReloader modelReloader) { @Override protected void onInitializeContainer() { - add(modal = new AbstractSemanticUIModal("form-modal", modalSettings(), modelReloader) { - - @Override - protected void onInitializeBody(ModalSection bodySection, String contentId) { - bodySection.add(new AddContactForm(contentId, contactsService, remoteCommunication, modelReloader) { - - @Override - protected void onAfterSubmit(ComponentActionCallback componentActionCallback) { - reloadList(); - - componentActionCallback.reload(ContactsPanel.this); - } - }); - } - }); - - add(new AbstractLicketLink("add-contact") { - @Override - protected void onClick(ComponentFunctionCallback callback) { - callback.call(modal.callShow(this)); - } - }); - add(new ContactsList("contact", new LicketComponentModel("contacts"), modelReloader)); add(new AbstractLicketActionLink("reload", remoteCommunication, modelReloader) { diff --git a/licket-demo/src/main/java/org/licket/demo/view/modal/AddContactFormModalSection.java b/licket-demo/src/main/java/org/licket/demo/view/modal/AddContactFormModalSection.java new file mode 100644 index 0000000..3282c1f --- /dev/null +++ b/licket-demo/src/main/java/org/licket/demo/view/modal/AddContactFormModalSection.java @@ -0,0 +1,18 @@ +package org.licket.demo.view.modal; + +import org.licket.core.module.application.LicketComponentModelReloader; +import org.licket.core.view.container.AbstractLicketMonoContainer; + +import static org.licket.core.model.LicketComponentModel.emptyComponentModel; +import static org.licket.core.view.LicketComponentView.fromComponentClass; + +/** + * @author grabslu + */ +public class AddContactFormModalSection extends AbstractLicketMonoContainer { + + public AddContactFormModalSection(String id, LicketComponentModelReloader modelReloader) { + super(id, Void.class, emptyComponentModel(), + fromComponentClass(AddContactFormModalSection.class), modelReloader); + } +} diff --git a/licket-demo/src/main/resources/org/licket/demo/view/AddContactForm.html b/licket-demo/src/main/resources/org/licket/demo/view/AddContactForm.html deleted file mode 100644 index 6e784e0..0000000 --- a/licket-demo/src/main/resources/org/licket/demo/view/AddContactForm.html +++ /dev/null @@ -1,17 +0,0 @@ -
-
-
- - -
- -
- - -
-
- -
- Add one -
-
\ No newline at end of file diff --git a/licket-demo/src/main/resources/org/licket/demo/view/ContactsAppRoot.html b/licket-demo/src/main/resources/org/licket/demo/view/ContactsAppRoot.html index 76e194a..62c8fde 100644 --- a/licket-demo/src/main/resources/org/licket/demo/view/ContactsAppRoot.html +++ b/licket-demo/src/main/resources/org/licket/demo/view/ContactsAppRoot.html @@ -7,13 +7,14 @@

Contacts list

-
-
- +
Add contact
+
+
+
diff --git a/licket-demo/src/main/resources/org/licket/demo/view/modal/AddContactFormModalSection.html b/licket-demo/src/main/resources/org/licket/demo/view/modal/AddContactFormModalSection.html new file mode 100644 index 0000000..187b62f --- /dev/null +++ b/licket-demo/src/main/resources/org/licket/demo/view/modal/AddContactFormModalSection.html @@ -0,0 +1,19 @@ +
+
+
+
+ + +
+ +
+ + +
+
+ +
+ Add one +
+
+
\ No newline at end of file diff --git a/licket-framework-surface/src/main/java/org/licket/surface/SurfaceContext.java b/licket-framework-surface/src/main/java/org/licket/surface/SurfaceContext.java index ea2bcdf..68f8fcd 100644 --- a/licket-framework-surface/src/main/java/org/licket/surface/SurfaceContext.java +++ b/licket-framework-surface/src/main/java/org/licket/surface/SurfaceContext.java @@ -4,6 +4,7 @@ import java.io.InputStream; import java.io.OutputStream; +import org.licket.core.id.CompositeId; import org.licket.surface.tag.ElementFactories; import org.licket.xml.Builder; import org.licket.xml.ParsingException; @@ -11,7 +12,6 @@ import static org.licket.surface.SurfaceProcessingException.contentParsingException; import static org.licket.surface.SurfaceProcessingException.ioException; -import static org.licket.surface.tag.ElementFactories.serviceLoaderFactories; /** * @@ -20,17 +20,19 @@ public class SurfaceContext { private final ElementFactories elementFactories; + private final CompositeId parentSurfaceContextRootId; private boolean skipComments; - public SurfaceContext() { - this(serviceLoaderFactories()); + public SurfaceContext(ElementFactories elementFactories, CompositeId parentSurfaceContextRootId) { + this.elementFactories = elementFactories; + this.parentSurfaceContextRootId = parentSurfaceContextRootId; } public SurfaceContext(ElementFactories elementFactories) { - this.elementFactories = elementFactories; + this(elementFactories, null); } - public void processTemplateContent(InputStream templateContent, OutputStream output) { + public final void processTemplateContent(InputStream templateContent, OutputStream output) { Builder builder = new Builder(new SurfaceNodeFactory(this, elementFactories)); try { Document document = builder.build(templateContent); @@ -42,11 +44,19 @@ public void processTemplateContent(InputStream templateContent, OutputStream out } } - public boolean isSkipComments() { + public final boolean isSubContext() { + return parentSurfaceContextRootId != null; + } + + public final boolean isSkipComments() { return skipComments; } - public void setSkipComments(boolean skipComments) { - this.skipComments = skipComments; + public final CompositeId getParentSurfaceContextRootId() { + return parentSurfaceContextRootId; + } + + public final SurfaceContext subContext(CompositeId parentContextId) { + return new SurfaceContext(elementFactories, parentContextId); } } diff --git a/licket-framework-surface/src/test/java/org/licket/surface/SurfaceIntegrationTest.java b/licket-framework-surface/src/test/java/org/licket/surface/SurfaceIntegrationTest.java deleted file mode 100644 index c77bffb..0000000 --- a/licket-framework-surface/src/test/java/org/licket/surface/SurfaceIntegrationTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.licket.surface; - -import org.junit.Ignore; -import org.junit.Test; - -import java.io.InputStream; - -/** - * @author activey - */ -@Ignore -public class SurfaceIntegrationTest { - - @Test - public void test() throws Exception { - // given - SurfaceContext surfaceContext = new SurfaceContext(); - surfaceContext.processTemplateContent(readTemplate("TestPage.html"), System.out); - } - - private InputStream readTemplate(String templateLocation) { - return SurfaceIntegrationTest.class.getClassLoader().getResourceAsStream(templateLocation); - } -} diff --git a/licket-framework/src/main/java/org/licket/core/resource/ResourceStorage.java b/licket-framework/src/main/java/org/licket/core/resource/ResourceStorage.java index 44f3095..8adab6f 100644 --- a/licket-framework/src/main/java/org/licket/core/resource/ResourceStorage.java +++ b/licket-framework/src/main/java/org/licket/core/resource/ResourceStorage.java @@ -1,5 +1,6 @@ package org.licket.core.resource; +import java.io.ByteArrayOutputStream; import java.util.Optional; import java.util.stream.Stream; @@ -20,4 +21,6 @@ public interface ResourceStorage { Stream getStylesheetResources(); String getResourceUrl(Resource resource); + + void replaceResourceContent(Resource resource, byte[] newResourceContent); } diff --git a/licket-framework/src/main/java/org/licket/core/view/AbstractLicketComponent.java b/licket-framework/src/main/java/org/licket/core/view/AbstractLicketComponent.java index 677c9bd..ce2981d 100644 --- a/licket-framework/src/main/java/org/licket/core/view/AbstractLicketComponent.java +++ b/licket-framework/src/main/java/org/licket/core/view/AbstractLicketComponent.java @@ -1,5 +1,6 @@ package org.licket.core.view; +import static com.google.common.base.Preconditions.checkNotNull; import static java.util.Optional.empty; import static java.util.Optional.of; import static org.licket.core.id.CompositeId.fromStringValue; @@ -23,151 +24,156 @@ public abstract class AbstractLicketComponent implements LicketComponent { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLicketComponent.class); - - private String id; - private Class modelClass; - private LicketComponentModel componentModel; - private LicketComponentView view; - private LicketComponent parent; - private boolean initialized; - - public AbstractLicketComponent(String id, Class modelClass) { - this(id, modelClass, emptyComponentModel(), noView()); - } - - public AbstractLicketComponent(String id, Class modelClass, LicketComponentModel componentModel) { - this(id, modelClass, componentModel, noView()); - } - - public AbstractLicketComponent(String id, Class modelClass, LicketComponentModel componentModel, - LicketComponentView view) { - this.id = id; - this.modelClass = modelClass; - this.componentModel = componentModel; - this.view = view; - } - - @PostConstruct - public final void initialize() { - if (initialized) { - return; - } - LOGGER.debug("Initializing component: {}", getCompositeId().getValue()); - onInitialize(); - this.initialized = true; - } - - protected void onInitialize() {} - - @Override - public final LicketComponentModel getComponentModel() { - return componentModel; - } - - @Override - public final void setComponentModel(LicketComponentModel componentModel) { - this.componentModel = componentModel; - } - - @Override - public final Class getComponentModelClass() { - return modelClass; - } - - @Override - public final void setComponentModelObject(T componentModelObject) { - componentModel.set(componentModelObject); - } - - @Override - public final String getId() { - return id; - } - - public final CompositeId getCompositeId() { - Optional> parentOptional = traverseUp(component -> true); - if (!parentOptional.isPresent()) { - return fromStringValue(id); - } - return fromStringValueWithAdditionalParts(parentOptional.get().getCompositeId().getValue(), id); - } - - public final LicketComponent getParent() { - return parent; - } - - @Override - public final void setParent(LicketComponent parent) { - this.parent = parent; - } - - public final Optional> traverseUp(Predicate> componentTraverser) { - if (parent == null) { - return empty(); - } - if (componentTraverser.test(parent)) { - return of(parent); - } - return parent.traverseUp(componentTraverser); - } - - @Override - public NameBuilder vueName() { - return name(getCompositeId().getNormalizedValue()); - } - - @Override - public final LicketComponentView getView() { - return view; - } - - public final void render(ComponentRenderingContext renderingContext) { - LOGGER.debug("Rendering component: {}", getCompositeId().getValue()); - onBeforeRender(renderingContext); - doRender(renderingContext); - } - - protected void onBeforeRender(ComponentRenderingContext renderingContext) {} - - private void doRender(ComponentRenderingContext renderingContext) { - if (!getView().hasTemplate()) { - LOGGER.trace("No separate view for component component: [{}], using original element content.", getId()); - return; - } - renderingContext.onSurfaceElement(element -> { - setTemplate(renderingContext, element); - }); - } - - private void setTemplate(ComponentRenderingContext renderingContext, SurfaceElement element) { - try { - if (getView().isTemplateExternal()) { - renderingContext - .renderResource(new ProxyResource(getView().viewResource(), getCompositeId().getValue())); - } else { - renderingContext.renderResource( - new ByteArrayResource(getCompositeId().getValue(), "text/html", element.toBytes())); - } - onElementReplaced(replaceElement(element)); - } catch (XMLStreamException e) { - LOGGER.error("An error occured while rendering component.", e); - return; - } - } - - protected void onElementReplaced(SurfaceElement surfaceElement) {} - - private SurfaceElement replaceElement(SurfaceElement element) { - SurfaceElement componentElement = new SurfaceElement(getId(), element.getNamespace()); - setRefAttribute(componentElement); - element.replaceWith(componentElement); - element.detach(); - - return componentElement; - } - - private void setRefAttribute(SurfaceElement element) { - element.addAttribute("ref", getId()); - } + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLicketComponent.class); + + private String id; + private Class modelClass; + private LicketComponentModel componentModel; + private LicketComponentView view; + private LicketComponent parent; + private boolean initialized; + + public AbstractLicketComponent(String id, Class modelClass) { + this(id, modelClass, emptyComponentModel(), noView()); + } + + public AbstractLicketComponent(String id, Class modelClass, + LicketComponentModel componentModel) { + this(id, modelClass, componentModel, noView()); + } + + public AbstractLicketComponent(String id, Class modelClass, + LicketComponentModel componentModel, LicketComponentView view) { + this.id = checkNotNull(id, "Component ID can not be null!"); + this.modelClass = checkNotNull(modelClass, "Model class can not be null!"); + this.componentModel = checkNotNull(componentModel, + "Component model can not be null! Use emptyComponentModel() instead."); + this.view = checkNotNull(view, "Component view can not be null!"); + } + + @PostConstruct + public final void initialize() { + if (initialized) { + return; + } + LOGGER.debug("Initializing component: {}", getCompositeId().getValue()); + onInitialize(); + this.initialized = true; + } + + protected void onInitialize() {} + + @Override + public final LicketComponentModel getComponentModel() { + return componentModel; + } + + @Override + public final void setComponentModel(LicketComponentModel componentModel) { + this.componentModel = componentModel; + } + + @Override + public final Class getComponentModelClass() { + return modelClass; + } + + @Override + public final void setComponentModelObject(T componentModelObject) { + componentModel.set(componentModelObject); + } + + @Override + public final String getId() { + return id; + } + + public final CompositeId getCompositeId() { + Optional> parentOptional = traverseUp(component -> true); + if (!parentOptional.isPresent()) { + return fromStringValue(id); + } + return fromStringValueWithAdditionalParts(parentOptional.get().getCompositeId().getValue(), id); + } + + public final LicketComponent getParent() { + return parent; + } + + @Override + public final void setParent(LicketComponent parent) { + this.parent = parent; + } + + public final Optional> traverseUp( + Predicate> componentTraverser) { + if (parent == null) { + return empty(); + } + if (componentTraverser.test(parent)) { + return of(parent); + } + return parent.traverseUp(componentTraverser); + } + + @Override + public NameBuilder vueName() { + return name(getCompositeId().getNormalizedValue()); + } + + @Override + public final LicketComponentView getView() { + return view; + } + + public final void render(ComponentRenderingContext renderingContext) { + LOGGER.debug("Rendering component: {}", getCompositeId().getValue()); + onBeforeRender(renderingContext); + doRender(renderingContext); + } + + protected void onBeforeRender(ComponentRenderingContext renderingContext) {} + + private void doRender(ComponentRenderingContext renderingContext) { + if (!getView().hasTemplate()) { + LOGGER.trace( + "No separate view for component component: [{}], using original element content.", + getId()); + return; + } + renderingContext.onSurfaceElement(element -> { + setTemplate(renderingContext, element); + }); + } + + private void setTemplate(ComponentRenderingContext renderingContext, SurfaceElement element) { + try { + if (getView().isTemplateExternal()) { +// renderingContext.renderResource( +// new ProxyResource(getView().viewResource(), getCompositeId().getValue())); + } else { + renderingContext.renderResource( + new ByteArrayResource(getCompositeId().getValue(), "text/html", element.toBytes())); + } + onElementReplaced(replaceElement(element)); + } catch (XMLStreamException e) { + LOGGER.error("An error occured while rendering component.", e); + return; + } + } + + protected void onElementReplaced(SurfaceElement surfaceElement) {} + + private SurfaceElement replaceElement(SurfaceElement element) { + SurfaceElement componentElement = new SurfaceElement(getId(), element.getNamespace()); + setRefAttribute(componentElement); + element.replaceWith(componentElement); + element.detach(); + + return componentElement; + } + + private void setRefAttribute(SurfaceElement element) { + element.addAttribute("ref", getId()); + } } diff --git a/licket-framework/src/main/java/org/licket/core/view/container/AbstractLicketMonoContainer.java b/licket-framework/src/main/java/org/licket/core/view/container/AbstractLicketMonoContainer.java index c093344..d9595c2 100644 --- a/licket-framework/src/main/java/org/licket/core/view/container/AbstractLicketMonoContainer.java +++ b/licket-framework/src/main/java/org/licket/core/view/container/AbstractLicketMonoContainer.java @@ -5,33 +5,29 @@ import org.licket.core.view.AbstractReloadableLicketComponent; import org.licket.core.view.LicketComponent; import org.licket.core.view.LicketComponentView; - import java.util.function.Predicate; /** * @author grabslu */ -public abstract class AbstractLicketMonoContainer extends AbstractReloadableLicketComponent - implements LicketComponentContainer { +public abstract class AbstractLicketMonoContainer extends AbstractReloadableLicketComponent implements LicketComponentContainer { private LicketComponent child; - public AbstractLicketMonoContainer(String id, Class modelClass, + public AbstractLicketMonoContainer(String id, Class modelClass, LicketComponentModelReloader modelReloader) { + super(id, modelClass, modelReloader); + } + + public AbstractLicketMonoContainer(String id, Class modelClass, LicketComponentModel componentModel, LicketComponentModelReloader modelReloader) { - super(id, modelClass, modelReloader); - } - - public AbstractLicketMonoContainer(String id, Class modelClass, - LicketComponentModel componentModel, LicketComponentModelReloader modelReloader) { - super(id, modelClass, componentModel, modelReloader); - } - - public AbstractLicketMonoContainer(String id, Class modelClass, - LicketComponentModel componentModel, LicketComponentView view, - LicketComponentModelReloader modelReloader) { - super(id, modelClass, componentModel, view, modelReloader); - } - + super(id, modelClass, componentModel, modelReloader); + } + + public AbstractLicketMonoContainer(String id, Class modelClass, LicketComponentModel componentModel, + LicketComponentView view, LicketComponentModelReloader modelReloader) { + super(id, modelClass, componentModel, view, modelReloader); + } + public final void add(LicketComponent child) { this.child = child; child.setParent(this); @@ -53,6 +49,8 @@ public void traverseDown(Predicate> componentConsumer) { if (child == null) { return; } - child.traverseDown(componentConsumer); + if (componentConsumer.test(child)) { + child.traverseDown(componentConsumer); + } } } diff --git a/licket-framework/src/main/java/org/licket/core/view/container/AbstractLicketMultiContainer.java b/licket-framework/src/main/java/org/licket/core/view/container/AbstractLicketMultiContainer.java index 0e95206..f289f29 100644 --- a/licket-framework/src/main/java/org/licket/core/view/container/AbstractLicketMultiContainer.java +++ b/licket-framework/src/main/java/org/licket/core/view/container/AbstractLicketMultiContainer.java @@ -4,10 +4,8 @@ import static com.google.common.collect.Lists.newArrayList; import static org.licket.framework.hippo.ExpressionStatementBuilder.expressionStatement; import static org.licket.framework.hippo.PropertyNameBuilder.property; - import java.util.List; import java.util.function.Predicate; - import org.licket.core.model.LicketComponentModel; import org.licket.core.module.application.LicketComponentModelReloader; import org.licket.core.view.AbstractReloadableLicketComponent; @@ -34,8 +32,8 @@ public AbstractLicketMultiContainer(String id, Class modelClass, LicketCompon super(id, modelClass, componentModel, modelReloader); } - public AbstractLicketMultiContainer(String id, Class modelClass, LicketComponentModel componentModel, LicketComponentView view, - LicketComponentModelReloader modelReloader) { + public AbstractLicketMultiContainer(String id, Class modelClass, LicketComponentModel componentModel, + LicketComponentView view, LicketComponentModelReloader modelReloader) { super(id, modelClass, componentModel, view, modelReloader); } diff --git a/licket-framework/src/main/java/org/licket/core/view/container/LicketInlineContainer.java b/licket-framework/src/main/java/org/licket/core/view/container/LicketInlineContainer.java new file mode 100644 index 0000000..c003bda --- /dev/null +++ b/licket-framework/src/main/java/org/licket/core/view/container/LicketInlineContainer.java @@ -0,0 +1,16 @@ +package org.licket.core.view.container; + +import org.licket.core.module.application.LicketComponentModelReloader; + +import static org.licket.core.model.LicketComponentModel.emptyComponentModel; +import static org.licket.core.view.LicketComponentView.internalTemplateView; + +/** + * @author grabslu + */ +public class LicketInlineContainer extends AbstractLicketMonoContainer { + + public LicketInlineContainer(String id, Class modelClass, LicketComponentModelReloader modelReloader) { + super(id, modelClass, emptyComponentModel(), internalTemplateView(), modelReloader); + } +} diff --git a/licket-framework/src/main/java/org/licket/core/view/form/AbstractLicketForm.java b/licket-framework/src/main/java/org/licket/core/view/form/AbstractLicketForm.java index 3d55ccf..acb691e 100644 --- a/licket-framework/src/main/java/org/licket/core/view/form/AbstractLicketForm.java +++ b/licket-framework/src/main/java/org/licket/core/view/form/AbstractLicketForm.java @@ -25,6 +25,7 @@ import org.licket.framework.hippo.BlockBuilder; import org.licket.framework.hippo.ExpressionStatementBuilder; import org.licket.framework.hippo.NameBuilder; +import org.licket.surface.element.SurfaceElement; /** * @author activey @@ -59,6 +60,11 @@ protected void onRenderContainer(ComponentRenderingContext renderingContext) { }); } + @Override + protected void onElementReplaced(SurfaceElement surfaceElement) { + super.onElementReplaced(surfaceElement); + } + @VueComponentFunction public void afterSubmit(@Name("response") NameBuilder response, BlockBuilder functionBody) { // setting current form model directly without event emitter @@ -80,6 +86,10 @@ public void afterSubmit(@Name("response") NameBuilder response, BlockBuilder fun componentActionCallback.forEachToBeReloaded(component -> { functionBody.appendStatement(reloadComponent(component)); }); + // invoking javascript calls + componentActionCallback.forEachCall(call -> functionBody.appendStatement( + expressionStatement(call) + )); } private ExpressionStatementBuilder reloadComponent(LicketComponent component) { diff --git a/licket-framework/src/main/java/org/licket/core/view/form/LicketInput.java b/licket-framework/src/main/java/org/licket/core/view/form/LicketInput.java index ca88dbd..6cf798f 100644 --- a/licket-framework/src/main/java/org/licket/core/view/form/LicketInput.java +++ b/licket-framework/src/main/java/org/licket/core/view/form/LicketInput.java @@ -30,7 +30,8 @@ public LicketInput(String id) { protected void onBeforeRender(ComponentRenderingContext renderingContext) { LOGGER.trace("Rendering LicketInput: [{}]", getId()); - Optional> parent = traverseUp(component -> component instanceof AbstractLicketMultiContainer); + Optional> parent = traverseUp( + component -> component instanceof AbstractLicketMultiContainer); if (!parent.isPresent()) { return; } diff --git a/licket-framework/src/main/java/org/licket/core/view/hippo/ComponentModelDecorator.java b/licket-framework/src/main/java/org/licket/core/view/hippo/ComponentModelDecorator.java index 8fdeae2..adc6f2d 100644 --- a/licket-framework/src/main/java/org/licket/core/view/hippo/ComponentModelDecorator.java +++ b/licket-framework/src/main/java/org/licket/core/view/hippo/ComponentModelDecorator.java @@ -27,12 +27,20 @@ public static ComponentModelDecorator fromComponentModel(LicketComponentModel return new ComponentModelDecorator(componentModel); } + private static Reader modelObjectLiteralReader(String modelStringValue) { + return new StringReader(format("model = %s", modelStringValue)); + } + public ObjectLiteralBuilder decorate(ObjectLiteralBuilder objectLiteral) throws IOException { ObjectMapper mapper = new ObjectMapper(); mapper.configure(QUOTE_FIELD_NAMES, false); // serialize component model to string json - String modelStringValue = mapper.writeValueAsString(componentModel.get()); + Object modelValue = componentModel.get(); + if (modelValue == null) { + return objectLiteral; + } + String modelStringValue = mapper.writeValueAsString(modelValue); // parse model declaration object literal AstRoot astRoot = new Parser().parse(modelObjectLiteralReader(modelStringValue), "test.js", 0); @@ -45,8 +53,4 @@ public ObjectLiteralBuilder decorate(ObjectLiteralBuilder objectLiteral) throws }); return objectLiteral; } - - private static Reader modelObjectLiteralReader(String modelStringValue) { - return new StringReader(format("model = %s", modelStringValue)); - } } diff --git a/licket-framework/src/main/java/org/licket/core/view/link/ComponentActionCallback.java b/licket-framework/src/main/java/org/licket/core/view/link/ComponentActionCallback.java index 7c85eb7..bd83c9f 100644 --- a/licket-framework/src/main/java/org/licket/core/view/link/ComponentActionCallback.java +++ b/licket-framework/src/main/java/org/licket/core/view/link/ComponentActionCallback.java @@ -9,7 +9,7 @@ /** * @author activey */ -public class ComponentActionCallback { +public class ComponentActionCallback extends ComponentFunctionCallback { private LicketComponent[] components = {}; diff --git a/licket-module-semanticui/src/main/java/org/licket/semantic/component/modal/AbstractSemanticUIModal.java b/licket-module-semanticui/src/main/java/org/licket/semantic/component/modal/AbstractSemanticUIModal.java index db89de6..699dde7 100644 --- a/licket-module-semanticui/src/main/java/org/licket/semantic/component/modal/AbstractSemanticUIModal.java +++ b/licket-module-semanticui/src/main/java/org/licket/semantic/component/modal/AbstractSemanticUIModal.java @@ -38,9 +38,9 @@ public AbstractSemanticUIModal(String id, ModalSettings modalSettings, LicketCom @Override protected final void onInitialize() { - this.bodyContainer = new ModalSection("body", modelReloader()); + this.bodyContainer = new ModalSection("main-section", modelReloader()); bodyContainer.setParent(this); - onInitializeBody(bodyContainer, "content"); + onInitializeBody(bodyContainer, "content-block"); bodyContainer.initialize(); } @@ -52,7 +52,9 @@ protected void onInitializeActions(ModalSection content, String contentId) {} @Override public void traverseDown(Predicate> componentConsumer) { - bodyContainer.traverseDown(componentConsumer); + if (componentConsumer.test(bodyContainer)) { + bodyContainer.traverseDown(componentConsumer); + } } protected void onBeforeRender(ComponentRenderingContext renderingContext) { @@ -107,4 +109,18 @@ public final FunctionCallBuilder callShow(LicketComponent caller) { name("show") )); } + + public final FunctionCallBuilder callHide(LicketComponent caller) { + // TODO check if caller and modal has the same parent, if not - call is not possible. + return functionCall().target( + property( + arrayElementGet() + .target(property(property("this", "$parent"), "$refs")) + .element(getId()), + name("hide") + )); + } + + + } diff --git a/licket-module-semanticui/src/main/java/org/licket/semantic/component/modal/ModalSection.java b/licket-module-semanticui/src/main/java/org/licket/semantic/component/modal/ModalSection.java index a959112..dacb4cc 100644 --- a/licket-module-semanticui/src/main/java/org/licket/semantic/component/modal/ModalSection.java +++ b/licket-module-semanticui/src/main/java/org/licket/semantic/component/modal/ModalSection.java @@ -1,8 +1,10 @@ package org.licket.semantic.component.modal; +import org.licket.core.model.LicketComponentModel; import org.licket.core.module.application.LicketComponentModelReloader; import org.licket.core.view.container.AbstractLicketMonoContainer; +import static org.licket.core.model.LicketComponentModel.emptyComponentModel; import static org.licket.core.view.LicketComponentView.internalTemplateView; /** @@ -11,6 +13,6 @@ public class ModalSection extends AbstractLicketMonoContainer { public ModalSection(String id, LicketComponentModelReloader modelReloader) { - super(id, Void.class, null, internalTemplateView(), modelReloader); + super(id, Void.class, emptyComponentModel(), internalTemplateView(), modelReloader); } } diff --git a/licket-module-semanticui/src/main/resources/org/licket/semantic/component/modal/AbstractSemanticUIModal.html b/licket-module-semanticui/src/main/resources/org/licket/semantic/component/modal/AbstractSemanticUIModal.html index 1b2a144..b9974f3 100644 --- a/licket-module-semanticui/src/main/resources/org/licket/semantic/component/modal/AbstractSemanticUIModal.html +++ b/licket-module-semanticui/src/main/resources/org/licket/semantic/component/modal/AbstractSemanticUIModal.html @@ -1,11 +1,11 @@