Author: adrianc
Date: Fri May 31 17:07:00 2013
New Revision: 1488315

URL: http://svn.apache.org/r1488315
Log:
Fixed some bugs in the form widget column sorting code:

1. URL parameters were being mangled by clunky string manipulation code.
2. The sort column logic was piggy-backed on the pagination event. I created a 
new choice for the form widget <on-event-update-area> element - "sort-column" - 
so column sort events can update their own areas.
3. The parameter name for the sort column was hard-coded, so column sorting in 
multiple lists on the same screen would not work. I added a new <form> 
attribute - "sort-field-parameter-name" - so each list can be sorted separately.

Modified:
    ofbiz/trunk/framework/widget/dtd/widget-form.xsd
    
ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/MacroFormRenderer.java
    ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelForm.java

Modified: ofbiz/trunk/framework/widget/dtd/widget-form.xsd
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/dtd/widget-form.xsd?rev=1488315&r1=1488314&r2=1488315&view=diff
==============================================================================
--- ofbiz/trunk/framework/widget/dtd/widget-form.xsd (original)
+++ ofbiz/trunk/framework/widget/dtd/widget-form.xsd Fri May 31 17:07:00 2013
@@ -115,6 +115,14 @@ under the License.
             <xs:attribute type="xs:string" name="default-widget-style" />
             <xs:attribute type="xs:string" name="default-tooltip-style" />
             <xs:attribute type="xs:string" name="default-required-field-style" 
/>
+            <xs:attribute type="xs:string" name="sort-field-parameter-name">
+                <xs:annotation>
+                    <xs:documentation>
+                        The name of the request parameter that is used for 
specifying the sorted column. This is required when you
+                        have more than one list on a screen - each list must 
use its own sort field parameter. Defaults to "sortField".
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
             <xs:attribute type="xs:string" name="default-sort-field-style">
                 <xs:annotation>
                     <xs:documentation>CSS style to used for form sort fields. 
Defaults to "sort-order".</xs:documentation>
@@ -424,6 +432,7 @@ under the License.
                 <xs:simpleType>
                     <xs:restriction base="xs:token">
                         <xs:enumeration value="paginate" />
+                        <xs:enumeration value="sort-column" />
                         <xs:enumeration value="submit" />
                     </xs:restriction>
                 </xs:simpleType>

Modified: 
ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/MacroFormRenderer.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/MacroFormRenderer.java?rev=1488315&r1=1488314&r2=1488315&view=diff
==============================================================================
--- 
ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/MacroFormRenderer.java 
(original)
+++ 
ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/MacroFormRenderer.java 
Fri May 31 17:07:00 2013
@@ -353,7 +353,7 @@ public class MacroFormRenderer implement
         if (UtilValidate.isNotEmpty(textField.getMask())) {
             mask = textField.getMask();
         }
-        String ajaxUrl = createAjaxParamsFromUpdateAreas(updateAreas, null, 
context);
+        String ajaxUrl = createAjaxParamsFromUpdateAreas(updateAreas, "", 
context);
         boolean disabled = textField.disabled;
         StringWriter sr = new StringWriter();
         sr.append("<@renderTextField ");
@@ -1091,7 +1091,7 @@ public class MacroFormRenderer implement
         boolean ajaxEnabled = (updateAreas != null || 
UtilValidate.isNotEmpty(backgroundSubmitRefreshTarget)) && 
this.javaScriptEnabled;
         String ajaxUrl = "";
         if (ajaxEnabled) {
-            ajaxUrl = createAjaxParamsFromUpdateAreas(updateAreas, null, 
context);
+            ajaxUrl = createAjaxParamsFromUpdateAreas(updateAreas, "", 
context);
         }
         StringWriter sr = new StringWriter();
         sr.append("<@renderSubmitField ");
