[Notice] Announcing the End of Demo Server [Read me]
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
2014-05-22
File name
Commit message
Commit date
2014-07-28
2014-07-28
@**
* Yobi, Project Hosting SW
*
* Copyright 2012 NAVER Corp.
* http://yobi.io
*
* @Author Ahn Hyeok Jun
*
* Licensed 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.
**@
@(title:String, issue:Issue, issueForm:Form[Issue], commentForm:Form[Comment],project:Project)
@import org.apache.commons.lang.StringUtils
@import helper._
@import scala.collection.mutable.Map
@import models.enumeration.ResourceType
@import models.enumeration.Operation
@import models.Milestone
@import java.net._
@import java.text.SimpleDateFormat
@import java.security.MessageDigest
@import utils.JodaDateUtil
@import utils.TemplateHelper._
@import utils.AccessControl._
@import utils.Config
@getTitle(issue:Issue) = @{ "#" + issue.getNumber + " " + issue.title }
@isFirstState(state:State) = {@if(issue.state.state == Issue.availableStates.get(0).state()){dirty}}
@urlToIssues = @{ urlToList(request.getHeader("Referer"), routes.IssueApp.issues(project.owner, project.name, "open").toString()) }
@urlToVote = @{
if(issue.isVotedBy(UserApp.currentUser)){
routes.VoteApp.unvote(project.owner, project.name, issue.getNumber).toString
} else {
routes.VoteApp.vote(project.owner, project.name, issue.getNumber).toString
}
}
@getVoteButtonTitle = {
@if(issue.isVotedBy(UserApp.currentUser)){
@Messages("issue.unvote.description")
} else {
@Messages("issue.vote.description")
}
}
@projectLayout(getTitle(issue), project, utils.MenuType.ISSUE){
@projectMenu(project, utils.MenuType.ISSUE, "main-menu-only")
<div class="page-wrap-outer">
<div class="project-page-wrap board-view">
@** Post Info **@
<div class="board-header issue">
<div class="pull-right mr10 mt10">
<div class="date" title="@JodaDateUtil.getDateString(issue.createdDate)">
@agoOrDateString(issue.createdDate)
</div>
<span class="badge badge-issue-@issue.state.state.toLowerCase">@Messages("issue.state." + issue.state.state)</span>
</div>
<div class="title">
<strong class="board-id">#@issue.getNumber</strong> @issue.title
</div>
</div>
@** Content body **@
<!--board-body-->
<div class="board-body row-fluid">
<div class="span9">
@if(StringUtils.isEmpty(issue.body)){
<div class="content empty-content"></div>
} else {
<div class="markdown-loader">
<i class=" yobicon-loading2"></i> Loading....
</div>
<div class="content markdown-wrap markdown-before" markdown="true">@issue.body</div>
}
<div class="attachments" id="attachments" data-resource-type="@ResourceType.ISSUE_POST" data-resource-id="@issue.id"></div>
</div>
<div class="span3 mb20">
<div class="author-info pull-right mr10">
<form id="issueUpdateForm" action="@routes.IssueApp.massUpdate(project.owner, project.name)" method="post" class="frm-wrap">
<input type="hidden" name="issues[0].id" value="@issue.id" />
@**<!-- author -->**@
<dl class="author">
<dt>@Messages("issue.author")</dt>
<dd style="padding:5px 10px;">
<a href="@routes.UserApp.userInfo(issue.authorLoginId)" class="usf-group">
<span class="avatar-wrap smaller">
<img src="@User.findByLoginId(issue.authorLoginId).avatarUrl" width="20" height="20">
</span>
@if(issue.authorLoginId != null){
<strong class="name">@issue.authorName</strong>
<span class="loginid"> <strong>@{"@"}</strong>@issue.authorLoginId</span>
} else {
<strong class="name">@Messages("issue.noAuthor")</strong>
}
</a>
</dd>
</dl>
@**<!-- // -->**@
@**<!-- state -->**@
<!--
<dl>
<dt>@Messages("issue.state")</dt>
<dd>
<div id="state" class="btn-group" data-name="state">
<button class="btn dropdown-toggle large" data-toggle="dropdown">
<span class="d-label">@Messages("issue.state")</span>
<span class="d-caret"><span class="caret"></span></span>
</button>
<ul class="dropdown-menu">
<li data-value="@State.OPEN.name" @if(issue.state == State.OPEN){data-selected="true" class="active"}><a>@Messages("issue.state.open")</a></li>
<li data-value="@State.CLOSED.name" @if(issue.state == State.CLOSED){data-selected="true" class="active"}><a>@Messages("issue.state.closed")</a></li>
</ul>
</div>
</dd>
</dl>
-->
@**<!-- assignee -->**@
<dl>
<dt>@Messages("issue.assignee")</dt>
<dd style="padding:5px 10px;">
@defining(issue.assigneeName != null) { isAssigned =>
@if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) {
@partial_assignee(project, issue)
} else {
@if(isAssigned){
<a href="@routes.UserApp.userInfo(issue.assignee.user.loginId)" class="usf-group">
<span class="avatar-wrap smaller">
<img src="@User.findByLoginId(issue.assignee.user.loginId).avatarUrl" width="20" height="20">
</span>
<strong class="name">@issue.assigneeName</strong>
<span class="loginid"> <strong>@{"@"}</strong>@issue.assignee.user.loginId</span>
</a>
} else {
<div>
@Messages("issue.noAssignee")
</div>
}
}
}
</dd>
</dl>
@**<!-- // -->**@
@**<!-- milestones -->**@
@if(project.menuSetting.milestone) {
<dl>
<dt>@Messages("milestone")</dt>
<dd style="padding:5px 10px;">
@if(Milestone.findByProjectId(project.id).isEmpty()){
<a href="@routes.MilestoneApp.newMilestoneForm(project.owner, project.name)" target="_blank" class="ybtn ybtn-success ybtn-small">@Messages("milestone.menu.new")</a>
} else {
@defining(issue.milestone != null) { hasMilestone =>
@if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) {
<select id="milestone" name="milestone.id" data-toggle="select2" data-format="milestone">
<option value="@Milestone.NULL_MILESTONE_ID" @if(!hasMilestone){ selected }>
@Messages("issue.noMilestone")
</option>
<optgroup label="@Messages("milestone.state.open")">
@for(milestone <- Milestone.findOpenMilestones(project.id)){
<option value="@milestone.id" data-state="@milestone.state"
@if(hasMilestone && issue.milestone.id == milestone.id){
selected
}>
@milestone.title
</option>
}
</optgroup>
<optgroup label="@Messages("milestone.state.closed")">
@for(milestone <- Milestone.findClosedMilestones(project.id)){
<option value="@milestone.id" data-state="@milestone.state"
@if(hasMilestone && issue.milestone.id == milestone.id){
selected
}>
@milestone.title
</option>
}
</optgroup>
</select>
} else {
@if(hasMilestone){
<a href="@routes.MilestoneApp.milestone(project.owner, project.name, issue.milestone.id)">
@issue.milestone.title
</a>
} else {
@Messages("issue.noMilestone")
}
}
}
}
</dd>
</dl>
}
@**<!-- // -->**@
@**<!-- labels -->**@
@if(!IssueLabel.findByProject(project).isEmpty){
<dl class="labels-wrap">
<dt>
@Messages("label")
<button type="button" class="ybtn ybtn-mini edit-button" style="margin-left:10px;"><i class="yobicon-edit vmiddle"></i></button>
</dt>
<dd>
<dd style="padding:5px 10px; line-height:30px; @if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)){padding-left:0;}">
@if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) {
<select id="issueLabels" multiple="multiple" data-toggle="select2" data-format="issuelabel"
data-dropdown-css-class="issue-labels" data-container-css-class="issue-labels">
<option></option>
@IssueLabel.findByProject(project).groupBy(_.category).map {
case (category, labels) => {
<optgroup label="@category">
@labels.map { label =>
<option value="@label.id" data-category="@category" @if(issue.labels.contains(label)){ selected }>
@label.name
</option>
}
</optgroup>
}
}
</select>
} else {
@for(label <- issue.labels.toList.sortBy(r => (r.category, r.name))) {
<a href='@routes.IssueApp.issues(project.owner, project.name, issue.state.state(), "html", 1)&labelIds=@label.id' class="label issue-label active static" data-labelId="@label.id" data-color="@label.color" style="background:@label.color">@label.name</a>
}
}
</dd>
</dl>
}
@**<!-- // -->**@
</form>
</div>
</div>
</div>
<div class="board-footer board-actrow">
<div class="pull-left">
<div>
@if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.WATCH)) {
<button id="watch-button" type="button" class="ybtn @if(issue.getWatchers.contains(UserApp.currentUser())) {ybtn-watching}"
data-toggle="button" data-watching="@if(issue.getWatchers.contains(UserApp.currentUser())){true}else{false}">
@if(issue.getWatchers.contains(UserApp.currentUser())) {
@Messages("project.unwatch")
} else {
@Messages("project.watch")
}
</button>
}
<div id="vote" class="vote-wrap">
@if(isResourceCreatable(User.findByLoginId(session.get("loginId")), issue.asResource(), ResourceType.ISSUE_COMMENT)) {
<a href="@urlToVote" class="ybtn @if(issue.isVotedBy(UserApp.currentUser)){ybtn-watching}" title="@getVoteButtonTitle"
data-request-method="post" data-toggle="tooltip">
<span class="heart"><i class="yobicon-hearts"></i></span>
<span class="desc">@Messages("issue.vote")</span>
@if(issue.voters.size > 0) {
<strong class="count">@issue.voters.size</strong>
}
</a>
} else {
<span class="ybtn ybtn-disabled" style="color:#777;" data-toggle="tooltip" title="@Messages("user.login.alert")" data-login="required">
<span class="heart"><i class="yobicon-hearts"></i></span>
<span class="desc">@Messages("issue.vote")</span>
@if(issue.voters.size > 0) {
<strong class="count">@issue.voters.size</strong>
}
</span>
}
@if(issue.voters.size > 0){
@partial_voters(issue, 3)
}
</div>
</div>
</div>
@if(issue.canBeDeleted) {
@if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.DELETE)) {
<a href="#deleteConfirm" data-toggle="modal" class="ybtn ybtn-danger">@Messages("button.delete")</a>
}
} else {
<button class="ybtn ybtn-disabled" data-toggle="tooltip" data-placement="top" title="@Messages("issue.can.not.be.deleted")">@Messages("button.delete")</button>
}
@if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) {
<a href="@routes.IssueApp.editIssueForm(project.owner, project.name, issue.getNumber)" class="ybtn">@Messages("button.edit")</a>
}
</div>
@** Comment **@
<div id="comments" class="board-comment-wrap">
<div id="timeline">
<div class="timeline-list">
@partial_comments(project, issue)
</div>
</div>
@common.commentForm(issue.asResource(), ResourceType.ISSUE_COMMENT, routes.IssueApp.newComment(project.owner, project.name, issue.getNumber).toString())
</div>
@** // Comment **@
<a href="@urlToIssues" class="ybtn pull-left" data-button="historyBack">@Messages("button.list")</a>
@help.keymap("issueDetail", project)
</div>
<script type="text/x-jquery-tmpl" id="tplAttachedFile"><!--
--><li class="attached-file" data-name="${fileName}" data-href="${fileHref}" data-mime="${mimeType}" data-size="${fileSize}">
<strong>${fileName}(${fileSizeReadable})${notice}</strong><!--
--><a class="attached-delete"><i class="ico btn-delete"></i></a></li>
</script>
@** Confirm to delete post **@
<div id="deleteConfirm" class="modal hide fade">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3>@Messages("issue.delete")</h3>
</div>
<div class="modal-body">
<p>@Messages("post.delete.confirm")</p>
</div>
<div class="modal-footer">
<button type="button" class="ybtn ybtn-danger" data-request-method="delete" data-request-uri="@routes.IssueApp.deleteIssue(project.owner, project.name, issue.getNumber)">@Messages("button.yes")</button>
<button type="button" class="ybtn" data-dismiss="modal">@Messages("button.no")</button>
</div>
</div>
</div>
@common.markdown(project)
@common.commentDeleteModal()
@common.select2()
<link rel="stylesheet" type="text/css" media="screen" href="@routes.IssueLabelApp.labelStyles(project.owner, project.name)">
<link rel="stylesheet" type="text/css" media="screen" href="@routes.Assets.at("javascripts/lib/atjs/jquery.atwho.css")">
<script type="text/javascript" src="@routes.Assets.at("javascripts/lib/atjs/jquery.caret.min.js")"></script>
<script type="text/javascript" src="@routes.Assets.at("javascripts/lib/atjs/jquery.atwho.js")"></script>
<script type="text/javascript">
$(document).ready(function(){
// yobi.issue.View
$yobi.loadModule("issue.View", {
"sWatchUrl" : "@routes.WatchApp.watch(issue.asResource.asParameter)",
"sUnwatchUrl" : "@routes.WatchApp.unwatch(issue.asResource.asParameter)",
"sIssuesUrl" : "@routes.IssueApp.massUpdate(project.owner, project.name)",
"sTimelineUrl" : "@routes.IssueApp.timeline(project.owner, project.name, issue.getNumber)",
"sIssueId" : "@issue.id",
"welMilestone" : $("#milestone"),
"welAssignee" : $("#assignee"),
"welIssueUpdateForm": $("#issueUpdateForm"),
"sIssueCheckBoxesSelector": "[type=checkbox][name=checked-issue]",
"sNextState" : "@issue.nextState().toString.toLowerCase",
"sNextStateUrl" : "@routes.IssueApp.nextState(project.owner, project.name, issue.getNumber)",
"sCommentWithStateUrl": "@routes.IssueApp.newComment(project.owner, project.name, issue.getNumber)"
});
// yobi.ShortcutKey
yobi.ShortcutKey.setKeymapLink({
"L": "@urlToIssues"
@if(project.menuSetting.issue) {
,"N": "@routes.IssueApp.newIssueForm(project.owner, project.name)"
}
@if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) {
,"E": "@routes.IssueApp.editIssueForm(project.owner, project.name, issue.getNumber)"
}
});
yobi.Mention({
target:'textarea[id^=editor-]',
url : "@Html(routes.ProjectApp.mentionList(project.owner, project.name, issue.getNumber, issue.asResource().getType.resource()).toString())"
});
});
</script>
}