提交 3b1c3867 编写于 作者: J Jesse Glick

Merge pull request #545 from jglick/Behaviour-specify-14495

[JENKINS-14495] Define Behaviour.specify.
...@@ -56,6 +56,11 @@ Upcoming changes</a> ...@@ -56,6 +56,11 @@ Upcoming changes</a>
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=--> <div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image> <ul class=image>
<li class=bug> <li class=bug>
Refactored <code>behavior.js</code> to run more predictably.
Plugin JavaScript should use <code>Behaviour.specify</code> in place of
<code>Behaviour.register</code>, <code>Behaviour.list</code>,
<code>hudsonRules</code>, and <code>jenkinsRules</code>.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-14495">issue 14495</a> cont'd)
Fixed a possible race condition in the remoting layer. Fixed a possible race condition in the remoting layer.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-14909">issue 14909</a>) (<a href="https://issues.jenkins-ci.org/browse/JENKINS-14909">issue 14909</a>)
<li class=bug> <li class=bug>
......
...@@ -20,8 +20,7 @@ function showhideCategory(col) { ...@@ -20,8 +20,7 @@ function showhideCategory(col) {
row.style.display = newDisplay; row.style.display = newDisplay;
} }
Behaviour.register({ Behaviour.specify("#filter-box", '_table', 0, function(e) {
"#filter-box": function(e) {
function applyFilter() { function applyFilter() {
var filter = e.value.toLowerCase(); var filter = e.value.toLowerCase();
["TR.plugin","TR.plugin-category"].each(function(clz) { ["TR.plugin","TR.plugin-category"].each(function(clz) {
...@@ -36,5 +35,4 @@ Behaviour.register({ ...@@ -36,5 +35,4 @@ Behaviour.register({
} }
e.onkeyup = applyFilter; e.onkeyup = applyFilter;
}
}); });
(function() { (function() {
Behaviour.register({ Behaviour.specify("INPUT.reveal-expandable-detail", 'ExpandableDetailsNote', 0, function(e) {
"INPUT.reveal-expandable-detail" : function(e) {
var detail = e.nextSibling; var detail = e.nextSibling;
makeButton(e,function() { makeButton(e,function() {
detail.style.display = (detail.style.display=="block")?"none":"block"; detail.style.display = (detail.style.display=="block")?"none":"block";
}); });
}
}); });
}()); }());
...@@ -29,7 +29,7 @@ THE SOFTWARE. ...@@ -29,7 +29,7 @@ THE SOFTWARE.
<f:entry title="${%Node/Label}" field="labels"> <f:entry title="${%Node/Label}" field="labels">
<div class="yahooTree labelAxis-tree" style="border: 1px solid gray; height: 10em; overflow:auto;" values="${instance.valueString}" /> <div class="yahooTree labelAxis-tree" style="border: 1px solid gray; height: 10em; overflow:auto;" values="${instance.valueString}" />
<script> <script>
hudsonRules["DIV.labelAxis-tree"] = function(e) { Behaviour.specify("DIV.labelAxis-tree", 'LabelAxis', 0, function(e) {
var tree = new YAHOO.widget.TreeView(e); var tree = new YAHOO.widget.TreeView(e);
var labels = new YAHOO.widget.TextNode("${%Labels}", tree.getRoot(), false); var labels = new YAHOO.widget.TextNode("${%Labels}", tree.getRoot(), false);
...@@ -60,7 +60,7 @@ THE SOFTWARE. ...@@ -60,7 +60,7 @@ THE SOFTWARE.
tree.subscribe("clickEvent", function(node) { tree.subscribe("clickEvent", function(node) {
return false; return false;
}); });
}; });
</script> </script>
</f:entry> </f:entry>
</j:jelly> </j:jelly>
...@@ -144,16 +144,15 @@ THE SOFTWARE. ...@@ -144,16 +144,15 @@ THE SOFTWARE.
}); });
})(); })();
Behaviour.register({ Behaviour.specify("#${strategyid} TD.stop A.remove", 'GlobalMatrixAuthorizationStrategy', 0, function(e) {
"#${strategyid} TD.stop A.remove" : function(e) {
e.onclick = function() { e.onclick = function() {
var tr = findAncestor(this,"TR"); var tr = findAncestor(this,"TR");
tr.parentNode.removeChild(tr); tr.parentNode.removeChild(tr);
return false; return false;
} }
e = null; <!-- avoid memory leak --> e = null; <!-- avoid memory leak -->
}, });
"#${strategyid} TD.stop A.toggleall" : function(e) { Behaviour.specify("#${strategyid} TD.stop A.toggleall", 'GlobalMatrixAuthorizationStrategy', 0, function(e) {
e.onclick = function() { e.onclick = function() {
var tr = findAncestor(this,"TR"); var tr = findAncestor(this,"TR");
var inputs = tr.getElementsByTagName("INPUT"); var inputs = tr.getElementsByTagName("INPUT");
...@@ -163,15 +162,14 @@ THE SOFTWARE. ...@@ -163,15 +162,14 @@ THE SOFTWARE.
return false; return false;
}; };
e = null; <!-- avoid memory leak --> e = null; <!-- avoid memory leak -->
}, });
<j:if test="${empty(descriptorPath)}"> <j:if test="${empty(descriptorPath)}">
<j:set var="descriptorPath" value="${descriptor.descriptorFullUrl}"/> <j:set var="descriptorPath" value="${descriptor.descriptorFullUrl}"/>
</j:if> </j:if>
<!-- validates the name --> <!-- validates the name -->
"#${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); FormChecker.delayedCheck("${descriptorPath}/checkName?value="+encodeURIComponent(e.getAttribute("name")),"GET",e.firstChild);
} });
});
</script> </script>
</f:block> </f:block>
</j:jelly> </j:jelly>
Behaviour.register({ Behaviour.specify("INPUT.advanced-button", 'advanced', 0, function(e) {
"INPUT.advanced-button" : function(e) {
makeButton(e,function(e) { makeButton(e,function(e) {
var link = e.target; var link = e.target;
while(!Element.hasClassName(link,"advancedLink")) while(!Element.hasClassName(link,"advancedLink"))
...@@ -23,5 +22,4 @@ Behaviour.register({ ...@@ -23,5 +22,4 @@ Behaviour.register({
layoutUpdateCallback.call(); layoutUpdateCallback.call();
}); });
e = null; // avoid memory leak e = null; // avoid memory leak
}
}); });
\ No newline at end of file
Behaviour.register({ Behaviour.specify("INPUT.apply-button", 'apply', 0, function (e) {
"INPUT.apply-button":function (e) {
var id; var id;
var containerId = "container"+(iota++); var containerId = "container"+(iota++);
...@@ -63,5 +62,4 @@ Behaviour.register({ ...@@ -63,5 +62,4 @@ Behaviour.register({
f.target = null; f.target = null;
} }
}); });
}
}); });
\ No newline at end of file
Behaviour.register({ Behaviour.specify("INPUT.combobox2", 'combobox', 0, function(e) {
"INPUT.combobox2" : function(e) {
var items = []; var items = [];
var c = new ComboBox(e,function(value) { var c = new ComboBox(e,function(value) {
...@@ -21,5 +20,4 @@ Behaviour.register({ ...@@ -21,5 +20,4 @@ Behaviour.register({
} }
}); });
}); });
}
}); });
\ No newline at end of file
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
// do the ones that extract innerHTML so that they can get their original HTML before // do the ones that extract innerHTML so that they can get their original HTML before
// other behavior rules change them (like YUI buttons.) // other behavior rules change them (like YUI buttons.)
Behaviour.list.unshift({ Behaviour.specify("DIV.hetero-list-container", 'hetero-list', -100, function(e) {
"DIV.hetero-list-container" : function(e) {
e=$(e); e=$(e);
if(isInsideRemovable(e)) return; if(isInsideRemovable(e)) return;
...@@ -134,9 +133,9 @@ Behaviour.list.unshift({ ...@@ -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=$(e);
e.on("mouseover",function() { e.on("mouseover",function() {
$(this).up(".repeated-chunk").addClassName("hover"); $(this).up(".repeated-chunk").addClassName("hover");
...@@ -144,5 +143,4 @@ Behaviour.list.unshift({ ...@@ -144,5 +143,4 @@ Behaviour.list.unshift({
e.on("mouseout",function() { e.on("mouseout",function() {
$(this).up(".repeated-chunk").removeClassName("hover"); $(this).up(".repeated-chunk").removeClassName("hover");
}); });
}
}); });
...@@ -24,11 +24,8 @@ var radioBlockSupport = { ...@@ -24,11 +24,8 @@ var radioBlockSupport = {
} }
}; };
Behaviour.list.unshift({ // this needs to happen before TR.row-set-end rule kicks in.
// this needs to happen before TR.row-set-end rule kicks in. Behaviour.specify("INPUT.radio-block-control", 'radioBlock', -100, function(r) {
// but this is a hack.
// TODO: how do we handle ordering?
"INPUT.radio-block-control" : function(r) {
r.id = "radio-block-"+(iota++); r.id = "radio-block-"+(iota++);
// when one radio button is clicked, we need to update foldable block for // when one radio button is clicked, we need to update foldable block for
...@@ -73,5 +70,4 @@ Behaviour.list.unshift({ ...@@ -73,5 +70,4 @@ Behaviour.list.unshift({
// install event handlers to update visibility. // install event handlers to update visibility.
// needs to use onclick and onchange for Safari compatibility // needs to use onclick and onchange for Safari compatibility
r.onclick = r.onchange = function() { g.updateButtons(); }; r.onclick = r.onchange = function() { g.updateButtons(); };
}
}); });
...@@ -99,8 +99,7 @@ var repeatableSupport = { ...@@ -99,8 +99,7 @@ var repeatableSupport = {
// do the ones that extract innerHTML so that they can get their original HTML before // do the ones that extract innerHTML so that they can get their original HTML before
// other behavior rules change them (like YUI buttons.) // other behavior rules change them (like YUI buttons.)
Behaviour.list.unshift({ Behaviour.specify("DIV.repeated-container", 'repeatable', -100, function(e) {
"DIV.repeated-container" : function(e) {
if(isInsideRemovable(e)) return; if(isInsideRemovable(e)) return;
// compute the insertion point // compute the insertion point
...@@ -109,27 +108,25 @@ Behaviour.list.unshift({ ...@@ -109,27 +108,25 @@ Behaviour.list.unshift({
ip = ip.previous(); ip = ip.previous();
// set up the logic // set up the logic
object(repeatableSupport).init(e, e.firstChild, ip); object(repeatableSupport).init(e, e.firstChild, ip);
}
}); });
Behaviour.register({
// button to add a new repeatable block // 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) { makeButton(e,function(e) {
repeatableSupport.onAdd(e.target); repeatableSupport.onAdd(e.target);
}); });
e = null; // avoid memory leak e = null; // avoid memory leak
}, });
"INPUT.repeatable-delete" : function(e) { Behaviour.specify("INPUT.repeatable-delete", 'repeatable', 0, function(e) {
makeButton(e,function(e) { makeButton(e,function(e) {
repeatableSupport.onDelete(e.target); repeatableSupport.onDelete(e.target);
}); });
e = null; // avoid memory leak e = null; // avoid memory leak
}, });
// radio buttons in repeatable content // radio buttons in repeatable content
"DIV.repeated-chunk" : function(d) { Behaviour.specify("DIV.repeated-chunk", 'repeatable', 0, function(d) {
var inputs = d.getElementsByTagName('INPUT'); var inputs = d.getElementsByTagName('INPUT');
for (var i = 0; i < inputs.length; i++) { for (var i = 0; i < inputs.length; i++) {
if (inputs[i].type == 'radio') { if (inputs[i].type == 'radio') {
...@@ -145,5 +142,4 @@ Behaviour.register({ ...@@ -145,5 +142,4 @@ Behaviour.register({
if (inputs[i].defaultChecked) inputs[i].checked = true; if (inputs[i].defaultChecked) inputs[i].checked = true;
} }
} }
}
}); });
\ No newline at end of file
...@@ -40,8 +40,7 @@ function updateListBox(listBox,url,config) { ...@@ -40,8 +40,7 @@ function updateListBox(listBox,url,config) {
new Ajax.Request(url, config); new Ajax.Request(url, config);
} }
Behaviour.register({ Behaviour.specify("SELECT.select", 'select', 0, function(e) {
"SELECT.select" : function(e) {
// controls that this SELECT box depends on // controls that this SELECT box depends on
refillOnChange(e,function(params) { refillOnChange(e,function(params) {
var value = e.value; var value = e.value;
...@@ -63,5 +62,4 @@ Behaviour.register({ ...@@ -63,5 +62,4 @@ Behaviour.register({
} }
}); });
}); });
}
}); });
\ No newline at end of file
Behaviour.register({ Behaviour.specify("TEXTAREA.codemirror", 'textarea', 0, function(e) {
"TEXTAREA.codemirror" : function(e) {
var h = e.clientHeight; var h = e.clientHeight;
var config = e.getAttribute("codemirror-config") || ""; var config = e.getAttribute("codemirror-config") || "";
config = eval('({'+config+'})'); config = eval('({'+config+'})');
...@@ -14,9 +13,9 @@ Behaviour.register({ ...@@ -14,9 +13,9 @@ Behaviour.register({
var scroller = codemirror.getScrollerElement(); var scroller = codemirror.getScrollerElement();
scroller.setAttribute("style","border:1px solid black;"); scroller.setAttribute("style","border:1px solid black;");
scroller.style.height = h+"px"; 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 previewDiv = findElementsBySelector(e,".textarea-preview")[0];
var showPreview = findElementsBySelector(e,".textarea-show-preview")[0]; var showPreview = findElementsBySelector(e,".textarea-show-preview")[0];
var hidePreview = findElementsBySelector(e,".textarea-hide-preview")[0]; var hidePreview = findElementsBySelector(e,".textarea-hide-preview")[0];
...@@ -54,5 +53,4 @@ Behaviour.register({ ...@@ -54,5 +53,4 @@ Behaviour.register({
$(hidePreview).hide(); $(hidePreview).hide();
$(previewDiv).hide(); $(previewDiv).hide();
}; };
}
}); });
\ No newline at end of file
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
hudsonRules["IMG.treeview-fold-control"] = function(e) { Behaviour.specify("IMG.treeview-fold-control", 'projectViewNested', 0, function(e) {
e.onexpanded = function() { e.onexpanded = function() {
var img = this; var img = this;
var tr = findAncestor(img, "TR"); var tr = findAncestor(img, "TR");
...@@ -50,4 +50,4 @@ hudsonRules["IMG.treeview-fold-control"] = function(e) { ...@@ -50,4 +50,4 @@ hudsonRules["IMG.treeview-fold-control"] = function(e) {
}); });
}; };
e = null; e = null;
}; });
...@@ -117,17 +117,17 @@ var breadcrumbs = (function() { ...@@ -117,17 +117,17 @@ var breadcrumbs = (function() {
return false; return false;
} }
jenkinsRules["#breadcrumbs LI"] = function (e) { Behaviour.specify("#breadcrumbs LI", 'breadcrumbs', 0, function (e) {
// when the mouse hovers over LI, activate the menu // when the mouse hovers over LI, activate the menu
e = $(e); e = $(e);
if (e.hasClassName("no-context-menu")) return; if (e.hasClassName("no-context-menu")) return;
e.observe("mouseover", function () { handleHover(e.firstChild,0) }); 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 // ditto for model-link, but give it a larger delay to avoid unintended menus to be displayed
$(a).observe("mouseover", function () { handleHover(a,500); }); $(a).observe("mouseover", function () { handleHover(a,500); });
}; });
/** /**
* @namespace breadcrumbs * @namespace breadcrumbs
......
// @include "org.kohsuke.stapler.zeroclipboard" // @include "org.kohsuke.stapler.zeroclipboard"
Behaviour.register({ Behaviour.specify("span.copy-button", 'copyButton', 0, function(e) {
"span.copy-button" : function(e) {
var btn = e.firstChild; var btn = e.firstChild;
var id = "copy-button"+(iota++); var id = "copy-button"+(iota++);
btn.id = id; btn.id = id;
...@@ -35,5 +34,4 @@ Behaviour.register({ ...@@ -35,5 +34,4 @@ Behaviour.register({
clip.addEventListener('onMouseUp',function() { clip.addEventListener('onMouseUp',function() {
$(id).removeClassName('yui-button-active') $(id).removeClassName('yui-button-active')
}); });
}
}); });
...@@ -61,4 +61,10 @@ public class BehaviorTest extends HudsonTestCase { ...@@ -61,4 +61,10 @@ public class BehaviorTest extends HudsonTestCase {
assertEquals("initial and appended yet different", r.getJavaScriptResult().toString()); 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());
}
} }
...@@ -30,10 +30,8 @@ THE SOFTWARE. ...@@ -30,10 +30,8 @@ THE SOFTWARE.
<l:layout title=""> <l:layout title="">
<l:main-panel> <l:main-panel>
<script> <script>
Behaviour.register({ Behaviour.specify(".a", 'test', 0, function (e) {
".a" : function (e) { e.innerHTML = e.getAttribute("value");
e.innerHTML = e.getAttribute("value");
}
}); });
</script> </script>
......
...@@ -26,20 +26,14 @@ THE SOFTWARE. ...@@ -26,20 +26,14 @@ THE SOFTWARE.
<l:layout title=""> <l:layout title="">
<l:main-panel> <l:main-panel>
<script> <script>
Behaviour.register({ Behaviour.specify(".a", 'test1', 0, function (e) {
".a" : function (e) { e.innerHTML += ' and appended';
e.innerHTML += ' and appended';
}
}); });
Behaviour.register({ Behaviour.specify(".a", 'test1', 0, function (e) {
".a" : function (e) { e.innerHTML += ' and appended';
e.innerHTML += ' and appended';
}
}); });
Behaviour.register({ Behaviour.specify(".a", 'test2', 0, function (e) {
".a" : function (e) { e.innerHTML += ' yet different';
e.innerHTML += ' yet different';
}
}); });
</script> </script>
<div class="a">initial</div> <div class="a">initial</div>
......
<!--
The MIT License
Copyright (c) 2012, CloudBees, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<l:layout title="">
<l:main-panel>
<script>
Behaviour.specify("DIV", 'generic', 0, function (e) {
e.innerHTML += ' generic';
});
Behaviour.specify(".a", 'early', -100, function (e) {
e.innerHTML += ' early';
});
Behaviour.specify(".a", 'late', 100, function (e) {
e.innerHTML += ' late';
});
Behaviour.specify("DIV", 'zyzzyva', 0, function (e) {
e.innerHTML += ' weevils!';
});
Behaviour.specify("DIV", 'abacus', 0, function (e) {
e.innerHTML += ' counted!';
});
</script>
<div class="a">initial</div>
</l:main-panel>
</l:layout>
</j:jelly>
...@@ -22,12 +22,12 @@ namespace("/lib/samples").sample(title:_("Syntax Highlighted Text Area")) { ...@@ -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. // see CodeMirror web site for more about how to control the newly instantiated text area.
script(""" script("""
hudsonRules["TEXTAREA.my-groovy-textbox"] = function(e) { Behaviour.specify("TEXTAREA.my-groovy-textbox", "SyntaxHighlightedTextArea", 0, function(e) {
var w = CodeMirror.fromTextArea(e,{ var w = CodeMirror.fromTextArea(e,{
mode:"text/x-groovy", mode:"text/x-groovy",
lineNumbers: true lineNumbers: true
}).getWrapperElement(); }).getWrapperElement();
w.setAttribute("style","border:1px solid black; margin-top: 1em; margin-bottom: 1em") w.setAttribute("style","border:1px solid black; margin-top: 1em; margin-bottom: 1em")
} });
""") """)
} }
...@@ -9,20 +9,16 @@ ...@@ -9,20 +9,16 @@
Usage: Usage:
var myrules = { Behaviour.specify('b.someclass', 'myrules.alert', 10, function(element) {
'b.someclass' : function(element){ element.onclick = function() {
element.onclick = function(){ alert(this.innerHTML);
alert(this.innerHTML); }
} });
}, Behaviour.specify('#someid u', 'myrules.blah', 0, function(element) {
'#someid u' : function(element){ element.onmouseover = function() {
element.onmouseover = function(){ this.innerHTML = "BLAH!";
this.innerHTML = "BLAH!"; }
} });
}
};
Behaviour.register(myrules);
// Call Behaviour.apply() to re-apply the rules (if you // Call Behaviour.apply() to re-apply the rules (if you
// update the dom, etc). // update the dom, etc).
...@@ -37,9 +33,35 @@ ...@@ -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, list : new Array,
/** @deprecated For backward compatibility only; use {@link specify} instead. */
register : function(sheet){ register : function(sheet){
Behaviour.list.push(sheet); Behaviour.list.push(sheet);
}, },
...@@ -65,28 +87,30 @@ var Behaviour = { ...@@ -65,28 +87,30 @@ var Behaviour = {
* this semantics is preserved. * this semantics is preserved.
*/ */
applySubtree : function(startNode,includeSelf) { applySubtree : function(startNode,includeSelf) {
var behaviorsBySelector = {}; if (!(startNode instanceof Array)) {
Behaviour.list._each(function(sheet) { startNode = [startNode];
for (var selector in sheet){ }
var behavior = sheet[selector]; storage._each(function (registration) {
var behaviors = behaviorsBySelector[selector]; if (registration.id == '_deprecated') {
if (behaviors == null) { Behaviour.list._each(function(sheet) {
behaviors = []; for (var selector in sheet){
behaviorsBySelector[selector] = behaviors; startNode._each(function (n) {
} var list = findElementsBySelector(n, selector, includeSelf);
if (behaviors.indexOf(behavior.toString()) == -1) { if (list.length > 0) { // just to simplify setting of a breakpoint.
behaviors.push(behavior.toString()); //console.log('deprecated:' + selector + ' on ' + list.length + ' elements');
function apply(n) { list._each(sheet[selector]);
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._each(apply) } else {
} else { startNode._each(function (node) {
apply(startNode); 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 = { ...@@ -103,7 +127,7 @@ var Behaviour = {
} }
} }
} }
} }})();
Behaviour.start(); Behaviour.start();
......
...@@ -561,7 +561,9 @@ function sequencer(fs) { ...@@ -561,7 +561,9 @@ function sequencer(fs) {
return next(); return next();
} }
/** @deprecated Use {@link Behaviour.specify} instead. */
var jenkinsRules = { var jenkinsRules = {
// XXX convert as many as possible to Behaviour.specify calls; some seem to have an implicit order dependency, but what?
"BODY" : function() { "BODY" : function() {
tooltip = new YAHOO.widget.Tooltip("tt", {context:[], zindex:999}); tooltip = new YAHOO.widget.Tooltip("tt", {context:[], zindex:999});
}, },
...@@ -1159,7 +1161,17 @@ var jenkinsRules = { ...@@ -1159,7 +1161,17 @@ var jenkinsRules = {
adjustSticker(); adjustSticker();
} }
}; };
/** @deprecated Use {@link Behaviour.specify} instead. */
var hudsonRules = jenkinsRules; // legacy name 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) { function applyTooltip(e,text) {
// copied from YAHOO.widget.Tooltip.prototype.configContext to efficiently add a new element // copied from YAHOO.widget.Tooltip.prototype.configContext to efficiently add a new element
...@@ -1212,10 +1224,6 @@ function refillOnChange(e,onChange) { ...@@ -1212,10 +1224,6 @@ function refillOnChange(e,onChange) {
h(); // initial fill h(); // initial fill
} }
Behaviour.register(hudsonRules);
function xor(a,b) { function xor(a,b) {
// convert both values to boolean by '!' and then do a!=b // convert both values to boolean by '!' and then do a!=b
return !a != !b; return !a != !b;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册