提交 b2cd4120 编写于 作者: K Kohsuke Kawaguchi

Breadcrumb is reworked to show descendants to provide additional navigational shortcuts.

Object that implements ModelObjectWithChildren can expose its children in the breadcrumb.
上级 0f6b02bd
......@@ -55,7 +55,9 @@ Upcoming changes</a>
<!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image>
<li class=>
<li class=rfe>
Breadcrumb is reworked to show descendants to provide additional navigational shortcuts.
(<a href="https://wiki.jenkins-ci.org/display/JENKINS/FOSDEM+UI+Enhancement+discussion+notes+2013">discussion</a>)
</ul>
</div><!--=TRUNK-END=-->
......
......@@ -127,6 +127,7 @@ import jenkins.model.GlobalConfiguration;
import jenkins.model.GlobalConfigurationCategory;
import jenkins.model.GlobalConfigurationCategory.Unclassified;
import jenkins.model.Jenkins;
import jenkins.model.ModelObjectWithChildren;
import jenkins.model.ModelObjectWithContextMenu;
import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
......@@ -183,6 +184,10 @@ public class Functions {
return o instanceof ModelObjectWithContextMenu;
}
public static boolean isModelWithChildren(Object o) {
return o instanceof ModelObjectWithChildren;
}
public static String xsDate(Calendar cal) {
return Util.XS_DATETIME_FORMATTER.format(cal.getTime());
}
......
......@@ -28,6 +28,7 @@ import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.io.StreamException;
import com.thoughtworks.xstream.io.xml.XppDriver;
import hudson.DescriptorExtensionList;
import hudson.Extension;
import hudson.ExtensionPoint;
import hudson.Functions;
import hudson.Indenter;
......@@ -55,6 +56,7 @@ import hudson.util.XStream2;
import hudson.views.ListViewColumn;
import hudson.widgets.Widget;
import jenkins.model.Jenkins;
import jenkins.model.ModelObjectWithChildren;
import jenkins.util.ProgressiveRendering;
import net.sf.json.JSON;
import net.sf.json.JSONArray;
......@@ -123,7 +125,7 @@ import org.kohsuke.accmod.restrictions.NoExternalUse;
* @see ViewGroup
*/
@ExportedBean
public abstract class View extends AbstractModelObject implements AccessControlled, Describable<View>, ExtensionPoint, Saveable {
public abstract class View extends AbstractModelObject implements AccessControlled, Describable<View>, ExtensionPoint, Saveable, ModelObjectWithChildren {
/**
* Container of this view. Set right after the construction
......@@ -1068,6 +1070,12 @@ public abstract class View extends AbstractModelObject implements AccessControll
}
}
public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
ContextMenu m = new ContextMenu();
for (TopLevelItem i : getItems())
m.add(i.getShortUrl(),i.getDisplayName());
return m;
}
/**
* A list of available view types.
......
......@@ -307,7 +307,9 @@ import javax.annotation.Nullable;
* @author Kohsuke Kawaguchi
*/
@ExportedBean
public class Jenkins extends AbstractCIBase implements ModifiableTopLevelItemGroup, StaplerProxy, StaplerFallback, ViewGroup, AccessControlled, DescriptorByNameOwner, ModelObjectWithContextMenu {
public class Jenkins extends AbstractCIBase implements ModifiableTopLevelItemGroup, StaplerProxy, StaplerFallback,
ViewGroup, AccessControlled, DescriptorByNameOwner,
ModelObjectWithContextMenu, ModelObjectWithChildren {
private transient final Queue queue;
/**
......@@ -3094,6 +3096,14 @@ public class Jenkins extends AbstractCIBase implements ModifiableTopLevelItemGro
return menu;
}
public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
ContextMenu menu = new ContextMenu();
for (View view : getViews()) {
menu.add(view.getViewUrl(),view.getDisplayName());
}
return menu;
}
/**
* Obtains the heap dump.
*/
......
package jenkins.model;
import hudson.model.ModelObject;
import jenkins.model.ModelObjectWithContextMenu.ContextMenu;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* {@link ModelObject} that has the children context menu in the breadcrumb.
*
* <p>
* The children context menu is to show all the immediate children that this model object owns,
* thereby providing quicker navigation to ancestors' siblings in the breadcrumb.
*
* @author Kohsuke Kawaguchi
* @see ModelObjectWithContextMenu
*/
public interface ModelObjectWithChildren extends ModelObject {
/**
* Generates the context menu to list up all the children.
*/
public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception;
}
......@@ -39,6 +39,7 @@ import java.util.List;
* shows the drop-down menu for providing quicker access to the actions to those objects.
*
* @author Kohsuke Kawaguchi
* @see ModelObjectWithChildren
*/
public interface ModelObjectWithContextMenu extends ModelObject {
/**
......
......@@ -39,7 +39,7 @@ THE SOFTWARE.
</st:documentation>
<j:if test="${mode=='breadcrumbs'}">
<li id="${attrs.id}">
<li id="${attrs.id}" class="item">
<a href="${attrs.href}" class="model-link inside">
${attrs.title}
</a>
......
......@@ -58,11 +58,22 @@ THE SOFTWARE.
<ul id="breadcrumbs">
<j:forEach var="anc" items="${request.ancestors}">
<j:if test="${h.isModel(anc.object) and anc.prev.url!=anc.url}">
<li class="">
<li class="item">
<a href="${anc.url}/" class="${h.isModelWithContextMenu(anc.object)?'model-link':null} inside">
${anc.object.displayName}
</a>
</li>
<j:choose>
<j:when test="${h.isModelWithChildren(anc.object)}">
<li class="children" href="${anc.url}/">
<!-- shows '>' for rendering children -->
</li>
</j:when>
<j:otherwise>
<li class="separator">
</li>
</j:otherwise>
</j:choose>
</j:if>
</j:forEach>
......
......@@ -29,9 +29,8 @@
#breadcrumbs LI {
float:left;
line-height:2em;
height: 2em;
color:#555753;
padding-right: 15px;
background:url('breadcrumb.gif') no-repeat right center;
}
#breadcrumbs LI A {
......@@ -49,7 +48,26 @@
color:#3465a4;
}
#menuSelector {/* used for showing '>' on the right of the anchor */
#breadcrumbs LI.children, #breadcrumbs LI.separator {/* '>' separator between two items */
width: 16px;
background-image: url(menu_right_arrow2.png);
background-position: center center;
background-repeat: no-repeat;
}
#breadcrumbs LI.children {
cursor: pointer;
}
#breadcrumbs LI.children:hover {
background-image: url(menu_right_arrow.png);
}
#breadcrumbs LI.separator:last-child {/* separators are for in-between only */
display: none;
}
#menuSelector {/* used for showing 'v' on the right of the anchor */
background-color:transparent;
background-image: url(menu_down_arrow.png);
background-position: center center;
......
......@@ -114,7 +114,7 @@ var breadcrumbs = (function() {
this.style.visibility = "hidden";
};
menuSelector.observe("click",function () {
handleHover(this.target);
invokeContextMenu(this.target);
});
// if the mouse leaves the selector, hide it
......@@ -137,14 +137,18 @@ var breadcrumbs = (function() {
})();
/**
* Called when the mouse cursor comes into the context menu hot spot.
* Called when the user clicks a mouse to show a context menu.
*
* If the mouse stays there for a while, a context menu gets displayed.
*
* @param {HTMLElement} e
* anchor tag
* @param {String} contextMenuUrl
* The URL that renders JSON for context menu. Optional.
*/
function handleHover(e) {
function invokeContextMenu(e,contextMenuUrl) {
contextMenuUrl = contextMenuUrl || "contextMenu";
function showMenu(items) {
menu.hide();
var pos = [e, "tl", "bl"];
......@@ -163,7 +167,7 @@ var breadcrumbs = (function() {
if (e.items) {// use what's already loaded
showMenu(e.items());
} else {// fetch menu on demand
xhr = new Ajax.Request(combinePath(e.getAttribute("href"),"contextMenu"), {
xhr = new Ajax.Request(combinePath(e.getAttribute("href"),contextMenuUrl), {
onComplete:function (x) {
var a = x.responseText.evalJSON().items;
function fillMenuItem(e) {
......@@ -210,6 +214,15 @@ var breadcrumbs = (function() {
});
});
Behaviour.specify("#breadcrumbs LI.children", 'breadcrumbs', 0, function (a) {
a.observe("mouseover",function() {
menuSelector.hide();
});
a.observe("click",function() {
invokeContextMenu(this,"childrenContextMenu");
})
});
/**
* @namespace breadcrumbs
* @class ContextMenu
......
......@@ -5,8 +5,6 @@ import jenkins.model.ModelObjectWithContextMenu;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册