Java tutorial
/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wicketstuff.js.ext; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.wicket.Component; import org.apache.wicket.MarkupContainer; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.behavior.AttributeAppender; import org.apache.wicket.behavior.Behavior; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.OnDomReadyHeaderItem; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.util.visit.IVisit; import org.apache.wicket.util.visit.IVisitor; import org.json.JSONException; import org.json.JSONObject; import org.wicketstuff.js.ext.util.ExtClass; import org.wicketstuff.js.ext.util.ExtEventListener; import org.wicketstuff.js.ext.util.ExtProperty; import org.wicketstuff.js.ext.util.ExtPropertyConverter; import org.wicketstuff.js.ext.util.ExtResourcesHeaderItem; import org.wicketstuff.js.ext.util.ExtThemeBehavior; import static org.wicketstuff.js.ext.util.ExtPropertyConverter.convert; @ExtClass("Ext.Component") public abstract class ExtComponent extends Panel implements IExtObservable { protected transient JSONObject properties = new JSONObject(); private static final int FLAG_ONRENDERPROPERTIES = 1; private static final List SUPPORTED_EVENTS = Arrays.asList("enable", "disable", "show", "hide"); private transient int flags = 0; @ExtProperty String cls; @ExtProperty IModel<String> fieldLabel; @ExtProperty Boolean hidden; @ExtProperty String stateId; @ExtProperty Boolean stateful; @ExtProperty String contentEl; Map<String, ExtEventAjaxBehavior> eventHandlers = new HashMap<String, ExtEventAjaxBehavior>(); public ExtComponent(String id) { super(id); } protected boolean isRenderFromMarkup() { return isExtRoot(); } protected boolean isExtRoot() { final MarkupContainer parent = getParent(); return !(parent instanceof ExtComponent) && !(parent instanceof ItemsRepeater.ExtItem) && !(parent instanceof Form && parent.getParent() instanceof ItemsRepeater.ExtItem); } @Override protected boolean getStatelessHint() { return false; } @Override protected void onBeforeRender() { if (!hasBeenRendered()) { updateContentElement(); if (isRenderFromMarkup()) { setOutputMarkupId(true); } else { setRenderBodyOnly(true); } addThemeBehavior(); } renderProperties(); super.onBeforeRender(); } private void updateContentElement() { final List<Component> children = new LinkedList<Component>(); visitChildren(new IVisitor<Component, Void>() { @Override public void component(Component component, IVisit<Void> visit) { if ((!(component instanceof ExtComponent)) && (!(component instanceof ItemsRepeater)) && (!(component instanceof ItemsRepeater.ExtItem))) { children.add(component); } visit.dontGoDeeper(); } }); if (children.size() > 1) { throw new WicketRuntimeException("More than one child component added to ExtComponent"); } if (children.size() == 1) { Component component = children.get(0); component.setOutputMarkupId(true); component.add(new AttributeAppender("class", Model.of("x-hidden"), " ") { @Override public boolean isTemporary(Component component) { return true; } }); this.contentEl = component.getMarkupId(); } onAfterUpdateContentElement(); } protected void onAfterUpdateContentElement() { } // iterate through child components and render properties private void renderProperties() { properties = new JSONObject(); try { properties.put("disabled", !isEnabled()); ExtPropertyConverter.addProperties(this, getClass(), properties); addListeners(); properties.put("resources", ExtObservableHelper.renderResources(this, ExtComponent.class)); onRenderProperties(properties); if ((flags & FLAG_ONRENDERPROPERTIES) == 0) { throw new RuntimeException("Class in hierarchy of " + getClass().getName() + " has overridden onRenderProperties, but did not call parent"); } flags &= ~FLAG_ONRENDERPROPERTIES; } catch (JSONException ex) { throw new RuntimeException("Error rendering properties", ex); } } protected void onRenderProperties(JSONObject properties) throws JSONException { if (isRenderFromMarkup()) { properties.put("applyTo", convert(getMarkupId())); } if (stateId == null) { properties.put("id", convert(getMarkupId())); } flags |= FLAG_ONRENDERPROPERTIES; } @Override public void renderHead(final IHeaderResponse response) { super.renderHead(response); response.render(ExtResourcesHeaderItem.get()); // find out if this is the root of a ext-component structure if (isExtRoot()) { StringBuilder js = new StringBuilder(); onRenderExtHead(js); response.render(OnDomReadyHeaderItem.forScript(js.toString())); } } private void onRenderExtHead(StringBuilder js) { preRenderExtHead(js); for (ExtObservable item : getExtObservables()) { item.onRenderExtHead(js); } for (ExtComponent item : getExtComponents()) { item.onRenderExtHead(js); } buildInstantiationJs(js, getExtClass(), properties); postRenderExtHead(js); } protected void preRenderExtHead(StringBuilder js) { } protected void buildInstantiationJs(StringBuilder js, String extClass, JSONObject properties) { js.append(String.format("var %s = new %s(%s);\n", getExtId(), extClass, properties.toString())); } protected void postRenderExtHead(StringBuilder js) { } protected final String getExtClass() { return ExtObservableHelper.getExtClass(this, ExtComponent.class); } private void addThemeBehavior() { if (isExtRoot()) { Component component = this; boolean foundTheme = false; while (component != null) { for (Behavior behavior : component.getBehaviors()) { if (behavior instanceof ExtThemeBehavior) { foundTheme = true; break; } } if (foundTheme) { break; } component = component.getParent(); } if (!foundTheme) { add(getThemeBehavior()); } } } protected ExtThemeBehavior getThemeBehavior() { return new ExtThemeBehavior(); } private void addListeners() throws JSONException { if (!eventHandlers.isEmpty()) { JSONObject jsonListeners = new JSONObject(); for (Map.Entry<String, ExtEventAjaxBehavior> entry : eventHandlers.entrySet()) { ExtEventAjaxBehavior behavior = entry.getValue(); if (!getBehaviors().contains(behavior)) { add(behavior); } jsonListeners.put(entry.getKey(), behavior.getEventScript()); } properties.put("listeners", jsonListeners); } } protected final String getExtId() { return getMarkupId().replace("-", "_"); } /** * Factory method to implement event specific ajax behavior. Default supported events are 'enable', 'disable', * 'show', 'hide'. * * @param event name of the event * @return the behavior for the event */ protected ExtEventAjaxBehavior newExtEventBehavior(String event) { if (SUPPORTED_EVENTS.contains(event)) { return new ExtEventAjaxBehavior(); } return new ExtEventAjaxBehavior(); } public List<ExtComponent> getExtComponents() { final List<ExtComponent> itemsList = new ArrayList<ExtComponent>(); visitChildren(new IVisitor<Component, Void>() { @Override public void component(Component component, IVisit<Void> visit) { if (component instanceof ExtComponent) { itemsList.add((ExtComponent) component); visit.dontGoDeeper(); return; } } }); return itemsList; } protected List<ExtObservable> getExtObservables() { return getBehaviors(ExtObservable.class); } public void addEventListener(String event, ExtEventListener listener) { if (!eventHandlers.containsKey(event)) { ExtEventAjaxBehavior behavior = newExtEventBehavior(event); eventHandlers.put(event, behavior); } eventHandlers.get(event).addListener(listener); } /* ExtProperties setters */ public ExtComponent setDisabled(Boolean disabled) { return (ExtComponent) setEnabled(!disabled); } public void setCls(String cls) { this.cls = cls; } public void setHidden(Boolean hidden) { this.hidden = hidden; } public void setStateId(String stateId) { this.stateId = stateId; } public void setStateful(Boolean stateful) { this.stateful = stateful; } public void setFieldLabel(IModel<String> fieldLabel) { this.fieldLabel = fieldLabel; } }