allow edit issue and comment
This commit is contained in:
parent
f114f78743
commit
371572cf5f
11 changed files with 243 additions and 53 deletions
|
@ -467,12 +467,17 @@ func runWeb(ctx *cli.Context) {
|
||||||
|
|
||||||
m.Combo("/:index/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
|
m.Combo("/:index/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
|
||||||
m.Group("/:index", func() {
|
m.Group("/:index", func() {
|
||||||
m.Post("/title", repo.UpdateIssueTitle)
|
|
||||||
m.Post("/label", repo.UpdateIssueLabel)
|
m.Post("/label", repo.UpdateIssueLabel)
|
||||||
m.Post("/milestone", repo.UpdateIssueMilestone)
|
m.Post("/milestone", repo.UpdateIssueMilestone)
|
||||||
m.Post("/assignee", repo.UpdateIssueAssignee)
|
m.Post("/assignee", repo.UpdateIssueAssignee)
|
||||||
}, reqRepoAdmin)
|
}, reqRepoAdmin)
|
||||||
|
|
||||||
|
m.Group("/:index", func() {
|
||||||
|
m.Post("/title", repo.UpdateIssueTitle)
|
||||||
|
m.Post("/content", repo.UpdateIssueContent)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
m.Post("/comments/:id", repo.UpdateCommentContent)
|
||||||
m.Group("/labels", func() {
|
m.Group("/labels", func() {
|
||||||
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
|
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
|
||||||
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
|
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
|
||||||
|
|
2
gogs.go
2
gogs.go
|
@ -17,7 +17,7 @@ import (
|
||||||
"github.com/gogits/gogs/modules/setting"
|
"github.com/gogits/gogs/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VER = "0.6.5.0819 Beta"
|
const APP_VER = "0.6.5.0820 Beta"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
|
|
@ -258,7 +258,27 @@ func IsErrIssueNotExist(err error) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err ErrIssueNotExist) Error() string {
|
func (err ErrIssueNotExist) Error() string {
|
||||||
return fmt.Sprintf("issue does not exist [id: %d, repo_id: %d, index: %4]", err.ID, err.RepoID, err.Index)
|
return fmt.Sprintf("issue does not exist [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _________ __
|
||||||
|
// \_ ___ \ ____ _____ _____ ____ _____/ |_
|
||||||
|
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\
|
||||||
|
// \ \___( <_> ) Y Y \ Y Y \ ___/| | \ |
|
||||||
|
// \______ /\____/|__|_| /__|_| /\___ >___| /__|
|
||||||
|
// \/ \/ \/ \/ \/
|
||||||
|
|
||||||
|
type ErrCommentNotExist struct {
|
||||||
|
ID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsErrCommentNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrCommentNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrCommentNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("comment does not exist [id: %d]", err.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// .____ ___. .__
|
// .____ ___. .__
|
||||||
|
|
|
@ -1363,6 +1363,14 @@ func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Comment) AfterDelete() {
|
||||||
|
_, err := DeleteAttachmentsByComment(c.ID, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Could not delete files for comment %d on issue #%d: %s", c.ID, c.IssueID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// HashTag returns unique hash tag for comment.
|
// HashTag returns unique hash tag for comment.
|
||||||
func (c *Comment) HashTag() string {
|
func (c *Comment) HashTag() string {
|
||||||
return "issuecomment-" + com.ToStr(c.ID)
|
return "issuecomment-" + com.ToStr(c.ID)
|
||||||
|
@ -1473,11 +1481,16 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri
|
||||||
return CreateComment(doer, repo, issue, 0, 0, COMMENT_TYPE_COMMENT, content, attachments)
|
return CreateComment(doer, repo, issue, 0, 0, COMMENT_TYPE_COMMENT, content, attachments)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommentById returns the comment with the given id
|
// GetCommentByID returns the comment by given ID.
|
||||||
func GetCommentById(id int64) (*Comment, error) {
|
func GetCommentByID(id int64) (*Comment, error) {
|
||||||
c := new(Comment)
|
c := new(Comment)
|
||||||
_, err := x.Id(id).Get(c)
|
has, err := x.Id(id).Get(c)
|
||||||
return c, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, ErrCommentNotExist{id}
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommentsByIssueID returns all comments of issue by given ID.
|
// GetCommentsByIssueID returns all comments of issue by given ID.
|
||||||
|
@ -1486,12 +1499,10 @@ func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
|
||||||
return comments, x.Where("issue_id=?", issueID).Asc("created").Find(&comments)
|
return comments, x.Where("issue_id=?", issueID).Asc("created").Find(&comments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Comment) AfterDelete() {
|
// UpdateComment updates information of comment.
|
||||||
_, err := DeleteAttachmentsByComment(c.ID, true)
|
func UpdateComment(c *Comment) error {
|
||||||
|
_, err := x.Id(c.ID).AllCols().Update(c)
|
||||||
if err != nil {
|
return err
|
||||||
log.Info("Could not delete files for comment %d on issue #%d: %s", c.ID, c.IssueID, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachment represent a attachment of issue/comment/release.
|
// Attachment represent a attachment of issue/comment/release.
|
||||||
|
|
2
public/css/gogs.min.css
vendored
2
public/css/gogs.min.css
vendored
File diff suppressed because one or more lines are too long
|
@ -2,26 +2,30 @@
|
||||||
|
|
||||||
var csrf;
|
var csrf;
|
||||||
|
|
||||||
|
function initCommentPreviewTab($form) {
|
||||||
|
var $tab_menu = $form.find('.tabular.menu');
|
||||||
|
$tab_menu.find('.item').tab();
|
||||||
|
$tab_menu.find('.item[data-tab="' + $tab_menu.data('preview') + '"]').click(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
$.post($this.data('url'), {
|
||||||
|
"_csrf": csrf,
|
||||||
|
"mode": "gfm",
|
||||||
|
"context": $this.data('context'),
|
||||||
|
"text": $form.find('.tab.segment[data-tab="' + $tab_menu.data('write') + '"] textarea').val()
|
||||||
|
},
|
||||||
|
function (data) {
|
||||||
|
$form.find('.tab.segment[data-tab="' + $tab_menu.data('preview') + '"]').html(data);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function initCommentForm() {
|
function initCommentForm() {
|
||||||
if ($('.comment.form').length == 0) {
|
if ($('.comment.form').length == 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var $form = $('.comment.form');
|
initCommentPreviewTab($('.comment.form'));
|
||||||
$form.find('.tabular.menu .item').tab();
|
|
||||||
$form.find('.tabular.menu .item[data-tab="preview"]').click(function () {
|
|
||||||
var $this = $(this);
|
|
||||||
$.post($this.data('url'), {
|
|
||||||
"_csrf": csrf,
|
|
||||||
"mode": "gfm",
|
|
||||||
"context": $this.data('context'),
|
|
||||||
"text": $form.find('.tab.segment[data-tab="write"] textarea').val()
|
|
||||||
},
|
|
||||||
function (data) {
|
|
||||||
$form.find('.tab.segment[data-tab="preview"]').html(data);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Labels
|
// Labels
|
||||||
var $list = $('.ui.labels.list');
|
var $list = $('.ui.labels.list');
|
||||||
|
@ -260,6 +264,66 @@ function initRepository() {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Edit issue or comment content
|
||||||
|
$('.edit-content').click(function () {
|
||||||
|
var $segment = $(this).parent().parent().next();
|
||||||
|
var $edit_content_zone = $segment.find('.edit-content-zone');
|
||||||
|
var $render_content = $segment.find('.render-content');
|
||||||
|
var $raw_content = $segment.find('.raw-content');
|
||||||
|
var $textarea;
|
||||||
|
|
||||||
|
// Setup new form
|
||||||
|
if ($edit_content_zone.html().length == 0) {
|
||||||
|
$edit_content_zone.html($('#edit-content-form').html());
|
||||||
|
$textarea = $segment.find('textarea');
|
||||||
|
|
||||||
|
// Give new write/preview data-tab name to distinguish from others
|
||||||
|
var $edit_content_form = $edit_content_zone.find('.ui.comment.form');
|
||||||
|
var $tabular_menu = $edit_content_form.find('.tabular.menu');
|
||||||
|
$tabular_menu.attr('data-write', $edit_content_zone.data('write'));
|
||||||
|
$tabular_menu.attr('data-preview', $edit_content_zone.data('preview'));
|
||||||
|
$tabular_menu.find('.write.item').attr('data-tab', $edit_content_zone.data('write'));
|
||||||
|
$tabular_menu.find('.preview.item').attr('data-tab', $edit_content_zone.data('preview'));
|
||||||
|
$edit_content_form.find('.write.segment').attr('data-tab', $edit_content_zone.data('write'));
|
||||||
|
$edit_content_form.find('.preview.segment').attr('data-tab', $edit_content_zone.data('preview'));
|
||||||
|
|
||||||
|
initCommentPreviewTab($edit_content_form);
|
||||||
|
|
||||||
|
$edit_content_zone.find('.cancel.button').click(function () {
|
||||||
|
$render_content.show();
|
||||||
|
$edit_content_zone.hide();
|
||||||
|
});
|
||||||
|
$edit_content_zone.find('.save.button').click(function () {
|
||||||
|
$render_content.show();
|
||||||
|
$edit_content_zone.hide();
|
||||||
|
|
||||||
|
$.post($edit_content_zone.data('update-url'), {
|
||||||
|
"_csrf": csrf,
|
||||||
|
"content": $textarea.val(),
|
||||||
|
"context": $edit_content_zone.data('context')
|
||||||
|
},
|
||||||
|
function (data) {
|
||||||
|
if (data.length == 0) {
|
||||||
|
$render_content.html($('#no-content').html());
|
||||||
|
} else {
|
||||||
|
$render_content.html(data.content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$textarea = $segment.find('textarea');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show write/preview tab and copy raw content as needed
|
||||||
|
$edit_content_zone.show();
|
||||||
|
$render_content.hide();
|
||||||
|
if ($textarea.val().length == 0) {
|
||||||
|
$textarea.val($raw_content.text());
|
||||||
|
}
|
||||||
|
$textarea.focus();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
// Change status
|
// Change status
|
||||||
var $status_btn = $('#status-button');
|
var $status_btn = $('#status-button');
|
||||||
$('#content').keyup(function () {
|
$('#content').keyup(function () {
|
||||||
|
|
|
@ -253,6 +253,10 @@
|
||||||
height: 200px;
|
height: 200px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit.buttons {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.event {
|
.event {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -543,19 +543,16 @@ func UpdateIssueTitle(ctx *middleware.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.IsSigned || ctx.User.Id != issue.PosterID || !ctx.Repo.IsAdmin() {
|
if !ctx.IsSigned || (ctx.User.Id != issue.PosterID && !ctx.Repo.IsAdmin()) {
|
||||||
ctx.Error(403)
|
ctx.Error(403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
title := ctx.Query("title")
|
issue.Name = ctx.Query("title")
|
||||||
if len(title) == 0 {
|
if len(issue.Name) == 0 {
|
||||||
ctx.JSON(200, map[string]interface{}{
|
ctx.Error(204)
|
||||||
"title": issue.Name,
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
issue.Name = title
|
|
||||||
|
|
||||||
if err := models.UpdateIssue(issue); err != nil {
|
if err := models.UpdateIssue(issue); err != nil {
|
||||||
ctx.Handle(500, "UpdateIssue", err)
|
ctx.Handle(500, "UpdateIssue", err)
|
||||||
|
@ -567,6 +564,28 @@ func UpdateIssueTitle(ctx *middleware.Context) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateIssueContent(ctx *middleware.Context) {
|
||||||
|
issue := getActionIssue(ctx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.IsSigned || (ctx.User.Id != issue.PosterID && !ctx.Repo.IsAdmin()) {
|
||||||
|
ctx.Error(403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
issue.Content = ctx.Query("content")
|
||||||
|
if err := models.UpdateIssue(issue); err != nil {
|
||||||
|
ctx.Handle(500, "UpdateIssue", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
"content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Query("context"))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func UpdateIssueLabel(ctx *middleware.Context) {
|
func UpdateIssueLabel(ctx *middleware.Context) {
|
||||||
issue := getActionIssue(ctx)
|
issue := getActionIssue(ctx)
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
|
@ -748,6 +767,42 @@ func NewComment(ctx *middleware.Context, form auth.CreateCommentForm) {
|
||||||
ctx.Redirect(fmt.Sprintf("%s/issues/%d#%s", ctx.Repo.RepoLink, issue.Index, comment.HashTag()))
|
ctx.Redirect(fmt.Sprintf("%s/issues/%d#%s", ctx.Repo.RepoLink, issue.Index, comment.HashTag()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateCommentContent(ctx *middleware.Context) {
|
||||||
|
comment, err := models.GetCommentByID(ctx.ParamsInt64(":id"))
|
||||||
|
if err != nil {
|
||||||
|
if models.IsErrCommentNotExist(err) {
|
||||||
|
ctx.Error(404, "GetCommentByID")
|
||||||
|
} else {
|
||||||
|
ctx.Handle(500, "GetCommentByID", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.IsSigned || (ctx.User.Id != comment.PosterID && !ctx.Repo.IsAdmin()) {
|
||||||
|
ctx.Error(403)
|
||||||
|
return
|
||||||
|
} else if comment.Type != models.COMMENT_TYPE_COMMENT {
|
||||||
|
ctx.Error(204)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
comment.Content = ctx.Query("content")
|
||||||
|
if len(comment.Content) == 0 {
|
||||||
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
"content": "",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := models.UpdateComment(comment); err != nil {
|
||||||
|
ctx.Handle(500, "UpdateComment", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
"content": string(base.RenderMarkdown([]byte(comment.Content), ctx.Query("context"))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func Labels(ctx *middleware.Context) {
|
func Labels(ctx *middleware.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.labels")
|
ctx.Data["Title"] = ctx.Tr("repo.labels")
|
||||||
ctx.Data["PageIsLabels"] = true
|
ctx.Data["PageIsLabels"] = true
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.6.5.0819 Beta
|
0.6.5.0820 Beta
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui top attached tabular menu">
|
<div class="ui top attached tabular menu" data-write="write" data-preview="preview">
|
||||||
<a class="active item" data-tab="write">{{.i18n.Tr "repo.release.write"}}</a>
|
<a class="active item" data-tab="write">{{.i18n.Tr "repo.release.write"}}</a>
|
||||||
<a class="item" data-tab="preview" data-url="/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.release.preview"}}</a>
|
<a class="item" data-tab="preview" data-url="/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.release.preview"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached active tab segment" data-tab="write">
|
<div class="ui bottom attached active tab segment" data-tab="write">
|
||||||
<textarea id="content" name="content"></textarea>
|
<textarea id="content" name="content"></textarea>
|
||||||
|
|
|
@ -50,16 +50,20 @@
|
||||||
<span class="text grey"><a {{if gt .Issue.Poster.Id 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.Name}}</a> {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}}</span>
|
<span class="text grey"><a {{if gt .Issue.Poster.Id 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.Name}}</a> {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}}</span>
|
||||||
<div class="ui right actions">
|
<div class="ui right actions">
|
||||||
{{if .IsIssueOwner}}
|
{{if .IsIssueOwner}}
|
||||||
<a class="item" href="#"><i class="octicon octicon-pencil"></i></a>
|
<a class="edit-content item" href="#"><i class="octicon octicon-pencil"></i></a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui attached segment markdown">
|
<div class="ui attached segment">
|
||||||
{{if .Issue.RenderedContent}}
|
<div class="render-content markdown">
|
||||||
{{.Issue.RenderedContent|Str2html}}
|
{{if .Issue.RenderedContent}}
|
||||||
{{else}}
|
{{.Issue.RenderedContent|Str2html}}
|
||||||
<span class="no-content">{{.i18n.Tr "repo.issues.no_content"}}</span>
|
{{else}}
|
||||||
{{end}}
|
<span class="no-content">{{.i18n.Tr "repo.issues.no_content"}}</span>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="raw-content hide">{{.Issue.Content}}</div>
|
||||||
|
<div class="edit-content-zone hide" data-write="issue-{{.Issue.ID}}-write" data-preview="issue-{{.Issue.ID}}-preview" data-update-url="{{.Link}}/content" data-context="{{.RepoLink}}"></div>
|
||||||
</div>
|
</div>
|
||||||
{{if .Issue.Attachments}}
|
{{if .Issue.Attachments}}
|
||||||
<div class="ui bottom attached segment">
|
<div class="ui bottom attached segment">
|
||||||
|
@ -98,16 +102,20 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if or $.IsRepositoryAdmin (eq .Poster.Id $.SignedUserID)}}
|
{{if or $.IsRepositoryAdmin (eq .Poster.Id $.SignedUserID)}}
|
||||||
<a class="item" href="#"><i class="octicon octicon-pencil"></i></a>
|
<a class="edit-content item" href="#" data-type="comment"><i class="octicon octicon-pencil"></i></a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui attached segment markdown">
|
<div class="ui attached segment">
|
||||||
{{if .RenderedContent}}
|
<div class="render-content markdown">
|
||||||
{{.RenderedContent|Str2html}}
|
{{if .RenderedContent}}
|
||||||
{{else}}
|
{{.RenderedContent|Str2html}}
|
||||||
<span class="no-content">{{$.i18n.Tr "repo.issues.no_content"}}</span>
|
{{else}}
|
||||||
{{end}}
|
<span class="no-content">{{$.i18n.Tr "repo.issues.no_content"}}</span>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="raw-content hide">{{.Content}}</div>
|
||||||
|
<div class="edit-content-zone hide" data-write="issuecomment-{{.ID}}-write" data-preview="issuecomment-{{.ID}}-preview" data-update-url="{{$.RepoLink}}/comments/{{.ID}}" data-context="{{$.RepoLink}}"></div>
|
||||||
</div>
|
</div>
|
||||||
{{if .Attachments}}
|
{{if .Attachments}}
|
||||||
<div class="ui bottom attached segment">
|
<div class="ui bottom attached segment">
|
||||||
|
@ -265,3 +273,26 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="hide" id="edit-content-form">
|
||||||
|
<div class="ui comment form">
|
||||||
|
<div class="ui top attached tabular menu">
|
||||||
|
<a class="active write item">{{$.i18n.Tr "repo.release.write"}}</a>
|
||||||
|
<a class="preview item" data-url="/api/v1/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "repo.release.preview"}}</a>
|
||||||
|
</div>
|
||||||
|
<div class="ui bottom attached active write tab segment">
|
||||||
|
<textarea id="content" name="content"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="ui bottom attached tab preview segment markdown">
|
||||||
|
{{$.i18n.Tr "repo.release.loading"}}
|
||||||
|
</div>
|
||||||
|
<div class="text right edit buttons">
|
||||||
|
<div class="ui basic blue cancel button">{{.i18n.Tr "repo.issues.cancel"}}</div>
|
||||||
|
<div class="ui green save button">{{.i18n.Tr "repo.issues.save"}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hide" id="no-content">
|
||||||
|
<span class="no-content">{{.i18n.Tr "repo.issues.no_content"}}</span>
|
||||||
|
</div>
|
Reference in a new issue