protected Iterator<MessageForRender> getMessages( FacesContext context, String forClientId, UIComponent component) { Iterator<MessageForRender> msgIter; if (forClientId != null) { if (forClientId.length() != 0) { UIComponent result = RendererUtils.getInstance().findComponentFor(component, forClientId); if (result == null) { msgIter = Iterators.emptyIterator(); } else { String clientId = result.getClientId(context); msgIter = getMessagesForId(context, clientId); } } else { msgIter = getMessagesForId(context, null); } } else { msgIter = Iterators.emptyIterator(); Iterator<String> clientIdsWithMessages = context.getClientIdsWithMessages(); while (clientIdsWithMessages.hasNext()) { String clientId = (String) clientIdsWithMessages.next(); msgIter = Iterators.concat(msgIter, getMessagesForId(context, clientId)); } } return msgIter; }
protected void setEventPhase(ItemChangeEvent event) { if (isImmediate() || (event.getNewItem() != null && RendererUtils.getInstance().isBooleanAttribute(event.getNewItem(), "immediate"))) { event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES); } else { event.setPhaseId(PhaseId.UPDATE_MODEL_VALUES); } }
protected void encodeScript(FacesContext facesContext, UIComponent component) throws IOException { JavaScriptService javaScriptService = ServiceTracker.getService(JavaScriptService.class); JSFunction messageObject = new JSObject(getJSClassName(), component.getClientId(facesContext)); Map<String, Object> attributes = component.getAttributes(); Builder<String, Object> parametersBuilder = ImmutableMap.builder(); String forId = (String) attributes.get("for"); RendererUtils rendererUtils = RendererUtils.getInstance(); if (!Strings.isNullOrEmpty(forId)) { UIComponent target = rendererUtils.findComponentFor(component, forId); if (null != target) { parametersBuilder.put("forComponentId", target.getClientId(facesContext)); } } Severity level = getLevel(component); if (FacesMessage.SEVERITY_INFO != level) { parametersBuilder.put("level", level.getOrdinal()); } if (!rendererUtils.isBooleanAttribute(component, "showSummary")) { parametersBuilder.put("showSummary", false); } if (rendererUtils.isBooleanAttribute(component, "showDetail")) { parametersBuilder.put("showDetail", true); } if (rendererUtils.isBooleanAttribute(component, "tooltip")) { parametersBuilder.put("tooltip", true); } if (isComponentMessages(component)) { parametersBuilder.put("isMessages", true); } messageObject.addParameter(parametersBuilder.build()); // RendererUtils.getInstance().writeScript(facesContext, component, messageObject); javaScriptService.addPageReadyScript(facesContext, messageObject); }
@Override protected Map<String, Object> getScriptObjectOptions( FacesContext context, UIComponent component) { AbstractTooltip tooltip = (AbstractTooltip) component; Map<String, Object> options = new HashMap<String, Object>(); RenderKitUtils.addToScriptHash( options, "ajax", getAjaxOptions(context, tooltip), TooltipMode.DEFAULT); Positioning jointPoint = tooltip.getJointPoint(); if (jointPoint == null) { jointPoint = org.richfaces.component.Positioning.DEFAULT; } Positioning direction = tooltip.getDirection(); if (direction == null) { direction = org.richfaces.component.Positioning.DEFAULT; } RenderKitUtils.addToScriptHash( options, "jointPoint", jointPoint.getValue(), Positioning.DEFAULT.getValue()); RenderKitUtils.addToScriptHash( options, "direction", direction.getValue(), Positioning.DEFAULT.getValue()); RenderKitUtils.addToScriptHash(options, "attached", tooltip.isAttached(), true); RenderKitUtils.addToScriptHash(options, "offset", getOffset(tooltip)); RenderKitUtils.addToScriptHash(options, "mode", tooltip.getMode(), TooltipMode.DEFAULT); RenderKitUtils.addToScriptHash(options, "hideDelay", tooltip.getHideDelay(), 0); RenderKitUtils.addToScriptHash(options, "hideEvent", tooltip.getHideEvent(), "mouseleave"); RenderKitUtils.addToScriptHash(options, "showDelay", tooltip.getShowDelay(), 0); RenderKitUtils.addToScriptHash(options, "showEvent", tooltip.getShowEvent(), "mouseenter"); RenderKitUtils.addToScriptHash(options, "followMouse", tooltip.isFollowMouse(), true); RenderKitUtils.addToScriptHash( options, "target", RENDERER_UTILS.findComponentFor(component, tooltip.getTarget()).getClientId(context)); addEventOption(context, tooltip, options, HIDE); addEventOption(context, tooltip, options, SHOW); addEventOption(context, tooltip, options, BEFORE_HIDE); addEventOption(context, tooltip, options, BEFORE_SHOW); return options; }
protected void encodeMessage(FacesContext facesContext, UIComponent component, Object msg) throws IOException { // TODO fix generator to properly detect iteration variable type MessageForRender message = (MessageForRender) msg; String summary = message.getSummary(); String detail = message.getDetail(); boolean showSummary = true; boolean showDetail = false; boolean isMessages = false; if (isComponentMessage(component)) { UIMessage uiMessage = (UIMessage) component; showSummary = uiMessage.isShowSummary(); showDetail = uiMessage.isShowDetail(); } else if (isComponentMessages(component)) { UIMessages uiMessages = (UIMessages) component; showSummary = uiMessages.isShowSummary(); showDetail = uiMessages.isShowDetail(); isMessages = true; } ResponseWriter responseWriter = facesContext.getResponseWriter(); // Message id responseWriter.writeAttribute( "id", component.getClientId() + ':' + message.getSourceId(), null); // tooltip boolean wroteTooltip = RendererUtils.getInstance().isBooleanAttribute(component, "tooltip"); if (wroteTooltip && !Strings.isNullOrEmpty(summary)) { responseWriter.writeAttribute("title", summary, null); } if (!wroteTooltip && showSummary) { writeMessageLabel(responseWriter, summary, isMessages ? "rf-msgs-sum" : "rf-msg-sum"); } if (showDetail) { writeMessageLabel(responseWriter, detail, isMessages ? "rf-msgs-det" : "rf-msg-det"); } message.rendered(); }
/** * @author amarkhel * @since 2010-10-24 */ @ResourceDependencies({ @ResourceDependency(library = "org.richfaces", name = "ajax.reslib"), @ResourceDependency(library = "org.richfaces", name = "base-component.reslib"), @ResourceDependency(name = "jquery.position.js"), @ResourceDependency(name = "richfaces-event.js"), @ResourceDependency(library = "org.richfaces", name = "popup.js"), @ResourceDependency(library = "org.richfaces", name = "tooltip.js"), @ResourceDependency(library = "org.richfaces", name = "tooltip.ecss") }) @JsfRenderer(type = "org.richfaces.TooltipRenderer", family = AbstractTooltip.COMPONENT_FAMILY) public class TooltipRenderer extends DivPanelRenderer implements MetaComponentRenderer { public static final String HIDE = "hide"; public static final String SHOW = "show"; public static final String BEFORE_HIDE = "beforehide"; public static final String BEFORE_SHOW = "beforeshow"; private static final int DEFAULT_ZINDEX_VALUE = 1000; private static final RendererUtils RENDERER_UTILS = RendererUtils.getInstance(); @Override protected void doDecode(FacesContext context, UIComponent component) { AbstractTooltip tooltip = (AbstractTooltip) component; Map<String, String> requestMap = context.getExternalContext().getRequestParameterMap(); String compClientId = component.getClientId(context); String clientId = requestMap.get(compClientId); if (clientId != null && clientId.equals(compClientId)) { context.getPartialViewContext().getRenderIds().add(tooltip.getContentClientId(context)); // TODO nick - this should be done on encode, not on decode addOnCompleteParam(context, tooltip.getClientId(context)); context.renderResponse(); } } protected static void addOnCompleteParam(FacesContext context, String tooltipId) { ExtendedPartialViewContext.getInstance(context) .appendOncomplete( new StringBuilder() .append("RichFaces.$('") .append(tooltipId) .append("').onCompleteHandler();") .toString()); } @Override protected void doEncodeBegin(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException { AbstractTooltip tooltip = (AbstractTooltip) component; writer.startElement(getMarkupElement(tooltip), component); writer.writeAttribute(ID_ATTRIBUTE, component.getClientId(context), "clientId"); writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, "display: none;", null); writer.startElement(getMarkupElement(tooltip), component); writer.writeAttribute(ID_ATTRIBUTE, component.getClientId(context) + ":wrp", null); writer.writeAttribute(CLASS_ATTRIBUTE, getStyleClass(component), null); int zindex = tooltip.getZindex(); if (zindex == Integer.MIN_VALUE) { zindex = DEFAULT_ZINDEX_VALUE; } String style = concatStyles("z-index:" + zindex, getStyle(component)); if (style != null && style.trim().length() > 0) { writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, style, null); } renderPassThroughAttributes(context, component, getPassThroughAttributes()); writer.startElement(getMarkupElement(tooltip), component); writer.writeAttribute(ID_ATTRIBUTE, component.getClientId(context) + ":cntr", null); writer.writeAttribute(CLASS_ATTRIBUTE, "rf-tt-cntr", null); if (tooltip.getMode() == TooltipMode.ajax) { encodeLoading(writer, context, tooltip); } encodeContentBegin(writer, context, tooltip); } private void encodeContentBegin( ResponseWriter writer, FacesContext context, AbstractTooltip tooltip) throws IOException { writer.startElement(getMarkupElement(tooltip), tooltip); writer.writeAttribute(ID_ATTRIBUTE, tooltip.getClientId(context) + ":content", null); writer.writeAttribute(CLASS_ATTRIBUTE, "rf-tt-cnt", null); if (tooltip.getChildCount() == 0) { writer.write(tooltip.getValue().toString()); } } private void encodeLoading(ResponseWriter writer, FacesContext context, AbstractTooltip tooltip) throws IOException { writer.startElement(getMarkupElement(tooltip), tooltip); writer.writeAttribute(ID_ATTRIBUTE, tooltip.getClientId(context) + ":loading", null); writer.writeAttribute(CLASS_ATTRIBUTE, "rf-tt-loading", null); UIComponent loading = tooltip.getFacet("loading"); if (loading != null && loading.isRendered()) { loading.encodeAll(context); } else { writer.writeText("Loading...", null); } writer.endElement(getMarkupElement(tooltip)); } private String getMarkupElement(AbstractTooltip component) { switch (component.getLayout()) { case block: return HtmlConstants.DIV_ELEM; case inline: return HtmlConstants.SPAN_ELEM; default: throw new IllegalStateException("Unknown tooltip layout (=" + component.getLayout() + ")"); } } @Override protected String getStyleClass(UIComponent component) { return concatClasses("rf-tt", attributeAsString(component, "styleClass")); } @Override protected JSObject getScriptObject(FacesContext context, UIComponent component) { return new JSObject( "RichFaces.ui.Tooltip", component.getClientId(context), getScriptObjectOptions(context, component)); } @Override protected Map<String, Object> getScriptObjectOptions( FacesContext context, UIComponent component) { AbstractTooltip tooltip = (AbstractTooltip) component; Map<String, Object> options = new HashMap<String, Object>(); RenderKitUtils.addToScriptHash( options, "ajax", getAjaxOptions(context, tooltip), TooltipMode.DEFAULT); Positioning jointPoint = tooltip.getJointPoint(); if (jointPoint == null) { jointPoint = org.richfaces.component.Positioning.DEFAULT; } Positioning direction = tooltip.getDirection(); if (direction == null) { direction = org.richfaces.component.Positioning.DEFAULT; } RenderKitUtils.addToScriptHash( options, "jointPoint", jointPoint.getValue(), Positioning.DEFAULT.getValue()); RenderKitUtils.addToScriptHash( options, "direction", direction.getValue(), Positioning.DEFAULT.getValue()); RenderKitUtils.addToScriptHash(options, "attached", tooltip.isAttached(), true); RenderKitUtils.addToScriptHash(options, "offset", getOffset(tooltip)); RenderKitUtils.addToScriptHash(options, "mode", tooltip.getMode(), TooltipMode.DEFAULT); RenderKitUtils.addToScriptHash(options, "hideDelay", tooltip.getHideDelay(), 0); RenderKitUtils.addToScriptHash(options, "hideEvent", tooltip.getHideEvent(), "mouseleave"); RenderKitUtils.addToScriptHash(options, "showDelay", tooltip.getShowDelay(), 0); RenderKitUtils.addToScriptHash(options, "showEvent", tooltip.getShowEvent(), "mouseenter"); RenderKitUtils.addToScriptHash(options, "followMouse", tooltip.isFollowMouse(), true); RenderKitUtils.addToScriptHash( options, "target", RENDERER_UTILS.findComponentFor(component, tooltip.getTarget()).getClientId(context)); addEventOption(context, tooltip, options, HIDE); addEventOption(context, tooltip, options, SHOW); addEventOption(context, tooltip, options, BEFORE_HIDE); addEventOption(context, tooltip, options, BEFORE_SHOW); return options; } public Integer[] getOffset(AbstractTooltip tooltip) { int horizontalOffset = tooltip.getHorizontalOffset(); int verticalOffset = tooltip.getVerticalOffset(); if (horizontalOffset == Integer.MIN_VALUE) { horizontalOffset = 10; } if (verticalOffset == Integer.MIN_VALUE) { verticalOffset = 10; } return new Integer[] {horizontalOffset, verticalOffset}; } private void encodeContentEnd( ResponseWriter writer, FacesContext context, AbstractTooltip tooltip) throws IOException { writer.endElement(getMarkupElement(tooltip)); } @Override protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException { encodeContentEnd(writer, context, (AbstractTooltip) component); writer.endElement(getMarkupElement((AbstractTooltip) component)); writer.endElement(getMarkupElement((AbstractTooltip) component)); writeJavaScript(writer, context, component); writer.endElement(getMarkupElement((AbstractTooltip) component)); } public void encodeMetaComponent( FacesContext context, UIComponent component, String metaComponentId) throws IOException { if (AbstractTooltip.CONTENT_META_COMPONENT_ID.equals(metaComponentId)) { AbstractTooltip tooltip = (AbstractTooltip) component; PartialResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter(); writer.startUpdate( tooltip.getClientId(context) + ":" + AbstractTooltip.CONTENT_META_COMPONENT_ID); encodeContentBegin(writer, context, tooltip); for (UIComponent child : tooltip.getChildren()) { child.encodeAll(context); } encodeContentEnd(writer, context, tooltip); writer.endUpdate(); } } public void decodeMetaComponent( FacesContext context, UIComponent component, String metaComponentId) { throw new UnsupportedOperationException(); } @Override protected Class<? extends UIComponent> getComponentClass() { return AbstractTooltip.class; } @Override protected void doEncodeChildren( ResponseWriter writer, FacesContext context, UIComponent component) throws IOException { AbstractTooltip tooltip = (AbstractTooltip) component; if (tooltip.getMode() == TooltipMode.client) { if (tooltip.getChildCount() > 0) { for (UIComponent kid : tooltip.getChildren()) { kid.encodeAll(context); } } } } @Override public boolean getRendersChildren() { return true; } }
/** * The <rich:togglePanel> component is used as a base for the other switchable components, the * <rich:accordion> component and the <rich:tabPanel> component. It provides an abstract * switchable component without any associated markup. As such, the <rich:togglePanel> * component could be customized to provide a switchable component when neither an accordion * component or a tab panel component is appropriate. * * @author akolonitsky * @author <a href="http://community.jboss.org/people/bleathem">Brian Leathem</a> */ @JsfComponent( tag = @Tag( type = TagType.Facelets, handler = "org.richfaces.view.facelets.html.TogglePanelTagHandler"), renderer = @JsfRenderer(type = "org.richfaces.TogglePanelRenderer"), attributes = {"core-props.xml", "events-mouse-props.xml", "i18n-props.xml"}) public abstract class AbstractTogglePanel extends UIOutput implements AbstractDivPanel, ItemChangeSource, MetaComponentResolver, MetaComponentEncoder { public static final String ACTIVE_ITEM_META_COMPONENT = "activeItem"; public static final String COMPONENT_TYPE = "org.richfaces.TogglePanel"; public static final String COMPONENT_FAMILY = "org.richfaces.TogglePanel"; public static final String META_NAME_FIRST = "@first"; public static final String META_NAME_PREV = "@prev"; public static final String META_NAME_NEXT = "@next"; public static final String META_NAME_LAST = "@last"; // TODO What is MessageId ? public static final String UPDATE_MESSAGE_ID = "javax.faces.component.UIInput.UPDATE"; private static final Logger LOG = RichfacesLogger.RENDERKIT.getLogger(); private static final RendererUtils UTILS = RendererUtils.getInstance(); private String submittedActiveItem = null; private enum PropertyKeys { localValueSet, required, valid, immediate, switchType } protected AbstractTogglePanel() { setRendererType("org.richfaces.TogglePanelRenderer"); } public static boolean isPanelItemDynamic(UIComponent component) { UIComponent parent = component.getParent(); while (parent != null) { if (parent instanceof AbstractTogglePanel) { return false; } if (parent instanceof UIRepeat) { return true; } parent = parent.getParent(); } return false; } // -------------------------------------------------- Editable Value Holder public Object getSubmittedValue() { return this.submittedActiveItem; } public void resetValue() { this.setValue(null); this.setSubmittedValue(null); this.setLocalValueSet(false); this.setValid(true); } public void setSubmittedValue(Object submittedValue) { this.submittedActiveItem = String.valueOf(submittedValue); } public boolean isLocalValueSet() { return (Boolean) getStateHelper().eval(PropertyKeys.localValueSet, false); } public void setLocalValueSet(boolean localValueSet) { getStateHelper().put(PropertyKeys.localValueSet, localValueSet); } public boolean isValid() { return (Boolean) getStateHelper().eval(PropertyKeys.valid, true); } public void setValid(boolean valid) { getStateHelper().put(PropertyKeys.valid, valid); } public boolean isRequired() { return (Boolean) getStateHelper().eval(PropertyKeys.required, false); } /** * Set the "required field" state for this component. * * @param required The new "required field" state */ public void setRequired(boolean required) { getStateHelper().put(PropertyKeys.required, required); } /** * Flag indicating that this component's value must be converted and validated immediately (that * is, during Apply Request Values phase), rather than waiting until Process Validations phase. */ @Attribute public boolean isImmediate() { return (Boolean) getStateHelper().eval(PropertyKeys.immediate, false); } public void setImmediate(boolean immediate) { getStateHelper().put(PropertyKeys.immediate, immediate); } // ----------------------------------------------------- UIComponent Methods @Override public void encodeBegin(FacesContext facesContext) throws IOException { updateActiveName(getActiveItem()); super.encodeBegin(facesContext); } public String updateActiveName(final String activeItemName) { boolean valid = false; if (!Strings.isNullOrEmpty(activeItemName)) { valid = isValidName(activeItemName); } if (!valid) { String firstItemName = getFirstNonDisabledItemName(); if (firstItemName != null) { setActiveItem(firstItemName); return firstItemName; } } return activeItemName; } private Boolean isValidName(final String name) { final AtomicReference<Boolean> result = new AtomicReference<Boolean>(Boolean.FALSE); visitTogglePanelItems( this, new TogglePanelVisitCallback() { @Override public VisitResult visit(FacesContext facesContext, TogglePanelVisitState visitState) { AbstractTogglePanelItemInterface panelItem = visitState.getItem(); if (name.equals(panelItem.getName())) { if (panelItem instanceof AbstractTogglePanelTitledItem) { AbstractTogglePanelTitledItem titledItem = (AbstractTogglePanelTitledItem) panelItem; result.set(!titledItem.isDisabled()); } else { result.set(Boolean.TRUE); } return VisitResult.COMPLETE; } return VisitResult.ACCEPT; } }); return result.get(); } /** Returns name of first non-disabled item in the list of panel's items. */ private String getFirstNonDisabledItemName() { final AtomicReference<String> result = new AtomicReference<String>(null); visitTogglePanelItems( this, new TogglePanelVisitCallback() { @Override public VisitResult visit(FacesContext facesContext, TogglePanelVisitState visitState) { AbstractTogglePanelItemInterface panelItem = visitState.getItem(); if (panelItem instanceof AbstractTogglePanelTitledItem) { AbstractTogglePanelTitledItem titledItem = (AbstractTogglePanelTitledItem) panelItem; if (!titledItem.isDisabled()) { result.set(titledItem.getName()); return VisitResult.COMPLETE; } else { return VisitResult.ACCEPT; } } else { result.set(panelItem.getName()); return VisitResult.COMPLETE; } } }); return result.get(); } /** * Specialized decode behavior on top of that provided by the superclass. In addition to the * standard <code>processDecodes</code> behavior inherited from {@link * javax.faces.component.UIComponentBase}, calls <code>processValue()</code> if the the <code> * immediate</code> property is true; if the component is invalid afterwards or a <code> * RuntimeException</code> is thrown, calls {@link FacesContext#renderResponse}. * * @throws NullPointerException {@inheritDoc} */ @Override public void processDecodes(FacesContext facesContext) { if (facesContext == null) { throw new NullPointerException(); } // Skip processing if our rendered flag is false if (!isRendered()) { return; } pushComponentToEL(facesContext, null); final String activeItem = getActiveItemValue(); EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED); VisitContext visitContext = new FullVisitContext(facesContext, hints); this.visitTree( visitContext, new VisitCallback() { @Override public VisitResult visit(VisitContext context, UIComponent target) { if (AbstractTogglePanel.this == target || target instanceof UIRepeat) { return VisitResult.ACCEPT; // Proceed with visit to target's children } if (isActiveItem(target, activeItem) || getSwitchType() == SwitchType.client) { target.processDecodes(context.getFacesContext()); } return VisitResult .REJECT; // No need to visit target's children, as they were recursively visited // above } }); // Process this component itself try { decode(facesContext); } catch (RuntimeException e) { facesContext.renderResponse(); throw e; } finally { popComponentFromEL(facesContext); } ItemChangeEvent event = createItemChangeEvent(facesContext); if (event != null) { event.queue(); } } /** * In addition to the standard <code>processValidators</code> behavior inherited from {@link * javax.faces.component.UIComponentBase}, calls <code>processValue()</code> if the <code> * immediate</code> property is false (which is the default); if the component is invalid * afterwards, calls {@link FacesContext#renderResponse}. If a <code>RuntimeException</code> is * thrown during validation processing, calls {@link FacesContext#renderResponse} and re-throw the * exception. * * @throws NullPointerException {@inheritDoc} */ @Override public void processValidators(FacesContext facesContext) { if (facesContext == null) { throw new NullPointerException(); } // Skip processing if our rendered flag is false if (!isRendered()) { return; } pushComponentToEL(facesContext, null); Application app = facesContext.getApplication(); app.publishEvent(facesContext, PreValidateEvent.class, this); final String activeItem = getActiveItemValue(); EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED); VisitContext visitContext = new FullVisitContext(facesContext, hints); this.visitTree( visitContext, new VisitCallback() { @Override public VisitResult visit(VisitContext context, UIComponent target) { if (AbstractTogglePanel.this == target || target instanceof UIRepeat) { return VisitResult.ACCEPT; // Proceed with visit to target's children } if (isActiveItem(target, activeItem) || getSwitchType() == SwitchType.client) { target.processValidators(context.getFacesContext()); } return VisitResult .REJECT; // No need to visit target's children, as they were recursively visited // above } }); app.publishEvent(facesContext, PostValidateEvent.class, this); popComponentFromEL(facesContext); } /** * In addition to the standard <code>processUpdates</code> behavior inherited from {@link * javax.faces.component.UIComponentBase}, calls <code>updateModel()</code>. If the component is * invalid afterwards, calls {@link FacesContext#renderResponse}. If a <code>RuntimeException * </code> is thrown during update processing, calls {@link FacesContext#renderResponse} and * re-throw the exception. * * @throws NullPointerException {@inheritDoc} */ @Override public void processUpdates(FacesContext facesContext) { if (facesContext == null) { throw new NullPointerException(); } // Skip processing if our rendered flag is false if (!isRendered()) { return; } pushComponentToEL(facesContext, null); final String activeItem = getActiveItemValue(); EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED); VisitContext visitContext = new FullVisitContext(facesContext, hints); this.visitTree( visitContext, new VisitCallback() { @Override public VisitResult visit(VisitContext context, UIComponent target) { if (AbstractTogglePanel.this == target || target instanceof UIRepeat) { return VisitResult.ACCEPT; // Proceed with visit to target's children } if (isActiveItem(target, activeItem) || getSwitchType() == SwitchType.client) { target.processUpdates(context.getFacesContext()); } return VisitResult .REJECT; // No need to visit target's children, as they were recursively visited // above } }); popComponentFromEL(facesContext); if (!isValid()) { facesContext.renderResponse(); } } /** @throws NullPointerException {@inheritDoc} */ @Override public void decode(FacesContext facesContext) { if (facesContext == null) { throw new NullPointerException(); } // Force validity back to "true" setValid(true); super.decode(facesContext); } public void updateModel(FacesContext facesContext) { if (facesContext == null) { throw new NullPointerException(); } if (!isValid() || !isLocalValueSet()) { return; } ValueExpression ve = getValueExpression("value"); if (ve == null) { return; } Throwable caught = null; FacesMessage message = null; try { ve.setValue(facesContext.getELContext(), getLocalValue()); setValue(null); setLocalValueSet(false); } catch (ELException e) { caught = e; String messageStr = e.getMessage(); Throwable result = e.getCause(); while (null != result && result.getClass().isAssignableFrom(ELException.class)) { messageStr = result.getMessage(); result = result.getCause(); } if (messageStr == null) { message = ServiceTracker.getService(MessageFactory.class) .createMessage( facesContext, FacesMessage.SEVERITY_ERROR, FacesMessages.UIINPUT_UPDATE, MessageUtil.getLabel(facesContext, this)); } else { message = new FacesMessage(FacesMessage.SEVERITY_ERROR, messageStr, messageStr); } setValid(false); } catch (Exception e) { caught = e; // message = MessageFactory.getMessage(facesContext, UPDATE_MESSAGE_ID, // MessageFactory.getHeader(facesContext, this)); setValid(false); } if (caught != null) { assert message != null; @SuppressWarnings({"ThrowableInstanceNeverThrown"}) UpdateModelException toQueue = new UpdateModelException(message, caught); ExceptionQueuedEventContext eventContext = new ExceptionQueuedEventContext(facesContext, toQueue, this, PhaseId.UPDATE_MODEL_VALUES); facesContext .getApplication() .publishEvent(facesContext, ExceptionQueuedEvent.class, eventContext); } } private ItemChangeEvent createItemChangeEvent(FacesContext facesContext) { if (facesContext == null) { throw new NullPointerException(); } // Submitted value == null means "the component was not submitted at all". String activeItem = getSubmittedActiveItem(); if (activeItem == null) { return null; } String previous = (String) getValue(); if (previous == null || !previous.equalsIgnoreCase(activeItem)) { UIComponent prevComp = null; UIComponent actvComp = null; if (previous != null) { try { prevComp = (UIComponent) getItem(previous); } catch (TogglePanelVisitException e) { if (LOG.isDebugEnabled()) { LOG.debug("Cannot include dynamic TogglePanelComponents in itemChangeEvents"); } prevComp = null; } } if (activeItem != null) { try { if (LOG.isDebugEnabled()) { LOG.debug("Cannot include dynamic TogglePanelComponents in itemChangeEvents"); } actvComp = (UIComponent) getItem(activeItem); } catch (TogglePanelVisitException e) { actvComp = null; } } return new ItemChangeEvent(this, previous, prevComp, activeItem, actvComp); } return null; } @Override public void queueEvent(FacesEvent event) { if ((event instanceof ItemChangeEvent) && (event.getComponent() == this)) { setEventPhase((ItemChangeEvent) event); } super.queueEvent(event); } protected void setEventPhase(ItemChangeEvent event) { if (isImmediate() || (event.getNewItem() != null && RendererUtils.getInstance().isBooleanAttribute(event.getNewItem(), "immediate"))) { event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES); } else { event.setPhaseId(PhaseId.UPDATE_MODEL_VALUES); } } protected void setEventPhase(FacesEvent event) { if (isImmediate()) { event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES); } else { event.setPhaseId(PhaseId.INVOKE_APPLICATION); } } @Override public void broadcast(FacesEvent event) throws AbortProcessingException { FacesContext facesContext = FacesContext.getCurrentInstance(); if (event instanceof ItemChangeEvent) { setValue(((ItemChangeEvent) event).getNewItemName()); setSubmittedActiveItem(null); if (event.getPhaseId() == PhaseId.UPDATE_MODEL_VALUES) { try { updateModel(facesContext); } catch (RuntimeException e) { facesContext.renderResponse(); throw e; } } else { facesContext.renderResponse(); } } super.broadcast(event); } // -------------------------------------------------- Panel Items Managing @Override public String getFamily() { return COMPONENT_FAMILY; } @Override public boolean getRendersChildren() { return true; } private String getActiveItemValue() { String value = getActiveItem(); if (value == null) { value = getSubmittedActiveItem(); } return value; } protected boolean isActiveItem(UIComponent kid) { return isActiveItem(kid, getActiveItemValue()); } protected boolean isActiveItem(UIComponent kid, String value) { if (kid == null || !(kid instanceof AbstractTogglePanelItemInterface)) { return false; } return isActiveItem((AbstractTogglePanelItemInterface) kid, value); } protected boolean isActiveItem(AbstractTogglePanelItemInterface item, String value) { if (item == null || value == null) { return false; } return item.getName().equals(value); } public TogglePanelVisitState visitTogglePanelItems( final AbstractTogglePanel panel, final TogglePanelVisitCallback callback) { FacesContext facesContext = getFacesContext(); EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED); final TogglePanelVisitState visitState = new TogglePanelVisitState(); VisitContext visitContext = new FullVisitContext(facesContext, hints); panel.visitTree( visitContext, new VisitCallback() { @Override public VisitResult visit(VisitContext context, UIComponent target) { if (target instanceof AbstractTogglePanelItemInterface) { AbstractTogglePanelItemInterface item = (AbstractTogglePanelItemInterface) target; visitState.setState(item.getName(), item); if (callback.visit(context.getFacesContext(), visitState) == VisitResult.COMPLETE) { visitState.setDynamic(item.isDynamicPanelItem()); return VisitResult.COMPLETE; } visitState.increment(); visitState.setState(null, null); return VisitResult.ACCEPT; } else if (AbstractTogglePanel.this == target || target instanceof UIRepeat) { return VisitResult.ACCEPT; } else { return VisitResult .REJECT; // target is not a source of toggle panel items for this toggle panel } } }); return visitState; } private TogglePanelVisitState getvisitStateByIndex(final int index) { TogglePanelVisitState visitState = visitTogglePanelItems( this, new TogglePanelVisitCallback() { @Override public VisitResult visit( FacesContext facesContext, TogglePanelVisitState visitState) { if (index == visitState.getCount()) { return VisitResult.COMPLETE; } else { return VisitResult.ACCEPT; } } }); return visitState; } public TogglePanelVisitState getVisitStateByName(final String name) { TogglePanelVisitState visitState = visitTogglePanelItems( this, new TogglePanelVisitCallback() { @Override public VisitResult visit( FacesContext facesContext, TogglePanelVisitState visitState) { if (name.equals(visitState.getName())) { return VisitResult.COMPLETE; } else { return VisitResult.ACCEPT; } } }); return visitState; } public AbstractTogglePanelItemInterface getItemByIndex(final int index) { TogglePanelVisitState visitState = getvisitStateByIndex(index); if (visitState.isDynamic()) { throw new TogglePanelVisitException( "Cannot access a dynamically generated AbstractToggleItemInterface directly. Use the visitor pattern instead."); } return visitState.getItem(); } public String getNameByIndex(final int index) { if (!this.isRendered()) { return null; } return getvisitStateByIndex(index).getName(); } public int getIndexByName(final String name) { if (!this.isRendered()) { return -1; } TogglePanelVisitState visitState = getVisitStateByName(name); if (visitState.getName() != null) { return visitState.getCount(); } else { return -1; } } public String getClientIdByName(final String name) { if (!this.isRendered()) { return null; } TogglePanelVisitState visitState = getVisitStateByName(name); if (visitState.getName() != null) { return visitState.getClientId(); } else { return null; } } public int getItemCount() { if (!this.isRendered()) { return 0; } TogglePanelVisitState visitState = visitTogglePanelItems( this, new TogglePanelVisitCallback() { @Override public VisitResult visit( FacesContext facesContext, TogglePanelVisitState visitState) { return VisitResult.ACCEPT; } }); return visitState.getCount(); } public AbstractTogglePanelItemInterface getItem(String name) { if (META_NAME_FIRST.equals(name)) { return getFirstItem(); } else if (META_NAME_PREV.equals(name)) { return getPrevItem(); } else if (META_NAME_NEXT.equals(name)) { return getNextItem(); } else if (META_NAME_LAST.equals(name)) { return getLastItem(); } else { return getItemByIndex(getChildIndex(name)); } } public AbstractTogglePanelItemInterface getFirstItem() { return getItemByIndex(0); } public AbstractTogglePanelItemInterface getPrevItem() { return getPrevItem(getActiveItem()); } public AbstractTogglePanelItemInterface getPrevItem(String name) { return getItemByIndex(getIndexByName(name) - 1); } public AbstractTogglePanelItemInterface getNextItem() { return getNextItem(getActiveItem()); } public AbstractTogglePanelItemInterface getNextItem(String name) { return getItemByIndex(getIndexByName(name) + 1); } public AbstractTogglePanelItemInterface getLastItem() { return getItemByIndex(getItemCount()); } @Deprecated public int getChildIndex(String name) { if (name == null) { throw new IllegalArgumentException("Name is required parameter."); } return getIndexByName(name); } // ------------------------------------------------ public String getSubmittedActiveItem() { return submittedActiveItem; } public void setSubmittedActiveItem(String submittedActiveItem) { this.submittedActiveItem = submittedActiveItem; } // ------------------------------------------------ Properties @Override @Attribute(hidden = true) public void setValue(Object value) { super.setValue(value); setLocalValueSet(true); } /** * Holds the active panel name. This name is a reference to the name identifier of the active * child <rich:togglePanelItem> component. */ @Attribute public String getActiveItem() { return (String) getValue(); } public void setActiveItem(String value) { setValue(value); } @Override public void setValueExpression(String name, ValueExpression binding) { if ("activeItem".equals(name)) { super.setValueExpression("value", binding); } else { super.setValueExpression(name, binding); } } /** * The switch mode when a panel is activated. One of: "client", "server", "ajax". Default: "ajax" */ @Attribute(generate = false) public SwitchType getSwitchType() { SwitchType switchType = (SwitchType) getStateHelper().eval(PropertyKeys.switchType); if (switchType == null) { switchType = SwitchType.DEFAULT; } return switchType; } public void setSwitchType(SwitchType switchType) { getStateHelper().put(PropertyKeys.switchType, switchType); } @Attribute(hidden = true) public abstract boolean isLimitRender(); /** * Applicable when cycling through the tabs. If "true", then when the last tab is active, cycling * to next will activate the first tab, if "false", cycling to next will have not effect. The * inverse applies for the first tab, and cycling to previous. Whether to Default: false */ @Attribute public abstract boolean isCycledSwitching(); @Attribute(hidden = true) public abstract Object getData(); @Attribute(hidden = true) public abstract String getStatus(); @Attribute(hidden = true) public abstract Object getExecute(); @Attribute(hidden = true) public abstract Object getRender(); /** Occurs on the server side when an item is changed through Ajax using the server mode */ @Attribute public abstract MethodExpression getItemChangeListener(); /** The client-side script method to be called after the item is changed. */ @Attribute(events = @EventName("itemchange")) public abstract String getOnitemchange(); /** The client-side script method to be called before the item is changed. */ @Attribute(events = @EventName("beforeitemchange")) public abstract String getOnbeforeitemchange(); // ------------------------------------------------ Event Processing Methods public void addItemChangeListener(ItemChangeListener listener) { addFacesListener(listener); } public ItemChangeListener[] getItemChangeListeners() { return (ItemChangeListener[]) getFacesListeners(ItemChangeListener.class); } public void removeItemChangeListener(ItemChangeListener listener) { removeFacesListener(listener); } public String resolveClientId( FacesContext facesContext, UIComponent contextComponent, String metaComponentId) { if (ACTIVE_ITEM_META_COMPONENT.equals(metaComponentId)) { return getClientId(facesContext) + MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR + metaComponentId; } return null; } public String substituteUnresolvedClientId( FacesContext facesContext, UIComponent contextComponent, String metaComponentId) { return null; } public void encodeMetaComponent(FacesContext facesContext, String metaComponentId) throws IOException { ((MetaComponentRenderer) getRenderer(facesContext)) .encodeMetaComponent(facesContext, this, metaComponentId); } @Override public boolean visitTree(VisitContext context, VisitCallback callback) { if (!isVisitable(context)) { return false; } FacesContext facesContext = context.getFacesContext(); pushComponentToEL(facesContext, null); try { VisitResult result = context.invokeVisitCallback(this, callback); if (result == VisitResult.COMPLETE) { return true; } if (result == VisitResult.ACCEPT) { if (context instanceof ExtendedVisitContext) { ExtendedVisitContext extendedVisitContext = (ExtendedVisitContext) context; if (extendedVisitContext.getVisitMode() == ExtendedVisitContextMode.RENDER) { result = extendedVisitContext.invokeMetaComponentVisitCallback( this, callback, ACTIVE_ITEM_META_COMPONENT); if (result == VisitResult.COMPLETE) { return true; } } } } if (result == VisitResult.ACCEPT) { Iterator<UIComponent> kids = this.getFacetsAndChildren(); while (kids.hasNext()) { boolean done = kids.next().visitTree(context, callback); if (done) { return true; } } } } finally { popComponentFromEL(facesContext); } return false; } }