Author: apatel
Date: Thu Jul 10 12:17:36 2008 New Revision: 675688 URL: http://svn.apache.org/viewvc?rev=675688&view=rev Log: Initial implementation of Ajax InPlaceEditor for form widget Display field. Mridul, Thanks for your effort. Modified: ofbiz/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml ofbiz/trunk/framework/images/webapp/images/prototypejs/controls.js ofbiz/trunk/framework/images/webapp/images/selectall.js ofbiz/trunk/framework/widget/dtd/widget-form.xsd ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelFormField.java ofbiz/trunk/framework/widget/src/org/ofbiz/widget/html/HtmlFormRenderer.java Modified: ofbiz/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml?rev=675688&r1=675687&r2=675688&view=diff ============================================================================== --- ofbiz/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml (original) +++ ofbiz/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml Thu Jul 10 12:17:36 2008 @@ -1018,6 +1018,14 @@ <event type="service" invoke="deleteEmploymentApp"/> <response name="success" type="request" value="EditEmploymentApps"/> </request-map> + + <!-- Ajax Requests --> + <request-map uri="ajaxUpdatePartyGroup"> + <security https="true" auth="true"/> + <event type="jsonservice" path="" invoke="updatePartyGroup"/> + <response name="success" type="none"/> + <response name="error" type="none"/> + </request-map> <!-- Lookup request mappings --> <request-map uri="LookupPartyName"><security https="true" auth="true"/><response name="success" type="view" value="LookupPartyName"/></request-map> Modified: ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml?rev=675688&r1=675687&r2=675688&view=diff ============================================================================== --- ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml (original) +++ ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml Thu Jul 10 12:17:36 2008 @@ -101,6 +101,14 @@ <form name="ViewPartyGroup" type="single" default-map-name="lookupGroup"> <auto-fields-entity entity-name="PartyGroup" default-field-type="display"/> <field name="partyTypeId"><ignored/></field> + <field name="groupName" id-name="groupName" widget-style="label"> + <display> + <in-place-editor url="/partymgr/control/ajaxUpdatePartyGroup" cancel-control="button" saving-text="Updating..." text-between-controls=" "> + <simple-editor/> + <field-map field-name="partyId" env-name="lookupGroup.partyId"/> + </in-place-editor> + </display> + </field> <field name="comments"><ignored/></field> <field name="logoImageUrl"><ignored/></field> <field name="description" title="${uiLabelMap.CommonDescription}"><display/></field> @@ -631,4 +639,4 @@ </field> <field name="fromDate"><display/></field> </form> -</forms> \ No newline at end of file +</forms> Modified: ofbiz/trunk/framework/images/webapp/images/prototypejs/controls.js URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/prototypejs/controls.js?rev=675688&r1=675687&r2=675688&view=diff ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/prototypejs/controls.js (original) +++ ofbiz/trunk/framework/images/webapp/images/prototypejs/controls.js Thu Jul 10 12:17:36 2008 @@ -521,6 +521,7 @@ this.element = element = $(element); this.prepareOptions(); this._controls = { }; + this._paramValue = ''; arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! Object.extend(this.options, options || { }); if (!this.options.formId && this.element.id) { @@ -539,6 +540,7 @@ this._boundFailureHandler = this.handleAJAXFailure.bind(this); this._boundSubmitHandler = this.handleFormSubmission.bind(this); this._boundWrapperHandler = this.wrapUp.bind(this); + this._boundSuccessHandler = this.updateElement.bind(this); this.registerListeners(); }, checkForEscapeOrReturn: function(e) { @@ -659,6 +661,7 @@ handleFormSubmission: function(e) { var form = this._form; var value = $F(this._controls.editor); + this._paramValue = value; this.prepareSubmission(); var params = this.options.callback(form, value) || ''; if (Object.isString(params)) @@ -677,12 +680,16 @@ Object.extend(options, { parameters: params, onComplete: this._boundWrapperHandler, - onFailure: this._boundFailureHandler + onFailure: this._boundFailureHandler, + onSuccess: this._boundSuccessHandler }); new Ajax.Request(this.url, options); } if (e) Event.stop(e); }, + updateElement: function() { + $(this.element).update(this._paramValue); + }, leaveEditMode: function() { this.element.removeClassName(this.options.savingClassName); this.removeForm(); Modified: ofbiz/trunk/framework/images/webapp/images/selectall.js URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/selectall.js?rev=675688&r1=675687&r2=675688&view=diff ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/selectall.js (original) +++ ofbiz/trunk/framework/images/webapp/images/selectall.js Thu Jul 10 12:17:36 2008 @@ -393,6 +393,16 @@ }); } +/** In Place Editor for display elements + * @param element The id of the display field + * @param url The request to be called to update the display field + * @param options Options to be passed to Ajax.InPlaceEditor +*/ + +function ajaxInPlaceEditDisplayField(element, url, options) { + options.htmlResponse = false; + new Ajax.InPlaceEditor($(element), url, options); +} // ===== End of Ajax Functions ===== // function replaceQueryParam(queryString, currentParam, newParam) { Modified: ofbiz/trunk/framework/widget/dtd/widget-form.xsd URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/dtd/widget-form.xsd?rev=675688&r1=675687&r2=675688&view=diff ============================================================================== --- ofbiz/trunk/framework/widget/dtd/widget-form.xsd (original) +++ ofbiz/trunk/framework/widget/dtd/widget-form.xsd Thu Jul 10 12:17:36 2008 @@ -547,6 +547,9 @@ </xs:attributeGroup> <xs:element name="display" substitutionGroup="AllFields"> <xs:complexType> + <xs:sequence> + <xs:element ref="in-place-editor" minOccurs="0" maxOccurs="1"/> + </xs:sequence> <xs:attributeGroup ref="attlist.display"/> </xs:complexType> </xs:element> @@ -1130,6 +1133,82 @@ <xs:attributeGroup name="attlist.entity-order-by"> <xs:attribute type="xs:string" name="field-name" use="required"/> </xs:attributeGroup> + <xs:element name="in-place-editor"> + <xs:annotation> + <xs:documentation>Enables in place editon for the display field.</xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:sequence> + <xs:choice minOccurs="1" maxOccurs="1"> + <xs:element ref="simple-editor"/> + </xs:choice> + <xs:element ref="field-map" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attributeGroup ref="attlist.in-place-editor"/> + </xs:complexType> + </xs:element> + <xs:attributeGroup name="attlist.in-place-editor"> + <xs:attribute name="url" type="xs:string" use="required"/> + <xs:attribute name="cancel-control"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="link"/> + <xs:enumeration value="button"/> + <xs:enumeration value="false"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="cancel-text" type="xs:string"/> + <xs:attribute name="click-to-edit-text" type="xs:string"/> + <xs:attribute name="field-post-creation"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="activate"/> + <xs:enumeration value="focus"/> + <xs:enumeration value="false"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="form-class-name" type="xs:string"/> + <xs:attribute name="form-id" type="xs:string"/> + <xs:attribute name="highlight-color" type="xs:string"/> + <xs:attribute name="highlight-end-color" type="xs:string"/> + <xs:attribute name="hover-class-name" type="xs:string"/> + <xs:attribute name="html-response"> + <xs:simpleType> + <xs:restriction base="xs:token"> + <xs:enumeration value="false"/> + <xs:enumeration value="true"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="loading-class-name" type="xs:string"/> + <xs:attribute name="loading-text" type="xs:string"/> + <xs:attribute name="ok-control"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="link"/> + <xs:enumeration value="button"/> + <xs:enumeration value="false"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="ok-text" type="xs:string"/> + <xs:attribute name="param-name" type="xs:string"/> + <xs:attribute name="saving-class-name" type="xs:string"/> + <xs:attribute name="saving-text" type="xs:string"/> + <xs:attribute name="submit-on-blur"> + <xs:simpleType> + <xs:restriction base="xs:token"> + <xs:enumeration value="false"/> + <xs:enumeration value="true"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="text-after-controls" type="xs:string"/> + <xs:attribute name="text-before-controls" type="xs:string"/> + <xs:attribute name="text-between-controls" type="xs:string"/> + </xs:attributeGroup> <xs:element name="list-options"> <xs:annotation> <xs:documentation>list-options will create options based on data in a list</xs:documentation> @@ -1178,6 +1257,15 @@ <xs:annotation><xs:documentation>What the user will see in the widget; defaults to the value of the key attribute.</xs:documentation></xs:annotation> </xs:attribute> </xs:attributeGroup> + <xs:element name="simple-editor"> + <xs:complexType> + <xs:attributeGroup ref="attlist.simple-editor"/> + </xs:complexType> + </xs:element> + <xs:attributeGroup name="attlist.simple-editor"> + <xs:attribute name="rows" type="xs:positiveInteger" default="1"/> + <xs:attribute name="cols" type="xs:positiveInteger" default="40"/> + </xs:attributeGroup> <xs:element name="sub-hyperlink"> <xs:complexType> <xs:attributeGroup ref="attlist.sub-hyperlink"/> Modified: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelFormField.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelFormField.java?rev=675688&r1=675687&r2=675688&view=diff ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelFormField.java (original) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/form/ModelFormField.java Thu Jul 10 12:17:36 2008 @@ -1772,12 +1772,268 @@ } } + public static class InPlaceEditor { + protected FlexibleStringExpander url; + protected String cancelControl; + protected String cancelText; + protected String clickToEditText; + protected String fieldPostCreation; + protected String formClassName; + protected String highlightColor; + protected String highlightEndColor; + protected String hoverClassName; + protected String htmlResponse; + protected String loadingClassName; + protected String loadingText; + protected String okControl; + protected String okText; + protected String paramName; + protected String savingClassName; + protected String savingText; + protected String submitOnBlur; + protected String textBeforeControls; + protected String textAfterControls; + protected String textBetweenControls; + protected String rows; + protected String cols; + protected Map<FlexibleMapAccessor, Object> fieldMap; + + public InPlaceEditor (Element element) { + this.setUrl(element.getAttribute("url")); + this.cancelControl = element.getAttribute("cancel-control"); + this.cancelText = element.getAttribute("cancel-text"); + this.clickToEditText = element.getAttribute("click-to-edit-text"); + this.fieldPostCreation = element.getAttribute("field-post-creation"); + this.formClassName = element.getAttribute("form-class-name"); + this.highlightColor = element.getAttribute("highlight-color"); + this.highlightEndColor = element.getAttribute("highlight-end-color"); + this.hoverClassName = element.getAttribute("hover-class-name"); + this.htmlResponse = element.getAttribute("html-response"); + this.loadingClassName = element.getAttribute("loading-class-name"); + this.loadingText = element.getAttribute("loading-text"); + this.okControl = element.getAttribute("ok-control"); + this.okText = element.getAttribute("ok-text"); + this.paramName = element.getAttribute("param-name"); + this.savingClassName = element.getAttribute("saving-class-name"); + this.savingText = element.getAttribute("saving-text"); + this.submitOnBlur = element.getAttribute("submit-on-blur"); + this.textBeforeControls = element.getAttribute("text-before-controls"); + this.textAfterControls = element.getAttribute("text-after-controls"); + this.textBetweenControls = element.getAttribute("text-between-controls"); + + Element simpleElement = UtilXml.firstChildElement(element, "simple-editor"); + this.rows = simpleElement.getAttribute("rows"); + this.cols = simpleElement.getAttribute("cols"); + + this.fieldMap = EntityFinderUtil.makeFieldMap(element); + } + + public String getUrl(Map<String, Object> context) { + if (this.url != null) { + return this.url.expandString(context); + } else { + return ""; + } + } + + public String getCancelControl() { + return cancelControl; + } + + public String getCancelText() { + return cancelText; + } + + public String getClickToEditText() { + return clickToEditText; + } + + public String getFieldPostCreation() { + return fieldPostCreation; + } + + public String getFormClassName() { + return formClassName; + } + + public String getHighlightColor() { + return highlightColor; + } + + public String getHighlightEndColor() { + return highlightEndColor; + } + + public String getHoverClassName() { + return hoverClassName; + } + + public String getHtmlResponse() { + return htmlResponse; + } + + public String getLoadingClassName() { + return loadingClassName; + } + + public String getLoadingText() { + return loadingText; + } + + public String getOkControl() { + return okControl; + } + + public String getOkText() { + return okText; + } + + public String getParamName() { + return paramName; + } + + public String getSavingClassName() { + return savingClassName; + } + + public String getSavingText() { + return savingText; + } + + public String getSubmitOnBlur() { + return submitOnBlur; + } + + public String getTextBeforeControls() { + return textBeforeControls; + } + + public String getTextAfterControls() { + return textAfterControls; + } + + public String getTextBetweenControls() { + return textBetweenControls; + } + + public String getRows() { + return rows; + } + + public String getCols() { + return cols; + } + + public Map<String, Object> getFieldMap(Map<String, Object> context) { + Map<String, Object> inPlaceEditorContext = new HashMap<String, Object>(); + EntityFinderUtil.expandFieldMapToContext(this.fieldMap, context, inPlaceEditorContext); + return inPlaceEditorContext; + } + + public void setUrl(String url) { + this.url = new FlexibleStringExpander(url); + } + + public void setCancelControl(String string) { + this.cancelControl = string; + } + + public void setCancelText(String string) { + this.cancelText = string; + } + + public void setClickToEditText(String string) { + this.clickToEditText = string; + } + + public void setFieldPostCreation(String string) { + this.fieldPostCreation = string; + } + + public void setFormClassName(String string) { + this.formClassName = string; + } + + public void setHighlightColor(String string) { + this.highlightColor = string; + } + + public void setHighlightEndColor(String string) { + this.highlightEndColor = string; + } + + public void setHoverClassName(String string) { + this.hoverClassName = string; + } + + public void setHtmlResponse(String string) { + this.htmlResponse = string; + } + + public void setLoadingClassName(String string) { + this.loadingClassName = string; + } + + public void setLoadingText(String string) { + this.loadingText = string; + } + + public void setOkControl(String string) { + this.okControl = string; + } + + public void setOkText(String string) { + this.okText = string; + } + + public void setParamName(String string) { + this.paramName = string; + } + + public void setSavingClassName(String string) { + this.savingClassName = string; + } + + public void setSavingText(String string) { + this.savingText = string; + } + + public void setSubmitOnBlur(String string) { + this.submitOnBlur = string; + } + + public void setTextBeforeControls(String string) { + this.textBeforeControls = string; + } + + public void setTextAfterControls(String string) { + this.textAfterControls = string; + } + + public void setTextBetweenControls(String string) { + this.textBetweenControls = string; + } + + public void setRows(String string) { + this.rows = string; + } + + public void setCols(String string) { + this.cols = string; + } + + public void setFieldMap(Map<FlexibleMapAccessor, Object> fieldMap) { + this.fieldMap = fieldMap; + } + } + public static class DisplayField extends FieldInfo { protected boolean alsoHidden = true; protected FlexibleStringExpander description; protected String type; // matches type of field, currently text or currency protected FlexibleStringExpander currency; protected FlexibleStringExpander date; + protected InPlaceEditor inPlaceEditor; protected DisplayField() { super(); @@ -1798,6 +2054,11 @@ this.setDescription(element.getAttribute("description")); this.setDate(element.getAttribute("date")); this.alsoHidden = !"false".equals(element.getAttribute("also-hidden")); + + Element inPlaceEditorElement = UtilXml.firstChildElement(element, "in-place-editor"); + if (inPlaceEditorElement != null) { + this.inPlaceEditor = new InPlaceEditor(inPlaceEditorElement); + } } public void renderFieldString(Appendable writer, Map<String, Object> context, FormStringRenderer formStringRenderer) throws IOException { @@ -1843,6 +2104,10 @@ } return retVal; } + + public InPlaceEditor getInPlaceEditor() { + return this.inPlaceEditor; + } /** * @param b @@ -1870,6 +2135,10 @@ public void setDate(String string) { date = new FlexibleStringExpander(string); } + + public void setInPlaceEditor(InPlaceEditor newInPlaceEditor) { + this.inPlaceEditor = newInPlaceEditor; + } } public static class DisplayEntityField extends DisplayField { 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=675688&r1=675687&r2=675688&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 Thu Jul 10 12:17:36 2008 @@ -26,6 +26,8 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -193,6 +195,101 @@ if (str.length() > 0) { writer.append("</span>"); } + + ModelFormField.InPlaceEditor inPlaceEditor = displayField.getInPlaceEditor(); + boolean ajaxEnabled = inPlaceEditor != null && this.javaScriptEnabled; + + if (ajaxEnabled) { + writer.append("<script language=\"JavaScript\" type=\"text/javascript\">"); + String url = inPlaceEditor.getUrl(context); + Map<String, Object> fieldMap = inPlaceEditor.getFieldMap(context); + if (fieldMap != null) { + url += '?'; + Set<Entry<String, Object>> fieldSet = fieldMap.entrySet(); + Iterator<Entry<String, Object>> fieldIterator = fieldSet.iterator(); + int count = 0; + while (fieldIterator.hasNext()) { + count++; + Entry<String, Object> field = fieldIterator.next(); + url += (String) field.getKey() + '=' + (String) field.getValue(); + if (count < fieldSet.size()) { + url += '&'; + } + } + } + writer.append("ajaxInPlaceEditDisplayField('"); + writer.append(modelFormField.getIdName() + "', '" +url+ "', {"); + if (UtilValidate.isNotEmpty(inPlaceEditor.getParamName())) { + writer.append("paramName: '" +inPlaceEditor.getParamName()+ "'"); + } else { + writer.append("paramName: '" +modelFormField.getFieldName()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getCancelControl())) { + writer.append(", cancelControl: '" +inPlaceEditor.getCancelControl()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getCancelText())) { + writer.append(", cancelText: '" +inPlaceEditor.getCancelText()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getClickToEditText())) { + writer.append(", clickToEditText: '" +inPlaceEditor.getClickToEditText()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getFieldPostCreation())) { + writer.append(", fieldPostCreation: '" +inPlaceEditor.getFieldPostCreation()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getFormClassName())) { + writer.append(", formClassName: '" +inPlaceEditor.getFormClassName()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getHighlightColor())) { + writer.append(", highlightColor: '" +inPlaceEditor.getHighlightColor()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getHighlightEndColor())) { + writer.append(", highlightEndColor: '" +inPlaceEditor.getHighlightEndColor()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getHoverClassName())) { + writer.append(", hoverClassName: '" +inPlaceEditor.getHoverClassName()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getHtmlResponse())) { + writer.append(", htmlResponse: " +inPlaceEditor.getHtmlResponse()); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getLoadingClassName())) { + writer.append(", loadingClassName: '" +inPlaceEditor.getLoadingClassName()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getLoadingText())) { + writer.append(", loadingText: '" +inPlaceEditor.getLoadingText()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getOkControl())) { + writer.append(", okControl: '" +inPlaceEditor.getOkControl()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getOkText())) { + writer.append(", okText: '" +inPlaceEditor.getOkText()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getSavingClassName())) { + writer.append(", savingClassName: '" +inPlaceEditor.getSavingClassName()+ "', "); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getSavingText())) { + writer.append(", savingText: '" +inPlaceEditor.getSavingText()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getSubmitOnBlur())) { + writer.append(", submitOnBlur: " +inPlaceEditor.getSubmitOnBlur()); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getTextBeforeControls())) { + writer.append(", textBeforeControls: '" +inPlaceEditor.getTextBeforeControls()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getTextAfterControls())) { + writer.append(", textAfterControls: '" +inPlaceEditor.getTextAfterControls()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getTextBetweenControls())) { + writer.append(", textBetweenControls: '" +inPlaceEditor.getTextBetweenControls()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getRows())) { + writer.append(", rows: '" +inPlaceEditor.getRows()+ "'"); + } + if (UtilValidate.isNotEmpty(inPlaceEditor.getCols())) { + writer.append(", cols: '" +inPlaceEditor.getCols()+ "'"); + } + writer.append("});"); + writer.append("</script>"); + } if (displayField instanceof DisplayEntityField) { this.makeHyperlinkString(writer, ((DisplayEntityField) displayField).getSubHyperlink(), context); |
Free forum by Nabble | Edit this page |