Author: adrianc
Date: Tue May 20 08:33:22 2008 New Revision: 658281 URL: http://svn.apache.org/viewvc?rev=658281&view=rev Log: Improved screen widget Ajax support. The original Ajax work was a great start, but there were limitations. These changes open things up a bit: 1) Ajax rendering falls back to plain HTML when the user has JavaScript disabled. 2) You can have more than one area updated during an event. IE7 updates only <div> elements, so be aware of that when using the Ajax feature. See the Example component for a demonstration. Modified: ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/string/FlexibleStringExpander.java ofbiz/trunk/framework/common/widget/CommonScreens.xml ofbiz/trunk/framework/example/config/ExampleUiLabels.xml ofbiz/trunk/framework/example/webapp/example/WEB-INF/controller.xml ofbiz/trunk/framework/example/widget/example/ExampleAjaxScreens.xml ofbiz/trunk/framework/example/widget/example/ExampleForms.xml ofbiz/trunk/framework/images/webapp/images/selectall.js ofbiz/trunk/framework/widget/dtd/widget-form.xsd ofbiz/trunk/framework/widget/dtd/widget-screen.xsd ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelForm.java ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlFormRenderer.java ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlScreenRenderer.java ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreenWidget.java Modified: ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/string/FlexibleStringExpander.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/string/FlexibleStringExpander.java?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/string/FlexibleStringExpander.java (original) +++ ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/string/FlexibleStringExpander.java Tue May 20 08:33:22 2008 @@ -19,8 +19,6 @@ package org.ofbiz.base.util.string; import java.io.Serializable; -import java.text.DateFormat; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -30,7 +28,6 @@ import org.ofbiz.base.util.BshUtil; import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.ObjectType; -import org.ofbiz.base.util.UtilDateTime; import org.ofbiz.base.util.UtilValidate; import org.ofbiz.base.util.collections.FlexibleMapAccessor; import org.ofbiz.base.util.UtilFormatOut; @@ -48,6 +45,7 @@ * and specified (XXX) currency * */ +@SuppressWarnings("serial") public class FlexibleStringExpander implements Serializable { public static final String module = FlexibleStringExpander.class.getName(); Modified: ofbiz/trunk/framework/common/widget/CommonScreens.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/widget/CommonScreens.xml?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/common/widget/CommonScreens.xml (original) +++ ofbiz/trunk/framework/common/widget/CommonScreens.xml Tue May 20 08:33:22 2008 @@ -100,6 +100,7 @@ <set field="layoutSettings.javaScripts[]" value="/images/calendar1.js" global="true"/> <set field="layoutSettings.javaScripts[]" value="/images/selectall.js" global="true"/> <set field="layoutSettings.javaScripts[]" value="/images/fieldlookup.js" global="true"/> + <set field="layoutSettings.javaScripts[]" value="/images/prototypejs/prototype.js" global="true"/> <!-- The default (global) shortcut icon --> <set field="layoutSettings.shortcutIcon" value="/images/ofbiz.ico" global="true"/> <!-- The default (global) logo --> @@ -205,6 +206,7 @@ <set field="layoutSettings.javaScripts[]" value="/images/calendar1.js" global="true"/> <set field="layoutSettings.javaScripts[]" value="/images/selectall.js" global="true"/> <set field="layoutSettings.javaScripts[]" value="/images/fieldlookup.js" global="true"/> + <set field="layoutSettings.javaScripts[]" value="/images/prototypejs/prototype.js" global="true"/> <!-- The default (global) shortcut icon --> <set field="layoutSettings.shortcutIcon" value="/images/ofbiz.ico" global="true"/> </actions> Modified: ofbiz/trunk/framework/example/config/ExampleUiLabels.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/example/config/ExampleUiLabels.xml?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/example/config/ExampleUiLabels.xml (original) +++ ofbiz/trunk/framework/example/config/ExampleUiLabels.xml Tue May 20 08:33:22 2008 @@ -27,6 +27,9 @@ <value xml:lang="th">à¸à¸±à¸§à¸à¸¢à¹à¸²à¸à¹à¸à¸£à¹à¸à¸£à¸¡à¸à¸à¸¡à¸à¸´à¸§à¹à¸à¸à¸£à¹</value> <value xml:lang="zh">æ ·ä¾åºç¨</value> </property> + <property key="ExampleAjaxIntro"> + <value xml:lang="en">To use this Ajax demonstration, you must have JavaScript enabled on your browser.</value> + </property> <property key="ExampleCompanyName"> <value xml:lang="en">OFBiz: Example</value> <value xml:lang="it">OFBiz: Esempi</value> Modified: ofbiz/trunk/framework/example/webapp/example/WEB-INF/controller.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/example/webapp/example/WEB-INF/controller.xml?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/example/webapp/example/WEB-INF/controller.xml (original) +++ ofbiz/trunk/framework/example/webapp/example/WEB-INF/controller.xml Tue May 20 08:33:22 2008 @@ -66,6 +66,18 @@ <response name="success" type="view" value="EditExample"/> <response name="error" type="view" value="EditExample"/> </request-map> + <request-map uri="createExampleAjax"> + <security https="true" auth="true"/> + <event type="service" invoke="createExample"/> + <response name="success" type="view" value="findExampleAjax"/> + <response name="error" type="view" value="findExampleAjax"/> + </request-map> + <request-map uri="updateExampleAjax"> + <security https="true" auth="true"/> + <event type="service" invoke="updateExample"/> + <response name="success" type="view" value="findExampleAjax"/> + <response name="error" type="view" value="findExampleAjax"/> + </request-map> <request-map uri="EditExampleItems"><security https="true" auth="true"/><response name="success" type="view" value="EditExampleItems"/></request-map> <request-map uri="createExampleItem"> @@ -147,8 +159,8 @@ <request-map uri="LookupExampleFeature"><security https="true" auth="true"/><response name="success" type="view" value="LookupExampleFeature"/></request-map> - <request-map uri="ListExampleFormOnly"><security https="true" auth="true"/><response name="success" type="view" value="ListExampleFormOnly"/></request-map> - <request-map uri="CreateExampleFormOnly"><security https="true" auth="true"/><response name="success" type="view" value="CreateExampleFormOnly"/></request-map> + <request-map uri="ListExampleFormOnly"><security https="true" auth="false"/><response name="success" type="view" value="ListExampleFormOnly"/></request-map> + <request-map uri="CreateExampleFormOnly"><security https="true" auth="false"/><response name="success" type="view" value="CreateExampleFormOnly"/></request-map> <!-- end of request mappings --> <!-- View Mappings --> Modified: ofbiz/trunk/framework/example/widget/example/ExampleAjaxScreens.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/example/widget/example/ExampleAjaxScreens.xml?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/example/widget/example/ExampleAjaxScreens.xml (original) +++ ofbiz/trunk/framework/example/widget/example/ExampleAjaxScreens.xml Tue May 20 08:33:22 2008 @@ -26,7 +26,6 @@ <actions> <set field="headerItem" value="AjaxExample"/> <set field="titleProperty" value="PageTitleFindExample"/> - <set field="layoutSettings.javaScripts[+0]" value="/images/prototypejs/prototype.js" global="true"/> </actions> <widgets> <decorator-screen name="main-decorator" location="${parameters.mainDecoratorLocation}"> @@ -37,11 +36,22 @@ </condition> <widgets> <container style="h1"><label>${uiLabelMap.${titleProperty}}</label></container> - <container id="ListExamplesAutoUpdate" auto-update-target="ListExampleFormOnly"> + <section> + <condition> + <if-compare field-name="javaScriptEnabled" value="true" operator="equals"/> + </condition> + <widgets/> + <fail-widgets> + <container style="button-bar"><label>${uiLabelMap.ExampleAjaxIntro}</label></container> + </fail-widgets> + </section> + <container id="ListExamplesAjax"> <include-screen name="ListExampleFormOnly"/> </container> <container style="h2"><label>${uiLabelMap.ExampleNewExample}</label></container> - <include-screen name="CreateExampleFormOnly"/> + <container id="EditExampleAjax"> + <include-screen name="CreateExampleFormOnly"/> + </container> </widgets> <fail-widgets> <label style="h3">${uiLabelMap.ExampleViewPermissionError}</label> @@ -55,21 +65,29 @@ <screen name="ListExampleFormOnly"> <section> + <condition> + <if-has-permission permission="EXAMPLE" action="_VIEW"/> + </condition> <actions> <!-- NOTE: these are needed because this may be run as a top level screen and would have no decorator --> <property-map resource="ExampleUiLabels" map-name="uiLabelMap" global="true"/> <property-map resource="CommonUiLabels" map-name="uiLabelMap" global="true"/> </actions> <widgets> - <include-form name="ListExamples" location="component://example/widget/example/ExampleForms.xml"/> + <include-form name="ListExamplesAjax" location="component://example/widget/example/ExampleForms.xml"/> </widgets> </section> </screen> <screen name="CreateExampleFormOnly"> <section> + <condition> + <if-has-permission permission="EXAMPLE" action="_VIEW"/> + </condition> <actions> <!-- these are only needed so that when bsh evaluates use-when attributes these will exist and not cause an error --> + <property-map resource="ExampleUiLabels" map-name="uiLabelMap" global="true"/> + <property-map resource="CommonUiLabels" map-name="uiLabelMap" global="true"/> <set field="exampleId" from-field="parameters.exampleId"/> <entity-one entity-name="Example" value-name="example"/> </actions> Modified: ofbiz/trunk/framework/example/widget/example/ExampleForms.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/example/widget/example/ExampleForms.xml?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/example/widget/example/ExampleForms.xml (original) +++ ofbiz/trunk/framework/example/widget/example/ExampleForms.xml Tue May 20 08:33:22 2008 @@ -34,6 +34,12 @@ <field name="description" title="${uiLabelMap.CommonDescription}"><display/></field> </form> + <!-- Typically, this extended form wouldn't be necessary. The parent form (ListExamples) would + have these attributes. --> + <form name="ListExamplesAjax" extends="ListExamples" type="list" paginate-target="authview/findExampleAjax" view-size="3"> + <on-event-update-area event-type="paginate" area-id="ListExamplesAjax" area-target="ListExampleFormOnly"/> + </form> + <form name="EditExample" type="single" target="updateExample" title="" default-map-name="example"> <actions> <entity-one entity-name="StatusItem" value-name="currentStatus" auto-field-map="false"> @@ -84,9 +90,12 @@ <field name="submitButton" use-when="example!=null" title="${uiLabelMap.CommonUpdate}"><submit button-type="button"/></field> </form> - <form name="EditExampleBackgroundSubmit" extends="EditExample"> - <field name="submitButton" use-when="example==null" title="${uiLabelMap.CommonCreate}"><submit button-type="button" background-submit-refresh-target="CreateExampleFormOnly"/></field> - <field name="submitButton" use-when="example!=null" title="${uiLabelMap.CommonUpdate}"><submit button-type="button" background-submit-refresh-target="CreateExampleFormOnly"/></field> + <!-- Typically, this extended form wouldn't be necessary. The parent form (EditExample) would + have these settings. --> + <form name="EditExampleBackgroundSubmit" type="single" extends="EditExample" target="updateExampleAjax"> + <alt-target use-when="example==null" target="createExampleAjax"/> + <on-event-update-area event-type="submit" area-id="ListExamplesAjax" area-target="ListExampleFormOnly"/> + <on-event-update-area event-type="submit" area-id="EditExampleAjax" area-target="CreateExampleFormOnly"/> </form> <!-- ExampleItem --> Modified: ofbiz/trunk/framework/images/webapp/images/selectall.js URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/selectall.js?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/selectall.js (original) +++ ofbiz/trunk/framework/images/webapp/images/selectall.js Tue May 20 08:33:22 2008 @@ -226,7 +226,7 @@ function ajaxUpdateAreas(areaCsvString) { var areaArray = areaCsvString.split(","); var numAreas = parseInt(areaArray.length / 3); - for (var i = 0; i < numAreas; i = i + 3) { + for (var i = 0; i < numAreas * 3; i = i + 3) { new Ajax.Updater(areaArray[i], areaArray[i + 1], {parameters: areaArray[i + 2]}); } } Modified: ofbiz/trunk/framework/widget/dtd/widget-form.xsd URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/dtd/widget-form.xsd?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/widget/dtd/widget-form.xsd (original) +++ ofbiz/trunk/framework/widget/dtd/widget-form.xsd Tue May 20 08:33:22 2008 @@ -36,6 +36,7 @@ <xs:element minOccurs="0" maxOccurs="unbounded" ref="auto-fields-service"/> <xs:element minOccurs="0" maxOccurs="unbounded" ref="auto-fields-entity"/> <xs:element minOccurs="0" maxOccurs="unbounded" ref="field"/> + <xs:element minOccurs="0" maxOccurs="unbounded" ref="on-event-update-area"/> <xs:element minOccurs="0" ref="sort-order"/> </xs:sequence> <xs:attributeGroup ref="attlist.form"/> @@ -317,6 +318,27 @@ <xs:attributeGroup name="attlist.sort-field"> <xs:attribute type="xs:string" name="name" use="required"/> </xs:attributeGroup> + <!-- ================== Form Events ==================== --> + <xs:attributeGroup name="attlist.on-form-event-update-area"> + <xs:attribute name="event-type" use="required"> + <xs:simpleType> + <xs:restriction base="xs:token"> + <xs:enumeration value="paginate"/> + <xs:enumeration value="submit"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute type="xs:string" name="area-id" use="required"/> + <xs:attribute type="xs:string" name="area-target" use="required"/> + </xs:attributeGroup> + <xs:element name="on-event-update-area"> + <xs:annotation> + <xs:documentation>Area to be updated when a form event occurs.</xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:attributeGroup ref="attlist.on-form-event-update-area"/> + </xs:complexType> + </xs:element> <!-- ================== FIELDS ==================== --> <xs:element name="AllFields" abstract="true"/> @@ -800,7 +822,8 @@ </xs:attribute> <xs:attribute type="xs:string" name="image-location"/> <xs:attribute type="xs:string" name="background-submit-refresh-target"> - <xs:annotation><xs:documentation>This will submit the form in the background and refresh just this form and not the rest of the page. Note that the button-type must be button.</xs:documentation></xs:annotation> + <xs:annotation><xs:documentation>Deprecated. Use the on-event-update-area element + instead.</xs:documentation></xs:annotation> </xs:attribute> </xs:attributeGroup> <xs:element name="text" substitutionGroup="AllFields"> Modified: ofbiz/trunk/framework/widget/dtd/widget-screen.xsd URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/dtd/widget-screen.xsd?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/widget/dtd/widget-screen.xsd (original) +++ ofbiz/trunk/framework/widget/dtd/widget-screen.xsd Tue May 20 08:33:22 2008 @@ -754,7 +754,17 @@ <xs:attributeGroup name="attlist.container"> <xs:attribute type="xs:string" name="id"/> <xs:attribute type="xs:string" name="style"/> - <xs:attribute type="xs:string" name="auto-update-target"/> + <xs:attribute type="xs:string" name="auto-update-target"> + <xs:annotation> + <xs:documentation>The URL to be called for periodic asynchronous area updates. + Some widget rendering environments support asynchronous updates.</xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:integer" name="auto-update-interval"> + <xs:annotation> + <xs:documentation>The auto-update interval, in seconds.</xs:documentation> + </xs:annotation> + </xs:attribute> </xs:attributeGroup> <xs:element name="image" substitutionGroup="AllWidgets"> <xs:complexType mixed="true"> Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelForm.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelForm.java?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelForm.java (original) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelForm.java Tue May 20 08:33:22 2008 @@ -182,6 +182,11 @@ protected FlexibleStringExpander rowCountExdr; protected List multiSubmitFields = FastList.newInstance(); protected int rowCount = 0; + + /** On Submit areas to be updated. */ + protected List<UpdateArea> onSubmitUpdateAreas; + /** On Paginate areas to be updated. */ + protected List<UpdateArea> onPaginateUpdateAreas; // ===== CONSTRUCTORS ===== /** Default Constructor */ @@ -271,11 +276,14 @@ this.targetWindowExdr = parent.targetWindowExdr; this.hideHeader = parent.hideHeader; this.clientAutocompleteFields = parent.clientAutocompleteFields; + this.paginateTarget = parent.paginateTarget; this.altTargets.addAll(parent.altTargets); this.actions = parent.actions; this.rowActions = parent.rowActions; this.defaultViewSize = parent.defaultViewSize; + this.onSubmitUpdateAreas = parent.onSubmitUpdateAreas; + this.onPaginateUpdateAreas = parent.onPaginateUpdateAreas; //these are done below in a special way... //this.fieldList = parent.fieldList; @@ -444,6 +452,13 @@ this.addAltTarget(altTarget); } + // on-event-update-area + List<? extends Element> updateAreaElements = UtilXml.childElementList(formElement, "on-event-update-area"); + for (Element updateAreaElement : updateAreaElements) { + UpdateArea updateArea = new UpdateArea(updateAreaElement); + this.addOnEventUpdateArea(updateArea); + } + // auto-fields-service List autoFieldsServiceElements = UtilXml.childElementList(formElement, "auto-fields-service"); Iterator autoFieldsServiceElementIter = autoFieldsServiceElements.iterator(); @@ -599,6 +614,40 @@ } } + public void addOnEventUpdateArea(UpdateArea updateArea) { + // Event types are sorted as a convenience + // for the rendering classes + if ("paginate".equals(updateArea.getEventType())) { + addOnPaginateUpdateArea(updateArea); + } else if ("submit".equals(updateArea.getEventType())) { + addOnSubmitUpdateArea(updateArea); + } + } + + protected void addOnSubmitUpdateArea(UpdateArea updateArea) { + if (onSubmitUpdateAreas == null) { + onSubmitUpdateAreas = FastList.newInstance(); + } + int index = onSubmitUpdateAreas.indexOf(updateArea); + if (index != -1) { + onSubmitUpdateAreas.set(index, updateArea); + } else { + onSubmitUpdateAreas.add(updateArea); + } + } + + protected void addOnPaginateUpdateArea(UpdateArea updateArea) { + if (onPaginateUpdateAreas == null) { + onPaginateUpdateAreas = FastList.newInstance(); + } + int index = onPaginateUpdateAreas.indexOf(updateArea); + if (index != -1) { + onPaginateUpdateAreas.set(index, updateArea); + } else { + onPaginateUpdateAreas.add(updateArea); + } + } + public void addAutoFieldsFromService(AutoFieldsService autoFieldsService) { autoFieldsServices.add(autoFieldsService); @@ -2169,6 +2218,10 @@ this.type = string; } + public List<UpdateArea> getOnPaginateUpdateAreas() { + return this.onPaginateUpdateAreas; + } + public String getPaginateTarget(Map context) { String targ = this.paginateTarget.expandString(context); if (UtilValidate.isEmpty(targ)) { @@ -2369,9 +2422,6 @@ this.overridenListSize = overridenListSize; } - /** - * @param string - */ public void setPaginateTarget(String string) { this.paginateTarget = new FlexibleStringExpander(string); } @@ -2546,6 +2596,12 @@ return inbetweenList; } + /* Returns the list of ModelForm.UpdateArea objects. + */ + public List<UpdateArea> getOnSubmitUpdateAreas() { + return this.onSubmitUpdateAreas; + } + public static class AltTarget { public String useWhen; public String target; @@ -2561,6 +2617,48 @@ } } + /** The UpdateArea class implements the <code><on-event-update-area></code> + * elements used in form widgets. + */ + public static class UpdateArea { + protected String eventType; + protected String areaId; + protected String areaTarget; + /** XML constructor. + * @param updateAreaElement The <code><on-xxx-update-area></code> + * XML element. + */ + public UpdateArea(Element updateAreaElement) { + this.eventType = updateAreaElement.getAttribute("event-type"); + this.areaId = updateAreaElement.getAttribute("area-id"); + this.areaTarget = updateAreaElement.getAttribute("area-target"); + } + /** String constructor. + * @param areaId The id of the widget element to be updated + * @param areaTarget The target URL called to update the area + */ + public UpdateArea(String eventType, String areaId, String areaTarget) { + this.eventType = eventType; + this.areaId = areaId; + this.areaTarget = areaTarget; + } + public int hashCode() { + return areaId.hashCode(); + } + public boolean equals(Object obj) { + return obj instanceof UpdateArea && obj.hashCode() == this.hashCode(); + } + public String getEventType() { + return eventType; + } + public String getAreaId() { + return areaId; + } + public String getAreaTarget(Map<String, ? extends Object> context) { + return FlexibleStringExpander.expandString(areaTarget, context); + } + } + public static class AutoFieldsService { public String serviceName; public String mapName; Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlFormRenderer.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlFormRenderer.java?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlFormRenderer.java (original) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlFormRenderer.java Tue May 20 08:33:22 2008 @@ -18,18 +18,21 @@ *******************************************************************************/ package org.ofbiz.widget.html; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.HashSet; -import java.util.Calendar; -import java.sql.Timestamp; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javolution.util.FastList; + +import org.apache.commons.lang.StringEscapeUtils; import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.UtilHttp; import org.ofbiz.base.util.UtilProperties; @@ -62,8 +65,6 @@ import org.ofbiz.widget.form.ModelFormField.TextFindField; import org.ofbiz.widget.form.ModelFormField.TextareaField; -import org.apache.commons.lang.StringEscapeUtils; - /** * Widget Library - HTML Form Renderer implementation */ @@ -872,8 +873,20 @@ } else { // default to "button" + String formId = modelForm.getContainerId(); + List<ModelForm.UpdateArea> updateAreas = modelForm.getOnSubmitUpdateAreas(); + // This is here for backwards compatibility. Use on-event-update-area + // elements instead. String backgroundSubmitRefreshTarget = submitField.getBackgroundSubmitRefreshTarget(context); if (UtilValidate.isNotEmpty(backgroundSubmitRefreshTarget)) { + if (updateAreas == null) { + updateAreas = FastList.newInstance(); + } + updateAreas.add(new ModelForm.UpdateArea("submit", formId, backgroundSubmitRefreshTarget)); + } + + boolean ajaxEnabled = (updateAreas != null || UtilValidate.isNotEmpty(backgroundSubmitRefreshTarget)) && UtilHttp.isJavaScriptEnabled(request); + if (ajaxEnabled) { buffer.append("<input type=\"button\""); } else { buffer.append("<input type=\"submit\""); @@ -906,17 +919,34 @@ // disabling for now, using form onSubmit action instead: buffer.append(singleClickAction); } - if (UtilValidate.isNotEmpty(backgroundSubmitRefreshTarget)) { - // onclick="javascript:submitFormInBackground($('EditExampleBackgroundSubmit'), 'EditExampleBackgroundSubmit', '<@ofbizUrl>/authview/CreateExampleFormOnly</@ofbizUrl>');" - String formId = submitField.getModelFormField().getModelForm().getContainerId(); - String formContainerId = submitField.getModelFormField().getModelForm().getContainerId(); - buffer.append(" onclick=\"javascript:submitFormInBackground($('"); - buffer.append(formId); - buffer.append("'), '"); - buffer.append(formContainerId); - buffer.append("', '"); - this.appendOfbizUrl(buffer, backgroundSubmitRefreshTarget); - buffer.append("');\""); + if (ajaxEnabled) { + buffer.append(" onclick=\""); + if (updateAreas.size() == 1) { + ModelForm.UpdateArea updateArea = updateAreas.get(0); + buffer.append("submitFormInBackground($('"); + buffer.append(formId); + buffer.append("'), '"); + buffer.append(updateArea.getAreaId()); + buffer.append("', '"); + this.appendOfbizUrl(buffer, updateArea.getAreaTarget(context)); + } else { + buffer.append("ajaxSubmitFormUpdateAreas($('"); + buffer.append(formId); + buffer.append("'), '"); + boolean firstLoop = true; + for (ModelForm.UpdateArea updateArea : updateAreas) { + if (firstLoop) { + firstLoop = false; + } else { + buffer.append(","); + } + String targetString = updateArea.getAreaTarget(context); + String target = UtilHttp.removeQueryStringFromTarget(targetString); + String targetParams = UtilHttp.getQueryStringFromTarget(targetString); + buffer.append(updateArea.getAreaId() + "," + target + "," + targetParams); + } + } + buffer.append("')\""); } buffer.append("/>"); @@ -1183,6 +1213,7 @@ context.put("_QBESTRING_", queryString); renderBeginningBoundaryComment(buffer, "Form Widget", modelForm); + if (this.renderPagination) { this.renderNextPrev(buffer, context, modelForm); } @@ -1989,11 +2020,21 @@ } public void renderNextPrev(StringBuffer buffer, Map context, ModelForm modelForm) { - String targetService = modelForm.getPaginateTarget(context); + boolean javaScriptEnabled = UtilHttp.isJavaScriptEnabled(request); + boolean ajaxEnabled = false; + List<ModelForm.UpdateArea> updateAreas = modelForm.getOnPaginateUpdateAreas(); + String targetService = null; + if (javaScriptEnabled) { + if (UtilValidate.isNotEmpty(updateAreas)) { + ajaxEnabled = true; + } + } else { + targetService = modelForm.getPaginateTarget(context); + } if (targetService == null) { targetService = "${targetService}"; } - if (UtilValidate.isEmpty(targetService)) { + if (UtilValidate.isEmpty(targetService) && updateAreas == null) { Debug.logWarning("Cannot paginate because TargetService is empty for the form: " + modelForm.getName(), module); return; } @@ -2048,9 +2089,13 @@ String paginateAnchor = modelForm.getPaginateTargetAnchor(); if (paginateAnchor != null) anchor = "#" + paginateAnchor; - // preparing the link text, so that later in the code we can reuse this and just add the viewIndex - String prepLinkText = ""; - prepLinkText = targetService; + // Create separate url path String and request parameters String, + // add viewIndex/viewSize parameters to request parameter String + String urlPath = UtilHttp.removeQueryStringFromTarget(targetService); + String prepLinkText = UtilHttp.getQueryStringFromTarget(targetService); + if (prepLinkText == null) { + prepLinkText = ""; + } if (prepLinkText.indexOf("?") < 0) { prepLinkText += "?"; } else if (!prepLinkText.endsWith("?")) { @@ -2060,93 +2105,209 @@ prepLinkText += queryString + "&"; } prepLinkText += viewSizeParam + "=" + viewSize + "&" + viewIndexParam + "="; + if (ajaxEnabled) { + // Prepare params for prototype.js + prepLinkText = prepLinkText.replace("?", ""); + prepLinkText = prepLinkText.replace("&", "&"); + } buffer.append("<div class=\"").append(modelForm.getPaginateStyle()).append("\">"); - buffer.append("<ul>"); + appendWhitespace(buffer); + buffer.append(" <ul>"); + appendWhitespace(buffer); String linkText; // First button - buffer.append("<li class=\"").append(modelForm.getPaginateFirstStyle()); + buffer.append(" <li class=\"").append(modelForm.getPaginateFirstStyle()); if (viewIndex > 0) { buffer.append("\"><a href=\""); - linkText = prepLinkText + 0 + anchor; - // - make the link - buffer.append(rh.makeLink(this.request, this.response, linkText)).append("\">").append(modelForm.getPaginateFirstLabel(context)).append("</a>"); + if (ajaxEnabled) { + buffer.append("javascript:ajaxUpdateAreas('"); + for (ModelForm.UpdateArea updateArea : updateAreas) { + linkText = UtilHttp.getQueryStringFromTarget(updateArea.getAreaTarget(context)); + if (UtilValidate.isEmpty(linkText)) { + linkText = ""; + } + if (!UtilValidate.isEmpty(queryString) && !queryString.equals("null")) { + linkText += queryString + "&"; + } + linkText += viewSizeParam + "=" + viewSize + "&" + viewIndexParam + "=" + 0 + anchor; + linkText = linkText.replace("?", ""); + linkText = linkText.replace("&", "&"); + buffer.append(updateArea.getAreaId() + ","); + buffer.append(rh.makeLink(this.request, this.response, UtilHttp.removeQueryStringFromTarget(updateArea.getAreaTarget(context)))); + buffer.append("," + linkText + ","); + } + buffer.append("')"); + } else { + linkText = prepLinkText + 0 + anchor; + buffer.append(rh.makeLink(this.request, this.response, urlPath + linkText)); + } + buffer.append("\">").append(modelForm.getPaginateFirstLabel(context)).append("</a>"); } else { // disabled button buffer.append("-disabled\">").append(modelForm.getPaginateFirstLabel(context)); } buffer.append("</li>"); + appendWhitespace(buffer); + // Previous button - buffer.append("<li class=\"").append(modelForm.getPaginatePreviousStyle()); + buffer.append(" <li class=\"").append(modelForm.getPaginatePreviousStyle()); if (viewIndex > 0) { buffer.append("\"><a href=\""); - linkText = prepLinkText + (viewIndex - 1) + anchor; - // - make the link - buffer.append(rh.makeLink(this.request, this.response, linkText)).append("\">").append(modelForm.getPaginatePreviousLabel(context)).append("</a>"); + if (ajaxEnabled) { + buffer.append("javascript:ajaxUpdateAreas('"); + for (ModelForm.UpdateArea updateArea : updateAreas) { + linkText = UtilHttp.getQueryStringFromTarget(updateArea.getAreaTarget(context)); + if (UtilValidate.isEmpty(linkText)) { + linkText = ""; + } + if (!UtilValidate.isEmpty(queryString) && !queryString.equals("null")) { + linkText += queryString + "&"; + } + linkText += viewSizeParam + "=" + viewSize + "&" + viewIndexParam + "=" + (viewIndex - 1) + anchor; + linkText = linkText.replace("?", ""); + linkText = linkText.replace("&", "&"); + buffer.append(updateArea.getAreaId() + ","); + buffer.append(rh.makeLink(this.request, this.response, UtilHttp.removeQueryStringFromTarget(updateArea.getAreaTarget(context)))); + buffer.append("," + linkText + ","); + } + buffer.append("')"); + } else { + linkText = prepLinkText + (viewIndex - 1) + anchor; + buffer.append(rh.makeLink(this.request, this.response, urlPath + linkText)); + } + buffer.append("\">").append(modelForm.getPaginatePreviousLabel(context)).append("</a>"); } else { // disabled button buffer.append("-disabled\">").append(modelForm.getPaginatePreviousLabel(context)); } buffer.append("</li>"); - // used for iterator and for the last page - int page = 0; - if (listSize > 0) { - - linkText = prepLinkText; - if(linkText.startsWith("/")) { - linkText = linkText.substring(1 , linkText.length()); - } + appendWhitespace(buffer); - buffer.append("<li>").append(pageLabel).append(" <select name=\"page\" size=\"1\" onchange=\"location.href = '" + linkText + "' + this.value;\" >"); - //actual value - for(int i = 0; i < listSize ; ) { - if( page == viewIndex ) { + // Page select dropdown + if (listSize > 0 && javaScriptEnabled) { + buffer.append(" <li>").append(pageLabel).append(" <select name=\"page\" size=\"1\" onchange=\""); + if (ajaxEnabled) { + buffer.append("javascript:ajaxUpdateAreas('"); + for (ModelForm.UpdateArea updateArea : updateAreas) { + linkText = UtilHttp.getQueryStringFromTarget(updateArea.getAreaTarget(context)); + if (UtilValidate.isEmpty(linkText)) { + linkText = ""; + } + if (!UtilValidate.isEmpty(queryString) && !queryString.equals("null")) { + linkText += queryString + "&"; + } + linkText += viewSizeParam + "=" + viewSize + "&" + viewIndexParam + "=' + this.value + '"; + linkText = linkText.replace("?", ""); + linkText = linkText.replace("&", "&"); + buffer.append(updateArea.getAreaId() + ","); + buffer.append(rh.makeLink(this.request, this.response, UtilHttp.removeQueryStringFromTarget(updateArea.getAreaTarget(context)))); + buffer.append("," + linkText + ","); + } + buffer.append("')\""); + } else { + linkText = prepLinkText; + if (linkText.startsWith("/")) { + linkText = linkText.substring(1); + } + buffer.append("location.href = '" + urlPath + linkText + "' + this.value;\""); + } + buffer.append(">"); + // actual value + int page = 0; + for (int i = 0; i < listSize;) { + if (page == viewIndex) { buffer.append("<option selected value=\""); } else { buffer.append("<option value=\""); } buffer.append(page); buffer.append("\">"); - buffer.append( 1 + page); + buffer.append(1 + page); buffer.append("</option>"); // increment page and calculate next index page++; i = page * viewSize; } buffer.append("</select></li>"); - buffer.append("<li>"); - buffer.append((lowIndex + 1) + " - " + (lowIndex + actualPageSize ) + " " + ofLabel + " " + listSize).append(" " + rowsLabel); + buffer.append((lowIndex + 1) + " - " + (lowIndex + actualPageSize) + " " + ofLabel + " " + listSize).append(" " + rowsLabel); buffer.append("</li>"); + appendWhitespace(buffer); } // Next button - buffer.append("<li class=\"").append(modelForm.getPaginateNextStyle()); + buffer.append(" <li class=\"").append(modelForm.getPaginateNextStyle()); if (highIndex < listSize) { buffer.append("\"><a href=\""); - linkText = prepLinkText + (viewIndex + 1) + anchor; - // - make the link - buffer.append(rh.makeLink(this.request, this.response, linkText)).append("\">").append(modelForm.getPaginateNextLabel(context)).append("</a>"); + if (ajaxEnabled) { + buffer.append("javascript:ajaxUpdateAreas('"); + for (ModelForm.UpdateArea updateArea : updateAreas) { + linkText = UtilHttp.getQueryStringFromTarget(updateArea.getAreaTarget(context)); + if (UtilValidate.isEmpty(linkText)) { + linkText = ""; + } + if (!UtilValidate.isEmpty(queryString) && !queryString.equals("null")) { + linkText += queryString + "&"; + } + linkText += viewSizeParam + "=" + viewSize + "&" + viewIndexParam + "=" + (viewIndex + 1) + anchor; + linkText = linkText.replace("?", ""); + linkText = linkText.replace("&", "&"); + buffer.append(updateArea.getAreaId() + ","); + buffer.append(rh.makeLink(this.request, this.response, UtilHttp.removeQueryStringFromTarget(updateArea.getAreaTarget(context)))); + buffer.append("," + linkText + ","); + } + buffer.append("')"); + } else { + linkText = prepLinkText + (viewIndex + 1) + anchor; + buffer.append(rh.makeLink(this.request, this.response, urlPath + linkText)); + } + buffer.append("\">").append(modelForm.getPaginateNextLabel(context)).append("</a>"); } else { // disabled button buffer.append("-disabled\">").append(modelForm.getPaginateNextLabel(context)); } buffer.append("</li>"); + appendWhitespace(buffer); + // Last button - buffer.append("<li class=\"").append(modelForm.getPaginateLastStyle()); + buffer.append(" <li class=\"").append(modelForm.getPaginateLastStyle()); if (highIndex < listSize) { buffer.append("\"><a href=\""); - linkText = prepLinkText + (page - 1) + anchor; - // - make the link - buffer.append(rh.makeLink(this.request, this.response, linkText)).append("\">").append(modelForm.getPaginateLastLabel(context)).append("</a>"); + if (ajaxEnabled) { + buffer.append("javascript:ajaxUpdateAreas('"); + for (ModelForm.UpdateArea updateArea : updateAreas) { + linkText = UtilHttp.getQueryStringFromTarget(updateArea.getAreaTarget(context)); + if (UtilValidate.isEmpty(linkText)) { + linkText = ""; + } + if (!UtilValidate.isEmpty(queryString) && !queryString.equals("null")) { + linkText += queryString + "&"; + } + linkText += viewSizeParam + "=" + viewSize + "&" + viewIndexParam + "=" + (listSize / viewSize) + anchor; + linkText = linkText.replace("?", ""); + linkText = linkText.replace("&", "&"); + buffer.append(updateArea.getAreaId() + ","); + buffer.append(rh.makeLink(this.request, this.response, UtilHttp.removeQueryStringFromTarget(updateArea.getAreaTarget(context)))); + buffer.append("," + linkText + ","); + } + buffer.append("')"); + } else { + linkText = prepLinkText + (listSize / viewSize) + anchor; + buffer.append(rh.makeLink(this.request, this.response, urlPath + linkText)); + } + buffer.append("\">").append(modelForm.getPaginateLastLabel(context)).append("</a>"); } else { // disabled button buffer.append("-disabled\">").append(modelForm.getPaginateLastLabel(context)); } buffer.append("</li>"); + appendWhitespace(buffer); - buffer.append("</ul>").append("</div>"); + buffer.append(" </ul>"); + appendWhitespace(buffer); + buffer.append("</div>"); appendWhitespace(buffer); } Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlScreenRenderer.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlScreenRenderer.java?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlScreenRenderer.java (original) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlScreenRenderer.java Tue May 20 08:33:22 2008 @@ -30,6 +30,8 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javolution.util.FastMap; + import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.GeneralException; import org.ofbiz.base.util.UtilFormatOut; @@ -38,19 +40,17 @@ import org.ofbiz.base.util.UtilValidate; import org.ofbiz.entity.GenericDelegator; import org.ofbiz.entity.GenericValue; +import org.ofbiz.service.LocalDispatcher; import org.ofbiz.webapp.control.RequestHandler; import org.ofbiz.webapp.taglib.ContentUrlTag; +import org.ofbiz.widget.WidgetContentWorker; +import org.ofbiz.widget.WidgetDataResourceWorker; import org.ofbiz.widget.form.FormStringRenderer; import org.ofbiz.widget.form.ModelForm; -import org.ofbiz.widget.html.HtmlWidgetRenderer; import org.ofbiz.widget.menu.MenuStringRenderer; import org.ofbiz.widget.menu.ModelMenu; -import org.ofbiz.widget.WidgetContentWorker; -import org.ofbiz.widget.WidgetDataResourceWorker; import org.ofbiz.widget.screen.ModelScreenWidget; import org.ofbiz.widget.screen.ScreenStringRenderer; -import org.ofbiz.service.LocalDispatcher; -import javolution.util.FastMap; /** * Widget Library - HTML Form Renderer implementation @@ -58,9 +58,15 @@ public class HtmlScreenRenderer extends HtmlWidgetRenderer implements ScreenStringRenderer { public static final String module = HtmlScreenRenderer.class.getName(); + protected int elementId = 999; public HtmlScreenRenderer() {} + protected String getNextElementId() { + elementId++; + return "hsr" + elementId; + } + public void renderSectionBegin(Writer writer, Map context, ModelScreenWidget.Section section) throws IOException { renderBeginningBoundaryComment(writer, section.isMainSection?"Screen":"Section Widget", section); } @@ -69,12 +75,30 @@ } public void renderContainerBegin(Writer writer, Map context, ModelScreenWidget.Container container) throws IOException { + String containerId = container.getId(context); + String autoUpdateTarget = container.getAutoUpdateTargetExdr(context); + HttpServletRequest request = (HttpServletRequest) context.get("request"); + if (UtilValidate.isNotEmpty(autoUpdateTarget) && UtilHttp.isJavaScriptEnabled(request)) { + if (UtilValidate.isEmpty(containerId)) { + containerId = getNextElementId(); + } + HttpServletResponse response = (HttpServletResponse) context.get("response"); + ServletContext ctx = (ServletContext) request.getAttribute("servletContext"); + RequestHandler rh = (RequestHandler) ctx.getAttribute("_REQUEST_HANDLER_"); + + writer.write("<script type=\"text/javascript\">ajaxUpdateAreaPeriodic('"); + writer.write(containerId); + writer.write("', '"); + writer.write(rh.makeLink(request, response, autoUpdateTarget)); + writer.write("', '"); + writer.write("', '" + container.getAutoUpdateInterval() + "');</script>"); + appendWhitespace(writer); + } writer.write("<div"); - String id = container.getId(context); - if (UtilValidate.isNotEmpty(id)) { + if (UtilValidate.isNotEmpty(containerId)) { writer.write(" id=\""); - writer.write(id); + writer.write(containerId); writer.write("\""); } @@ -91,21 +115,6 @@ public void renderContainerEnd(Writer writer, Map context, ModelScreenWidget.Container container) throws IOException { writer.write("</div>"); appendWhitespace(writer); - String autoUpdateTarget = container.getAutoUpdateTargetExdr(context); - String containerId = container.getId(context); - if (UtilValidate.isNotEmpty(autoUpdateTarget) && UtilValidate.isNotEmpty(containerId)) { - HttpServletResponse response = (HttpServletResponse) context.get("response"); - HttpServletRequest request = (HttpServletRequest) context.get("request"); - ServletContext ctx = (ServletContext) request.getAttribute("servletContext"); - RequestHandler rh = (RequestHandler) ctx.getAttribute("_REQUEST_HANDLER_"); - - writer.write("<script type=\"text/javascript\">new Ajax.PeriodicalUpdater('"); - writer.write(containerId); - writer.write("', '"); - writer.write(rh.makeLink(request, response, autoUpdateTarget)); - writer.write("');</script>"); - appendWhitespace(writer); - } } public void renderScreenletBegin(Writer writer, Map context, boolean collapsed, ModelScreenWidget.Screenlet screenlet) throws IOException { Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreenWidget.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreenWidget.java?rev=658281&r1=658280&r2=658281&view=diff ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreenWidget.java (original) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/screen/ModelScreenWidget.java Tue May 20 08:33:22 2008 @@ -263,6 +263,7 @@ protected FlexibleStringExpander idExdr; protected FlexibleStringExpander styleExdr; protected FlexibleStringExpander autoUpdateTargetExdr; + protected String autoUpdateInterval = "2"; protected List<ModelScreenWidget> subWidgets; public Container(ModelScreen modelScreen, Element containerElement) { @@ -270,6 +271,9 @@ this.idExdr = new FlexibleStringExpander(containerElement.getAttribute("id")); this.styleExdr = new FlexibleStringExpander(containerElement.getAttribute("style")); this.autoUpdateTargetExdr = new FlexibleStringExpander(containerElement.getAttribute("auto-update-target")); + if (containerElement.hasAttribute("auto-update-interval")) { + this.autoUpdateInterval = containerElement.getAttribute("auto-update-interval"); + } // read sub-widgets List subElementList = UtilXml.childElementList(containerElement); @@ -303,6 +307,10 @@ return this.autoUpdateTargetExdr.expandString(context); } + public String getAutoUpdateInterval() { + return this.autoUpdateInterval; + } + public String rawString() { return "<container id=\"" + this.idExdr.getOriginal() + "\" style=\"" + this.styleExdr.getOriginal() + "\" auto-update-target=\"" + this.autoUpdateTargetExdr.getOriginal() + "\">"; } @@ -1437,3 +1445,12 @@ } } + + + + + + + + + |
Free forum by Nabble | Edit this page |