@@ -2037,7 +2037,7 @@ public class MacroFormRenderer implement
         this.appendContentUrl(imgSrc, "/images/fieldlookup.gif");
         String ajaxUrl = "";
         if (ajaxEnabled) {
-            ajaxUrl = createAjaxParamsFromUpdateAreas(updateAreas, null, 
context);
+            ajaxUrl = createAjaxParamsFromUpdateAreas(updateAreas, "", 
context);
         }
         String lookupPresentation = lookupField.getLookupPresentation();
         if (UtilValidate.isEmpty(lookupPresentation)) {
@@ -2679,21 +2679,21 @@ public class MacroFormRenderer implement
     public void renderSortField(Appendable writer, Map<String, Object> 
context, ModelFormField modelFormField, String titleText) throws IOException {
         boolean ajaxEnabled = false;
         ModelForm modelForm = modelFormField.getModelForm();
-        List<ModelForm.UpdateArea> updateAreas = 
modelForm.getOnPaginateUpdateAreas();
-        String targetService = modelForm.getPaginateTarget(context);
+        List<ModelForm.UpdateArea> updateAreas = 
modelForm.getOnSortColumnUpdateAreas();
+        if (updateAreas == null) {
+            // For backward compatibility.
+            updateAreas = modelForm.getOnPaginateUpdateAreas();
+        }
         if (this.javaScriptEnabled) {
             if (UtilValidate.isNotEmpty(updateAreas)) {
                 ajaxEnabled = true;
             }
         }
-        if (targetService == null) {
-            targetService = "${targetService}";
-        }
-        if (UtilValidate.isEmpty(targetService) && updateAreas == null) {
-            Debug.logWarning("Cannot sort because TargetService is empty for 
the form: " + modelForm.getName(), module);
+        String paginateTarget = modelForm.getPaginateTarget(context);
+        if (paginateTarget.isEmpty() && updateAreas == null) {
+            Debug.logWarning("Cannot sort because the paginate target URL is 
empty for the form: " + modelForm.getName(), module);
             return;
         }
-        String str = (String) context.get("_QBESTRING_");
         String oldSortField = modelForm.getSortField(context);
         String sortFieldStyle = modelFormField.getSortFieldStyle();
         // if the entry-name is defined use this instead of field name
@@ -2701,7 +2701,7 @@ public class MacroFormRenderer implement
         if (UtilValidate.isEmpty(columnField)) {
             columnField = modelFormField.getFieldName();
         }
-        // switch beetween asc/desc order
+        // switch between asc/desc order
         String newSortField = columnField;
         if (UtilValidate.isNotEmpty(oldSortField)) {
             if (oldSortField.equals(columnField)) {
@@ -2712,36 +2712,31 @@ public class MacroFormRenderer implement
                 sortFieldStyle = modelFormField.getSortFieldStyleAsc();
             }
         }
-        //  strip sortField param from the query string
-        HashSet<String> paramName = new HashSet<String>();
-        paramName.add("sortField");
-        String queryString = UtilHttp.stripNamedParamsFromQueryString(str, 
paramName);
-        String urlPath = UtilHttp.removeQueryStringFromTarget(targetService);
-        String prepLinkText = UtilHttp.getQueryStringFromTarget(targetService);
-        if (UtilValidate.isNotEmpty(queryString)) {
-            queryString = UtilHttp.encodeAmpersands(queryString);
-        }
-        if (prepLinkText == null) {
-            prepLinkText = "";
-        }
-        if (prepLinkText.indexOf("?") < 0) {
-            prepLinkText += "?";
-        } else if (!prepLinkText.endsWith("?")) {
-            prepLinkText += "&amp;";
-        }
-        if (!UtilValidate.isEmpty(queryString) && !queryString.equals("null")) 
{
-            prepLinkText += queryString + "&amp;";
-        }
-        prepLinkText += "sortField" + "=" + newSortField;
-        if (ajaxEnabled) {
-            prepLinkText = prepLinkText.replace("?", "");
-            prepLinkText = prepLinkText.replace("&amp;", "&");
-        }
-        String linkUrl = "";
+        String queryString = 
UtilHttp.getQueryStringFromTarget(paginateTarget).replace("?", "");
+        Map<String, Object> paramMap = 
UtilHttp.getQueryStringOnlyParameterMap(queryString);
+        String qbeString = (String) context.get("_QBESTRING_");
+        if (qbeString != null) {
+            qbeString = qbeString.replaceAll("&amp;", "&");
+            
paramMap.putAll(UtilHttp.getQueryStringOnlyParameterMap(qbeString));
+        }
+        paramMap.put(modelForm.getSortFieldParameterName(), newSortField);
+        UtilHttp.canonicalizeParameterMap(paramMap);
+        String linkUrl = null;
         if (ajaxEnabled) {
-            linkUrl = createAjaxParamsFromUpdateAreas(updateAreas, 
prepLinkText, context);
+            linkUrl = createAjaxParamsFromUpdateAreas(updateAreas, paramMap, 
null, context);
         } else {
-            linkUrl = rh.makeLink(this.request, this.response, urlPath + 
prepLinkText);
+            StringBuilder sb = new StringBuilder("?");
+            Iterator<Map.Entry<String, Object>> iter = 
paramMap.entrySet().iterator();
+            while (iter.hasNext()) {
+                Map.Entry<String, Object> entry = iter.next();
+                sb.append(entry.getKey()).append("=").append(entry.getValue());
+                if (iter.hasNext()) {
+                    sb.append("&amp;");
+                }
+            }
+            String newQueryString = sb.toString();
+            String urlPath = 
UtilHttp.removeQueryStringFromTarget(paginateTarget);
+            linkUrl = rh.makeLink(this.request, this.response, 
urlPath.concat(newQueryString));
         }
         StringWriter sr = new StringWriter();
         sr.append("<@renderSortField ");
@@ -2755,7 +2750,47 @@ public class MacroFormRenderer implement
         sr.append(Boolean.toString(ajaxEnabled));
         sr.append(" />");
         executeMacro(writer, sr.toString());
+    }
 
+    /** Create an ajaxXxxx JavaScript CSV string from a list of UpdateArea 
objects. See
+     * <code>selectall.js</code>.
+     * @param updateAreas
+     * @param extraParams Renderer-supplied additional target parameters
+     * @param context
+     * @return Parameter string or empty string if no UpdateArea objects were 
found
+     */
+    private String createAjaxParamsFromUpdateAreas(List<ModelForm.UpdateArea> 
updateAreas, Map<String, Object> extraParams, String anchor, Map<String, ? 
extends Object> context) {
+        StringBuilder sb = new StringBuilder();
+        Iterator<ModelForm.UpdateArea> updateAreaIter = updateAreas.iterator();
+        while (updateAreaIter.hasNext()) {
+            ModelForm.UpdateArea updateArea = updateAreaIter.next();
+            sb.append(updateArea.getAreaId()).append(",");
+            String ajaxTarget = updateArea.getAreaTarget(context);
+            String urlPath = UtilHttp.removeQueryStringFromTarget(ajaxTarget);
+            sb.append(this.rh.makeLink(this.request, 
this.response,urlPath)).append(",");
+            String queryString = 
UtilHttp.getQueryStringFromTarget(ajaxTarget).replace("?", "");
+            Map<String, Object> parameters = 
UtilHttp.getQueryStringOnlyParameterMap(queryString);
+            Map<String, Object> ctx = UtilGenerics.checkMap(context);
+            Map<String, Object> updateParams = 
UtilGenerics.checkMap(updateArea.getParameterMap(ctx));
+            parameters.putAll(updateParams);
+            UtilHttp.canonicalizeParameterMap(parameters);
+            parameters.putAll(extraParams);
+            Iterator<Map.Entry<String, Object>> paramIter = 
parameters.entrySet().iterator();
+            while (paramIter.hasNext()) {
+                Map.Entry<String, Object> entry = paramIter.next();
+                sb.append(entry.getKey()).append("=").append(entry.getValue());
+                if (paramIter.hasNext()) {
+                    sb.append("&");
+                }
+            }
+            if (anchor != null) {
+                sb.append("#").append(anchor);
+            }
+            if (updateAreaIter.hasNext()) {
+                sb.append(",");
+            }
+        }
+        return sb.toString();
     }
 
     /** Create an ajaxXxxx JavaScript CSV string from a list of UpdateArea 
objects. See

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=1488315&r1=1488314&r2=1488315&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 Fri 
May 31 17:07:00 2013
@@ -198,11 +198,14 @@ public class ModelForm extends ModelWidg
     protected FlexibleStringExpander rowCountExdr;
     protected List<ModelFormField> multiSubmitFields = FastList.newInstance();
     protected int rowCount = 0;
+    private String sortFieldParameterName = "sortField";
 
     /** On Submit areas to be updated. */
     protected List<UpdateArea> onSubmitUpdateAreas;
     /** On Paginate areas to be updated. */
     protected List<UpdateArea> onPaginateUpdateAreas;
+    /** On Sort Column areas to be updated. */
+    protected List<UpdateArea> onSortColumnUpdateAreas;
 
     // ===== CONSTRUCTORS =====
     /** Default Constructor */
@@ -305,6 +308,7 @@ public class ModelForm extends ModelWidg
                 this.defaultViewSize = parent.defaultViewSize;
                 this.onSubmitUpdateAreas = parent.onSubmitUpdateAreas;
                 this.onPaginateUpdateAreas = parent.onPaginateUpdateAreas;
+                this.onSortColumnUpdateAreas = parent.onSortColumnUpdateAreas;
                 this.altRowStyles = parent.altRowStyles;
 
                 this.useWhenFields = parent.useWhenFields;
@@ -324,6 +328,7 @@ public class ModelForm extends ModelWidg
                 this.fieldGroupMap = parent.fieldGroupMap;
                 this.fieldGroupList = parent.fieldGroupList;
                 this.lastOrderFields = parent.lastOrderFields;
+                this.sortFieldParameterName = parent.sortFieldParameterName;
 
             }
         }
@@ -462,7 +467,10 @@ public class ModelForm extends ModelWidg
         if (this.paginate == null || formElement.hasAttribute("paginate")) {
             this.paginate = 
FlexibleStringExpander.getInstance(formElement.getAttribute("paginate"));
         }
-
+        String sortFieldParameterName = 
formElement.getAttribute("sort-field-parameter-name");
+        if (!sortFieldParameterName.isEmpty()) {
+            this.sortFieldParameterName = sortFieldParameterName;
+        }
         this.skipStart = "true".equals(formElement.getAttribute("skip-start"));
         this.skipEnd = "true".equals(formElement.getAttribute("skip-end"));
         this.hideHeader = 
"true".equals(formElement.getAttribute("hide-header"));
@@ -686,6 +694,8 @@ public class ModelForm extends ModelWidg
             addOnPaginateUpdateArea(updateArea);
         } else if ("submit".equals(updateArea.getEventType())) {
             addOnSubmitUpdateArea(updateArea);
+        } else if ("sort-column".equals(updateArea.getEventType())) {
+            addOnSortColumnUpdateArea(updateArea);
         }
     }
 
