/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 com.googlecode.wicket.jquery.ui.widget.dialog; import java.io.Serializable; import java.util.Arrays; import java.util.List; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import com.googlecode.wicket.jquery.core.IJQueryWidget; import com.googlecode.wicket.jquery.core.JQueryBehavior; import com.googlecode.wicket.jquery.core.JQueryPanel; import com.googlecode.wicket.jquery.core.Options; import com.googlecode.wicket.jquery.core.ajax.IJQueryAjaxAware; import com.googlecode.wicket.jquery.ui.interaction.behavior.DisplayNoneBehavior; import com.googlecode.wicket.jquery.ui.widget.dialog.DialogBehavior.ButtonAjaxBehavior; /** * Base class for implementing jQuery dialogs * Sebastien Briquet - sebfz1 * * @param <T> the type of the model object */ public abstract class AbstractDialog<T extends Serializable> extends JQueryPanel implements IDialogListener { private static final long serialVersionUID = 1L; /* Default Button labels */ public static final String LBL_OK = "OK"; public static final String LBL_NO = "No"; public static final String LBL_YES = "Yes"; public static final String LBL_CLOSE = "Close"; public static final String LBL_CANCEL = "Cancel"; public static final String LBL_SUBMIT = "Submit"; /** Default width */ private static final int WIDTH = 450; private IModel<String> title; private boolean modal; private DialogBehavior widgetBehavior; /** Default button */ private final DialogButton btnOk = new DialogButton(LBL_OK); /** * Constructor * @param id the markupId, an html div suffice to host a dialog. * @param title the title of the dialog */ public AbstractDialog(String id, String title) { this(id, title, null, true); } /** * Constructor * @param id the markupId, an html div suffice to host a dialog. * @param title the title of the dialog */ public AbstractDialog(String id, IModel<String> title) { this(id, title, null, true); } /** * Constructor * @param id the markupId, an html div suffice to host a dialog. * @param title the title of the dialog * @param model the model to be used in the dialog. */ public AbstractDialog(String id, String title, IModel<T> model) { this(id, title, model, true); } /** * Constructor * @param id the markupId, an html div suffice to host a dialog. * @param title the title of the dialog * @param model the model to be used in the dialog. */ public AbstractDialog(String id, IModel<String> title, IModel<T> model) { this(id, title, model, true); } /** * Constructor * @param id the markupId, an html div suffice to host a dialog. * @param title the title of the dialog * @param modal indicates whether the dialog is modal */ public AbstractDialog(String id, String title, boolean modal) { this(id, title, null, modal); } /** * Constructor * @param id the markupId, an html div suffice to host a dialog. * @param title the title of the dialog * @param modal indicates whether the dialog is modal */ public AbstractDialog(String id, IModel<String> title, boolean modal) { this(id, title, null, modal); } /** * Constructor * @param id markupId, an html div suffice to host a dialog. * @param title the title of the dialog * @param modal indicates whether the dialog is modal * @param model the model to be used in the dialog */ public AbstractDialog(String id, String title, IModel<T> model, boolean modal) { this(id, Model.of(title), model, modal); } /** * Constructor * @param id markupId, an html div suffice to host a dialog. * @param title the title of the dialog * @param modal indicates whether the dialog is modal * @param model the model to be used in the dialog */ public AbstractDialog(String id, IModel<String> title, IModel<T> model, boolean modal) { super(id, model); this.title = title; this.modal = modal; this.add(new DisplayNoneBehavior()); //enhancement, fixes issue #22 this.setOutputMarkupPlaceholderTag(true); } // Events // @Override protected void onInitialize() { super.onInitialize(); this.add(this.widgetBehavior = this.newWidgetBehavior(JQueryWidget.getSelector(this))); //warning: ButtonAjaxBehavior(s) should be set at this point! } @Override public void onConfigure(JQueryBehavior behavior) { // class options // behavior.setOption("autoOpen", false); behavior.setOption("title", Options.asString(this.title.getObject())); behavior.setOption("modal", this.modal); behavior.setOption("resizable", this.isResizable()); behavior.setOption("width", this.getWidth()); } /** * Triggered when the dialog opens * @param target the { AjaxRequestTarget} */ protected void onOpen(AjaxRequestTarget target) { } /** * Triggered when a button is clicked. * This method may be overridden to handle button behaviors, but the dialog will not been closed until <code>super.onClick(event)</code> or { #close(AjaxRequestTarget, DialogButton)} is called. */ @Override public void onClick(AjaxRequestTarget target, DialogButton button) { this.close(target, button); } /** * Internal onClick method, fired by the behavior<br/> * The purpose of this method is to prevent the behavior calling { #onClick(AjaxRequestTarget, DialogButton)} directly, as <code>onClick</code> is implemented by default * * @param target the { AjaxRequestTarget} * @param button the { DialogButton} */ void internalOnClick(AjaxRequestTarget target, DialogButton button) { this.onClick(target, button); } // Properties // /** * Gets the dialog's buttons.<br/> * It is allowed to return a predefined list (ie: DialogButtons#OK_CANCEL#toList()) as long as the buttons state (enable and/or visible) are not modified<br/> * <b>Warning: </b>It is not legal to create the buttons to be returned in this method. * { #btnOk} by default */ protected List<DialogButton> getButtons() { return Arrays.asList(this.btnOk); } /** * Gets the dialog's with * { #WIDTH} by default */ public int getWidth() { return AbstractDialog.WIDTH; } /** * Gets the dialog's title * the dialog's title */ public IModel<String> getTitle() { return this.title; } /** * Sets the dialog's title * @param title the dialog's title */ public void setTitle(IModel<String> title) { if (title == null) { throw new IllegalArgumentException("argument title must be not null"); } this.title = title; } /** * Gets the modal flag * the modal flag supplied to the constructor by default */ public boolean isModal() { return this.modal; } /** * Indicated whether the dialog is resizable * false by default */ public boolean isResizable() { return false; } @Override public boolean isDefaultCloseEventEnabled() { return false; } /** * Gets the model * the parameterized model */ @SuppressWarnings("unchecked") public IModel<T> getModel() { return (IModel<T>)this.getDefaultModel(); } /** * Gets the model object * the typed model object */ @SuppressWarnings("unchecked") public T getModelObject() { return (T)this.getDefaultModelObject(); } /** * Sets the model object * @param object the typed model object */ public void setModelObject(T object) { this.setDefaultModelObject(object); } // Methods // /** * Finds a { DialogButton} - identified by its text - within the list of buttons returned by { #getButtons()} * @param text the button's text * the { DialogButton} if found, null otherwise */ public DialogButton findButton(String text) { for (DialogButton button : this.getButtons()) { if (button != null && button.equals(text)) { return button; } } return null; } /** * Opens the dialogs in ajax. * * @param target the { AjaxRequestTarget} */ public final void open(AjaxRequestTarget target) { this.onOpen(target); if (this.widgetBehavior != null) { this.widgetBehavior.open(target); } } /** * Closes the dialogs in ajax. * * @param target the { AjaxRequestTarget} * @param button the button that closes the dialog */ public final void close(AjaxRequestTarget target, DialogButton button) { if (this.widgetBehavior != null) { this.widgetBehavior.close(target); } this.onClose(target, button); } // IJQueryWidget // /** * IJQueryWidget#newWidgetBehavior(String) */ @Override public DialogBehavior newWidgetBehavior(String selector) { return new DialogBehavior(selector) { private static final long serialVersionUID = 1L; @Override public boolean isDefaultCloseEventEnabled() { return AbstractDialog.this.isDefaultCloseEventEnabled(); } @Override protected List<DialogButton> getButtons() { return AbstractDialog.this.getButtons(); } @Override public void onClick(AjaxRequestTarget target, DialogButton button) { AbstractDialog.this.internalOnClick(target, button); } @Override public void onClose(AjaxRequestTarget target, DialogButton button) { AbstractDialog.this.onClose(target, button); } @Override protected ButtonAjaxBehavior newButtonAjaxBehavior(IJQueryAjaxAware source, DialogButton button) { return AbstractDialog.this.newButtonAjaxBehavior(source, button); } }; } /** * Gets a new { ButtonAjaxBehavior} that will be called by the corresponding { DialogButton}.<br/> * This method mays be overridden internally to provide another behavior * * @param source the { IJQueryAjaxAware} source * @param button the button that is passed to the behavior so it can be retrieved via the <code>DialogBehavior#ClickEvent</code> * the { ButtonAjaxBehavior} */ protected ButtonAjaxBehavior newButtonAjaxBehavior(IJQueryAjaxAware source, DialogButton button) { return new ButtonAjaxBehavior(source, button); } } |
/** * Event listener shared by the { AbstractDialog} widget and the { DialogBehavior} * * Sebastien Briquet - sebfz1 * */ interface IDialogListener { /** * Indicates whether the default close event (the click on the X-icon) is enabled * If true, the { #onClose(AjaxRequestTarget, DialogButton)} event will be triggered, with a null { DialogButton} * * false by default */ boolean isDefaultCloseEventEnabled(); /** * Triggered when a button is clicked. * This method may be overridden to handle button behaviors, but the dialog will not been closed until <code>super.onClick(event)</code> or { DialogBehavior#close(AjaxRequestTarget)} is called. * @param target the { AjaxRequestTarget} * @param button the button that closed the dialog */ void onClick(AjaxRequestTarget target, DialogButton button); /** * Triggered when the dialog closes. * @param target the { AjaxRequestTarget} * @param button the button that closed the dialog */ void onClose(AjaxRequestTarget target, DialogButton button); } |
public abstract class AbstractFormDialog<T extends Serializable> extends AbstractDialog<T> { private static final long serialVersionUID = 1L; /** * Constructor * @param id the markup id * @param title the dialog's title */ public AbstractFormDialog(String id, String title) { super(id, title); } /** * Constructor * @param id the markup id * @param title the dialog's title */ public AbstractFormDialog(String id, IModel<String> title) { super(id, title); } /** * Constructor * @param id the markup id * @param title the dialog's title * @param model the dialog's model */ public AbstractFormDialog(String id, String title, IModel<T> model) { super(id, title, model, true); } /** * Constructor * @param id the markup id * @param title the dialog's title * @param model the dialog's model */ public AbstractFormDialog(String id, IModel<String> title, IModel<T> model) { super(id, title, model, true); } /** * Constructor * @param id the markup id * @param title the dialog's title * @param modal indicates whether the dialog is modal */ public AbstractFormDialog(String id, String title, boolean modal) { super(id, title, modal); } /** * Constructor * @param id the markup id * @param title the dialog's title * @param modal indicates whether the dialog is modal */ public AbstractFormDialog(String id, IModel<String> title, boolean modal) { super(id, title, modal); } /** * Constructor * @param id the markup id * @param title the dialog's title * @param model the dialog's model * @param modal indicates whether the dialog is modal */ public AbstractFormDialog(String id, String title, IModel<T> model, boolean modal) { super(id, title, model, modal); } /** * Constructor * @param id the markup id * @param title the dialog's title * @param model the dialog's model * @param modal indicates whether the dialog is modal */ public AbstractFormDialog(String id, IModel<String> title, IModel<T> model, boolean modal) { super(id, title, model, modal); } // Properties // /** * Gets the button that is in charge to submit the form.<br/> * It should be in the list of buttons returned by { #getButtons()} * the submit button */ protected abstract DialogButton getSubmitButton(); /** * Returns whether form should be processed the default way. When false (default is true), all * validation and form updating is bypassed and the onSubmit method of that button is called * directly, and the onSubmit method of the parent form is not called. A common use for this is * to create a cancel button. * * defaultFormProcessing */ public boolean getDefaultFormProcessing() { return true; //default } /** * Gets the form to be validated by this dialog.<br/> * Warning, the onSubmit and the onError are being delegated to this dialog. However, it does not prevent the use of Form#onSubmit nor Form#onError * the form */ public abstract Form<?> getForm(); /** * Returns the form associated to the button.<br/> * It means that it will return the form if the button is the submit button and null otherwise. * The callback script will differ depending on this. * * @param button the dialog's button * the { Form} or <code>null</code> */ protected Form<?> getForm(DialogButton button) { if (button.equals(this.getSubmitButton())) { return this.getForm(); } return null; } // Events // @Override void internalOnClick(AjaxRequestTarget target, DialogButton button) { final Form<?> form = this.getForm(button); if (form != null) { form.process(new DialogFormSubmitter(target)); if (!form.hasError()) { this.onClick(target, button); //fires onClick (& closes the dialog by default) } } else { this.onClick(target, button); //fires onClick (& closes the dialog by default) } } @Override public void onClose(AjaxRequestTarget target, DialogButton button) { //not mandatory to override } /** * Triggered after { Form#onError()} (when the form processing has error(s)) * @param target */ protected abstract void onError(AjaxRequestTarget target); /** * Triggered after { Form#onSubmit()} (the form has been submitted and it does not have error) * @param target */ protected abstract void onSubmit(AjaxRequestTarget target); // Factories // /** * Gets the { FormButtonAjaxBehavior} associated to the specified button. * * the { ButtonAjaxBehavior} */ @Override protected ButtonAjaxBehavior newButtonAjaxBehavior(IJQueryAjaxAware source, DialogButton button) { return new FormButtonAjaxBehavior(source, button, this.getForm(button)); } /** * Provides the form-dialog { IFormSubmitter}<br/> * This is basically the same technic used in AjaxButton class. */ protected class DialogFormSubmitter implements IFormSubmitter { private final AjaxRequestTarget target; /** * Constructor * @param target the { AjaxRequestTarget} */ public DialogFormSubmitter(AjaxRequestTarget target) { this.target = target; } @Override public Form<?> getForm() { return AbstractFormDialog.this.getForm(); } @Override public boolean getDefaultFormProcessing() { return AbstractFormDialog.this.getDefaultFormProcessing(); } @Override public void onSubmit() { AbstractFormDialog.this.onSubmit(this.target); } @Override public void onError() { AbstractFormDialog.this.onError(this.target); } @Override public void onAfterSubmit() { //wicket6 } } /** * Provides the button's form-submit behavior */ protected static class FormButtonAjaxBehavior extends ButtonAjaxBehavior { private static final long serialVersionUID = 1L; private final Form<?> form; /** * Constructor * @param source the { IJQueryAjaxAware} * @param button the { DialogButton} * @param form the { Form} */ public FormButtonAjaxBehavior(IJQueryAjaxAware source, DialogButton button, Form<?> form) { super(source, button); this.form = form; } /** * The formId may intentionally be null */ @Override protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { super.updateAjaxAttributes(attributes); if (this.form != null) { attributes.setMethod(Method.POST); attributes.setFormId(this.form.getMarkupId()); } } } } |
AbstractDialog 依赖DialogBehavior
public abstract class DialogBehavior extends JQueryBehavior implements IJQueryAjaxAware, IDialogListener { private static final long serialVersionUID = 1L; private static final String METHOD = "dialog"; private JQueryAjaxBehavior onDefaultClose = null; /** * Constructor * * @param selector the html selector (ie: "#myId") */ public DialogBehavior(String selector) { super(selector, METHOD); } /** * Constructor * * @param selector the html selector (ie: "#myId") * @param options the {@link Options} */ public DialogBehavior(String selector, Options options) { super(selector, METHOD, options); } // Properties // /** * Gets the dialog's buttons.<br/> * * @return the {@link List} of {@link Button} */ protected abstract List<DialogButton> getButtons(); // Methods // @Override public void bind(Component component) { super.bind(component); for (DialogButton button : this.getButtons()) { component.add(this.newButtonAjaxBehavior(this, button)); } if (this.isDefaultCloseEventEnabled()) { component.add(this.onDefaultClose = this.newDefaultCloseBehavior()); } } /** * Opens the dialogs in ajax.<br/> * @param target the {@link AjaxRequestTarget} */ public void open(AjaxRequestTarget target) { target.appendJavaScript(this.$("'open'")); } /** * Closes the dialogs in ajax.<br/> * @param target the {@link AjaxRequestTarget} */ public void close(AjaxRequestTarget target) { target.appendJavaScript(this.$("'close'")); } // Events // @Override public void onConfigure(Component component) { super.onConfigure(component); if (this.onDefaultClose != null) { this.setOption("close", this.onDefaultClose.getCallbackFunction()); } // buttons events // StringBuffer buttons = new StringBuffer("[ "); int index = 0; for(ButtonAjaxBehavior behavior : component.getBehaviors(ButtonAjaxBehavior.class)) { DialogButton button = behavior.getButton(); if (index++ > 0) { buttons.append(", "); } buttons.append("{"); buttons.append("'id': '").append(button.getMarkupId()).append("', "); buttons.append("'text': '").append(button.toString()).append("', "); if (!button.isEnabled()) { buttons.append("'disabled': true, "); } if (button.getIcon() != null) { buttons.append("icons: { primary: '").append(button.getIcon()).append("' }, "); } buttons.append("'click': function() { ").append(behavior.getCallbackScript()).append(" }"); buttons.append("}"); } buttons.append(" ]"); this.setOption("buttons", buttons); } @Override public void onAjax(AjaxRequestTarget target, JQueryEvent event) { if (event instanceof ClickEvent) { this.onClick(target, ((ClickEvent) event).getButton()); } else if (event instanceof CloseEvent) { this.onClose(target, null); } } // Factories // /** * Gets a new ButtonAjaxBehavior that will be called by the corresponding dialog's button.<br/> * This method mays be overridden internally to provide another behavior; * * @param source the {@link IJQueryAjaxAware} source * @param button the button that is passed to the behavior so it can be retrieved via the {@link ClickEvent} * @return the {@link ButtonAjaxBehavior} */ protected abstract ButtonAjaxBehavior newButtonAjaxBehavior(IJQueryAjaxAware source, DialogButton button); /** * Gets the ajax behavior that will be triggered when the user clicks on the X-icon * * @return the {@link JQueryAjaxBehavior} */ protected JQueryAjaxBehavior newDefaultCloseBehavior() { return new JQueryAjaxBehavior(this) { private static final long serialVersionUID = 1L; @Override public String getCallbackFunction() { return "function(event, ui) { if (event.button == 0) { " + this.getCallbackScript() + " } }"; } @Override protected JQueryEvent newEvent() { return new CloseEvent(); } }; } // Ajax behaviors // /** * Provides the {@link JQueryAjaxBehavior} being called by the button(s). */ protected static class ButtonAjaxBehavior extends JQueryAjaxBehavior { private static final long serialVersionUID = 1L; private final DialogButton button; /** * Constructor * @param source the {@link IJQueryAjaxAware} * @param button the {@link DialogButton} to attach to the {@link ClickEvent} */ public ButtonAjaxBehavior(IJQueryAjaxAware source, DialogButton button) { super(source); this.button = button; } /** * Gets the {@link DialogButton} * @return the {@link DialogButton} */ public DialogButton getButton() { return this.button; } @Override protected JQueryEvent newEvent() { return new ClickEvent(this.button); } } // Events classes // /** * Provides a dialog event that will be transmitted to the {@link AbstractDialog} */ protected static class ClickEvent extends JQueryEvent { private final DialogButton button; public ClickEvent(DialogButton button) { super(); this.button = button; } /** * Get the button that has been attached to this event object * @return the button */ public DialogButton getButton() { return this.button; } } /** * An event object that will be broadcasted when the user clicks on the X-icon */ protected static class CloseEvent extends JQueryEvent { } } |
JqueryEvent
public class JQueryEvent { /** * Constructor. */ public JQueryEvent() { } } |
public abstract class JQueryAjaxBehavior extends AbstractDefaultAjaxBehavior { private static final long serialVersionUID = 1L; private final IJQueryAjaxAware source; private final Duration duration; /** * Constructor * @param source {@link Behavior} to which the event - returned by {@link #newEvent()} - will be broadcasted. */ public JQueryAjaxBehavior(IJQueryAjaxAware source) { this(source, Duration.NONE); } /** * Constructor * @param source {@link Behavior} to which the event - returned by {@link #newEvent()} - will be broadcasted. * @param duration {@link Duration}. If different than {@link Duration#NONE}, an {@link ThrottlingSettings} will be added with the specified {@link Duration}. */ public JQueryAjaxBehavior(IJQueryAjaxAware source, Duration duration) { this.source = source; this.duration = duration; } @Override protected void respond(AjaxRequestTarget target) { if (this.source != null) { this.source.onAjax(target, this.newEvent()); } } /** * Gets the {@link JQueryEvent} to be broadcasted to the {@link IJQueryAjaxAware} source when the behavior will respond * @return the {@link JQueryEvent} */ protected abstract JQueryEvent newEvent(); // wicket 6.x // @Override protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { super.updateAjaxAttributes(attributes); if (this.duration != Duration.NONE) { attributes.setThrottlingSettings(new ThrottlingSettings("jquery-throttle", this.duration)); } } /** * Gets the {@link CallbackParameter}<code>s</code> that *may* be passed to {@link #getCallbackFunction(CallbackParameter...)}<br/> * This is a convenience method that allows to define {@link CallbackParameter}<code>s</code> before the invocation of {@link #getCallbackFunction(CallbackParameter...)}. * * @return an array of {@link CallbackParameter} * @see #getCallbackFunction() */ protected CallbackParameter[] getCallbackParameters() { return new CallbackParameter[] {}; } /** * Calls {@link #getCallbackFunction(CallbackParameter...)} by passing {@link CallbackParameter}<code>s</code> from {@link #getCallbackParameters()} * * @return the javascript function. */ public String getCallbackFunction() { return super.getCallbackFunction(this.getCallbackParameters()).toString(); } } |
public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior { private static final long serialVersionUID = 1L; /** reference to the default indicator gif file. */ public static final ResourceReference INDICATOR = new PackageResourceReference( AbstractDefaultAjaxBehavior.class, "indicator.gif"); private static final String DYNAMIC_PARAMETER_FUNCTION_TEMPLATE = "function(attrs){%s}"; private static final String PRECONDITION_FUNCTION_TEMPLATE = "function(attrs){%s}"; private static final String COMPLETE_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, textStatus){%s}"; private static final String FAILURE_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, errorMessage, textStatus){%s}"; private static final String SUCCESS_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, data, textStatus){%s}"; private static final String AFTER_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}"; private static final String BEFORE_SEND_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, settings){%s}"; private static final String BEFORE_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}"; /** * Subclasses should call super.onBind() * * @see org.apache.wicket.behavior.AbstractAjaxBehavior#onBind() */ @Override protected void onBind() { getComponent().setOutputMarkupId(true); } /** * @see org.apache.wicket.behavior.AbstractAjaxBehavior#renderHead(Component, * org.apache.wicket.markup.head.IHeaderResponse) */ @Override public void renderHead(final Component component, final IHeaderResponse response) { super.renderHead(component, response); CoreLibrariesContributor.contributeAjax(component.getApplication(), response); RequestCycle requestCycle = component.getRequestCycle(); Url baseUrl = requestCycle.getUrlRenderer().getBaseUrl(); CharSequence ajaxBaseUrl = Strings.escapeMarkup(baseUrl.toString()); response.render(JavaScriptHeaderItem.forScript("Wicket.Ajax.baseUrl=\"" + ajaxBaseUrl + "\";", "wicket-ajax-base-url")); renderExtraHeaderContributors(component, response); } /** * Renders header contribution by IAjaxCallListener instances which additionally implement * IComponentAwareHeaderContributor interface. * * @param component * the component assigned to this behavior * @param response * the current header response */ private void renderExtraHeaderContributors(final Component component, final IHeaderResponse response) { AjaxRequestAttributes attributes = getAttributes(); List<IAjaxCallListener> ajaxCallListeners = attributes.getAjaxCallListeners(); for (IAjaxCallListener ajaxCallListener : ajaxCallListeners) { if (ajaxCallListener instanceof IComponentAwareHeaderContributor) { IComponentAwareHeaderContributor contributor = (IComponentAwareHeaderContributor)ajaxCallListener; contributor.renderHead(component, response); } } } /** * @return the Ajax settings for this behavior * @since 6.0 */ protected final AjaxRequestAttributes getAttributes() { AjaxRequestAttributes attributes = new AjaxRequestAttributes(); WebApplication application = (WebApplication)getComponent().getApplication(); AjaxRequestTargetListenerCollection ajaxRequestTargetListeners = application.getAjaxRequestTargetListeners(); for (AjaxRequestTarget.IListener listener : ajaxRequestTargetListeners) { if (listener instanceof AjaxRequestTarget.AbstractListener) { ((AjaxRequestTarget.AbstractListener)listener).updateAjaxAttributes(attributes); } } updateAjaxAttributesBackwardCompatibility(attributes); updateAjaxAttributes(attributes); return attributes; } /** * Gives a chance to the specializations to modify the attributes. * * @param attributes * @since 6.0 */ protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { } /** * The code below handles backward compatibility. * * @param attributes */ private void updateAjaxAttributesBackwardCompatibility(final AjaxRequestAttributes attributes) { AjaxCallListener backwardCompatibleAjaxCallListener = new AjaxCallListener(); backwardCompatibleAjaxCallListener.onSuccess(getSuccessScript()); backwardCompatibleAjaxCallListener.onFailure(getFailureScript()); backwardCompatibleAjaxCallListener.onPrecondition(getPreconditionScript()); attributes.getAjaxCallListeners().add(backwardCompatibleAjaxCallListener); AjaxChannel channel = getChannel(); if (channel != null) { attributes.setChannel(channel); } } /** * <pre> * { * u: 'editable-label?6-1.IBehaviorListener.0-text1-label', // url * m: 'POST', // method name. Default: 'GET' * c: 'label7', // component id (String) or window for page * e: 'click', // event name * sh: [], // list of success handlers * fh: [], // list of failure handlers * pre: [], // list of preconditions. If empty set default : Wicket.$(settings{c}) !== null * ep: {}, // extra parameters * async: true|false, // asynchronous XHR or not * ch: 'someName|d', // AjaxChannel * i: 'indicatorId', // indicator component id * ad: true, // allow default * } * </pre> * * @param component * the component with that behavior * @return the attributes as string in JSON format */ protected final CharSequence renderAjaxAttributes(final Component component) { AjaxRequestAttributes attributes = getAttributes(); return renderAjaxAttributes(component, attributes); } /** * * @param component * @param attributes * @return the attributes as string in JSON format */ protected final CharSequence renderAjaxAttributes(final Component component, AjaxRequestAttributes attributes) { JSONObject attributesJson = new JSONObject(); try { attributesJson.put(AjaxAttributeName.URL.jsonName(), getCallbackUrl()); Method method = attributes.getMethod(); if (Method.POST == method) { attributesJson.put(AjaxAttributeName.METHOD.jsonName(), method); } if (component instanceof Page == false) { String componentId = component.getMarkupId(); attributesJson.put(AjaxAttributeName.MARKUP_ID.jsonName(), componentId); } String formId = attributes.getFormId(); if (Strings.isEmpty(formId) == false) { attributesJson.put(AjaxAttributeName.FORM_ID.jsonName(), formId); } if (attributes.isMultipart()) { attributesJson.put(AjaxAttributeName.IS_MULTIPART.jsonName(), true); } String submittingComponentId = attributes.getSubmittingComponentName(); if (Strings.isEmpty(submittingComponentId) == false) { attributesJson.put(AjaxAttributeName.SUBMITTING_COMPONENT_NAME.jsonName(), submittingComponentId); } String indicatorId = findIndicatorId(); if (Strings.isEmpty(indicatorId) == false) { attributesJson.put(AjaxAttributeName.INDICATOR_ID.jsonName(), indicatorId); } for (IAjaxCallListener ajaxCallListener : attributes.getAjaxCallListeners()) { if (ajaxCallListener != null) { CharSequence beforeHandler = ajaxCallListener.getBeforeHandler(component); appendListenerHandler(beforeHandler, attributesJson, AjaxAttributeName.BEFORE_HANDLER.jsonName(), BEFORE_HANDLER_FUNCTION_TEMPLATE); CharSequence beforeSendHandler = ajaxCallListener.getBeforeSendHandler(component); appendListenerHandler(beforeSendHandler, attributesJson, AjaxAttributeName.BEFORE_SEND_HANDLER.jsonName(), BEFORE_SEND_HANDLER_FUNCTION_TEMPLATE); CharSequence afterHandler = ajaxCallListener.getAfterHandler(component); appendListenerHandler(afterHandler, attributesJson, AjaxAttributeName.AFTER_HANDLER.jsonName(), AFTER_HANDLER_FUNCTION_TEMPLATE); CharSequence successHandler = ajaxCallListener.getSuccessHandler(component); appendListenerHandler(successHandler, attributesJson, AjaxAttributeName.SUCCESS_HANDLER.jsonName(), SUCCESS_HANDLER_FUNCTION_TEMPLATE); CharSequence failureHandler = ajaxCallListener.getFailureHandler(component); appendListenerHandler(failureHandler, attributesJson, AjaxAttributeName.FAILURE_HANDLER.jsonName(), FAILURE_HANDLER_FUNCTION_TEMPLATE); CharSequence completeHandler = ajaxCallListener.getCompleteHandler(component); appendListenerHandler(completeHandler, attributesJson, AjaxAttributeName.COMPLETE_HANDLER.jsonName(), COMPLETE_HANDLER_FUNCTION_TEMPLATE); CharSequence precondition = ajaxCallListener.getPrecondition(component); appendListenerHandler(precondition, attributesJson, AjaxAttributeName.PRECONDITION.jsonName(), PRECONDITION_FUNCTION_TEMPLATE); } } JSONArray extraParameters = JsonUtils.asArray(attributes.getExtraParameters()); if (extraParameters.length() > 0) { attributesJson.put(AjaxAttributeName.EXTRA_PARAMETERS.jsonName(), extraParameters); } List<CharSequence> dynamicExtraParameters = attributes.getDynamicExtraParameters(); if (dynamicExtraParameters != null) { for (CharSequence dynamicExtraParameter : dynamicExtraParameters) { String func = String.format(DYNAMIC_PARAMETER_FUNCTION_TEMPLATE, dynamicExtraParameter); JsonFunction function = new JsonFunction(func); attributesJson.append(AjaxAttributeName.DYNAMIC_PARAMETER_FUNCTION.jsonName(), function); } } if (attributes.isAsynchronous() == false) { attributesJson.put(AjaxAttributeName.IS_ASYNC.jsonName(), false); } String[] eventNames = attributes.getEventNames(); if (eventNames.length == 1) { attributesJson.put(AjaxAttributeName.EVENT_NAME.jsonName(), eventNames[0]); } else { for (String eventName : eventNames) { attributesJson.append(AjaxAttributeName.EVENT_NAME.jsonName(), eventName); } } AjaxChannel channel = attributes.getChannel(); if (channel != null) { attributesJson.put(AjaxAttributeName.CHANNEL.jsonName(), channel); } if (attributes.isAllowDefault()) { attributesJson.put(AjaxAttributeName.IS_ALLOW_DEFAULT.jsonName(), true); } if (AjaxRequestAttributes.EventPropagation.BUBBLE.equals(attributes.getEventPropagation())) { attributesJson.put(AjaxAttributeName.EVENT_PROPAGATION.jsonName(), "bubble"); } else if (AjaxRequestAttributes.EventPropagation.STOP_IMMEDIATE.equals(attributes.getEventPropagation())) { attributesJson.put(AjaxAttributeName.EVENT_PROPAGATION.jsonName(), "stopImmediate"); } Duration requestTimeout = attributes.getRequestTimeout(); if (requestTimeout != null) { attributesJson.put(AjaxAttributeName.REQUEST_TIMEOUT.jsonName(), requestTimeout.getMilliseconds()); } boolean wicketAjaxResponse = attributes.isWicketAjaxResponse(); if (wicketAjaxResponse == false) { attributesJson.put(AjaxAttributeName.IS_WICKET_AJAX_RESPONSE.jsonName(), false); } String dataType = attributes.getDataType(); if (AjaxRequestAttributes.XML_DATA_TYPE.equals(dataType) == false) { attributesJson.put(AjaxAttributeName.DATATYPE.jsonName(), dataType); } ThrottlingSettings throttlingSettings = attributes.getThrottlingSettings(); if (throttlingSettings != null) { JSONObject throttlingSettingsJson = new JSONObject(); throttlingSettingsJson.put(AjaxAttributeName.THROTTLING_ID.jsonName(), throttlingSettings.getId()); throttlingSettingsJson.put(AjaxAttributeName.THROTTLING_DELAY.jsonName(), throttlingSettings.getDelay().getMilliseconds()); if (throttlingSettings.getPostponeTimerOnUpdate()) { throttlingSettingsJson.put( AjaxAttributeName.THROTTLING_POSTPONE_ON_UPDATE.jsonName(), true); } attributesJson.put(AjaxAttributeName.THROTTLING.jsonName(), throttlingSettingsJson); } postprocessConfiguration(attributesJson, component); } catch (JSONException e) { throw new WicketRuntimeException(e); } String attributesAsJson = attributesJson.toString(); return attributesAsJson; } private void appendListenerHandler(final CharSequence handler, final JSONObject attributesJson, final String propertyName, final String functionTemplate) throws JSONException { if (Strings.isEmpty(handler) == false) { final JsonFunction function; if (handler instanceof JsonFunction) { function = (JsonFunction)handler; } else { String func = String.format(functionTemplate, handler); function = new JsonFunction(func); } attributesJson.append(propertyName, function); } } /** * Gives a chance to modify the JSON attributesJson that is going to be used as attributes for * the Ajax call. * * @param attributesJson * the JSON object created by #renderAjaxAttributes() * @param component * the component with the attached Ajax behavior * @throws JSONException * thrown if an error occurs while modifying {@literal attributesJson} argument */ protected void postprocessConfiguration(JSONObject attributesJson, Component component) throws JSONException { } /** * @return javascript that will generate an ajax GET request to this behavior with its assigned * component */ public CharSequence getCallbackScript() { return getCallbackScript(getComponent()); } /** * @param component * the component to use when generating the attributes * @return script that can be used to execute this Ajax behavior. */ // 'protected' because this method is intended to be called by other Behavior methods which // accept the component as parameter protected CharSequence getCallbackScript(final Component component) { CharSequence ajaxAttributes = renderAjaxAttributes(component); return "Wicket.Ajax.ajax(" + ajaxAttributes + ");"; } /** * Generates a javascript function that can take parameters and performs an AJAX call which * includes these parameters. The generated code looks like this: * * <pre> * function(param1, param2) { * var attrs = attrsJson; * var params = {'param1': param1, 'param2': param2}; * attrs.ep = jQuery.extend(attrs.ep, params); * Wicket.Ajax.ajax(attrs); * } * </pre> * * @param extraParameters * @return A function that can be used as a callback function in javascript */ public CharSequence getCallbackFunction(CallbackParameter... extraParameters) { StringBuilder sb = new StringBuilder(); sb.append("function ("); boolean first = true; for (CallbackParameter curExtraParameter : extraParameters) { if (curExtraParameter.getFunctionParameterName() != null) { if (!first) sb.append(','); else first = false; sb.append(curExtraParameter.getFunctionParameterName()); } } sb.append(") {\n"); sb.append(getCallbackFunctionBody(extraParameters)); sb.append("}\n"); return sb; } /** * Generates the body the {@linkplain #getCallbackFunction(CallbackParameter...) callback * function}. To embed this code directly into a piece of javascript, make sure any context * parameters are available as local variables, global variables or within the closure. * * @param extraParameters * @return The body of the {@linkplain #getCallbackFunction(CallbackParameter...) callback * function}. */ public CharSequence getCallbackFunctionBody(CallbackParameter... extraParameters) { AjaxRequestAttributes attributes = getAttributes(); attributes.setEventNames(); CharSequence attrsJson = renderAjaxAttributes(getComponent(), attributes); StringBuilder sb = new StringBuilder(); sb.append("var attrs = "); sb.append(attrsJson); sb.append(";\n"); sb.append("var params = {"); boolean first = true; for (CallbackParameter curExtraParameter : extraParameters) { if (curExtraParameter.getAjaxParameterName() != null) { if (!first) sb.append(','); else first = false; sb.append('\'') .append(curExtraParameter.getAjaxParameterName()) .append("': ") .append(curExtraParameter.getAjaxParameterCode()); } } sb.append("};\n"); if (attributes.getExtraParameters().isEmpty()) sb.append("attrs." + AjaxAttributeName.EXTRA_PARAMETERS + " = params;\n"); else sb.append("attrs." + AjaxAttributeName.EXTRA_PARAMETERS + " = Wicket.merge(attrs." + AjaxAttributeName.EXTRA_PARAMETERS + ", params);\n"); sb.append("Wicket.Ajax.ajax(attrs);\n"); return sb; } /** * @return an optional javascript expression that determines whether the request will actually * execute (in form of return XXX;); * @deprecated Use {@link org.apache.wicket.ajax.attributes.AjaxRequestAttributes} */ @Deprecated protected CharSequence getPreconditionScript() { return null; } /** * @return javascript that will run when the ajax call finishes with an error status */ @Deprecated protected CharSequence getFailureScript() { return null; } /** * @return javascript that will run when the ajax call finishes successfully */ @Deprecated protected CharSequence getSuccessScript() { return null; } /** * Provides an AjaxChannel for this Behavior. * * @return an AjaxChannel - Defaults to null. * @deprecated Use {@link org.apache.wicket.ajax.attributes.AjaxRequestAttributes} */ @Deprecated protected AjaxChannel getChannel() { return null; } /** * Finds the markup id of the indicator. The default search order is: component, behavior, * component's parent hierarchy. * * @return markup id or <code>null</code> if no indicator found */ protected String findIndicatorId() { if (getComponent() instanceof IAjaxIndicatorAware) { return ((IAjaxIndicatorAware)getComponent()).getAjaxIndicatorMarkupId(); } if (this instanceof IAjaxIndicatorAware) { return ((IAjaxIndicatorAware)this).getAjaxIndicatorMarkupId(); } Component parent = getComponent().getParent(); while (parent != null) { if (parent instanceof IAjaxIndicatorAware) { return ((IAjaxIndicatorAware)parent).getAjaxIndicatorMarkupId(); } parent = parent.getParent(); } return null; } /** * @see org.apache.wicket.behavior.IBehaviorListener#onRequest() */ @Override public final void onRequest() { WebApplication app = (WebApplication)getComponent().getApplication(); AjaxRequestTarget target = app.newAjaxRequestTarget(getComponent().getPage()); RequestCycle requestCycle = RequestCycle.get(); requestCycle.scheduleRequestHandlerAfterCurrent(target); respond(target); } /** * @param target * The AJAX target */ protected abstract void respond(AjaxRequestTarget target); } |
wicket-jquery-ui 下载页面https://github.com/sebfz1/wicket-jquery-ui