/* Clients.java Purpose: Description: History: Fri May 26 14:25:06 2006, Created by tomyeh Copyright (C) 2006 Potix Corporation. All Rights Reserved. {{IS_RIGHT This program is distributed under LGPL Version 2.1 in the hope that it will be useful, but WITHOUT ANY WARRANTY. }}IS_RIGHT */ package org.zkoss.zk.ui.util; import java.util.List; import java.util.Locale; import org.zkoss.web.servlet.http.Encodes; import org.zkoss.zk.au.AuResponse; import org.zkoss.zk.au.out.AuAlert; import org.zkoss.zk.au.out.AuClearBusy; import org.zkoss.zk.au.out.AuClearWrongValue; import org.zkoss.zk.au.out.AuConfirmClose; import org.zkoss.zk.au.out.AuInvoke; import org.zkoss.zk.au.out.AuLoadCSS; import org.zkoss.zk.au.out.AuLoadScript; import org.zkoss.zk.au.out.AuLog; import org.zkoss.zk.au.out.AuMoveBy; import org.zkoss.zk.au.out.AuMoveTo; import org.zkoss.zk.au.out.AuNotification; import org.zkoss.zk.au.out.AuPrint; import org.zkoss.zk.au.out.AuResizeBy; import org.zkoss.zk.au.out.AuResizeTo; import org.zkoss.zk.au.out.AuResizeWidget; import org.zkoss.zk.au.out.AuScript; import org.zkoss.zk.au.out.AuScrollBy; import org.zkoss.zk.au.out.AuScrollIntoView; import org.zkoss.zk.au.out.AuScrollTo; import org.zkoss.zk.au.out.AuShowBusy; import org.zkoss.zk.au.out.AuSubmitForm; import org.zkoss.zk.au.out.AuWrongValue; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Execution; import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.sys.ExecutionCtrl; /** * Utilities to send {@link AuResponse} to the client. * * <p>Utilities here are mainly to control how the client (a.k.a., the browser window) * behaves. To get the status, you might refer to {@link org.zkoss.zk.ui.event.ClientInfoEvent}. * * @author tomyeh * @see org.zkoss.zk.ui.event.ClientInfoEvent */ public class Clients { /** Sends an AU response ({@link AuResponse}) to the client. * It is the same as <code>response(response.getOverrideKey(), response)</code>. * * @since 3.0.0 */ public static final void response(AuResponse response) { Executions.getCurrent().addAuResponse(response); } /** Sends an AU response ({@link AuResponse}) to the client * with the given key (instead of {@link AuResponse#getOverrideKey}). * * @param key could be anything. The second invocation of this method * in the same execution with the same key will override the previous one. * In other words, the previous one will be dropped. * If null is specified, the response is simply appended to the end * without overriding any previous one. * @since 3.0.4 * @see #response */ public static final void response(String key, AuResponse response) { Executions.getCurrent().addAuResponse(key, response); } /** Asks the browser to confirm users whether to close the browser window. * * <p>If an non-null (non-empty) string is set, the browser will show up * a confirmation dialog when an user tries to close the browser window, * or browse to another URL. * To reset (i.e., not showing any confirmation dialog), just call this * method again with null. * * @param mesg the message to show when confirming users. * If null (default) or empty, users can close the browser window directly. */ public static final void confirmClose(String mesg) { response(new AuConfirmClose(mesg)); } /** Shows an error message at the browser. * It works and looks similar to {@link org.zkoss.zul.Messagebox}. * However, it is not customizable (at the server), but it is * much faster and light-weighted. * @since 5.0.3 */ public static final void alert(String msg) { response(new AuAlert(msg)); } /** Shows an error message at the browser. * It is similar to {@link org.zkoss.zul.Messagebox}. * @param msg the message to display. * @param title the title of the message box * @param icon the icon to show. It could null, "QUESTION", "EXCLAMATION", "INFORMATION", "ERROR", "NONE". * If null, "ERROR" is assumed * @since 5.0.3 */ public static final void alert(String msg, String title, String icon) { response(new AuAlert(msg, title, icon)); } /** Shows an error message for the specified component, if any, * at the browser. * <p>You have to clear the error message manually with {@link #clearWrongValue}. * @since 5.0.0 */ public static final void wrongValue(Component comp, String msg) { response(new AuWrongValue(comp, msg)); } /** Closes the error message of the specified component, if any, * at the browser. * @since 5.0.0 */ public static final void clearWrongValue(Component comp) { response(new AuClearWrongValue(comp)); } /** Closes the error message of the specified components, if any, * at the browser. * @since 5.0.0 */ public static final void clearWrongValue(List<Component> comps) { response(new AuClearWrongValue(comps)); //append, not overwrite } /** Closes the error message of the specified components, if any, * at the browser. * @since 5.0.0 */ public static final void clearWrongValue(Component[] comps) { response(new AuClearWrongValue(comps)); //append, not overwrite } /** Submits the form with the specified ID. */ public static final void submitForm(String formId) { response(new AuSubmitForm(formId)); } /** Submits the form with the specified form. * It assumes the form component is a HTML form. */ public static final void submitForm(Component form) { submitForm(form.getUuid()); } /** Asks the client to print the current desktop (a.k.a., browser window). */ public static void print() { response(new AuPrint()); } /** Scrolls the ancestor elements to make the specified element visible. * @since 3.6.1 */ public static final void scrollIntoView(Component cmp) { response(new AuScrollIntoView(cmp)); } /** Scrolls the current desktop (a.k.a., browser window) by the specified number of pixels. * If the number passed is positive, the desktop is scrolled down. * If negative, it is scrolled up. * @see #scrollTo */ public static final void scrollBy(int x, int y) { response(new AuScrollBy(x, y)); } /** Scrolls the current desktop (a.k.a., browser window) to the specified location (in pixels). * * @see #scrollBy */ public static final void scrollTo(int x, int y) { response(new AuScrollTo(x, y)); } /** Resizes the current desktop (a.k.a., browser window) by the specified number of pixels. * If the numbers passed are positive, the desktop size is increased. * Negative numbers reduce the size of the desktop. * * @see #resizeTo */ public static final void resizeBy(int x, int y) { response(new AuResizeBy(x, y)); } /** Resizes the current desktop (a.k.a., browser window) to the specified size (in pixels). * * @see #resizeBy */ public static final void resizeTo(int x, int y) { response(new AuResizeTo(x, y)); } /** Moves the current desktop (a.k.a., browser window) by the specified number of pixels. * If the number passed is positive, the desktop is moved down. * If negative, it is moved up. * @see #moveTo */ public static final void moveBy(int x, int y) { response(new AuMoveBy(x, y)); } /** Moves the current desktop (a.k.a., browser window) to the specified location (in pixels). * * @see #moveBy */ public static final void moveTo(int x, int y) { response(new AuMoveTo(x, y)); } /** Asks the browser to evaluate the specified JavaScript. * <p>It has no effect if the client doesn't support JavaScript. * * @param javaScript the javaScript codes to run at the browser */ public static final void evalJavaScript(String javaScript) { response(new AuScript(null, javaScript)); } /** * Notification type: information */ public static final String NOTIFICATION_TYPE_INFO = "info"; /** * Notification type: warning */ public static final String NOTIFICATION_TYPE_WARNING = "warning"; /** * Notification type: error */ public static final String NOTIFICATION_TYPE_ERROR = "error"; /** * Shows a message at the center of the browser window. * @param msg the message to show * @since 6.0.1 */ public static final void showNotification(String msg) { showNotification(msg, null, null, null, -1, false); } /** * Shows a message at the center of the browser window. * @param msg the message to show * @param closable whether to close notification manually or not. If true there will be a * close button on notification message and won't close until user click the button * or duration time up, default false. * @since 6.5.0 */ public static final void showNotification(String msg, boolean closable) { showNotification(msg, null, null, null, -1, closable); } /** * Shows a message at the right side of the given component. * @param msg the message to show * @param ref the referenced component, null to be based on browser window * @since 6.0.1 */ public static final void showNotification(String msg, Component ref) { showNotification(msg, null, ref, null, -1, false); } /** * Shows a message at the right side of the given component. * @param msg the message to show * @param ref the referenced component, null to be based on browser window * @param closable whether to close notification manually or not. If true there will be a * close button on notification message and won't close until user click the button * or duration time up, default false. * @since 6.5.0 */ public static final void showNotification(String msg, Component ref, boolean closable) { showNotification(msg, null, ref, null, -1, closable); } /** * Displays a message. * @param msg the message to show * @param type available types are "info", "warning", "error" * @param ref the referenced component, null to be based on browser window * @param position predefined positions. * <p> Available options are: * <ul> * <li><b>before_start</b><br/> the message appears above the anchor, aligned to the left.</li> * <li><b>before_center</b><br/> the message appears above the anchor, aligned to the center.</li> * <li><b>before_end</b><br/> the message appears above the anchor, aligned to the right.</li> * <li><b>after_start</b><br/> the message appears below the anchor, aligned to the left.</li> * <li><b>after_center</b><br/> the message appears below the anchor, aligned to the center.</li> * <li><b>after_end</b><br/> the message appears below the anchor, aligned to the right.</li> * <li><b>start_before</b><br/> the message appears to the left of the anchor, aligned to the top.</li> * <li><b>start_center</b><br/> the message appears to the left of the anchor, aligned to the middle.</li> * <li><b>start_after</b><br/> the message appears to the left of the anchor, aligned to the bottom.</li> * <li><b>end_before</b><br/> the message appears to the right of the anchor, aligned to the top.</li> * <li><b>end_center</b><br/> the message appears to the right of the anchor, aligned to the middle.</li> * <li><b>end_after</b><br/> the message appears to the right of the anchor, aligned to the bottom.</li> * <li><b>overlap/top_left</b><br/> the message overlaps the anchor, with anchor and message aligned at top-left.</li> * <li><b>top_center</b><br/> the message overlaps the anchor, with anchor and message aligned at top-center.</li> * <li><b>overlap_end/top_right</b><br/> the message overlaps the anchor, with anchor and message aligned at top-right.</li> * <li><b>middle_left</b><br/> the message overlaps the anchor, with anchor and message aligned at middle-left.</li> * <li><b>middle_center</b><br/> the message overlaps the anchor, with anchor and message aligned at middle-center.</li> * <li><b>middle_right</b><br/> the message overlaps the anchor, with anchor and message aligned at middle-right.</li> * <li><b>overlap_before/bottom_left</b><br/> the message overlaps the anchor, with anchor and message aligned at bottom-left.</li> * <li><b>bottom_center</b><br/> the message overlaps the anchor, with anchor and message aligned at bottom-center.</li> * <li><b>overlap_after/bottom_right</b><br/> the message overlaps the anchor, with anchor and message aligned at bottom-right.</li> * <li><b>at_pointer</b><br/> the message appears with the upper-left aligned with the mouse cursor.</li> * <li><b>after_pointer</b><br/> the message appears with the top aligned with * the bottom of the mouse cursor, with the left side of the message at the horizontal position of the mouse cursor.</li> * </ul></p> * @param duration the duration of notification in millisecond. If zero or * negative the notification does not dismiss until user left-clicks outside * of the notification box. * @since 6.0.1 */ public static final void showNotification(String msg, String type, Component ref, String position, int duration) { showNotification(msg, type, ref, position, duration, false); } /** * Displays a message. * * @param msg the message to show * @param type available types are "info", "warning", "error" * @param ref the referenced component, null to be based on browser window * @param position predefined positions. * <p> Available options are: * <ul> * <li><b>before_start</b><br/> the message appears above the anchor, aligned to the left.</li> * <li><b>before_center</b><br/> the message appears above the anchor, aligned to the center.</li> * <li><b>before_end</b><br/> the message appears above the anchor, aligned to the right.</li> * <li><b>after_start</b><br/> the message appears below the anchor, aligned to the left.</li> * <li><b>after_center</b><br/> the message appears below the anchor, aligned to the center.</li> * <li><b>after_end</b><br/> the message appears below the anchor, aligned to the right.</li> * <li><b>start_before</b><br/> the message appears to the left of the anchor, aligned to the top.</li> * <li><b>start_center</b><br/> the message appears to the left of the anchor, aligned to the middle.</li> * <li><b>start_after</b><br/> the message appears to the left of the anchor, aligned to the bottom.</li> * <li><b>end_before</b><br/> the message appears to the right of the anchor, aligned to the top.</li> * <li><b>end_center</b><br/> the message appears to the right of the anchor, aligned to the middle.</li> * <li><b>end_after</b><br/> the message appears to the right of the anchor, aligned to the bottom.</li> * <li><b>overlap/top_left</b><br/> the message overlaps the anchor, with anchor and message aligned at top-left.</li> * <li><b>top_center</b><br/> the message overlaps the anchor, with anchor and message aligned at top-center.</li> * <li><b>overlap_end/top_right</b><br/> the message overlaps the anchor, with anchor and message aligned at top-right.</li> * <li><b>middle_left</b><br/> the message overlaps the anchor, with anchor and message aligned at middle-left.</li> * <li><b>middle_center</b><br/> the message overlaps the anchor, with anchor and message aligned at middle-center.</li> * <li><b>middle_right</b><br/> the message overlaps the anchor, with anchor and message aligned at middle-right.</li> * <li><b>overlap_before/bottom_left</b><br/> the message overlaps the anchor, with anchor and message aligned at bottom-left.</li> * <li><b>bottom_center</b><br/> the message overlaps the anchor, with anchor and message aligned at bottom-center.</li> * <li><b>overlap_after/bottom_right</b><br/> the message overlaps the anchor, with anchor and message aligned at bottom-right.</li> * <li><b>at_pointer</b><br/> the message appears with the upper-left aligned with the mouse cursor.</li> * <li><b>after_pointer</b><br/> the message appears with the top aligned with * the bottom of the mouse cursor, with the left side of the message at the horizontal position of the mouse cursor.</li> * </ul></p> * @param duration the duration of notification in millisecond. If zero or * negative the notification does not dismiss until user left-clicks outside * of the notification box. * @param closable whether to close notification manually or not. If true there will be a * close button on notification message and won't close until user click the button * or duration time up, default false. * @since 6.5.0 */ public static final void showNotification(String msg, String type, Component ref, String position, int duration, boolean closable) { Execution exec = Executions.getCurrent(); Page page = ref != null ? ref.getPage() : null; if (page == null && exec instanceof ExecutionCtrl) page = ((ExecutionCtrl) exec).getCurrentPage(); if (type == null) type = NOTIFICATION_TYPE_INFO; response(new AuNotification(msg, type, page, ref, position, duration, closable)); } /** * Displays a message. * @param msg the message to show * @param type available types are "info", "warning", "error" * @param ref the referenced component, null to be based on browser window * @param x the horizontal position of the notification, aligned at top-left (in pixel) * @param y the vertical position of the notification, aligned at top-left (in pixel) * @param duration the duration of notification in millisecond. If zero or * negative the notification does not dismiss until user left-clicks outside * of the notification box. * @since 6.0.1 */ public static final void showNotification(String msg, String type, Component ref, int x, int y, int duration) { showNotification(msg, type, ref, x, y, duration, false); } /** * Displays a message. * @param msg the message to show * @param type available types are "info", "warning", "error" * @param ref the referenced component, null to be based on browser window * @param x the horizontal position of the notification, aligned at top-left (in pixel) * @param y the vertical position of the notification, aligned at top-left (in pixel) * @param duration the duration of notification in millisecond. If zero or * negative the notification does not dismiss until user left-clicks outside * of the notification box. * @param closable whether to close notification manually or not. If true there will be a * close button on notification message and won't close until user click the button * or duration time up, default false. * @since 6.5.0 */ public static final void showNotification(String msg, String type, Component ref, int x, int y, int duration, boolean closable) { Execution exec = Executions.getCurrent(); Page page = ref != null ? ref.getPage() : null; if (page == null && exec instanceof ExecutionCtrl) page = ((ExecutionCtrl) exec).getCurrentPage(); if (type == null) type = NOTIFICATION_TYPE_INFO; response(new AuNotification(msg, type, page, ref, x, y, duration, closable)); } /** Shows the busy message at the browser such that * the user knows the system is busy. * * <p>It is usually used with {@link org.zkoss.zk.ui.event.Events#echoEvent} * to prevent the user to click another buttons or components. * * <p>To cover only a particular component, use {@link #showBusy(Component, String)}. * To close, use {@link #clearBusy()}. * * @param msg the message to show. If null, the default message (processing) * is shown. * @see #clearBusy() * @since 5.0.0 */ public static final void showBusy(String msg) { response(new AuShowBusy(msg)); } /** Shows the busy message at the browser that covers only the specified * component. * It is used to denote a portion of the desktop is busy, and * the user still can access the other part. * In other words, it means there is a long operation taking place. * <p>To execute a long operation asynchronously, the developer can use * a working thread, * or use {@link org.zkoss.zk.ui.event.EventQueue#subscribe(org.zkoss.zk.ui.event.EventListener,boolean)}. * <p>See also <a href="http://books.zkoss.org/wiki/ZK_Developer%27s_Reference/UI_Patterns/Long_Operations">Long Operations</a> * * @param comp the component that the busy message to cover. * Ignored if null. Notice that if the component is not found, * the busy message won't be shown. In additions, the busy message * is removed automatically if the component is detached later. * To manually remove the busy message, use {@link #clearBusy(Component)} * @param msg the message to show. If null, the default message (processing) * is shown. * @see #clearBusy(Component) * @since 5.0.0 */ public static final void showBusy(Component comp, String msg) { response(new AuShowBusy(comp, msg)); } /** Cleans the busy message at the browser. * @see #showBusy(String) * @since 5.0.0 */ public static final void clearBusy() { response(new AuClearBusy()); } /** Clears the busy message at the browser that covers only the specified * component. * @param comp the component that the busy message to cover. * @see #showBusy(Component, String) * @since 5.0.0 */ public static final void clearBusy(Component comp) { response(new AuClearBusy(comp)); } /** Forces the client to re-calculate the size of the given component. * For better performance, ZK Client Engine will cache the size of * components with hflex=min or vflex=min, and recalculate it only * necessary. However, sometimes it is hard (too costly) to know * if the size of a component with flex=min is changed. For example, * If another component is added to it and causes the size changed. * In this case, you could use this method to enforce the re-calculation. * @since 5.0.8 */ public static final void resize(Component comp) { response(new AuResizeWidget(comp)); } /** Reloads the client-side messages in the specified locale. * It is used if you allow the user to change the locale dynamically. * * <p>Notice that this method only reloads the <i>standard</i> messages. * The application has to update the component's content (such as labels) * manually if necessary. * * <p>Limitation: it reloads only the messages of ZK Client Engine * and ZUL components. It does not reload messages loaded by your * own JavaScript codes. * * @param locale the locale. If null, {@link org.zkoss.util.Locales#getCurrent} * is assumed. * @exception UnsupportedOperationException if the device is not ajax. * @since 3.6.3 */ public static final void reloadMessages(Locale locale) throws java.io.IOException { Executions.getCurrent().getDesktop().getDevice().reloadMessages(locale); } /** Logs the message to the client. * <p>data[0]: the title * @since 5.0.8 */ public static final void log(String msg) { response(new AuLog(msg)); } /** Logs the message to the client. * @param msg message, cast to String * @since 8.0.0 */ public static final void log(Object msg) { response(new AuLog((String) msg)); } /** * Loads a JavaScript file to client and execute it. * <p> By default, this method won't cache the JavaScript file, but you can * enable it by invoking {@link #loadScript(String, String, boolean)}. * @param url * the JavasScript file path, it will be encoded with * {@link Encodes#encodeURL(javax.servlet.ServletContext, javax.servlet.ServletRequest, javax.servlet.ServletResponse, String)} * if any. * @since 8.0.0 * @see Encodes#encodeURL * @see #loadScript(String, String, boolean) */ public static final void loadScript(String url) { response(new AuLoadScript(url, null, false)); } /** * Loads a JavaScript file to client and execute it. * * @param url * the JavasScript file path, it will be encoded with * {@link Encodes#encodeURL(javax.servlet.ServletContext, javax.servlet.ServletRequest, javax.servlet.ServletResponse, String)} * if any. * @param callback a callback script to execute when the JavaScript file has loaded. * @param cache true means the url will be cached and executed only once. * @since 8.0.0 * @see Encodes#encodeURL */ public static final void loadScript(String url, String callback, boolean cache) { response(new AuLoadScript(url, callback, cache)); } /** * Loads a CSS file. * @param url the URL of the CSS file * @since 8.0.0 */ public static final void loadCSS(String url) { response(new AuLoadCSS(url)); } /** * Send a command to client (afterCommand) * @param component target component * @param commandName the command name which would be triggered in client * @param data data which would be sent to client * @since 8.0.0 */ public static final void sendClientCommand(Component component, String commandName, Object data) { response(new AuInvoke(component, "$afterCommand", new Object[] { commandName, data })); } }