diff --git a/changelog.html b/changelog.html
index d4295ee18e4f333f97edf8562213d09c8dc6d902..1474d2405d9cfae80ee2e2862329cde34279d435 100644
--- a/changelog.html
+++ b/changelog.html
@@ -56,6 +56,11 @@ Upcoming changes
-
+ Refactored
behavior.js
to run more predictably.
+ Plugin JavaScript should use Behaviour.specify
in place of
+ Behaviour.register
, Behaviour.list
,
+ hudsonRules
, and jenkinsRules
.
+ (issue 14495 cont'd)
Fixed a possible race condition in the remoting layer.
(issue 14909)
-
diff --git a/core/src/main/resources/hudson/PluginManager/_table.js b/core/src/main/resources/hudson/PluginManager/_table.js
index 7f666624bafd1c182b0186d68c3b089e604b50ef..785ad45551741b7615f47a2457a62e0dd64e1578 100644
--- a/core/src/main/resources/hudson/PluginManager/_table.js
+++ b/core/src/main/resources/hudson/PluginManager/_table.js
@@ -20,8 +20,7 @@ function showhideCategory(col) {
row.style.display = newDisplay;
}
-Behaviour.register({
- "#filter-box": function(e) {
+Behaviour.specify("#filter-box", '_table', 0, function(e) {
function applyFilter() {
var filter = e.value.toLowerCase();
["TR.plugin","TR.plugin-category"].each(function(clz) {
@@ -36,5 +35,4 @@ Behaviour.register({
}
e.onkeyup = applyFilter;
- }
});
diff --git a/core/src/main/resources/hudson/console/ExpandableDetailsNote/script.js b/core/src/main/resources/hudson/console/ExpandableDetailsNote/script.js
index 569707427deee1bf9f477a2f483454504a5c0aaa..39b041f4d9dbb8f2fae849ead185ddf9e0fbebdf 100644
--- a/core/src/main/resources/hudson/console/ExpandableDetailsNote/script.js
+++ b/core/src/main/resources/hudson/console/ExpandableDetailsNote/script.js
@@ -1,11 +1,8 @@
(function() {
- Behaviour.register({
-
- "INPUT.reveal-expandable-detail" : function(e) {
+ Behaviour.specify("INPUT.reveal-expandable-detail", 'ExpandableDetailsNote', 0, function(e) {
var detail = e.nextSibling;
makeButton(e,function() {
detail.style.display = (detail.style.display=="block")?"none":"block";
});
- }
});
}());
diff --git a/core/src/main/resources/hudson/matrix/LabelAxis/config.jelly b/core/src/main/resources/hudson/matrix/LabelAxis/config.jelly
index c1db0de3821969401710db24cdcccdfe5b4a07f0..28804d7f79b734a7128f358cca8d0d60570a98cd 100644
--- a/core/src/main/resources/hudson/matrix/LabelAxis/config.jelly
+++ b/core/src/main/resources/hudson/matrix/LabelAxis/config.jelly
@@ -29,7 +29,7 @@ THE SOFTWARE.
diff --git a/core/src/main/resources/hudson/security/GlobalMatrixAuthorizationStrategy/config.jelly b/core/src/main/resources/hudson/security/GlobalMatrixAuthorizationStrategy/config.jelly
index f5e9fae5e198358e77bbd93c391ef33ed947fdc6..51a70d8ea055891594a2bb83fb3a12d930e6ac21 100644
--- a/core/src/main/resources/hudson/security/GlobalMatrixAuthorizationStrategy/config.jelly
+++ b/core/src/main/resources/hudson/security/GlobalMatrixAuthorizationStrategy/config.jelly
@@ -144,16 +144,15 @@ THE SOFTWARE.
});
})();
- Behaviour.register({
- "#${strategyid} TD.stop A.remove" : function(e) {
+ Behaviour.specify("#${strategyid} TD.stop A.remove", 'GlobalMatrixAuthorizationStrategy', 0, function(e) {
e.onclick = function() {
var tr = findAncestor(this,"TR");
tr.parentNode.removeChild(tr);
return false;
}
e = null;
- },
- "#${strategyid} TD.stop A.toggleall" : function(e) {
+ });
+ Behaviour.specify("#${strategyid} TD.stop A.toggleall", 'GlobalMatrixAuthorizationStrategy', 0, function(e) {
e.onclick = function() {
var tr = findAncestor(this,"TR");
var inputs = tr.getElementsByTagName("INPUT");
@@ -163,15 +162,14 @@ THE SOFTWARE.
return false;
};
e = null;
- },
+ });
- "#${strategyid} TR.permission-row" : function(e) {
+ Behaviour.specify("#${strategyid} TR.permission-row", 'GlobalMatrixAuthorizationStrategy', 0, function(e) {
FormChecker.delayedCheck("${descriptorPath}/checkName?value="+encodeURIComponent(e.getAttribute("name")),"GET",e.firstChild);
- }
- });
+ });
diff --git a/core/src/main/resources/lib/form/advanced/advanced.js b/core/src/main/resources/lib/form/advanced/advanced.js
index 7d01f8d44b946ffdd150e50908fffcb0f20c5d51..4f1c0baac052b6583a1cf55b2a2f55d5e47333c6 100644
--- a/core/src/main/resources/lib/form/advanced/advanced.js
+++ b/core/src/main/resources/lib/form/advanced/advanced.js
@@ -1,5 +1,4 @@
-Behaviour.register({
- "INPUT.advanced-button" : function(e) {
+Behaviour.specify("INPUT.advanced-button", 'advanced', 0, function(e) {
makeButton(e,function(e) {
var link = e.target;
while(!Element.hasClassName(link,"advancedLink"))
@@ -23,5 +22,4 @@ Behaviour.register({
layoutUpdateCallback.call();
});
e = null; // avoid memory leak
- }
});
\ No newline at end of file
diff --git a/core/src/main/resources/lib/form/apply/apply.js b/core/src/main/resources/lib/form/apply/apply.js
index 4c3cecb066326ec23c1494d5e96a343d5033d3e4..4e2cdc11d12946178ecea2853e7832e80847872f 100644
--- a/core/src/main/resources/lib/form/apply/apply.js
+++ b/core/src/main/resources/lib/form/apply/apply.js
@@ -1,5 +1,4 @@
-Behaviour.register({
- "INPUT.apply-button":function (e) {
+Behaviour.specify("INPUT.apply-button", 'apply', 0, function (e) {
var id;
var containerId = "container"+(iota++);
@@ -63,5 +62,4 @@ Behaviour.register({
f.target = null;
}
});
- }
});
\ No newline at end of file
diff --git a/core/src/main/resources/lib/form/combobox/combobox.js b/core/src/main/resources/lib/form/combobox/combobox.js
index 50acde5149a36415195636a1c7a6d1236963589f..d15b7bc78c240b1c06f27699f35df03c9a7b71f2 100644
--- a/core/src/main/resources/lib/form/combobox/combobox.js
+++ b/core/src/main/resources/lib/form/combobox/combobox.js
@@ -1,5 +1,4 @@
-Behaviour.register({
- "INPUT.combobox2" : function(e) {
+Behaviour.specify("INPUT.combobox2", 'combobox', 0, function(e) {
var items = [];
var c = new ComboBox(e,function(value) {
@@ -21,5 +20,4 @@ Behaviour.register({
}
});
});
- }
});
\ No newline at end of file
diff --git a/core/src/main/resources/lib/form/hetero-list/hetero-list.js b/core/src/main/resources/lib/form/hetero-list/hetero-list.js
index d7e92648659c268e4ed6e0cdf48cf9e8af61bc2c..9991f6196ed5910c8bbf246e45dd5b8f8047880e 100644
--- a/core/src/main/resources/lib/form/hetero-list/hetero-list.js
+++ b/core/src/main/resources/lib/form/hetero-list/hetero-list.js
@@ -2,8 +2,7 @@
// do the ones that extract innerHTML so that they can get their original HTML before
// other behavior rules change them (like YUI buttons.)
-Behaviour.list.unshift({
- "DIV.hetero-list-container" : function(e) {
+Behaviour.specify("DIV.hetero-list-container", 'hetero-list', -100, function(e) {
e=$(e);
if(isInsideRemovable(e)) return;
@@ -134,9 +133,9 @@ Behaviour.list.unshift({
}
});
}
- },
+ });
- "DIV.dd-handle" : function(e) {
+Behaviour.specify("DIV.dd-handle", 'hetero-list', -100, function(e) {
e=$(e);
e.on("mouseover",function() {
$(this).up(".repeated-chunk").addClassName("hover");
@@ -144,5 +143,4 @@ Behaviour.list.unshift({
e.on("mouseout",function() {
$(this).up(".repeated-chunk").removeClassName("hover");
});
- }
});
diff --git a/core/src/main/resources/lib/form/radioBlock/radioBlock.js b/core/src/main/resources/lib/form/radioBlock/radioBlock.js
index a8804e8d527606d129503acf9de60e62f2473dbb..0911cdb995fb72021387f5b7458f92a6cc64d9b6 100644
--- a/core/src/main/resources/lib/form/radioBlock/radioBlock.js
+++ b/core/src/main/resources/lib/form/radioBlock/radioBlock.js
@@ -24,11 +24,8 @@ var radioBlockSupport = {
}
};
-Behaviour.list.unshift({
- // this needs to happen before TR.row-set-end rule kicks in.
- // but this is a hack.
- // TODO: how do we handle ordering?
- "INPUT.radio-block-control" : function(r) {
+// this needs to happen before TR.row-set-end rule kicks in.
+Behaviour.specify("INPUT.radio-block-control", 'radioBlock', -100, function(r) {
r.id = "radio-block-"+(iota++);
// when one radio button is clicked, we need to update foldable block for
@@ -73,5 +70,4 @@ Behaviour.list.unshift({
// install event handlers to update visibility.
// needs to use onclick and onchange for Safari compatibility
r.onclick = r.onchange = function() { g.updateButtons(); };
- }
});
diff --git a/core/src/main/resources/lib/form/repeatable/repeatable.js b/core/src/main/resources/lib/form/repeatable/repeatable.js
index 047e25078ea186856c11dcca4e4302bdeadf5470..7ad9ae5b7942dcaa92ba11ab89b51f2581ecff89 100644
--- a/core/src/main/resources/lib/form/repeatable/repeatable.js
+++ b/core/src/main/resources/lib/form/repeatable/repeatable.js
@@ -99,8 +99,7 @@ var repeatableSupport = {
// do the ones that extract innerHTML so that they can get their original HTML before
// other behavior rules change them (like YUI buttons.)
-Behaviour.list.unshift({
- "DIV.repeated-container" : function(e) {
+Behaviour.specify("DIV.repeated-container", 'repeatable', -100, function(e) {
if(isInsideRemovable(e)) return;
// compute the insertion point
@@ -109,27 +108,25 @@ Behaviour.list.unshift({
ip = ip.previous();
// set up the logic
object(repeatableSupport).init(e, e.firstChild, ip);
- }
});
-Behaviour.register({
// button to add a new repeatable block
- "INPUT.repeatable-add" : function(e) {
+Behaviour.specify("INPUT.repeatable-add", 'repeatable', 0, function(e) {
makeButton(e,function(e) {
repeatableSupport.onAdd(e.target);
});
e = null; // avoid memory leak
- },
+ });
- "INPUT.repeatable-delete" : function(e) {
+Behaviour.specify("INPUT.repeatable-delete", 'repeatable', 0, function(e) {
makeButton(e,function(e) {
repeatableSupport.onDelete(e.target);
});
e = null; // avoid memory leak
- },
+ });
// radio buttons in repeatable content
- "DIV.repeated-chunk" : function(d) {
+Behaviour.specify("DIV.repeated-chunk", 'repeatable', 0, function(d) {
var inputs = d.getElementsByTagName('INPUT');
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].type == 'radio') {
@@ -145,5 +142,4 @@ Behaviour.register({
if (inputs[i].defaultChecked) inputs[i].checked = true;
}
}
- }
});
\ No newline at end of file
diff --git a/core/src/main/resources/lib/form/select/select.js b/core/src/main/resources/lib/form/select/select.js
index 5727fca794d90fd34dec616e9cc66d7252f972bd..56090590de32bd246b722021147f91fd6d03322c 100644
--- a/core/src/main/resources/lib/form/select/select.js
+++ b/core/src/main/resources/lib/form/select/select.js
@@ -40,8 +40,7 @@ function updateListBox(listBox,url,config) {
new Ajax.Request(url, config);
}
-Behaviour.register({
- "SELECT.select" : function(e) {
+Behaviour.specify("SELECT.select", 'select', 0, function(e) {
// controls that this SELECT box depends on
refillOnChange(e,function(params) {
var value = e.value;
@@ -63,5 +62,4 @@ Behaviour.register({
}
});
});
- }
});
\ No newline at end of file
diff --git a/core/src/main/resources/lib/form/textarea/textarea.js b/core/src/main/resources/lib/form/textarea/textarea.js
index 56984a110ab8bfadac78f5fe6edd1b8bcdaba2d0..de78308fe6af910c3c68e0b41237c5a5b3c9187d 100644
--- a/core/src/main/resources/lib/form/textarea/textarea.js
+++ b/core/src/main/resources/lib/form/textarea/textarea.js
@@ -1,5 +1,4 @@
-Behaviour.register({
- "TEXTAREA.codemirror" : function(e) {
+Behaviour.specify("TEXTAREA.codemirror", 'textarea', 0, function(e) {
var h = e.clientHeight;
var config = e.getAttribute("codemirror-config") || "";
config = eval('({'+config+'})');
@@ -14,9 +13,9 @@ Behaviour.register({
var scroller = codemirror.getScrollerElement();
scroller.setAttribute("style","border:1px solid black;");
scroller.style.height = h+"px";
- },
+ });
- "DIV.textarea-preview-container" : function (e) {
+Behaviour.specify("DIV.textarea-preview-container", 'textarea', 100, function (e) {
var previewDiv = findElementsBySelector(e,".textarea-preview")[0];
var showPreview = findElementsBySelector(e,".textarea-show-preview")[0];
var hidePreview = findElementsBySelector(e,".textarea-hide-preview")[0];
@@ -54,5 +53,4 @@ Behaviour.register({
$(hidePreview).hide();
$(previewDiv).hide();
};
- }
});
\ No newline at end of file
diff --git a/core/src/main/resources/lib/hudson/projectViewNested.js b/core/src/main/resources/lib/hudson/projectViewNested.js
index a379e0a6ca741bdb0e9a3cf4cd3119a2376d9d87..cf492bf228300394b91ef1fc22a2bc02a72d5224 100644
--- a/core/src/main/resources/lib/hudson/projectViewNested.js
+++ b/core/src/main/resources/lib/hudson/projectViewNested.js
@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-hudsonRules["IMG.treeview-fold-control"] = function(e) {
+Behaviour.specify("IMG.treeview-fold-control", 'projectViewNested', 0, function(e) {
e.onexpanded = function() {
var img = this;
var tr = findAncestor(img, "TR");
@@ -50,4 +50,4 @@ hudsonRules["IMG.treeview-fold-control"] = function(e) {
});
};
e = null;
-};
+});
diff --git a/core/src/main/resources/lib/layout/breadcrumbs.js b/core/src/main/resources/lib/layout/breadcrumbs.js
index 4f660ee98e3a4402c2f7d49401662fa0069ded49..42e10ae52fc49d1f7b5e76e66ad8f8d8b25c3b54 100644
--- a/core/src/main/resources/lib/layout/breadcrumbs.js
+++ b/core/src/main/resources/lib/layout/breadcrumbs.js
@@ -117,17 +117,17 @@ var breadcrumbs = (function() {
return false;
}
- jenkinsRules["#breadcrumbs LI"] = function (e) {
+ Behaviour.specify("#breadcrumbs LI", 'breadcrumbs', 0, function (e) {
// when the mouse hovers over LI, activate the menu
e = $(e);
if (e.hasClassName("no-context-menu")) return;
e.observe("mouseover", function () { handleHover(e.firstChild,0) });
- };
+ });
- jenkinsRules["A.model-link"] = function (a) {
+ Behaviour.specify("A.model-link", 'breadcrumbs', 0, function (a) {
// ditto for model-link, but give it a larger delay to avoid unintended menus to be displayed
$(a).observe("mouseover", function () { handleHover(a,500); });
- };
+ });
/**
* @namespace breadcrumbs
diff --git a/core/src/main/resources/lib/layout/copyButton/copyButton.js b/core/src/main/resources/lib/layout/copyButton/copyButton.js
index 0fb109e14f9de204e0f349ca7ad27d311f2c0998..c3eff557022c636d5822f2c7dadf0bcb07160acf 100644
--- a/core/src/main/resources/lib/layout/copyButton/copyButton.js
+++ b/core/src/main/resources/lib/layout/copyButton/copyButton.js
@@ -1,7 +1,6 @@
// @include "org.kohsuke.stapler.zeroclipboard"
-Behaviour.register({
- "span.copy-button" : function(e) {
+Behaviour.specify("span.copy-button", 'copyButton', 0, function(e) {
var btn = e.firstChild;
var id = "copy-button"+(iota++);
btn.id = id;
@@ -35,5 +34,4 @@ Behaviour.register({
clip.addEventListener('onMouseUp',function() {
$(id).removeClassName('yui-button-active')
});
- }
});
diff --git a/test/src/test/java/scripts/BehaviorTest.java b/test/src/test/java/scripts/BehaviorTest.java
index e2b5c3e5e9e3f7330e53e3ddca4518181cd0cd94..2d92747272fd9f9ab3edc0698369c79c445eae72 100644
--- a/test/src/test/java/scripts/BehaviorTest.java
+++ b/test/src/test/java/scripts/BehaviorTest.java
@@ -61,4 +61,10 @@ public class BehaviorTest extends HudsonTestCase {
assertEquals("initial and appended yet different", r.getJavaScriptResult().toString());
}
+ public void testSelectorOrdering() throws Exception {
+ HtmlPage p = createWebClient().goTo("self/testSelectorOrdering");
+ ScriptResult r = p.executeJavaScript("document.getElementsBySelector('DIV.a')[0].innerHTML");
+ assertEquals("initial early counted! generic weevils! late", r.getJavaScriptResult().toString());
+ }
+
}
diff --git a/test/src/test/resources/lib/layout/RenderOnDemandTest/testBehaviour.jelly b/test/src/test/resources/lib/layout/RenderOnDemandTest/testBehaviour.jelly
index 22446e40450311fcfb70868249b4035da5131957..e32126ea54f5cec643c608e323ef72f802dc66e5 100644
--- a/test/src/test/resources/lib/layout/RenderOnDemandTest/testBehaviour.jelly
+++ b/test/src/test/resources/lib/layout/RenderOnDemandTest/testBehaviour.jelly
@@ -30,10 +30,8 @@ THE SOFTWARE.
diff --git a/test/src/test/resources/scripts/BehaviorTest/testDuplicateRegistrations.jelly b/test/src/test/resources/scripts/BehaviorTest/testDuplicateRegistrations.jelly
index f0a29d2d261f906ac3cd67d95abeaa4cd85c818e..33cb5f48505cf7e644ff20ffaffccaa9360f1b89 100644
--- a/test/src/test/resources/scripts/BehaviorTest/testDuplicateRegistrations.jelly
+++ b/test/src/test/resources/scripts/BehaviorTest/testDuplicateRegistrations.jelly
@@ -26,20 +26,14 @@ THE SOFTWARE.
initial
diff --git a/test/src/test/resources/scripts/BehaviorTest/testSelectorOrdering.jelly b/test/src/test/resources/scripts/BehaviorTest/testSelectorOrdering.jelly
new file mode 100644
index 0000000000000000000000000000000000000000..60eb9b897204fd14278225ec41833d38638d276f
--- /dev/null
+++ b/test/src/test/resources/scripts/BehaviorTest/testSelectorOrdering.jelly
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+ initial
+
+
+
diff --git a/ui-samples-plugin/src/main/resources/jenkins/plugins/ui_samples/SyntaxHighlightedTextArea/index.groovy b/ui-samples-plugin/src/main/resources/jenkins/plugins/ui_samples/SyntaxHighlightedTextArea/index.groovy
index 48998f33c526f783a515f8df91b189a1cd347461..25f8d94435fced503abb8f23d3e34ac1a79b41ee 100644
--- a/ui-samples-plugin/src/main/resources/jenkins/plugins/ui_samples/SyntaxHighlightedTextArea/index.groovy
+++ b/ui-samples-plugin/src/main/resources/jenkins/plugins/ui_samples/SyntaxHighlightedTextArea/index.groovy
@@ -22,12 +22,12 @@ namespace("/lib/samples").sample(title:_("Syntax Highlighted Text Area")) {
// see CodeMirror web site for more about how to control the newly instantiated text area.
script("""
- hudsonRules["TEXTAREA.my-groovy-textbox"] = function(e) {
+ Behaviour.specify("TEXTAREA.my-groovy-textbox", "SyntaxHighlightedTextArea", 0, function(e) {
var w = CodeMirror.fromTextArea(e,{
mode:"text/x-groovy",
lineNumbers: true
}).getWrapperElement();
w.setAttribute("style","border:1px solid black; margin-top: 1em; margin-bottom: 1em")
- }
+ });
""")
}
diff --git a/war/src/main/webapp/scripts/behavior.js b/war/src/main/webapp/scripts/behavior.js
index af70f049e79c06527a95abe5f6035d3a7d0901b2..da29afae54e6a14eff8f38129dc9fecb5fc3f88f 100644
--- a/war/src/main/webapp/scripts/behavior.js
+++ b/war/src/main/webapp/scripts/behavior.js
@@ -9,20 +9,16 @@
Usage:
- var myrules = {
- 'b.someclass' : function(element){
- element.onclick = function(){
- alert(this.innerHTML);
- }
- },
- '#someid u' : function(element){
- element.onmouseover = function(){
- this.innerHTML = "BLAH!";
- }
- }
- };
-
- Behaviour.register(myrules);
+ Behaviour.specify('b.someclass', 'myrules.alert', 10, function(element) {
+ element.onclick = function() {
+ alert(this.innerHTML);
+ }
+ });
+ Behaviour.specify('#someid u', 'myrules.blah', 0, function(element) {
+ element.onmouseover = function() {
+ this.innerHTML = "BLAH!";
+ }
+ });
// Call Behaviour.apply() to re-apply the rules (if you
// update the dom, etc).
@@ -37,9 +33,35 @@
*/
-var Behaviour = {
+var Behaviour = (function() {
+ var storage = [{selector: '', id: '_deprecated', priority: 0}];
+ return {
+
+ /**
+ * Specifies something to do when an element matching a CSS selector is encountered.
+ * @param {String} selector a CSS selector triggering your behavior
+ * @param {String} id combined with selector, uniquely identifies this behavior; prevents duplicate registrations
+ * @param {Number} priority relative position of this behavior in case multiple apply to a given element; lower numbers applied first (sorted by id then selector in case of tie); choose 0 if you do not care
+ * @param {Function} behavior callback function taking one parameter, a (DOM) {@link Element}, and returning void
+ */
+ specify : function(selector, id, priority, behavior) {
+ for (var i = 0; i < storage.length; i++) {
+ if (storage[i].selector == selector && storage[i].id == id) {
+ storage.splice(i, 1);
+ break;
+ }
+ }
+ storage.push({selector: selector, id: id, priority: priority, behavior: behavior});
+ storage.sort(function(a, b) {
+ var location = a.priority - b.priority;
+ return location != 0 ? location : a.id < b.id ? -1 : a.id > b.id ? 1 : a.selector < b.selector ? -1 : a.selector > b.selector ? 1 : 0;
+ });
+ },
+
+ /** @deprecated For backward compatibility only; use {@link specify} instead. */
list : new Array,
+ /** @deprecated For backward compatibility only; use {@link specify} instead. */
register : function(sheet){
Behaviour.list.push(sheet);
},
@@ -65,28 +87,30 @@ var Behaviour = {
* this semantics is preserved.
*/
applySubtree : function(startNode,includeSelf) {
- var behaviorsBySelector = {};
- Behaviour.list._each(function(sheet) {
- for (var selector in sheet){
- var behavior = sheet[selector];
- var behaviors = behaviorsBySelector[selector];
- if (behaviors == null) {
- behaviors = [];
- behaviorsBySelector[selector] = behaviors;
- }
- if (behaviors.indexOf(behavior.toString()) == -1) {
- behaviors.push(behavior.toString());
- function apply(n) {
- var list = findElementsBySelector(n,selector,includeSelf);
- if (list.length>0) // just to simplify setting of a breakpoint.
- list._each(sheet[selector]);
+ if (!(startNode instanceof Array)) {
+ startNode = [startNode];
+ }
+ storage._each(function (registration) {
+ if (registration.id == '_deprecated') {
+ Behaviour.list._each(function(sheet) {
+ for (var selector in sheet){
+ startNode._each(function (n) {
+ var list = findElementsBySelector(n, selector, includeSelf);
+ if (list.length > 0) { // just to simplify setting of a breakpoint.
+ //console.log('deprecated:' + selector + ' on ' + list.length + ' elements');
+ list._each(sheet[selector]);
+ }
+ });
}
- if (startNode instanceof Array) {
- startNode._each(apply)
- } else {
- apply(startNode);
+ });
+ } else {
+ startNode._each(function (node) {
+ var list = findElementsBySelector(node, registration.selector, includeSelf);
+ if (list.length > 0) {
+ //console.log(registration.id + ':' + registration.selector + ' @' + registration.priority + ' on ' + list.length + ' elements');
+ list._each(registration.behavior);
}
- }
+ });
}
});
},
@@ -103,7 +127,7 @@ var Behaviour = {
}
}
}
-}
+}})();
Behaviour.start();
diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js
index cc814d5885d45d3e5c47d906c31a4117acee148d..ed96e2f2f5b9e83ac35c4e49d8df0c6cf9ae2980 100644
--- a/war/src/main/webapp/scripts/hudson-behavior.js
+++ b/war/src/main/webapp/scripts/hudson-behavior.js
@@ -561,7 +561,9 @@ function sequencer(fs) {
return next();
}
+/** @deprecated Use {@link Behaviour.specify} instead. */
var jenkinsRules = {
+// XXX convert as many as possible to Behaviour.specify calls; some seem to have an implicit order dependency, but what?
"BODY" : function() {
tooltip = new YAHOO.widget.Tooltip("tt", {context:[], zindex:999});
},
@@ -1159,7 +1161,17 @@ var jenkinsRules = {
adjustSticker();
}
};
+/** @deprecated Use {@link Behaviour.specify} instead. */
var hudsonRules = jenkinsRules; // legacy name
+(function() {
+ var p = 20;
+ for (var selector in jenkinsRules) {
+ Behaviour.specify(selector, 'hudson-behavior', p++, jenkinsRules[selector]);
+ delete jenkinsRules[selector];
+ }
+})();
+// now empty, but plugins can stuff things in here later:
+Behaviour.register(hudsonRules);
function applyTooltip(e,text) {
// copied from YAHOO.widget.Tooltip.prototype.configContext to efficiently add a new element
@@ -1212,10 +1224,6 @@ function refillOnChange(e,onChange) {
h(); // initial fill
}
-Behaviour.register(hudsonRules);
-
-
-
function xor(a,b) {
// convert both values to boolean by '!' and then do a!=b
return !a != !b;