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 { } } |
public class JQueryBehavior extends JQueryAbstractBehavior { private static final long serialVersionUID = 1L; private static final String NULL_OPTIONS = "Options have not been defined (null has been supplied to the constructor)"; private final String selector; private final String method; private final Options options; private List<String> events = null; /** * Constructor * @param selector the html selector (ie: "#myId") */ public JQueryBehavior(String selector) { this(selector, ""); } /** * Constructor * @param selector the html selector (ie: "#myId") * @param method the jquery method */ public JQueryBehavior(String selector, String method) { this(selector, method, new Options()); } /** * Constructor * @param selector the html selector (ie: "#myId") * @param method the jquery method * @param options the {@link Options} */ public JQueryBehavior(String selector, String method, Options options) { super(method); this.method = method; this.options = options; this.selector = selector; } // Methods // @Override public void renderHead(Component component, IHeaderResponse response) { super.renderHead(component, response); // renders javascript events if (this.events != null) { StringBuilder statements = new StringBuilder("jQuery(function() { "); for (String event : this.events) { statements.append(event); } statements.append(" });"); response.render(JavaScriptHeaderItem.forScript(statements, this.getToken() + "-events")); } } // Properties // /** * Gets the selector * @return the selector */ //XXX: report as new (and this.selector private) public String getSelector() { return this.selector; } /** * Gets the jQuery method * @return the method */ //XXX: report as new (and this.method private) public String getMethod() { return this.method; } /** * Gets a behavior option, referenced by its key * @param key the option key * @return null if the key does not exists */ public Object getOption(String key) { if (this.options == null) { throw new WicketRuntimeException(NULL_OPTIONS); } return this.options.get(key); } /** * Sets a behavior option. * @param key the option key * @param value the option value * @return the {@link JQueryBehavior} (this) */ public JQueryBehavior setOption(String key, Serializable value) { if (this.options == null) { throw new WicketRuntimeException(NULL_OPTIONS); } this.options.set(key, value); return this; } /** * Gets the {@link Options} * @return the {@link Options} */ //XXX: report as new (and this.options private) public Options getOptions() { return this.options; } /** * Adds or replace behavior options * @param options the {@link Options} */ public void setOptions(Options options) { for (Entry<String, Serializable> option : options.entries()) { this.setOption(option.getKey(), option.getValue()); } } // Statements // /** * Registers a jQuery event callback * @param event the jQuery event (ie: "click") * @param callback the jQuery callback */ protected void on(String event, String callback) { this.on(this.selector, event, callback); } /** * Registers a jQuery event callback * @param selector the html selector (ie: "#myId") * @param event the jQuery event (ie: "click") * @param callback the jQuery callback */ protected void on(String selector, String event, String callback) { if (this.events == null) { this.events = new ArrayList<String>(); } this.events.add(String.format("jQuery('%s').on('%s', %s);", selector, event, callback)); } @Override protected String $() { return JQueryBehavior.$(this.selector, this.method, this.options.toString()); } /** * Gets the jQuery statement.<br/> * <b>Warning: </b> This method is *not* called by the behavior directly (only {@link #$()} is). * @param options the list of options to be supplied to the current method * @return Statement like 'jQuery(function() { ... })' */ public String $(Object... options) { return this.$(Options.fromList(options)); } /** * Gets the jQuery statement.<br/> * <b>Warning: </b> This method is *not* called by the behavior directly (only {@link #$()} is). * @param options the options to be supplied to the current method * @return Statement like 'jQuery(function() { ... })' */ public String $(String options) { return JQueryBehavior.$(this.selector, this.method, options); } /** * Gets the jQuery statement. * @param selector the html selector (ie: "#myId") * @param method the jQuery method to invoke * @param options the options to be applied * @return Statement like 'jQuery(function() { ... })' */ private static String $(String selector, String method, String options) { return String.format("jQuery(function() { jQuery('%s').%s(%s); });", selector, method, options); } // Events // @Override public void onConfigure(Component component) { super.onConfigure(component); if (component instanceof IJQueryWidget) { ((IJQueryWidget)component).onConfigure(this); } } @Override public void beforeRender(Component component) { super.beforeRender(component); if (component instanceof IJQueryWidget) { ((IJQueryWidget)component).onBeforeRender(this); } } } |
public abstract class JQueryAbstractBehavior extends Behavior { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(JQueryAbstractBehavior.class); /** * Gets the {@link IJQueryLibrarySettings} * @return the {@link IJQueryLibrarySettings} */ public static IJQueryLibrarySettings getJQueryLibrarySettings() { if (Application.exists() && (Application.get().getJavaScriptLibrarySettings() instanceof IJQueryLibrarySettings)) { return (IJQueryLibrarySettings) Application.get().getJavaScriptLibrarySettings(); } return JQueryLibrarySettings.get(); } /** * Behavior name */ private final String name; /** * Additional references */ private final List<ResourceReference> references; /** * Constructor. * @param name the name of the behavior. It is used in the token so the behavior can be identified in the generated page. */ public JQueryAbstractBehavior(final String name) { this.name = name; this.references = new ArrayList<ResourceReference>(); } /** * Adds a reference to be added at {@link #renderHead(Component, IHeaderResponse)} time. * @param reference a {@link CssResourceReference}, a {@link JavaScriptResourceReference} or a {@link JQueryPluginResourceReference} * @return true (as specified by Collection.add(E)) */ public boolean add(ResourceReference reference) { return this.references.add(reference); } @Override public void renderHead(Component component, IHeaderResponse response) { // Gets the library settings // IJQueryLibrarySettings settings = getJQueryLibrarySettings(); // jQuery UI resource reference // if (settings.getJQueryUIReference() != null) { response.render(new PriorityHeaderItem(JavaScriptHeaderItem.forReference(settings.getJQueryUIReference()))); } // jQuery Globalize resource reference // if (settings.getJQueryGlobalizeReference() != null) { response.render(new PriorityHeaderItem(JavaScriptHeaderItem.forReference(settings.getJQueryGlobalizeReference()))); } // Additional resource references // for(ResourceReference reference : this.references) { if (reference instanceof CssResourceReference) { response.render(new PriorityHeaderItem(CssHeaderItem.forReference(reference))); } if (reference instanceof JavaScriptResourceReference) { response.render(new PriorityHeaderItem(JavaScriptHeaderItem.forReference(reference))); } } // Adds the statement // AjaxRequestTarget target = component.getRequestCycle().find(AjaxRequestTarget.class); if (target != null) { target.appendJavaScript(this.toString()); } else { this.renderScript(JavaScriptHeaderItem.forScript(this.toString(), this.getToken()), response); } } /** * Renders the {@link Behavior}'s javascript<br/> * This can be overridden to provides a priority:</br> * <code>response.render(new PriorityHeaderItem(item));</code> * * @param script the {@link JavaScriptHeaderItem} * @param response the {@link IHeaderResponse} */ protected void renderScript(JavaScriptHeaderItem script, IHeaderResponse response) { response.render(script); } /** * Gets the jQuery statement. * @return Statement like 'jQuery(function() { ... })' */ protected abstract String $(); // Properties // /** * Get the unique behavior token that act as the script id. * @return the token */ String getToken() { return String.format("jquery-%s-%d", this.name, this.hashCode()); } // Events // @Override public void onConfigure(Component component) { super.onConfigure(component); if (Application.exists() && Application.get().usesDevelopmentConfig()) { if (!Application.get().getMarkupSettings().getStripWicketTags()) { LOG.warn("Application>MarkupSettings>StripWicketTags setting is currently set to false. It is highly recommended to set it to true to prevent widget misbehaviors."); } } } @Override public final String toString() { return this.$(); } } |
public interface IJQueryAjaxAware { void onAjax(AjaxRequestTarget target, JQueryEvent event); } |
interface IDialogListener { /** * Indicates whether the default close event (the click on the X-icon) is enabled * If true, the {@link #onClose(AjaxRequestTarget, DialogButton)} event will be triggered, with a null {@link DialogButton} * * @return 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 {@link DialogBehavior#close(AjaxRequestTarget)} is called. * @param target the {@link AjaxRequestTarget} * @param button the button that closed the dialog */ void onClick(AjaxRequestTarget target, DialogButton button); /** * Triggered when the dialog closes. * @param target the {@link AjaxRequestTarget} * @param button the button that closed the dialog */ void onClose(AjaxRequestTarget target, DialogButton button); } |