Wiki: UI for page new

This commit is contained in:
Unknwon 2015-11-25 20:10:25 -05:00
parent 2f28a0310b
commit 2b10fdc4dc
20 changed files with 307 additions and 49 deletions

View file

@ -470,7 +470,7 @@ func runWeb(ctx *cli.Context) {
}, func(ctx *middleware.Context) { }, func(ctx *middleware.Context) {
ctx.Data["PageIsSettings"] = true ctx.Data["PageIsSettings"] = true
}) })
}, reqSignIn, middleware.RepoAssignment(true), reqRepoAdmin, middleware.RepoRef()) }, reqSignIn, middleware.RepoAssignment(), reqRepoAdmin, middleware.RepoRef())
m.Group("/:username/:reponame", func() { m.Group("/:username/:reponame", func() {
m.Get("/action/:action", repo.Action) m.Get("/action/:action", repo.Action)
@ -516,7 +516,7 @@ func runWeb(ctx *cli.Context) {
m.Combo("/compare/*").Get(repo.CompareAndPullRequest). m.Combo("/compare/*").Get(repo.CompareAndPullRequest).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost) Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
}, reqSignIn, middleware.RepoAssignment(true)) }, reqSignIn, middleware.RepoAssignment())
m.Group("/:username/:reponame", func() { m.Group("/:username/:reponame", func() {
m.Group("", func() { m.Group("", func() {
@ -530,7 +530,17 @@ func runWeb(ctx *cli.Context) {
}) })
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue) m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
m.Get("/branches", repo.Branches) // m.Get("/branches", repo.Branches)
m.Group("/wiki", func() {
m.Get("/?:page", repo.Wiki)
m.Group("", func() {
m.Get("/_new", repo.NewWiki)
m.Get("/:page/_edit", repo.EditWiki)
}, reqSignIn)
}, middleware.RepoRef())
m.Get("/archive/*", repo.Download) m.Get("/archive/*", repo.Download)
m.Group("/pulls/:index", func() { m.Group("/pulls/:index", func() {
@ -550,13 +560,13 @@ func runWeb(ctx *cli.Context) {
}, middleware.RepoRef()) }, middleware.RepoRef())
m.Get("/compare/:before([a-z0-9]{40})...:after([a-z0-9]{40})", repo.CompareDiff) m.Get("/compare/:before([a-z0-9]{40})...:after([a-z0-9]{40})", repo.CompareDiff)
}, ignSignIn, middleware.RepoAssignment(true)) }, ignSignIn, middleware.RepoAssignment())
m.Group("/:username", func() { m.Group("/:username", func() {
m.Group("/:reponame", func() { m.Group("/:reponame", func() {
m.Get("", repo.Home) m.Get("", repo.Home)
m.Get("\\.git$", repo.Home) m.Get("\\.git$", repo.Home)
}, ignSignIn, middleware.RepoAssignment(true, true), middleware.RepoRef()) }, ignSignIn, middleware.RepoAssignment(true), middleware.RepoRef())
m.Group("/:reponame", func() { m.Group("/:reponame", func() {
m.Any("/*", ignSignInAndCsrf, repo.HTTP) m.Any("/*", ignSignInAndCsrf, repo.HTTP)

View file

@ -535,6 +535,14 @@ milestones.deletion = Milestone Deletion
milestones.deletion_desc = Delete this milestone will remove its information in all related issues. Do you want to continue? milestones.deletion_desc = Delete this milestone will remove its information in all related issues. Do you want to continue?
milestones.deletion_success = Milestone has been deleted successfully! milestones.deletion_success = Milestone has been deleted successfully!
wiki = Wiki
wiki.welcome = Welcome to Wiki!
wiki.welcome_desc = Wiki is the place where you would like to document your project together and make it better.
wiki.create_first_page = Create the first page
wiki.new_page = Create New Page
wiki.default_commit_message = Write a note about this update (optional).
wiki.save_page = Save Page
settings = Settings settings = Settings
settings.options = Options settings.options = Options
settings.collaboration = Collaboration settings.collaboration = Collaboration

View file

@ -264,6 +264,14 @@ func (repo *Repository) RepoPath() (string, error) {
return repo.repoPath(x) return repo.repoPath(x)
} }
func (repo *Repository) WikiPath() (string, error) {
if err := repo.GetOwner(); err != nil {
return "", err
}
return WikiPath(repo.Owner.Name, repo.Name), nil
}
func (repo *Repository) RepoLink() (string, error) { func (repo *Repository) RepoLink() (string, error) {
if err := repo.GetOwner(); err != nil { if err := repo.GetOwner(); err != nil {
return "", err return "", err
@ -877,6 +885,11 @@ func RepoPath(userName, repoName string) string {
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".git") return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".git")
} }
// WikiPath returns wiki data path by given user and repository name.
func WikiPath(userName, repoName string) string {
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
}
// TransferOwnership transfers all corresponding setting from old user to new one. // TransferOwnership transfers all corresponding setting from old user to new one.
func TransferOwnership(u *User, newOwnerName string, repo *Repository) error { func TransferOwnership(u *User, newOwnerName string, repo *Repository) error {
newOwner, err := GetUserByName(newOwnerName) newOwner, err := GetUserByName(newOwnerName)

File diff suppressed because one or more lines are too long

View file

@ -223,7 +223,7 @@ func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
} }
} }
func RepoAssignment(redirect bool, args ...bool) macaron.Handler { func RepoAssignment(args ...bool) macaron.Handler {
return func(ctx *Context) { return func(ctx *Context) {
var ( var (
displayBare bool // To display bare page if it is a bare repo. displayBare bool // To display bare page if it is a bare repo.

View file

@ -4,8 +4,8 @@
"files": { "files": {
"\/css\/dropzone-4.2.0.css": { "\/css\/dropzone-4.2.0.css": {
"fileType": 16, "fileType": 16,
"ignore": 0, "ignore": 1,
"ignoreWasSetByUser": 0, "ignoreWasSetByUser": 1,
"inputAbbreviatedPath": "\/css\/dropzone-4.2.0.css", "inputAbbreviatedPath": "\/css\/dropzone-4.2.0.css",
"outputAbbreviatedPath": "No Output Path", "outputAbbreviatedPath": "No Output Path",
"outputPathIsOutsideProject": 0, "outputPathIsOutsideProject": 0,
@ -92,6 +92,15 @@
"outputPathIsOutsideProject": 0, "outputPathIsOutsideProject": 0,
"outputPathIsSetByUser": 0 "outputPathIsSetByUser": 0
}, },
"\/css\/simplemde-1.8.1.min.css": {
"fileType": 16,
"ignore": 1,
"ignoreWasSetByUser": 1,
"inputAbbreviatedPath": "\/css\/simplemde-1.8.1.min.css",
"outputAbbreviatedPath": "No Output Path",
"outputPathIsOutsideProject": 0,
"outputPathIsSetByUser": 0
},
"\/css\/themes\/default\/assets\/images\/flags.png": { "\/css\/themes\/default\/assets\/images\/flags.png": {
"fileType": 32768, "fileType": 32768,
"ignore": 0, "ignore": 0,

View file

@ -1758,6 +1758,11 @@ footer .container .links > *:first-child {
line-height: 10px; line-height: 10px;
white-space: nowrap; white-space: nowrap;
} }
.repository .navbar .ui.label {
margin-top: -2px;
margin-left: 7px;
padding: 3px 5px;
}
.repository .owner.dropdown { .repository .owner.dropdown {
min-width: 40% !important; min-width: 40% !important;
} }
@ -2513,6 +2518,19 @@ footer .container .links > *:first-child {
.repository.forks .list .item .link { .repository.forks .list .item .link {
padding-top: 5px; padding-top: 5px;
} }
.repository.wiki.start .ui.segment {
padding-top: 70px;
padding-bottom: 100px;
}
.repository.wiki.start .ui.segment .mega-octicon {
font-size: 48px;
}
.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment {
background: inherit;
}
.repository.wiki.new .editor-preview {
background-color: white;
}
.repository.settings.collaboration .collaborator.list { .repository.settings.collaboration .collaborator.list {
padding: 0; padding: 0;
} }

7
public/css/simplemde-1.8.1.min.css vendored Executable file

File diff suppressed because one or more lines are too long

View file

@ -445,6 +445,53 @@ function initRepository() {
} }
} }
function initWiki() {
if ($('.repository.wiki').length == 0) {
return;
}
if ($('.repository.wiki.new').length > 0) {
var $edit_area = $('#edit-area');
var simplemde = new SimpleMDE({
autoDownloadFontAwesome: false,
element: $edit_area[0],
previewRender: function (plainText, preview) { // Async method
setTimeout(function () {
if ($('.editor-preview-active').length == 0) {
return;
}
$.post($edit_area.data('url'), {
"_csrf": csrf,
"mode": "gfm",
"context": $edit_area.data('context'),
"text": plainText
},
function (data) {
preview.innerHTML = '<div class="markdown">' + data + '</div>';
emojify.run($('.editor-preview')[0]);
}
);
}, 0);
return "Loading...";
},
renderingConfig: {
singleLineBreaks: false
},
spellChecker: false,
tabSize: 4,
toolbar: ["bold", "italic", "strikethrough", "|",
"heading", "heading-1", "heading-2", "heading-3", "|",
"code", "quote", "|",
"unordered-list", "ordered-list", "|",
"link", "image", "horizontal-rule", "|",
"preview", "fullscreen"]
})
}
}
function initOrganization() { function initOrganization() {
if ($('.organization').length == 0) { if ($('.organization').length == 0) {
return; return;
@ -835,6 +882,7 @@ $(document).ready(function () {
initCommentForm(); initCommentForm();
initInstall(); initInstall();
initRepository(); initRepository();
initWiki();
initOrganization(); initOrganization();
initUser(); initUser();
initWebhook(); initWebhook();

14
public/js/libs/simplemde-1.8.1.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View file

@ -32,6 +32,14 @@
} }
} }
.navbar {
.ui.label {
margin-top: -2px;
margin-left: 7px;
padding: 3px 5px;
}
}
.owner.dropdown { .owner.dropdown {
min-width: 40% !important; min-width: 40% !important;
} }
@ -939,6 +947,31 @@
} }
} }
&.wiki {
&.start {
.ui.segment {
padding-top: 70px;
padding-bottom: 100px;
.mega-octicon {
font-size: 48px;
}
}
}
&.new {
.CodeMirror {
.CodeMirror-code .cm-comment {
background: inherit;
}
}
.editor-preview {
background-color: white;
}
}
}
&.settings { &.settings {
&.collaboration { &.collaboration {
.collaborator.list { .collaborator.list {

View file

@ -5,12 +5,9 @@
package v1 package v1
import ( import (
"strings"
"github.com/gogits/gogs/modules/auth/apiv1" "github.com/gogits/gogs/modules/auth/apiv1"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/middleware" "github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
) )
// Render an arbitrary Markdown document. // Render an arbitrary Markdown document.
@ -27,8 +24,7 @@ func Markdown(ctx *middleware.Context, form apiv1.MarkdownForm) {
switch form.Mode { switch form.Mode {
case "gfm": case "gfm":
ctx.Write(base.RenderMarkdown([]byte(form.Text), ctx.Write(base.RenderMarkdown([]byte(form.Text), form.Context))
setting.AppUrl+strings.TrimPrefix(form.Context, "/")))
default: default:
ctx.Write(base.RenderRawMarkdown([]byte(form.Text), "")) ctx.Write(base.RenderRawMarkdown([]byte(form.Text), ""))
} }

View file

@ -29,6 +29,7 @@ const (
func Home(ctx *middleware.Context) { func Home(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Repo.Repository.Name ctx.Data["Title"] = ctx.Repo.Repository.Name
ctx.Data["PageIsViewCode"] = true
ctx.Data["RequireHighlightJS"] = true ctx.Data["RequireHighlightJS"] = true
branchName := ctx.Repo.BranchName branchName := ctx.Repo.BranchName
@ -52,8 +53,6 @@ func Home(ctx *middleware.Context) {
treeLink += "/" + treename treeLink += "/" + treename
} }
ctx.Data["IsRepoToolbarSource"] = true
isViewBranch := ctx.Repo.IsBranch isViewBranch := ctx.Repo.IsBranch
ctx.Data["IsViewBranch"] = isViewBranch ctx.Data["IsViewBranch"] = isViewBranch

49
routers/repo/wiki.go Normal file
View file

@ -0,0 +1,49 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"github.com/Unknwon/com"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/middleware"
)
const (
WIKI_START base.TplName = "repo/wiki/start"
WIKI_VIEW base.TplName = "repo/wiki/view"
WIKI_NEW base.TplName = "repo/wiki/new"
)
func Wiki(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.wiki")
ctx.Data["PageIsWiki"] = true
wikiPath := models.WikiPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
if !com.IsDir(wikiPath) {
ctx.HTML(200, WIKI_START)
return
}
ctx.HTML(200, WIKI_VIEW)
}
func NewWiki(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
ctx.Data["PageIsWiki"] = true
ctx.Data["RequireSimpleMDE"] = true
wikiPath := models.WikiPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
if !com.IsDir(wikiPath) {
ctx.Data["title"] = "Home"
}
ctx.HTML(200, WIKI_NEW)
}
func EditWiki(ctx *middleware.Context) {
ctx.PlainText(200, []byte(ctx.Params(":page")))
}

View file

@ -19,6 +19,11 @@
<script src="{{AppSubUrl}}/js/jquery-1.11.3.min.js"></script> <script src="{{AppSubUrl}}/js/jquery-1.11.3.min.js"></script>
<link rel="stylesheet" href="{{AppSubUrl}}/css/font-awesome-4.4.0.min.css"> <link rel="stylesheet" href="{{AppSubUrl}}/css/font-awesome-4.4.0.min.css">
{{if .RequireSimpleMDE}}
<link rel="stylesheet" href="{{AppSubUrl}}/css/simplemde-1.8.1.min.css">
<script src="{{AppSubUrl}}/js/libs/simplemde-1.8.1.min.js"></script>
{{end}}
<!-- Stylesheet --> <!-- Stylesheet -->
<link rel="stylesheet" href="{{AppSubUrl}}/css/semantic-2.1.6.min.css"> <link rel="stylesheet" href="{{AppSubUrl}}/css/semantic-2.1.6.min.css">
<link rel="stylesheet" href="{{AppSubUrl}}/css/gogs.css?v={{MD5 AppVer}}"> <link rel="stylesheet" href="{{AppSubUrl}}/css/gogs.css?v={{MD5 AppVer}}">

View file

@ -1,7 +1,7 @@
<div class="field"> <div class="field">
<div class="ui top attached tabular menu" data-write="write" data-preview="preview"> <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="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.release.preview"}}</a> <a class="item" data-tab="preview" data-url="{{AppSubUrl}}/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" tabindex="4"></textarea> <textarea id="content" name="content" tabindex="4"></textarea>

View file

@ -1,16 +1,22 @@
{{if not .IsBareRepo}} {{if not .IsBareRepo}}
<div class="ui {{if .IsRepositoryAdmin}}five{{else}}four{{end}} item menu"> <div class="ui secondary pointing menu navbar">
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}">
<i class="icon octicon octicon-code"></i> {{.i18n.Tr "repo.code"}}
</a>
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues"> <a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">
<i class="icon octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues"}} <span class="ui blue label">{{.Repository.NumOpenIssues}}</span> <i class="icon octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues"}} <span class="ui blue small label">{{.Repository.NumOpenIssues}}</span>
</a> </a>
<a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls"> <a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls">
<i class="icon octicon octicon-git-pull-request"></i> {{.i18n.Tr "repo.pulls"}} <span class="ui blue label">{{.Repository.NumOpenPulls}}</span> <i class="icon octicon octicon-git-pull-request"></i> {{.i18n.Tr "repo.pulls"}} <span class="ui blue small label">{{.Repository.NumOpenPulls}}</span>
</a> </a>
<a class="{{if .PageIsCommits}}active{{end}} item" href="{{.RepoLink}}/commits/{{EscapePound .BranchName}}"> <a class="{{if .PageIsCommits}}active{{end}} item" href="{{.RepoLink}}/commits/{{EscapePound .BranchName}}">
<i class="icon octicon octicon-history"></i> {{.i18n.Tr "repo.commits"}} <span class="ui blue label">{{.CommitsCount}}</span> <i class="icon octicon octicon-history"></i> {{.i18n.Tr "repo.commits"}} <span class="ui blue small label">{{.CommitsCount}}</span>
</a> </a>
<a class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases"> <a class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases">
<i class="icon octicon octicon-tag"></i> {{.i18n.Tr "repo.releases"}} <span class="ui blue label">{{.Repository.NumTags}}</span> <i class="icon octicon octicon-tag"></i> {{.i18n.Tr "repo.releases"}} <span class="ui blue small label">{{.Repository.NumTags}}</span>
</a>
<a class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki">
<i class="icon octicon octicon-book"></i> {{.i18n.Tr "repo.wiki"}}
</a> </a>
{{if .IsRepositoryAdmin}} {{if .IsRepositoryAdmin}}
<a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings"> <a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings">

View file

@ -0,0 +1,27 @@
{{template "base/head" .}}
<div class="repository wiki new">
{{template "repo/header" .}}
<div class="ui container">
{{template "repo/sidebar" .}}
<div class="ui header">
{{.i18n.Tr "repo.wiki.new_page"}}
</div>
<form class="ui form" action="{{.Link}}" method="post">
<div class="field">
<input name="title" value="{{.title}}" autofocus>
</div>
<div class="field">
<textarea id="edit-area" name="content" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.wiki.welcome"}}</textarea>
</div>
<div class="field">
<input name="message" placeholder="{{.i18n.Tr "repo.wiki.default_commit_message"}}">
</div>
<div class="text right">
<button class="ui green button">
{{.i18n.Tr "repo.wiki.save_page"}}
</button>
</div>
</form>
</div>
</div>
{{template "base/footer" .}}

View file

@ -0,0 +1,16 @@
{{template "base/head" .}}
<div class="repository wiki start">
{{template "repo/header" .}}
<div class="ui container">
{{template "repo/sidebar" .}}
<div class="ui center segment">
<span class="mega-octicon octicon-book"></span>
<h2>{{.i18n.Tr "repo.wiki.welcome"}}</h2>
<p>{{.i18n.Tr "repo.wiki.welcome_desc"}}</p>
{{if .IsSigned}}
<a class="ui green button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.create_first_page"}}</a>
{{end}}
</div>
</div>
</div>
{{template "base/footer" .}}

View file