adds issue detail view - fixes #24

Fri, 23 Oct 2020 13:29:33 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 23 Oct 2020 13:29:33 +0200
changeset 146
b0e83cab0bde
parent 145
6d2d69fd1c12
child 147
dfec8c5f8db0

adds issue detail view - fixes #24

src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/viewmodel/IssueDetailView.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/viewmodel/IssueEditView.java file | annotate | diff | comparison | revisions
src/main/resources/localization/projects.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/projects_de.properties file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/jsp/issue-form.jsp file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/jsp/issue-view.jsp file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/jspf/issue-list.jspf file | annotate | diff | comparison | revisions
src/main/webapp/lightpit.css file | annotate | diff | comparison | revisions
     1.1 --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java	Fri Oct 23 12:38:20 2020 +0200
     1.2 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java	Fri Oct 23 13:29:33 2020 +0200
     1.3 @@ -422,16 +422,39 @@
     1.4  
     1.5      private void configureIssueEditor(IssueEditView viewModel, Issue issue, DataAccessObjects dao) throws SQLException {
     1.6          final var project = viewModel.getProjectInfo().getProject();
     1.7 -        issue.setProject(project);
     1.8 +        issue.setProject(project); // automatically set current project for new issues
     1.9          viewModel.setIssue(issue);
    1.10          viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions());
    1.11          viewModel.setUsers(dao.getUserDao().list());
    1.12          viewModel.setComponents(dao.getComponentDao().list(project));
    1.13 -        if (issue.getId() >= 0) {
    1.14 -            viewModel.setComments(dao.getIssueDao().listComments(issue));
    1.15 -        }
    1.16      }
    1.17  
    1.18 +    @RequestMapping(requestPath = "$project/issues/$issue/view", method = HttpMethod.GET)
    1.19 +    public ResponseType viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException {
    1.20 +        final var viewModel = new IssueDetailView();
    1.21 +        populate(viewModel, pathParameters, dao);
    1.22 +
    1.23 +        final var projectInfo = viewModel.getProjectInfo();
    1.24 +        if (projectInfo == null) {
    1.25 +            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
    1.26 +            return ResponseType.NONE;
    1.27 +        }
    1.28 +
    1.29 +        final var issueDao = dao.getIssueDao();
    1.30 +        final var issue = issueDao.find(Functions.parseIntOrZero(pathParameters.get("issue")));
    1.31 +        if (issue == null) {
    1.32 +            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
    1.33 +            return ResponseType.NONE;
    1.34 +        }
    1.35 +
    1.36 +        issueDao.joinVersionInformation(issue);
    1.37 +        viewModel.setIssue(issue);
    1.38 +        viewModel.setComments(issueDao.listComments(issue));
    1.39 +
    1.40 +        return forwardView(req, viewModel, "issue-view");
    1.41 +    }
    1.42 +
    1.43 +    // TODO: why should the issue editor be child of $project?
    1.44      @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET)
    1.45      public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException {
    1.46          final var viewModel = new IssueEditView();
    1.47 @@ -522,8 +545,8 @@
    1.48  
    1.49              dao.getIssueDao().saveOrUpdate(issue, issue.getProject());
    1.50  
    1.51 -            // TODO: fix issue #14
    1.52 -            setRedirectLocation(req, "./projects/" + issue.getProject().getNode() + "/all-components/all-versions/issues/");
    1.53 +            // TODO: fix redirect location
    1.54 +            setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
    1.55              setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
    1.56  
    1.57              return ResponseType.HTML;
    1.58 @@ -561,8 +584,8 @@
    1.59  
    1.60              dao.getIssueDao().saveComment(issueComment);
    1.61  
    1.62 -            // TODO: fix redirect location (e.g. after fixing #24)
    1.63 -            setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/edit");
    1.64 +            // TODO: fix redirect location
    1.65 +            setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
    1.66              setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
    1.67  
    1.68              return ResponseType.HTML;
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/IssueDetailView.java	Fri Oct 23 13:29:33 2020 +0200
     2.3 @@ -0,0 +1,28 @@
     2.4 +package de.uapcore.lightpit.viewmodel;
     2.5 +
     2.6 +import de.uapcore.lightpit.entities.Issue;
     2.7 +import de.uapcore.lightpit.entities.IssueComment;
     2.8 +
     2.9 +import java.util.List;
    2.10 +
    2.11 +public class IssueDetailView extends ProjectView {
    2.12 +    private Issue issue;
    2.13 +
    2.14 +    private List<IssueComment> comments;
    2.15 +
    2.16 +    public void setIssue(Issue issue) {
    2.17 +        this.issue = issue;
    2.18 +    }
    2.19 +
    2.20 +    public Issue getIssue() {
    2.21 +        return issue;
    2.22 +    }
    2.23 +
    2.24 +    public List<IssueComment> getComments() {
    2.25 +        return comments;
    2.26 +    }
    2.27 +
    2.28 +    public void setComments(List<IssueComment> comments) {
    2.29 +        this.comments = comments;
    2.30 +    }
    2.31 +}
     3.1 --- a/src/main/java/de/uapcore/lightpit/viewmodel/IssueEditView.java	Fri Oct 23 12:38:20 2020 +0200
     3.2 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/IssueEditView.java	Fri Oct 23 13:29:33 2020 +0200
     3.3 @@ -4,23 +4,12 @@
     3.4  
     3.5  import java.util.*;
     3.6  
     3.7 -public class IssueEditView extends ProjectView {
     3.8 -    private Issue issue;
     3.9 -
    3.10 +public class IssueEditView extends IssueDetailView {
    3.11      private List<Project> projects = Collections.emptyList();
    3.12      private Set<Version> versionsUpcoming = new HashSet<>();
    3.13      private Set<Version> versionsRecent = new HashSet<>();
    3.14      private List<User> users;
    3.15      private List<Component> components;
    3.16 -    private List<IssueComment> comments;
    3.17 -
    3.18 -    public void setIssue(Issue issue) {
    3.19 -        this.issue = issue;
    3.20 -    }
    3.21 -
    3.22 -    public Issue getIssue() {
    3.23 -        return issue;
    3.24 -    }
    3.25  
    3.26      public List<Project> getProjects() {
    3.27          return projects;
    3.28 @@ -42,8 +31,8 @@
    3.29          versionsRecent.clear();
    3.30          versionsUpcoming.clear();
    3.31          // keep the current selection, if any
    3.32 -        versionsRecent.addAll(issue.getAffectedVersions());
    3.33 -        versionsUpcoming.addAll(issue.getResolvedVersions());
    3.34 +        versionsRecent.addAll(getIssue().getAffectedVersions());
    3.35 +        versionsUpcoming.addAll(getIssue().getResolvedVersions());
    3.36          for (var v : versions) {
    3.37              if (v.getStatus().isReleased()) {
    3.38                  if (!v.getStatus().equals(VersionStatus.Deprecated))
    3.39 @@ -77,12 +66,4 @@
    3.40      public IssueCategory[] getIssueCategory() {
    3.41          return IssueCategory.values();
    3.42      }
    3.43 -
    3.44 -    public List<IssueComment> getComments() {
    3.45 -        return comments;
    3.46 -    }
    3.47 -
    3.48 -    public void setComments(List<IssueComment> comments) {
    3.49 -        this.comments = comments;
    3.50 -    }
    3.51  }
     4.1 --- a/src/main/resources/localization/projects.properties	Fri Oct 23 12:38:20 2020 +0200
     4.2 +++ b/src/main/resources/localization/projects.properties	Fri Oct 23 13:29:33 2020 +0200
     4.3 @@ -29,6 +29,7 @@
     4.4  button.version.create=New Version
     4.5  button.version.edit=Edit Version
     4.6  button.issue.create=New Issue
     4.7 +button.issue.edit=Edit Issue
     4.8  button.issue.all=All Issues
     4.9  button.comment=Comment
    4.10  
     5.1 --- a/src/main/resources/localization/projects_de.properties	Fri Oct 23 12:38:20 2020 +0200
     5.2 +++ b/src/main/resources/localization/projects_de.properties	Fri Oct 23 13:29:33 2020 +0200
     5.3 @@ -29,6 +29,7 @@
     5.4  button.version.create=Neue Version
     5.5  button.version.edit=Version Bearbeiten
     5.6  button.issue.create=Neuer Vorgang
     5.7 +button.issue.edit=Vorgang Bearbeiten
     5.8  button.issue.all=Alle Vorg\u00e4nge
     5.9  button.comment=Kommentieren
    5.10  
     6.1 --- a/src/main/webapp/WEB-INF/jsp/issue-form.jsp	Fri Oct 23 12:38:20 2020 +0200
     6.2 +++ b/src/main/webapp/WEB-INF/jsp/issue-form.jsp	Fri Oct 23 13:29:33 2020 +0200
     6.3 @@ -169,56 +169,20 @@
     6.4          <tr>
     6.5              <td colspan="2">
     6.6                  <input type="hidden" name="id" value="${issue.id}"/>
     6.7 -                <%-- TODO: fix #14 --%>
     6.8 -                <a href="./projects/${issue.project.node}/all-components/all-versions/issues/" class="button">
     6.9 +                <c:if test="${issue.id ge 0}">
    6.10 +                <a href="./projects/${issue.project.node}/issues/${issue.id}/view" class="button">
    6.11                      <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/>
    6.12                  </a>
    6.13 +                </c:if>
    6.14 +                <c:if test="${issue.id lt 0}">
    6.15 +                    <%-- TODO: fix #14 --%>
    6.16 +                    <a href="./projects/${issue.project.node}/all-components/all-versions/issues/" class="button">
    6.17 +                        <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/>
    6.18 +                    </a>
    6.19 +                </c:if>
    6.20                  <button type="submit"><fmt:message bundle="${lightpit_bundle}" key="button.okay"/></button>
    6.21              </td>
    6.22          </tr>
    6.23          </tfoot>
    6.24      </table>
    6.25  </form>
    6.26 -<hr class="comments-separator"/>
    6.27 -<h2><fmt:message key="issue.comments"/></h2>
    6.28 -<c:if test="${viewmodel.issue.id ge 0}">
    6.29 -<form id="comment-form" action="./projects/commit-issue-comment" method="post">
    6.30 -    <table class="formtable fullwidth">
    6.31 -        <tbody>
    6.32 -            <tr>
    6.33 -                <td><textarea rows="5" name="comment" required></textarea></td>
    6.34 -            </tr>
    6.35 -        </tbody>
    6.36 -        <tfoot>
    6.37 -            <tr>
    6.38 -                <td>
    6.39 -                    <input type="hidden" name="issueid" value="${issue.id}"/>
    6.40 -                    <button type="submit"><fmt:message key="button.comment"/></button>
    6.41 -                </td>
    6.42 -            </tr>
    6.43 -        </tfoot>
    6.44 -    </table>
    6.45 -</form>
    6.46 -    <c:forEach var="comment" items="${viewmodel.comments}">
    6.47 -        <div class="comment">
    6.48 -            <div class="caption">
    6.49 -                <c:if test="${not empty comment.author}">
    6.50 -                    <c:out value="${comment.author.displayname}"/>
    6.51 -                </c:if>
    6.52 -                <c:if test="${empty comment.author}">
    6.53 -                    <fmt:message key="issue.comments.anonauthor"/>
    6.54 -                </c:if>
    6.55 -            </div>
    6.56 -            <div class="smalltext">
    6.57 -                <fmt:formatDate type="BOTH" value="${comment.created}" />
    6.58 -                <c:if test="${comment.updateCount gt 0}">
    6.59 -                    <!-- TODO: update count -->
    6.60 -                </c:if>
    6.61 -            </div>
    6.62 -            <div class="medskip">
    6.63 -                <c:out value="${comment.comment}"/>
    6.64 -            </div>
    6.65 -        </div>
    6.66 -    </c:forEach>
    6.67 -</c:if>
    6.68 -
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/main/webapp/WEB-INF/jsp/issue-view.jsp	Fri Oct 23 13:29:33 2020 +0200
     7.3 @@ -0,0 +1,186 @@
     7.4 +<%--
     7.5 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     7.6 +
     7.7 +Copyright 2018 Mike Becker. All rights reserved.
     7.8 +
     7.9 +Redistribution and use in source and binary forms, with or without
    7.10 +modification, are permitted provided that the following conditions are met:
    7.11 +
    7.12 +1. Redistributions of source code must retain the above copyright
    7.13 +notice, this list of conditions and the following disclaimer.
    7.14 +
    7.15 +2. Redistributions in binary form must reproduce the above copyright
    7.16 +notice, this list of conditions and the following disclaimer in the
    7.17 +documentation and/or other materials provided with the distribution.
    7.18 +
    7.19 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    7.20 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    7.21 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    7.22 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    7.23 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    7.24 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    7.25 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    7.26 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    7.27 +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    7.28 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    7.29 +--%>
    7.30 +<%@page pageEncoding="UTF-8" %>
    7.31 +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    7.32 +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    7.33 +
    7.34 +<jsp:useBean id="viewmodel" type="de.uapcore.lightpit.viewmodel.IssueDetailView" scope="request"/>
    7.35 +<c:set var="issue" scope="page" value="${viewmodel.issue}" />
    7.36 +
    7.37 +<table class="formtable fullwidth">
    7.38 +    <colgroup>
    7.39 +        <col>
    7.40 +        <col style="width: 100%">
    7.41 +    </colgroup>
    7.42 +    <tbody>
    7.43 +    <c:if test="${viewmodel.issue.id ge 0}">
    7.44 +    <tr>
    7.45 +        <th><fmt:message key="issue.id"/></th>
    7.46 +        <td>${issue.id}</td>
    7.47 +    </tr>
    7.48 +    </c:if>
    7.49 +    <tr>
    7.50 +        <th><fmt:message key="issue.project"/></th>
    7.51 +        <td>
    7.52 +            <c:out value="${issue.project.name}" />
    7.53 +        </td>
    7.54 +    </tr>
    7.55 +    <tr>
    7.56 +        <th><fmt:message key="issue.created"/></th>
    7.57 +        <td><fmt:formatDate value="${issue.created}" /></td>
    7.58 +    </tr>
    7.59 +    <tr>
    7.60 +        <th><fmt:message key="issue.updated"/></th>
    7.61 +        <td><fmt:formatDate value="${issue.updated}" /></td>
    7.62 +    </tr>
    7.63 +    <tr>
    7.64 +        <th><fmt:message key="issue.component"/></th>
    7.65 +        <td>
    7.66 +            <c:if test="${not empty issue.component}">
    7.67 +                <c:out value="${issue.component.name}"/>
    7.68 +            </c:if>
    7.69 +            <c:if test="${empty issue.component}">
    7.70 +                <fmt:message key="placeholder.null-component"/>
    7.71 +            </c:if>
    7.72 +        </td>
    7.73 +    </tr>
    7.74 +    <tr>
    7.75 +        <th><fmt:message key="issue.category"/></th>
    7.76 +        <td>
    7.77 +            <div class="issue-tag ${issue.category}" style="width: auto">
    7.78 +                <fmt:message key="issue.category.${issue.category}" />
    7.79 +            </div>
    7.80 +        </td>
    7.81 +    </tr>
    7.82 +    <tr>
    7.83 +        <th><fmt:message key="issue.status"/></th>
    7.84 +        <td>
    7.85 +            <div class="issue-tag phase-${issue.status.phase}" style="width: auto">
    7.86 +                <fmt:message key="issue.status.${issue.status}" />
    7.87 +            </div>
    7.88 +        </td>
    7.89 +    </tr>
    7.90 +    <tr>
    7.91 +        <th><fmt:message key="issue.subject"/></th>
    7.92 +        <td><c:out value="${issue.subject}"/></td>
    7.93 +    </tr>
    7.94 +    <tr>
    7.95 +        <th class="vtop"><fmt:message key="issue.description"/></th>
    7.96 +        <td>
    7.97 +            <textarea readonly rows="10"><c:out value="${issue.description}"/></textarea>
    7.98 +        </td>
    7.99 +    </tr>
   7.100 +    <tr>
   7.101 +        <th><fmt:message key="issue.assignee"/></th>
   7.102 +        <td>
   7.103 +            <c:if test="${not empty issue.assignee}">
   7.104 +                <c:out value="${issue.assignee.displayname}"/>
   7.105 +            </c:if>
   7.106 +            <c:if test="${empty issue.assignee}">
   7.107 +                <fmt:message key="placeholder.null-assignee" />
   7.108 +            </c:if>
   7.109 +        </td>
   7.110 +    </tr>
   7.111 +    <tr>
   7.112 +        <th class="vtop"><fmt:message key="issue.affected-versions"/></th>
   7.113 +        <td>
   7.114 +            <c:forEach var="version" items="${issue.affectedVersions}">
   7.115 +                <c:out value="${version.name}"/>
   7.116 +            </c:forEach>
   7.117 +        </td>
   7.118 +    </tr>
   7.119 +    <tr>
   7.120 +        <th class="vtop"><fmt:message key="issue.resolved-versions"/></th>
   7.121 +        <td>
   7.122 +            <c:forEach var="version" items="${issue.resolvedVersions}">
   7.123 +                <c:out value="${version.name}"/>
   7.124 +            </c:forEach>
   7.125 +        </td>
   7.126 +    </tr>
   7.127 +    <tr>
   7.128 +        <th><fmt:message key="issue.eta"/></th>
   7.129 +        <td><fmt:formatDate value="${issue.eta}" /></td>
   7.130 +    </tr>
   7.131 +    </tbody>
   7.132 +    <tfoot>
   7.133 +    <tr>
   7.134 +        <td colspan="2">
   7.135 +            <%-- TODO: fix #14 --%>
   7.136 +            <a href="./projects/${issue.project.node}/all-components/all-versions/issues/" class="button">
   7.137 +                <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/>
   7.138 +            </a>
   7.139 +            <a href="./projects/${issue.project.node}/issues/${issue.id}/edit" class="button submit">
   7.140 +                <fmt:message key="button.issue.edit"/>
   7.141 +            </a>
   7.142 +        </td>
   7.143 +    </tr>
   7.144 +    </tfoot>
   7.145 +</table>
   7.146 +
   7.147 +<hr class="comments-separator"/>
   7.148 +<h2><fmt:message key="issue.comments"/></h2>
   7.149 +<c:if test="${viewmodel.issue.id ge 0}">
   7.150 +<form id="comment-form" action="./projects/commit-issue-comment" method="post">
   7.151 +    <table class="formtable fullwidth">
   7.152 +        <tbody>
   7.153 +            <tr>
   7.154 +                <td><textarea rows="5" name="comment" required></textarea></td>
   7.155 +            </tr>
   7.156 +        </tbody>
   7.157 +        <tfoot>
   7.158 +            <tr>
   7.159 +                <td>
   7.160 +                    <input type="hidden" name="issueid" value="${issue.id}"/>
   7.161 +                    <button type="submit"><fmt:message key="button.comment"/></button>
   7.162 +                </td>
   7.163 +            </tr>
   7.164 +        </tfoot>
   7.165 +    </table>
   7.166 +</form>
   7.167 +    <c:forEach var="comment" items="${viewmodel.comments}">
   7.168 +        <div class="comment">
   7.169 +            <div class="caption">
   7.170 +                <c:if test="${not empty comment.author}">
   7.171 +                    <c:out value="${comment.author.displayname}"/>
   7.172 +                </c:if>
   7.173 +                <c:if test="${empty comment.author}">
   7.174 +                    <fmt:message key="issue.comments.anonauthor"/>
   7.175 +                </c:if>
   7.176 +            </div>
   7.177 +            <div class="smalltext">
   7.178 +                <fmt:formatDate type="BOTH" value="${comment.created}" />
   7.179 +                <c:if test="${comment.updateCount gt 0}">
   7.180 +                    <!-- TODO: update count -->
   7.181 +                </c:if>
   7.182 +            </div>
   7.183 +            <div class="medskip">
   7.184 +                <c:out value="${comment.comment}"/>
   7.185 +            </div>
   7.186 +        </div>
   7.187 +    </c:forEach>
   7.188 +</c:if>
   7.189 +
     8.1 --- a/src/main/webapp/WEB-INF/jspf/issue-list.jspf	Fri Oct 23 12:38:20 2020 +0200
     8.2 +++ b/src/main/webapp/WEB-INF/jspf/issue-list.jspf	Fri Oct 23 13:29:33 2020 +0200
     8.3 @@ -17,7 +17,7 @@
     8.4          <tr>
     8.5              <td>
     8.6                  <span class="phase-${issue.status.phase}">
     8.7 -                    <a href="./projects/${issue.project.node}/issues/${issue.id}/edit">
     8.8 +                    <a href="./projects/${issue.project.node}/issues/${issue.id}/view">
     8.9                          #${issue.id}&nbsp;-&nbsp;<c:out value="${issue.subject}" />
    8.10                      </a>
    8.11                  </span>
     9.1 --- a/src/main/webapp/lightpit.css	Fri Oct 23 12:38:20 2020 +0200
     9.2 +++ b/src/main/webapp/lightpit.css	Fri Oct 23 13:29:33 2020 +0200
     9.3 @@ -145,12 +145,12 @@
     9.4      background: #f0f0ff;
     9.5  }
     9.6  
     9.7 -button[type=submit] {
     9.8 +button[type=submit], a.button.submit {
     9.9      background: #20a0ff;
    9.10      color: white;
    9.11  }
    9.12  
    9.13 -button[type=submit]:hover {
    9.14 +button[type=submit]:hover, a.button.submit:hover {
    9.15      background: #1090cf;
    9.16  }
    9.17  

mercurial