diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 0c83a7aef1..6ef1277c62 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1034,6 +1034,9 @@ wiki.save_page = Save Page wiki.last_commit_info = %s edited this page %s wiki.edit_page_button = Edit wiki.new_page_button = New Page +wiki.file_revision = Page Revision +wiki.wiki_page_revisions = Wiki Page Revisions +wiki.back_to_wiki = Back to wiki page wiki.delete_page_button = Delete Page wiki.delete_page_notice_1 = Deleting the wiki page '%s' cannot be undone. Continue? wiki.page_already_exists = A wiki page with the same name already exists. diff --git a/public/css/index.css b/public/css/index.css index 9039409f14..b948766b41 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -290,6 +290,11 @@ footer .ui.left,footer .ui.right{line-height:40px} .markdown:not(code) .csv-data tr{border-top:0} .markdown:not(code) .csv-data th{font-weight:700;background:#f8f8f8;border-top:0} .markdown:not(code) .ui.list .list,.markdown:not(code) ol.ui.list ol,.markdown:not(code) ul.ui.list ul{padding-left:2em} +.repository.wiki.revisions .ui.container>.ui.stackable.grid{flex-direction:row-reverse} +.repository.wiki.revisions .ui.container>.ui.stackable.grid>.header{margin-top:0} +.repository.wiki.revisions .ui.container>.ui.stackable.grid>.header .sub.header{padding-left:52px} +.file-revisions-btn{display:block;float:left;margin-bottom:2px!important;padding:11px!important;margin-right:10px!important} +.file-revisions-btn i{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} .home .logo{max-width:220px} @media only screen and (max-width:767px){.home .hero h1{font-size:3.5em} .home .hero h2{font-size:2em} diff --git a/public/less/_markdown.less b/public/less/_markdown.less index e971248f6f..1dcc2caf94 100644 --- a/public/less/_markdown.less +++ b/public/less/_markdown.less @@ -494,3 +494,35 @@ padding-left: 2em; } } + +.repository.wiki.revisions { + .ui.container > .ui.stackable.grid { + -ms-flex-direction: row-reverse; + flex-direction: row-reverse; + + > .header { + margin-top: 0; + + .sub.header { + padding-left: 52px; + } + } + } +} + +.file-revisions-btn { + display: block; + float: left; + margin-bottom: 2px !important; + padding: 11px !important; + margin-right: 10px !important; + + i { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } +} diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go index 43149c0340..0fdf853630 100644 --- a/routers/repo/wiki.go +++ b/routers/repo/wiki.go @@ -23,10 +23,11 @@ import ( ) const ( - tplWikiStart base.TplName = "repo/wiki/start" - tplWikiView base.TplName = "repo/wiki/view" - tplWikiNew base.TplName = "repo/wiki/new" - tplWikiPages base.TplName = "repo/wiki/pages" + tplWikiStart base.TplName = "repo/wiki/start" + tplWikiView base.TplName = "repo/wiki/view" + tplWikiRevision base.TplName = "repo/wiki/revision" + tplWikiNew base.TplName = "repo/wiki/new" + tplWikiPages base.TplName = "repo/wiki/pages" ) // MustEnableWiki check if wiki is enabled, if external then redirect @@ -107,18 +108,20 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte { // wikiContentsByName returns the contents of a wiki page, along with a boolean // indicating whether the page exists. Writes to ctx if an error occurs. -func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName string) ([]byte, bool) { - entry, err := findEntryForFile(commit, models.WikiNameToFilename(wikiName)) - if err != nil { +func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName string) ([]byte, *git.TreeEntry, string, bool) { + var entry *git.TreeEntry + var err error + pageFilename := models.WikiNameToFilename(wikiName) + if entry, err = findEntryForFile(commit, pageFilename); err != nil { ctx.ServerError("findEntryForFile", err) - return nil, false + return nil, nil, "", false } else if entry == nil { - return nil, false + return nil, nil, "", true } - return wikiContentsByEntry(ctx, entry), true + return wikiContentsByEntry(ctx, entry), entry, pageFilename, false } -func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, *git.TreeEntry) { +func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { wikiRepo, commit, err := findWikiRepoCommit(ctx) if err != nil { if !git.IsErrNotExist(err) { @@ -128,88 +131,176 @@ func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, *gi } // Get page list. - if isViewPage { - entries, err := commit.ListEntries() - if err != nil { - ctx.ServerError("ListEntries", err) - return nil, nil - } - pages := make([]PageMeta, 0, len(entries)) - for _, entry := range entries { - if !entry.IsRegular() { - continue - } - wikiName, err := models.WikiFilenameToName(entry.Name()) - if err != nil { - if models.IsErrWikiInvalidFileName(err) { - continue - } - ctx.ServerError("WikiFilenameToName", err) - return nil, nil - } else if wikiName == "_Sidebar" || wikiName == "_Footer" { - continue - } - pages = append(pages, PageMeta{ - Name: wikiName, - SubURL: models.WikiNameToSubURL(wikiName), - }) - } - ctx.Data["Pages"] = pages + entries, err := commit.ListEntries() + if err != nil { + ctx.ServerError("ListEntries", err) + return nil, nil } + pages := make([]PageMeta, 0, len(entries)) + for _, entry := range entries { + if !entry.IsRegular() { + continue + } + wikiName, err := models.WikiFilenameToName(entry.Name()) + if err != nil { + if models.IsErrWikiInvalidFileName(err) { + continue + } + ctx.ServerError("WikiFilenameToName", err) + return nil, nil + } else if wikiName == "_Sidebar" || wikiName == "_Footer" { + continue + } + pages = append(pages, PageMeta{ + Name: wikiName, + SubURL: models.WikiNameToSubURL(wikiName), + }) + } + ctx.Data["Pages"] = pages + // get requested pagename pageName := models.NormalizeWikiName(ctx.Params(":page")) if len(pageName) == 0 { pageName = "Home" } ctx.Data["PageURL"] = models.WikiNameToSubURL(pageName) - ctx.Data["old_title"] = pageName ctx.Data["Title"] = pageName ctx.Data["title"] = pageName ctx.Data["RequireHighlightJS"] = true - pageFilename := models.WikiNameToFilename(pageName) - var entry *git.TreeEntry - if entry, err = findEntryForFile(commit, pageFilename); err != nil { - ctx.ServerError("findEntryForFile", err) - return nil, nil - } else if entry == nil { + //lookup filename in wiki - get filecontent, gitTree entry , real filename + data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName) + if noEntry { ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_pages") + } + if entry == nil || ctx.Written() { return nil, nil } - data := wikiContentsByEntry(ctx, entry) + + sidebarContent, _, _, _ := wikiContentsByName(ctx, commit, "_Sidebar") if ctx.Written() { return nil, nil } - if isViewPage { - sidebarContent, sidebarPresent := wikiContentsByName(ctx, commit, "_Sidebar") - if ctx.Written() { - return nil, nil - } - - footerContent, footerPresent := wikiContentsByName(ctx, commit, "_Footer") - if ctx.Written() { - return nil, nil - } - - metas := ctx.Repo.Repository.ComposeMetas() - ctx.Data["content"] = markdown.RenderWiki(data, ctx.Repo.RepoLink, metas) - ctx.Data["sidebarPresent"] = sidebarPresent - ctx.Data["sidebarContent"] = markdown.RenderWiki(sidebarContent, ctx.Repo.RepoLink, metas) - ctx.Data["footerPresent"] = footerPresent - ctx.Data["footerContent"] = markdown.RenderWiki(footerContent, ctx.Repo.RepoLink, metas) - } else { - ctx.Data["content"] = string(data) - ctx.Data["sidebarPresent"] = false - ctx.Data["sidebarContent"] = "" - ctx.Data["footerPresent"] = false - ctx.Data["footerContent"] = "" + footerContent, _, _, _ := wikiContentsByName(ctx, commit, "_Footer") + if ctx.Written() { + return nil, nil } + metas := ctx.Repo.Repository.ComposeMetas() + ctx.Data["content"] = markdown.RenderWiki(data, ctx.Repo.RepoLink, metas) + ctx.Data["sidebarPresent"] = sidebarContent != nil + ctx.Data["sidebarContent"] = markdown.RenderWiki(sidebarContent, ctx.Repo.RepoLink, metas) + ctx.Data["footerPresent"] = footerContent != nil + ctx.Data["footerContent"] = markdown.RenderWiki(footerContent, ctx.Repo.RepoLink, metas) + + // get commit count - wiki revisions + commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename) + ctx.Data["CommitCount"] = commitsCount + return wikiRepo, entry } +func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { + wikiRepo, commit, err := findWikiRepoCommit(ctx) + if err != nil { + if !git.IsErrNotExist(err) { + ctx.ServerError("GetBranchCommit", err) + } + return nil, nil + } + + // get requested pagename + pageName := models.NormalizeWikiName(ctx.Params(":page")) + if len(pageName) == 0 { + pageName = "Home" + } + ctx.Data["PageURL"] = models.WikiNameToSubURL(pageName) + ctx.Data["old_title"] = pageName + ctx.Data["Title"] = pageName + ctx.Data["title"] = pageName + ctx.Data["RequireHighlightJS"] = true + + //lookup filename in wiki - get filecontent, gitTree entry , real filename + data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName) + if noEntry { + ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_pages") + } + if entry == nil || ctx.Written() { + return nil, nil + } + + ctx.Data["content"] = string(data) + ctx.Data["sidebarPresent"] = false + ctx.Data["sidebarContent"] = "" + ctx.Data["footerPresent"] = false + ctx.Data["footerContent"] = "" + + // get commit count - wiki revisions + commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename) + ctx.Data["CommitCount"] = commitsCount + + // get page + page := ctx.QueryInt("page") + if page <= 1 { + page = 1 + } + + // get Commit Count + commitsHistory, err := wikiRepo.CommitsByFileAndRange("master", pageFilename, page) + if err != nil { + ctx.ServerError("CommitsByFileAndRange", err) + return nil, nil + } + commitsHistory = models.ValidateCommitsWithEmails(commitsHistory) + commitsHistory = models.ParseCommitsWithSignature(commitsHistory) + + ctx.Data["Commits"] = commitsHistory + + pager := context.NewPagination(int(commitsCount), git.CommitsRangeSize, page, 5) + pager.SetDefaultParams(ctx) + ctx.Data["Page"] = pager + + return wikiRepo, entry +} + +func renderEditPage(ctx *context.Context) { + _, commit, err := findWikiRepoCommit(ctx) + if err != nil { + if !git.IsErrNotExist(err) { + ctx.ServerError("GetBranchCommit", err) + } + return + } + + // get requested pagename + pageName := models.NormalizeWikiName(ctx.Params(":page")) + if len(pageName) == 0 { + pageName = "Home" + } + ctx.Data["PageURL"] = models.WikiNameToSubURL(pageName) + ctx.Data["old_title"] = pageName + ctx.Data["Title"] = pageName + ctx.Data["title"] = pageName + ctx.Data["RequireHighlightJS"] = true + + //lookup filename in wiki - get filecontent, gitTree entry , real filename + data, entry, _, noEntry := wikiContentsByName(ctx, commit, pageName) + if noEntry { + ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_pages") + } + if entry == nil || ctx.Written() { + return + } + + ctx.Data["content"] = string(data) + ctx.Data["sidebarPresent"] = false + ctx.Data["sidebarContent"] = "" + ctx.Data["footerPresent"] = false + ctx.Data["footerContent"] = "" +} + // Wiki renders single wiki page func Wiki(ctx *context.Context) { ctx.Data["PageIsWiki"] = true @@ -221,7 +312,7 @@ func Wiki(ctx *context.Context) { return } - wikiRepo, entry := renderWikiPage(ctx, true) + wikiRepo, entry := renderViewPage(ctx) if ctx.Written() { return } @@ -247,6 +338,39 @@ func Wiki(ctx *context.Context) { ctx.HTML(200, tplWikiView) } +// WikiRevision renders file revision list of wiki page +func WikiRevision(ctx *context.Context) { + ctx.Data["PageIsWiki"] = true + ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(models.UnitTypeWiki) && !ctx.Repo.Repository.IsArchived + + if !ctx.Repo.Repository.HasWiki() { + ctx.Data["Title"] = ctx.Tr("repo.wiki") + ctx.HTML(200, tplWikiStart) + return + } + + wikiRepo, entry := renderRevisionPage(ctx) + if ctx.Written() { + return + } + if entry == nil { + ctx.Data["Title"] = ctx.Tr("repo.wiki") + ctx.HTML(200, tplWikiStart) + return + } + + // Get last change information. + wikiPath := entry.Name() + lastCommit, err := wikiRepo.GetCommitByPath(wikiPath) + if err != nil { + ctx.ServerError("GetCommitByPath", err) + return + } + ctx.Data["Author"] = lastCommit.Author + + ctx.HTML(200, tplWikiRevision) +} + // WikiPages render wiki pages list page func WikiPages(ctx *context.Context) { if !ctx.Repo.Repository.HasWiki() { @@ -399,7 +523,7 @@ func EditWiki(ctx *context.Context) { return } - renderWikiPage(ctx, false) + renderEditPage(ctx) if ctx.Written() { return } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 744088a9d7..ec57e8f5fd 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -804,6 +804,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/wiki", func() { m.Get("/?:page", repo.Wiki) m.Get("/_pages", repo.WikiPages) + m.Get("/:page/_revision", repo.WikiRevision) m.Group("", func() { m.Combo("/_new").Get(repo.NewWiki). diff --git a/templates/repo/wiki/revision.tmpl b/templates/repo/wiki/revision.tmpl new file mode 100644 index 0000000000..a64c386edc --- /dev/null +++ b/templates/repo/wiki/revision.tmpl @@ -0,0 +1,104 @@ +{{template "base/head" .}} +
{{.i18n.Tr "repo.commits.author"}} | +SHA1 | +{{.i18n.Tr "repo.commits.date"}} | +
---|---|---|
+ {{if .User}} + {{if .User.FullName}} + {{.User.FullName}} + {{else}} + {{.Author.Name}} + {{end}} + {{else}} + {{.Author.Name}} + {{end}} + | ++ + | +{{TimeSince .Author.When $.Lang}} | +