diff --git a/src/helma/framework/core/Application.java b/src/helma/framework/core/Application.java index d0664eba..ae5de2d1 100644 --- a/src/helma/framework/core/Application.java +++ b/src/helma/framework/core/Application.java @@ -1194,25 +1194,60 @@ public final class Application implements Runnable { /** * Return the href to the root of this application. + * @return the root element's URL + * @throws UnsupportedEncodingException if the application's charset property + * is not a valid encoding name */ public String getRootHref() throws UnsupportedEncodingException { - return getNodeHref(null, null); + return getNodeHref(null, null, null); } /** * Return a path to be used in a URL pointing to the given element and action + * @param elem the object to get the URL for + * @param actionName an optional action name + * @param queryParams optional map of query parameters + * @return the element's URL + * @throws UnsupportedEncodingException if the application's charset property + * is not a valid encoding name */ - public String getNodeHref(Object elem, String actionName) + public String getNodeHref(Object elem, String actionName, Map queryParams) throws UnsupportedEncodingException { - StringBuffer b = new StringBuffer(baseURI); + StringBuffer buffer = new StringBuffer(baseURI); - composeHref(elem, b, 0); + composeHref(elem, buffer, 0); if (actionName != null) { - b.append(UrlEncoded.encode(actionName, charset)); + buffer.append(UrlEncoded.encode(actionName, charset)); + } + if (queryParams != null) { + appendQueryParams(buffer, queryParams, null, 0); } - return b.toString(); + return buffer.toString(); + } + + private int appendQueryParams(StringBuffer buffer, Map params, + String prefix, int count) + throws UnsupportedEncodingException { + for (Iterator it = params.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + Object value = entry.getValue(); + if (value == null) { + continue; + } + String key = UrlEncoded.encode(entry.getKey().toString(), charset); + if (prefix != null) key = prefix + '[' + key + ']'; + if (value instanceof Map) { + count = appendQueryParams(buffer, (Map) value, key, count); + } else { + buffer.append(count++ == 0 ? '?' : '&'); + buffer.append(key); + buffer.append('='); + buffer.append(UrlEncoded.encode(value.toString(), charset)); + } + } + return count; } private void composeHref(Object elem, StringBuffer b, int pathCount) diff --git a/src/helma/scripting/rhino/HopObject.java b/src/helma/scripting/rhino/HopObject.java index 512f822d..d69e8ce0 100644 --- a/src/helma/scripting/rhino/HopObject.java +++ b/src/helma/scripting/rhino/HopObject.java @@ -292,30 +292,33 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco } /** - * Get the href (URL path) of this object within the application. - * - * @param action the action name, or null/undefined for the "main" action. - * - * @return ... + * Get the URL for this object with the application + * @param action optional action name + * @param params optional query parameters + * @return the URL for the object + * @throws UnsupportedEncodingException if the application's charset property + * is not a valid encoding name */ - public Object jsFunction_href(Object action) throws UnsupportedEncodingException, - IOException { + public Object jsFunction_href(Object action, Object params) + throws UnsupportedEncodingException, IOException { if (proxy == null) { return null; } - String act = null; + String actionName = null; + Map queryParams = params instanceof Scriptable ? + core.scriptableToProperties((Scriptable) params) : null; INode node = getNode(); if (action != null) { if (action instanceof Wrapper) { - act = ((Wrapper) action).unwrap().toString(); + actionName = ((Wrapper) action).unwrap().toString(); } else if (!(action instanceof Undefined)) { - act = action.toString(); + actionName = action.toString(); } } - String basicHref = core.app.getNodeHref(node, act); + String basicHref = core.app.getNodeHref(node, actionName, queryParams); return core.postProcessHref(node, className, basicHref); } @@ -931,8 +934,8 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco return node.getName(); } - if ("__fullname__".equals(name)) { - return node.getFullName(); + if ("__path__".equals(name)) { + return node.getPath(); } if ("__hash__".equals(name)) { diff --git a/src/helma/scripting/rhino/JavaObject.java b/src/helma/scripting/rhino/JavaObject.java index e3f0234b..feef345c 100644 --- a/src/helma/scripting/rhino/JavaObject.java +++ b/src/helma/scripting/rhino/JavaObject.java @@ -110,30 +110,32 @@ public class JavaObject extends NativeJavaObject { } /** - * - * - * @param action ... - * - * @return ... + * Get the URL for this object with the application + * @param action optional action name + * @param params optional query parameters + * @return the URL for the object + * @throws UnsupportedEncodingException if the application's charset property + * is not a valid encoding name */ - public Object href(Object action) throws UnsupportedEncodingException, - IOException { + public Object href(Object action, Object params) + throws UnsupportedEncodingException, IOException { if (javaObject == null) { return null; } - String act = null; + String actionName = null; + Map queryParams = params instanceof Scriptable ? + core.scriptableToProperties((Scriptable) params) : null; if (action != null) { if (action instanceof Wrapper) { - act = ((Wrapper) action).unwrap().toString(); + actionName = ((Wrapper) action).unwrap().toString(); } else if (!(action instanceof Undefined)) { - act = action.toString(); + actionName = action.toString(); } } - String basicHref = core.app.getNodeHref(javaObject, act); - + String basicHref = core.app.getNodeHref(javaObject, actionName, queryParams); return core.postProcessHref(javaObject, protoName, basicHref); } diff --git a/src/helma/scripting/rhino/RhinoCore.java b/src/helma/scripting/rhino/RhinoCore.java index ca975e12..dc27a969 100644 --- a/src/helma/scripting/rhino/RhinoCore.java +++ b/src/helma/scripting/rhino/RhinoCore.java @@ -802,10 +802,13 @@ public final class RhinoCore implements ScopeProvider { if (ids[i] instanceof String) { String key = (String) ids[i]; Object value = obj.get(key, obj); + // Normalize values to either null, string, or nested map if (value == Undefined.instance || value == Scriptable.NOT_FOUND) { value = null; } else if (value instanceof Scriptable) { value = scriptableToProperties((Scriptable) value); + } else { + value = ScriptRuntime.toString(value); } props.put(key, value); } @@ -1197,7 +1200,7 @@ public final class RhinoCore implements ScopeProvider { cx.setWrapFactory(wrapper); cx.setOptimizationLevel(optLevel); cx.setInstructionObserverThreshold(10000); - if (cx.isValidLanguageVersion(languageVersion)) { + if (Context.isValidLanguageVersion(languageVersion)) { cx.setLanguageVersion(languageVersion); } else { app.logError("Unsupported rhino.languageVersion: " + languageVersion);