@@ -718,6 +728,23 @@ public class ModelForm extends ModelWidg
         }
     }
 
+    protected void addOnSortColumnUpdateArea(UpdateArea updateArea) {
+        if (onSortColumnUpdateAreas == null) {
+            onSortColumnUpdateAreas = FastList.newInstance();
+        }
+        int index = onSortColumnUpdateAreas.indexOf(updateArea);
+        if (index != -1) {
+            if (UtilValidate.isNotEmpty(updateArea.areaTarget)) {
+                onSortColumnUpdateAreas.set(index, updateArea);
+            } else {
+                // blank target indicates a removing override
+                onSortColumnUpdateAreas.remove(index);
+            }
+        } else {
+            onSortColumnUpdateAreas.add(updateArea);
+        }
+    }
+
     public void addAutoFieldsFromService(AutoFieldsService autoFieldsService) {
         autoFieldsServices.add(autoFieldsService);
 
@@ -2335,6 +2362,10 @@ public class ModelForm extends ModelWidg
         this.type = string;
     }
 
+    public List<UpdateArea> getOnSortColumnUpdateAreas() {
+        return this.onSortColumnUpdateAreas;
+    }
+
     public List<UpdateArea> getOnPaginateUpdateAreas() {
         return this.onPaginateUpdateAreas;
     }
@@ -2758,24 +2789,25 @@ public class ModelForm extends ModelWidg
     }
 
     public String getSortField(Map<String, Object> context) {
-        String field = "sortField";
         String value = null;
-
         try {
-            value = (String)context.get(field);
+            value = (String)context.get(this.sortFieldParameterName);
             if (value == null) {
                 Map<String, String> parameters = 
UtilGenerics.cast(context.get("parameters"));
                 if (parameters != null) {
-                    value = parameters.get(field);
+                    value = parameters.get(this.sortFieldParameterName);
                 }
             }
         } catch (Exception e) {
             Debug.logWarning(e, "Error getting sortField: " + e.toString(), 
module);
         }
-
         return value;
     }
 
+    public String getSortFieldParameterName() {
+        return this.sortFieldParameterName;
+    }
+
     /* Returns the list of ModelForm.UpdateArea objects.
      */
     public List<UpdateArea> getOnSubmitUpdateAreas() {


Reply via email to