From 17317bb4ca92183cbca48557d09455b2a16605fb Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 5 Jun 2012 18:08:43 -0700 Subject: [PATCH] supported more complex relative path --- core/src/main/java/hudson/RelativePath.java | 19 ++++++++++++-- .../main/webapp/scripts/hudson-behavior.js | 25 +++++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/hudson/RelativePath.java b/core/src/main/java/hudson/RelativePath.java index 0beadad283..c5f562db3b 100644 --- a/core/src/main/java/hudson/RelativePath.java +++ b/core/src/main/java/hudson/RelativePath.java @@ -14,8 +14,23 @@ import static java.lang.annotation.RetentionPolicy.*; * nearby parameters that belong to different parents. * *

- * Currently, "..", "../..", etc. are supported to indicate - * parameters that belong to the ancestors. + * ".." refers + * to values in the parent object, and "foo" refers to the child + * object of the current object named "foo". They can be combined + * with '/' like path, such as "../foo/bar", "../..", and etc. + * + *

+ * A good way to think about this is the file system structure. + * {@code @RelativePath} is like the dirname, and {@code QueryParameter} + * is like the basename. Together they form a relative path. + * And because of the structured form submissions, + * form elements are organized in a tree structure of JSON objects, + * which is akin to directories and files. + * + *

+ * The relative path then points from the current input element + * (for which you are doing form validation, for example) to the target + * input element that you want to obtain the value. * * @author Kohsuke Kawaguchi * @since 1.376 diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js index c274df4eb7..834f3fe64e 100644 --- a/war/src/main/webapp/scripts/hudson-behavior.js +++ b/war/src/main/webapp/scripts/hudson-behavior.js @@ -144,6 +144,9 @@ var FormChecker = { * @param {string} name * Name of the control to find. Can include "../../" etc in the prefix. * See @RelativePath. + * + * We assume that the name is normalized and doesn't contain any redundant component. + * That is, ".." can only appear as prefix, and "foo/../bar" is not OK (because it can be reduced to "bar") */ function findNearBy(e,name) { while (name.startsWith("../")) { @@ -151,21 +154,33 @@ function findNearBy(e,name) { e = findFormParent(e,null,true); } + // name="foo/bar/zot" -> prefixes=["bar","foo"] & name="zot" + var prefixes = name.split("/"); + name = prefixes.pop(); + prefixes = prefixes.reverse(); + // does 'e' itself match the criteria? // as some plugins use the field name as a parameter value, instead of 'value' var p = findFormItem(e,name,function(e,filter) { - if (filter(e)) return e; - return null; + return filter(e) ? e : null; }); - if (p!=null) return p; + if (p!=null && prefixes.length==0) return p; var owner = findFormParent(e,null,true); - function locate(iterator,e) { + function locate(iterator,e) {// keep finding elements until we find the good match while (true) { e = iterator(e,name); if (e==null) return null; - if (findFormParent(e,null,true)==owner) + + // make sure this candidate element 'e' is in the right point in the hierarchy + var p = e; + for (var i=0; i