mirror of https://github.com/mindoc-org/mindoc.git
parent
d38417535a
commit
ad67558b80
|
@ -0,0 +1,14 @@
|
||||||
|
FROM golang:1.8.1-alpine
|
||||||
|
|
||||||
|
|
||||||
|
ADD . /go/src/github.com/lifei6671/godoc
|
||||||
|
|
||||||
|
|
||||||
|
WORKDIR /go/src/github.com/lifei6671/godoc
|
||||||
|
|
||||||
|
RUN chmod +x start.sh
|
||||||
|
|
||||||
|
RUN go build -ldflags "-w" && \
|
||||||
|
rm -rf commands controllers models routers search vendor .gitignore .travis.yml Dockerfile gide.yaml LICENSE main.go README.md utils graphics Godeps
|
||||||
|
|
||||||
|
CMD ["./start.sh"]
|
|
@ -4,13 +4,15 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
"os"
|
||||||
|
"encoding/gob"
|
||||||
|
|
||||||
"github.com/lifei6671/godoc/models"
|
"github.com/lifei6671/godoc/models"
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
"os"
|
|
||||||
"github.com/lifei6671/godoc/conf"
|
"github.com/lifei6671/godoc/conf"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegisterDataBase 注册数据库
|
// RegisterDataBase 注册数据库
|
||||||
|
@ -75,7 +77,7 @@ func RegisterLogger() {
|
||||||
logs.EnableFuncCallDepth(true)
|
logs.EnableFuncCallDepth(true)
|
||||||
logs.Async()
|
logs.Async()
|
||||||
|
|
||||||
beego.BeeLogger.DelLogger("console")
|
//beego.BeeLogger.DelLogger("console")
|
||||||
beego.SetLogger("file",`{"filename":"logs/log.log"}`)
|
beego.SetLogger("file",`{"filename":"logs/log.log"}`)
|
||||||
beego.SetLogFuncCall(true)
|
beego.SetLogFuncCall(true)
|
||||||
beego.BeeLogger.Async()
|
beego.BeeLogger.Async()
|
||||||
|
@ -101,3 +103,7 @@ func RegisterCommand() {
|
||||||
func RegisterFunction() {
|
func RegisterFunction() {
|
||||||
beego.AddFuncMap("config",models.GetOptionValue)
|
beego.AddFuncMap("config",models.GetOptionValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register(models.Member{})
|
||||||
|
}
|
|
@ -5,6 +5,12 @@ sessionon = true
|
||||||
sessionname = smart_webhook_id
|
sessionname = smart_webhook_id
|
||||||
copyrequestbody = true
|
copyrequestbody = true
|
||||||
|
|
||||||
|
#默认Session生成Key的秘钥
|
||||||
|
beegoserversessionkey=123456
|
||||||
|
#Session储存方式
|
||||||
|
sessionprovider=file
|
||||||
|
sessionproviderconfig=./logs
|
||||||
|
|
||||||
#生成回调地址时完整的域名
|
#生成回调地址时完整的域名
|
||||||
base_url = https://hook.iminho.me
|
base_url = https://hook.iminho.me
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@ sessionon = true
|
||||||
sessionname = smart_webhook_id
|
sessionname = smart_webhook_id
|
||||||
copyrequestbody = true
|
copyrequestbody = true
|
||||||
|
|
||||||
|
#默认Session生成Key的秘钥
|
||||||
|
beegoserversessionkey=123456
|
||||||
|
#Session储存方式
|
||||||
|
sessionprovider=file
|
||||||
|
sessionproviderconfig=./logs
|
||||||
|
|
||||||
#生成回调地址时完整的域名
|
#生成回调地址时完整的域名
|
||||||
base_url = https://hook.iminho.me
|
base_url = https://hook.iminho.me
|
||||||
|
|
||||||
|
|
|
@ -77,3 +77,6 @@ func (c *AccountController) Logout(){
|
||||||
c.Redirect(beego.URLFor("AccountController.Login"),302)
|
c.Redirect(beego.URLFor("AccountController.Login"),302)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *AccountController) Captcha() {
|
||||||
|
|
||||||
|
}
|
|
@ -7,32 +7,42 @@ import (
|
||||||
"github.com/lifei6671/godoc/models"
|
"github.com/lifei6671/godoc/models"
|
||||||
"github.com/lifei6671/godoc/conf"
|
"github.com/lifei6671/godoc/conf"
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type BaseController struct {
|
type BaseController struct {
|
||||||
beego.Controller
|
beego.Controller
|
||||||
Member *models.Member
|
Member *models.Member
|
||||||
|
Option map[string]string
|
||||||
|
EnableAnonymous bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare 预处理.
|
// Prepare 预处理.
|
||||||
func (c *BaseController) Prepare (){
|
func (c *BaseController) Prepare (){
|
||||||
c.Data["SiteName"] = "MinDoc"
|
c.Data["SiteName"] = "MinDoc"
|
||||||
c.Data["Member"] = models.Member{}
|
c.Data["Member"] = models.Member{}
|
||||||
|
c.EnableAnonymous = false
|
||||||
|
|
||||||
|
|
||||||
if member,ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0{
|
if member,ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0{
|
||||||
c.Member = &member
|
c.Member = &member
|
||||||
c.Data["Member"] = c.Member
|
c.Data["Member"] = c.Member
|
||||||
}else{
|
}else{
|
||||||
c.Member = models.NewMember()
|
//c.Member = models.NewMember()
|
||||||
c.Member.Find(1)
|
//c.Member.Find(1)
|
||||||
c.Data["Member"] = *c.Member
|
//c.Data["Member"] = *c.Member
|
||||||
}
|
}
|
||||||
c.Data["BaseUrl"] = c.Ctx.Input.Scheme() + "://" + c.Ctx.Request.Host
|
c.Data["BaseUrl"] = c.Ctx.Input.Scheme() + "://" + c.Ctx.Request.Host
|
||||||
|
|
||||||
if options,err := models.NewOption().All();err == nil {
|
if options,err := models.NewOption().All();err == nil {
|
||||||
|
c.Option = make(map[string]string,len(options))
|
||||||
for _,item := range options {
|
for _,item := range options {
|
||||||
c.Data[item.OptionName] = item.OptionValue
|
c.Data[item.OptionName] = item.OptionValue
|
||||||
|
c.Option[item.OptionName] = item.OptionValue
|
||||||
|
if strings.EqualFold(item.OptionName,"ENABLE_ANONYMOUS") && item.OptionValue == "true" {
|
||||||
|
c.EnableAnonymous = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -499,7 +499,28 @@ func (c *BookController) Delete() {
|
||||||
|
|
||||||
//发布项目
|
//发布项目
|
||||||
func (c *BookController) Release() {
|
func (c *BookController) Release() {
|
||||||
c.JsonResult(0,"ok")
|
c.Prepare()
|
||||||
|
|
||||||
|
identify := c.GetString("identify")
|
||||||
|
book ,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if err == models.ErrPermissionDenied {
|
||||||
|
c.JsonResult(6001,"权限不足")
|
||||||
|
}
|
||||||
|
if err == orm.ErrNoRows {
|
||||||
|
c.JsonResult(6002,"项目不存在")
|
||||||
|
}
|
||||||
|
beego.Error(err)
|
||||||
|
c.JsonResult(6003,"未知错误")
|
||||||
|
}
|
||||||
|
if book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder && book.RoleId != conf.BookEditor{
|
||||||
|
c.JsonResult(6003,"权限不足")
|
||||||
|
}
|
||||||
|
|
||||||
|
go models.NewDocument().ReleaseContent(book.BookId)
|
||||||
|
|
||||||
|
c.JsonResult(0,"发布任务已推送到任务队列,稍后将在后台执行。")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *BookController) SaveSort() {
|
func (c *BookController) SaveSort() {
|
||||||
|
|
|
@ -21,12 +21,135 @@ type DocumentController struct {
|
||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DocumentController) Index() {
|
func isReadable (identify,token string,c *DocumentController) *models.BookResult {
|
||||||
p.TplName = "document/index.tpl"
|
book,err := models.NewBook().FindByFieldFirst("identify",identify)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
beego.Error(err)
|
||||||
|
c.Abort("500")
|
||||||
|
}
|
||||||
|
//如果文档是私有的
|
||||||
|
if book.PrivatelyOwned == 1 {
|
||||||
|
|
||||||
|
is_ok := false
|
||||||
|
|
||||||
|
if c.Member != nil{
|
||||||
|
_, err := models.NewRelationship().FindForRoleId(book.BookId, c.Member.MemberId)
|
||||||
|
if err == nil {
|
||||||
|
is_ok = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if book.PrivateToken != "" && !is_ok {
|
||||||
|
//如果有访问的Token,并且该项目设置了访问Token,并且和用户提供的相匹配,则记录到Session中.
|
||||||
|
//如果用户未提供Token且用户登录了,则判断用户是否参与了该项目.
|
||||||
|
//如果用户未登录,则从Session中读取Token.
|
||||||
|
if token != "" && strings.EqualFold(token, book.PrivateToken) {
|
||||||
|
c.SetSession(identify, token)
|
||||||
|
|
||||||
|
} else if token, ok := c.GetSession(identify).(string); !ok || !strings.EqualFold(token, book.PrivateToken) {
|
||||||
|
c.Abort("403")
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
c.Abort("403")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
bookResult := book.ToBookResult()
|
||||||
|
|
||||||
|
if c.Member != nil {
|
||||||
|
rel ,err := models.NewRelationship().FindByBookIdAndMemberId(bookResult.BookId,c.Member.MemberId)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
bookResult.MemberId = rel.MemberId
|
||||||
|
bookResult.RoleId = rel.RoleId
|
||||||
|
bookResult.RelationshipId = rel.RelationshipId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bookResult
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DocumentController) Read() {
|
func (c *DocumentController) Index() {
|
||||||
p.TplName = "document/kancloud.tpl"
|
c.Prepare()
|
||||||
|
identify := c.Ctx.Input.Param(":key")
|
||||||
|
token := c.GetString("token")
|
||||||
|
|
||||||
|
if identify == "" {
|
||||||
|
c.Abort("404")
|
||||||
|
}
|
||||||
|
bookResult := isReadable(identify,token,c)
|
||||||
|
|
||||||
|
c.TplName = "document/" + bookResult.Theme + "_read.tpl"
|
||||||
|
|
||||||
|
tree,err := models.NewDocument().CreateDocumentTreeForHtml(bookResult.BookId,0)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
beego.Error(err)
|
||||||
|
c.Abort("500")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
c.Data["Model"] = bookResult
|
||||||
|
c.Data["Result"] = template.HTML(tree)
|
||||||
|
c.Data["Title"] = "概要"
|
||||||
|
c.Data["Content"] = bookResult.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *DocumentController) Read() {
|
||||||
|
c.Prepare()
|
||||||
|
identify := c.Ctx.Input.Param(":key")
|
||||||
|
token := c.GetString("token")
|
||||||
|
id := c.GetString(":id")
|
||||||
|
|
||||||
|
if identify == "" || id == ""{
|
||||||
|
c.Abort("404")
|
||||||
|
}
|
||||||
|
bookResult := isReadable(identify,token,c)
|
||||||
|
|
||||||
|
c.TplName = "document/" + bookResult.Theme + "_read.tpl"
|
||||||
|
|
||||||
|
doc := models.NewDocument()
|
||||||
|
|
||||||
|
if doc_id,err := strconv.Atoi(id);err == nil {
|
||||||
|
doc,err = doc.Find(doc_id)
|
||||||
|
if err != nil {
|
||||||
|
beego.Error(err)
|
||||||
|
c.Abort("500")
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
doc,err = doc.FindByFieldFirst("identify",id)
|
||||||
|
if err != nil {
|
||||||
|
beego.Error(err)
|
||||||
|
c.Abort("500")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if doc.BookId != bookResult.BookId {
|
||||||
|
c.Abort("403")
|
||||||
|
}
|
||||||
|
if c.IsAjax() {
|
||||||
|
var data struct{
|
||||||
|
DocTitle string `json:"doc_title"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
data.DocTitle = doc.DocumentName
|
||||||
|
data.Body = doc.Release
|
||||||
|
data.Title = doc.DocumentName + " - Powered by MinDoc"
|
||||||
|
|
||||||
|
c.JsonResult(0,"ok",data)
|
||||||
|
}
|
||||||
|
|
||||||
|
tree,err := models.NewDocument().CreateDocumentTreeForHtml(bookResult.BookId,doc.DocumentId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
beego.Error(err)
|
||||||
|
c.Abort("500")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["Model"] = bookResult
|
||||||
|
c.Data["Result"] = template.HTML(tree)
|
||||||
|
c.Data["Title"] = doc.DocumentName
|
||||||
|
c.Data["Content"] = template.HTML(doc.Release)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DocumentController) Edit() {
|
func (c *DocumentController) Edit() {
|
||||||
|
@ -67,7 +190,7 @@ func (c *DocumentController) Edit() {
|
||||||
c.Data["Result"] = template.JS("[]")
|
c.Data["Result"] = template.JS("[]")
|
||||||
|
|
||||||
trees ,err := models.NewDocument().FindDocumentTree(bookResult.BookId)
|
trees ,err := models.NewDocument().FindDocumentTree(bookResult.BookId)
|
||||||
beego.Info("",trees)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
beego.Error("FindDocumentTree => ", err)
|
beego.Error("FindDocumentTree => ", err)
|
||||||
}else{
|
}else{
|
||||||
|
|
|
@ -1,9 +1,44 @@
|
||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/lifei6671/godoc/models"
|
||||||
|
"github.com/lifei6671/godoc/utils"
|
||||||
|
)
|
||||||
|
|
||||||
type HomeController struct {
|
type HomeController struct {
|
||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *HomeController) Index() {
|
func (c *HomeController) Index() {
|
||||||
p.TplName = "home/index.tpl"
|
c.Prepare()
|
||||||
|
c.TplName = "home/index.tpl"
|
||||||
|
//如果没有开启匿名访问,则跳转到登录页面
|
||||||
|
if !c.EnableAnonymous && c.Member == nil {
|
||||||
|
c.Redirect(beego.URLFor("AccountController.Login"),302)
|
||||||
|
}
|
||||||
|
pageIndex,_ := c.GetInt("page",1)
|
||||||
|
pageSize := 18
|
||||||
|
|
||||||
|
member_id := 0
|
||||||
|
|
||||||
|
if c.Member != nil {
|
||||||
|
member_id = c.Member.MemberId
|
||||||
|
}
|
||||||
|
books,totalCount,err := models.NewBook().FindForHomeToPager(pageIndex,pageSize,member_id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
beego.Error(err)
|
||||||
|
c.Abort("500")
|
||||||
|
}
|
||||||
|
if totalCount > 0 {
|
||||||
|
html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, pageSize, totalCount)
|
||||||
|
|
||||||
|
c.Data["PageHtml"] = html
|
||||||
|
}else {
|
||||||
|
c.Data["PageHtml"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["Lists"] = books
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,18 +320,27 @@ func (c *ManagerController) Setting() {
|
||||||
if !c.Member.IsAdministrator() {
|
if !c.Member.IsAdministrator() {
|
||||||
c.Abort("403")
|
c.Abort("403")
|
||||||
}
|
}
|
||||||
if c.Ctx.Input.IsPost() {
|
|
||||||
|
|
||||||
}
|
|
||||||
options,err := models.NewOption().All()
|
options,err := models.NewOption().All()
|
||||||
|
|
||||||
|
if c.Ctx.Input.IsPost() {
|
||||||
|
for _,item := range options {
|
||||||
|
item.OptionValue = c.GetString(item.OptionName)
|
||||||
|
item.InsertOrUpdate()
|
||||||
|
}
|
||||||
|
c.JsonResult(0,"ok")
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Abort("500")
|
c.Abort("500")
|
||||||
}
|
}
|
||||||
|
c.Data["SITE_TITLE"] = c.Option["SITE_NAME"]
|
||||||
|
|
||||||
for _,item := range options {
|
for _,item := range options {
|
||||||
c.Data[item.OptionName] = item
|
c.Data[item.OptionName] = item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ManagerController) Comments() {
|
func (c *ManagerController) Comments() {
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
## 日志存放目录
|
|
1
main.go
1
main.go
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
_ "github.com/lifei6671/godoc/routers"
|
_ "github.com/lifei6671/godoc/routers"
|
||||||
|
_ "github.com/garyburd/redigo/redis"
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/lifei6671/godoc/commands"
|
"github.com/lifei6671/godoc/commands"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
"github.com/lifei6671/godoc/conf"
|
"github.com/lifei6671/godoc/conf"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Book struct .
|
// Book struct .
|
||||||
|
@ -32,8 +33,10 @@ type Book struct {
|
||||||
// CommentStatus 评论设置的状态:open 为允许所有人评论,closed 为不允许评论, group_only 仅允许参与者评论 ,registered_only 仅允许注册者评论.
|
// CommentStatus 评论设置的状态:open 为允许所有人评论,closed 为不允许评论, group_only 仅允许参与者评论 ,registered_only 仅允许注册者评论.
|
||||||
CommentStatus string `orm:"column(comment_status);size(20);default(open)" json:"comment_status"`
|
CommentStatus string `orm:"column(comment_status);size(20);default(open)" json:"comment_status"`
|
||||||
CommentCount int `orm:"column(comment_count);type(int)" json:"comment_count"`
|
CommentCount int `orm:"column(comment_count);type(int)" json:"comment_count"`
|
||||||
Cover string `orm:"column();size(1000)" json:"cover"`
|
//封面地址
|
||||||
|
Cover string `orm:"column(cover);size(1000)" json:"cover"`
|
||||||
|
//主题风格
|
||||||
|
Theme string `orm:"columen(theme);size(255);default(default)" json:"theme"`
|
||||||
// CreateTime 创建时间 .
|
// CreateTime 创建时间 .
|
||||||
CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
|
CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
|
||||||
MemberId int `orm:"column(member_id);size(100)" json:"member_id"`
|
MemberId int `orm:"column(member_id);size(100)" json:"member_id"`
|
||||||
|
@ -109,23 +112,27 @@ func (m *Book) Update(cols... string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Book) FindByField(field string,value interface{}) ([]Book,error) {
|
//根据指定字段查询结果集.
|
||||||
|
func (m *Book) FindByField(field string,value interface{}) ([]*Book,error) {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
|
|
||||||
var books []Book
|
var books []*Book
|
||||||
_,err := o.QueryTable(conf.GetDatabasePrefix() + m.TableName()).Filter(field,value).All(&books)
|
_,err := o.QueryTable(m.TableNameWithPrefix()).Filter(field,value).All(&books)
|
||||||
|
|
||||||
return books,err
|
return books,err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//根据指定字段查询一个结果.
|
||||||
func (m *Book) FindByFieldFirst(field string,value interface{})(*Book,error) {
|
func (m *Book) FindByFieldFirst(field string,value interface{})(*Book,error) {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
|
|
||||||
err := o.QueryTable(conf.GetDatabasePrefix() + m.TableName()).Filter(field,value).One(m)
|
err := o.QueryTable(m.TableNameWithPrefix()).Filter(field,value).One(m)
|
||||||
|
|
||||||
return m,err
|
return m,err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//分页查询指定用户的项目
|
||||||
func (m *Book) FindToPager(pageIndex, pageSize ,memberId int) (books []*BookResult,totalCount int,err error){
|
func (m *Book) FindToPager(pageIndex, pageSize ,memberId int) (books []*BookResult,totalCount int,err error){
|
||||||
|
|
||||||
relationship := NewRelationship()
|
relationship := NewRelationship()
|
||||||
|
@ -242,11 +249,75 @@ func (m *Book) ThoroughDeleteBook(id int) error {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Book) FindForHomeToPager(pageIndex, pageSize ,member_id int) (books []*BookResult,totalCount int,err error) {
|
||||||
|
o := orm.NewOrm()
|
||||||
|
|
||||||
|
offset := (pageIndex - 1) * pageSize
|
||||||
|
//如果是登录用户
|
||||||
|
if member_id > 0 {
|
||||||
|
sql1 := "SELECT COUNT(*) FROM md_books AS book LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.member_id = ? WHERE relationship_id > 0 OR book.privately_owned = 0"
|
||||||
|
|
||||||
|
err = o.Raw(sql1,member_id).QueryRow(&totalCount)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sql2 := `SELECT book.*,rel1.*,member.account AS create_name FROM md_books AS book
|
||||||
|
LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.member_id = ?
|
||||||
|
LEFT JOIN md_relationship AS rel1 ON rel1.book_id = book.book_id AND rel1.role_id = 0
|
||||||
|
LEFT JOIN md_members AS member ON rel1.member_id = member.member_id
|
||||||
|
WHERE rel.relationship_id > 0 OR book.privately_owned = 0 ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?`
|
||||||
|
|
||||||
|
_,err = o.Raw(sql2,member_id,offset,pageSize).QueryRows(&books)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}else{
|
||||||
|
count,err1 := o.QueryTable(m.TableNameWithPrefix()).Filter("privately_owned",0).Count()
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
err = err1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
totalCount = int(count)
|
||||||
|
|
||||||
|
sql := `SELECT book.*,rel.*,member.account AS create_name FROM md_books AS book
|
||||||
|
LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.role_id = 0
|
||||||
|
LEFT JOIN md_members AS member ON rel.member_id = member.member_id
|
||||||
|
WHERE book.privately_owned = 0 ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?`
|
||||||
|
|
||||||
|
_,err = o.Raw(sql,offset,pageSize).QueryRows(&books)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (book *Book) ToBookResult() *BookResult {
|
||||||
|
|
||||||
|
m := NewBookResult()
|
||||||
|
|
||||||
|
m.BookId = book.BookId
|
||||||
|
m.BookName = book.BookName
|
||||||
|
m.Identify = book.Identify
|
||||||
|
m.OrderIndex = book.OrderIndex
|
||||||
|
m.Description = strings.Replace(book.Description, "\r\n", "<br/>", -1)
|
||||||
|
m.PrivatelyOwned = book.PrivatelyOwned
|
||||||
|
m.PrivateToken = book.PrivateToken
|
||||||
|
m.DocCount = book.DocCount
|
||||||
|
m.CommentStatus = book.CommentStatus
|
||||||
|
m.CommentCount = book.CommentCount
|
||||||
|
m.CreateTime = book.CreateTime
|
||||||
|
m.ModifyTime = book.ModifyTime
|
||||||
|
m.Cover = book.Cover
|
||||||
|
m.Label = book.Label
|
||||||
|
m.Status = book.Status
|
||||||
|
m.Editor = book.Editor
|
||||||
|
m.Theme = book.Theme
|
||||||
|
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
"strings"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/lifei6671/godoc/conf"
|
"github.com/lifei6671/godoc/conf"
|
||||||
)
|
)
|
||||||
|
@ -23,6 +23,7 @@ type BookResult struct {
|
||||||
CreateName string `json:"create_name"`
|
CreateName string `json:"create_name"`
|
||||||
ModifyTime time.Time `json:"modify_time"`
|
ModifyTime time.Time `json:"modify_time"`
|
||||||
Cover string `json:"cover"`
|
Cover string `json:"cover"`
|
||||||
|
Theme string `json:"theme"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
MemberId int `json:"member_id"`
|
MemberId int `json:"member_id"`
|
||||||
Editor string `json:"editor"`
|
Editor string `json:"editor"`
|
||||||
|
@ -39,6 +40,7 @@ func NewBookResult() *BookResult {
|
||||||
return &BookResult{}
|
return &BookResult{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 根据项目标识查询项目以及指定用户权限的信息.
|
// 根据项目标识查询项目以及指定用户权限的信息.
|
||||||
func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult,error) {
|
func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult,error) {
|
||||||
if identify == "" || member_id <= 0 {
|
if identify == "" || member_id <= 0 {
|
||||||
|
@ -77,24 +79,9 @@ func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult,
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.BookId = book.BookId
|
m = book.ToBookResult()
|
||||||
m.BookName = book.BookName
|
|
||||||
m.Identify = book.Identify
|
|
||||||
m.OrderIndex = book.OrderIndex
|
|
||||||
m.Description = strings.Replace(book.Description, "\r\n", "<br/>", -1)
|
|
||||||
m.PrivatelyOwned = book.PrivatelyOwned
|
|
||||||
m.PrivateToken = book.PrivateToken
|
|
||||||
m.DocCount = book.DocCount
|
|
||||||
m.CommentStatus = book.CommentStatus
|
|
||||||
m.CommentCount = book.CommentCount
|
|
||||||
m.CreateTime = book.CreateTime
|
|
||||||
m.CreateName = member.Account
|
|
||||||
m.ModifyTime = book.ModifyTime
|
|
||||||
m.Cover = book.Cover
|
|
||||||
m.Label = book.Label
|
|
||||||
m.Status = book.Status
|
|
||||||
m.Editor = book.Editor
|
|
||||||
|
|
||||||
|
m.CreateName = member.Account
|
||||||
m.MemberId = relationship.MemberId
|
m.MemberId = relationship.MemberId
|
||||||
m.RoleId = relationship.RoleId
|
m.RoleId = relationship.RoleId
|
||||||
m.RelationshipId = relationship.RelationshipId
|
m.RelationshipId = relationship.RelationshipId
|
||||||
|
|
|
@ -112,7 +112,17 @@ func (m *Document) RecursiveDocument(doc_id int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Document) ReleaseContent(book_id int) {
|
||||||
|
|
||||||
|
o := orm.NewOrm()
|
||||||
|
|
||||||
|
_,err := o.Raw("UPDATE md_documents SET `release` = content WHERE book_id =?",book_id).Exec()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
beego.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
|
"bytes"
|
||||||
|
"strconv"
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
"html/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DocumentTree struct {
|
type DocumentTree struct {
|
||||||
|
@ -9,6 +13,7 @@ type DocumentTree struct {
|
||||||
DocumentName string `json:"text"`
|
DocumentName string `json:"text"`
|
||||||
ParentId interface{} `json:"parent"`
|
ParentId interface{} `json:"parent"`
|
||||||
Identify string `json:"identify"`
|
Identify string `json:"identify"`
|
||||||
|
BookIdentify string `json:"-"`
|
||||||
Version int64 `json:"version"`
|
Version int64 `json:"version"`
|
||||||
State *DocumentSelected `json:"state,omitempty"`
|
State *DocumentSelected `json:"state,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -17,7 +22,7 @@ type DocumentSelected struct {
|
||||||
Opened bool `json:"opened"`
|
Opened bool `json:"opened"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//获取项目的文档树状结构
|
||||||
func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree,error){
|
func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree,error){
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
|
|
||||||
|
@ -30,6 +35,7 @@ func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree,error){
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return trees,err
|
return trees,err
|
||||||
}
|
}
|
||||||
|
book,_ := NewBook().Find(book_id)
|
||||||
|
|
||||||
trees = make([]*DocumentTree,count)
|
trees = make([]*DocumentTree,count)
|
||||||
|
|
||||||
|
@ -41,6 +47,7 @@ func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree,error){
|
||||||
tree.DocumentId = item.DocumentId
|
tree.DocumentId = item.DocumentId
|
||||||
tree.Identify = item.Identify
|
tree.Identify = item.Identify
|
||||||
tree.Version = item.Version
|
tree.Version = item.Version
|
||||||
|
tree.BookIdentify = book.Identify
|
||||||
if item.ParentId > 0 {
|
if item.ParentId > 0 {
|
||||||
tree.ParentId = item.ParentId
|
tree.ParentId = item.ParentId
|
||||||
}else{
|
}else{
|
||||||
|
@ -54,3 +61,102 @@ func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree,error){
|
||||||
|
|
||||||
return trees,nil
|
return trees,nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Document) CreateDocumentTreeForHtml(book_id, selected_id int) (string,error) {
|
||||||
|
trees,err := m.FindDocumentTree(book_id)
|
||||||
|
if err != nil {
|
||||||
|
return "",err
|
||||||
|
}
|
||||||
|
parent_id := getSelectedNode(trees,selected_id)
|
||||||
|
|
||||||
|
buf := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
getDocumentTree(trees,0,selected_id,parent_id,buf)
|
||||||
|
|
||||||
|
return buf.String(),nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//使用递归的方式获取指定ID的顶级ID
|
||||||
|
func getSelectedNode(array []*DocumentTree, parent_id int) int {
|
||||||
|
|
||||||
|
for _,item := range array {
|
||||||
|
if _,ok := item.ParentId.(string); ok && item.DocumentId == parent_id {
|
||||||
|
return item.DocumentId
|
||||||
|
}else if pid,ok := item.ParentId.(int); ok && item.DocumentId == parent_id{
|
||||||
|
return getSelectedNode(array,pid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDocumentTree(array []*DocumentTree,parent_id int,selected_id int,selected_parent_id int,buf *bytes.Buffer) {
|
||||||
|
buf.WriteString("<ul>")
|
||||||
|
|
||||||
|
for _,item := range array {
|
||||||
|
pid := 0
|
||||||
|
|
||||||
|
if p,ok := item.ParentId.(int);ok {
|
||||||
|
pid = p
|
||||||
|
}
|
||||||
|
if pid == parent_id {
|
||||||
|
/**
|
||||||
|
$selected = $item['doc_id'] == $selected_id ? ' class="jstree-clicked"' : '';
|
||||||
|
$selected_li = $item['doc_id'] == $selected_parent_id ? ' class="jstree-open"' : '';
|
||||||
|
|
||||||
|
$menu .= '<li id="'.$item['doc_id'].'"'.$selected_li.'><a href="'. route('document.show',['doc_id'=> $item['doc_id']]) .'" title="' . htmlspecialchars($item['doc_name']) . '"'.$selected.'>' . $item['doc_name'] .'</a>';
|
||||||
|
|
||||||
|
$key = array_search($item['doc_id'], array_column($array, 'parent_id'));
|
||||||
|
|
||||||
|
if ($key !== false) {
|
||||||
|
self::createTree($item['doc_id'], $array,$selected_id,$selected_parent_id);
|
||||||
|
}
|
||||||
|
$menu .= '</li>';
|
||||||
|
*/
|
||||||
|
selected := ""
|
||||||
|
if item.DocumentId == selected_id {
|
||||||
|
selected = ` class="jstree-clicked"`
|
||||||
|
}
|
||||||
|
selected_li := ""
|
||||||
|
if item.DocumentId == selected_parent_id {
|
||||||
|
selected_li = ` class="jstree-open"`
|
||||||
|
}
|
||||||
|
buf.WriteString("<li id=\"")
|
||||||
|
buf.WriteString(strconv.Itoa(item.DocumentId))
|
||||||
|
buf.WriteString("\"")
|
||||||
|
buf.WriteString(selected_li)
|
||||||
|
buf.WriteString("><a href=\"")
|
||||||
|
if item.Identify != ""{
|
||||||
|
uri := beego.URLFor("DocumentController.Read",":key",item.BookIdentify,":id" ,item.Identify)
|
||||||
|
buf.WriteString(uri)
|
||||||
|
}else{
|
||||||
|
uri := beego.URLFor("DocumentController.Read",":key",item.BookIdentify,":id" ,item.DocumentId)
|
||||||
|
buf.WriteString(uri)
|
||||||
|
}
|
||||||
|
buf.WriteString("\" title=\"")
|
||||||
|
buf.WriteString(template.HTMLEscapeString(item.DocumentName) + "\"")
|
||||||
|
buf.WriteString(selected + ">")
|
||||||
|
buf.WriteString(template.HTMLEscapeString(item.DocumentName) + "</a>")
|
||||||
|
|
||||||
|
for _,sub := range array {
|
||||||
|
if p,ok := sub.ParentId.(int);ok && p == item.DocumentId{
|
||||||
|
getDocumentTree(array,p,selected_id,selected_parent_id,buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.WriteString("</li>")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.WriteString("</ul>")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ func (m *Member) Login(account string,password string) (*Member,error) {
|
||||||
ok,err := utils.PasswordVerify(member.Password,password) ;
|
ok,err := utils.PasswordVerify(member.Password,password) ;
|
||||||
|
|
||||||
if ok && err == nil {
|
if ok && err == nil {
|
||||||
|
m.ResolveRoleName()
|
||||||
return member,nil
|
return member,nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,22 +68,23 @@ func (m *Member) Login(account string,password string) (*Member,error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add 添加一个用户.
|
// Add 添加一个用户.
|
||||||
func (member *Member) Add () (error) {
|
func (m *Member) Add () (error) {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
|
|
||||||
hash ,err := utils.PasswordHash(member.Password);
|
hash ,err := utils.PasswordHash(m.Password);
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
member.Password = hash
|
m.Password = hash
|
||||||
|
|
||||||
_,err = o.Insert(member)
|
_,err = o.Insert(m)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
m.ResolveRoleName()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +105,11 @@ func (m *Member) Find(id int) error{
|
||||||
if err := o.Read(m); err != nil {
|
if err := o.Read(m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
m.ResolveRoleName()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Member) ResolveRoleName (){
|
||||||
if m.Role == conf.MemberSuperRole {
|
if m.Role == conf.MemberSuperRole {
|
||||||
m.RoleName = "超级管理员"
|
m.RoleName = "超级管理员"
|
||||||
}else if m.Role == conf.MemberAdminRole {
|
}else if m.Role == conf.MemberAdminRole {
|
||||||
|
@ -110,17 +117,6 @@ func (m *Member) Find(id int) error{
|
||||||
}else if m.Role == conf.MemberGeneralRole {
|
}else if m.Role == conf.MemberGeneralRole {
|
||||||
m.RoleName = "普通用户"
|
m.RoleName = "普通用户"
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Member) ResolveRoleName (){
|
|
||||||
if m.Role == 0 {
|
|
||||||
m.RoleName = "超级管理员"
|
|
||||||
}else if m.Role == 1 {
|
|
||||||
m.RoleName = "管理员"
|
|
||||||
}else if m.Role == 2 {
|
|
||||||
m.RoleName = "普通用户"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Member) FindByAccount (account string) (*Member,error) {
|
func (m *Member) FindByAccount (account string) (*Member,error) {
|
||||||
|
@ -154,13 +150,7 @@ func (m *Member) FindToPager(pageIndex, pageSize int) ([]*Member,int64,error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _,m := range members {
|
for _,m := range members {
|
||||||
if m.Role == 0 {
|
m.ResolveRoleName()
|
||||||
m.RoleName = "超级管理员"
|
|
||||||
}else if m.Role == 1 {
|
|
||||||
m.RoleName = "管理员"
|
|
||||||
}else if m.Role == 2 {
|
|
||||||
m.RoleName = "普通用户"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return members,totalCount,nil
|
return members,totalCount,nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,9 +67,10 @@ func GetOptionValue(key, def string) string {
|
||||||
func (p *Option) InsertOrUpdate() error {
|
func (p *Option) InsertOrUpdate() error {
|
||||||
|
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if p.OptionId > 0 {
|
if p.OptionId > 0 {
|
||||||
_,err = o.Update(o)
|
_,err = o.Update(p)
|
||||||
}else{
|
}else{
|
||||||
_,err = o.Insert(p)
|
_,err = o.Insert(p)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package routers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/astaxie/beego/context"
|
||||||
|
"github.com/lifei6671/godoc/conf"
|
||||||
|
"github.com/lifei6671/godoc/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var FilterUser = func(ctx *context.Context) {
|
||||||
|
_, ok := ctx.Input.Session(conf.LoginSessionName).(models.Member)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
ctx.Redirect(302, beego.URLFor("AccountController.Login"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
beego.InsertFilter("/manager",beego.BeforeRouter,FilterUser)
|
||||||
|
beego.InsertFilter("/manager/*",beego.BeforeRouter,FilterUser)
|
||||||
|
beego.InsertFilter("/setting",beego.BeforeRouter,FilterUser)
|
||||||
|
beego.InsertFilter("/setting/*",beego.BeforeRouter,FilterUser)
|
||||||
|
beego.InsertFilter("/book",beego.BeforeRouter,FilterUser)
|
||||||
|
beego.InsertFilter("/book/*",beego.BeforeRouter,FilterUser)
|
||||||
|
beego.InsertFilter("/api/*",beego.BeforeRouter,FilterUser)
|
||||||
|
}
|
|
@ -12,9 +12,10 @@ func init() {
|
||||||
beego.Router("/logout", &controllers.AccountController{},"*:Logout")
|
beego.Router("/logout", &controllers.AccountController{},"*:Logout")
|
||||||
beego.Router("/register", &controllers.AccountController{},"*:Register")
|
beego.Router("/register", &controllers.AccountController{},"*:Register")
|
||||||
beego.Router("/find_password", &controllers.AccountController{},"*:FindPassword")
|
beego.Router("/find_password", &controllers.AccountController{},"*:FindPassword")
|
||||||
|
beego.Router("/captcha", &controllers.AccountController{},"*:Captcha")
|
||||||
|
|
||||||
beego.Router("/manager", &controllers.ManagerController{},"*:Index")
|
beego.Router("/manager", &controllers.ManagerController{},"*:Index")
|
||||||
beego.Router("/manager/users", &controllers.ManagerController{})
|
beego.Router("/manager/users", &controllers.ManagerController{},"*:Users")
|
||||||
beego.Router("/manager/member/create", &controllers.ManagerController{},"post:CreateMember")
|
beego.Router("/manager/member/create", &controllers.ManagerController{},"post:CreateMember")
|
||||||
beego.Router("/manager/member/update-member-status",&controllers.ManagerController{},"post:UpdateMemberStatus")
|
beego.Router("/manager/member/update-member-status",&controllers.ManagerController{},"post:UpdateMemberStatus")
|
||||||
beego.Router("/manager/member/change-member-role", &controllers.ManagerController{},"post:ChangeMemberRole")
|
beego.Router("/manager/member/change-member-role", &controllers.ManagerController{},"post:ChangeMemberRole")
|
||||||
|
@ -47,15 +48,15 @@ func init() {
|
||||||
beego.Router("/book/setting/token", &controllers.BookController{},"post:CreateToken")
|
beego.Router("/book/setting/token", &controllers.BookController{},"post:CreateToken")
|
||||||
beego.Router("/book/setting/delete", &controllers.BookController{},"post:Delete")
|
beego.Router("/book/setting/delete", &controllers.BookController{},"post:Delete")
|
||||||
|
|
||||||
beego.Router("/docs/:key/edit/?:id", &controllers.DocumentController{},"*:Edit")
|
beego.Router("/api/:key/edit/?:id", &controllers.DocumentController{},"*:Edit")
|
||||||
beego.Router("/docs/upload",&controllers.DocumentController{},"post:Upload")
|
beego.Router("/api/upload",&controllers.DocumentController{},"post:Upload")
|
||||||
beego.Router("/docs/:key/create",&controllers.DocumentController{},"post:Create")
|
beego.Router("/api/:key/create",&controllers.DocumentController{},"post:Create")
|
||||||
beego.Router("/docs/:key/delete", &controllers.DocumentController{},"post:Delete")
|
beego.Router("/api/:key/delete", &controllers.DocumentController{},"post:Delete")
|
||||||
beego.Router("/docs/:key/content/?:id",&controllers.DocumentController{},"*:Content")
|
beego.Router("/api/:key/content/?:id",&controllers.DocumentController{},"*:Content")
|
||||||
|
|
||||||
|
|
||||||
beego.Router("/docs/:key", &controllers.DocumentController{},"*:Index")
|
beego.Router("/docs/:key", &controllers.DocumentController{},"*:Index")
|
||||||
beego.Router("/docs/:key/:id", &controllers.DocumentController{},"*:Read")
|
beego.Router("/docs/:key/:id", &controllers.DocumentController{},"*:Read")
|
||||||
|
|
||||||
beego.Router("/:key/attach_files/:attach_id",&controllers.DocumentController{},"get:DownloadAttachment")
|
beego.Router("/attach_files/:key/:attach_id",&controllers.DocumentController{},"get:DownloadAttachment")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd /go/src/github.com/lifei6671/godoc/
|
||||||
|
|
||||||
|
goFile="godoc"
|
||||||
|
|
||||||
|
|
||||||
|
chmod +x $goFile
|
||||||
|
|
||||||
|
if [ ! -f "conf/app.conf" ] ; then
|
||||||
|
cp conf/app.conf.example conf/app.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z $db_host ] ; then
|
||||||
|
sed -i 's/^db_host.*/db_host='$db_host'/g' conf/app.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z $db_port ] ; then
|
||||||
|
sed -i 's/^db_port.*/db_port='$db_port'/g' conf/app.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z $db_database ] ; then
|
||||||
|
sed -i 's/^db_database.*/db_database='$db_database'/g' conf/app.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z $db_username ] ; then
|
||||||
|
sed -i 's/^db_username.*/db_username='$db_username'/g' conf/app.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z $db_password ] ; then
|
||||||
|
sed -i 's/^db_password.*/db_password='$db_password'/g' conf/app.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z $httpport ] ; then
|
||||||
|
sed -i 's/^httpport.*/httpport='$httpport'/g' conf/app.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
./$goFile
|
|
@ -141,6 +141,71 @@ h6 {
|
||||||
zoom:1;border-bottom: 1px solid #ddd
|
zoom:1;border-bottom: 1px solid #ddd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.m-manual .manual-tab .tab-util {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: -14px
|
||||||
|
}
|
||||||
|
.m-manual .manual-tab .tab-util .item {
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 4px
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-fullscreen-switch {
|
||||||
|
display: block
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-fullscreen-switch .open,.manual-fullscreen-switch .close {
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #5cb85c;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: #fff;
|
||||||
|
position: relative;
|
||||||
|
font-size: 16px;
|
||||||
|
vertical-align: top;
|
||||||
|
opacity : 1;
|
||||||
|
text-shadow:none;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.manual-fullscreen-switch .open:hover,.manual-fullscreen-switch .close:hover {
|
||||||
|
background-color: #449d44;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-fullscreen-switch .open:before,.manual-fullscreen-switch .close:before {
|
||||||
|
position: absolute;
|
||||||
|
top: 7px;
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-fullscreen-switch .open {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.m-manual.manual-fullscreen-active .manual-fullscreen-switch {
|
||||||
|
/*margin-top: 30px;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.m-manual.manual-fullscreen-active .manual-fullscreen-switch .open {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.m-manual.manual-fullscreen-active .manual-fullscreen-switch .close {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.m-manual.manual-fullscreen-active .manual-left .m-copyright,.m-manual.manual-fullscreen-active .manual-left .tab-navg,.m-manual.manual-fullscreen-active .manual-left .tab-wrap{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.m-manual.manual-fullscreen-active .manual-left{
|
||||||
|
width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.m-manual .manual-tab .tab-navg:after {
|
.m-manual .manual-tab .tab-navg:after {
|
||||||
content: '.';
|
content: '.';
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -149,7 +214,7 @@ h6 {
|
||||||
line-height: 9;
|
line-height: 9;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
clear: both;
|
clear: both;
|
||||||
visibility: hidden
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.m-manual .manual-tab .tab-navg .navg-item {
|
.m-manual .manual-tab .tab-navg .navg-item {
|
||||||
|
@ -246,6 +311,9 @@ h6 {
|
||||||
-o-transition-timing-function: linear;
|
-o-transition-timing-function: linear;
|
||||||
-o-transition-delay: 0s
|
-o-transition-delay: 0s
|
||||||
}
|
}
|
||||||
|
.m-manual.manual-fullscreen-active .manual-right{
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
.m-manual .manual-right .manual-article{
|
.m-manual .manual-right .manual-article{
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
@ -266,7 +334,9 @@ h6 {
|
||||||
color: #7e888b
|
color: #7e888b
|
||||||
}
|
}
|
||||||
.manual-article .article-content{
|
.manual-article .article-content{
|
||||||
max-width: 980px;
|
min-width: 980px;
|
||||||
|
max-width: 98%;
|
||||||
|
padding: 10px 20px;
|
||||||
margin-left: auto!important;
|
margin-left: auto!important;
|
||||||
margin-right: auto!important
|
margin-right: auto!important
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,7 @@ textarea{
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.manual-list .list-item .manual-item-standard .cover {
|
.manual-list .list-item .manual-item-standard .cover {
|
||||||
border: 1px solid #f3f3f3;
|
border: 1px solid #999999;
|
||||||
width: 171px;
|
width: 171px;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
|
@ -84,6 +84,7 @@ $(function () {
|
||||||
if(Object.prototype.toString.call(window.documentCategory) === '[object Array]' && window.documentCategory.length > 0){
|
if(Object.prototype.toString.call(window.documentCategory) === '[object Array]' && window.documentCategory.length > 0){
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url : window.releaseURL,
|
url : window.releaseURL,
|
||||||
|
data :{"identify" : window.book.identify },
|
||||||
type : "post",
|
type : "post",
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function (res) {
|
success : function (res) {
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/* Make clicks pass-through */
|
||||||
|
#nprogress {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nprogress .bar {
|
||||||
|
background: #29d;
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1031;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fancy blur effect */
|
||||||
|
#nprogress .peg {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 10px #29d, 0 0 5px #29d;
|
||||||
|
opacity: 1.0;
|
||||||
|
|
||||||
|
-webkit-transform: rotate(3deg) translate(0px, -4px);
|
||||||
|
-ms-transform: rotate(3deg) translate(0px, -4px);
|
||||||
|
transform: rotate(3deg) translate(0px, -4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove these to get rid of the spinner */
|
||||||
|
#nprogress .spinner {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1031;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nprogress .spinner-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
border: solid 2px transparent;
|
||||||
|
border-top-color: #29d;
|
||||||
|
border-left-color: #29d;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
-webkit-animation: nprogress-spinner 400ms linear infinite;
|
||||||
|
animation: nprogress-spinner 400ms linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nprogress-custom-parent {
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nprogress-custom-parent #nprogress .spinner,
|
||||||
|
.nprogress-custom-parent #nprogress .bar {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes nprogress-spinner {
|
||||||
|
0% { -webkit-transform: rotate(0deg); }
|
||||||
|
100% { -webkit-transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
@keyframes nprogress-spinner {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,476 @@
|
||||||
|
/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
|
||||||
|
* @license MIT */
|
||||||
|
|
||||||
|
;(function(root, factory) {
|
||||||
|
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
define(factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
module.exports = factory();
|
||||||
|
} else {
|
||||||
|
root.NProgress = factory();
|
||||||
|
}
|
||||||
|
|
||||||
|
})(this, function() {
|
||||||
|
var NProgress = {};
|
||||||
|
|
||||||
|
NProgress.version = '0.2.0';
|
||||||
|
|
||||||
|
var Settings = NProgress.settings = {
|
||||||
|
minimum: 0.08,
|
||||||
|
easing: 'ease',
|
||||||
|
positionUsing: '',
|
||||||
|
speed: 200,
|
||||||
|
trickle: true,
|
||||||
|
trickleRate: 0.02,
|
||||||
|
trickleSpeed: 800,
|
||||||
|
showSpinner: true,
|
||||||
|
barSelector: '[role="bar"]',
|
||||||
|
spinnerSelector: '[role="spinner"]',
|
||||||
|
parent: 'body',
|
||||||
|
template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates configuration.
|
||||||
|
*
|
||||||
|
* NProgress.configure({
|
||||||
|
* minimum: 0.1
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
NProgress.configure = function(options) {
|
||||||
|
var key, value;
|
||||||
|
for (key in options) {
|
||||||
|
value = options[key];
|
||||||
|
if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last number.
|
||||||
|
*/
|
||||||
|
|
||||||
|
NProgress.status = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.
|
||||||
|
*
|
||||||
|
* NProgress.set(0.4);
|
||||||
|
* NProgress.set(1.0);
|
||||||
|
*/
|
||||||
|
|
||||||
|
NProgress.set = function(n) {
|
||||||
|
var started = NProgress.isStarted();
|
||||||
|
|
||||||
|
n = clamp(n, Settings.minimum, 1);
|
||||||
|
NProgress.status = (n === 1 ? null : n);
|
||||||
|
|
||||||
|
var progress = NProgress.render(!started),
|
||||||
|
bar = progress.querySelector(Settings.barSelector),
|
||||||
|
speed = Settings.speed,
|
||||||
|
ease = Settings.easing;
|
||||||
|
|
||||||
|
progress.offsetWidth; /* Repaint */
|
||||||
|
|
||||||
|
queue(function(next) {
|
||||||
|
// Set positionUsing if it hasn't already been set
|
||||||
|
if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS();
|
||||||
|
|
||||||
|
// Add transition
|
||||||
|
css(bar, barPositionCSS(n, speed, ease));
|
||||||
|
|
||||||
|
if (n === 1) {
|
||||||
|
// Fade out
|
||||||
|
css(progress, {
|
||||||
|
transition: 'none',
|
||||||
|
opacity: 1
|
||||||
|
});
|
||||||
|
progress.offsetWidth; /* Repaint */
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
css(progress, {
|
||||||
|
transition: 'all ' + speed + 'ms linear',
|
||||||
|
opacity: 0
|
||||||
|
});
|
||||||
|
setTimeout(function() {
|
||||||
|
NProgress.remove();
|
||||||
|
next();
|
||||||
|
}, speed);
|
||||||
|
}, speed);
|
||||||
|
} else {
|
||||||
|
setTimeout(next, speed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
NProgress.isStarted = function() {
|
||||||
|
return typeof NProgress.status === 'number';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the progress bar.
|
||||||
|
* This is the same as setting the status to 0%, except that it doesn't go backwards.
|
||||||
|
*
|
||||||
|
* NProgress.start();
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
NProgress.start = function() {
|
||||||
|
if (!NProgress.status) NProgress.set(0);
|
||||||
|
|
||||||
|
var work = function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
if (!NProgress.status) return;
|
||||||
|
NProgress.trickle();
|
||||||
|
work();
|
||||||
|
}, Settings.trickleSpeed);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Settings.trickle) work();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides the progress bar.
|
||||||
|
* This is the *sort of* the same as setting the status to 100%, with the
|
||||||
|
* difference being `done()` makes some placebo effect of some realistic motion.
|
||||||
|
*
|
||||||
|
* NProgress.done();
|
||||||
|
*
|
||||||
|
* If `true` is passed, it will show the progress bar even if its hidden.
|
||||||
|
*
|
||||||
|
* NProgress.done(true);
|
||||||
|
*/
|
||||||
|
|
||||||
|
NProgress.done = function(force) {
|
||||||
|
if (!force && !NProgress.status) return this;
|
||||||
|
|
||||||
|
return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments by a random amount.
|
||||||
|
*/
|
||||||
|
|
||||||
|
NProgress.inc = function(amount) {
|
||||||
|
var n = NProgress.status;
|
||||||
|
|
||||||
|
if (!n) {
|
||||||
|
return NProgress.start();
|
||||||
|
} else {
|
||||||
|
if (typeof amount !== 'number') {
|
||||||
|
amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
n = clamp(n + amount, 0, 0.994);
|
||||||
|
return NProgress.set(n);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NProgress.trickle = function() {
|
||||||
|
return NProgress.inc(Math.random() * Settings.trickleRate);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for all supplied jQuery promises and
|
||||||
|
* increases the progress as the promises resolve.
|
||||||
|
*
|
||||||
|
* @param $promise jQUery Promise
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
var initial = 0, current = 0;
|
||||||
|
|
||||||
|
NProgress.promise = function($promise) {
|
||||||
|
if (!$promise || $promise.state() === "resolved") {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current === 0) {
|
||||||
|
NProgress.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
initial++;
|
||||||
|
current++;
|
||||||
|
|
||||||
|
$promise.always(function() {
|
||||||
|
current--;
|
||||||
|
if (current === 0) {
|
||||||
|
initial = 0;
|
||||||
|
NProgress.done();
|
||||||
|
} else {
|
||||||
|
NProgress.set((initial - current) / initial);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) renders the progress bar markup based on the `template`
|
||||||
|
* setting.
|
||||||
|
*/
|
||||||
|
|
||||||
|
NProgress.render = function(fromStart) {
|
||||||
|
if (NProgress.isRendered()) return document.getElementById('nprogress');
|
||||||
|
|
||||||
|
addClass(document.documentElement, 'nprogress-busy');
|
||||||
|
|
||||||
|
var progress = document.createElement('div');
|
||||||
|
progress.id = 'nprogress';
|
||||||
|
progress.innerHTML = Settings.template;
|
||||||
|
|
||||||
|
var bar = progress.querySelector(Settings.barSelector),
|
||||||
|
perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0),
|
||||||
|
parent = document.querySelector(Settings.parent),
|
||||||
|
spinner;
|
||||||
|
|
||||||
|
css(bar, {
|
||||||
|
transition: 'all 0 linear',
|
||||||
|
transform: 'translate3d(' + perc + '%,0,0)'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!Settings.showSpinner) {
|
||||||
|
spinner = progress.querySelector(Settings.spinnerSelector);
|
||||||
|
spinner && removeElement(spinner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent != document.body) {
|
||||||
|
addClass(parent, 'nprogress-custom-parent');
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.appendChild(progress);
|
||||||
|
return progress;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the element. Opposite of render().
|
||||||
|
*/
|
||||||
|
|
||||||
|
NProgress.remove = function() {
|
||||||
|
removeClass(document.documentElement, 'nprogress-busy');
|
||||||
|
removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent');
|
||||||
|
var progress = document.getElementById('nprogress');
|
||||||
|
progress && removeElement(progress);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the progress bar is rendered.
|
||||||
|
*/
|
||||||
|
|
||||||
|
NProgress.isRendered = function() {
|
||||||
|
return !!document.getElementById('nprogress');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine which positioning CSS rule to use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
NProgress.getPositioningCSS = function() {
|
||||||
|
// Sniff on document.body.style
|
||||||
|
var bodyStyle = document.body.style;
|
||||||
|
|
||||||
|
// Sniff prefixes
|
||||||
|
var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' :
|
||||||
|
('MozTransform' in bodyStyle) ? 'Moz' :
|
||||||
|
('msTransform' in bodyStyle) ? 'ms' :
|
||||||
|
('OTransform' in bodyStyle) ? 'O' : '';
|
||||||
|
|
||||||
|
if (vendorPrefix + 'Perspective' in bodyStyle) {
|
||||||
|
// Modern browsers with 3D support, e.g. Webkit, IE10
|
||||||
|
return 'translate3d';
|
||||||
|
} else if (vendorPrefix + 'Transform' in bodyStyle) {
|
||||||
|
// Browsers without 3D support, e.g. IE9
|
||||||
|
return 'translate';
|
||||||
|
} else {
|
||||||
|
// Browsers without translate() support, e.g. IE7-8
|
||||||
|
return 'margin';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers
|
||||||
|
*/
|
||||||
|
|
||||||
|
function clamp(n, min, max) {
|
||||||
|
if (n < min) return min;
|
||||||
|
if (n > max) return max;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) converts a percentage (`0..1`) to a bar translateX
|
||||||
|
* percentage (`-100%..0%`).
|
||||||
|
*/
|
||||||
|
|
||||||
|
function toBarPerc(n) {
|
||||||
|
return (-1 + n) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) returns the correct CSS for changing the bar's
|
||||||
|
* position given an n percentage, and speed and ease from Settings
|
||||||
|
*/
|
||||||
|
|
||||||
|
function barPositionCSS(n, speed, ease) {
|
||||||
|
var barCSS;
|
||||||
|
|
||||||
|
if (Settings.positionUsing === 'translate3d') {
|
||||||
|
barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' };
|
||||||
|
} else if (Settings.positionUsing === 'translate') {
|
||||||
|
barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' };
|
||||||
|
} else {
|
||||||
|
barCSS = { 'margin-left': toBarPerc(n)+'%' };
|
||||||
|
}
|
||||||
|
|
||||||
|
barCSS.transition = 'all '+speed+'ms '+ease;
|
||||||
|
|
||||||
|
return barCSS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) Queues a function to be executed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var queue = (function() {
|
||||||
|
var pending = [];
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
var fn = pending.shift();
|
||||||
|
if (fn) {
|
||||||
|
fn(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function(fn) {
|
||||||
|
pending.push(fn);
|
||||||
|
if (pending.length == 1) next();
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) Applies css properties to an element, similar to the jQuery
|
||||||
|
* css method.
|
||||||
|
*
|
||||||
|
* While this helper does assist with vendor prefixed property names, it
|
||||||
|
* does not perform any manipulation of values prior to setting styles.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var css = (function() {
|
||||||
|
var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ],
|
||||||
|
cssProps = {};
|
||||||
|
|
||||||
|
function camelCase(string) {
|
||||||
|
return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) {
|
||||||
|
return letter.toUpperCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVendorProp(name) {
|
||||||
|
var style = document.body.style;
|
||||||
|
if (name in style) return name;
|
||||||
|
|
||||||
|
var i = cssPrefixes.length,
|
||||||
|
capName = name.charAt(0).toUpperCase() + name.slice(1),
|
||||||
|
vendorName;
|
||||||
|
while (i--) {
|
||||||
|
vendorName = cssPrefixes[i] + capName;
|
||||||
|
if (vendorName in style) return vendorName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStyleProp(name) {
|
||||||
|
name = camelCase(name);
|
||||||
|
return cssProps[name] || (cssProps[name] = getVendorProp(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyCss(element, prop, value) {
|
||||||
|
prop = getStyleProp(prop);
|
||||||
|
element.style[prop] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function(element, properties) {
|
||||||
|
var args = arguments,
|
||||||
|
prop,
|
||||||
|
value;
|
||||||
|
|
||||||
|
if (args.length == 2) {
|
||||||
|
for (prop in properties) {
|
||||||
|
value = properties[prop];
|
||||||
|
if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
applyCss(element, args[1], args[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) Determines if an element or space separated list of class names contains a class name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function hasClass(element, name) {
|
||||||
|
var list = typeof element == 'string' ? element : classList(element);
|
||||||
|
return list.indexOf(' ' + name + ' ') >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) Adds a class to an element.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addClass(element, name) {
|
||||||
|
var oldList = classList(element),
|
||||||
|
newList = oldList + name;
|
||||||
|
|
||||||
|
if (hasClass(oldList, name)) return;
|
||||||
|
|
||||||
|
// Trim the opening space.
|
||||||
|
element.className = newList.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) Removes a class from an element.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function removeClass(element, name) {
|
||||||
|
var oldList = classList(element),
|
||||||
|
newList;
|
||||||
|
|
||||||
|
if (!hasClass(element, name)) return;
|
||||||
|
|
||||||
|
// Replace the class name.
|
||||||
|
newList = oldList.replace(' ' + name + ' ', ' ');
|
||||||
|
|
||||||
|
// Trim the opening and closing spaces.
|
||||||
|
element.className = newList.substring(1, newList.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) Gets a space separated list of the class names on the element.
|
||||||
|
* The list is wrapped with a single space on each end to facilitate finding
|
||||||
|
* matches within the list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function classList(element) {
|
||||||
|
return (' ' + (element.className || '') + ' ').replace(/\s+/gi, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Internal) Removes an element from the DOM.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function removeElement(element) {
|
||||||
|
element && element.parentNode && element.parentNode.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NProgress;
|
||||||
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN" xmlns="http://www.w3.org/1999/html">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
<a href="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="btn btn-default btn-sm pull-right" style="margin-right: 5px;" target="_blank"><i class="fa fa-eye"></i> 阅读</a>
|
<a href="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="btn btn-default btn-sm pull-right" style="margin-right: 5px;" target="_blank"><i class="fa fa-eye"></i> 阅读</a>
|
||||||
|
|
||||||
{{if eq .Model.RoleId 0 1 2}}
|
{{if eq .Model.RoleId 0 1 2}}
|
||||||
<a href="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="btn btn-default btn-sm pull-right" style="margin-right: 5px;" target="_blank"><i class="fa fa-upload" aria-hidden="true"></i> 发布</a>
|
<button class="btn btn-default btn-sm pull-right" style="margin-right: 5px;" id="btnRelease"><i class="fa fa-upload" aria-hidden="true"></i> 发布</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -98,7 +98,27 @@
|
||||||
</div>
|
</div>
|
||||||
<script src="/static/jquery/1.12.4/jquery.min.js"></script>
|
<script src="/static/jquery/1.12.4/jquery.min.js"></script>
|
||||||
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
|
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="/static/layer/layer.js"></script>
|
||||||
<script src="/static/js/main.js" type="text/javascript"></script>
|
<script src="/static/js/main.js" type="text/javascript"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function () {
|
||||||
|
$("#btnRelease").on("click",function () {
|
||||||
|
$.ajax({
|
||||||
|
url : "{{urlfor "BookController.Release" ":key" .Model.Identify}}",
|
||||||
|
data :{"identify" : "{{.Model.Identify}}" },
|
||||||
|
type : "post",
|
||||||
|
dataType : "json",
|
||||||
|
success : function (res) {
|
||||||
|
if(res.errcode === 0){
|
||||||
|
layer.msg("发布任务已推送到任务队列,稍后将在后台执行。");
|
||||||
|
}else{
|
||||||
|
layer.msg(res.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -60,7 +60,7 @@
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<a :href="'{{urlfor "DocumentController.Index" ":key" ""}}' + item.identify" title="查看文档" data-toggle="tooltip"><i class="fa fa-eye"></i> 查看文档</a>
|
<a :href="'{{urlfor "DocumentController.Index" ":key" ""}}' + item.identify" title="查看文档" data-toggle="tooltip"><i class="fa fa-eye"></i> 查看文档</a>
|
||||||
<template v-if="item.role_id != 3">
|
<template v-if="item.role_id != 3">
|
||||||
<a :href="'/docs/' + item.identify + '/edit'" title="编辑文档" data-toggle="tooltip"><i class="fa fa-edit" aria-hidden="true"></i> 编辑文档</a>
|
<a :href="'/api/' + item.identify + '/edit'" title="编辑文档" data-toggle="tooltip"><i class="fa fa-edit" aria-hidden="true"></i> 编辑文档</a>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<title>编辑文档 - Powered by MinDoc</title>
|
||||||
|
|
||||||
|
<!-- Bootstrap -->
|
||||||
|
<link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="/static/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||||
|
<link href="/static/jstree/3.3.4/themes/default/style.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<link href="/static/nprogress/nprogress.css" rel="stylesheet">
|
||||||
|
<link href="/static/css/kancloud.css" rel="stylesheet">
|
||||||
|
<link href="/static/css/jstree.css" rel="stylesheet">
|
||||||
|
{{if eq .Model.Editor "markdown"}}
|
||||||
|
<link href="/static/editor.md/css/editormd.preview.css" rel="stylesheet">
|
||||||
|
{{else}}
|
||||||
|
<link href="/static/highlight/styles/zenburn.css" rel="stylesheet">
|
||||||
|
{{end}}
|
||||||
|
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
||||||
|
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="/static/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||||
|
<script src="/static/respond.js/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="m-manual manual-reader">
|
||||||
|
<header class="navbar navbar-static-top manual-head" role="banner">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="navbar-header pull-left manual-title">
|
||||||
|
<span class="slidebar" id="slidebar"><i class="fa fa-align-justify"></i></span>
|
||||||
|
{{.Model.BookName}}
|
||||||
|
<span style="font-size: 12px;font-weight: 100;"></span>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-header pull-right manual-menu">
|
||||||
|
<div class="dropdown">
|
||||||
|
<button id="dLabel" class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
项目
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="dLabel">
|
||||||
|
{{if gt .Member.MemberId 0}}
|
||||||
|
{{if eq .Model.RoleId 0 1 2}}
|
||||||
|
<li><a href="{{urlfor "DocumentController.Edit" ":key" .Model.Identify ":id" ""}}">返回编辑</a> </li>
|
||||||
|
{{end}}
|
||||||
|
<li><a href="{{urlfor "BookController.Index"}}">我的项目</a> </li>
|
||||||
|
<li role="presentation" class="divider"></li>
|
||||||
|
{{end}}
|
||||||
|
{{if eq .Model.PrivatelyOwned 0}}
|
||||||
|
<li><a href="javascript:" data-toggle="modal" data-target="#shareProject">项目分享</a> </li>
|
||||||
|
<li role="presentation" class="divider"></li>
|
||||||
|
{{/*<li><a href="https://wiki.iminho.me/export/1" target="_blank">项目导出</a> </li>*/}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<li><a href="{{urlfor "HomeController.Index"}}" title="返回首页">返回首页</a> </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<article class="container-fluid manual-body">
|
||||||
|
<div class="manual-left">
|
||||||
|
<div class="manual-tab">
|
||||||
|
<div class="tab-navg">
|
||||||
|
<span data-mode="view" class="navg-item active"><i class="fa fa-align-justify"></i><b class="text">目录</b></span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-util">
|
||||||
|
<span class="manual-fullscreen-switch">
|
||||||
|
<b class="open fa fa-angle-right" title="展开"></b>
|
||||||
|
<b class="close fa fa-angle-left" title="关闭"></b>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-wrap">
|
||||||
|
<div class="tab-item manual-catalog">
|
||||||
|
<div class="catalog-list read-book-preview" id="sidebar">
|
||||||
|
{{.Result}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="m-copyright">
|
||||||
|
<p>
|
||||||
|
本文档使用 <a href="https://doc.iminho.me" target="_blank">MinDoc</a> 发布
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="manual-right">
|
||||||
|
<div class="manual-article">
|
||||||
|
<div class="article-head">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-2">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8 text-center">
|
||||||
|
<h1 id="article-title">{{.Title}}</h1>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="article-content">
|
||||||
|
<div class="article-body {{if eq .Model.Editor "markdown"}}markdown-body editormd-preview-container{{else}}editor-content{{end}}" id="page-content">
|
||||||
|
{{.Content}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="manual-progress"><b class="progress-bar"></b></div>
|
||||||
|
</article>
|
||||||
|
<div class="manual-mask"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Share Modal -->
|
||||||
|
<div class="modal fade" id="shareProject" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
||||||
|
<h4 class="modal-title" id="myModalLabel">项目分享</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="password" class="col-sm-2 control-label">项目地址</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" value="{{.BaseUrl}}{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="form-control" onmouseover="this.select()" id="projectUrl" title="项目地址">
|
||||||
|
</div>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="/static/jquery/1.12.4/jquery.min.js"></script>
|
||||||
|
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="/static/jstree/3.3.4/jstree.min.js" type="text/javascript"></script>
|
||||||
|
<script type="text/javascript" src="/static/nprogress/nprogress.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/highlight/highlight.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/highlight/highlightjs-line-numbers.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var events = $("body");
|
||||||
|
var catalog = null;
|
||||||
|
function initHighlighting() {
|
||||||
|
$('pre code').each(function (i, block) {
|
||||||
|
hljs.highlightBlock(block);
|
||||||
|
});
|
||||||
|
|
||||||
|
hljs.initLineNumbersOnLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
window.isFullScreen = false;
|
||||||
|
|
||||||
|
initHighlighting();
|
||||||
|
|
||||||
|
$("#sidebar").jstree({
|
||||||
|
'plugins':["wholerow","types"],
|
||||||
|
"types": {
|
||||||
|
"default" : {
|
||||||
|
"icon" : false // 删除默认图标
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'core' : {
|
||||||
|
'check_callback' : true,
|
||||||
|
"multiple" : false ,
|
||||||
|
'animation' : 0
|
||||||
|
}
|
||||||
|
}).on('select_node.jstree',function (node,selected,event) {
|
||||||
|
$(".m-manual").removeClass('manual-mobile-show-left');
|
||||||
|
var url = selected.node.a_attr.href;
|
||||||
|
|
||||||
|
if(url === window.location.href){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url : url,
|
||||||
|
type : "GET",
|
||||||
|
beforeSend :function (xhr) {
|
||||||
|
var body = events.data('body_' + selected.node.id);
|
||||||
|
var title = events.data('title_' + selected.node.id);
|
||||||
|
var doc_title = events.data('doc_title_' + selected.node.id);
|
||||||
|
|
||||||
|
if(body && title && doc_title){
|
||||||
|
|
||||||
|
$("#page-content").html(body);
|
||||||
|
$("title").text(title);
|
||||||
|
$("#article-title").text(doc_title);
|
||||||
|
|
||||||
|
events.trigger('article.open',url,true);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NProgress.start();
|
||||||
|
},
|
||||||
|
success : function (res) {
|
||||||
|
if(res.errcode === 0){
|
||||||
|
var body = res.data.body;
|
||||||
|
var doc_title = res.data.doc_title;
|
||||||
|
var title = res.data.title;
|
||||||
|
|
||||||
|
$("#page-content").html(body);
|
||||||
|
$("title").text(title);
|
||||||
|
$("#article-title").text(doc_title);
|
||||||
|
|
||||||
|
events.data('body_' + selected.node.id,body);
|
||||||
|
events.data('title_' + selected.node.id,title);
|
||||||
|
events.data('doc_title_' + selected.node.id,doc_title);
|
||||||
|
|
||||||
|
events.trigger('article.open',url,false);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
layer.msg("加载失败");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete : function () {
|
||||||
|
NProgress.done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#slidebar").on("click",function () {
|
||||||
|
$(".m-manual").addClass('manual-mobile-show-left');
|
||||||
|
});
|
||||||
|
$(".manual-mask").on("click",function () {
|
||||||
|
$(".m-manual").removeClass('manual-mobile-show-left');
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".manual-fullscreen-switch").on("click",function () {
|
||||||
|
isFullScreen = !isFullScreen;
|
||||||
|
if (isFullScreen) {
|
||||||
|
$(".m-manual").addClass('manual-fullscreen-active');
|
||||||
|
} else {
|
||||||
|
$(".m-manual").removeClass('manual-fullscreen-active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
events.on('article.open', function (event, url,init) {
|
||||||
|
if ('pushState' in history) {
|
||||||
|
|
||||||
|
if (init == false) {
|
||||||
|
history.replaceState({ }, '', url);
|
||||||
|
init = true;
|
||||||
|
} else {
|
||||||
|
history.pushState({ }, '', url);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
location.hash = url;
|
||||||
|
}
|
||||||
|
initHighlighting();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -129,7 +129,7 @@
|
||||||
<script type="text/javascript" src="/static/layer/layer.js"></script>
|
<script type="text/javascript" src="/static/layer/layer.js"></script>
|
||||||
<script src="/static/to-markdown/dist/to-markdown.js" type="text/javascript"></script>
|
<script src="/static/to-markdown/dist/to-markdown.js" type="text/javascript"></script>
|
||||||
<script src="/static/js/jquery.form.js" type="text/javascript"></script>
|
<script src="/static/js/jquery.form.js" type="text/javascript"></script>
|
||||||
<script src="/static/js/edirot.js" type="text/javascript"></script>
|
<script src="/static/js/editor.js" type="text/javascript"></script>
|
||||||
<script src="/static/js/html-editor.js" type="text/javascript"></script>
|
<script src="/static/js/html-editor.js" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -160,7 +160,7 @@
|
||||||
<script src="/static/editor.md/editormd.js" type="text/javascript"></script>
|
<script src="/static/editor.md/editormd.js" type="text/javascript"></script>
|
||||||
<script type="text/javascript" src="/static/layer/layer.js"></script>
|
<script type="text/javascript" src="/static/layer/layer.js"></script>
|
||||||
<script src="/static/js/jquery.form.js" type="text/javascript"></script>
|
<script src="/static/js/jquery.form.js" type="text/javascript"></script>
|
||||||
<script src="/static/js/edirot.js" type="text/javascript"></script>
|
<script src="/static/js/editor.js" type="text/javascript"></script>
|
||||||
<script src="/static/js/markdown.js" type="text/javascript"></script>
|
<script src="/static/js/markdown.js" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -1,10 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Title</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -25,158 +25,27 @@
|
||||||
<div class="container manual-body">
|
<div class="container manual-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="manual-list">
|
<div class="manual-list">
|
||||||
|
{{range $index,$item := .Lists}}
|
||||||
<div class="list-item">
|
<div class="list-item">
|
||||||
<dl class="manual-item-standard">
|
<dl class="manual-item-standard">
|
||||||
<dt>
|
<dt>
|
||||||
<a href="{{urlfor "DocumentController.Index" ":key" "test"}}">
|
<a href="{{urlfor "DocumentController.Index" ":key" $item.Identify}}" title="{{$item.BookName}}-{{$item.CreateName}}">
|
||||||
<img src="/uploads/201704/b4c17ca29fe7b7f4dec402d7dd7543c6_100.png" class="cover">
|
<img src="{{$item.Cover}}" class="cover" alt="{{$item.BookName}}-{{$item.CreateName}}">
|
||||||
</a>
|
</a>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<a href="#" class="name">Docker生产环境实践指南</a>
|
<a href="{{urlfor "DocumentController.Index" ":key" $item.Identify}}" class="name" title="{{$item.BookName}}-{{$item.CreateName}}">{{$item.BookName}}</a>
|
||||||
</dd>
|
</dd>
|
||||||
<dd>
|
<dd>
|
||||||
<span class="author">
|
<span class="author">
|
||||||
<b class="text">作者</b>
|
<b class="text">作者</b>
|
||||||
<b class="text">-</b>
|
<b class="text">-</b>
|
||||||
<b class="text">Minho</b>
|
<b class="text">{{$item.CreateName}}</b>
|
||||||
</span>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
<div class="list-item">
|
|
||||||
<dl class="manual-item-standard">
|
|
||||||
<dt>
|
|
||||||
<a href="#">
|
|
||||||
<img src="/uploads/201704/b4c17ca29fe7b7f4dec402d7dd7543c6_100.png">
|
|
||||||
</a>
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<a href="#" class="name">Docker生产环境实践指南</a>
|
|
||||||
</dd>
|
|
||||||
<dd>
|
|
||||||
<span class="author">
|
|
||||||
<b class="text">作者</b>
|
|
||||||
<b class="text">-</b>
|
|
||||||
<b class="text">Minho</b>
|
|
||||||
</span>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
<div class="list-item">
|
|
||||||
<dl class="manual-item-standard">
|
|
||||||
<dt>
|
|
||||||
<a href="#">
|
|
||||||
<img src="/uploads/201704/b4c17ca29fe7b7f4dec402d7dd7543c6_100.png">
|
|
||||||
</a>
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<a href="#" class="name">Docker生产环境实践指南</a>
|
|
||||||
</dd>
|
|
||||||
<dd>
|
|
||||||
<span class="author">
|
|
||||||
<b class="text">作者</b>
|
|
||||||
<b class="text">-</b>
|
|
||||||
<b class="text">Minho</b>
|
|
||||||
</span>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
<div class="list-item">
|
|
||||||
<dl class="manual-item-standard">
|
|
||||||
<dt>
|
|
||||||
<a href="#">
|
|
||||||
<img src="/uploads/201704/b4c17ca29fe7b7f4dec402d7dd7543c6_100.png">
|
|
||||||
</a>
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<a href="#" class="name">Docker生产环境实践指南</a>
|
|
||||||
</dd>
|
|
||||||
<dd>
|
|
||||||
<span class="author">
|
|
||||||
<b class="text">作者</b>
|
|
||||||
<b class="text">-</b>
|
|
||||||
<b class="text">Minho</b>
|
|
||||||
</span>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
<div class="list-item">
|
|
||||||
<dl class="manual-item-standard">
|
|
||||||
<dt>
|
|
||||||
<a href="#">
|
|
||||||
<img src="/uploads/201704/b4c17ca29fe7b7f4dec402d7dd7543c6_100.png">
|
|
||||||
</a>
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<a href="#" class="name">Docker生产环境实践指南</a>
|
|
||||||
</dd>
|
|
||||||
<dd>
|
|
||||||
<span class="author">
|
|
||||||
<b class="text">作者</b>
|
|
||||||
<b class="text">-</b>
|
|
||||||
<b class="text">Minho</b>
|
|
||||||
</span>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
<div class="list-item">
|
|
||||||
<dl class="manual-item-standard">
|
|
||||||
<dt>
|
|
||||||
<a href="#">
|
|
||||||
<img src="/uploads/201704/b4c17ca29fe7b7f4dec402d7dd7543c6_100.png">
|
|
||||||
</a>
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<a href="#" class="name">Docker生产环境实践指南</a>
|
|
||||||
</dd>
|
|
||||||
<dd>
|
|
||||||
<span class="author">
|
|
||||||
<b class="text">作者</b>
|
|
||||||
<b class="text">-</b>
|
|
||||||
<b class="text">Minho</b>
|
|
||||||
</span>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
<div class="list-item">
|
|
||||||
<dl class="manual-item-standard">
|
|
||||||
<dt>
|
|
||||||
<a href="#">
|
|
||||||
<img src="/uploads/201704/b4c17ca29fe7b7f4dec402d7dd7543c6_100.png">
|
|
||||||
</a>
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<a href="#" class="name">Docker生产环境实践指南</a>
|
|
||||||
</dd>
|
|
||||||
<dd>
|
|
||||||
<span class="author">
|
|
||||||
<b class="text">作者</b>
|
|
||||||
<b class="text">-</b>
|
|
||||||
<b class="text">Minho</b>
|
|
||||||
</span>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
<div class="list-item">
|
|
||||||
<dl class="manual-item-standard">
|
|
||||||
<dt>
|
|
||||||
<a href="#">
|
|
||||||
<img src="/uploads/201704/b4c17ca29fe7b7f4dec402d7dd7543c6_100.png">
|
|
||||||
</a>
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<a href="#" class="name">Docker生产环境实践指南</a>
|
|
||||||
</dd>
|
|
||||||
<dd>
|
|
||||||
<span class="author">
|
|
||||||
<b class="text">作者</b>
|
|
||||||
<b class="text">-</b>
|
|
||||||
<b class="text">Minho</b>
|
|
||||||
</span>
|
</span>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -99,7 +99,21 @@
|
||||||
<script src="/static/js/main.js" type="text/javascript"></script>
|
<script src="/static/js/main.js" type="text/javascript"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function () {
|
$(function () {
|
||||||
|
$("#gloablEditForm").ajaxForm({
|
||||||
|
beforeSubmit : function () {
|
||||||
|
var title = $.trim($("#siteName").val());
|
||||||
|
|
||||||
|
if (title === ""){
|
||||||
|
return showError("网站标题不能为空");
|
||||||
|
}
|
||||||
|
},success : function (res) {
|
||||||
|
if(res.errcode === 0) {
|
||||||
|
showSuccess("保存成功")
|
||||||
|
}else{
|
||||||
|
showError(res.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
<header class="navbar navbar-static-top navbar-fixed-top manual-header" role="banner">
|
<header class="navbar navbar-static-top navbar-fixed-top manual-header" role="banner">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="navbar-header col-sm-12 col-md-6 col-lg-5">
|
<div class="navbar-header col-sm-12 col-md-6 col-lg-5">
|
||||||
<a href="/" class="navbar-brand">MinDoc</a>
|
<a href="/" class="navbar-brand">
|
||||||
|
{{if .SITE_TITLE}}
|
||||||
|
{{.SITE_TITLE}}
|
||||||
|
{{else}}
|
||||||
|
{{.SITE_NAME}}
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
<div class="btn-group dropdown-menu-right pull-right slidebar visible-xs-inline-block visible-sm-inline-block">
|
<div class="btn-group dropdown-menu-right pull-right slidebar visible-xs-inline-block visible-sm-inline-block">
|
||||||
<button class="btn btn-default dropdown-toggle hidden-lg" type="button" data-toggle="dropdown"><i class="fa fa-align-justify"></i></button>
|
<button class="btn btn-default dropdown-toggle hidden-lg" type="button" data-toggle="dropdown"><i class="fa fa-align-justify"></i></button>
|
||||||
<ul class="dropdown-menu" role="menu">
|
<ul class="dropdown-menu" role="menu">
|
||||||
|
@ -19,6 +25,7 @@
|
||||||
</div>
|
</div>
|
||||||
<nav class="navbar-collapse hidden-xs hidden-sm" role="navigation">
|
<nav class="navbar-collapse hidden-xs hidden-sm" role="navigation">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
|
{{if gt .Member.MemberId 0}}
|
||||||
<li>
|
<li>
|
||||||
<div class="img user-info" data-toggle="dropdown">
|
<div class="img user-info" data-toggle="dropdown">
|
||||||
<img src="{{.Member.Avatar}}" class="img-circle userbar-avatar">
|
<img src="{{.Member.Avatar}}" class="img-circle userbar-avatar">
|
||||||
|
@ -45,6 +52,9 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
{{else}}
|
||||||
|
<li><a href="{{urlfor "AccountController.Login"}}" title="用户登录">登录</a></li>
|
||||||
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue