You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by ma...@apache.org on 2013/02/04 17:01:36 UTC
svn commit: r1442158 - in /incubator/bloodhound/trunk:
bloodhound_dashboard/bhdashboard/htdocs/js/ bloodhound_theme/bhtheme/
bloodhound_theme/bhtheme/htdocs/ bloodhound_theme/bhtheme/templates/
trac/trac/web/
Author: matevz
Date: Mon Feb 4 16:01:36 2013
New Revision: 1442158
URL: http://svn.apache.org/viewvc?rev=1442158&view=rev
Log:
#217 - Make Bloodhound's layout responsive (initial implementation)
Added:
incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/htdocs/js/bloodhound-stickyscroll.js (with props)
Modified:
incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css
incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html
incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket_box.html
incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bloodhound_theme.html
incubator/bloodhound/trunk/bloodhound_theme/bhtheme/theme.py
incubator/bloodhound/trunk/trac/trac/web/chrome.py
Added: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/htdocs/js/bloodhound-stickyscroll.js
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/htdocs/js/bloodhound-stickyscroll.js?rev=1442158&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/htdocs/js/bloodhound-stickyscroll.js (added)
+++ incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/htdocs/js/bloodhound-stickyscroll.js Mon Feb 4 16:01:36 2013
@@ -0,0 +1,59 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+$(document).ready(function stickyStatus() {
+
+ $(window).scroll(function onScroll() {
+
+ var windowWidth = $(window).width();
+
+ var docViewTop = $(window).scrollTop();
+ var docViewBottom = docViewTop + $(window).height();
+
+ var headerTop = $("header").offset().top;
+ var headerBottom = headerTop + $("header").height();
+
+ var statusTop = $("#stickyStatus").offset().top;
+ var statusBottom = statusTop + $("#stickyStatus").height();
+
+ var desktopStickyHeight = $("#stickyStatus").outerHeight();
+
+ if(windowWidth >= 768) {
+ if (docViewTop > headerBottom) {
+ $("#stickyStatus").addClass("sticky");
+ $(".stickyOffset").css("height", desktopStickyHeight + "px");
+ }
+ else {
+ $("#stickyStatus").removeClass("sticky");
+ $(".stickyOffset").css("height", "0px");
+ }
+ }
+ else {
+ if (docViewTop > headerBottom) {
+ $("#stickyStatus").addClass("sticky");
+ $(".stickyOffset").css("height", mobileStickyHeight + "px");
+ }
+ else {
+ $("#stickyStatus").removeClass("sticky");
+ $(".stickyOffset").css("height", "0px");
+ }
+ }
+
+ });
+});
Propchange: incubator/bloodhound/trunk/bloodhound_dashboard/bhdashboard/htdocs/js/bloodhound-stickyscroll.js
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css?rev=1442158&r1=1442157&r2=1442158&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css (original)
+++ incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css Mon Feb 4 16:01:36 2013
@@ -17,8 +17,29 @@
under the License.
*/
+body {
+ background-color: rgb(92%, 91%, 88%);
+}
+
+.container:first-child {
+ background-color: rgb(100%, 100%, 100%);
+ padding: 5px 20px;
+ border-left: 1px solid rgb(70%, 70%, 70%);
+ border-right: 1px solid rgb(70%, 70%, 70%);
+ border-bottom: 1px solid rgb(70%, 70%, 70%);
+ box-shadow: 0px 0px 10px 2px rgba(50%, 50%, 50%, 0.4);
+ border-bottom-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+}
+
+#searchbox {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
#mainsearch {
- margin-bottom: 0px;
+ margin-bottom: 0;
+ display: inline-block;
}
#mainnav {
@@ -134,9 +155,9 @@ div.reports form {
/* @end */
-#ticket table.properties td,
-#ticket table.properties th {
- font-size: 100%;
+#ticket .properties table td,
+#ticket .properties table th {
+ border: none;
}
#ticket footer {
@@ -144,6 +165,14 @@ div.reports form {
}
+#trac-ticket-title {
+ margin-bottom: 5px;
+}
+
+#trac-ticket-title span.ticket-info {
+ font-weight: normal;
+}
+
#activityfeed img {
display: none;
}
@@ -156,6 +185,11 @@ div.reports form {
color: grey;
}
+#mobile-activity {
+ margin-top: 50px;
+}
+
+
div.reports form,
div.reports .inlinebutton {
float: right;
@@ -172,12 +206,6 @@ div.reports h2 {
/* @group Wiki */
-/*
-textarea.wikitext {
- min-width: 66%;
-}
-*/
-
.wiki-toc {
float: right;
margin-left: 25px;
@@ -202,33 +230,43 @@ pre.wiki {
/* @group Ticket page modifications */
-#comment {
- width: 605px;
+.bh-ticket-buttons {
+ padding-left: 5px;
}
-#field-description {
- width: 505px;
+.clearboth {
+ clear: both;
}
-#qct-fieldset #field-description {
- width: auto;
+.ticket .keywords {
+ margin: 20px 0;
}
-.bh-ticket-buttons {
- padding-left: 5px;
+.ticket .properties h5 {
+ margin-top: 0;
+ margin-bottom: 0;
}
-.ticket .properties .enum h5, #basic-properties h5 {
- margin-top: 0px;
+.ticket-box-field, .ticket-box-info {
+ margin-top: 0;
+ margin-bottom: 0;
}
-.ownership {
- margin-left: 25px;
+.ticket-box-info dt {
+ text-align: left;
}
-.ticket textarea {
- height: auto;
- width: auto;
+#modifyproperties th, #modifyproperties td {
+ vertical-align: baseline;
+ border: none;
+}
+
+.ticket-summary #field-summary {
+ margin-bottom: 0;
+}
+
+.ticket .properties .enum h5 {
+ margin-top: 0px;
}
.trac-loading {
@@ -259,6 +297,10 @@ pre.wiki {
width: 260px;
}
+#qct-fieldset #field-description {
+ width: auto;
+}
+
#qct-box #qct-cancel {
display: inline;
color: #08C;
@@ -478,14 +520,107 @@ input[type="submit"].btn.btn-micro {
display: inherit !important;
}
+.breadcrumb {
+ background-color: #FBFBFB;
+ background-image: -moz-linear-gradient(center top , #FFFFFF, #F5F5F5);
+ background-repeat: repeat-x;
+ border: 1px solid #DDDDDD;
+ border-radius: 3px 3px 3px 3px;
+ box-shadow: 0 1px 0 #FFFFFF inset;
+ list-style: none outside none;
+ margin: 0 0 18px;
+ padding: 7px 14px;
+}
+
@media (max-width: 979px) {
.hidden-desktop {
display: inherit !important;
}
}
-.help-msg[title] {
- cursor: help;
+@media (min-width: 979px) and (max-width: 1199px) {
+ .main-nav ul {
+ background-color: red;
+ }
+}
+
+@media (max-width: 767px) {
+ body {
+ padding-left: 8px;
+ padding-right: 8px;
+ }
+
+ #logo, #usermenu, #breadcrumbbar {
+ float: left;
+ }
+
+ #searchbox {
+ float: left;
+ margin-right: 10px;
+ }
+
+ .breadcrumb {
+ margin-top: 7px;
+ }
+
+ .comment-meta {
+ margin-bottom: 5px;
+ }
+
+ .comment-meta .id,
+ .comment-meta .date {
+ text-align: right;
+ }
+
+ .sticky {
+ width: 100%;
+ position: relative;
+ left: 0px;
+ padding-left: 29px;
+ }
+
+ #belowStatus {
+ margin-top: 5px;
+ }
+
+ .ticket .properties div[class*="span"] {
+ float: left;
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ #changelog .change .span2 {
+ float: left;
+ }
+}
+
+@media (max-width: 480px) {
+ body {
+ padding-left: 0px;
+ padding-right: 0px;
+ }
+
+ h1 {
+ font-size: 30px;
+ margin-bottom: 0px;
+ line-height: 1;
+ }
+
+ .container:first-child {
+ border-left: 0px solid white;
+ border-right: 0px solid white;
+ padding: 0px;
+ }
+
+ header, #belowStatus, #mobile-activity,
+ #stickyStatus, #footer-container {
+ padding-left: 7px;
+ padding-right: 7px;
+ }
+
+ .ownership {
+ padding-left: 15px;
+ }
}
/* Revert some changes introduced in 2.1.0 */
@@ -496,18 +631,6 @@ h6 {
text-transform: uppercase;
}
-.breadcrumb {
- background-color: #FBFBFB;
- background-image: -moz-linear-gradient(center top , #FFFFFF, #F5F5F5);
- background-repeat: repeat-x;
- border: 1px solid #DDDDDD;
- border-radius: 3px 3px 3px 3px;
- box-shadow: 0 1px 0 #FFFFFF inset;
- list-style: none outside none;
- margin: 0 0 18px;
- padding: 7px 14px;
-}
-
/* @end */
/* @group Bootstrap extensions */
@@ -679,34 +802,116 @@ endColorstr='#ffe6e6e6', GradientType=0)
/* @group Sticky Status */
-[class*="span"].stickyStatus {
- margin-left: 0px;
+#stickyStatus {
+ position: relative;
+ background-color: white;
+ z-index: 20;
}
-.stickyStatus.affix {
- background-color: #FFFFFF;
- border-bottom: 2px solid #A4A4A4;
- position: fixed;
+/* The box-shadow overhanging to the left and right are hacks only.
+ We should look for a better solution for production code. */
+#stickyStatus.sticky {
+ position: fixed !important;
top: 0px;
- z-index: 1024;
+ opacity: 1;
+ background-color: rgb(93%, 93%, 93%);
+
+ padding-bottom: 10px;
+
+ border-bottom: 1px solid rgba(75%, 75%, 75%, 0.5);
+
+ -webkit-box-shadow: 0px 6px 5px -4px rgba(50%, 50%, 50%, 0.5),
+ -20px 0px 0px rgb(93%, 93%, 93%),
+ 20px 0px 0px rgb(93%, 93%, 93%);
+ -moz-box-shadow: 0px 6px 5px -4px rgba(50%, 50%, 50%, 0.5),
+ -20px 0px 0px rgb(93%, 93%, 93%),
+ 20px 0px 0px rgb(93%, 93%, 93%);
+ box-shadow: 0px 6px 5px -4px rgba(50%, 50%, 50%, 0.5),
+ -20px 0px 0px rgb(93%, 93%, 93%),
+ 20px 0px 0px rgb(93%, 93%, 93%);
+
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ -o-transition: all 0.3s ease-out;
+ -ms-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out;
+}
+
+#belowStatus {
+ position: relative;
+ margin-top: 20px;
+}
+
+.offsetSticky {
+ height: 130px;
+}
+
+#stickyStatus h2,
+#stickyStatus ul {
+ margin-bottom: 3px;
+}
+
+#stickyStatus h2 {
+ line-height: 30px;
+}
+
+.local-nav {
+ display: inline-block;
+ margin-left: 0;
+}
+
+.ownership {
+ padding-left: 25px;
+}
+
+#description {
+ margin-top: 10px;
+}
+
+.comment {
+ border-top: 1px solid rgb(80%, 80%, 80%);
+ margin-bottom: 10px;
+ padding-top: 5px;
+}
+
+.comment-meta {
+ overflow: hidden;
+}
+
+.comment-meta .id,
+.comment-meta .date {
+ float: right;
+ color: #888;
+ font-size: 90%;
+}
+
+.comment-meta span:first-child {
+ font-weight: 700;
+}
+
+.add-comment textarea {
+ height: 100px;
+ border: 1px solid #eee;
+ color: lightgray;
+ display: block;
}
/* @end */
/* @group Wiki Tables */
-TABLE.wiki {
+table.wiki {
border: 1px solid #CCCCCC;
border-collapse: collapse;
border-spacing: 0;
}
-TABLE.wiki td {
+table.wiki td {
border: 1px solid #CCCCCC;
padding: 0.1em 0.25em;
}
-TABLE.wiki th {
+table.wiki th {
border: 1px solid #BBBBBB;
padding: 0.1em 0.25em;
background-color: #F7F7F7;
Modified: incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html?rev=1442158&r1=1442157&r2=1442158&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html (original)
+++ incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html Mon Feb 4 16:01:36 2013
@@ -34,16 +34,28 @@
has_edit_comment = 'TICKET_EDIT_COMMENT' in perm(ticket.resource);
has_property_editor = not version and version != 0 and not cnum_edit
and (can_append or can_modify or can_edit or can_create);
- colspan = 'span8' if bhdb else 'span12'">
+ colspan = 'span8';
+ cols_activity = 'span4'">
<xi:include href="layout.html" />
<xi:include href="widget_macros.html" />
<head>
+ <!--! hack for hiding the activity feed title in desktop/tablet landscape mode (the title is part of the sticky) -->
+ <style>
+ @media (min-width: 768px) {
+ #activity h3 { display: none !important; }
+ }
+ @media (max-width: 767px) {
+ #activity h3 { display: inherit !important; }
+ }
+ </style>
+ <meta py:if="responsive_layout" name="viewport" content="width=device-width, initial-scale=1.0" />
<title py:choose="">
<py:when test="ticket.exists">#${ticket.id} (${ticket.summary})</py:when>
<py:otherwise>New Ticket</py:otherwise>
</title>
<script py:if="ticket.exists" type="text/javascript" src="${chrome.htdocs_location}js/threaded_comments.js"></script>
+ <script type="text/javascript" src="${href.chrome('dashboard/js/bloodhound-stickyscroll.js')}"></script>
<script type="text/javascript" py:choose="">
jQuery(document).ready(function($) {
/* Affixed navbar */
@@ -149,11 +161,10 @@
$('.local-nav a[href = "#inplace-edit"]').click(modify_ticket);
</py:if>
- $('body').scrollspy({
- 'target' : '.local-nav' ,
- 'offset' : $('.stickyBox').height() + 40
+ $('body').scrollspy({
+ 'target' : '.ticket-navbar',
+ 'offset' : 0
})
-
$("div.description").find("h1,h2,h3,h4,h5,h6").addAnchor(_("Link to this section"));
$(".foldable").enableFolding(false, true);
<py:when test="ticket.exists">/*<![CDATA[*/
@@ -225,219 +236,159 @@
<a href="#comment:$cnum" class="$cls">$prefix$cnum</a>
</py:def>
- <div id="content" class="ticket row">
+ <py:def function="render_ticket_summary(t, showid)">
+ <h2 class="ticket-summary searchable clip-affix" py:choose="" data-edit="${'inplace' if can_modify or can_create else None}" id="vc-summary">
+ <py:when test="t.exists"><py:if test="showid"><span class="visible-phone">#$t.id - </span></py:if> ☆ $t.summary</py:when>
+ <py:otherwise>Create Ticket</py:otherwise>
+ </h2>
+ </py:def>
+
+ <py:def function="render_ticket_navbar(t)">
+ <div class="ticket-navbar" py:if="t.exists"
+ py:with="sections = (
+ (_('Overview'), 'content', True, _('View ticket fields and description'), 'icon-list'),
+ (_('Attachments'), 'attachments', attachments.attachments or attachments.can_create, _('Go to the list of attachments'), 'icon-file'),
+ (_('Comments'), 'changelog', True, _('Go to the changelog'), 'icon-comment'),
+ (_('Add comment'), 'propertyform', t.exists and can_append, _('Go to the ticket editor'), 'icon-plus-sign'),
+ (_('Modify Ticket'), 'inplace-edit', can_modify or can_edit or can_create, _('Modify ticket fields and description'), 'icon-edit'),
+ )">
+ <ul class="btn-group local-nav nav">
+ <li py:for="s in sections" py:if="s[2]" class="btn">
+ <a href="#${s[1]}" title="${s[3]}">
+ <i class="${s[4]}"></i>
+ <!-- show first three descriptions on tables, hide all on phones -->
+ <py:choose>
+ <span py:when="sections.index(s) > 2" class="hidden-phone hidden-tablet">${s[0]}</span>
+ <span py:otherwise="" class="hidden-phone">${s[0]}</span>
+ </py:choose>
+ </a>
+ </li>
+ </ul>
+ </div>
+ </py:def>
+
+ <div class="ticket">
<div class="trac-topnav span2" py:if="ticket.exists and has_property_editor">
<a href="#propertyform" title="Go to the ticket editor">Modify</a> ↓
</div>
<br/>
- <div class="$colspan">
- <py:if test="ticket.exists">
- <div class="row">
- <div class="$colspan"><form py:strip="not has_property_editor" method="post"
- id="inplace-propertyform"
- action="${href.ticket(ticket.id) + '#trac-add-comment' if ticket.exists
- else href.newticket() + '#ticket'}">
- <py:if test="has_property_editor">
- <input type="hidden" name="start_time"
- value="${to_utimestamp(start_time)}" />
- <input type="hidden" name="view_time"
- value="${to_utimestamp(ticket['changetime'])}" />
- </py:if>
- <input id="hidden-comment" type="hidden" name="comment"
- value=""/>
- <div class="stickyBox">
- <div id="overview" class="stickyStatus $colspan">
- <div class="whitebox"></div>
- <div class="properties">
- <h2 class="summary searchable clip-affix" py:choose=""
- data-edit="${'inplace' if can_modify or can_create else None}"
- id="vc-summary">
- <py:when test="ticket.exists">☆ $ticket.summary</py:when>
- <py:otherwise>Create Ticket</py:otherwise>
- </h2>
- </div>
- <div class="row">
- <span class="ownership">
- <py:choose test="">
- <py:when test="ticket.exists">
- <a href="${href.ticket(ticket.id)}"
- i18n:msg="id">Ticket #${ticket.id}</a>
- </py:when>
- <py:otherwise>
- New Ticket <small><span py:if="preview_mode and ticket.type" class="status">(${ticket.type})</span></small>
- </py:otherwise>
- </py:choose>
- <py:if test="ticket.exists"> -
- <py:if test="ticket.changetime != ticket.time">
- <span i18n:msg="modified">Last modified
- <time datetime="${ticket.changetime.strftime('%Y-%m-%d')}">
- ${pretty_dateinfo(ticket.changetime)}
- </time>.
- </span>
- </py:if>
- </py:if>
+ <div class="row">
+ <form py:strip="not has_property_editor" method="post" id="inplace-propertyform"
+ action="${href.ticket(ticket.id) + '#trac-add-comment' if ticket.exists else href.newticket() + '#ticket'}">
+ <py:if test="has_property_editor">
+ <input type="hidden" name="start_time" value="${to_utimestamp(start_time)}" />
+ <input type="hidden" name="view_time" value="${to_utimestamp(ticket['changetime'])}" />
+ </py:if>
+ <input id="hidden-comment" type="hidden" name="comment" value="" />
+
+ <!--! ticket + activity sticky -->
+ <div id="stickyStatus" class="span12">
+ <div class="row">
+ <!--! ticket info -->
+ <div class="$colspan">
+ <!--! ticket properties -->
+ <div class="properties">
+ ${render_ticket_summary(ticket, False)}
+
+ <h5 id="trac-ticket-title" py:choose="">
+ <py:when test="ticket.exists">
+ <a href="${href.ticket(ticket.id)}"
+ i18n:msg="id">Ticket #${ticket.id}</a>
+ </py:when>
+ <py:otherwise>
+ New Ticket <small><span py:if="preview_mode and ticket.type" class="status">(${ticket.type})</span></small>
+ </py:otherwise>
+
+ <span class="ticket-info">
+<!--!
+ <span id="h_reporter"> - Reported by
+ <span id="vc-reporter" data-edit="${'inplace' if only_for_admin else None}">
+ ${reporter_link if defined('reporter_link') else authorinfo(ticket.reporter)},
+ </span>
+ </span>
+-->
<span id="h_owner">Assigned to
- ${(owner_link if defined('owner_link') else authorinfo(ticket.owner)) if ticket.owner else ''}.
+ ${(owner_link if defined('owner_link') else authorinfo(ticket.owner)) if ticket.owner else ''}
</span>
+ <br />
+ <span i18n:msg="created" py:if="ticket.exists">Opened ${pretty_dateinfo(ticket.time)}</span>
+ <py:if test="ticket.changetime != ticket.time">,
+ <span i18n:msg="modified">Last modified ${pretty_dateinfo(ticket.changetime)}</span>
+ </py:if>
+ <span py:if="not ticket.exists" class="label label-warning">(ticket not yet created)</span>
</span>
- </div>
- <div class="local-nav" py:if="ticket.exists"
- py:with="sections = (
- (_('Overview'), 'content', True, _('View ticket fields and description'), 'icon-list'),
- (_('Attachments'), 'attachments', attachments.attachments or attachments.can_create, _('Go to the list of attachments'), 'icon-file'),
- (_('Comments'), 'changelog', True, _('Go to the changelog'), 'icon-comment'),
- (_('Add comment'), 'propertyform', ticket.exists and can_append, _('Go to the ticket editor'), 'icon-plus-sign'),
- (_('Modify Ticket'), 'inplace-edit', can_modify or can_edit or can_create, _('Modify ticket fields and description'), 'icon-edit'),
- )">
- <div>
- <small>
- <ul class="nav btn-group">
- <li py:for="s in sections" py:if="s[2]" class="btn">
- <a href="#${s[1]}" title="${s[3]}">
- <i class="${s[4]}"></i>
- ${s[0]}
- </a>
- </li>
- </ul>
- </small>
- </div>
- </div>
- <div class="stickyEndMark"></div>
+ </h5>
</div>
+
+ <!--! ticket navbar -->
+ ${render_ticket_navbar(ticket)}
</div>
- <script type="text/javascript">
- setup_sticky_panel('#overview');
- </script>
-
- <div id="basic-properties">
- <div class="row">
- <div class="span4">
- <div class="row">
- <div class="span2">
- <h5 id="h_reporter" class="pull-right">
- Reporter:
- </h5>
- </div>
- <div class="span2" id="vc-reporter"
- data-edit="${'inplace' if only_for_admin else None}">
- ${reporter_link if defined('reporter_link') else authorinfo(ticket.reporter)}
-
- </div>
- </div>
- </div>
- <div class="span4">
- <div class="row">
- <div class="span2">
- <h5 id="h_reporter" class="pull-right">
- Opened:
- </h5>
- </div>
- <div class="span2">
- <time datetime="${ticket.time.strftime('%Y-%m-%d')}">
- ${pretty_dateinfo(ticket.time)}
- </time>
-
- </div>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="span4">
- <div class="row">
- <div class="span2">
- <h5 id="h_type" class="pull-right">
- Type:
- </h5>
- </div>
- <div id="vc-type" class="span2"
- data-edit="${'inplace' if can_modify or can_edit or can_create else None}">
- <small py:if="ticket.type">${ticket.type}</small>
-
- </div>
- </div>
- </div>
- <div class="span4">
- <div class="row">
- <div class="span2">
- <h5 id="h_status" class="pull-right">
- Status:
- </h5>
- </div>
- <div class="span2">
- <small>${ticket.status}
- <py:if test="ticket.resolution">: ${ticket.resolution}</py:if>
- </small>
-
+
+ <!--! activity header -->
+ <div py:if="bhdb and ticket.exists" class="$cols_activity hidden-phone">
+ <h2>${_('Activity')}</h2>
+ </div>
+ </div>
+ </div>
+
+ <div id="content" class="span8">
+ <div id="belowStatus">
+ <div class="stickyOffset" style="height: 0px;"></div>
+
+ <!--! ticket details -->
+ <py:if test="ticket.exists">
+ <!--! main ticket info -->
+ <div class="properties">
+ <div class="row">
+ <div class="span4">
+ <div class="row">
+ <div class="span2">
+ <h5 id="h_reporter" class="pull-right">
+ Reporter:
+ </h5>
+ </div>
+ <div class="span2" id="vc-reporter" data-edit="${'inplace' if only_for_admin else None}">
+ ${reporter_link if defined('reporter_link') else authorinfo(ticket.reporter)}
+ </div>
</div>
</div>
</div>
</div>
- </div>
- <xi:include href="bh_ticket_box.html"
- py:with="preview_mode = change_preview.fields ;
- colcount = 4 if bhdb else 6"/>
- </form></div>
-
- <!--! do not show attachments for old versions of this ticket or for new tickets -->
- <div class="$colspan" py:if="not version and version != 0 and ticket.exists">
- <xi:include href="bh_list_of_attachments.html"
- py:with="alist = attachments; foldable = True"/>
- </div>
- <div class="$colspan">
- <div style="${'display: none' if not changes else None}">
- <div style="position: relative">
- <form id="prefs" method="get" action="${href.prefs()}" style="position: absolute; right: 0">
- <div id="trac-comments-order" style="display: inline">
- <input type="radio" id="trac-comments-oldest" name="trac-comments-order" value="oldest" checked="checked" />
- <label for="trac-comments-oldest">
- <span class="label">Oldest first</span>
- </label>
- <input type="radio" id="trac-comments-newest" name="trac-comments-order" value="newest" />
- <label for="trac-comments-newest">
- <span class="label">Newest first</span>
- </label>
- <span id="trac-threaded-toggle" style="display: none">
- <input type="radio" id="trac-comments-threaded" name="trac-comments-order" value="threaded" />
- <label for="trac-comments-threaded">
- <span class="label">Threaded</span>
- </label>
- </span>
- </div>
- <div style="display: inline">
- <input id="trac-comments-only-toggle" type="checkbox" />
- <label for="trac-comments-only-toggle">
- <span class="label">Comments only</span>
- </label>
- </div>
- </form>
+ <div>
+ <xi:include href="bh_ticket_box.html"
+ py:with="preview_mode = change_preview.fields ;
+ colcount = 4 if bhdb else 6"/>
</div>
-
- <br/>
- <h2 class="foldable">Change History</h2>
-
- <div id="changelog">
- <py:for each="change in changes">
- <div class="change${' trac-new' if change.date > start_time and 'attachment' not in change.fields else None}"
- id="${'trac-change-%d-%d' % (change.cnum, to_utimestamp(change.date)) if 'cnum' in change else None}">
- <xi:include href="bh_ticket_change.html"/>
- </div>
- </py:for>
+
+ <!--! do not show attachments for old versions of this ticket or for new tickets -->
+ <div py:if="not version and version != 0 and ticket.exists">
+ <xi:include href="bh_list_of_attachments.html"
+ py:with="alist = attachments; foldable = True"/>
</div>
- </div>
+ </py:if>
+
</div>
</div>
- </py:if>
- <!--! End of the section we don't show on initial new tickets -->
+ </form>
- <div class="row">
+ <div py:if="bhdb and ticket.exists" id="activity" class="$cols_activity hidden-phone">
+ <bh:widget urn="Timeline">
+ <bh:args>
+ <bh:arg name="filters">ticket,ticket_details,changeset</bh:arg>
+ </bh:args>
+ </bh:widget>
+ </div>
+
+ <div class="$colspan">
+ <!--! add comment + modify ticket -->
<form py:if="has_property_editor" method="post" id="propertyform"
action="${href.ticket(ticket.id) + '#trac-add-comment' if ticket.exists
else href.newticket() + '#ticket'}">
- <div class="$colspan">
+ <div py:if="ticket.exists and can_append">
<!--! Add comment -->
- <div py:if="ticket.exists and can_append" id="trac-add-comment" class="field">
+ <div id="trac-add-comment" class="field">
<div class="trac-nav">
<a href="#content" title="View ticket fields and description">View</a> ↑
</div>
@@ -445,8 +396,8 @@
<a id="edit" onfocus="$('#comment').get(0).focus()">Add a comment</a>
</h2>
<div id="trac-edit-warning" class="warning system-message alert"
- style="${'display: none' if start_time == ticket['changetime'] else None}"
- i18n:msg="">
+ style="${'display: none' if start_time == ticket['changetime'] else None}"
+ i18n:msg="">
<span class="label label-warning">Warning</span>
This ticket has been modified since you started editing. You should review the
<em class="trac-new">other modifications</em> which have been appended above,
@@ -455,8 +406,7 @@
</div>
<!--! Comment field -->
<fieldset class="iefix">
- <textarea id="comment" name="comment" class="wikitext trac-resizable" rows="10" cols="78">
-${comment}</textarea>
+ <textarea id="comment" name="comment" class="span8 wikitext trac-resizable" rows="10">${comment}</textarea>
<label for="comment" class="help-block pull-right" i18n:msg="">
<span class="label label-info">Tip</span>
You may use
@@ -467,143 +417,131 @@ ${comment}</textarea>
</div>
</div>
- <div class="$colspan">
- <div>
- <h2 py:if="ticket.exists" class="foldable">Modify Ticket</h2>
- <div id="modify" class="well">
- <!--! Properties -->
- <fieldset id="properties" py:if="can_modify or can_edit or can_create"
- py:with="fields = [f for f in fields if not f.skip]">
- <legend py:choose="">
- <py:when test="ticket.exists">Change Properties</py:when>
- <py:otherwise>Properties</py:otherwise>
- </legend>
- <table>
- <tr py:if="can_modify or can_create">
- <th><label for="field-summary">Summary:</label></th>
- <td class="fullrow" colspan="3">
- <input type="text" id="field-summary" name="field_summary"
- value="$ticket.summary" size="70"
- class="input-xlarge" />
- </td>
- </tr>
- <py:if test="only_for_admin">
- <tr>
- <th><label for="field-reporter">Reporter:</label></th>
- <td class="fullrow" colspan="3">
- <input type="text" id="field-reporter" name="field_reporter"
- value="${ticket.reporter}" class="input-medium" />
- </td>
- </tr>
- </py:if>
- <py:if test="can_edit or can_create">
- <tr>
- <th><label for="field-description">Description:</label></th>
- <td class="fullrow" colspan="3">
- <fieldset class="iefix">
- <textarea id="field-description" name="field_description"
- class="wikitext trac-resizable" rows="10" cols="68">
-${ticket.description}</textarea>
- <label for="field-description" id="field-description-help" class="help-block pull-right" i18n:msg="">
- <span class="label label-info">Tip</span>
- You may use
- <a tabindex="42" href="${href.wiki('WikiFormatting')}">WikiFormatting</a> here.
- </label>
- </fieldset>
- </td>
- </tr>
- </py:if>
- <tr py:for="row in group(fields, 2, lambda f: f.type != 'textarea')"
- py:if="can_modify or can_create"
- py:with="fullrow = len(row) == 1">
- <py:for each="idx, field in enumerate(row)"
- py:with="value = ticket.get_value_or_default(field.name)">
- <th class="col${idx + 1}" py:if="idx == 0 or not fullrow">
- <label for="field-${field.name}" py:if="field"
- i18n:msg="field">${
- field.edit_label or field.label or field.name}:</label>
- </th>
- <td class="col${idx + 1}" py:if="idx == 0 or not fullrow"
- colspan="${3 if fullrow else None}"
- id="${'editor-' + field.name if field else None}">
- <py:choose test="field.type" py:if="field">
- <select py:when="'select'" id="field-${field.name}" name="field_${field.name}" class="input-medium">
- <option py:if="field.optional"></option>
- <option py:for="option in field.options"
+ <div>
+ <h2 py:if="ticket.exists" class="foldable">Modify Ticket</h2>
+ <div id="modify" class="well">
+ <!--! Properties -->
+ <fieldset id="properties" py:if="can_modify or can_edit or can_create"
+ py:with="fields = [f for f in fields if not f.skip]">
+ <legend py:choose="">
+ <py:when test="ticket.exists">Change Properties</py:when>
+ <py:otherwise>Properties</py:otherwise>
+ </legend>
+
+ <table id="modifyproperties">
+ <tr py:if="can_modify or can_create">
+ <td colspan="2">
+ <label for="field-summary">Summary:</label>
+ <input class="${'span4' if ticket.exists else 'span7'}" type="text" id="field-summary" name="field_summary" value="$ticket.summary" />
+ </td>
+ </tr>
+
+ <tr py:if="only_for_admin">
+ <td colspan="2">
+ <label for="field-reporter">Reporter:</label>
+ <input class="${'span2' if ticket.exists else 'span7'}" type="text" id="field-reporter" name="field_reporter" value="${ticket.reporter}" />
+ </td>
+ </tr>
+
+ <tr py:if="can_edit or can_create">
+ <td colspan="2">
+ <label for="field-description">Description:</label>
+ <fieldset class="iefix">
+ <textarea id="field-description" name="field_description"
+ class="span7 wikitext trac-resizable" rows="10">${ticket.description}</textarea>
+ <label for="field-description" id="field-description-help" class="help-block pull-right" i18n:msg="">
+ <span class="label label-info">Tip</span>
+ You may use
+ <a tabindex="42" href="${href.wiki('WikiFormatting')}">WikiFormatting</a> here.
+ </label>
+ </fieldset>
+ </td>
+ </tr>
+
+ <tr py:for="row in group(fields, 2, lambda f: f.type != 'textarea')"
+ py:if="can_modify or can_create">
+ <py:for each="idx, field in enumerate(row)"
+ py:with="value = ticket.get_value_or_default(field.name)">
+ <td>
+ <label for="field-${field.name}" py:if="field" id="${'editor-' + field.name}"
+ i18n:msg="field">${field.edit_label or field.label or field.name}:</label>
+ <py:choose test="field.type" py:if="field">
+ <select py:when="'select'" id="field-${field.name}" name="field_${field.name}"
+ class="${'span2' if ticket.exists else 'span3'}">
+ <option py:if="field.optional"></option>
+ <option py:for="option in field.options"
+ selected="${value == option or None}"
+ value="$option" py:content="option"></option>
+ <optgroup py:for="optgroup in field.optgroups"
+ py:if="optgroup.options"
+ label="${optgroup.label}">
+ <option py:for="option in optgroup.options"
selected="${value == option or None}"
value="$option" py:content="option"></option>
- <optgroup py:for="optgroup in field.optgroups"
- py:if="optgroup.options"
- label="${optgroup.label}">
- <option py:for="option in optgroup.options"
- selected="${value == option or None}"
- value="$option" py:content="option"></option>
- </optgroup>
- </select>
- <textarea py:when="'textarea'" id="field-${field.name}" name="field_${field.name}"
- cols="${field.width}" rows="${field.height}"
- class="${'wikitext ' if field.format == 'wiki' else None}trac-resizable">
-${value}</textarea>
- <span py:when="'checkbox'">
- <input type="checkbox" id="field-${field.name}" name="field_${field.name}"
- checked="${value == '1' or None}" value="1" />
- <input type="hidden" name="field_checkbox_${field.name}" value="1" />
- </span>
- <label py:when="'radio'" class="checkbox inline"
- py:for="idx, option in enumerate(field.options)">
- <input type="radio" name="field_${field.name}" value="${option}"
- checked="${value == option or None}" />
- ${option}
- </label>
- <py:otherwise><!--! Text input fields -->
- <py:choose>
- <span py:when="field.cc_entry"><!--! Special case for Cc: field -->
- <em>${field.cc_entry}</em>
- <input type="checkbox" id="field-cc" name="cc_update"
- title="This checkbox allows you to add or remove yourself from the CC list."
- checked="${field.cc_update}" />
- </span>
- <!--! Cc: when TICKET_EDIT_CC is allowed -->
- <span py:when="field.name == 'cc'">
- <input type="text" id="field-${field.name}"
- title="Space or comma delimited email addresses and usernames are accepted."
- name="field_${field.name}" value="${value}" />
- </span>
- <!--! All the other text input fields -->
- <input py:otherwise="" type="text" id="field-${field.name}"
+ </optgroup>
+ </select>
+ <textarea py:when="'textarea'" id="field-${field.name}" name="field_${field.name}"
+ cols="${field.width}" rows="${field.height}"
+ class="${'wikitext ' if field.format == 'wiki' else None}trac-resizable">${value}</textarea>
+ <span py:when="'checkbox'">
+ <input type="checkbox" id="field-${field.name}" name="field_${field.name}"
+ checked="${value == '1' or None}" value="1" />
+ <input type="hidden" name="field_checkbox_${field.name}" value="1" />
+ </span>
+ <label py:when="'radio'" class="checkbox inline"
+ py:for="idx, option in enumerate(field.options)">
+ <input type="radio" name="field_${field.name}" value="${option}"
+ checked="${value == option or None}" />
+ ${option}
+ </label>
+ <py:otherwise><!--! Text input fields -->
+ <py:choose>
+ <span py:when="field.cc_entry"><!--! Special case for Cc: field -->
+ <em>${field.cc_entry}</em>
+ <input type="checkbox" id="field-cc" name="cc_update"
+ title="This checkbox allows you to add or remove yourself from the CC list."
+ checked="${field.cc_update}" />
+ </span>
+ <!--! Cc: when TICKET_EDIT_CC is allowed -->
+ <span py:when="field.name == 'cc'">
+ <input type="text" id="field-${field.name}"
+ title="Space or comma delimited email addresses and usernames are accepted."
name="field_${field.name}" value="${value}" />
- </py:choose>
- </py:otherwise>
- </py:choose>
- </td>
- </py:for>
- </tr>
- </table>
- </fieldset>
-
- <!--! Workflow support -->
- <py:if test="ticket.exists"> <!--! do not display the actions for New tickets -->
- <py:choose>
- <fieldset py:when="can_append or can_modify" id="action">
- <legend>Action</legend>
- <xi:include href="bh_ticket_actions.html" />
- </fieldset>
- <py:otherwise>
- <py:for each="key, label, controls, hints in action_controls">
- <input py:if="key == action" type="hidden" name="action" value="$action" />
- </py:for>
- </py:otherwise>
- </py:choose>
- </py:if>
- </div>
+ </span>
+ <!--! All the other text input fields -->
+ <input py:otherwise="" type="text" id="field-${field.name}"
+ name="field_${field.name}" value="${value}" />
+ </py:choose>
+ </py:otherwise>
+ </py:choose>
+ </td>
+ </py:for>
+ </tr>
+ </table>
+ </fieldset>
+
+ <!--! Workflow support -->
+ <py:if test="ticket.exists"> <!--! do not display the actions for New tickets -->
+ <py:choose>
+ <fieldset py:when="can_append or can_modify" id="action">
+ <legend>Action</legend>
+ <xi:include href="bh_ticket_actions.html" />
+ </fieldset>
+ <py:otherwise>
+ <py:for each="key, label, controls, hints in action_controls">
+ <input py:if="key == action" type="hidden" name="action" value="$action" />
+ </py:for>
+ </py:otherwise>
+ </py:choose>
+ </py:if>
</div>
</div>
<div class="$colspan">
<!--! Preview of ticket changes -->
<div py:if="ticket.exists and can_append" id="ticketchange" class="ticketdraft"
- style="${'display: none' if not (change_preview.fields or change_preview.comment)
- or cnum_edit is not None else None}">
+ style="${'display: none' if not (change_preview.fields or change_preview.comment)
+ or cnum_edit is not None else None}">
<xi:include href="bh_ticket_change.html" py:with="change = change_preview; preview = True"/>
</div>
</div>
@@ -638,9 +576,7 @@ ${value}</textarea>
I have files to attach to this ticket
</label>
</p>
- </div>
- <div class="$colspan">
<div py:if="ticket.exists" class="trac-nav">
<a href="#attachments" title="Go to the list of attachments">Attachments</a> ↑
</div>
@@ -654,57 +590,96 @@ ${value}</textarea>
<input type="submit" class="btn" name="submit" value="${_('Submit changes') if ticket.exists else _('Create ticket')}" />
</div>
</div>
-
</form>
</div>
- <div class="row">
- <div class="$colspan">
- <xi:include href="bh_ticket_box.html" py:if="not ticket.exists" py:with="preview_mode = True"/>
+ <div py:if="ticket.exists and changes" class="$colspan">
+ <h2 class="foldable">Change History</h2>
+ <div>
+ <form id="prefs" method="get" action="${href.prefs()}">
+ <div id="trac-comments-order" style="display: inline">
+ <input type="radio" id="trac-comments-oldest" name="trac-comments-order" value="oldest" checked="checked" />
+ <label for="trac-comments-oldest">
+ <span class="label">Oldest first</span>
+ </label>
+ <input type="radio" id="trac-comments-newest" name="trac-comments-order" value="newest" />
+ <label for="trac-comments-newest">
+ <span class="label">Newest first</span>
+ </label>
+ <span id="trac-threaded-toggle" style="display: none">
+ <input type="radio" id="trac-comments-threaded" name="trac-comments-order" value="threaded" />
+ <label for="trac-comments-threaded">
+ <span class="label">Threaded</span>
+ </label>
+ </span>
+ </div>
+ <div style="display: inline">
+ <input id="trac-comments-only-toggle" type="checkbox" />
+ <label for="trac-comments-only-toggle">
+ <span class="label">Comments only</span>
+ </label>
+ </div>
+ </form>
+ <div id="changelog">
+ <py:for each="change in changes">
+ <div class="change${' trac-new' if change.date > start_time and 'attachment' not in change.fields else None}"
+ id="${'trac-change-%d-%d' % (change.cnum, to_utimestamp(change.date)) if 'cnum' in change else None}">
+ <xi:include href="bh_ticket_change.html"/>
+ </div>
+ </py:for>
+ </div>
+ </div>
+ </div>
+
+ <div class="$colspan">
+ <div py:if="not ticket.exists">
+ <xi:include href="bh_ticket_box.html" py:with="preview_mode = True"/>
</div>
- <div class="$colspan">
- <div id="help" class="help-block pull-right" i18n:msg="">
- <span class="label label-info">Note:</span> See
- <a href="${href.wiki('TracTickets')}">TracTickets</a> for help on using
- tickets.
- </div>
+ <div id="help" class="help-block pull-right" i18n:msg="">
+ <span class="label label-info">Note:</span> See
+ <a href="${href.wiki('TracTickets')}">TracTickets</a> for help on using tickets.
</div>
</div>
- </div>
- <div py:if="bhdb" class="span4">
- <bh:widget urn="Timeline">
- <bh:args>
- <bh:arg name="filters">ticket,ticket_details,changeset</bh:arg>
- </bh:args>
- </bh:widget>
+
+ <div py:if="bhdb and ticket.exists" class="$cols_activity visible-phone">
+ <div id="mobile-activity">
+ <bh:widget urn="Timeline">
+ <bh:args>
+ <bh:arg name="filters">ticket,ticket_details,changeset</bh:arg>
+ </bh:args>
+ </bh:widget>
+ </div>
+ </div>
+
</div>
</div>
<script type="text/x-tmpl" id="tmpl-inplace-submit" py:if="has_property_editor">
- <div class="btn-toolbar" style="margin: 0px">
- <div class="btn-group input-append">
- <button id="edit-submit" class="btn btn-primary" type="submit"
- value="Submit changes" name="submit">
- Update (<span id="submit-action-label"></span>)
- </button>
- <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
- <span class="caret"></span>
- </button>
- <ul class="dropdown-menu">
- <fieldset id="workflow-actions">
- </fieldset>
- </ul>
- </div>
- <div class="btn-group">
- <button id="edit-cancel" class="btn-link" title="Discard changes">
- Cancel
- </button>
- </div>
- <div class="btn-group">
- <span class="trac-loading"> </span>
- </div>
+ <div class="btn-toolbar">
+ <div class="btn-group">
+ <button id="edit-submit" class="btn btn-primary" type="submit"
+ value="Submit changes" name="submit">
+ Update (<span id="submit-action-label"></span>)
+ </button>
+ <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <fieldset id="workflow-actions">
+ </fieldset>
+ </ul>
+ </div>
+ <div class="btn-group">
+ <button id="edit-cancel" class="btn-link" title="Discard changes">
+ Cancel
+ </button>
+ </div>
+ <div class="btn-group">
+ <span class="trac-loading"> </span>
+ </div>
</div>
</script>
+
</body>
</html>
Modified: incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket_box.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket_box.html?rev=1442158&r1=1442157&r2=1442158&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket_box.html (original)
+++ incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket_box.html Mon Feb 4 16:01:36 2013
@@ -36,66 +36,75 @@ Arguments:
xmlns:i18n="http://genshi.edgewall.org/i18n"
id="ticket" class="${'ticketdraft' if preview_mode else None}">
- <py:def function="render_fields_row(fields_row, csscls, fontsize, is_inline)">
- <div class="row">
- <div py:for="idx, field in enumerate(fields_row)" py:if="field is not None"
- class="$csscls${' enum' if is_inline else None}" >
- <div class="row" py:strip="not is_inline">
- <div class="span2" py:strip="not is_inline">
- <h5 id="${'h_' + field.name if field else None}"
- class="${'pull-right' if is_inline else None}">
- <py:if test="field"><i18n:msg params="field">${field.label or field.name}:</i18n:msg></py:if>
- </h5>
- </div>
- <div class="${'span2' if is_inline else None}" data-edit="inplace"
- id="${'vc-' + field.name if field else None}">
- <py:if test="field">
- <py:choose test="">
- <py:when test="'rendered' in field">${field.rendered}</py:when>
- <py:otherwise>${ticket[field.name]}</py:otherwise>
- </py:choose>
- </py:if>
-
+ <py:def function="render_fields_row(fields_row, fontsize, is_inline)">
+ <py:for each="idx, field in enumerate(fields_row)">
+ <py:if test="field is not None">
+ <div class="span4">
+ <div class="row">
+ <div class="span2">
+ <h5 id="${'h_' + field.name if field else None}" class="pull-right">
+ <py:if test="field"><i18n:msg params="field">${field.label or field.name}:</i18n:msg></py:if>
+ </h5>
+ </div>
+ <div class="span2" data-edit="${'inplace' if (field and field.name != 'status') else None}" id="${'vc-' + field.name if field else None}">
+ <py:if test="field">
+ <py:choose test="">
+ <py:when test="'rendered' in field">${field.rendered}</py:when>
+ <py:otherwise>${ticket[field.name]}</py:otherwise>
+ </py:choose>
+ </py:if>
+ </div>
</div>
</div>
- </div>
- </div>
+ </py:if>
+ </py:for>
</py:def>
- <py:with vars="basefields = [f for f in fields if not f.skip and f.name not in ('type', 'owner', 'keywords')];
+
+ <!--!
+ Todo: ticket status and type are included here and thrown out of
+ bh_ticket view. The resolution field is still missing, and all of
+ this should probably be consolidated into the ticket widget itself,
+ instead of this code (i.e., status, type and resolution should not
+ be marked as .skip)
+ -->
+ <py:with vars="basefields = [f for f in fields if (f.name == 'status' or f.name == 'type' or not f.skip)
+ and f.name not in ('owner', 'keywords')];
small_fields = [f for f in basefields if f.type not in ('text', 'textarea') and f.name != 'cc'];
- text_fields = [f for f in basefields if f.type == 'text' or f.name == 'cc'];
+ text_fields = [f for f in basefields if (f.type == 'text' and f.name != 'type') or f.name == 'cc'];
area_fields = [f for f in basefields if f.type == 'textarea'];
_colcount = colcount or 6">
- <div class="properties" style="margin-bottom: 1.2em">
- <py:with vars="_fields, csscls, count, fontsize, is_inline =
- (small_fields, 'span4', _colcount / 2, None, True)">
- <py:for each="fields_row in group(_fields, count)">
- ${render_fields_row(fields_row, csscls, fontsize, is_inline)}
- </py:for>
+ <div class="properties">
+ <py:with vars="_fields, count = (small_fields, _colcount / 2)">
+ <div py:for="fields_row in group(_fields, count)" class="row">
+ ${render_fields_row(fields_row, None, True)}
+ </div>
</py:with>
</div>
- <div class="${'well' if not preview_mode else None}">
- <!--! use a placeholder if it's a new ticket -->
- <py:for each="field in fields">
- <py:if test="field.name == 'keywords'">
- <div title="Keywords">
- <i class="icon-tags"></i>
- <span data-edit="${'inplace' if can_modify or can_edit or can_create else None}" id="vc-keywords">${field.rendered}</span>
- </div>
- </py:if>
- </py:for>
- <div class="description">
- <h5 id="comment:description">
- Description
- <span py:if="description_change" class="lastmod pull-right"
- title="$description_change.date">
- <i18n:msg params="author">(last modified by ${authorinfo(description_change.author)})</i18n:msg>
- (<a href="${href.ticket(ticket.id, action='diff', version=description_change.cnum)}">diff</a>)
- </span>
- </h5>
-
+ <div class="clearboth"></div>
+
+ <!--! use a placeholder if it's a new ticket -->
+ <py:for each="field in fields">
+ <py:if test="field.name == 'keywords'">
+ <div title="Keywords" class="keywords">
+ <i class="icon-tags"></i>
+ <span data-edit="${'inplace' if can_modify or can_edit or can_create else None}" id="vc-keywords">${field.rendered}</span>
+ </div>
+ </py:if>
+ </py:for>
+
+
+ <div class="description">
+ <h5 id="comment:description">
+ Description
+ <span py:if="description_change" class="lastmod pull-right"
+ title="$description_change.date">
+ <i18n:msg params="author">(last modified by ${authorinfo(description_change.author)})</i18n:msg>
+ (<a href="${href.ticket(ticket.id, action='diff', version=description_change.cnum)}">diff</a>)
+ </span>
+ </h5>
+
<!--! Quote the description (only for existing tickets) -->
<div class="pull-right">
<form py:if="ticket.exists and ticket.description and can_append"
@@ -110,17 +119,16 @@ Arguments:
<py:if test="ticket.description">
${wiki_to_html(context, ticket.description, escape_newlines=preserve_newlines)}
</py:if>
- </div>
- <br py:if="not ticket.description" style="clear: both" />
</div>
+ <br py:if="not ticket.description" style="clear: both" />
</div>
- <div class="properties" style="margin-top: 1.2em">
- <py:for each="_fields, csscls, count, fontsize, is_inline in
- [(text_fields, 'span4', _colcount / 2, None, False),
- (area_fields, colspan, 1, None, False)]">
- <py:for each="fields_row in group(_fields, count)">
- ${render_fields_row(fields_row, csscls, fontsize, is_inline)}
- </py:for>
+
+ <div class="properties">
+ <py:for each="_fields, count in
+ [(text_fields, _colcount / 2), (area_fields, colspan, 1)]">
+ <div py:for="fields_row in group(_fields, count)" class="row">
+ ${render_fields_row(fields_row, None, False)}
+ </div>
</py:for>
</div>
</py:with>
Modified: incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bloodhound_theme.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bloodhound_theme.html?rev=1442158&r1=1442157&r2=1442158&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bloodhound_theme.html (original)
+++ incubator/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bloodhound_theme.html Mon Feb 4 16:01:36 2013
@@ -25,9 +25,9 @@
xmlns:py="http://genshi.edgewall.org/"
py:strip="">
- <link rel="stylesheet" href="${href.chrome('dashboard/css/bootstrap.css')}" type="text/css" />
-
<py:match path="head" once="true"><head>
+ <link rel="stylesheet" href="${href.chrome('dashboard/css/bootstrap.css')}" type="text/css" />
+ <link rel="stylesheet" href="${href.chrome('dashboard/css/bootstrap-responsive.css')}" type="text/css" />
<title py:with="title = list(select('title/text()'))" py:choose="">
<py:when test="title">${title}</py:when>
<py:otherwise>${project.name or 'Apache(TM) Bloodhound'}</py:otherwise>
@@ -51,21 +51,26 @@
type="text/javascript"></script>
<script src="${href.chrome('dashboard/js/bootstrap-affix.js')}"
type="text/javascript"></script>
+ <script src="${href.chrome('dashboard/js/bootstrap-button.js')}"
+ type="text/javascript"></script>
</head></py:match>
<py:match path="body" once="true" buffer="false"><body>
<div class="container">
+ <!--! header -->
<header>
- <div class="row" style="position:relative;">
- <div class="span4">
+ <div class="row">
+ <!--! logo -->
+ <div id="logo" class="span4">
<p>
<img src="${chrome.logo.src or href.chrome('theme/img/bh_logo.png')}"
alt="Bloodhound Logo" />
</p>
</div>
+ <!--! top menu (login, logout...) -->
<py:with vars="meta_items = dict([i.name, i] for i in chrome.nav.metanav)">
- <div class="span8">
+ <div id="usermenu" class="span8">
<div class="metanav pull-right">
<span id="nav_login" py:choose="">
<py:when test="req.authname and req.authname != 'anonymous'">
@@ -88,125 +93,139 @@
</div>
</py:with>
</div>
- <div class="row" style="position:relative;">
- <div class="span4">
- <form id="mainsearch" class="form-inline" action="${href.search()}" method="get">
- <input type="text" class="span3" id="q" name="q"
- placeholder="Search anything. Try #EF-492."
- value="${req.search_query}" />
- <input type="submit" value="Search" class="btn btn-warning"/>
- </form>
- </div>
- <div class="span2">
- <py:def function="field_select(field, value)">
- <select id="field-${field.name}" name="field_${field.name}"
- class="input-medium" data-empty="true" data-field="${field.name}">
- <option py:if="field.optional"></option>
- <option py:for="option in field.options"
- selected="${value == option or None}"
- value = "$option"
- py:content="option"></option>
- <optgroup py:for="optgroup in field.optgroups"
- py:if="optgroup.options"
- label="${optgroup.label}">
- <option py:for="option in optgroup.options"
- selected="${value == option or None}"
- value = "$option"
- py:content="option"></option>
- </optgroup>
- </select>
- </py:def>
- <py:def function="qct_box()">
- <div>
- <label for="field-summary">Summary</label>
- <input type="text" id="field-summary"
- name="field_summary" placeholder="Ticket summary" />
- </div>
- <div>
- <label for="field-description">Description</label>
- <textarea id="field-description" name="field_description"
- rows="3" cols="28"
- placeholder="Ticket description"></textarea>
- </div>
- <div class="form-horizontal">
- <py:for each="field in qct.fields">
- <label class="control-label" for="field-${field.name}">${field.label}</label>
- <div class="controls">
- ${field_select(field, None)}
+ <!--! search + main nav -->
+ <div class="row">
+ <!--! search box -->
+ <div class="span6">
+ <div id="searchbox" class="btn-toolbar">
+ <div class="btn-group">
+ <form id="mainsearch" class="form-inline" action="${href.search()}" method="get">
+ <div class="input-append">
+ <input type="text" class="span3" id="q" name="q"
+ placeholder="Search anything. Try #EF-492."
+ value="${req.search_query}" />
+ <button type="submit" class="btn btn-warning">
+ <span class="hidden-phone hidden-tablet">Search</span>
+ <i class="icon-search icon-white"></i>
+ </button>
</div>
- </py:for>
+ </form>
</div>
- </py:def>
- <py:choose test="">
- <py:when test="qct">
- <div class="btn-group">
- <a href="#" class="btn btn-primary dropdown-toggle"
- id="qct-newticket" data-animation="true" data-html="true"
- data-trigger="manual" data-toggle="dropdown">
- Create Ticket
- </a>
- <div id="qct-box" class="dropdown-menu" style="width: 300px;"
- py:choose="">
- <div class="popover-title">
- <h3>
- Create Ticket
- <a style="top: -33px; right: -25px; position: relative;"
- class="pull-right" href="${href.newticket()}">
- <small>Full dialogue »</small>
- </a>
- </h3>
+
+ <!--! create ticket button + dropdown -->
+ <div class="btn-group">
+ <py:def function="field_select(field, value)">
+ <select id="field-${field.name}" name="field_${field.name}"
+ class="input-medium" data-empty="true" data-field="${field.name}">
+ <option py:if="field.optional"></option>
+ <option py:for="option in field.options"
+ selected="${value == option or None}"
+ value = "$option"
+ py:content="option"></option>
+ <optgroup py:for="optgroup in field.optgroups"
+ py:if="optgroup.options"
+ label="${optgroup.label}">
+ <option py:for="option in optgroup.options"
+ selected="${value == option or None}"
+ value = "$option"
+ py:content="option"></option>
+ </optgroup>
+ </select>
+ </py:def>
+ <py:def function="qct_box()">
+ <div>
+ <label for="field-summary">Summary</label>
+ <input type="text" id="field-summary"
+ name="field_summary" placeholder="Ticket summary" />
+ </div>
+ <div>
+ <label for="field-description">Description</label>
+ <textarea id="field-description" name="field_description"
+ rows="3" cols="28"
+ placeholder="Ticket description"></textarea>
+ </div>
+ <div class="form-horizontal">
+ <py:for each="field in qct.fields">
+ <label class="control-label" for="field-${field.name}">${field.label}</label>
+ <div class="controls">
+ ${field_select(field, None)}
</div>
- <div class="popover-content">
- <py:when test="'TICKET_CREATE' in perm">
- <form id="qct-form" name="qct" method="post">
- <div id="qct-fieldset">
- ${qct_box()}
- </div>
- </form>
- <button id="qct-create" class="btn" data-target="${href()}">Create</button>
- <a id="qct-cancel">Cancel</a>
- </py:when>
- <div py:otherwise="" class="alert alert-info">
- <p>
- <span class="label label-important">TICKET_CREATE</span>
- privileges are required to perform this operation.
- You don't have the required permissions
- <py:choose>
- <py:when test="req.authname == 'anonymous'">
- <br/><br/>
- <a href="${href.login()}" class="btn" style="display: inline;">Login</a>
- </py:when>
- <py:otherwise>
- Please contact your administrator or team leader to
- request these.
- </py:otherwise>
- </py:choose>
- </p>
+ </py:for>
+ </div>
+ </py:def>
+ <py:choose test="">
+ <py:when test="qct">
+ <a href="#" class="btn btn-primary dropdown-toggle"
+ id="qct-newticket" data-animation="true" data-html="true"
+ data-trigger="manual" data-toggle="dropdown">
+ <span class="visible-phone"><i class="icon-plus-sign icon-white"></i></span>
+ <span class="hidden-phone">Create Ticket</span>
+ </a>
+ <div id="qct-box" class="dropdown-menu" style="width: 300px;"
+ py:choose="">
+ <div class="popover-title">
+ <h3>
+ Create Ticket
+ <a style="top: -33px; right: -25px; position: relative;"
+ class="pull-right" href="${href.newticket()}">
+ <small>Full dialogue »</small>
+ </a>
+ </h3>
+ </div>
+ <div class="popover-content">
+ <py:when test="'TICKET_CREATE' in perm">
+ <form id="qct-form" name="qct" method="post">
+ <div id="qct-fieldset">
+ ${qct_box()}
+ </div>
+ </form>
+ <button id="qct-create" class="btn" data-target="${href()}">Create</button>
+ <a id="qct-cancel">Cancel</a>
+ </py:when>
+ <div py:otherwise="" class="alert alert-info">
+ <p>
+ <span class="label label-important">TICKET_CREATE</span>
+ privileges are required to perform this operation.
+ You don't have the required permissions
+ <py:choose>
+ <py:when test="req.authname == 'anonymous'">
+ <br/><br/>
+ <a href="${href.login()}" class="btn" style="display: inline;">Login</a>
+ </py:when>
+ <py:otherwise>
+ Please contact your administrator or team leader to
+ request these.
+ </py:otherwise>
+ </py:choose>
+ </p>
+ </div>
</div>
</div>
- </div>
- </div>
- </py:when>
- <py:otherwise>
-
- </py:otherwise>
- </py:choose>
+ </py:when>
+ <py:otherwise>
+
+ </py:otherwise>
+ </py:choose>
+ </div>
+ </div>
</div>
+
+
+ <!--! main navigation tabs -->
<div class="span6">
<ul py:if="chrome.nav.mainnav or chrome.nav.metanav"
- class="nav nav-tabs pull-right"
+ class="nav nav-tabs pull-right hidden-phone"
id="mainnav"
py:with="mainnav_show = ('wiki', 'tickets', 'browser');
metanav_hide = ('login', 'logout', 'prefs', 'help', 'about')">
- <!-- TODO: Parameterize visible mainnav items in trac.ini -->
+ <!--! TODO: Parameterize visible mainnav items in trac.ini -->
<li py:if="chrome.nav.mainnav"
py:for="idx, item in enumerate(i for i in chrome.nav.mainnav if i.name in mainnav_show)"
class="${classes(first_last(idx, chrome.nav.mainnav), active=item.active)}">${item.label}</li>
<li class="dropdown ${all(not i.active for i in chrome.nav.mainnav if i.name in mainnav_show) and 'active' or None}"
py:if="len([i for i in chrome.nav.metanav if i.name not in metanav_hide] +
[i for i in chrome.nav.mainnav if i.name not in mainnav_show])">
- <a class="dropdown-toggle" data-toggle="dropdown" href="#">Apps
- <b class="caret"></b></a>
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#">Apps<b class="caret"></b></a>
<ul class="dropdown-menu">
<li py:if="chrome.nav.mainnav"
py:for="idx, item in enumerate(i for i in chrome.nav.mainnav if i.name not in mainnav_show)"
@@ -224,14 +243,16 @@
</li>
</ul>
</div>
- <div class="span12">
+
+ <!--! breadcrumb (TODO: which ones do we hide on the phones/tablets?) -->
+ <div id="breadcrumbbar" class="span12">
<ul class="breadcrumb">
<li py:choose="">
<xi:include py:when="value_of('resourcepath_template')"
href="${resourcepath_template}" />
<py:otherwise> </py:otherwise>
</li>
- <li class="pull-right">
+ <li class="pull-right hidden-phone">
<py:for py:if="chrome.ctxtnav"
py:with="max_idx = len(chrome.ctxtnav) - 1"
each="idx, item in enumerate(chrome.ctxtnav)">
@@ -241,8 +262,9 @@
</li>
</ul>
</div>
- <div style="text-align: right;" class="span3"></div>
</div>
+
+ <!--! alerts (warnings, notices) -->
<div class="row">
<!-- div id="alert-log" class="dropdown-menu" style="display: none">
<div class="popover-title">
@@ -275,7 +297,13 @@
</div>
</div>
</header>
+
+ <!--! main content -->
${select('*|text()|comment()')}
+ </div>
+
+ <!--! footer -->
+ <div class="container">
<div class="row footer">
<div class="span8">
${chrome.labels.footer_left_prefix}
@@ -291,7 +319,6 @@
</div>
</div>
</div>
- <br/>
</body></py:match>
<xi:include href="bh_admin.html" py:with="bh_fix_legacy = True" />
Modified: incubator/bloodhound/trunk/bloodhound_theme/bhtheme/theme.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_theme/bhtheme/theme.py?rev=1442158&r1=1442157&r2=1442158&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_theme/bhtheme/theme.py (original)
+++ incubator/bloodhound/trunk/bloodhound_theme/bhtheme/theme.py Mon Feb 4 16:01:36 2013
@@ -21,6 +21,7 @@ import sys
from genshi.builder import tag
from genshi.core import TEXT
from genshi.filters.transform import Transformer
+from genshi.output import DocType
from trac.config import Option
from trac.core import *
@@ -36,7 +37,7 @@ from trac.util.translation import _
from trac.versioncontrol.web_ui.browser import BrowserModule
from trac.web.api import IRequestFilter, IRequestHandler, ITemplateStreamFilter
from trac.web.chrome import (add_script, add_stylesheet, INavigationContributor,
- ITemplateProvider, prevnext_nav)
+ ITemplateProvider, prevnext_nav, Chrome)
from trac.wiki.admin import WikiAdmin
from themeengine.api import ThemeBase, ThemeEngineSystem
@@ -135,6 +136,7 @@ class BloodhoundTheme(ThemeBase):
labels_footer_right = Option('labels', 'footer_right', '')
_wiki_pages = None
+ Chrome.default_html_doctype = DocType.HTML5
implements(IRequestFilter, INavigationContributor, ITemplateProvider,
ITemplateStreamFilter)
@@ -255,6 +257,11 @@ class BloodhoundTheme(ThemeBase):
if modifier is not None:
modifier = getattr(self, modifier)
modifier(req, template, data, content_type, is_active_theme)
+
+ if is_active_theme:
+ data['responsive_layout'] = self.env.config.getbool(
+ 'bloodhound', 'responsive_layout', 'true')
+
return template, data, content_type
# ITemplateProvider methods
Modified: incubator/bloodhound/trunk/trac/trac/web/chrome.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/web/chrome.py?rev=1442158&r1=1442157&r2=1442158&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/web/chrome.py (original)
+++ incubator/bloodhound/trunk/trac/trac/web/chrome.py Mon Feb 4 16:01:36 2013
@@ -479,6 +479,9 @@ class Chrome(Component):
templates = None
+ # default doctype for 'text/html' output
+ default_html_doctype = DocType.XHTML_STRICT
+
# A dictionary of default context data for templates
_default_context_data = {
'_': translation.gettext,
@@ -936,8 +939,8 @@ class Chrome(Component):
The `content_type` argument is used to choose the kind of template
used (`NewTextTemplate` if `'text/plain'`, `MarkupTemplate` otherwise),
- and tweak the rendering process (use of XHTML Strict doctype if
- `'text/html'` is given).
+ and tweak the rendering process. Doctype for `'text/html'` can be
+ specified by setting the default_html_doctype (default is XHTML Strict)
When `fragment` is specified, the (filtered) Genshi stream is
returned.
@@ -975,7 +978,7 @@ class Chrome(Component):
stream.render('text', out=buffer, encoding='utf-8')
return buffer.getvalue()
- doctype = {'text/html': DocType.XHTML_STRICT}.get(content_type)
+ doctype = {'text/html': Chrome.default_html_doctype}.get(content_type)
if doctype:
if req.form_token:
stream |= self._add_form_token(req.form_token)