member center, blog redesign
No files matched your search
@@ -0,0 +1,101 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "strings"
|
||||||
|
// "time"
|
||||||
|
// "encoding/json"
|
||||||
|
// "github.com/leanote/leanote/app/info"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
// "github.com/leanote/leanote/app/lea/blog"
|
||||||
|
// "gopkg.in/mgo.v2/bson"
|
||||||
|
// "github.com/leanote/leanote/app/types"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "math"
|
||||||
|
// "os"
|
||||||
|
// "path"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Preview struct {
|
||||||
|
Blog
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到要预览的主题绝对路径
|
||||||
|
func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
|
||||||
|
if themeId != "" {
|
||||||
|
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了
|
||||||
|
} else {
|
||||||
|
themeId = c.Session["themeId"] // 直接从session中获取
|
||||||
|
}
|
||||||
|
if themeId == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
theme := themeService.GetTheme(c.GetUserId(), themeId)
|
||||||
|
|
||||||
|
c.RenderArgs["isPreview"] = true
|
||||||
|
c.RenderArgs["themePath"] = theme.Path
|
||||||
|
if theme.Path == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Preview) Index(userIdOrEmail string, themeId string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath(themeId) {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Index(c.GetUserId())
|
||||||
|
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Preview) Tag(userIdOrEmail, tag string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Tag(c.GetUserId(), tag)
|
||||||
|
}
|
||||||
|
func (c Preview) Tags(userIdOrEmail string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Tags(c.GetUserId())
|
||||||
|
// if tag == "" {
|
||||||
|
// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
// }
|
||||||
|
// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Archive(userIdOrEmail string, notebookId string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Archive(c.GetUserId(), notebookId)
|
||||||
|
// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Cate(notebookId string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Cate(notebookId)
|
||||||
|
// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Post(noteId string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Post(noteId)
|
||||||
|
// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Single(singleId string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Single(singleId)
|
||||||
|
// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Search(userIdOrEmail, keywords string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Search(c.GetUserId(), keywords)
|
||||||
|
// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
@@ -18,8 +18,8 @@ func (c Admin) Index() revel.Result {
|
|||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
|
|
||||||
c.RenderArgs["countUser"] = userService.CountUser()
|
c.RenderArgs["countUser"] = userService.CountUser()
|
||||||
c.RenderArgs["countNote"] = noteService.CountNote()
|
c.RenderArgs["countNote"] = noteService.CountNote("")
|
||||||
c.RenderArgs["countBlog"] = noteService.CountBlog()
|
c.RenderArgs["countBlog"] = noteService.CountBlog("")
|
||||||
|
|
||||||
return c.RenderTemplate("admin/index.html");
|
return c.RenderTemplate("admin/index.html");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package admin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"time"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
)
|
)
|
||||||
|
|
||||||
// admin 首页
|
// admin 首页
|
||||||
@@ -13,10 +15,13 @@ type AdminUser struct {
|
|||||||
|
|
||||||
// admin 主页
|
// admin 主页
|
||||||
var userPageSize = 10
|
var userPageSize = 10
|
||||||
func (c AdminUser) Index(sorter, keywords string) revel.Result {
|
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
|
||||||
pageNumber := c.GetPage()
|
pageNumber := c.GetPage()
|
||||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime"});
|
if userPageSize == 0 {
|
||||||
pageInfo, users := userService.ListUsers(pageNumber, userPageSize, sorterField, isAsc, keywords);
|
pageSize = userPageSize
|
||||||
|
}
|
||||||
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"});
|
||||||
|
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords);
|
||||||
c.RenderArgs["pageInfo"] = pageInfo
|
c.RenderArgs["pageInfo"] = pageInfo
|
||||||
c.RenderArgs["users"] = users
|
c.RenderArgs["users"] = users
|
||||||
c.RenderArgs["keywords"] = keywords
|
c.RenderArgs["keywords"] = keywords
|
||||||
@@ -26,3 +31,35 @@ func (c AdminUser) Index(sorter, keywords string) revel.Result {
|
|||||||
func (c AdminUser) Add() revel.Result {
|
func (c AdminUser) Add() revel.Result {
|
||||||
return c.RenderTemplate("admin/user/add.html");
|
return c.RenderTemplate("admin/user/add.html");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加
|
||||||
|
func (c AdminUser) Register(email, pwd string) revel.Result {
|
||||||
|
re := info.NewRe();
|
||||||
|
|
||||||
|
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||||
|
return c.RenderRe(re);
|
||||||
|
}
|
||||||
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
|
return c.RenderRe(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册
|
||||||
|
re.Ok, re.Msg = authService.Register(email, pwd)
|
||||||
|
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改帐户
|
||||||
|
func (c AdminUser) UpdateAccount(userId string) revel.Result {
|
||||||
|
userInfo := userService.GetUserInfo(userId)
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
return c.RenderTemplate("admin/user/update_account.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminUser) DoUpdateAccount(userId, accountType string, accountStartTime, accountEndTime string, maxImageNum, maxImageSize, maxAttachNum, maxAttachSize, maxPerAttachSize int) revel.Result {
|
||||||
|
re := info.NewRe();
|
||||||
|
s, _ := time.Parse("2006-01-02 15:04:02", accountStartTime)
|
||||||
|
e, _ := time.Parse("2006-01-02 15:04:02", accountEndTime)
|
||||||
|
re.Ok = userService.UpdateAccount(userId, accountType, s, e, maxImageNum, maxImageSize, maxAttachNum, maxAttachSize, maxPerAttachSize )
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/leanote/leanote/app/service"
|
"github.com/leanote/leanote/app/service"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/lea/blog"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -27,6 +28,7 @@ var attachService *service.AttachService
|
|||||||
var configService *service.ConfigService
|
var configService *service.ConfigService
|
||||||
var emailService *service.EmailService
|
var emailService *service.EmailService
|
||||||
var sessionService *service.SessionService
|
var sessionService *service.SessionService
|
||||||
|
var themeService *service.ThemeService
|
||||||
|
|
||||||
var pageSize = 1000
|
var pageSize = 1000
|
||||||
var defaultSortField = "UpdatedTime"
|
var defaultSortField = "UpdatedTime"
|
||||||
@@ -126,6 +128,7 @@ func InitService() {
|
|||||||
configService = service.ConfigS
|
configService = service.ConfigS
|
||||||
emailService = service.EmailS
|
emailService = service.EmailS
|
||||||
sessionService = service.SessionS
|
sessionService = service.SessionS
|
||||||
|
themeService = service.ThemeS
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -137,10 +140,12 @@ func init() {
|
|||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
||||||
|
|
||||||
revel.OnAppStart(func() {
|
revel.OnAppStart(func() {
|
||||||
siteUrl, _ = revel.Config.String("site.url")
|
siteUrl, _ = revel.Config.String("site.url")
|
||||||
|
|
||||||
|
// 博客初始化模板
|
||||||
|
blog.Init()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "github.com/revel/revel"
|
||||||
|
// "gopkg.in/mgo.v2/bson"
|
||||||
|
// "encoding/json"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/controllers"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "fmt"
|
||||||
|
// "math"
|
||||||
|
// "strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 公用Controller, 其它Controller继承它
|
||||||
|
type MemberBaseController struct {
|
||||||
|
controllers.BaseController // 不能用*BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到sorterField 和 isAsc
|
||||||
|
// okSorter = ['email', 'username']
|
||||||
|
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
|
||||||
|
sorter := ""
|
||||||
|
c.Params.Bind(&sorter, "sorter")
|
||||||
|
if sorter == "" {
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sorter形式 email-up, email-down
|
||||||
|
s2 := strings.Split(sorter, "-")
|
||||||
|
if len(s2) != 2 {
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 必须是可用的sorter
|
||||||
|
if okSorter != nil && len(okSorter) > 0 {
|
||||||
|
if !InArray(okSorter, s2[0]) {
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sorterField = strings.Title(s2[0])
|
||||||
|
if s2[1] == "up" {
|
||||||
|
isAsc = true
|
||||||
|
} else {
|
||||||
|
isAsc = false
|
||||||
|
}
|
||||||
|
c.RenderArgs["sorter"] = sorter
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBaseController) updateConfig(keys []string) {
|
||||||
|
userId := c.GetUserId()
|
||||||
|
for _, key := range keys {
|
||||||
|
v := c.Params.Values.Get(key)
|
||||||
|
configService.UpdateGlobalStringConfig(userId, key, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,428 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"os"
|
||||||
|
"io/ioutil"
|
||||||
|
"time"
|
||||||
|
"fmt"
|
||||||
|
// "github.com/leanote/leanote/app/lea/blog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// admin 首页
|
||||||
|
|
||||||
|
type MemberBlog struct {
|
||||||
|
MemberBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) common() info.UserBlog {
|
||||||
|
userId := c.GetUserId()
|
||||||
|
userInfo := userService.GetUserInfo(userId)
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
|
// 得到博客设置信息
|
||||||
|
c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
|
||||||
|
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
c.RenderArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
return userBlog
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基本信息设置
|
||||||
|
func (c MemberBlog) Base() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Blog Base Info"
|
||||||
|
return c.RenderTemplate("member/blog/base.html");
|
||||||
|
}
|
||||||
|
func (c MemberBlog) Comment() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Comment"
|
||||||
|
return c.RenderTemplate("member/blog/comment.html");
|
||||||
|
}
|
||||||
|
func (c MemberBlog) Domain() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Domain"
|
||||||
|
return c.RenderTemplate("member/blog/domain.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) Paging() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Paging"
|
||||||
|
return c.RenderTemplate("member/blog/paging.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) Cate() revel.Result {
|
||||||
|
userBlog := c.common()
|
||||||
|
c.RenderArgs["title"] = "Cate"
|
||||||
|
|
||||||
|
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
|
||||||
|
notebooksMap := map[string]info.Notebook{}
|
||||||
|
for _, each := range notebooks {
|
||||||
|
notebooksMap[each.NotebookId.Hex()] = each
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
notebooks2 := make([]info.Notebook, len(notebooks))
|
||||||
|
|
||||||
|
// 先要保证已有的是正确的排序
|
||||||
|
cateIds := userBlog.CateIds
|
||||||
|
has := map[string]bool{} // cateIds中有的
|
||||||
|
if cateIds != nil && len(cateIds) > 0 {
|
||||||
|
for _, cateId := range cateIds {
|
||||||
|
if n, ok := notebooksMap[cateId]; ok {
|
||||||
|
notebooks2[i] = n
|
||||||
|
i++
|
||||||
|
has[cateId] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 之后
|
||||||
|
for _, each := range notebooks {
|
||||||
|
id := each.NotebookId.Hex()
|
||||||
|
if !has[id] {
|
||||||
|
notebooks2[i] = each
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.RenderArgs["notebooks"] = notebooks2
|
||||||
|
|
||||||
|
return c.RenderTemplate("member/blog/cate.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改分类排序
|
||||||
|
func (c MemberBlog) UpateCateIds(cateIds []string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.UpateCateIds(c.GetUserId(), cateIds)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存之, 包含增加与保存
|
||||||
|
func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.AddOrUpdateSingle(c.GetUserId(), singleId, title, content)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Add Single"
|
||||||
|
c.RenderArgs["singleId"] = singleId
|
||||||
|
if singleId != "" {
|
||||||
|
c.RenderArgs["single"] = blogService.GetSingle(singleId)
|
||||||
|
}
|
||||||
|
return c.RenderTemplate("member/blog/add_single.html");
|
||||||
|
}
|
||||||
|
func (c MemberBlog) SortSingles(singleIds []string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.SortSingles(c.GetUserId(), singleIds)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) DeleteSingle(singleId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.DeleteSingle(c.GetUserId(), singleId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) Single() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Cate"
|
||||||
|
c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId())
|
||||||
|
|
||||||
|
return c.RenderTemplate("member/blog/single.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主题
|
||||||
|
func (c MemberBlog) Theme() revel.Result {
|
||||||
|
c.common()
|
||||||
|
activeTheme, otherThemes := themeService.GetUserThemes(c.GetUserId())
|
||||||
|
c.RenderArgs["activeTheme"] = activeTheme
|
||||||
|
c.RenderArgs["otherThemes"] = otherThemes
|
||||||
|
|
||||||
|
c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes()
|
||||||
|
|
||||||
|
c.RenderArgs["title"] = "Theme"
|
||||||
|
return c.RenderTemplate("member/blog/theme.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑主题
|
||||||
|
var baseTpls = []string{"header.html", "footer.html", "index.html", "cate.html", "search.html", "post.html", "single.html", "tags.html", "tag_posts.html", "archive.html", "share_comment.html", "404.html", "theme.json", "style.css", "blog.js"}
|
||||||
|
func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
|
||||||
|
// 查看用户是否有该theme, 若没有则复制default之
|
||||||
|
// 得到主题的文件列表
|
||||||
|
userBlog := blogService.GetUserBlog(c.GetUserId())
|
||||||
|
if themeId == "" {
|
||||||
|
_, themeId = themeService.NewThemeForFirst(userBlog)
|
||||||
|
return c.Redirect("/member/blog/updateTheme?themeId=" + themeId)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Upate Theme"
|
||||||
|
c.RenderArgs["isNew"] = isNew
|
||||||
|
|
||||||
|
// 先复制之
|
||||||
|
c.RenderArgs["themeId"] = themeId
|
||||||
|
|
||||||
|
// 得到脚本目录
|
||||||
|
userId := c.GetUserId()
|
||||||
|
|
||||||
|
theme := themeService.GetTheme(userId, themeId)
|
||||||
|
c.RenderArgs["theme"] = theme
|
||||||
|
|
||||||
|
path := revel.BasePath + "/" + theme.Path
|
||||||
|
|
||||||
|
tpls := ListDir(path)
|
||||||
|
myTpls := make([]string, len(baseTpls))
|
||||||
|
tplMap := map[string]bool{}
|
||||||
|
for i, t := range baseTpls {
|
||||||
|
myTpls[i] = t
|
||||||
|
tplMap[t] = true
|
||||||
|
}
|
||||||
|
// 得到没有的tpls
|
||||||
|
for _, t := range tpls {
|
||||||
|
if t == "images" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !tplMap[t] {
|
||||||
|
myTpls = append(myTpls, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.RenderArgs["myTpls"] = myTpls
|
||||||
|
|
||||||
|
return c.RenderTemplate("member/blog/update_theme.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到文件内容
|
||||||
|
func (c MemberBlog) GetTplContent(themeId string, filename string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = true
|
||||||
|
re.Item = themeService.GetTplContent(c.GetUserId(), themeId, filename)
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = themeService.UpdateTplContent(c.GetUserId(), themeId, filename, content)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) DeleteTpl(themeId, filename string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.DeleteTpl(c.GetUserId(), themeId, filename)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) ListThemeImages(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
userId := c.GetUserId()
|
||||||
|
path := themeService.GetThemeAbsolutePath(userId, themeId) + "/images"
|
||||||
|
os.MkdirAll(path, 0755)
|
||||||
|
images := ListDir(path)
|
||||||
|
re.List = images
|
||||||
|
re.Ok = true
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) DeleteThemeImage(themeId, filename string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
path := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images/" + filename
|
||||||
|
re.Ok = DeleteFile(path)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传主题图片
|
||||||
|
func (c MemberBlog) UploadThemeImage(themeId string) revel.Result {
|
||||||
|
re := c.uploadImage(themeId);
|
||||||
|
c.RenderArgs["fileUrlPath"] = re.Id
|
||||||
|
c.RenderArgs["resultCode"] = re.Code
|
||||||
|
c.RenderArgs["resultMsg"] = re.Msg
|
||||||
|
return c.RenderTemplate("file/blog_logo.html")
|
||||||
|
}
|
||||||
|
func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
|
||||||
|
var fileId = ""
|
||||||
|
var resultCode = 0 // 1表示正常
|
||||||
|
var resultMsg = "内部错误" // 错误信息
|
||||||
|
var Ok = false
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
re.Id = fileId // 只是id, 没有其它信息
|
||||||
|
re.Code = resultCode
|
||||||
|
re.Msg = resultMsg
|
||||||
|
re.Ok = Ok
|
||||||
|
}()
|
||||||
|
|
||||||
|
file, handel, err := c.Request.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
// 生成上传路径
|
||||||
|
dir := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images"
|
||||||
|
err = os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
// 生成新的文件名
|
||||||
|
filename := handel.Filename
|
||||||
|
|
||||||
|
var ext string;
|
||||||
|
|
||||||
|
_, ext = SplitFilename(filename)
|
||||||
|
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
||||||
|
resultMsg = "不是图片"
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = filename
|
||||||
|
data, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
LogJ(err)
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
// > 2M?
|
||||||
|
if(len(data) > 5 * 1024 * 1024) {
|
||||||
|
resultCode = 0
|
||||||
|
resultMsg = "图片大于2M"
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
toPath := dir + "/" + filename;
|
||||||
|
err = ioutil.WriteFile(toPath, data, 0777)
|
||||||
|
if err != nil {
|
||||||
|
LogJ(err)
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
TransToGif(toPath, 0, true)
|
||||||
|
resultCode = 1
|
||||||
|
resultMsg = "上传成功!"
|
||||||
|
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 使用主题
|
||||||
|
func (c MemberBlog) ActiveTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.ActiveTheme(c.GetUserId(), themeId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 删除主题
|
||||||
|
func (c MemberBlog) DeleteTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.DeleteTheme(c.GetUserId(), themeId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 管理员公开主题
|
||||||
|
func (c MemberBlog) PublicTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.PublicTheme(c.GetUserId(), themeId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 导出
|
||||||
|
func (c MemberBlog) ExportTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
var path string
|
||||||
|
re.Ok, path = themeService.ExportTheme(c.GetUserId(), themeId)
|
||||||
|
if !re.Ok {
|
||||||
|
return c.RenderText("error...")
|
||||||
|
}
|
||||||
|
fw, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderText("error")
|
||||||
|
}
|
||||||
|
return c.RenderBinary(fw, GetFilename(path), revel.Attachment, time.Now()) // revel.Attachment
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入主题
|
||||||
|
func (c MemberBlog) ImportTheme() revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
file, handel, err := c.Request.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
re.Msg = fmt.Sprintf("%v", err)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
// 生成上传路径
|
||||||
|
userId := c.GetUserId()
|
||||||
|
dir := revel.BasePath + "/public/upload/" + userId + "/tmp"
|
||||||
|
err = os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
re.Msg = fmt.Sprintf("%v", err)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 生成新的文件名
|
||||||
|
filename := handel.Filename
|
||||||
|
|
||||||
|
var ext string;
|
||||||
|
_, ext = SplitFilename(filename)
|
||||||
|
if(ext != ".zip") {
|
||||||
|
re.Msg = "请上传zip文件"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = filename
|
||||||
|
data, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// > 10M?
|
||||||
|
if(len(data) > 10 * 1024 * 1024) {
|
||||||
|
re.Msg = "文件大于10M"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
toPath := dir + "/" + filename;
|
||||||
|
err = ioutil.WriteFile(toPath, data, 0777)
|
||||||
|
if err != nil {
|
||||||
|
re.Msg = fmt.Sprintf("%v", err)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传好后, 增加之
|
||||||
|
themeService.ImportTheme(c.GetUserId(), toPath)
|
||||||
|
|
||||||
|
re.Ok = true
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安装
|
||||||
|
func (c MemberBlog) InstallTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.InstallTheme(c.GetUserId(), themeId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 新建主题
|
||||||
|
func (c MemberBlog) NewTheme() revel.Result {
|
||||||
|
_, themeId := themeService.NewTheme(c.GetUserId())
|
||||||
|
return c.Redirect("/member/blog/updateTheme?isNew=1&themeId=" + themeId)
|
||||||
|
}
|
||||||
|
//-----------
|
||||||
|
//
|
||||||
|
func (c MemberBlog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc bool) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = blogService.UpdateUserBlogPaging(c.GetUserId(), perPageSize, sortField, isAsc)
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
// admin 首页
|
||||||
|
|
||||||
|
type MemberIndex struct {
|
||||||
|
MemberBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// admin 主页
|
||||||
|
func (c MemberIndex) Index() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.RenderArgs["title"] = "Leanote Member Center"
|
||||||
|
|
||||||
|
c.RenderArgs["countNote"] = noteService.CountNote(c.GetUserId())
|
||||||
|
c.RenderArgs["countBlog"] = noteService.CountBlog(c.GetUserId())
|
||||||
|
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
|
return c.RenderTemplate("member/index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板
|
||||||
|
func (c MemberIndex) T(t string) revel.Result {
|
||||||
|
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
||||||
|
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
||||||
|
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
||||||
|
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
|
||||||
|
return c.RenderTemplate("admin/" + t + ".html")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberIndex) GetView(view string) revel.Result {
|
||||||
|
return c.RenderTemplate("admin/" + view);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 帐户信息
|
||||||
|
|
||||||
|
type MemberUser struct {
|
||||||
|
MemberBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberUser) Username() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Username"
|
||||||
|
return c.RenderTemplate("member/user/username.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberUser) Email() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Email"
|
||||||
|
return c.RenderTemplate("member/user/email.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberUser) Password() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Password"
|
||||||
|
return c.RenderTemplate("member/user/password.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberUser) Avatar() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Avatar"
|
||||||
|
return c.RenderTemplate("member/user/avatar.html");
|
||||||
|
}
|
||||||
|
func (c MemberUser) AddAccount() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Add Account"
|
||||||
|
return c.RenderTemplate("member/user/add_account.html");
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leanote/leanote/app/service"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var userService *service.UserService
|
||||||
|
var noteService *service.NoteService
|
||||||
|
var trashService *service.TrashService
|
||||||
|
var notebookService *service.NotebookService
|
||||||
|
var noteContentHistoryService *service.NoteContentHistoryService
|
||||||
|
var authService *service.AuthService
|
||||||
|
var shareService *service.ShareService
|
||||||
|
var blogService *service.BlogService
|
||||||
|
var tagService *service.TagService
|
||||||
|
var pwdService *service.PwdService
|
||||||
|
var tokenService *service.TokenService
|
||||||
|
var suggestionService *service.SuggestionService
|
||||||
|
var albumService *service.AlbumService
|
||||||
|
var noteImageService *service.NoteImageService
|
||||||
|
var fileService *service.FileService
|
||||||
|
var attachService *service.AttachService
|
||||||
|
var configService *service.ConfigService
|
||||||
|
var emailService *service.EmailService
|
||||||
|
var upgradeService *service.UpgradeService
|
||||||
|
var themeService *service.ThemeService
|
||||||
|
|
||||||
|
var adminUsername = "admin"
|
||||||
|
// 拦截器
|
||||||
|
// 不需要拦截的url
|
||||||
|
// Index 除了Note之外都不需要
|
||||||
|
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||||
|
"Login": true,
|
||||||
|
"DoLogin": true,
|
||||||
|
"Logout": true,
|
||||||
|
"Register": true,
|
||||||
|
"DoRegister": true,
|
||||||
|
"FindPasswword": true,
|
||||||
|
"DoFindPassword": true,
|
||||||
|
"FindPassword2": true,
|
||||||
|
"FindPasswordUpdate": true,
|
||||||
|
"Suggestion": true,
|
||||||
|
},
|
||||||
|
"Blog": map[string]bool{"Index": true,
|
||||||
|
"View": true,
|
||||||
|
"AboutMe": true,
|
||||||
|
"SearchBlog": true,
|
||||||
|
},
|
||||||
|
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||||
|
"User": map[string]bool{"UpdateEmail": true,
|
||||||
|
"ActiveEmail":true,
|
||||||
|
},
|
||||||
|
"Oauth": map[string]bool{"GithubCallback": true},
|
||||||
|
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||||
|
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
||||||
|
}
|
||||||
|
func needValidate(controller, method string) bool {
|
||||||
|
// 在里面
|
||||||
|
if v, ok := commonUrl[controller]; ok {
|
||||||
|
// 在commonUrl里
|
||||||
|
if _, ok2 := v[method]; ok2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
// controller不在这里的, 肯定要验证
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||||
|
// 全部变成首字大写
|
||||||
|
/*
|
||||||
|
var controller = strings.Title(c.Name)
|
||||||
|
var method = strings.Title(c.MethodName)
|
||||||
|
// 是否需要验证?
|
||||||
|
if !needValidate(controller, method) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 验证是否已登录
|
||||||
|
// 必须是管理员
|
||||||
|
if _, ok := c.Session["Username"]; ok {
|
||||||
|
return nil // 已登录
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没有登录, 判断是否是ajax操作
|
||||||
|
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Msg = "NOTLOGIN"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Redirect("/login")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最外层init.go调用
|
||||||
|
// 获取service, 单例
|
||||||
|
func InitService() {
|
||||||
|
notebookService = service.NotebookS
|
||||||
|
noteService = service.NoteS
|
||||||
|
noteContentHistoryService = service.NoteContentHistoryS
|
||||||
|
trashService = service.TrashS
|
||||||
|
shareService = service.ShareS
|
||||||
|
userService = service.UserS
|
||||||
|
tagService = service.TagS
|
||||||
|
blogService = service.BlogS
|
||||||
|
tokenService = service.TokenS
|
||||||
|
noteImageService = service.NoteImageS
|
||||||
|
fileService = service.FileS
|
||||||
|
albumService= service.AlbumS
|
||||||
|
attachService = service.AttachS
|
||||||
|
pwdService = service.PwdS
|
||||||
|
suggestionService = service.SuggestionS
|
||||||
|
authService = service.AuthS
|
||||||
|
configService = service.ConfigS
|
||||||
|
emailService = service.EmailS
|
||||||
|
upgradeService = service.UpgradeS
|
||||||
|
themeService = service.ThemeS
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberIndex{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberUser{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberBlog{})
|
||||||
|
revel.OnAppStart(func() {
|
||||||
|
adminUsername, _ = revel.Config.String("adminUsername")
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
包括基本信息设置
|
||||||
|
博客设置
|
||||||
@@ -2,9 +2,9 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/revel/revel"
|
||||||
"gopkg.in/mgo.v2"
|
"gopkg.in/mgo.v2"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"github.com/revel/revel"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init mgo and the common DAO
|
// Init mgo and the common DAO
|
||||||
@@ -23,6 +23,8 @@ var ShareNotebooks *mgo.Collection
|
|||||||
var HasShareNotes *mgo.Collection
|
var HasShareNotes *mgo.Collection
|
||||||
var Blogs *mgo.Collection
|
var Blogs *mgo.Collection
|
||||||
var Users *mgo.Collection
|
var Users *mgo.Collection
|
||||||
|
var Groups *mgo.Collection
|
||||||
|
var GroupUsers *mgo.Collection
|
||||||
|
|
||||||
var Tags *mgo.Collection
|
var Tags *mgo.Collection
|
||||||
var TagNotes *mgo.Collection
|
var TagNotes *mgo.Collection
|
||||||
@@ -46,6 +48,8 @@ var EmailLogs *mgo.Collection
|
|||||||
var BlogLikes *mgo.Collection
|
var BlogLikes *mgo.Collection
|
||||||
var BlogComments *mgo.Collection
|
var BlogComments *mgo.Collection
|
||||||
var Reports *mgo.Collection
|
var Reports *mgo.Collection
|
||||||
|
var BlogSingles *mgo.Collection
|
||||||
|
var Themes *mgo.Collection
|
||||||
|
|
||||||
// session
|
// session
|
||||||
var Sessions *mgo.Collection
|
var Sessions *mgo.Collection
|
||||||
@@ -54,7 +58,7 @@ var Sessions *mgo.Collection
|
|||||||
func Init() {
|
func Init() {
|
||||||
var url string
|
var url string
|
||||||
var ok bool
|
var ok bool
|
||||||
config := revel.Config;
|
config := revel.Config
|
||||||
url, ok = config.String("db.url")
|
url, ok = config.String("db.url")
|
||||||
dbname, _ := config.String("db.dbname")
|
dbname, _ := config.String("db.dbname")
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -66,9 +70,9 @@ func Init() {
|
|||||||
if username == "" || password == "" {
|
if username == "" || password == "" {
|
||||||
usernameAndPassword = ""
|
usernameAndPassword = ""
|
||||||
}
|
}
|
||||||
url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
|
url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
|
||||||
}
|
}
|
||||||
|
|
||||||
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
|
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
|
||||||
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
|
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
|
||||||
var err error
|
var err error
|
||||||
@@ -82,55 +86,60 @@ func Init() {
|
|||||||
|
|
||||||
// notebook
|
// notebook
|
||||||
Notebooks = Session.DB(dbname).C("notebooks")
|
Notebooks = Session.DB(dbname).C("notebooks")
|
||||||
|
|
||||||
// notes
|
// notes
|
||||||
Notes = Session.DB(dbname).C("notes")
|
Notes = Session.DB(dbname).C("notes")
|
||||||
|
|
||||||
// noteContents
|
// noteContents
|
||||||
NoteContents = Session.DB(dbname).C("note_contents")
|
NoteContents = Session.DB(dbname).C("note_contents")
|
||||||
NoteContentHistories = Session.DB(dbname).C("note_content_histories")
|
NoteContentHistories = Session.DB(dbname).C("note_content_histories")
|
||||||
|
|
||||||
// share
|
// share
|
||||||
ShareNotes = Session.DB(dbname).C("share_notes")
|
ShareNotes = Session.DB(dbname).C("share_notes")
|
||||||
ShareNotebooks = Session.DB(dbname).C("share_notebooks")
|
ShareNotebooks = Session.DB(dbname).C("share_notebooks")
|
||||||
HasShareNotes = Session.DB(dbname).C("has_share_notes")
|
HasShareNotes = Session.DB(dbname).C("has_share_notes")
|
||||||
|
|
||||||
// user
|
// user
|
||||||
Users = Session.DB(dbname).C("users")
|
Users = Session.DB(dbname).C("users")
|
||||||
|
// group
|
||||||
|
Groups = Session.DB(dbname).C("groups")
|
||||||
|
GroupUsers = Session.DB(dbname).C("group_users")
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
Blogs = Session.DB(dbname).C("blogs")
|
Blogs = Session.DB(dbname).C("blogs")
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
Tags = Session.DB(dbname).C("tags")
|
Tags = Session.DB(dbname).C("tags")
|
||||||
TagNotes = Session.DB(dbname).C("tag_notes")
|
TagNotes = Session.DB(dbname).C("tag_notes")
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
UserBlogs = Session.DB(dbname).C("user_blogs")
|
UserBlogs = Session.DB(dbname).C("user_blogs")
|
||||||
|
BlogSingles = Session.DB(dbname).C("blog_singles")
|
||||||
|
Themes = Session.DB(dbname).C("themes")
|
||||||
|
|
||||||
// find password
|
// find password
|
||||||
Tokens = Session.DB(dbname).C("tokens")
|
Tokens = Session.DB(dbname).C("tokens")
|
||||||
|
|
||||||
// Suggestion
|
// Suggestion
|
||||||
Suggestions = Session.DB(dbname).C("suggestions")
|
Suggestions = Session.DB(dbname).C("suggestions")
|
||||||
|
|
||||||
// Album & file
|
// Album & file
|
||||||
Albums = Session.DB(dbname).C("albums")
|
Albums = Session.DB(dbname).C("albums")
|
||||||
Files = Session.DB(dbname).C("files")
|
Files = Session.DB(dbname).C("files")
|
||||||
Attachs = Session.DB(dbname).C("attachs")
|
Attachs = Session.DB(dbname).C("attachs")
|
||||||
|
|
||||||
NoteImages = Session.DB(dbname).C("note_images")
|
NoteImages = Session.DB(dbname).C("note_images")
|
||||||
|
|
||||||
Configs = Session.DB(dbname).C("configs")
|
Configs = Session.DB(dbname).C("configs")
|
||||||
EmailLogs = Session.DB(dbname).C("email_logs")
|
EmailLogs = Session.DB(dbname).C("email_logs")
|
||||||
|
|
||||||
// 社交
|
// 社交
|
||||||
BlogLikes = Session.DB(dbname).C("blog_likes")
|
BlogLikes = Session.DB(dbname).C("blog_likes")
|
||||||
BlogComments = Session.DB(dbname).C("blog_comments")
|
BlogComments = Session.DB(dbname).C("blog_comments")
|
||||||
|
|
||||||
// 举报
|
// 举报
|
||||||
Reports = Session.DB(dbname).C("reports")
|
Reports = Session.DB(dbname).C("reports")
|
||||||
|
|
||||||
// session
|
// session
|
||||||
Sessions = Session.DB(dbname).C("sessions")
|
Sessions = Session.DB(dbname).C("sessions")
|
||||||
}
|
}
|
||||||
@@ -174,22 +183,29 @@ func UpdateByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId,
|
|||||||
return Err(err)
|
return Err(err)
|
||||||
}
|
}
|
||||||
func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field string, value interface{}) bool {
|
func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field string, value interface{}) bool {
|
||||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field:value}})
|
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field: value}})
|
||||||
}
|
}
|
||||||
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
|
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
|
||||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
|
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool {
|
func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool {
|
||||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field:value}})
|
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field: value}})
|
||||||
}
|
}
|
||||||
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
|
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
|
||||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
|
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
|
||||||
}
|
}
|
||||||
//
|
|
||||||
|
//
|
||||||
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
|
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
|
||||||
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
|
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
|
||||||
return Err(err)
|
return Err(err)
|
||||||
}
|
}
|
||||||
|
func UpdateByQI(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
||||||
|
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
||||||
|
return Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
// 查询条件和值
|
// 查询条件和值
|
||||||
func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
||||||
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
||||||
@@ -255,6 +271,7 @@ func GetByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i i
|
|||||||
}
|
}
|
||||||
collection.Find(q).Select(selector).One(i)
|
collection.Find(q).Select(selector).One(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询某些字段, q是查询条件, fields是字段名列表
|
// 查询某些字段, q是查询条件, fields是字段名列表
|
||||||
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
||||||
selector := make(bson.M, len(fields))
|
selector := make(bson.M, len(fields))
|
||||||
@@ -270,6 +287,11 @@ func GetByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId, i i
|
|||||||
collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i)
|
collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 按field去重
|
||||||
|
func Distinct(collection *mgo.Collection, q bson.M, field string, i interface{}) {
|
||||||
|
collection.Find(q).Distinct(field, i)
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------
|
//----------------------
|
||||||
|
|
||||||
func Count(collection *mgo.Collection, q interface{}) int {
|
func Count(collection *mgo.Collection, q interface{}) int {
|
||||||
@@ -303,9 +325,9 @@ func Err(err error) bool {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
// 删除时, 查找
|
// 删除时, 查找
|
||||||
if err.Error() == "not found" {
|
if err.Error() == "not found" {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 仅仅为了博客的主题
|
||||||
|
|
||||||
|
type BlogInfoCustom struct {
|
||||||
|
UserId string
|
||||||
|
Username string
|
||||||
|
UserLogo string
|
||||||
|
Title string
|
||||||
|
SubTitle string
|
||||||
|
Logo string
|
||||||
|
OpenComment bool
|
||||||
|
CommentType string
|
||||||
|
ThemeId string
|
||||||
|
SubDomain string
|
||||||
|
Domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Post struct {
|
||||||
|
NoteId string
|
||||||
|
}
|
||||||
|
// 归档
|
||||||
|
type Archive struct {
|
||||||
|
Year int
|
||||||
|
Posts []map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TagsCounts []TagCount
|
||||||
|
type TagCount struct {
|
||||||
|
Tag string
|
||||||
|
Count int
|
||||||
|
}
|
||||||
|
func (this TagsCounts) Len() int {
|
||||||
|
return len(this)
|
||||||
|
}
|
||||||
|
func (this TagsCounts) Less(i, j int) bool {
|
||||||
|
return this[i].Count > this[j].Count
|
||||||
|
}
|
||||||
|
func (this TagsCounts) Swap(i, j int) {
|
||||||
|
this[i], this[j] = this[j], this[i]
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
type BlogItem struct {
|
type BlogItem struct {
|
||||||
Note
|
Note
|
||||||
|
Abstract string
|
||||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||||
HasMore bool // 是否是否还有
|
HasMore bool // 是否是否还有
|
||||||
User User // 用户信息
|
User User // 用户信息
|
||||||
@@ -18,13 +19,13 @@ type UserBlogBase struct {
|
|||||||
Logo string `Logo`
|
Logo string `Logo`
|
||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
SubTitle string `SubTitle` // 副标题
|
SubTitle string `SubTitle` // 副标题
|
||||||
AboutMe string `AboutMe` // 关于我
|
// AboutMe string `AboutMe` // 关于我
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserBlogComment struct {
|
type UserBlogComment struct {
|
||||||
CanComment bool `CanComment` // 是否可以评论
|
CanComment bool `CanComment` // 是否可以评论
|
||||||
CommentType string `CommentType` // default 或 disqus
|
CommentType string `CommentType` // default 或 disqus
|
||||||
DisqusId string `DisqusId`
|
DisqusId string `DisqusId`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserBlogStyle struct {
|
type UserBlogStyle struct {
|
||||||
@@ -38,18 +39,47 @@ type UserBlog struct {
|
|||||||
Logo string `Logo`
|
Logo string `Logo`
|
||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
SubTitle string `SubTitle` // 副标题
|
SubTitle string `SubTitle` // 副标题
|
||||||
AboutMe string `AboutMe` // 关于我
|
AboutMe string `AboutMe` // 关于我, 弃用
|
||||||
|
|
||||||
|
CanComment bool `CanComment` // 是否可以评论
|
||||||
|
|
||||||
CanComment bool `CanComment` // 是否可以评论
|
|
||||||
|
|
||||||
CommentType string `CommentType` // default 或 disqus
|
CommentType string `CommentType` // default 或 disqus
|
||||||
DisqusId string `DisqusId`
|
DisqusId string `DisqusId`
|
||||||
|
|
||||||
Style string `Style` // 风格
|
Style string `Style` // 风格
|
||||||
Css string `Css` // 自定义css
|
Css string `Css` // 自定义css
|
||||||
|
|
||||||
|
ThemeId bson.ObjectId `ThemeId,omitempty` // 主题Id
|
||||||
|
ThemePath string `bson:"ThemePath" json:"-"` // 不存值, 从Theme中获取, 相对路径 public/
|
||||||
|
|
||||||
|
CateIds []string `CateIds,omitempty` // 分类Id, 排序好的
|
||||||
|
Singles []map[string]string `Singles,omitempty` // 单页, 排序好的, map包含: ["Title"], ["SingleId"]
|
||||||
|
|
||||||
|
PerPageSize int `PerPageSize,omitempty`
|
||||||
|
SortField string `SortField` // 排序字段
|
||||||
|
IsAsc bool `IsAsc,omitempty` // 排序类型, 降序, 升序, 默认是false, 表示降序
|
||||||
|
|
||||||
SubDomain string `SubDomain` // 二级域名
|
SubDomain string `SubDomain` // 二级域名
|
||||||
Domain string `Domain` // 自定义域名
|
Domain string `Domain` // 自定义域名
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 博客统计信息
|
||||||
|
type BlogStat struct {
|
||||||
|
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
|
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
|
||||||
|
LikeNum int `LikeNum,omitempty` // 点赞次数 2014/9/28
|
||||||
|
CommentNum int `CommentNum,omitempty` // 评论次数 2014/9/28
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单页
|
||||||
|
type BlogSingle struct {
|
||||||
|
SingleId bson.ObjectId `bson:"_id"`
|
||||||
|
UserId bson.ObjectId `UserId`
|
||||||
|
Title string `Title`
|
||||||
|
Content string `Content`
|
||||||
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------
|
//------------------------
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 主题, 每个用户有多个主题, 这里面有主题的配置信息
|
||||||
|
// 模板, css, js, images, 都在路径Path下
|
||||||
|
type Theme struct {
|
||||||
|
ThemeId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
|
UserId bson.ObjectId `UserId`
|
||||||
|
Name string `Name`
|
||||||
|
Version string `Version`
|
||||||
|
Author string `Author`
|
||||||
|
AuthorUrl string `AuthorUrl`
|
||||||
|
Path string `Path` // 文件夹路径
|
||||||
|
Info map[string]interface{} `Info` // 所有信息
|
||||||
|
IsActive bool `IsActive` // 是否在用
|
||||||
|
|
||||||
|
IsDefault bool `IsDefault` // leanote默认主题, 如果用户修改了默认主题, 则先copy之. 也是admin用户的主题
|
||||||
|
Style string `Style,omitempty` // 之前的, 只有default的用户才有blog_default, blog_daqi, blog_left_fixed
|
||||||
|
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
|
}
|
||||||
@@ -34,4 +34,45 @@ type User struct {
|
|||||||
ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别
|
ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别
|
||||||
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
|
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
|
||||||
ThirdType int `ThirdType` // 第三方类型
|
ThirdType int `ThirdType` // 第三方类型
|
||||||
|
|
||||||
|
// 用户的帐户类型
|
||||||
|
|
||||||
|
ImageNum int `bson:"ImageNum" json:"-"` // 图片数量
|
||||||
|
ImageSize int `bson:"ImageSize" json:"-"` // 图片大小
|
||||||
|
AttachNum int `bson:"AttachNum" json:"-"` // 附件数量
|
||||||
|
AttachSize int `bson:"AttachSize" json:"-"` // 附件大小
|
||||||
|
PerAttachSize int `bson:"PerAttachSize" json:"-"` // 单个附件大小
|
||||||
|
|
||||||
|
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
|
||||||
|
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
|
||||||
|
AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期
|
||||||
|
// 阈值
|
||||||
|
MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量
|
||||||
|
MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小
|
||||||
|
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
||||||
|
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
||||||
|
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserAccount struct {
|
||||||
|
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
|
||||||
|
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
|
||||||
|
AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期
|
||||||
|
// 阈值
|
||||||
|
MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量
|
||||||
|
MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小
|
||||||
|
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
||||||
|
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
||||||
|
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户与博客信息结合, 公开
|
||||||
|
type UserAndBlog struct {
|
||||||
|
UserId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
|
Email string `Email` // 全是小写
|
||||||
|
Username string `Username` // 不区分大小写, 全是小写
|
||||||
|
Logo string `Logo`
|
||||||
|
BlogTitle string `BlogTitle` // 博客标题
|
||||||
|
BlogLogo string `BlogLogo` // 博客Logo
|
||||||
|
BlogUrl string `BlogUrl` // 博客链接
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/controllers"
|
"github.com/leanote/leanote/app/controllers"
|
||||||
"github.com/leanote/leanote/app/controllers/admin"
|
"github.com/leanote/leanote/app/controllers/admin"
|
||||||
|
"github.com/leanote/leanote/app/controllers/member"
|
||||||
_ "github.com/leanote/leanote/app/lea/binder"
|
_ "github.com/leanote/leanote/app/lea/binder"
|
||||||
"github.com/leanote/leanote/app/lea/session"
|
"github.com/leanote/leanote/app/lea/session"
|
||||||
"github.com/leanote/leanote/app/lea/memcache"
|
"github.com/leanote/leanote/app/lea/memcache"
|
||||||
@@ -56,6 +57,11 @@ func init() {
|
|||||||
i = i - 1;
|
i = i - 1;
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
// 增加或减少
|
||||||
|
revel.TemplateFuncs["incr"] = func(n, i int) int {
|
||||||
|
n = n + i;
|
||||||
|
return n
|
||||||
|
}
|
||||||
revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
|
revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
|
||||||
if arr == nil {
|
if arr == nil {
|
||||||
return template.HTML("")
|
return template.HTML("")
|
||||||
@@ -79,6 +85,9 @@ func init() {
|
|||||||
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
|
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
|
||||||
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
||||||
}
|
}
|
||||||
|
revel.TemplateFuncs["dateFormat"] = func(t time.Time, format string) template.HTML {
|
||||||
|
return template.HTML(t.Format(format))
|
||||||
|
}
|
||||||
revel.TemplateFuncs["unixDatetime"] = func(unixSec string) template.HTML {
|
revel.TemplateFuncs["unixDatetime"] = func(unixSec string) template.HTML {
|
||||||
sec, _ := strconv.Atoi(unixSec)
|
sec, _ := strconv.Atoi(unixSec)
|
||||||
t := time.Unix(int64(sec), 0)
|
t := time.Unix(int64(sec), 0)
|
||||||
@@ -135,8 +144,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
revel.TemplateFuncs["li"] = func(a string) string {
|
revel.TemplateFuncs["li"] = func(a string) string {
|
||||||
Log(a)
|
|
||||||
Log("life==")
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
// str连接
|
// str连接
|
||||||
@@ -248,6 +255,7 @@ func init() {
|
|||||||
// https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js
|
// https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js
|
||||||
// http://play.golang.org/p/snygrVpQva
|
// http://play.golang.org/p/snygrVpQva
|
||||||
// http://grokbase.com/t/gg/golang-nuts/142a6dhfh3/go-nuts-text-template-using-comparison-operators-eq-gt-etc-on-non-existent-variable-causes-the-template-to-stop-outputting-but-with-no-error-correct-behaviour
|
// http://grokbase.com/t/gg/golang-nuts/142a6dhfh3/go-nuts-text-template-using-comparison-operators-eq-gt-etc-on-non-existent-variable-causes-the-template-to-stop-outputting-but-with-no-error-correct-behaviour
|
||||||
|
/*
|
||||||
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
|
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
|
||||||
switch a1.(type) {
|
switch a1.(type) {
|
||||||
case string:
|
case string:
|
||||||
@@ -273,6 +281,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{{range $i := N 1 10}}
|
{{range $i := N 1 10}}
|
||||||
@@ -302,6 +311,7 @@ func init() {
|
|||||||
service.InitService()
|
service.InitService()
|
||||||
controllers.InitService()
|
controllers.InitService()
|
||||||
admin.InitService()
|
admin.InitService()
|
||||||
|
member.InitService()
|
||||||
service.ConfigS.InitGlobalConfigs()
|
service.ConfigS.InitGlobalConfigs()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package lea
|
package lea
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"path/filepath"
|
|
||||||
"os"
|
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 分离文件名与扩展名(包含.)
|
// 分离文件名与扩展名(包含.)
|
||||||
@@ -14,14 +15,14 @@ func SplitFilename(filename string) (baseName, ext string) {
|
|||||||
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
|
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
|
||||||
baseName = strings.TrimRight(filename, ext)
|
baseName = strings.TrimRight(filename, ext)
|
||||||
ext = strings.ToLower(ext)
|
ext = strings.ToLower(ext)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 转换文件的格式
|
// 转换文件的格式
|
||||||
// toExt包含.
|
// toExt包含.
|
||||||
func TransferExt(path string, toExt string) string {
|
func TransferExt(path string, toExt string) string {
|
||||||
dir := filepath.Dir(path) + "/" // 文件路径
|
dir := filepath.Dir(path) + "/" // 文件路径
|
||||||
name := filepath.Base(path) // 文件名 a.jpg
|
name := filepath.Base(path) // 文件名 a.jpg
|
||||||
// 获取文件名与路径
|
// 获取文件名与路径
|
||||||
baseName, _ := SplitFilename(name)
|
baseName, _ := SplitFilename(name)
|
||||||
return dir + baseName + toExt
|
return dir + baseName + toExt
|
||||||
@@ -38,7 +39,7 @@ func GetFilesize(path string) int64 {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return fileinfo.Size()
|
return fileinfo.Size()
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清空dir下所有的文件和文件夹
|
// 清空dir下所有的文件和文件夹
|
||||||
@@ -79,12 +80,103 @@ func CopyFile(srcName, dstName string) (written int64, err error) {
|
|||||||
return io.Copy(dst, src)
|
return io.Copy(dst, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CopyDir(source string, dest string) (err error) {
|
||||||
|
// get properties of source dir
|
||||||
|
sourceinfo, err := os.Stat(source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create dest dir
|
||||||
|
|
||||||
|
err = os.MkdirAll(dest, sourceinfo.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
directory, _ := os.Open(source)
|
||||||
|
|
||||||
|
objects, err := directory.Readdir(-1)
|
||||||
|
|
||||||
|
for _, obj := range objects {
|
||||||
|
|
||||||
|
sourcefilepointer := source + "/" + obj.Name()
|
||||||
|
|
||||||
|
destinationfilepointer := dest + "/" + obj.Name()
|
||||||
|
|
||||||
|
if obj.IsDir() {
|
||||||
|
// create sub-directories - recursively
|
||||||
|
err = CopyDir(sourcefilepointer, destinationfilepointer)
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Println(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// perform copy
|
||||||
|
_, err = CopyFile(sourcefilepointer, destinationfilepointer)
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteFile(path string) bool {
|
||||||
|
err := os.Remove(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func IsDirExists(path string) bool {
|
func IsDirExists(path string) bool {
|
||||||
fi, err := os.Stat(path)
|
fi, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return os.IsExist(err)
|
return os.IsExist(err)
|
||||||
}else{
|
} else {
|
||||||
return fi.IsDir()
|
return fi.IsDir()
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获得文件str内容
|
||||||
|
func GetFileStrContent(path string) string {
|
||||||
|
fileBytes, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(fileBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsFileExist(filename string) bool {
|
||||||
|
var exist = true
|
||||||
|
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||||
|
exist = false
|
||||||
|
}
|
||||||
|
return exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入string内容
|
||||||
|
func PutFileStrContent(path, content string) bool {
|
||||||
|
var f *os.File
|
||||||
|
var err1 error
|
||||||
|
defer (func() {
|
||||||
|
if f != nil {
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
f, err1 = os.OpenFile(path, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666) //打开文件
|
||||||
|
// Log(err1)
|
||||||
|
// var n int
|
||||||
|
_, err1 = io.WriteString(f, content) //写入文件(字符串)
|
||||||
|
// Log(content)
|
||||||
|
// Log(err1)
|
||||||
|
// Log(n)
|
||||||
|
// Log(path)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
Log(err1)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -27,6 +27,12 @@ var rulesStr = `{
|
|||||||
],
|
],
|
||||||
"domain": [
|
"domain": [
|
||||||
{"rule": "domain", "msg": "errorDomain"}
|
{"rule": "domain", "msg": "errorDomain"}
|
||||||
|
],
|
||||||
|
"perPageSize": [
|
||||||
|
{"rule": "min", "data": "1", "msg": "errorPerPageSize"}
|
||||||
|
],
|
||||||
|
"sortField": [
|
||||||
|
{"rule": "sortField", "msg": "errorSortField"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@@ -49,6 +55,25 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
|
|||||||
ok = len(value) >= dataI
|
ok = len(value) >= dataI
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
|
"min": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := rule["data"]
|
||||||
|
dataI, _ := strconv.Atoi(data)
|
||||||
|
vI, _ := strconv.Atoi(value)
|
||||||
|
ok = vI >= dataI
|
||||||
|
return
|
||||||
|
},
|
||||||
|
|
||||||
|
"sortField": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sortFields := []string{"PublicTime", "CreatedTime", "UpdatedTime", "Title"}
|
||||||
|
ok = InArray(sortFields, value)
|
||||||
|
return
|
||||||
|
},
|
||||||
|
|
||||||
"password": func(value string, rule map[string]string)(ok bool, msg string) {
|
"password": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
if value == "" {
|
if value == "" {
|
||||||
|
|||||||
@@ -0,0 +1,230 @@
|
|||||||
|
package archive
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
// main functions shows how to TarGz a directory/file and
|
||||||
|
// UnTarGz a file
|
||||||
|
// Gzip and tar from source directory or file to destination file
|
||||||
|
// you need check file exist before you call this function
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
/*
|
||||||
|
os.Mkdir("/home/ty4z2008/tar", 0777)
|
||||||
|
w, err := CopyFile("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/src/1.pdf")
|
||||||
|
//targetfile,sourcefile
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
fmt.Println(w)
|
||||||
|
|
||||||
|
TarGz("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/test.tar.gz") //压缩
|
||||||
|
//UnTarGz("/home/ty4z2008/1.tar.gz", "/home/ty4z2008") //解压
|
||||||
|
os.RemoveAll("/home/ty4z2008/tar")
|
||||||
|
*/
|
||||||
|
// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz")
|
||||||
|
Zip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.zip")
|
||||||
|
fmt.Println("ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TarGz(srcDirPath string, destFilePath string) (ok bool) {
|
||||||
|
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
fw, err := os.Create(destFilePath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fw.Close()
|
||||||
|
|
||||||
|
// Gzip writer
|
||||||
|
gw := gzip.NewWriter(fw)
|
||||||
|
defer gw.Close()
|
||||||
|
|
||||||
|
// Tar writer
|
||||||
|
tw := tar.NewWriter(gw)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
// Check if it's a file or a directory
|
||||||
|
f, err := os.Open(srcDirPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if fi.IsDir() {
|
||||||
|
// handle source directory
|
||||||
|
// fmt.Println("Cerating tar.gz from directory...")
|
||||||
|
tarGzDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||||
|
} else {
|
||||||
|
// handle file directly
|
||||||
|
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||||
|
tarGzFile(srcDirPath, fi.Name(), tw, fi)
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with directories
|
||||||
|
// if find files, handle them with tarGzFile
|
||||||
|
// Every recurrence append the base path to the recPath
|
||||||
|
// recPath is the path inside of tar.gz
|
||||||
|
func tarGzDir(srcDirPath string, recPath string, tw *tar.Writer) {
|
||||||
|
// Open source diretory
|
||||||
|
dir, err := os.Open(srcDirPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer dir.Close()
|
||||||
|
|
||||||
|
// Get file info slice
|
||||||
|
fis, err := dir.Readdir(0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, fi := range fis {
|
||||||
|
// Append path
|
||||||
|
curPath := srcDirPath + "/" + fi.Name()
|
||||||
|
// Check it is directory or file
|
||||||
|
if fi.IsDir() {
|
||||||
|
// Directory
|
||||||
|
// (Directory won't add unitl all subfiles are added)
|
||||||
|
// fmt.Printf("Adding path...%s\n", curPath)
|
||||||
|
tarGzDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||||
|
} else {
|
||||||
|
// File
|
||||||
|
// fmt.Printf("Adding file...%s\n", curPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with files
|
||||||
|
func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
|
||||||
|
if fi.IsDir() {
|
||||||
|
// fmt.Println("??")
|
||||||
|
// Create tar header
|
||||||
|
hdr := new(tar.Header)
|
||||||
|
// if last character of header name is '/' it also can be directory
|
||||||
|
// but if you don't set Typeflag, error will occur when you untargz
|
||||||
|
hdr.Name = recPath // + "/"
|
||||||
|
// fmt.Println(hdr.Name)
|
||||||
|
hdr.Typeflag = tar.TypeDir
|
||||||
|
// hdr.Size = 0
|
||||||
|
//hdr.Mode = 0755 | c_ISDIR
|
||||||
|
// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!!
|
||||||
|
// hdr.ModTime = fi.ModTime() // 加这个会有错误!!
|
||||||
|
|
||||||
|
// Write hander
|
||||||
|
err := tw.WriteHeader(hdr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// File reader
|
||||||
|
fr, err := os.Open(srcFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fr.Close()
|
||||||
|
|
||||||
|
// Create tar header
|
||||||
|
hdr := new(tar.Header)
|
||||||
|
hdr.Name = recPath
|
||||||
|
// fmt.Println(hdr.Name)
|
||||||
|
hdr.Size = fi.Size()
|
||||||
|
hdr.Mode = int64(fi.Mode())
|
||||||
|
hdr.ModTime = fi.ModTime()
|
||||||
|
|
||||||
|
// Write hander
|
||||||
|
err = tw.WriteHeader(hdr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file data
|
||||||
|
_, err = io.Copy(tw, fr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ungzip and untar from source file to destination directory
|
||||||
|
// you need check file exist before you call this function
|
||||||
|
func UnTarGz(srcFilePath string, destDirPath string) {
|
||||||
|
// fmt.Println("UnTarGzing " + srcFilePath + "...")
|
||||||
|
// Create destination directory
|
||||||
|
os.Mkdir(destDirPath, os.ModePerm)
|
||||||
|
|
||||||
|
fr, err := os.Open(srcFilePath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fr.Close()
|
||||||
|
|
||||||
|
// Gzip reader
|
||||||
|
gr, err := gzip.NewReader(fr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer gr.Close()
|
||||||
|
|
||||||
|
// Tar reader
|
||||||
|
tr := tar.NewReader(gr)
|
||||||
|
|
||||||
|
for {
|
||||||
|
hdr, err := tr.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
// End of tar archive
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//handleError(err)
|
||||||
|
// fmt.Println("UnTarGzing file..." + hdr.Name)
|
||||||
|
// Check if it is diretory or file
|
||||||
|
if hdr.Typeflag != tar.TypeDir {
|
||||||
|
// Get files from archive
|
||||||
|
// Create diretory before create file
|
||||||
|
os.MkdirAll(destDirPath+"/"+path.Dir(hdr.Name), os.ModePerm)
|
||||||
|
// Write data to file
|
||||||
|
fw, _ := os.Create(destDirPath + "/" + hdr.Name)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(fw, tr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fmt.Println("Well done!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyfile
|
||||||
|
func CopyFile(dstName, srcName string) (written int64, err error) {
|
||||||
|
src, err := os.Open(srcName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
return io.Copy(dst, src)
|
||||||
|
}
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
package archive
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
// main functions shows how to TarGz a directory/file and
|
||||||
|
// UnTarGz a file
|
||||||
|
// Gzip and tar from source directory or file to destination file
|
||||||
|
// you need check file exist before you call this function
|
||||||
|
|
||||||
|
func Zip(srcDirPath string, destFilePath string) (ok bool) {
|
||||||
|
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
fw, err := os.Create(destFilePath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fw.Close()
|
||||||
|
|
||||||
|
// Tar writer
|
||||||
|
tw := zip.NewWriter(fw)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
// Check if it's a file or a directory
|
||||||
|
f, err := os.Open(srcDirPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if fi.IsDir() {
|
||||||
|
// handle source directory
|
||||||
|
// fmt.Println("Cerating tar.gz from directory...")
|
||||||
|
zipDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||||
|
} else {
|
||||||
|
// handle file directly
|
||||||
|
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||||
|
zipFile(srcDirPath, fi.Name(), tw, fi)
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with directories
|
||||||
|
// if find files, handle them with zipFile
|
||||||
|
// Every recurrence append the base path to the recPath
|
||||||
|
// recPath is the path inside of tar.gz
|
||||||
|
func zipDir(srcDirPath string, recPath string, tw *zip.Writer) {
|
||||||
|
// Open source diretory
|
||||||
|
dir, err := os.Open(srcDirPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer dir.Close()
|
||||||
|
|
||||||
|
// Get file info slice
|
||||||
|
fis, err := dir.Readdir(0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, fi := range fis {
|
||||||
|
// Append path
|
||||||
|
curPath := srcDirPath + "/" + fi.Name()
|
||||||
|
// Check it is directory or file
|
||||||
|
if fi.IsDir() {
|
||||||
|
// Directory
|
||||||
|
// (Directory won't add unitl all subfiles are added)
|
||||||
|
// fmt.Printf("Adding path...%s\n", curPath)
|
||||||
|
zipDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||||
|
} else {
|
||||||
|
// File
|
||||||
|
// fmt.Printf("Adding file...%s\n", curPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
zipFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with files
|
||||||
|
func zipFile(srcFile string, recPath string, tw *zip.Writer, fi os.FileInfo) {
|
||||||
|
if fi.IsDir() {
|
||||||
|
// fmt.Println("??")
|
||||||
|
// Create tar header
|
||||||
|
/*
|
||||||
|
fh, err := zip.FileInfoHeader(fi)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fh.Name = recPath // + "/"
|
||||||
|
err = tw.WriteHeader(hdr)
|
||||||
|
tw.Create(recPath)
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
// File reader
|
||||||
|
fr, err := os.Open(srcFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fr.Close()
|
||||||
|
|
||||||
|
// Write hander
|
||||||
|
w, err2 := tw.Create(recPath)
|
||||||
|
if err2 != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Write file data
|
||||||
|
_, err = io.Copy(w, fr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ungzip and untar from source file to destination directory
|
||||||
|
// you need check file exist before you call this function
|
||||||
|
func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
|
||||||
|
ok = false
|
||||||
|
msg = ""
|
||||||
|
|
||||||
|
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
msg = fmt.Sprintf("%v", err)
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
os.Mkdir(destDirPath, os.ModePerm)
|
||||||
|
r, err := zip.OpenReader(srcFilePath);
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer r.Close();
|
||||||
|
for _, f := range r.File {
|
||||||
|
// fmt.Println("FileName : ", f.Name); // j/aaa.zip
|
||||||
|
rc, err := f.Open();
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 把首文件夹去掉, 即j去掉, 分离出文件夹和文件名
|
||||||
|
paths := strings.Split(f.Name, "/")
|
||||||
|
prePath := ""
|
||||||
|
filename := ""
|
||||||
|
l := len(paths)
|
||||||
|
// fmt.Println(l)
|
||||||
|
if l > 1 {
|
||||||
|
// 去掉第1个文件夹
|
||||||
|
if l == 2 {
|
||||||
|
filename = paths[1]
|
||||||
|
} else {
|
||||||
|
filename = paths[l-1]
|
||||||
|
prePath = strings.Join(paths[1:l-1], "/")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filename = f.Name
|
||||||
|
}
|
||||||
|
// fmt.Println(prePath)
|
||||||
|
|
||||||
|
// 相对于目标文件件下的路径
|
||||||
|
destPath := destDirPath + "/" + filename
|
||||||
|
if prePath != "" {
|
||||||
|
os.MkdirAll(destDirPath + "/" + prePath, os.ModePerm)
|
||||||
|
destPath = destDirPath + "/" + prePath + "/" + filename
|
||||||
|
}
|
||||||
|
// Write data to file
|
||||||
|
// fmt.Println(destPath)
|
||||||
|
fw, _ := os.Create(destPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(fw, rc)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,302 @@
|
|||||||
|
package blog
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"html/template"
|
||||||
|
"io/ioutil"
|
||||||
|
// "os"
|
||||||
|
"fmt"
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
// leanote 自定义主题
|
||||||
|
// 不使用revel的模板机制
|
||||||
|
// By life
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
var ts = []string{"header.html", "footer.html", "highlight.html", "comment.html", "view.html", "404.html"}
|
||||||
|
var selfTs = []string{"header.html", "footer.html", "index.html", "about_me.html"} // 用户自定义的文件列表
|
||||||
|
|
||||||
|
type BlogTpl struct {
|
||||||
|
Template *template.Template
|
||||||
|
PathContent map[string]string // path => content
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BlogTpl) Content(name string) string {
|
||||||
|
return this.PathContent[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
var BlogTplObject *BlogTpl
|
||||||
|
var CloneTemplate *template.Template
|
||||||
|
|
||||||
|
type RenderTemplateResult struct {
|
||||||
|
Template *template.Template
|
||||||
|
PathContent map[string]string
|
||||||
|
RenderArgs map[string]interface{}
|
||||||
|
|
||||||
|
IsPreview bool // 是否是预览
|
||||||
|
CurBlogTpl *BlogTpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTemplateError(err error) (templateName string, line int, description string) {
|
||||||
|
description = err.Error()
|
||||||
|
i := regexp.MustCompile(`:\d+:`).FindStringIndex(description)
|
||||||
|
if i != nil {
|
||||||
|
line, err = strconv.Atoi(description[i[0]+1 : i[1]-1])
|
||||||
|
if err != nil {
|
||||||
|
}
|
||||||
|
templateName = description[:i[0]]
|
||||||
|
if colon := strings.Index(templateName, ":"); colon != -1 {
|
||||||
|
templateName = templateName[colon+1:]
|
||||||
|
}
|
||||||
|
templateName = strings.TrimSpace(templateName)
|
||||||
|
description = description[i[1]+1:]
|
||||||
|
}
|
||||||
|
return templateName, line, description
|
||||||
|
}
|
||||||
|
func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response, wr io.Writer) {
|
||||||
|
err := r.Template.Execute(wr, r.RenderArgs)
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var templateContent []string
|
||||||
|
templateName, line, description := parseTemplateError(err)
|
||||||
|
var content = ""
|
||||||
|
if templateName == "" {
|
||||||
|
templateName = r.Template.Name()
|
||||||
|
content = r.PathContent[templateName]
|
||||||
|
} else {
|
||||||
|
content = r.PathContent[templateName]
|
||||||
|
}
|
||||||
|
if content != "" {
|
||||||
|
templateContent = strings.Split(content, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
compileError := &revel.Error{
|
||||||
|
Title: "Template Execution Error",
|
||||||
|
Path: templateName,
|
||||||
|
Description: description,
|
||||||
|
Line: line,
|
||||||
|
SourceLines: templateContent,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 这里, 错误!!
|
||||||
|
// 这里应该导向到本主题的错误页面
|
||||||
|
resp.Status = 500
|
||||||
|
ErrorResult{r.RenderArgs, compileError, r.IsPreview, r.CurBlogTpl}.Apply(req, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||||
|
// Handle panics when rendering templates.
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
chunked := revel.Config.BoolDefault("results.chunked", false)
|
||||||
|
|
||||||
|
// If it's a HEAD request, throw away the bytes.
|
||||||
|
out := io.Writer(resp.Out)
|
||||||
|
if req.Method == "HEAD" {
|
||||||
|
out = ioutil.Discard
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a prod mode, write the status, render, and hope for the best.
|
||||||
|
// (In a dev mode, always render to a temporary buffer first to avoid having
|
||||||
|
// error pages distorted by HTML already written)
|
||||||
|
if chunked && !revel.DevMode {
|
||||||
|
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||||
|
r.render(req, resp, out) // 这里!!!
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the template into a temporary buffer, to see if there was an error
|
||||||
|
// rendering the template. If not, then copy it into the response buffer.
|
||||||
|
// Otherwise, template render errors may result in unpredictable HTML (and
|
||||||
|
// would carry a 200 status code)
|
||||||
|
var b bytes.Buffer
|
||||||
|
r.render(req, resp, &b)
|
||||||
|
if !chunked {
|
||||||
|
resp.Out.Header().Set("Content-Length", strconv.Itoa(b.Len()))
|
||||||
|
}
|
||||||
|
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||||
|
b.WriteTo(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 博客模板
|
||||||
|
func Init() {
|
||||||
|
BlogTplObject = &BlogTpl{PathContent: map[string]string{}}
|
||||||
|
BlogTplObject.Template = template.New("blog").Funcs(revel.TemplateFuncs)
|
||||||
|
for _, path := range ts {
|
||||||
|
fileBytes, _ := ioutil.ReadFile(revel.ViewsPath + "/Blog/" + path)
|
||||||
|
fileStr := string(fileBytes)
|
||||||
|
path := "blog/" + path
|
||||||
|
// path := path
|
||||||
|
BlogTplObject.PathContent[path] = fileStr
|
||||||
|
BlogTplObject.Template.New(path).Parse(fileStr) // 以blog为根
|
||||||
|
}
|
||||||
|
// 复制一份
|
||||||
|
CloneTemplate, _ = BlogTplObject.Template.Clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// name = index.html, search.html, cate.html, page.html
|
||||||
|
// basePath 表未用户主题的基路径, 如/xxx/public/upload/32323232/themes/theme1, 如果没有, 则表示用自带的
|
||||||
|
// isPreview 如果是, 错误提示则显示系统的 500 错误详情信息, 供debug
|
||||||
|
//
|
||||||
|
func RenderTemplate(name string, args map[string]interface{}, basePath string, isPreview bool) revel.Result {
|
||||||
|
var r *RenderTemplateResult
|
||||||
|
// 传来的主题路径为空, 则用系统的
|
||||||
|
// 都不会为空的
|
||||||
|
if basePath == "" {
|
||||||
|
path := "blog/" + name
|
||||||
|
// path := name
|
||||||
|
t := BlogTplObject.Template.Lookup(path)
|
||||||
|
r = &RenderTemplateResult{
|
||||||
|
Template: t,
|
||||||
|
PathContent: BlogTplObject.PathContent, // 为了显示错误
|
||||||
|
RenderArgs: args, // 把args给它
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 复制一份
|
||||||
|
newBlogTplObject := &BlogTpl{}
|
||||||
|
var err error
|
||||||
|
newBlogTplObject.Template, err = CloneTemplate.Clone() // 复制一份, 为防止多用户出现问题, 因为newBlogTplObject是全局的
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
newBlogTplObject.PathContent = map[string]string{}
|
||||||
|
for k, v := range BlogTplObject.PathContent {
|
||||||
|
newBlogTplObject.PathContent[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将该basePath下的所有文件提出
|
||||||
|
files := ListDir(basePath)
|
||||||
|
Log(basePath)
|
||||||
|
LogJ(files);
|
||||||
|
for _, t := range files {
|
||||||
|
if !strings.Contains(t, ".html") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fileBytes, err := ioutil.ReadFile(basePath + "/" + t)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fileStr := string(fileBytes)
|
||||||
|
newBlogTplObject.PathContent[t] = fileStr
|
||||||
|
newBlogTplObject.Template.New(t).Parse(fileStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果本主题下没有, 则用系统的
|
||||||
|
t := newBlogTplObject.Template.Lookup(name)
|
||||||
|
|
||||||
|
if t == nil {
|
||||||
|
path := "blog/" + name
|
||||||
|
t = BlogTplObject.Template.Lookup(path)
|
||||||
|
}
|
||||||
|
r = &RenderTemplateResult{
|
||||||
|
Template: t,
|
||||||
|
PathContent: newBlogTplObject.PathContent, // 为了显示错误
|
||||||
|
RenderArgs: args,
|
||||||
|
CurBlogTpl: newBlogTplObject,
|
||||||
|
IsPreview: isPreview,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// 错误显示
|
||||||
|
|
||||||
|
type ErrorResult struct {
|
||||||
|
RenderArgs map[string]interface{}
|
||||||
|
Error error
|
||||||
|
IsPreview bool
|
||||||
|
CurBlogTpl *BlogTpl
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误显示出
|
||||||
|
func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||||
|
format := req.Format
|
||||||
|
status := resp.Status
|
||||||
|
if status == 0 {
|
||||||
|
status = http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType := revel.ContentTypeByFilename("xxx." + format)
|
||||||
|
if contentType == revel.DefaultFileContentType {
|
||||||
|
contentType = "text/plain"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the error template.
|
||||||
|
var err error
|
||||||
|
templatePath := fmt.Sprintf("errors/%d.%s", status, format)
|
||||||
|
err = nil
|
||||||
|
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
|
||||||
|
|
||||||
|
// This func shows a plaintext error message, in case the template rendering
|
||||||
|
// doesn't work.
|
||||||
|
showPlaintext := func(err error) {
|
||||||
|
revel.PlaintextErrorResult{fmt.Errorf("Server Error:\n%s\n\n"+
|
||||||
|
"Additionally, an error occurred when rendering the error page:\n%s",
|
||||||
|
r.Error, err)}.Apply(req, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据是否是preview来得到404模板
|
||||||
|
// 是, 则显示系统的错误信息, blog-500.html
|
||||||
|
var tmpl *template.Template
|
||||||
|
if r.IsPreview {
|
||||||
|
tmpl = r.CurBlogTpl.Template.Lookup("blog/404.html")
|
||||||
|
} else {
|
||||||
|
tmpl = r.CurBlogTpl.Template.Lookup("404.html")
|
||||||
|
}
|
||||||
|
if tmpl == nil {
|
||||||
|
if err == nil {
|
||||||
|
err = fmt.Errorf("Couldn't find template %s", templatePath)
|
||||||
|
}
|
||||||
|
showPlaintext(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's not a revel error, wrap it in one.
|
||||||
|
var revelError *revel.Error
|
||||||
|
switch e := r.Error.(type) {
|
||||||
|
case *revel.Error:
|
||||||
|
revelError = e
|
||||||
|
case error:
|
||||||
|
revelError = &revel.Error{
|
||||||
|
Title: "Server Error",
|
||||||
|
Description: e.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if revelError == nil {
|
||||||
|
panic("no error provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.RenderArgs == nil {
|
||||||
|
r.RenderArgs = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
r.RenderArgs["Error"] = revelError
|
||||||
|
r.RenderArgs["Router"] = revel.MainRouter
|
||||||
|
|
||||||
|
// 不是preview就不要显示错误了
|
||||||
|
LogJ(revelError)
|
||||||
|
// if r.IsPreview {
|
||||||
|
var b bytes.Buffer
|
||||||
|
out := io.Writer(resp.Out)
|
||||||
|
// out = ioutil.Discard
|
||||||
|
err = tmpl.Execute(&b, r.RenderArgs)
|
||||||
|
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||||
|
b.WriteTo(out)
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"os"
|
"os"
|
||||||
// "path/filepath"
|
// "path/filepath"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
@@ -89,4 +90,13 @@ func trimQueryParams(url string) string {
|
|||||||
url = Substr(url, 0, pos);
|
url = Substr(url, 0, pos);
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过domain得到ip
|
||||||
|
func GetIpFromDomain(domain string) string {
|
||||||
|
ip, _ := net.LookupIP(domain)
|
||||||
|
if ip != nil && len(ip) > 0 {
|
||||||
|
return ip[0].String()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,12 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
|||||||
if route.ControllerName != "Static" {
|
if route.ControllerName != "Static" {
|
||||||
// api设置
|
// api设置
|
||||||
// leanote.com/api/user/get => ApiUser::Get
|
// leanote.com/api/user/get => ApiUser::Get
|
||||||
if strings.HasPrefix(path, "/api/") || strings.HasPrefix(path, "api/") {
|
//* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了
|
||||||
|
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api"){
|
||||||
route.ControllerName = "Api" + route.ControllerName
|
route.ControllerName = "Api" + route.ControllerName
|
||||||
|
} else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "Member") {
|
||||||
|
// member设置
|
||||||
|
route.ControllerName = "Member" + route.ControllerName
|
||||||
}
|
}
|
||||||
// end
|
// end
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
// "github.com/leanote/leanote/app/lea/netutil"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
// "time"
|
// "time"
|
||||||
// "sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
@@ -30,6 +32,13 @@ note, notebook都可设为blog
|
|||||||
type BlogService struct {
|
type BlogService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 得到博客统计信息
|
||||||
|
// ReadNum, LikeNum, CommentNum
|
||||||
|
func (this *BlogService) GetBlogStat(noteId string) (stat info.BlogStat) {
|
||||||
|
note := noteService.GetBlogNote(noteId)
|
||||||
|
stat = info.BlogStat{note.NoteId, note.ReadNum, note.LikeNum, note.CommentNum}
|
||||||
|
return
|
||||||
|
}
|
||||||
// 得到某博客具体信息
|
// 得到某博客具体信息
|
||||||
func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
||||||
note := noteService.GetBlogNote(noteId)
|
note := noteService.GetBlogNote(noteId)
|
||||||
@@ -42,7 +51,7 @@ func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
|||||||
noteContent := noteService.GetNoteContent(note.NoteId.Hex(), note.UserId.Hex())
|
noteContent := noteService.GetNoteContent(note.NoteId.Hex(), note.UserId.Hex())
|
||||||
|
|
||||||
// 组装成blogItem
|
// 组装成blogItem
|
||||||
blog = info.BlogItem{note, noteContent.Content, false, info.User{}}
|
blog = info.BlogItem{note, noteContent.Abstract, noteContent.Content, false, info.User{}}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -56,11 +65,11 @@ func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook {
|
|||||||
|
|
||||||
// 博客列表
|
// 博客列表
|
||||||
// userId 表示谁的blog
|
// userId 表示谁的blog
|
||||||
func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int, sortField string, isAsc bool) (int, []info.BlogItem) {
|
func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int, sortField string, isAsc bool) (info.Page, []info.BlogItem) {
|
||||||
count, notes := noteService.ListNotes(userId, notebookId, false, page, pageSize, sortField, isAsc, true);
|
count, notes := noteService.ListNotes(userId, notebookId, false, page, pageSize, sortField, isAsc, true);
|
||||||
|
|
||||||
if(notes == nil || len(notes) == 0) {
|
if(notes == nil || len(notes) == 0) {
|
||||||
return 0, nil
|
return info.Page{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到content, 并且每个都要substring
|
// 得到content, 并且每个都要substring
|
||||||
@@ -83,47 +92,253 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int
|
|||||||
for i, note := range notes {
|
for i, note := range notes {
|
||||||
hasMore := true
|
hasMore := true
|
||||||
var content string
|
var content string
|
||||||
|
var abstract string
|
||||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||||
content = noteContent.Abstract
|
abstract = noteContent.Abstract
|
||||||
|
content = noteContent.Content
|
||||||
}
|
}
|
||||||
blogs[i] = info.BlogItem{note, content, hasMore, info.User{}}
|
blogs[i] = info.BlogItem{note, abstract, content, hasMore, info.User{}}
|
||||||
}
|
}
|
||||||
return count, blogs
|
|
||||||
|
pageInfo := info.NewPage(page, pageSize, count, nil)
|
||||||
|
|
||||||
|
return pageInfo, blogs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sortField string, isAsc bool) (int, []info.BlogItem) {
|
// 得到博客的标签, 那得先得到所有博客, 比较慢
|
||||||
|
/*
|
||||||
|
[
|
||||||
|
{Tag:xxx, Count: 32}
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
func (this *BlogService) ListBlogsTag(userId string) (info.TagsCounts) {
|
||||||
|
// 得到所有博客
|
||||||
|
notes := []info.Note{}
|
||||||
|
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": false, "IsBlog": true}
|
||||||
|
db.ListByQWithFields(db.Notes, query, []string{"Tags"}, ¬es)
|
||||||
|
if(notes == nil || len(notes) == 0) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// 统计所有的Tags和数目
|
||||||
|
tagsCount := map[string]int{}
|
||||||
|
for _, note := range notes {
|
||||||
|
tags := note.Tags
|
||||||
|
if tags != nil && len(tags) > 0 {
|
||||||
|
for _, tag := range tags {
|
||||||
|
count := tagsCount[tag]
|
||||||
|
count++
|
||||||
|
tagsCount[tag] = count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 排序, 从大到小
|
||||||
|
var tagsCounts info.TagsCounts
|
||||||
|
tagsCounts = make(info.TagsCounts, len(tagsCount))
|
||||||
|
i := 0
|
||||||
|
for tag, count := range tagsCount {
|
||||||
|
tagsCounts[i] = info.TagCount{tag, count}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
sort.Sort(&tagsCounts)
|
||||||
|
return tagsCounts
|
||||||
|
}
|
||||||
|
// 归档博客
|
||||||
|
/*
|
||||||
|
数据: 按年汇总
|
||||||
|
[
|
||||||
|
archive1,
|
||||||
|
archive2,
|
||||||
|
]
|
||||||
|
archive的数据类型是
|
||||||
|
{
|
||||||
|
Year: 2014
|
||||||
|
Posts: []
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
func (this *BlogService) ListBlogsArchive(userId, notebookId string, sortField string, isAsc bool) ([]info.Archive) {
|
||||||
|
_, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true);
|
||||||
|
|
||||||
|
if(notes == nil || len(notes) == 0) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
arcs := []info.Archive{}
|
||||||
|
// 按年汇总
|
||||||
|
arcsMap := map[int]*info.Archive{}
|
||||||
|
var t time.Time
|
||||||
|
var arc *info.Archive
|
||||||
|
everYear := 0
|
||||||
|
for _, note := range notes {
|
||||||
|
if sortField == "PublicTime" {
|
||||||
|
t = note.PublicTime
|
||||||
|
} else if sortField == "CreatedTime"{
|
||||||
|
t = note.CreatedTime
|
||||||
|
} else {
|
||||||
|
t = note.UpdatedTime
|
||||||
|
}
|
||||||
|
year := t.Year()
|
||||||
|
if everYear == 0 {
|
||||||
|
everYear = year
|
||||||
|
}
|
||||||
|
|
||||||
|
if everYear != year {
|
||||||
|
arcs = append(arcs, *arcsMap[everYear])
|
||||||
|
everYear = year
|
||||||
|
}
|
||||||
|
|
||||||
|
if arcT, ok := arcsMap[year]; ok {
|
||||||
|
arc = arcT
|
||||||
|
} else {
|
||||||
|
arc = &info.Archive{Year: year, Posts: []map[string]interface{}{}}
|
||||||
|
}
|
||||||
|
arc.Posts = append(arc.Posts, map[string]interface{}{
|
||||||
|
"NoteId": note.NoteId.Hex(),
|
||||||
|
"Title": note.Title,
|
||||||
|
"CreatedTime": note.CreatedTime,
|
||||||
|
"UpdatedTime": note.UpdatedTime,
|
||||||
|
"PublicTime": note.PublicTime,
|
||||||
|
"Desc": note.Desc,
|
||||||
|
"Tags": note.Tags,
|
||||||
|
"CommentNum": note.CommentNum,
|
||||||
|
"ReadNum": note.ReadNum,
|
||||||
|
"LikeNum": note.LikeNum,
|
||||||
|
"IsMarkdown": note.IsMarkdown,
|
||||||
|
});
|
||||||
|
arcsMap[year] = arc
|
||||||
|
}
|
||||||
|
// 最后一个
|
||||||
|
arcs = append(arcs, *arcsMap[everYear])
|
||||||
|
|
||||||
|
return arcs
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据tag搜索博客
|
||||||
|
func (this *BlogService) SearchBlogByTags(tags []string, userId string, pageNumber, pageSize int, sortField string, isAsc bool) (pageInfo info.Page, blogs []info.BlogItem) {
|
||||||
|
notes := []info.Note{}
|
||||||
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
|
|
||||||
|
// 不是trash的
|
||||||
|
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
|
"IsTrash": false,
|
||||||
|
"IsBlog": true,
|
||||||
|
"Tags": bson.M{"$all": tags}}
|
||||||
|
|
||||||
|
q := db.Notes.Find(query);
|
||||||
|
|
||||||
|
// 总记录数
|
||||||
|
count, _ := q.Count()
|
||||||
|
if count == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
q.Sort(sortFieldR).
|
||||||
|
Skip(skipNum).
|
||||||
|
Limit(pageSize).
|
||||||
|
All(¬es)
|
||||||
|
|
||||||
|
blogs = this.notes2BlogItems(notes)
|
||||||
|
pageInfo = info.NewPage(pageNumber, pageSize, count, nil)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BlogService) notes2BlogItems(notes []info.Note) []info.BlogItem{
|
||||||
|
// 得到content, 并且每个都要substring
|
||||||
|
noteIds := make([]bson.ObjectId, len(notes))
|
||||||
|
for i, note := range notes {
|
||||||
|
noteIds[i] = note.NoteId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接得到noteContents表的abstract
|
||||||
|
// 这里可能是乱序的
|
||||||
|
noteContents := noteService.ListNoteContentByNoteIds(noteIds) // 返回[info.NoteContent]
|
||||||
|
noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents))
|
||||||
|
for _, noteContent := range noteContents {
|
||||||
|
noteContentsMap[noteContent.NoteId] = noteContent
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装成blogItem
|
||||||
|
// 按照notes的顺序
|
||||||
|
blogs := make([]info.BlogItem, len(noteIds))
|
||||||
|
for i, note := range notes {
|
||||||
|
hasMore := true
|
||||||
|
var content, abstract string
|
||||||
|
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||||
|
abstract = noteContent.Abstract
|
||||||
|
content = noteContent.Content
|
||||||
|
}
|
||||||
|
blogs[i] = info.BlogItem{note, abstract, content, hasMore, info.User{}}
|
||||||
|
}
|
||||||
|
return blogs
|
||||||
|
}
|
||||||
|
func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sortField string, isAsc bool) (info.Page, []info.BlogItem) {
|
||||||
count, notes := noteService.SearchNote(key, userId, page, pageSize, sortField, isAsc, true);
|
count, notes := noteService.SearchNote(key, userId, page, pageSize, sortField, isAsc, true);
|
||||||
|
|
||||||
if(notes == nil || len(notes) == 0) {
|
if(notes == nil || len(notes) == 0) {
|
||||||
return 0, nil
|
return info.Page{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到content, 并且每个都要substring
|
blogs := this.notes2BlogItems(notes)
|
||||||
noteIds := make([]bson.ObjectId, len(notes))
|
pageInfo := info.NewPage(page, pageSize, count, nil)
|
||||||
for i, note := range notes {
|
return pageInfo, blogs
|
||||||
noteIds[i] = note.NoteId
|
}
|
||||||
|
|
||||||
|
// 上一篇文章, 下一篇文章
|
||||||
|
// sorterField, baseTime是基准, sorterField=PublicTime, title
|
||||||
|
// isAsc是用户自定义的排序方式
|
||||||
|
func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bool, baseTime interface{}) (info.Note, info.Note) {
|
||||||
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
var sortFieldT1, sortFieldT2 bson.M
|
||||||
|
var sortFieldR1, sortFieldR2 string
|
||||||
|
if !isAsc {
|
||||||
|
// 降序
|
||||||
|
/*
|
||||||
|
------- pre
|
||||||
|
----- now
|
||||||
|
--- next
|
||||||
|
--
|
||||||
|
*/
|
||||||
|
// 上一篇时间要比它大, 找最小的
|
||||||
|
sortFieldT1 = bson.M{"$gt": baseTime}
|
||||||
|
sortFieldR1 = sorterField
|
||||||
|
// 下一篇时间要比它小
|
||||||
|
sortFieldT2 = bson.M{"$lt": baseTime}
|
||||||
|
sortFieldR2 = "-" + sorterField
|
||||||
|
} else {
|
||||||
|
// 升序
|
||||||
|
/*
|
||||||
|
--- pre
|
||||||
|
----- now
|
||||||
|
------- next
|
||||||
|
---------
|
||||||
|
*/
|
||||||
|
// 上一篇要比它小, 找最大的
|
||||||
|
sortFieldT1 = bson.M{"$lt": baseTime}
|
||||||
|
sortFieldR1 = "-" + sorterField
|
||||||
|
// 下一篇, 找最小的
|
||||||
|
sortFieldT2 = bson.M{"$gt": baseTime}
|
||||||
|
sortFieldR2 = sorterField
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接得到noteContents表的abstract
|
// 上一篇, 比基时间要小, 但是是最后一篇, 所以是降序
|
||||||
// 这里可能是乱序的
|
note := info.Note{}
|
||||||
noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent]
|
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true,
|
||||||
noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents))
|
sorterField: sortFieldT1,
|
||||||
for _, noteContent := range noteContents {
|
|
||||||
noteContentsMap[noteContent.NoteId] = noteContent
|
|
||||||
}
|
}
|
||||||
|
q := db.Notes.Find(query);
|
||||||
|
q.Sort(sortFieldR1).Limit(1).One(¬e)
|
||||||
|
|
||||||
|
// 下一篇, 比基时间要大, 但是是第一篇, 所以是升序
|
||||||
|
note2 := info.Note{}
|
||||||
|
query[sorterField] = sortFieldT2
|
||||||
|
// Log(isAsc)
|
||||||
|
// LogJ(query)
|
||||||
|
// Log(sortFieldR2)
|
||||||
|
q = db.Notes.Find(query);
|
||||||
|
q.Sort(sortFieldR2).Limit(1).One(¬e2)
|
||||||
|
|
||||||
// 组装成blogItem
|
return note, note2
|
||||||
// 按照notes的顺序
|
|
||||||
blogs := make([]info.BlogItem, len(noteIds))
|
|
||||||
for i, note := range notes {
|
|
||||||
hasMore := true
|
|
||||||
var content string
|
|
||||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
|
||||||
content = noteContent.Abstract
|
|
||||||
}
|
|
||||||
blogs[i] = info.BlogItem{note, content, hasMore, info.User{}}
|
|
||||||
}
|
|
||||||
return count, blogs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------
|
//-------
|
||||||
@@ -200,29 +415,39 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b
|
|||||||
content = noteContent.Abstract
|
content = noteContent.Abstract
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
blogs[i] = info.BlogItem{note, content, hasMore, userMap[note.UserId]}
|
blogs[i] = info.BlogItem{note, "", content, hasMore, userMap[note.UserId]}
|
||||||
}
|
}
|
||||||
pageInfo = info.NewPage(page, pageSize, count, nil)
|
pageInfo = info.NewPage(page, pageSize, count, nil)
|
||||||
|
|
||||||
return pageInfo, blogs
|
return pageInfo, blogs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------
|
//------------------------
|
||||||
// 博客设置
|
// 博客设置
|
||||||
func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) {
|
func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) {
|
||||||
/*
|
|
||||||
if userBlog.Title == "" {
|
|
||||||
userInfo := userService.GetUserInfo(userBlog)
|
|
||||||
userBlog.Title = userInfo.Username + " 's Blog"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Logo路径问题, 有些有http: 有些没有
|
// Logo路径问题, 有些有http: 有些没有
|
||||||
Log(userBlog.Logo)
|
|
||||||
if userBlog.Logo != "" && !strings.HasPrefix(userBlog.Logo, "http") {
|
if userBlog.Logo != "" && !strings.HasPrefix(userBlog.Logo, "http") {
|
||||||
userBlog.Logo = strings.Trim(userBlog.Logo, "/")
|
userBlog.Logo = strings.Trim(userBlog.Logo, "/")
|
||||||
userBlog.Logo = siteUrl + "/" + userBlog.Logo
|
userBlog.Logo = siteUrl + "/" + userBlog.Logo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if userBlog.SortField == "" {
|
||||||
|
userBlog.SortField = "PublicTime"
|
||||||
|
}
|
||||||
|
if userBlog.PerPageSize <= 0 {
|
||||||
|
userBlog.PerPageSize = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// themePath
|
||||||
|
if userBlog.Style == "" {
|
||||||
|
userBlog.Style = defaultStyle
|
||||||
|
}
|
||||||
|
if userBlog.ThemeId == "" {
|
||||||
|
userBlog.ThemePath = themeService.GetDefaultThemePath(userBlog.Style)
|
||||||
|
} else {
|
||||||
|
userBlog.ThemePath = themeService.GetThemePath(userBlog.UserId.Hex(), userBlog.ThemeId.Hex())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (this *BlogService) GetUserBlog(userId string) info.UserBlog {
|
func (this *BlogService) GetUserBlog(userId string) info.UserBlog {
|
||||||
userBlog := info.UserBlog{}
|
userBlog := info.UserBlog{}
|
||||||
@@ -246,7 +471,28 @@ func (this *BlogService) UpdateUserBlogComment(userId string, userBlog info.User
|
|||||||
func (this *BlogService) UpdateUserBlogStyle(userId string, userBlog info.UserBlogStyle) bool {
|
func (this *BlogService) UpdateUserBlogStyle(userId string, userBlog info.UserBlogStyle) bool {
|
||||||
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||||
}
|
}
|
||||||
|
// 分页与排序
|
||||||
|
func (this *BlogService) UpdateUserBlogPaging(userId string, perPageSize int, sortField string, isAsc bool) (ok bool, msg string) {
|
||||||
|
if ok, msg = Vds(map[string]string{"perPageSize": strconv.Itoa(perPageSize), "sortField": sortField}); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)},
|
||||||
|
bson.M{"PerPageSize": perPageSize, "SortField": sortField, "IsAsc": isAsc})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BlogService) GetUserBlogBySubDomain(subDomain string) info.UserBlog {
|
||||||
|
blogUser := info.UserBlog{}
|
||||||
|
db.GetByQ(db.UserBlogs, bson.M{"SubDomain": subDomain}, &blogUser)
|
||||||
|
this.fixUserBlog(&blogUser)
|
||||||
|
return blogUser
|
||||||
|
}
|
||||||
|
func (this *BlogService) GetUserBlogByDomain(domain string) info.UserBlog {
|
||||||
|
blogUser := info.UserBlog{}
|
||||||
|
db.GetByQ(db.UserBlogs, bson.M{"Domain": domain}, &blogUser)
|
||||||
|
this.fixUserBlog(&blogUser)
|
||||||
|
return blogUser
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
// 后台管理
|
// 后台管理
|
||||||
@@ -264,7 +510,7 @@ func (this *BlogService) SetRecommend(noteId string, isRecommend bool) bool {
|
|||||||
// 博客社交, 评论
|
// 博客社交, 评论
|
||||||
|
|
||||||
// 返回所有liked用户, bool是否还有
|
// 返回所有liked用户, bool是否还有
|
||||||
func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.User, bool) {
|
func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.UserAndBlog, bool) {
|
||||||
// 默认前5
|
// 默认前5
|
||||||
pageSize := 5
|
pageSize := 5
|
||||||
skipNum, sortFieldR := parsePageAndSort(1, pageSize, "CreatedTime", false)
|
skipNum, sortFieldR := parsePageAndSort(1, pageSize, "CreatedTime", false)
|
||||||
@@ -291,11 +537,11 @@ func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.User,
|
|||||||
userIds[i] = like.UserId
|
userIds[i] = like.UserId
|
||||||
}
|
}
|
||||||
// 得到用户信息
|
// 得到用户信息
|
||||||
userMap := userService.MapUserInfoAndBlogInfosByUserIds(userIds)
|
userMap := userService.MapUserAndBlogByUserIds(userIds)
|
||||||
|
|
||||||
users := make([]info.User, len(likes));
|
users := make([]info.UserAndBlog, len(likes));
|
||||||
for i, like := range likes {
|
for i, like := range likes {
|
||||||
users[i] = userMap[like.UserId]
|
users[i] = userMap[like.UserId.Hex()]
|
||||||
}
|
}
|
||||||
|
|
||||||
return users, count > pageSize
|
return users, count > pageSize
|
||||||
@@ -495,7 +741,7 @@ func (this *BlogService) LikeComment(commentId, userId string) (ok bool, isILike
|
|||||||
// 评论列表
|
// 评论列表
|
||||||
// userId主要是显示userId是否点过某评论的赞
|
// userId主要是显示userId是否点过某评论的赞
|
||||||
// 还要获取用户信息
|
// 还要获取用户信息
|
||||||
func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) (info.Page, []info.BlogCommentPublic, map[string]info.User) {
|
func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) (info.Page, []info.BlogCommentPublic, map[string]info.UserAndBlog) {
|
||||||
pageInfo := info.Page{CurPage: page}
|
pageInfo := info.Page{CurPage: page}
|
||||||
|
|
||||||
comments2 := []info.BlogComment{}
|
comments2 := []info.BlogComment{}
|
||||||
@@ -540,15 +786,10 @@ func (this *BlogService) ListComments(userId, noteId string, page, pageSize int)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 得到用户信息
|
// 得到用户信息
|
||||||
userMap := userService.MapUserInfoByUserIds(userIds)
|
userMap := userService.MapUserAndBlogByUserIds(userIds)
|
||||||
userMap2 := make(map[string]info.User, len(userMap))
|
|
||||||
for userId, v := range userMap {
|
|
||||||
userMap2[userId.Hex()] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
pageInfo = info.NewPage(page, pageSize, count, nil)
|
pageInfo = info.NewPage(page, pageSize, count, nil)
|
||||||
|
|
||||||
return pageInfo, comments, userMap2
|
return pageInfo, comments, userMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// 举报
|
// 举报
|
||||||
@@ -568,4 +809,127 @@ func (this *BlogService) Report(noteId, commentId, reason, userId string) (bool)
|
|||||||
report.CommentId = bson.ObjectIdHex(commentId)
|
report.CommentId = bson.ObjectIdHex(commentId)
|
||||||
}
|
}
|
||||||
return db.Insert(db.Reports, report)
|
return db.Insert(db.Reports, report)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------
|
||||||
|
// 分类排序
|
||||||
|
|
||||||
|
// CateIds
|
||||||
|
func (this *BlogService) UpateCateIds(userId string, cateIds[] string) bool {
|
||||||
|
return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "CateIds", cateIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单页
|
||||||
|
func (this *BlogService) GetSingles(userId string) []map[string]string {
|
||||||
|
userBlog := this.GetUserBlog(userId)
|
||||||
|
singles := userBlog.Singles
|
||||||
|
return singles
|
||||||
|
}
|
||||||
|
func (this *BlogService) GetSingle(singleId string) info.BlogSingle {
|
||||||
|
page := info.BlogSingle{}
|
||||||
|
db.Get(db.BlogSingles, singleId, &page)
|
||||||
|
return page
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BlogService) updateBlogSingles(userId string, isDelete bool, isAdd bool, singleId, title string) (ok bool) {
|
||||||
|
userBlog := this.GetUserBlog(userId)
|
||||||
|
singles := userBlog.Singles
|
||||||
|
if singles == nil {
|
||||||
|
singles = []map[string]string{}
|
||||||
|
}
|
||||||
|
if isDelete || !isAdd { // 删除或更新, 需要找到相应的
|
||||||
|
i := 0
|
||||||
|
for _, p := range singles {
|
||||||
|
if p["SingleId"] == singleId {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
// 得到i
|
||||||
|
// 找不到
|
||||||
|
if i == len(singles) {
|
||||||
|
} else {
|
||||||
|
// 找到了, 如果是删除, 则删除
|
||||||
|
if isDelete {
|
||||||
|
singles = append(singles[:i], singles[i+1:]...)
|
||||||
|
} else {
|
||||||
|
singles[i]["Title"] = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 是添加, 直接添加到最后
|
||||||
|
singles = append(singles, map[string]string{"SingleId": singleId, "Title": title})
|
||||||
|
}
|
||||||
|
return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "Singles", singles)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除页面
|
||||||
|
func (this *BlogService) DeleteSingle(userId, singleId string) (ok bool) {
|
||||||
|
ok = db.DeleteByIdAndUserId(db.BlogSingles, singleId, userId)
|
||||||
|
if ok {
|
||||||
|
// 还要修改UserBlog中的Singles
|
||||||
|
this.updateBlogSingles(userId, true, false, singleId, "")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 更新或添加
|
||||||
|
func (this *BlogService) AddOrUpdateSingle(userId, singleId, title, content string) (ok bool) {
|
||||||
|
ok = false
|
||||||
|
if singleId != "" {
|
||||||
|
ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{
|
||||||
|
"Title": title,
|
||||||
|
"Content": content,
|
||||||
|
"UpdatedTime": time.Now(),
|
||||||
|
})
|
||||||
|
if ok {
|
||||||
|
// 还要修改UserBlog中的Singles
|
||||||
|
this.updateBlogSingles(userId, false, false, singleId, title)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 添加
|
||||||
|
page := info.BlogSingle{SingleId: bson.NewObjectId(), UserId: bson.ObjectIdHex(userId), Title: title, Content: content,
|
||||||
|
CreatedTime: time.Now(),
|
||||||
|
}
|
||||||
|
page.UpdatedTime = page.CreatedTime
|
||||||
|
ok = db.Insert(db.BlogSingles, page)
|
||||||
|
|
||||||
|
// 还要修改UserBlog中的Singles
|
||||||
|
this.updateBlogSingles(userId, false, true, page.SingleId.Hex(), title)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新排序
|
||||||
|
func (this *BlogService) SortSingles(userId string, singleIds []string) (ok bool) {
|
||||||
|
if singleIds == nil || len(singleIds) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userBlog := this.GetUserBlog(userId)
|
||||||
|
singles := userBlog.Singles
|
||||||
|
if singles == nil || len(singles) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
singlesMap := map[string]map[string]string{}
|
||||||
|
for _, page := range singles {
|
||||||
|
singlesMap[page["SingleId"]] = page
|
||||||
|
}
|
||||||
|
|
||||||
|
singles2 := make([]map[string]string, len(singles))
|
||||||
|
for i, singleId := range singleIds {
|
||||||
|
singles2[i] = singlesMap[singleId]
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "Singles", singles2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到用户的博客url
|
||||||
|
func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog) (string) {
|
||||||
|
if userBlog.Domain != "" && configService.AllowCustomDomain() {
|
||||||
|
return configService.GetUserUrl(userBlog.Domain)
|
||||||
|
} else if userBlog.SubDomain != "" {
|
||||||
|
return configService.GetUserSubUrl(userBlog.SubDomain)
|
||||||
|
}
|
||||||
|
return configService.GetBlogUrl() + "/" + userBlog.UserId.Hex()
|
||||||
|
}
|
||||||
@@ -111,6 +111,11 @@ func (this *NoteService) ListNoteAbstractsByNoteIds(noteIds []bson.ObjectId) (no
|
|||||||
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract"}, ¬es)
|
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract"}, ¬es)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (this *NoteService) ListNoteContentByNoteIds(noteIds []bson.ObjectId) (notes []info.NoteContent) {
|
||||||
|
notes = []info.NoteContent{}
|
||||||
|
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract", "Content"}, ¬es)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 添加笔记
|
// 添加笔记
|
||||||
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
||||||
@@ -171,6 +176,17 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
|
|||||||
|
|
||||||
// 添加笔记和内容
|
// 添加笔记和内容
|
||||||
// 这里使用 info.NoteAndContent 接收?
|
// 这里使用 info.NoteAndContent 接收?
|
||||||
|
func (this *NoteService) AddNoteAndContentForController(note info.Note, noteContent info.NoteContent, updatedUserId string) info.Note {
|
||||||
|
if note.UserId.Hex() != updatedUserId {
|
||||||
|
if !shareService.HasUpdateNotebookPerm(note.UserId.Hex(), updatedUserId, note.NotebookId.Hex()) {
|
||||||
|
Log("NO AUTH11")
|
||||||
|
return info.Note{}
|
||||||
|
} else {
|
||||||
|
Log("HAS AUTH -----------")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.AddNoteAndContent(note, noteContent, bson.ObjectIdHex(updatedUserId));
|
||||||
|
}
|
||||||
func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
||||||
if(note.NoteId.Hex() == "") {
|
if(note.NoteId.Hex() == "") {
|
||||||
noteId := bson.NewObjectId()
|
noteId := bson.NewObjectId()
|
||||||
@@ -194,7 +210,7 @@ func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUp
|
|||||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||||
if userId != updatedUserId {
|
if userId != updatedUserId {
|
||||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||||
Log("NO AUTH")
|
Log("NO AUTH2")
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
Log("HAS AUTH -----------")
|
Log("HAS AUTH -----------")
|
||||||
@@ -419,15 +435,20 @@ func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------
|
//------------------
|
||||||
// 搜索Note
|
// 搜索Note, 博客使用了
|
||||||
func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int, sortField string, isAsc, isBlog bool) (count int, notes []info.Note) {
|
func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int, sortField string, isAsc, isBlog bool) (count int, notes []info.Note) {
|
||||||
notes = []info.Note{}
|
notes = []info.Note{}
|
||||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
|
|
||||||
|
// 利用标题和desc, 不用content
|
||||||
|
orQ := []bson.M{
|
||||||
|
bson.M{"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}},
|
||||||
|
bson.M{"Desc": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}},
|
||||||
|
}
|
||||||
// 不是trash的
|
// 不是trash的
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
"IsTrash": false,
|
"IsTrash": false,
|
||||||
"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}},
|
"$or": orQ,
|
||||||
}
|
}
|
||||||
if isBlog {
|
if isBlog {
|
||||||
query["IsBlog"] = true
|
query["IsBlog"] = true
|
||||||
@@ -509,11 +530,20 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------
|
//------------
|
||||||
// 统计
|
// 统计
|
||||||
func (this *NoteService) CountNote() int {
|
func (this *NoteService) CountNote(userId string) int {
|
||||||
return db.Count(db.Notes, bson.M{"IsTrash": false})
|
q := bson.M{"IsTrash": false}
|
||||||
|
if userId != "" {
|
||||||
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
|
}
|
||||||
|
return db.Count(db.Notes, q)
|
||||||
}
|
}
|
||||||
func (this *NoteService) CountBlog() int {
|
func (this *NoteService) CountBlog(userId string) int {
|
||||||
return db.Count(db.Notes, bson.M{"IsBlog": true, "IsTrash": false})
|
q := bson.M{"IsBlog": true, "IsTrash": false}
|
||||||
|
if userId != "" {
|
||||||
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
|
}
|
||||||
|
return db.Count(db.Notes, q)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,477 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/lea/archive"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
"strings"
|
||||||
|
"os"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"regexp"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 主题
|
||||||
|
type ThemeService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultStyle = "blog_default"
|
||||||
|
var elegantStyle = "blog_daqi"
|
||||||
|
var fixedStyle = "blog_left_fixed"
|
||||||
|
|
||||||
|
// admin用户的主题基路径
|
||||||
|
func (this *ThemeService) getDefaultThemeBasePath() string {
|
||||||
|
return revel.BasePath + "/public/blog/themes"
|
||||||
|
}
|
||||||
|
// 默认主题路径
|
||||||
|
func (this *ThemeService) getDefaultThemePath(style string) string {
|
||||||
|
if style == elegantStyle {
|
||||||
|
return this.getDefaultThemeBasePath() + "/elegant"
|
||||||
|
} else if style == fixedStyle {
|
||||||
|
return this.getDefaultThemeBasePath() + "/nav_fixed"
|
||||||
|
} else {
|
||||||
|
return this.getDefaultThemeBasePath() + "/default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// blogService用
|
||||||
|
func (this *ThemeService) GetDefaultThemePath(style string) string {
|
||||||
|
if style == elegantStyle {
|
||||||
|
return "public/blog/themes/elegant"
|
||||||
|
} else if style == fixedStyle {
|
||||||
|
return "public/blog/themes/nav_fixed"
|
||||||
|
} else {
|
||||||
|
return "public/blog/themes/default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到默认主题
|
||||||
|
// style是之前的值, 有3个值 blog_default, blog_daqi, blog_left_fixed
|
||||||
|
func (this *ThemeService) getDefaultTheme(style string) info.Theme {
|
||||||
|
if style == elegantStyle {
|
||||||
|
return info.Theme{
|
||||||
|
IsDefault: true,
|
||||||
|
Path: "public/blog/themes/elegant",
|
||||||
|
Name: "leanote elegant",
|
||||||
|
Author: "leanote",
|
||||||
|
AuthorUrl: "http://leanote.com",
|
||||||
|
Version: "1.0",
|
||||||
|
}
|
||||||
|
} else if style == fixedStyle {
|
||||||
|
return info.Theme{
|
||||||
|
IsDefault: true,
|
||||||
|
Path: "public/blog/themes/nav_fixed",
|
||||||
|
Name: "leanote nav fixed",
|
||||||
|
Author: "leanote",
|
||||||
|
AuthorUrl: "http://leanote.com",
|
||||||
|
Version: "1.0",
|
||||||
|
}
|
||||||
|
} else { // blog default
|
||||||
|
return info.Theme{
|
||||||
|
IsDefault: true,
|
||||||
|
Path: "public/blog/themes/default",
|
||||||
|
Name: "leanote default",
|
||||||
|
Author: "leanote",
|
||||||
|
AuthorUrl: "http://leanote.com",
|
||||||
|
Version: "1.0",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户的主题路径设置
|
||||||
|
func (this *ThemeService) getUserThemeBasePath(userId string) string {
|
||||||
|
return revel.BasePath + "/public/upload/" + userId + "/themes"
|
||||||
|
}
|
||||||
|
func (this *ThemeService) getUserThemePath(userId, themeId string) string {
|
||||||
|
return this.getUserThemeBasePath(userId) + "/" + themeId
|
||||||
|
}
|
||||||
|
func (this *ThemeService) getUserThemePath2(userId, themeId string) string {
|
||||||
|
return "public/upload/" + userId + "/themes/" + themeId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新建主题
|
||||||
|
// 复制默认主题到文件夹下
|
||||||
|
func (this *ThemeService) CopyDefaultTheme(userBlog info.UserBlog) (ok bool, themeId string) {
|
||||||
|
newThemeId := bson.NewObjectId()
|
||||||
|
themeId = newThemeId.Hex()
|
||||||
|
userId := userBlog.UserId.Hex()
|
||||||
|
themePath := this.getUserThemePath(userId, themeId)
|
||||||
|
err := os.MkdirAll(themePath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 复制默认主题
|
||||||
|
defaultThemePath := this.getDefaultThemePath(userBlog.Style)
|
||||||
|
err = CopyDir(defaultThemePath, themePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到数据库中
|
||||||
|
theme, _ := this.getThemeConfig(themePath)
|
||||||
|
theme.ThemeId = newThemeId
|
||||||
|
theme.Path = this.getUserThemePath2(userId, themeId)
|
||||||
|
theme.CreatedTime = time.Now()
|
||||||
|
theme.UpdatedTime = theme.CreatedTime
|
||||||
|
theme.UserId = bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
ok = db.Insert(db.Themes, theme)
|
||||||
|
return ok, themeId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一次新建主题
|
||||||
|
// 设为active true
|
||||||
|
func (this *ThemeService) NewThemeForFirst(userBlog info.UserBlog) (ok bool, themeId string) {
|
||||||
|
ok, themeId = this.CopyDefaultTheme(userBlog)
|
||||||
|
db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新建主题, 判断是否有主题了
|
||||||
|
func (this *ThemeService) NewTheme(userId string) (ok bool, themeId string) {
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
// 如果还没有主题, 那先复制旧的主题
|
||||||
|
if userBlog.ThemeId == "" {
|
||||||
|
themeService.NewThemeForFirst(userBlog)
|
||||||
|
}
|
||||||
|
// 再copy一个默认主题
|
||||||
|
userBlog.Style = "defaultStyle";
|
||||||
|
ok, themeId = this.CopyDefaultTheme(userBlog)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将字符串转成Theme配置
|
||||||
|
func (this *ThemeService) parseConfig(configStr string) (theme info.Theme, err error) {
|
||||||
|
theme = info.Theme{}
|
||||||
|
// 除去/**/注释
|
||||||
|
reg, _ := regexp.Compile("/\\*[\\s\\S]*?\\*/")
|
||||||
|
configStr = reg.ReplaceAllString(configStr, "")
|
||||||
|
// 转成map
|
||||||
|
config := map[string]interface{}{}
|
||||||
|
err = json.Unmarshal([]byte(configStr), &config)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 没有错, 则将Name, Version, Author, AuthorUrl
|
||||||
|
Name := config["Name"]
|
||||||
|
if Name != nil {
|
||||||
|
theme.Name = Name.(string)
|
||||||
|
}
|
||||||
|
Version := config["Version"]
|
||||||
|
if Version != nil {
|
||||||
|
theme.Version = Version.(string)
|
||||||
|
}
|
||||||
|
Author := config["Author"]
|
||||||
|
if Author != nil {
|
||||||
|
theme.Author = Author.(string)
|
||||||
|
}
|
||||||
|
AuthorUrl := config["AuthorUrl"]
|
||||||
|
if AuthorUrl != nil {
|
||||||
|
theme.AuthorUrl = AuthorUrl.(string)
|
||||||
|
}
|
||||||
|
theme.Info = config
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取theme.json得到值
|
||||||
|
func (this *ThemeService) getThemeConfig(themePath string) (theme info.Theme, err error) {
|
||||||
|
theme = info.Theme{}
|
||||||
|
configStr := GetFileStrContent(themePath + "/theme.json")
|
||||||
|
theme, err = this.parseConfig(configStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ThemeService) GetTheme(userId, themeId string) info.Theme {
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQ(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, &theme)
|
||||||
|
return theme
|
||||||
|
}
|
||||||
|
func (this *ThemeService) GetThemeById(themeId string) info.Theme {
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQ(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, &theme)
|
||||||
|
return theme
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到主题信息, 为了给博客用
|
||||||
|
func (this *ThemeService) GetThemeInfo(themeId, style string) map[string]interface{} {
|
||||||
|
q := bson.M{}
|
||||||
|
if themeId == "" {
|
||||||
|
if style == "" {
|
||||||
|
style = defaultStyle
|
||||||
|
}
|
||||||
|
q["Style"] = style
|
||||||
|
q["IsDefault"] = true
|
||||||
|
} else {
|
||||||
|
q["_id"] = bson.ObjectIdHex(themeId)
|
||||||
|
}
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQ(db.Themes, q, &theme)
|
||||||
|
return theme.Info
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到用户的主题
|
||||||
|
// 若用户没有主题, 则至少有一个默认主题
|
||||||
|
// 第一个返回值是当前active
|
||||||
|
func (this *ThemeService) GetUserThemes(userId string) (theme info.Theme, themes []info.Theme) {
|
||||||
|
theme = info.Theme{}
|
||||||
|
themes = []info.Theme{}
|
||||||
|
|
||||||
|
// db.ListByQ(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId)}, &themes)
|
||||||
|
|
||||||
|
// 创建时间逆序
|
||||||
|
query := bson.M{"UserId": bson.ObjectIdHex(userId)}
|
||||||
|
q := db.Themes.Find(query);
|
||||||
|
q.Sort("-CreatedTime").All(&themes)
|
||||||
|
if len(themes) == 0 {
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
theme = this.getDefaultTheme(userBlog.Style)
|
||||||
|
} else {
|
||||||
|
var has = false
|
||||||
|
// 第一个是active的主题
|
||||||
|
themes2 := make([]info.Theme, len(themes))
|
||||||
|
i := 0
|
||||||
|
for _, t := range themes {
|
||||||
|
if t.IsActive {
|
||||||
|
theme = t
|
||||||
|
} else {
|
||||||
|
has = true
|
||||||
|
themes2[i] = t
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if has {
|
||||||
|
themes = themes2
|
||||||
|
} else {
|
||||||
|
themes = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到默认主题供选择
|
||||||
|
func (this *ThemeService) GetDefaultThemes() (themes []info.Theme) {
|
||||||
|
themes = []info.Theme{}
|
||||||
|
db.ListByQ(db.Themes, bson.M{"IsDefault": true}, &themes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到模板内容
|
||||||
|
func (this *ThemeService) GetTplContent(userId, themeId, filename string) string {
|
||||||
|
path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename
|
||||||
|
return GetFileStrContent(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到主题的绝对路径
|
||||||
|
func (this *ThemeService) GetThemeAbsolutePath(userId, themeId string) string {
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQWithFields(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, []string{"Path"}, &theme)
|
||||||
|
if theme.Path != "" {
|
||||||
|
return revel.BasePath + "/" + theme.Path
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
func (this *ThemeService) GetThemePath(userId, themeId string) string {
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQWithFields(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, []string{"Path"}, &theme)
|
||||||
|
if theme.Path != "" {
|
||||||
|
return theme.Path
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// 更新模板内容
|
||||||
|
func (this *ThemeService) UpdateTplContent(userId, themeId, filename, content string) (ok bool, msg string) {
|
||||||
|
path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename
|
||||||
|
if strings.Contains(filename, ".html") {
|
||||||
|
// 模板
|
||||||
|
if ok, msg = this.mustTpl(filename, content); ok {
|
||||||
|
ok = PutFileStrContent(path, content)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if filename == "theme.json" {
|
||||||
|
// 主题配置, 判断是否是正确的json
|
||||||
|
theme, err := this.parseConfig(content)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Sprintf("%v", err)
|
||||||
|
}
|
||||||
|
// 正确, 更新theme信息
|
||||||
|
ok = db.UpdateByQMap(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)},
|
||||||
|
bson.M{
|
||||||
|
"Name": theme.Name,
|
||||||
|
"Version": theme.Version,
|
||||||
|
"Author": theme.Author,
|
||||||
|
"AuthorUrl": theme.AuthorUrl,
|
||||||
|
"Info": theme.Info,
|
||||||
|
})
|
||||||
|
if ok {
|
||||||
|
ok = PutFileStrContent(path, content)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = PutFileStrContent(path, content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ThemeService) DeleteTpl(userId, themeId, filename string) (ok bool) {
|
||||||
|
path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename
|
||||||
|
ok = DeleteFile(path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否有语法错误
|
||||||
|
func (this *ThemeService) mustTpl(filename, content string) (ok bool, msg string) {
|
||||||
|
ok = true
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
Log(err)
|
||||||
|
msg = fmt.Sprintf("%v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
template.Must(template.New(filename).Funcs(revel.TemplateFuncs).Parse(content))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////
|
||||||
|
|
||||||
|
// 使用主题
|
||||||
|
func (this *ThemeService) ActiveTheme(userId, themeId string) (ok bool) {
|
||||||
|
if db.Has(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}) {
|
||||||
|
// 之前的设为false
|
||||||
|
db.UpdateByQField(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId), "IsActive": true}, "IsActive", false)
|
||||||
|
// 现在的设为true
|
||||||
|
db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true)
|
||||||
|
|
||||||
|
// UserBlog ThemeId
|
||||||
|
db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "ThemeId", bson.ObjectIdHex(themeId))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除主题
|
||||||
|
func (this *ThemeService) DeleteTheme(userId, themeId string) (ok bool) {
|
||||||
|
return db.Delete(db.Themes,bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId), "IsActive": false})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公开主题, 只有管理员才有权限, 之前没公开的变成公开
|
||||||
|
func (this *ThemeService) PublicTheme(userId, themeId string) (ok bool) {
|
||||||
|
// 是否是管理员?
|
||||||
|
userInfo := userService.GetUserInfo(userId)
|
||||||
|
if userInfo.Username == adminUsername {
|
||||||
|
theme := this.GetThemeById(themeId)
|
||||||
|
return db.UpdateByQField(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(themeId)}, "IsDefault", !theme.IsDefault)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 导出主题
|
||||||
|
func (this *ThemeService) ExportTheme(userId, themeId string) (ok bool, path string) {
|
||||||
|
theme := this.GetThemeById(themeId)
|
||||||
|
// 打包
|
||||||
|
// 验证路径, 别把整个项目打包了
|
||||||
|
Log(theme.Path)
|
||||||
|
if theme.Path == "" ||
|
||||||
|
(!strings.HasPrefix(theme.Path, "public/upload") &&
|
||||||
|
!strings.HasPrefix(theme.Path, "public/blog/themes")) ||
|
||||||
|
strings.Contains(theme.Path, "..") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcePath := revel.BasePath + "/" + theme.Path
|
||||||
|
targetPath := revel.BasePath + "/public/upload/" + userId + "/tmp"
|
||||||
|
err := os.MkdirAll(targetPath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
Log(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
targetName := targetPath + "/" + theme.Name + ".zip"
|
||||||
|
Log(sourcePath)
|
||||||
|
Log(targetName)
|
||||||
|
ok = archive.Zip(sourcePath, targetName)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, targetName
|
||||||
|
}
|
||||||
|
// 导入主题
|
||||||
|
// path == /llllllll/..../public/upload/.../aa.zip, 绝对路径
|
||||||
|
func (this *ThemeService) ImportTheme(userId, path string) (ok bool, msg string) {
|
||||||
|
themeIdO := bson.NewObjectId()
|
||||||
|
themeId := themeIdO.Hex()
|
||||||
|
targetPath := this.getUserThemePath(userId, themeId) // revel.BasePath + "/public/upload/" + userId + "/themes/" + themeId
|
||||||
|
if ok, msg = archive.Unzip(path, targetPath); !ok {
|
||||||
|
DeleteFile(targetPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 解压成功, 那么新建之
|
||||||
|
// 保存到数据库中
|
||||||
|
theme, _ := this.getThemeConfig(targetPath)
|
||||||
|
if theme.Name == "" {
|
||||||
|
ok = false
|
||||||
|
DeleteFile(targetPath)
|
||||||
|
msg = "解析错误"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
theme.ThemeId = themeIdO
|
||||||
|
theme.Path = this.getUserThemePath2(userId, themeId)
|
||||||
|
theme.CreatedTime = time.Now()
|
||||||
|
theme.UpdatedTime = theme.CreatedTime
|
||||||
|
theme.UserId = bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
ok = db.Insert(db.Themes, theme)
|
||||||
|
if !ok {
|
||||||
|
DeleteFile(targetPath)
|
||||||
|
}
|
||||||
|
DeleteFile(path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安装主题
|
||||||
|
// 得到该主题路径
|
||||||
|
func (this *ThemeService) InstallTheme(userId, themeId string) (ok bool) {
|
||||||
|
theme := this.GetThemeById(themeId)
|
||||||
|
// 不是默认主题, 即不是admin用户的主题, 不能乱安装
|
||||||
|
if !theme.IsDefault {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户之前是否有主题?
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
if userBlog.ThemeId == "" {
|
||||||
|
this.NewThemeForFirst(userBlog)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成新主题
|
||||||
|
newThemeId := bson.NewObjectId()
|
||||||
|
themeId = newThemeId.Hex()
|
||||||
|
themePath := this.getUserThemePath(userId, themeId)
|
||||||
|
err := os.MkdirAll(themePath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 复制默认主题
|
||||||
|
sourceThemePath := revel.BasePath + "/" + theme.Path
|
||||||
|
err = CopyDir(sourceThemePath, themePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到数据库中
|
||||||
|
theme, _ = this.getThemeConfig(themePath)
|
||||||
|
theme.ThemeId = newThemeId
|
||||||
|
theme.Path = this.getUserThemePath2(userId, themeId)
|
||||||
|
theme.CreatedTime = time.Now()
|
||||||
|
theme.UpdatedTime = theme.CreatedTime
|
||||||
|
theme.UserId = bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
ok = db.Insert(db.Themes, theme)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
@@ -19,9 +19,34 @@ func (this *UpgradeService) UpgradeBlog() bool {
|
|||||||
|
|
||||||
// PublicTime, RecommendTime = UpdatedTime
|
// PublicTime, RecommendTime = UpdatedTime
|
||||||
for _, note := range notes {
|
for _, note := range notes {
|
||||||
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime})
|
if note.IsBlog && note.PublicTime.Year() < 100 {
|
||||||
Log(note.NoteId.Hex())
|
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime})
|
||||||
|
Log(note.NoteId.Hex())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 11-5自定义博客升级, 将aboutMe移至pages
|
||||||
|
func (this *UpgradeService) UpgradeBetaToSelfBlog(userId string) (ok bool, msg string) {
|
||||||
|
if configService.GetGlobalStringConfig("UpgradeBetaToSelfBlog") != "" {
|
||||||
|
return false, "已升级"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. aboutMe -> page
|
||||||
|
userBlogs := []info.UserBlog{}
|
||||||
|
db.ListByQ(db.UserBlogs, bson.M{}, &userBlogs)
|
||||||
|
|
||||||
|
for _, userBlog := range userBlogs {
|
||||||
|
blogService.AddOrUpdateSingle(userBlog.UserId.Hex(), "", "About Me", userBlog.AboutMe)
|
||||||
|
}
|
||||||
|
|
||||||
|
configService.UpdateGlobalStringConfig(userId, "UpgradeBetaToSelfBlog", "ok")
|
||||||
|
|
||||||
|
ok = true
|
||||||
|
msg = "success"
|
||||||
|
|
||||||
|
// 2. 默认主题, 给admin用户
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ func (this *UserService) AddUser(user info.User) bool {
|
|||||||
go func() {
|
go func() {
|
||||||
emailService.RegisterSendActiveEmail(user, user.Email)
|
emailService.RegisterSendActiveEmail(user, user.Email)
|
||||||
// 发送给我 life@leanote.com
|
// 发送给我 life@leanote.com
|
||||||
// emailService.SendEmail("life@leanote.com", "新增用户", "{header}用户名" + user.Email + "{footer}");
|
emailService.SendEmail("life@leanote.com", "新增用户", "{header}用户名" + user.Email + "{footer}");
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +133,57 @@ func (this *UserService) MapUserInfoAndBlogInfosByUserIds(userIds []bson.ObjectI
|
|||||||
return this.MapUserInfoByUserIds(userIds)
|
return this.MapUserInfoByUserIds(userIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 返回info.UserAndBlog
|
||||||
|
func (this *UserService) MapUserAndBlogByUserIds(userIds []bson.ObjectId) map[string]info.UserAndBlog {
|
||||||
|
users := []info.User{}
|
||||||
|
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users)
|
||||||
|
|
||||||
|
userBlogs := []info.UserBlog{}
|
||||||
|
db.ListByQ(db.UserBlogs, bson.M{"_id": bson.M{"$in": userIds}}, &userBlogs)
|
||||||
|
|
||||||
|
userBlogMap := make(map[bson.ObjectId]info.UserBlog, len(userBlogs))
|
||||||
|
for _, user := range userBlogs {
|
||||||
|
userBlogMap[user.UserId] = user
|
||||||
|
}
|
||||||
|
|
||||||
|
userAndBlogMap := make(map[string]info.UserAndBlog, len(users))
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
this.setUserLogo(&user)
|
||||||
|
|
||||||
|
userBlog, ok := userBlogMap[user.UserId]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
userAndBlogMap[user.UserId.Hex()] = info.UserAndBlog{
|
||||||
|
UserId: user.UserId,
|
||||||
|
Username: user.Username,
|
||||||
|
Email: user.Email,
|
||||||
|
Logo: user.Logo,
|
||||||
|
BlogTitle: userBlog.Title,
|
||||||
|
BlogLogo: userBlog.Logo,
|
||||||
|
BlogUrl: blogService.GetUserBlogUrl(&userBlog),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userAndBlogMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到userAndBlog公开信息
|
||||||
|
func (this *UserService) GetUserAndBlog(userId string) info.UserAndBlog {
|
||||||
|
user := this.GetUserInfo(userId)
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
return info.UserAndBlog{
|
||||||
|
UserId: user.UserId,
|
||||||
|
Username: user.Username,
|
||||||
|
Email: user.Email,
|
||||||
|
Logo: user.Logo,
|
||||||
|
BlogTitle: userBlog.Title,
|
||||||
|
BlogLogo: userBlog.Logo,
|
||||||
|
BlogUrl: blogService.GetUserBlogUrl(&userBlog),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 通过ids得到users, 按id的顺序组织users
|
// 通过ids得到users, 按id的顺序组织users
|
||||||
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
||||||
users := []info.User{}
|
users := []info.User{}
|
||||||
@@ -143,9 +194,11 @@ func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.
|
|||||||
usersMap[user.UserId] = user
|
usersMap[user.UserId] = user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasAppend := map[bson.ObjectId]bool{} // 为了防止userIds有重复的
|
||||||
users2 := []info.User{};
|
users2 := []info.User{};
|
||||||
for _, userId := range userIds {
|
for _, userId := range userIds {
|
||||||
if user, ok := usersMap[userId]; ok {
|
if user, ok := usersMap[userId]; ok && !hasAppend[userId] {
|
||||||
|
hasAppend[userId] = true
|
||||||
users2 = append(users2, user)
|
users2 = append(users2, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,7 +222,7 @@ func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.U
|
|||||||
// 更新username
|
// 更新username
|
||||||
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
||||||
if userId == "" || username == "" || username == "admin" { // admin用户是内置的, 不能设置
|
if userId == "" || username == "" || username == "admin" { // admin用户是内置的, 不能设置
|
||||||
return false, "用户已存在"
|
return false, "usernameIsExisted"
|
||||||
}
|
}
|
||||||
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
||||||
username = strings.ToLower(username)
|
username = strings.ToLower(username)
|
||||||
@@ -177,7 +230,7 @@ func (this *UserService) UpdateUsername(userId, username string) (bool, string)
|
|||||||
// 先判断是否存在
|
// 先判断是否存在
|
||||||
userIdO := bson.ObjectIdHex(userId)
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
if db.Has(db.Users, bson.M{"Username": username, "_id": bson.M{"$ne": userIdO}}) {
|
if db.Has(db.Users, bson.M{"Username": username, "_id": bson.M{"$ne": userIdO}}) {
|
||||||
return false, "用户已存在"
|
return false, "usernameIsExisted"
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := db.UpdateByQMap(db.Users, bson.M{"_id": userIdO}, bson.M{"Username": username, "UsernameRaw": usernameRaw})
|
ok := db.UpdateByQMap(db.Users, bson.M{"_id": userIdO}, bson.M{"Username": username, "UsernameRaw": usernameRaw})
|
||||||
@@ -195,7 +248,7 @@ func (this *UserService) UpdateAvatar(userId, avatarPath string) (bool) {
|
|||||||
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
||||||
userInfo := this.GetUserInfo(userId)
|
userInfo := this.GetUserInfo(userId)
|
||||||
if userInfo.Pwd != Md5(oldPwd) {
|
if userInfo.Pwd != Md5(oldPwd) {
|
||||||
return false, "旧密码错误"
|
return false, "oldPasswordError"
|
||||||
}
|
}
|
||||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||||
return ok, ""
|
return ok, ""
|
||||||
@@ -207,6 +260,21 @@ func (this *UserService) UpdateTheme(userId, theme string) (bool) {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 帐户类型设置
|
||||||
|
func (this *UserService) UpdateAccount(userId, accountType string, accountStartTime, accountEndTime time.Time,
|
||||||
|
maxImageNum, maxImageSize, maxAttachNum, maxAttachSize, maxPerAttachSize int) bool {
|
||||||
|
return db.UpdateByQI(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, info.UserAccount{
|
||||||
|
AccountType: accountType,
|
||||||
|
AccountStartTime: accountStartTime,
|
||||||
|
AccountEndTime: accountEndTime,
|
||||||
|
MaxImageNum: maxImageNum,
|
||||||
|
MaxImageSize: maxImageSize,
|
||||||
|
MaxAttachNum: maxAttachNum,
|
||||||
|
MaxAttachSize: maxAttachSize,
|
||||||
|
MaxPerAttachSize: maxPerAttachSize,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//---------------
|
//---------------
|
||||||
// 修改email
|
// 修改email
|
||||||
|
|
||||||
@@ -261,6 +329,13 @@ func (this *UserService) UpdateEmail(token string) (ok bool, msg, email string)
|
|||||||
//---------
|
//---------
|
||||||
// 第三方添加账号
|
// 第三方添加账号
|
||||||
func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg string) {
|
func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg string) {
|
||||||
|
// 判断该用户是否已有了帐户
|
||||||
|
userInfo := this.GetUserInfo(userId)
|
||||||
|
if userInfo.Email != "" {
|
||||||
|
msg = "你已有帐户"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 判断email是否存在
|
// 判断email是否存在
|
||||||
if this.IsExistsUser(email) {
|
if this.IsExistsUser(email) {
|
||||||
msg = "该用户已存在"
|
msg = "该用户已存在"
|
||||||
|
|||||||
@@ -28,8 +28,10 @@ var emailService, EmailS *EmailService
|
|||||||
var AuthS *AuthService
|
var AuthS *AuthService
|
||||||
var UpgradeS *UpgradeService
|
var UpgradeS *UpgradeService
|
||||||
var SessionS, sessionService *SessionService
|
var SessionS, sessionService *SessionService
|
||||||
|
var ThemeS, themeService *ThemeService
|
||||||
|
|
||||||
var siteUrl string
|
var siteUrl string
|
||||||
|
var adminUsername = "admin"
|
||||||
|
|
||||||
// onAppStart调用
|
// onAppStart调用
|
||||||
func InitService() {
|
func InitService() {
|
||||||
@@ -53,6 +55,7 @@ func InitService() {
|
|||||||
EmailS = NewEmailService()
|
EmailS = NewEmailService()
|
||||||
UpgradeS = &UpgradeService{}
|
UpgradeS = &UpgradeService{}
|
||||||
SessionS = &SessionService{}
|
SessionS = &SessionService{}
|
||||||
|
ThemeS = &ThemeService{}
|
||||||
|
|
||||||
notebookService = NotebookS
|
notebookService = NotebookS
|
||||||
noteService = NoteS
|
noteService = NoteS
|
||||||
@@ -70,7 +73,7 @@ func InitService() {
|
|||||||
configService = ConfigS
|
configService = ConfigS
|
||||||
emailService = EmailS
|
emailService = EmailS
|
||||||
sessionService = SessionS
|
sessionService = SessionS
|
||||||
|
themeService = ThemeS
|
||||||
|
|
||||||
//
|
|
||||||
siteUrl, _ = revel.Config.String("site.url")
|
siteUrl, _ = revel.Config.String("site.url")
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">
|
||||||
|
{{if .page}}
|
||||||
|
修改页面
|
||||||
|
{{else}}
|
||||||
|
添加页面
|
||||||
|
{{end}}
|
||||||
|
</h3></div>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" type="text/css">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="baseMsg" style="display: none"></div>
|
||||||
|
<input type="hidden" id="singleId" value="{{.single.SingleId.Hex}}" />
|
||||||
|
<div class="form-group">
|
||||||
|
<label>标题</label>
|
||||||
|
<input type="text" class="form-control" id="title" name="title"
|
||||||
|
value="{{.single.Title}}"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "请输入页面标题"},
|
||||||
|
]'
|
||||||
|
data-msg_target="#baseMsg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="content1">内容</label>
|
||||||
|
<div id="popularToolbar"></div>
|
||||||
|
<textarea id="content1" name="content">{{.single.Content}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script type="text/javascript" src="/tinymce/tinymce.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
tinymce.init({
|
||||||
|
selector : "#content1",
|
||||||
|
content_css : [ "/css/bootstrap.css", "/css/editor/editor.css" ],
|
||||||
|
skin : "custom",
|
||||||
|
language : "{{.locale}}",
|
||||||
|
height : 300,
|
||||||
|
width : "100%",
|
||||||
|
skin : "custom",
|
||||||
|
plugins : [
|
||||||
|
"advlist autolink link leanote_image lists charmap hr ",
|
||||||
|
"searchreplace visualblocks visualchars leanote_code tabfocus",
|
||||||
|
"table contextmenu directionality textcolor paste fullpage textcolor"],
|
||||||
|
toolbar1 : "formatselect |fontselect fontsizeselect| forecolor backcolor | bold italic underline strikethrough | bullist numlist |",
|
||||||
|
menubar : false,
|
||||||
|
statusbar : false,
|
||||||
|
font_formats : "Arial=arial,helvetica,sans-serif;"
|
||||||
|
+ "Arial Black=arial black,avant garde;"
|
||||||
|
+ "Times New Roman=times new roman,times;"
|
||||||
|
+ "Courier New=courier new,courier;"
|
||||||
|
+ "Tahoma=tahoma,arial,helvetica,sans-serif;"
|
||||||
|
+ "Verdana=verdana,geneva;" + "宋体=SimSun;"
|
||||||
|
+ "新宋体=NSimSun;" + "黑体=SimHei;"
|
||||||
|
+ "微软雅黑=Microsoft YaHei",
|
||||||
|
block_formats : "Header 1=h1;Header 2=h2;Header 3=h3; Header 4=h4;Pre=pre;Paragraph=p"
|
||||||
|
});
|
||||||
|
|
||||||
|
// 基本设置
|
||||||
|
var vdPage = new vd.init("#formData");
|
||||||
|
$("#baseBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!vdPage.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
singleId: $("#singleId").val(),
|
||||||
|
title : $("#title").val(),
|
||||||
|
content : getEditorContent()
|
||||||
|
}
|
||||||
|
ajaxPost("/member/blog/doAddOrUpdateSingle/", data, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
// 添加成功后, 跳转之
|
||||||
|
art.tips("Success")
|
||||||
|
if(!data.pageId) {
|
||||||
|
location.href = "/member/blog/single";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "baseInfoSet"}}</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="baseMsg" style="display: none"></div>
|
||||||
|
<div class="form-horizontal" role="form" id="userBlogForm">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="title" class="col-sm-2 control-label">{{msg . "blogName"}}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" id="Title" name="Title"
|
||||||
|
placeholder="eg: leanote's blog"
|
||||||
|
value="{{if .userBlog.Title}}{{.userBlog.Title}}{{else}}{{.userInfo.Email}} 's blog{{end}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="logo" class="col-sm-2 control-label">{{msg . "blogLogo"}}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="hidden" name="Logo" id="Logo"
|
||||||
|
value="{{.userBlog.Logo}}" />
|
||||||
|
<form id="formLogo" action="{{$.siteUrl}}/file/uploadBlogLogo" method="post"
|
||||||
|
enctype="multipart/form-data" target="logoTarget">
|
||||||
|
<input type="file" class="form-control" id="logo2" name="file"
|
||||||
|
onChange='$("#formLogo").submit();' />
|
||||||
|
<div id="logoImg"
|
||||||
|
{{if .userBlog.Logo }}
|
||||||
|
{{else}}
|
||||||
|
style="display: none"{{end}}
|
||||||
|
>
|
||||||
|
<img src="{{.userBlog.Logo}}" style="height: 40px" /> <a
|
||||||
|
href="#" id="deleteLogo">{{msg . "delete"}}</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<iframe id="logoTarget" name="logoTarget" src="#" style="display: none"></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="subTitle" class="col-sm-2 control-label">{{msg . "blogDesc"}}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" id="SubTitle"
|
||||||
|
name="SubTitle" value="{{.userBlog.SubTitle}}"
|
||||||
|
placeholder="eg: leanote, Not Just A Notebook">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="aboutMe" class="col-sm-2 control-label"></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div id="popularToolbar"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="aboutMe" class="col-sm-2 control-label">{{msg . "aboutMe"}}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea id="AboutMe" name="AboutMe">{{.userBlog.AboutMe}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script type="text/javascript" src="/tinymce/tinymce.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
$("#deleteLogo").click(function() {
|
||||||
|
$("#Logo").val("");
|
||||||
|
$("#logoImg").hide();
|
||||||
|
});
|
||||||
|
// 基本设置
|
||||||
|
$("#baseBtn").click(function() {
|
||||||
|
var data = {
|
||||||
|
Title : $("#Title").val(),
|
||||||
|
SubTitle : $("#SubTitle").val(),
|
||||||
|
Logo : $("#Logo").val()
|
||||||
|
}
|
||||||
|
post("/member/blog/setUserBlogBase", data, function(ret) {
|
||||||
|
showAlert("#baseMsg", "{{msg . "saveSuccess"}}", "success");
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// filename, result, resultCode
|
||||||
|
function uploadFinish(ret) {
|
||||||
|
if (ret) {
|
||||||
|
if (ret.resultCode == '1') {
|
||||||
|
$("#logoImg img").attr("src", urlPrefix + "/" + ret.filename).parent().show();
|
||||||
|
$("#Logo").val(ret.filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
alert(ret.result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 上传出错
|
||||||
|
alert("error");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">(笔记本)分类</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
分类是公开为博客的笔记本
|
||||||
|
<br />
|
||||||
|
拖动可排序
|
||||||
|
<ul class="list-group gutter list-group-lg list-group-sp sortable">
|
||||||
|
{{range .notebooks}}
|
||||||
|
<li class="list-group-item" draggable="true" data-id="{{.NotebookId.Hex}}">
|
||||||
|
<span class="pull-left media-xs"><i class="fa fa-sort text-muted fa m-r-sm"></i></span>
|
||||||
|
{{.Title}}
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script type="text/javascript" src="/public/member/js/jquery.sortable.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$("#baseBtn").click(function(){
|
||||||
|
var ids = [];
|
||||||
|
$(".list-group-item").each(function() {
|
||||||
|
ids.push($(this).data("id"));
|
||||||
|
});
|
||||||
|
ajaxPost("/member/blog/upateCateIds", {cateIds: ids}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "commentSet"}}</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="baseMsg" style="display: none"></div>
|
||||||
|
<form class="form-horizontal" role="form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="subTitle" class="col-sm-3 control-label">{{msg . "chooseComment"}}</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="CanComment" name="CanComment"
|
||||||
|
{{if .userBlog.CanComment}}checked="checked"{{end}} > {{msg . "openComment"}}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div id="commentSet" {{if not .userBlog.CanComment}}style="display: none"{{end}}>
|
||||||
|
<label>
|
||||||
|
<input type="radio"
|
||||||
|
name="commentType"
|
||||||
|
value="default"
|
||||||
|
{{if or (not .userBlog.CommentType) (eq .userBlog.CommentType "default")}}checked="checked"{{end}} > Default
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="commentType" id="disqus"
|
||||||
|
value="disqus"
|
||||||
|
{{if eq .userBlog.CommentType "disqus"}}checked="checked"{{end}} > Disqus
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div id="disqusSet" {{if not (eq .userBlog.CommentType "disqus")}}style="display: none"{{end}}>
|
||||||
|
<label for="DisqusId">Disqus Id</label> <input type="text"
|
||||||
|
class="form-control" style="display: inline; width: 50%"
|
||||||
|
id="DisqusId" name="DisqusId"
|
||||||
|
value="{{if .userBlog.DisqusId}}{{.userBlog.DisqusId}}{{else}}leanote{{end}}">
|
||||||
|
<br />
|
||||||
|
{{msg . "disqusHelp"}}
|
||||||
|
<a target="_blank" href="http://leanote.com/blog/view/52db8463e01c530ef8000001">{{msg . "needHelp"}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
// 评论
|
||||||
|
$("#baseBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var data = {
|
||||||
|
CanComment : $("#CanComment").is(":checked"),
|
||||||
|
CommentType: $("input[name='commentType']:checked").val(),
|
||||||
|
DisqusId : $("#DisqusId").val(),
|
||||||
|
}
|
||||||
|
post("/member/blog/setUserBlogComment", data, function(ret) {
|
||||||
|
showAlert("#baseMsg", "{{msg . "saveSuccess"}}", "success");
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
$("#CanComment").click(function() {
|
||||||
|
if ($(this).is(":checked")) {
|
||||||
|
$("#commentSet").show();
|
||||||
|
} else {
|
||||||
|
$("#commentSet").hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("input[name='commentType']").click(function() {
|
||||||
|
if ($("input[name='commentType']:checked").val() == "disqus") {
|
||||||
|
$("#disqusSet").show();
|
||||||
|
} else {
|
||||||
|
$("#disqusSet").hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">分页与排序设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="domainMsg" style="display: none"></div>
|
||||||
|
|
||||||
|
<form class="form-horizontal" role="form" id="dataFrom">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="perPageSize" class="col-sm-2 control-label">每页记录数</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
placeholder="10"
|
||||||
|
id="perPageSize"
|
||||||
|
name="perPageSize"
|
||||||
|
value="{{.userBlog.PerPageSize}}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="perPageSize" class="col-sm-2 control-label">排序字段</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-control"
|
||||||
|
id="sortField"
|
||||||
|
name="sortField"
|
||||||
|
value="">
|
||||||
|
<option value="PublicTime" {{if eq $.userBlog.SortField "PublicTime"}}selected{{end}}>公开为博客时间</option>
|
||||||
|
<option value="CreatedTime" {{if eq $.userBlog.SortField "CreatedTimeTime"}}selected{{end}}>创建时间</option>
|
||||||
|
<option value="UpdatedTime" {{if eq $.userBlog.SortField "UpdatedTime"}}selected{{end}}>更新时间</option>
|
||||||
|
<option value="Title" {{if eq $.userBlog.SortField "Title"}}selected{{end}}>标题</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">排序类型</label>
|
||||||
|
<div class="col-sm-10" style="margin-top: 5px;">
|
||||||
|
<label><input type="radio" name="isAsc" value="0" {{if not .userBlog.IsAsc}}checked{{end}}> 降序</label>
|
||||||
|
<label><input type="radio" name="isAsc" value="1" {{if .userBlog.IsAsc}}checked{{end}}> 升序</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
// domain
|
||||||
|
$("#baseBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var data = $("#dataFrom").serialize();
|
||||||
|
post("/member/blog/setUserBlogPaging", data, function(re) {
|
||||||
|
if(re.Ok) {
|
||||||
|
showAlert("#domainMsg", "{{msg . "saveSuccess"}}", "success");
|
||||||
|
} else {
|
||||||
|
showAlert("#domainMsg", re.Msg, "danger");
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">页面</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>
|
||||||
|
您可以添加多个单页面
|
||||||
|
<a href="/member/blog/addOrUpdateSingle" id="addBtn" class="btn btn-success">添加页面</a>
|
||||||
|
</p>
|
||||||
|
<ul class="list-group gutter list-group-lg list-group-sp sortable">
|
||||||
|
{{range .singles}}
|
||||||
|
<li class="list-group-item" draggable="true" data-id="{{.SingleId}}">
|
||||||
|
<span class="pull-right">
|
||||||
|
<a href="/member/blog/addOrUpdateSingle?singleId={{.SingleId}}"><i class="fa fa-pencil icon-muted fa-fw m-r-xs page-edit" data-id="{{.SingleId}}"></i></a>
|
||||||
|
<a href="#"><i class="fa fa-times icon-muted fa-fw page-delete" data-id="{{.SingleId}}"></i></a>
|
||||||
|
</span>
|
||||||
|
<span class="pull-left media-xs"><i class="fa fa-sort text-muted fa m-r-sm"></i></span>
|
||||||
|
<div class="clear">
|
||||||
|
{{.Title}}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{if .singles}}
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">保存排序</button>
|
||||||
|
</footer>
|
||||||
|
{{end}}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script type="text/javascript" src="{{.siteUrl}}/public/member/js/jquery.sortable.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$("#baseBtn").click(function(){
|
||||||
|
var ids = [];
|
||||||
|
$(".list-group-item").each(function() {
|
||||||
|
ids.push($(this).data("id"));
|
||||||
|
});
|
||||||
|
ajaxPost("/member/blog/sortSingles", {singleIds: ids}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".page-delete").click(function() {
|
||||||
|
var singleId = $(this).data('id');
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
ajaxPost("/member/blog/deleteSingle", {singleId: singleId}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md clearfix">
|
||||||
|
<h3 class="m-b-none">
|
||||||
|
{{msg . "themeSet"}}
|
||||||
|
<small>(<a href="http://blog.leanote.com/post/545f1a5c380782565e000000" target="_blank">{{msg . "needHelp"}}</a>)</small>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 theme-container">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div>
|
||||||
|
<form id="uploadAvatar" method="post" action="/member/blog/importTheme" enctype="multipart/form-data">
|
||||||
|
<div id="dropAvatar" class="dropzone">
|
||||||
|
<a class="btn btn-default btn-new" href="/member/blog/newTheme"><span class="fa fa-plus"></span> 新建主题</a>
|
||||||
|
<a class="btn btn-success btn-choose-file">
|
||||||
|
<span class="fa fa-upload"></span> 导入主题(.zip)
|
||||||
|
</a>
|
||||||
|
<input type="file" name="file" multiple/>
|
||||||
|
<div id="avatarUploadMsg"></div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
当前主题:
|
||||||
|
</p>
|
||||||
|
<ul class="themes">
|
||||||
|
<li class="theme">
|
||||||
|
<a class="choose-theme" data-method="put" href="#" rel="nofollow">
|
||||||
|
<div class="theme-thumb thumb active-theme">
|
||||||
|
<img src="/{{.activeTheme.Path}}/images/screenshot.png" alt="preview">
|
||||||
|
</div>
|
||||||
|
<span class="theme-title">{{.activeTheme.Name}}</span>
|
||||||
|
</a>
|
||||||
|
<span class="theme-author">
|
||||||
|
By: <a href="{{.activeTheme.AuthorUrl}}" target="_blank">{{.activeTheme.Author}}</a>
|
||||||
|
</span>
|
||||||
|
<div class="theme-btns">
|
||||||
|
<div class="btn-group" data-id="{{.activeTheme.ThemeId.Hex}}">
|
||||||
|
<a class="btn btn-default btn-sm btn-export"><span class="fa fa-download"></span> 导出</a>
|
||||||
|
<a class="btn btn-default btn-sm" href="{{$.siteUrl}}/preview?themeId={{.activeTheme.ThemeId.Hex}}" target="_blank"><span class="fa fa-eye"></span> 预览</a>
|
||||||
|
<a class="btn btn-primary btn-sm" target="_blank" href="/member/blog/updateTheme?themeId={{if .activeTheme.ThemeId}}{{.activeTheme.ThemeId.Hex}}{{end}}"><span class="fa fa-pencil"></span> 编辑</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<p>
|
||||||
|
我的其它主题:
|
||||||
|
</p>
|
||||||
|
<ul class="themes">
|
||||||
|
{{range $.otherThemes}}
|
||||||
|
{{if .ThemeId}}
|
||||||
|
<li class="theme">
|
||||||
|
<a class="choose-theme" data-method="put" href="#" rel="nofollow">
|
||||||
|
<div class="theme-thumb thumb">
|
||||||
|
<img src="/{{.Path}}/images/screenshot.png" alt="preview">
|
||||||
|
</div>
|
||||||
|
<span class="theme-title">{{.Name}}</span>
|
||||||
|
</a>
|
||||||
|
<span class="theme-author">
|
||||||
|
By: <a href="{{.AuthorUrl}}" target="_blank">{{.Author}}</a>
|
||||||
|
</span>
|
||||||
|
<div class="theme-btns">
|
||||||
|
<div class="btn-group" data-id="{{.ThemeId.Hex}}">
|
||||||
|
<a class="btn btn-default btn-sm btn-delete" data-loading-text="..."><span class="fa fa-remove"></span> 删除</a>
|
||||||
|
<a class="btn btn-default btn-sm btn-export"><span class="fa fa-download"></span> 导出</a>
|
||||||
|
<a class="btn btn-default btn-sm" href="{{$.siteUrl}}/preview?themeId={{.ThemeId.Hex}}" target="_blank"><span class="fa fa-eye"></span> 预览</a>
|
||||||
|
<a class="btn btn-default btn-sm" target="_blank" href="/member/blog/updateTheme?themeId={{.ThemeId.Hex}}"><span class="fa fa-pencil"></span> 编辑</a>
|
||||||
|
<a class="btn btn-primary btn-sm btn-active" data-loading-text="..."><span class="fa fa-check"></span> 使用</a>
|
||||||
|
{{if $.isAdmin}}
|
||||||
|
<a class="btn btn-default btn-sm btn-public" data-loading-text="...">
|
||||||
|
{{if .IsDefault}}
|
||||||
|
公开
|
||||||
|
{{else}}
|
||||||
|
私有
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
无
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<p>
|
||||||
|
leanote主题市场:
|
||||||
|
</p>
|
||||||
|
<ul class="themes">
|
||||||
|
{{range $.optionThemes}}
|
||||||
|
<li class="theme">
|
||||||
|
<a class="choose-theme" data-method="put" href="#" rel="nofollow">
|
||||||
|
<div class="theme-thumb thumb">
|
||||||
|
<img src="/{{.Path}}/images/screenshot.png" alt="preview">
|
||||||
|
</div>
|
||||||
|
<span class="theme-title">{{.Name}}</span>
|
||||||
|
</a>
|
||||||
|
<span class="theme-author">
|
||||||
|
By: <a href="{{.AuthorUrl}}" target="_blank">{{.Author}}</a>
|
||||||
|
</span>
|
||||||
|
<p class="theme-btns" data-id="{{.ThemeId.Hex}}">
|
||||||
|
<a class="btn btn-primary btn-sm btn-install"><span class="fa fa-gear"></span> 安装</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script src="/js/require.js"></script>
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
// 使用主题
|
||||||
|
$(".btn-active").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
t.button("loading");
|
||||||
|
ajaxPost("/member/blog/activeTheme", {themeId: id}, function(re) {
|
||||||
|
t.button("reset");
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert("Error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 导出主题
|
||||||
|
$(".btn-export").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
window.open("/member/blog/exportTheme?themeId=" + id);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 删除主题
|
||||||
|
$(".btn-delete").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
t.button("loading");
|
||||||
|
ajaxPost("/member/blog/deleteTheme", {themeId: id}, function(re) {
|
||||||
|
t.button("reset");
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert("Error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 安装主题
|
||||||
|
$(".btn-install").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
t.button("loading");
|
||||||
|
ajaxPost("/member/blog/installTheme", {themeId: id}, function(re) {
|
||||||
|
t.button("reset");
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert("Error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
{{if .isAdmin}}
|
||||||
|
// 只有管理员才有公开主题
|
||||||
|
$(".btn-public").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
t.button("loading");
|
||||||
|
ajaxPost("/member/blog/publicTheme", {themeId: id}, function(re) {
|
||||||
|
t.button("reset");
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert("Error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// 导入主题
|
||||||
|
require.config({
|
||||||
|
baseUrl: '/public',
|
||||||
|
paths: {
|
||||||
|
'import_theme': 'js/app/import_theme',
|
||||||
|
'jquery.ui.widget': 'tinymce/plugins/leaui_image/public/js/jquery.ui.widget',
|
||||||
|
'fileupload': '/tinymce/plugins/leaui_image/public/js/jquery.fileupload',
|
||||||
|
'iframe-transport': '/tinymce/plugins/leaui_image/public/js/jquery.iframe-transport'
|
||||||
|
},
|
||||||
|
shim: {
|
||||||
|
'fileupload': {deps: ['jquery.ui.widget', 'iframe-transport']}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$(function() {
|
||||||
|
require(['import_theme'], function(import_theme) {});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md">
|
||||||
|
<h3 class="m-b-none">
|
||||||
|
{{if .isNew}}
|
||||||
|
新建主题
|
||||||
|
{{else}}
|
||||||
|
编辑主题
|
||||||
|
-
|
||||||
|
{{.theme.Name}}
|
||||||
|
{{end}}
|
||||||
|
<a class="btn btn-default" href="{{$.siteUrl}}/preview?themeId={{.themeId}}" target="_blank"><span class="fa fa-eye"></span> 预览</a>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#tplContent * {
|
||||||
|
font-family: Monaco, Menlo, 'Ubuntu Mono', Consolas, source-code-pro, monospace;
|
||||||
|
}
|
||||||
|
.image-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.image-list li {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.image-list li .thumb {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
line-height: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 3px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.op {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading">
|
||||||
|
模板, 样式, 脚本:
|
||||||
|
</header>
|
||||||
|
<div class="panel-body" style="height:430px;overflow: auto;">
|
||||||
|
|
||||||
|
<div class="list-group bg-white file-list">
|
||||||
|
{{range .myTpls}}
|
||||||
|
<a href="#" class="list-group-item " data-file="{{.}}">
|
||||||
|
<i class="fa fa-remove icon-muted remove-file" title="delete file" ></i>
|
||||||
|
{{.}}
|
||||||
|
<span class="badge"></span>
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<a class="btn btn-default" id="newFile">新建文件</a>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading">
|
||||||
|
当前文件: <span id="curTpl">header.html</span>
|
||||||
|
<span id="msg"></span>
|
||||||
|
</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div id="tplContent" class="form-control" style="width: 100%; height: 400px;"></div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="saveBtn" class="btn btn-success">{{msg . "save"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading">
|
||||||
|
图片: images/
|
||||||
|
</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<ul class="image-list" id="imageList">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<form id="formLogo" action="/member/blog/uploadThemeImage" method="post"
|
||||||
|
enctype="multipart/form-data" target="logoTarget">
|
||||||
|
<input type="hidden" name="themeId" value="{{.themeId}}" />
|
||||||
|
<input type="file" class="form-control" id="logo2" name="file"
|
||||||
|
onChange='$("#formLogo").submit();' />
|
||||||
|
</form>
|
||||||
|
<iframe id="logoTarget" name="logoTarget" src="#" style="display: none"></iframe>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script src="/public/member/js/ace/ace.js" type="text/javascript"></script>
|
||||||
|
<script>
|
||||||
|
var editor = ace.edit("tplContent");
|
||||||
|
editor.setTheme("ace/theme/tomorrow");
|
||||||
|
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
var userId = "{{.userInfo.UserId.Hex}}";
|
||||||
|
var themeId = "{{.themeId}}";
|
||||||
|
var themeBasePath = "/{{$.theme.Path}}";
|
||||||
|
var theme = {
|
||||||
|
cache: {}, // filename => content
|
||||||
|
curTplO: $("#curTpl"),
|
||||||
|
tplContentO: $("#tplContent"),
|
||||||
|
saveBtnO: $("#saveBtn"),
|
||||||
|
newFileO: $("#newFile"),
|
||||||
|
curTpl: "",
|
||||||
|
tplInfos: {"header.html": "头部", "footer.html": "底部", "index.html": "首页", "cate.html": "分类页", "search.html": "搜索页", "single.html": "单页", "archive.html": "归档页", "view.html": "详情页", "tags.html": "标签页", "tag_posts.html": "标签博客", "comment.html": "分享评论", "404.html":"404", "theme.json": "主题配置"},
|
||||||
|
init: function() {
|
||||||
|
var self = this;
|
||||||
|
self.showTplInfo();
|
||||||
|
$(".file-list").on("click", "a", function() {
|
||||||
|
$(".file-list a").removeClass("active");
|
||||||
|
var filename = $(this).data('file');
|
||||||
|
self.saveCurContent(); // 保存当前的
|
||||||
|
self.renderTpl(filename); // 再渲染
|
||||||
|
$(this).addClass("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
self.renderTpl("header.html");
|
||||||
|
$(".file-list a").eq(0).addClass("active");
|
||||||
|
|
||||||
|
self.saveBtnO.click(function(){
|
||||||
|
self.saveCurContent($(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
self.removeFile();
|
||||||
|
self.newFile();
|
||||||
|
|
||||||
|
self.initImage();
|
||||||
|
},
|
||||||
|
removeFile: function() {
|
||||||
|
var self = this;
|
||||||
|
$(".file-list").on("click", ".remove-file", function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
var $a = $(this).closest("a");
|
||||||
|
var file = $a.data('file');
|
||||||
|
art.confirm("Are you sure to delete " + file + " ?", function() {
|
||||||
|
ajaxPost("/member/blog/deleteTpl", {themeId: themeId, filename: file}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
$a.remove();
|
||||||
|
if(self.curTpl == file) {
|
||||||
|
$(".file-list a").eq(0).trigger("click");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
newFile: function() {
|
||||||
|
var self = this;
|
||||||
|
self.newFileO.click(function() {
|
||||||
|
art.prompt("文件名", function(file){
|
||||||
|
if(!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var t = '<a href="#" class="list-group-item " data-file="' + file + '"> <i class="fa fa-remove icon-muted remove-file" title="delete file" ></i> ' + file + '<span class="badge"></span></a>';
|
||||||
|
$(".file-list").append(t);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showTplInfo: function() {
|
||||||
|
var self = this;
|
||||||
|
$(".file-list a").each(function() {
|
||||||
|
var file = $(this).data("file");
|
||||||
|
var info = "";
|
||||||
|
info = self.tplInfos[file];
|
||||||
|
if(!info) {
|
||||||
|
if(file.indexOf(".css") > 0) {
|
||||||
|
info = "样式";
|
||||||
|
} else if(file.indexOf(".js") > 0) {
|
||||||
|
info = "脚本";
|
||||||
|
} else if(file.indexOf(".html") > 0) {
|
||||||
|
info = "模板";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$(this).find(".remove-file").remove();
|
||||||
|
}
|
||||||
|
$(this).find(".badge").text(info);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
msgO: $("#msg"),
|
||||||
|
saveCurContent: function(t) {
|
||||||
|
var self = this;
|
||||||
|
var content = editor.getValue()
|
||||||
|
|
||||||
|
var filename = self.curTpl;
|
||||||
|
// 之前的内容是否有改动
|
||||||
|
if(self.cache[filename] == content) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(t) {
|
||||||
|
t.button("loading");
|
||||||
|
}
|
||||||
|
self.msgO.html("正在保存...");
|
||||||
|
ajaxPost("/member/blog/updateTplContent", {themeId: themeId, filename: self.curTpl, content: content}, function(re) {
|
||||||
|
if(t) {
|
||||||
|
t.button("reset");
|
||||||
|
}
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
self.cache[filename] = content;
|
||||||
|
// art.tips("Success");
|
||||||
|
self.msgO.html("保存成功")
|
||||||
|
setTimeout(function() {
|
||||||
|
self.msgO.html("");
|
||||||
|
}, 3000);
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
renderContent: function(name, content) {
|
||||||
|
var self = this;
|
||||||
|
self.curTplO.html(name);
|
||||||
|
self.curTpl = name; // 这里设计
|
||||||
|
var lang = "html";
|
||||||
|
if(name.indexOf(".js") > 0 || name.indexOf(".json") > 0) {
|
||||||
|
lang = "javascript";
|
||||||
|
} else if(name.indexOf(".css") > 0) {
|
||||||
|
lang = "css";
|
||||||
|
}
|
||||||
|
editor.setValue(content);
|
||||||
|
editor.session.setMode("ace/mode/" + lang);
|
||||||
|
editor.gotoLine(1);
|
||||||
|
setTimeout(function() {
|
||||||
|
editor.gotoLine(1);
|
||||||
|
}, 200);
|
||||||
|
},
|
||||||
|
renderTpl: function(name) {
|
||||||
|
var self = this;
|
||||||
|
var content = "";
|
||||||
|
self.curTpl = name; // 这里设置
|
||||||
|
if(self.cache[name]) {
|
||||||
|
content = self.cache[name];
|
||||||
|
self.renderContent(name, content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ajaxGet("/member/blog/getTplContent", {themeId: themeId, filename: name}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
self.cache[name] = re.Item;
|
||||||
|
self.renderContent(name, re.Item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//-----------------
|
||||||
|
// theme images
|
||||||
|
imageListO: $("#imageList"),
|
||||||
|
initImage: function() {
|
||||||
|
var self = this;
|
||||||
|
self.reRenderImages();
|
||||||
|
self.imageListO.on("click", ".delete-image", function(re) {
|
||||||
|
var file = $(this).data('image');
|
||||||
|
var t = this;
|
||||||
|
art.confirm("Are you sure to delete it " + file + " ?", function() {
|
||||||
|
ajaxPost("/member/blog/deleteThemeImage", {themeId: themeId, filename: file}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
$(t).closest("li").remove();
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
renderImages: function(images) {
|
||||||
|
var self = this;
|
||||||
|
if(!images || images.length == 0) {
|
||||||
|
self.imageListO.html("无图片");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var html = "";
|
||||||
|
for(var i = 0; i < images.length; ++i) {
|
||||||
|
var image = images[i];
|
||||||
|
var path = themeBasePath + "/images/" + image;
|
||||||
|
|
||||||
|
html += '<li><div class="thumb"><img src="' + path + '"></div><div class="op"><span>' + image + '</span><br /><a class="btn btn-xs btn-warning delete-image" data-image="' + image + '"><span class="fa fa-remove"></span></a></div></li>';
|
||||||
|
}
|
||||||
|
self.imageListO.html(html);
|
||||||
|
},
|
||||||
|
reRenderImages: function() {
|
||||||
|
var self = this;
|
||||||
|
ajaxGet("/member/blog/listThemeImages", {themeId: themeId}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
var images = re.List;
|
||||||
|
self.renderImages(images);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
$(function() {
|
||||||
|
theme.init();
|
||||||
|
$(window).keydown(function(e) {
|
||||||
|
if (e.keyCode == 83 && (e.ctrlKey || e.metaKey)) {
|
||||||
|
e.preventDefault();
|
||||||
|
theme.saveBtnO.trigger("click");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// filename, result, resultCode
|
||||||
|
function uploadFinish(ret) {
|
||||||
|
if (ret) {
|
||||||
|
if (ret.resultCode == '1') {
|
||||||
|
theme.reRenderImages();
|
||||||
|
art.tips(ret.result)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
art.alert(ret.result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 上传出错
|
||||||
|
art.alert("error");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||||
|
<script src="/js/bootstrap.js"></script>
|
||||||
|
<script src="/js/i18n/msg.{{.locale}}.js"></script>
|
||||||
|
<script src="/public/admin/js/artDialog/jquery.artDialog.js?skin=default"></script>
|
||||||
|
<script src="/public/js/common.js"></script>
|
||||||
|
<script src="/public/member/js/member.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
var pathname = location.pathname; // admin/t
|
||||||
|
var search = location.search; // ?t=xxx, 如果有?page呢
|
||||||
|
var fullPath = pathname;
|
||||||
|
if(search.indexOf("?t=") >= 0) {
|
||||||
|
var fullPath = pathname + search; // /admin/t?t=xxx
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fullPath == "/member/index") {
|
||||||
|
fullPath = "/member";
|
||||||
|
}
|
||||||
|
$("#nav > li").removeClass("active");
|
||||||
|
// alert(fullPath);
|
||||||
|
// 自己
|
||||||
|
var $thisLi = $('#nav a[href="' + fullPath + '"]').parent();
|
||||||
|
$thisLi.addClass("active");
|
||||||
|
// 父也active
|
||||||
|
$thisLi.parent().parent().addClass('active');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">{{.userInfo.Username}}, 欢迎来到leanote</h3></div>
|
||||||
|
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="row m-l-none m-r-none bg-light lter">
|
||||||
|
<div class="col-sm-6 col-md-3 padder-v b-r b-light">
|
||||||
|
<span class="fa-stack fa-2x pull-left m-r-sm">
|
||||||
|
<i class="fa fa-circle fa-stack-2x text-warning"></i>
|
||||||
|
<i class="fa fa-file-o fa-stack-1x text-white"></i>
|
||||||
|
</span>
|
||||||
|
<a class="clear" href="javascript:;">
|
||||||
|
<span class="h3 block m-t-xs"><strong>{{.countNote}}</strong></span>
|
||||||
|
<small class="text-muted text-uc">{{msg . "note"}}</small>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-6 col-md-3 padder-v b-r b-light">
|
||||||
|
<span class="fa-stack fa-2x pull-left m-r-sm">
|
||||||
|
<i class="fa fa-circle fa-stack-2x text-info"></i>
|
||||||
|
<i class="fa fa-bold fa-stack-1x text-white"></i>
|
||||||
|
</span>
|
||||||
|
<a class="clear" href="javascript:;">
|
||||||
|
<span class="h3 block m-t-xs"><strong>{{.countBlog}}</strong></span>
|
||||||
|
<small class="text-muted text-uc">{{msg . "blog"}}</small>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 最新动态 -->
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<h4 class="font-thin padder">
|
||||||
|
Leanote 动态
|
||||||
|
</h4>
|
||||||
|
<ul class="list-group" id="eventsList"></ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<form>
|
||||||
|
<textarea class="form-control no-border" rows="3" placeholder="Suggestions to leanote"></textarea>
|
||||||
|
</form>
|
||||||
|
<footer class="panel-footer bg-light lter">
|
||||||
|
<button class="btn btn-info pull-right btn-sm">
|
||||||
|
POST
|
||||||
|
</button>
|
||||||
|
<ul class="nav nav-pills nav-sm">
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
-->
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
// leanote动态
|
||||||
|
var url = "https://leanote.com/blog/listCateLatest/5446753cfacfaa4f56000000";
|
||||||
|
function renderItem(item) {
|
||||||
|
return '<li class="list-group-item"><p><a target="_blank" href="http://leanote.com/blog/post/' + item.NoteId + '">' + item.Title + '</a></p><small class="block text-muted"><i class="fa fa-clock-o"></i> ' + goNowToDatetime(item.PublicTime) + '</small></li>';
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
dataType: "jsonp",//跨域访问 dataType 必须是jsonp 类型。
|
||||||
|
url: url,
|
||||||
|
type: "GET",
|
||||||
|
jsonp: "callback",
|
||||||
|
jsonpCallback: "jsonpCallback",
|
||||||
|
success: function(data) {
|
||||||
|
if(typeof data == "object" && data.Ok) {
|
||||||
|
var list = data.List;
|
||||||
|
var html = "";
|
||||||
|
for(var i = 0; i < list.length; ++i) {
|
||||||
|
var item = list[i];
|
||||||
|
html += renderItem(item);
|
||||||
|
}
|
||||||
|
$("#eventsList").html(html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
<nav class="nav-primary hidden-xs">
|
||||||
|
<ul class="nav" id="nav">
|
||||||
|
|
||||||
|
<li class="active">
|
||||||
|
<a href="/member">
|
||||||
|
<i class="fa fa-dashboard icon">
|
||||||
|
<b class="bg-success">
|
||||||
|
</b>
|
||||||
|
</i>
|
||||||
|
<span>
|
||||||
|
{{msg . "memberCenter"}}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="#">
|
||||||
|
<i class="fa fa-user icon">
|
||||||
|
<b class="bg-danger">
|
||||||
|
</b>
|
||||||
|
</i>
|
||||||
|
<span class="pull-right">
|
||||||
|
<i class="fa fa-angle-down text">
|
||||||
|
</i>
|
||||||
|
<i class="fa fa-angle-up text-active">
|
||||||
|
</i>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
帐户信息
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<!-- 导航列表 -->
|
||||||
|
<ul class="nav lt">
|
||||||
|
{{if $.userInfo.Email}}
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/username">
|
||||||
|
<span>
|
||||||
|
用户名
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/avatar">
|
||||||
|
<span>
|
||||||
|
头像
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/email">
|
||||||
|
<span>
|
||||||
|
邮箱
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/password">
|
||||||
|
<span>
|
||||||
|
密码
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{else}}
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/add_account">
|
||||||
|
<span>
|
||||||
|
添加leanote帐户
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li id="adminEmailNav">
|
||||||
|
<a href="#layout">
|
||||||
|
<i class="fa fa-bold icon">
|
||||||
|
<b class="bg-warning">
|
||||||
|
</b>
|
||||||
|
</i>
|
||||||
|
<span class="pull-right">
|
||||||
|
<i class="fa fa-angle-down text">
|
||||||
|
</i>
|
||||||
|
<i class="fa fa-angle-up text-active">
|
||||||
|
</i>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
博客
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<ul class="nav lt">
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/base">
|
||||||
|
<span>
|
||||||
|
基本信息
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/comment">
|
||||||
|
<span>
|
||||||
|
评论
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/cate">
|
||||||
|
<span>
|
||||||
|
分类
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/single">
|
||||||
|
<span>
|
||||||
|
单页面
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/paging">
|
||||||
|
<span>
|
||||||
|
分页与排序设置
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/theme">
|
||||||
|
<span>
|
||||||
|
主题
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="app">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>
|
||||||
|
{{.title}}
|
||||||
|
</title>
|
||||||
|
<meta name="description" content="leanote member center"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
|
||||||
|
<link href="/css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet">
|
||||||
|
<link href="/public/admin/css/bootstrap.3.2.0.min.css" rel="stylesheet">
|
||||||
|
<link href="/public/member/css/member.css" rel="stylesheet">
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="/public/admin/js/ie/html5shiv.js"></script>
|
||||||
|
<script src="/public/admin/js/ie/respond.min.js"></script>
|
||||||
|
<script src="/public/admin/js/ie/excanvas.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
<body class="">
|
||||||
|
<section class="vbox">
|
||||||
|
<header class="bg-dark dk header navbar navbar-fixed-top-xs">
|
||||||
|
<div class="navbar-header aside-md" id="logo">
|
||||||
|
<a href="/member" class="navbar-brand clearfix" data-toggle="fullscreen">
|
||||||
|
<span class="logo-icon"></span>
|
||||||
|
<span class="logo-title">{{msg . "memberCenter"}}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="nav navbar-nav navbar-right m-n hidden-xs nav-user">
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<a href="http://lea.leanote.com" class="dk" target="_blank">
|
||||||
|
lea++
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<a href="/note" class="dk" target="_blank">
|
||||||
|
{{msg . "myNote"}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<a href="/blog/{{$.session.Username}}" class="dk" target="_blank">
|
||||||
|
{{msg . "myBlog"}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<a href="/logout" class="dk">
|
||||||
|
{{msg . "logout"}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<img alt="{{.userInfo.Username}}" title="{{.userInfo.Username}}" src="{{if .userInfo.Logo}}{{.userInfo.Logo}}{{else}}/images/blog/default_avatar.png{{end}}" id="myAvatar"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
<section>
|
||||||
|
<section class="hbox stretch">
|
||||||
|
<!-- .aside -->
|
||||||
|
<aside class="bg-light lter b-r aside-md hidden-print hidden-xs" id="nav">
|
||||||
|
<section class="vbox">
|
||||||
|
<!--
|
||||||
|
<header class="header bg-primary lter text-center clearfix">
|
||||||
|
<div class="btn-group">
|
||||||
|
<div class="hidden-nav-xs">
|
||||||
|
<a class="btn btn-sm btn-primary">
|
||||||
|
Welcome, admin!
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<section class="w-f scrollable">
|
||||||
|
<div class="slim-scroll" data-height="auto" data-disable-fade-out="true"
|
||||||
|
data-distance="0" data-size="5px" data-color="#333333">
|
||||||
|
<!-- nav -->
|
||||||
|
{{template "member/nav.html" .}}
|
||||||
|
<!-- / nav -->
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<footer class="footer lt hidden-xs b-t b-light" style="min-height: initial;
|
||||||
|
padding: 10px 15px;text-align:center;">
|
||||||
|
<a href="http://leanote.com" target="_blank">leanote</a> © 2014
|
||||||
|
<!--
|
||||||
|
<a href="#nav" data-toggle="class:nav-xs" class="pull-right btn btn-sm btn-default btn-icon">
|
||||||
|
<i class="fa fa-angle-left text">
|
||||||
|
</i>
|
||||||
|
<i class="fa fa-angle-right text-active">
|
||||||
|
</i>
|
||||||
|
</a>
|
||||||
|
-->
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</aside>
|
||||||
|
<!-- /.aside -->
|
||||||
|
<section id="content">
|
||||||
|
<section class="vbox">
|
||||||
|
<section class="scrollable padder">
|
||||||
|
<!-- 导航
|
||||||
|
<ul class="breadcrumb no-border no-radius b-b b-light pull-in">
|
||||||
|
<li>
|
||||||
|
<a href="index.html">
|
||||||
|
<i class="fa fa-home">
|
||||||
|
</i>
|
||||||
|
Home
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#">
|
||||||
|
Elements
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="active">
|
||||||
|
Components
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
-->
|
||||||
|
<!-- 主要内容区 -->
|
||||||
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">用户名设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="thirdAccountMsg" style="display: none"></div>
|
||||||
|
{{msg . "thirdCreateAcountTips"}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="thirdEmail">{{msg . "email"}}</label>
|
||||||
|
<input type="text" class="form-control" id="thirdEmail" name="email"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputEmail"},
|
||||||
|
{rule: "email", msg: "errorEmail"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#thirdAccountMsg"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="thirdPwd">{{msg . "password"}}</label>
|
||||||
|
<input type="password" class="form-control" id="thirdPwd" name="pwd"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputPassword"},
|
||||||
|
{rule: "password", msg: "errorPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#thirdAccountMsg"
|
||||||
|
/>
|
||||||
|
{{msg . "passwordTips"}}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="thirdPwd2">{{msg . "password2"}}</label>
|
||||||
|
<input type="password" class="form-control" id="thirdPwd2" name="pwd2"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputPassword2"},
|
||||||
|
{rule: "equalTo", data:"#thirdPwd", msg: "confirmPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#thirdAccountMsg"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="accountBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
// 第三方账号设置
|
||||||
|
var acountVd = new vd.init("#formData");
|
||||||
|
$("#accountBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!acountVd.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var email = $("#thirdEmail").val();
|
||||||
|
var pwd = $("#thirdPwd").val();
|
||||||
|
var pwd2 = $("#thirdPwd2").val();
|
||||||
|
post("/user/addAccount", {email: email, pwd: pwd}, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
showAlert("#thirdAccountMsg", getMsg("createAccountSuccess"), "success");
|
||||||
|
setTimeout(function() {
|
||||||
|
location.reload();
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
showAlert("#thirdAccountMsg", ret.Msg || getMsg("createAccountFailed"), "danger");
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">头像设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="uploadAvatar" method="post" action="/file/uploadAvatar" enctype="multipart/form-data">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<div id="dropAvatar" class="dropzone">
|
||||||
|
<div>
|
||||||
|
<img src="{{if .userInfo.Logo}}{{.userInfo.Logo}}{{else}}/images/blog/default_avatar.png{{end}}" id="avatar"/>
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-success btn-choose-file">
|
||||||
|
<span class="fa fa-upload"></span> Choose Image
|
||||||
|
</a>
|
||||||
|
<input type="file" name="file" multiple/>
|
||||||
|
</div>
|
||||||
|
<div id="avatarUploadMsg">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script src="/js/require.js"></script>
|
||||||
|
<script>
|
||||||
|
var UrlPrefix = "{{.siteUrl}}"; // 为了发weibo
|
||||||
|
require.config({
|
||||||
|
baseUrl: '/public',
|
||||||
|
paths: {
|
||||||
|
// ajax upload image/attach
|
||||||
|
'attachment_upload': 'js/app/attachment_upload',
|
||||||
|
'jquery.ui.widget': 'tinymce/plugins/leaui_image/public/js/jquery.ui.widget',
|
||||||
|
'fileupload': '/tinymce/plugins/leaui_image/public/js/jquery.fileupload',
|
||||||
|
'iframe-transport': '/tinymce/plugins/leaui_image/public/js/jquery.iframe-transport'
|
||||||
|
},
|
||||||
|
shim: {
|
||||||
|
'fileupload': {deps: ['jquery.ui.widget', 'iframe-transport']}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$(function() {
|
||||||
|
require(['attachment_upload'], function(attachment_upload) {});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">邮箱设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
{{msg . "currentEmail" .userInfo.Email}}
|
||||||
|
<br />
|
||||||
|
{{if .userInfo.Verified}}
|
||||||
|
<span class="label label-green">{{msg . "verified"}}</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="label label-red">{{msg . "unVerified"}}</span>
|
||||||
|
<a class="raw nowToActive">{{msg . "verifiedNow"}}</a>
|
||||||
|
{{msg . "or"}}
|
||||||
|
<a class="raw reSendActiveEmail">{{msg . "resendVerifiedEmail"}}</a>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div class="alert alert-danger" id="emailMsg" style="display: none"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{msg . "email"}}</label>
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
id="email"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputEmail"},
|
||||||
|
{rule: "email", msg: "errorEmail"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#emailMsg"
|
||||||
|
/>
|
||||||
|
{{msg . "updateEmailTips"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="emailBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 激活邮件 -->
|
||||||
|
<div class="modal fade bs-modal-sm" id="reSendActiveEmailDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-sm">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title" class="modalTitle">{{msg . "sendVerifiedEmail"}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div style="max-height: 300px; padding: 5px 0; text-align: center; overflow-y: auto; overflow-x: hidden" class="weibo">
|
||||||
|
<span class="text">
|
||||||
|
<img src="/images/loading-24.gif"/>
|
||||||
|
{{msg . "emailInSending"}} {{.userInfo.Email}}...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||||
|
<button type="button" class="btn btn-success viewEmailBtn disabled">{{msg . "checkEmail"}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
// 修改邮箱
|
||||||
|
var emailVd = new vd.init("#formData");
|
||||||
|
$("#emailBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!emailVd.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var email = $("#email").val();
|
||||||
|
post("/user/updateEmailSendActiveEmail", {email: email}, function(e) {
|
||||||
|
if(e.Ok) {
|
||||||
|
var url = getEmailLoginAddress(email);
|
||||||
|
showAlert("#emailMsg", getMsg("verifiedEmaiHasSent") +" <a href='" + url + "' target='_blank'>" + getMsg("checkEmail") + "</a>", "success");
|
||||||
|
} else {
|
||||||
|
showAlert("#emailMsg", e.Msg || getMsg("emailSendFailed"), "danger");
|
||||||
|
}
|
||||||
|
}, "#emailBtn");
|
||||||
|
});
|
||||||
|
|
||||||
|
// 重新发送
|
||||||
|
$(".reSendActiveEmail").click(function() {
|
||||||
|
// 弹框出来
|
||||||
|
showDialog2("#reSendActiveEmailDialog", {postShow: function() {
|
||||||
|
ajaxGet("/user/reSendActiveEmail", {}, function(ret) {
|
||||||
|
if (typeof ret == "object" && ret.Ok) {
|
||||||
|
$("#reSendActiveEmailDialog .text").html(getMsg("sendSuccess"))
|
||||||
|
$("#reSendActiveEmailDialog .viewEmailBtn").removeClass("disabled");
|
||||||
|
$("#reSendActiveEmailDialog .viewEmailBtn").click(function() {
|
||||||
|
hideDialog();
|
||||||
|
var url = getEmailLoginAddress("{{.userInfo.Email}}");
|
||||||
|
window.open(url, "_blank");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$("#reSendActiveEmailDialog .text").html(getMsg("sendFailed"))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}});
|
||||||
|
});
|
||||||
|
// 现在去验证
|
||||||
|
$(".nowToActive").click(function() {
|
||||||
|
var url = getEmailLoginAddress("{{.userInfo.Email}}");
|
||||||
|
window.open(url, "_blank");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">用户名设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="pwdMsg" style="display: none"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="oldPwd">{{msg . "oldPassword"}}</label>
|
||||||
|
<input type="password" class="form-control" id="oldPwd" name="oldPwd"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#pwdMsg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="pwd">{{msg . "newPassword"}}</label>
|
||||||
|
<input type="password" class="form-control" id="pwd" name="pwd"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputNewPassword"},
|
||||||
|
{rule: "password", msg: "errorPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#pwdMsg"
|
||||||
|
>
|
||||||
|
{{msg . "passwordTips"}}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="pwd2">{{msg . "password2"}}</label>
|
||||||
|
<input type="password" class="form-control" id="pwd2" name="pwd2"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputPassword2"},
|
||||||
|
{rule: "equalTo", data:"#pwd", msg: "confirmPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#pwdMsg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="pwdBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
// 修改密码
|
||||||
|
var updatePwdVd = new vd.init("#formData");
|
||||||
|
$("#pwdBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!updatePwdVd.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var oldPwd = $("#oldPwd").val();
|
||||||
|
var pwd = $("#pwd").val();
|
||||||
|
post("/user/updatePwd", {oldPwd: oldPwd, pwd: pwd}, function(e) {
|
||||||
|
if(e.Ok) {
|
||||||
|
showAlert("#pwdMsg", getMsg("updatePasswordSuccess"), "success");
|
||||||
|
} else {
|
||||||
|
showAlert("#pwdMsg", e.Msg, "danger");
|
||||||
|
}
|
||||||
|
}, "#pwdBtn");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">用户名设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="usernameMsg" style="display: none"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{msg . "username"}}</label>
|
||||||
|
<input type="text" class="form-control" id="username"
|
||||||
|
value="{{.userInfo.Username}}"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputUsername"},
|
||||||
|
{rule: "noSpecialChars", msg: "noSpecialChars"},
|
||||||
|
{rule: "minLength", data: 4, msg: "minLength", msgData: 4}
|
||||||
|
]'
|
||||||
|
data-msg_target="#usernameMsg"
|
||||||
|
/>
|
||||||
|
{{msg . "setUsernameTips" .userInfo.Email}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="usernameBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
//-------------
|
||||||
|
var usernameVd = new vd.init("#formData");
|
||||||
|
$("#usernameBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!usernameVd.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var username = $("#username").val();
|
||||||
|
post("/user/updateUsername", {username: username}, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
showAlert('#usernameMsg', getMsg("updateUsernameSuccess"), "success");
|
||||||
|
} else {
|
||||||
|
showAlert('#usernameMsg', ret.Msg || getMsg("usernameIsExisted"), "danger");
|
||||||
|
}
|
||||||
|
}, "#usernameBtn");
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -136,30 +136,28 @@ function log(o) {
|
|||||||
<i class="fa fa-angle-down"></i>
|
<i class="fa fa-angle-down"></i>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu li-a" role="menu">
|
<ul class="dropdown-menu li-a" role="menu">
|
||||||
<li role="presentation" id="setInfo">
|
<li role="presentation">
|
||||||
<a>
|
<a href="/member" target="_blank">
|
||||||
<i class="fa fa-info"></i>
|
<i class="fa fa-user"></i>
|
||||||
{{msg . "accountSetting"}}
|
{{msg . "memberCenter"}}
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li role="presentation" id="setAvatarMenu">
|
|
||||||
<a>
|
|
||||||
<i class="fa fa-smile-o"></i>
|
|
||||||
{{msg . "setAvatar"}}
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li role="presentation" id="setTheme">
|
<li role="presentation" id="setTheme">
|
||||||
<a>
|
<a>
|
||||||
<i class="fa fa-sun-o"></i>
|
<i class="fa fa-sun-o"></i>
|
||||||
{{msg . "themeSetting"}}
|
{{msg . "themeSetting"}}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<!--
|
|
||||||
<li role="presentation" id="yourSuggestions">
|
<li role="presentation" class="divider"></li>
|
||||||
<i class="fa fa-comment-o"></i>
|
<li role="presentation">
|
||||||
{{msg . "yourSuggestions"}}
|
<a href="/member/blog/base" target="_blank">
|
||||||
|
<i class="fa fa-bold"></i>
|
||||||
|
{{msg . "blogSet"}}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
-->
|
|
||||||
<li role="presentation" class="my-link" >
|
<li role="presentation" class="my-link" >
|
||||||
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
||||||
<i class="fa fa-bold"></i>
|
<i class="fa fa-bold"></i>
|
||||||
|
|||||||
@@ -136,30 +136,28 @@ function log(o) {
|
|||||||
<i class="fa fa-angle-down"></i>
|
<i class="fa fa-angle-down"></i>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu li-a" role="menu">
|
<ul class="dropdown-menu li-a" role="menu">
|
||||||
<li role="presentation" id="setInfo">
|
<li role="presentation">
|
||||||
<a>
|
<a href="/member" target="_blank">
|
||||||
<i class="fa fa-info"></i>
|
<i class="fa fa-user"></i>
|
||||||
{{msg . "accountSetting"}}
|
{{msg . "memberCenter"}}
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li role="presentation" id="setAvatarMenu">
|
|
||||||
<a>
|
|
||||||
<i class="fa fa-smile-o"></i>
|
|
||||||
{{msg . "setAvatar"}}
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li role="presentation" id="setTheme">
|
<li role="presentation" id="setTheme">
|
||||||
<a>
|
<a>
|
||||||
<i class="fa fa-sun-o"></i>
|
<i class="fa fa-sun-o"></i>
|
||||||
{{msg . "themeSetting"}}
|
{{msg . "themeSetting"}}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<!--
|
|
||||||
<li role="presentation" id="yourSuggestions">
|
<li role="presentation" class="divider"></li>
|
||||||
<i class="fa fa-comment-o"></i>
|
<li role="presentation">
|
||||||
{{msg . "yourSuggestions"}}
|
<a href="/member/blog/base" target="_blank">
|
||||||
|
<i class="fa fa-bold"></i>
|
||||||
|
{{msg . "blogSet"}}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
-->
|
|
||||||
<li role="presentation" class="my-link" >
|
<li role="presentation" class="my-link" >
|
||||||
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
||||||
<i class="fa fa-bold"></i>
|
<i class="fa fa-bold"></i>
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
<input id="friendsEmail" type="text" class="form-control" placeholder="{{msg . "friendEmail"}}">
|
<input id="friendsEmail" type="text" class="form-control" placeholder="{{msg . "friendEmail"}}">
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<label for="readPerm1"><input type="radio" name="perm1" checked="checked" value="0" id="readPerm1"> {{msg . "readOnly"}}</label>
|
<label for="readPerm1"><input type="radio" name="perm1" checked="checked" value="0" id="readPerm1"> {{msg $ "readOnly"}}</label>
|
||||||
<label for="writePerm1"><input type="radio" name="perm1" value="1" id="writePerm1"> {{msg . "writable"}}</label>
|
<label for="writePerm1"><input type="radio" name="perm1" value="1" id="writePerm1"> {{msg $ "writable"}}</label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" onclick="addShareNoteOrNotebook(1)">{{msg . "share"}}</button>
|
<button class="btn btn-success" onclick="addShareNoteOrNotebook(1)">{{msg . "share"}}</button>
|
||||||
@@ -40,9 +40,9 @@
|
|||||||
<td>{{$v.Email}}</td>
|
<td>{{$v.Email}}</td>
|
||||||
<td>
|
<td>
|
||||||
{{if eq $v.Perm 0}}
|
{{if eq $v.Perm 0}}
|
||||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg . "readOnly"}}</a>
|
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg $ "readOnly"}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg . "writable"}}</a>
|
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg $ "writable"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -25,32 +25,60 @@ POST /findPasswordUpdate Auth.FindPasswordUpdate
|
|||||||
|
|
||||||
# blog
|
# blog
|
||||||
|
|
||||||
GET /blog/getLikeAndComments Blog.GetLikeAndComments
|
GET /blog/getLikesAndComments Blog.GetLikesAndComments
|
||||||
GET /blog/getLike Blog.GetLike
|
GET /blog/getLikes Blog.GetLikes
|
||||||
GET /blog/listLikes Blog.ListLikes
|
* /blog/incReadNum Blog.IncReadNum
|
||||||
GET /blog/incReadNum Blog.IncReadNum
|
* /blog/likePost Blog.LikePost
|
||||||
POST /blog/likeBlog Blog.LikeBlog
|
* /blog/likeComment Blog.LikeComment
|
||||||
POST /blog/likeComment Blog.LikeComment
|
* /blog/deleteComment Blog.DeleteComment
|
||||||
POST /blog/deleteComment Blog.DeleteComment
|
GET /blog/getComments Blog.GetComments
|
||||||
GET /blog/listComments Blog.ListComments
|
* /blog/commentPost Blog.CommentPost
|
||||||
POST /blog/comment Blog.Comment
|
GET /blog/getPostStat Blog.GetPostStat
|
||||||
GET /blog/ListComments Blog.ListComments
|
|
||||||
|
|
||||||
|
|
||||||
|
GET /blog/tags/:userIdOrEmail Blog.Tags
|
||||||
|
GET /blog/tags Blog.Tags
|
||||||
|
|
||||||
|
GET /blog/tag/:userIdOrEmail/:tag Blog.Tag
|
||||||
|
GET /blog/tag/:tag Blog.Tag
|
||||||
|
|
||||||
GET /blog/search/:userIdOrEmail Blog.Search
|
GET /blog/search/:userIdOrEmail Blog.Search
|
||||||
GET /blog/search Blog.Search
|
GET /blog/search Blog.Search
|
||||||
GET /blog/set Blog.Set
|
|
||||||
GET /blog/aboutMe/:userIdOrEmail Blog.AboutMe
|
GET /blog/archive/:userIdOrEmail Blog.Archive
|
||||||
GET /blog/aboutMe Blog.AboutMe
|
GET /blog/archive Blog.Archive
|
||||||
GET /blog/view/:noteId Blog.View
|
|
||||||
POST /blog/setUserBlogBase Blog.SetUserBlogBase
|
GET /blog/post/:noteId Blog.Post
|
||||||
POST /blog/setUserBlogComment Blog.SetUserBlogComment
|
GET /blog/view/:noteId Blog.Post
|
||||||
POST /blog/setUserBlogStyle Blog.SetUserBlogStyle
|
GET /blog/single/:singleId Blog.Single
|
||||||
|
|
||||||
GET /blog/cate/:notebookId Blog.Cate
|
GET /blog/cate/:notebookId Blog.Cate
|
||||||
GET /blog/listCateLatest/:notebookId Blog.ListCateLatest
|
GET /blog/listCateLatest/:notebookId Blog.ListCateLatest
|
||||||
GET /blog/isMe.js Blog.IsMe
|
|
||||||
GET /blog/:userIdOrEmail Blog.Index
|
GET /blog/:userIdOrEmail Blog.Index
|
||||||
GET /blog Blog.Index
|
GET /blog Blog.Index
|
||||||
|
GET /blog/* Blog.E()
|
||||||
|
|
||||||
|
#---------------
|
||||||
|
# preview
|
||||||
|
GET /preview/tags/:userIdOrEmail Preview.Tags
|
||||||
|
GET /preview/tags Preview.Tags
|
||||||
|
|
||||||
|
GET /preview/tag/:userIdOrEmail/:tag Preview.Tag
|
||||||
|
GET /preview/tag/:tag Preview.Tag
|
||||||
|
|
||||||
|
GET /preview/search/:userIdOrEmail Preview.Search
|
||||||
|
GET /preview/search Preview.Search
|
||||||
|
|
||||||
|
GET /preview/archive/:userIdOrEmail Preview.Archive
|
||||||
|
GET /preview/archive Preview.Archive
|
||||||
|
|
||||||
|
GET /preview/view/:noteId Preview.Post
|
||||||
|
GET /preview/post/:noteId Preview.Post
|
||||||
|
GET /preview/single/:singleId Preview.Single
|
||||||
|
|
||||||
|
GET /preview/cate/:notebookId Preview.Cate
|
||||||
|
GET /preview/:userIdOrEmail Preview.Index
|
||||||
|
GET /preview Preview.Index
|
||||||
|
|
||||||
# Map static resources from the /app/public folder to the /public path
|
# Map static resources from the /app/public folder to the /public path
|
||||||
GET /favicon.ico Static.Serve("public/images/favicon.ico")
|
GET /favicon.ico Static.Serve("public/images/favicon.ico")
|
||||||
@@ -64,9 +92,12 @@ GET /tinymce/*filepath Static.Serve("public/tinymce")
|
|||||||
#GET /plugins/*filepath Static.Serve("public/tinymce/plugins")
|
#GET /plugins/*filepath Static.Serve("public/tinymce/plugins")
|
||||||
GET /upload/*filepath Static.Serve("public/upload")
|
GET /upload/*filepath Static.Serve("public/upload")
|
||||||
|
|
||||||
# API
|
# member
|
||||||
# the prefix of api's controllername is "Api"
|
# the prefix of member's controllername is "Member"
|
||||||
|
* /member MemberIndex.Index
|
||||||
|
* /member/index MemberIndex.Index
|
||||||
|
|
||||||
# common
|
# common
|
||||||
* /:controller/:action :controller.:action
|
* /:controller/:action :controller.:action
|
||||||
* /api/:controller/:action :controller.:action # 需要
|
* /api/:controller/:action :controller.:action
|
||||||
|
* /member/:controller/:action :controller.:action
|
||||||
@@ -87,6 +87,7 @@ new=New
|
|||||||
newMarkdown=New markdown note
|
newMarkdown=New markdown note
|
||||||
clickAddTag=Click to add Tag
|
clickAddTag=Click to add Tag
|
||||||
notebook=Notebook
|
notebook=Notebook
|
||||||
|
note=Note
|
||||||
myNotebook=My notebook
|
myNotebook=My notebook
|
||||||
addNotebook=Add notebook
|
addNotebook=Add notebook
|
||||||
search=Search
|
search=Search
|
||||||
@@ -129,6 +130,7 @@ logout=Logout
|
|||||||
basicInfo=Basic
|
basicInfo=Basic
|
||||||
updateEmail=Update email
|
updateEmail=Update email
|
||||||
usernameSetting=Update username
|
usernameSetting=Update username
|
||||||
|
username=Username
|
||||||
oldPassword=Old password
|
oldPassword=Old password
|
||||||
newPassword=New password
|
newPassword=New password
|
||||||
admin=Admin
|
admin=Admin
|
||||||
@@ -222,17 +224,24 @@ inputPassword=Password is required
|
|||||||
inputNewPassword=The new password is required
|
inputNewPassword=The new password is required
|
||||||
inputPassword2=Please input the new password again
|
inputPassword2=Please input the new password again
|
||||||
errorPassword=The passowd's length is at least 6 and be sure as complex as possible
|
errorPassword=The passowd's length is at least 6 and be sure as complex as possible
|
||||||
|
oldPasswordError=The old password not match
|
||||||
confirmPassword=Password not matched
|
confirmPassword=Password not matched
|
||||||
updatePasswordSuccess=Update password success
|
updatePasswordSuccess=Update password success
|
||||||
errorDomain=The custom domain is invalid, eg. www.myblog.com
|
errorDomain=The custom domain is invalid, eg. www.myblog.com
|
||||||
domainExisted=Custom domain is already existed
|
domainExisted=Custom domain is already existed
|
||||||
errorSubDomain=Please input the valid sub domain, the length is at least 4 and no special chars
|
errorSubDomain=Please input the valid sub domain, the length is at least 4 and no special chars
|
||||||
subDomainExisted=Sub domain is already existed
|
subDomainExisted=Sub domain is already existed
|
||||||
|
domainNotPointToLeanote=The custom domin hasn't pointed to d.leanote.com
|
||||||
|
errorPerPageSize=Page size is error
|
||||||
|
errorSortField=Sort Field is error
|
||||||
|
|
||||||
# lea++
|
# lea++
|
||||||
leaDesc=leanote blog platform
|
leaDesc=leanote blog platform
|
||||||
recommend=Recommend
|
recommend=Recommend
|
||||||
latest=Latest
|
latest=Latest
|
||||||
|
|
||||||
|
# 用户中心
|
||||||
|
memberCenter=Member Center
|
||||||
|
|
||||||
# error
|
# error
|
||||||
notFound=This page cann't found.
|
notFound=This page cann't found.
|
||||||
@@ -108,6 +108,7 @@ new=新建
|
|||||||
newMarkdown=新建Markdown笔记
|
newMarkdown=新建Markdown笔记
|
||||||
clickAddTag=点击添加标签
|
clickAddTag=点击添加标签
|
||||||
notebook=笔记本
|
notebook=笔记本
|
||||||
|
note=笔记
|
||||||
myNotebook=我的笔记本
|
myNotebook=我的笔记本
|
||||||
addNotebook=添加笔记本
|
addNotebook=添加笔记本
|
||||||
search=搜索
|
search=搜索
|
||||||
@@ -150,6 +151,7 @@ logout=退出
|
|||||||
basicInfo=基本信息
|
basicInfo=基本信息
|
||||||
updateEmail=修改Email
|
updateEmail=修改Email
|
||||||
usernameSetting=用户名设置
|
usernameSetting=用户名设置
|
||||||
|
username=用户名
|
||||||
oldPassword=旧密码
|
oldPassword=旧密码
|
||||||
newPassword=新密码
|
newPassword=新密码
|
||||||
admin=后台管理
|
admin=后台管理
|
||||||
@@ -248,17 +250,24 @@ inputPassword=请输入密码
|
|||||||
inputNewPassword=请输入新密码
|
inputNewPassword=请输入新密码
|
||||||
inputPassword2=请输入确认密码
|
inputPassword2=请输入确认密码
|
||||||
errorPassword=请输入长度不少于6位的密码, 尽量复杂
|
errorPassword=请输入长度不少于6位的密码, 尽量复杂
|
||||||
|
oldPasswordError=旧密码错误
|
||||||
confirmPassword=两次密码输入不正确
|
confirmPassword=两次密码输入不正确
|
||||||
updatePasswordSuccess=修改密码成功
|
updatePasswordSuccess=修改密码成功
|
||||||
errorDomain=请输入正确的域名, 如www.myblog.com
|
errorDomain=请输入正确的域名, 如www.myblog.com
|
||||||
domainExisted=域名已存在
|
domainExisted=域名已存在
|
||||||
errorSubDomain=请输入正确的博客子域名, 长度至少为4, 不能包含特殊字符
|
errorSubDomain=请输入正确的博客子域名, 长度至少为4, 不能包含特殊字符
|
||||||
subDomainExisted=博客子域名已存在
|
subDomainExisted=博客子域名已存在
|
||||||
|
domainNotPointToLeanote=该域名还未指向 d.leanote.com, 请稍后再试
|
||||||
|
errorPerPageSize=每页记录数至少为1
|
||||||
|
errorSortField=排序类型错误
|
||||||
|
|
||||||
# lea++
|
# lea++
|
||||||
leaDesc=leanote博客平台
|
leaDesc=leanote博客平台
|
||||||
recommend=推荐
|
recommend=推荐
|
||||||
latest=最新
|
latest=最新
|
||||||
|
|
||||||
|
# 用户中心
|
||||||
|
memberCenter=用户中心
|
||||||
|
|
||||||
# 必须要加这个, 奇怪
|
# 必须要加这个, 奇怪
|
||||||
[CN]
|
[CN]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
博客的默认主题和一些公用的静态文件
|
||||||
|
|
||||||
|
themes 是默认主题, 有3个
|
||||||
|
|
||||||
|
用户自定义的主题不在这里, 在public/upload/userId/thmems下
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
.entry-controls {
|
||||||
|
text-align: right;
|
||||||
|
padding-top: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-top: 1px solid #f1f2f3;
|
||||||
|
}
|
||||||
|
.entry-controls .right-section {
|
||||||
|
float: right;
|
||||||
|
color: #9d9e9f;
|
||||||
|
}
|
||||||
|
.entry-controls .right-section a {
|
||||||
|
color: #9d9e9f;
|
||||||
|
}
|
||||||
|
.post-menu-button {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
.ui-menu-button {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.entry-controls .control-item {
|
||||||
|
margin-left: 15px;
|
||||||
|
color: #9d9e9f;
|
||||||
|
font-size: 15px;
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transition: all 0.05s ease-in-out;
|
||||||
|
-moz-transition: all 0.05s ease-in-out;
|
||||||
|
-o-transition: all 0.05s ease-in-out;
|
||||||
|
transition: all 0.05s ease-in-out;
|
||||||
|
}
|
||||||
|
.vote-section-wrapper {
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.entry-controls .voters {
|
||||||
|
display: block;
|
||||||
|
margin-top: 52px;
|
||||||
|
height: 25px;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.entry-controls .voters .more-voters,
|
||||||
|
.entry-controls .voters .voter {
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
position: relative;
|
||||||
|
margin: 0 8px 8px 0;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.entry-controls .voters .voter > img {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.avatar-small {
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.comment-box {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.comment-box a {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.comment-box .box-header {
|
||||||
|
border-top: 1px solid #f1f2f3;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #9d9e9f;
|
||||||
|
padding: 30px 0 10px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.comment-box .box-header .icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
vertical-align: -3px;
|
||||||
|
}
|
||||||
|
.comment-box .box-header a.comment-options {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.comment-box .box-header {
|
||||||
|
padding-left: 17px;
|
||||||
|
padding-right: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.comment-box .load-more {
|
||||||
|
height: 26px;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding-top: 24px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
border-top: solid 1px #f1f2f3;
|
||||||
|
}
|
||||||
|
.comment-box .load-more a {
|
||||||
|
color: #9d9e9f;
|
||||||
|
}
|
||||||
|
.comment-box .ui-spinner {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.comment-box .ui-spinner.small {
|
||||||
|
position: relative;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
.comment-box.empty.cannot-comment {
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
.comment-box.cannot-comment .editable,
|
||||||
|
.comment-box.cannot-comment .editable,
|
||||||
|
.comment-box.comment-box.cannot-comment .command,
|
||||||
|
.comment-box.comment-box.cannot-comment .op-link.reply {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.comment-box.empty.cannot-comment .comment-form {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.comment-box.empty.cannot-comment .comment-box-ft {
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
.comment-box.empty.cannot-comment .comment-box-ft,
|
||||||
|
.comment-box .comment-box-ft {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
.comment-box .avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 20px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.comment-box .message {
|
||||||
|
margin-top: 24px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: center;
|
||||||
|
background: #F7F8F9;
|
||||||
|
color: #9d9e9f;
|
||||||
|
}
|
||||||
|
.comment-item {
|
||||||
|
position: relative;
|
||||||
|
list-style: none;
|
||||||
|
outline: 0;
|
||||||
|
padding: 15px 0;
|
||||||
|
border-bottom: solid 1px #f1f2f3;
|
||||||
|
}
|
||||||
|
.item-highlight * {
|
||||||
|
border-radius: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.comment-item {
|
||||||
|
padding-left: 17px;
|
||||||
|
padding-right: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.comment-item > .avatar-link {
|
||||||
|
float: left;
|
||||||
|
margin: 4px 0 0;
|
||||||
|
}
|
||||||
|
.comment-item > .comment-body {
|
||||||
|
margin: 0 0 0 60px;
|
||||||
|
}
|
||||||
|
.comment-item .comment-content {
|
||||||
|
min-height: 22px;
|
||||||
|
font-size: 15px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
.comment-item .comment-hd,
|
||||||
|
.comment-item .comment-ft {
|
||||||
|
color: #9d9e9f;
|
||||||
|
}
|
||||||
|
.comment-item .comment-hd .desc,
|
||||||
|
.comment-item .comment-ft .desc {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.comment-item .comment-ft {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.comment-item .op-link {
|
||||||
|
color: #9d9e9f;
|
||||||
|
font-size: 15px;
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
.comment-item .op-link {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 420px) {
|
||||||
|
.comment-item .op-link .icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.comment-item .like-num {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.comment-item .like-num.nil {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.comment-item:hover .op-link {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
.comment-form.comment-reply-form {
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
.comment-form .row {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.comment-form .editable {
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 16px;
|
||||||
|
min-height: 18px;
|
||||||
|
line-height: 26px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
width: 100%;
|
||||||
|
color: #222;
|
||||||
|
cursor: text;
|
||||||
|
border: 1px solid #DDD;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) inset;
|
||||||
|
background: #e6eaed;
|
||||||
|
color: #747f8c;
|
||||||
|
}
|
||||||
|
#commentForm {
|
||||||
|
border-top: solid 1px #f1f2f3;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
.comment-form .editable:focus {
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
}
|
||||||
|
.comment-form > .command {
|
||||||
|
display: none;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.comment-form > .command .save {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.comment-form > .command .cancel {
|
||||||
|
color: #9d9e9f;
|
||||||
|
vertical-align: -7px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.comment-form.expanded .command {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.comment-form > .avatar + .editable {
|
||||||
|
margin-left: 60px;
|
||||||
|
}
|
||||||
|
#comments {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#comments form {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.comment-form {
|
||||||
|
padding-left: 17px;
|
||||||
|
padding-right: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-zan {
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
.btn-weibo {
|
||||||
|
border-radius: 50px;
|
||||||
|
color: #d44137;
|
||||||
|
border-color: #d44137;
|
||||||
|
}
|
||||||
|
.btn-weibo:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: #d44137;
|
||||||
|
}
|
||||||
|
.btn-weixin {
|
||||||
|
color: #38ad5a;
|
||||||
|
border-color: #38ad5a;
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
.btn-weixin:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: #38ad5a;
|
||||||
|
}
|
||||||
|
.reply-comment-btn {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
.avatar-wrap {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.editor-wrap {
|
||||||
|
margin-left: 60px;
|
||||||
|
}
|
||||||
|
#weixinQRCode {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.report-form ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.report-form .options > li {
|
||||||
|
list-style: none;
|
||||||
|
display: block;
|
||||||
|
line-height: 2;
|
||||||
|
color: #666768;
|
||||||
|
}
|
||||||
|
.report-form .options input {
|
||||||
|
margin-right: 10px;
|
||||||
|
vertical-align: 1px;
|
||||||
|
}
|
||||||
|
.footnote {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
#moreComments {
|
||||||
|
padding: 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.needLogin {
|
||||||
|
padding: 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 18px;
|
||||||
|
border-top: 1px solid #f1f2f3;
|
||||||
|
}
|
||||||
|
.needLogin a {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
!function(t,e){"use strict";"undefined"!=typeof module&&module.exports?module.exports=e(require("jquery")(t)):"function"==typeof define&&define.amd?define("bootstrap-dialog",["jquery"],function(t){return e(t)}):t.BootstrapDialog=e(t.jQuery)}(this,function(t){"use strict";var e=function(n){this.defaultOptions=t.extend(!0,{id:e.newGuid(),buttons:[],data:{},onshow:null,onshown:null,onhide:null,onhidden:null},e.defaultOptions),this.indexedButtons={},this.registeredButtonHotkeys={},this.draggableData={isMouseDown:!1,mouseOffset:{}},this.realized=!1,this.opened=!1,this.initOptions(n),this.holdThisInstance()};return e.NAMESPACE="bootstrap-dialog",e.TYPE_DEFAULT="type-default",e.TYPE_INFO="type-info",e.TYPE_PRIMARY="type-primary",e.TYPE_SUCCESS="type-success",e.TYPE_WARNING="type-warning",e.TYPE_DANGER="type-danger",e.DEFAULT_TEXTS={},e.DEFAULT_TEXTS[e.TYPE_DEFAULT]="提示",e.DEFAULT_TEXTS[e.TYPE_INFO]="提示",e.DEFAULT_TEXTS[e.TYPE_PRIMARY]="提示",e.DEFAULT_TEXTS[e.TYPE_SUCCESS]="Success",e.DEFAULT_TEXTS[e.TYPE_WARNING]="Warning",e.DEFAULT_TEXTS[e.TYPE_DANGER]="Danger",e.SIZE_NORMAL="size-normal",e.SIZE_LARGE="size-large",e.BUTTON_SIZES={},e.BUTTON_SIZES[e.SIZE_NORMAL]="",e.BUTTON_SIZES[e.SIZE_LARGE]="btn-lg",e.ICON_SPINNER="glyphicon glyphicon-asterisk",e.ZINDEX_BACKDROP=1040,e.ZINDEX_MODAL=1050,e.defaultOptions={type:e.TYPE_PRIMARY,size:e.SIZE_NORMAL,cssClass:"",title:null,message:null,nl2br:!0,closable:!0,closeByBackdrop:!0,closeByKeyboard:!0,spinicon:e.ICON_SPINNER,autodestroy:!0,draggable:!1,animate:!0,description:""},e.configDefaultOptions=function(n){e.defaultOptions=t.extend(!0,e.defaultOptions,n)},e.dialogs={},e.openAll=function(){t.each(e.dialogs,function(t,e){e.open()})},e.closeAll=function(){t.each(e.dialogs,function(t,e){e.close()})},e.moveFocus=function(){var n=null;t.each(e.dialogs,function(t,e){n=e}),null!==n&&n.isRealized()&&n.getModal().focus()},e.showScrollbar=function(){var n=null;if(t.each(e.dialogs,function(t,e){n=e}),null!==n&&n.isRealized()&&n.isOpened()){var o=n.getModal().data("bs.modal");o.checkScrollbar(),t("body").addClass("modal-open"),o.setScrollbar()}},e.prototype={constructor:e,initOptions:function(e){return this.options=t.extend(!0,this.defaultOptions,e),this},holdThisInstance:function(){return e.dialogs[this.getId()]=this,this},initModalStuff:function(){return this.setModal(this.createModal()).setModalDialog(this.createModalDialog()).setModalContent(this.createModalContent()).setModalHeader(this.createModalHeader()).setModalBody(this.createModalBody()).setModalFooter(this.createModalFooter()),this.getModal().append(this.getModalDialog()),this.getModalDialog().append(this.getModalContent()),this.getModalContent().append(this.getModalHeader()).append(this.getModalBody()).append(this.getModalFooter()),this},createModal:function(){var e=t('<div class="modal" tabindex="-1" role="dialog" aria-hidden="true"></div>');return e.prop("id",this.getId()).attr("aria-labelledby",this.getId()+"_title"),e},getModal:function(){return this.$modal},setModal:function(t){return this.$modal=t,this},createModalDialog:function(){return t('<div class="modal-dialog"></div>')},getModalDialog:function(){return this.$modalDialog},setModalDialog:function(t){return this.$modalDialog=t,this},createModalContent:function(){return t('<div class="modal-content"></div>')},getModalContent:function(){return this.$modalContent},setModalContent:function(t){return this.$modalContent=t,this},createModalHeader:function(){return t('<div class="modal-header"></div>')},getModalHeader:function(){return this.$modalHeader},setModalHeader:function(t){return this.$modalHeader=t,this},createModalBody:function(){return t('<div class="modal-body"></div>')},getModalBody:function(){return this.$modalBody},setModalBody:function(t){return this.$modalBody=t,this},createModalFooter:function(){return t('<div class="modal-footer"></div>')},getModalFooter:function(){return this.$modalFooter},setModalFooter:function(t){return this.$modalFooter=t,this},createDynamicContent:function(t){var e=null;return e="function"==typeof t?t.call(t,this):t,"string"==typeof e&&(e=this.formatStringContent(e)),e},formatStringContent:function(t){return this.options.nl2br?t.replace(/\r\n/g,"<br />").replace(/[\r\n]/g,"<br />"):t},setData:function(t,e){return this.options.data[t]=e,this},getData:function(t){return this.options.data[t]},setId:function(t){return this.options.id=t,this},getId:function(){return this.options.id},getType:function(){return this.options.type},setType:function(t){return this.options.type=t,this.updateType(),this},updateType:function(){if(this.isRealized()){var t=[e.TYPE_DEFAULT,e.TYPE_INFO,e.TYPE_PRIMARY,e.TYPE_SUCCESS,e.TYPE_WARNING,e.TYPE_DANGER];this.getModal().removeClass(t.join(" ")).addClass(this.getType())}return this},getSize:function(){return this.options.size},setSize:function(t){return this.options.size=t,this},getCssClass:function(){return this.options.cssClass},setCssClass:function(t){return this.options.cssClass=t,this},geLine truncated
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* @preserve
|
||||||
|
* Project: Bootstrap Hover Dropdown
|
||||||
|
* Author: Cameron Spear
|
||||||
|
* Version: v2.0.11
|
||||||
|
* Contributors: Mattia Larentis
|
||||||
|
* Dependencies: Bootstrap's Dropdown plugin, jQuery
|
||||||
|
* Description: A simple plugin to enable Bootstrap dropdowns to active on hover and provide a nice user experience.
|
||||||
|
* License: MIT
|
||||||
|
* Homepage: http://cameronspear.com/blog/bootstrap-dropdown-on-hover-plugin/
|
||||||
|
*/
|
||||||
|
;(function ($, window, undefined) {
|
||||||
|
// outside the scope of the jQuery plugin to
|
||||||
|
// keep track of all dropdowns
|
||||||
|
var $allDropdowns = $();
|
||||||
|
|
||||||
|
// if instantlyCloseOthers is true, then it will instantly
|
||||||
|
// shut other nav items when a new one is hovered over
|
||||||
|
$.fn.dropdownHover = function (options) {
|
||||||
|
// don't do anything if touch is supported
|
||||||
|
// (plugin causes some issues on mobile)
|
||||||
|
if('ontouchstart' in document) return this; // don't want to affect chaining
|
||||||
|
|
||||||
|
// the element we really care about
|
||||||
|
// is the dropdown-toggle's parent
|
||||||
|
$allDropdowns = $allDropdowns.add(this.parent());
|
||||||
|
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this),
|
||||||
|
$parent = $this.parent(),
|
||||||
|
defaults = {
|
||||||
|
delay: 500,
|
||||||
|
instantlyCloseOthers: true
|
||||||
|
},
|
||||||
|
data = {
|
||||||
|
delay: $(this).data('delay'),
|
||||||
|
instantlyCloseOthers: $(this).data('close-others')
|
||||||
|
},
|
||||||
|
showEvent = 'show.bs.dropdown',
|
||||||
|
hideEvent = 'hide.bs.dropdown',
|
||||||
|
// shownEvent = 'shown.bs.dropdown',
|
||||||
|
// hiddenEvent = 'hidden.bs.dropdown',
|
||||||
|
settings = $.extend(true, {}, defaults, options, data),
|
||||||
|
timeout;
|
||||||
|
|
||||||
|
$parent.hover(function (event) {
|
||||||
|
// so a neighbor can't open the dropdown
|
||||||
|
if(!$parent.hasClass('open') && !$this.is(event.target)) {
|
||||||
|
// stop this event, stop executing any code
|
||||||
|
// in this callback but continue to propagate
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
openDropdown(event);
|
||||||
|
}, function () {
|
||||||
|
timeout = window.setTimeout(function () {
|
||||||
|
$parent.removeClass('open');
|
||||||
|
$this.trigger(hideEvent);
|
||||||
|
}, settings.delay);
|
||||||
|
});
|
||||||
|
|
||||||
|
// this helps with button groups!
|
||||||
|
$this.hover(function (event) {
|
||||||
|
/*
|
||||||
|
// life
|
||||||
|
// this helps prevent a double event from firing.
|
||||||
|
// see https://github.com/CWSpear/bootstrap-hover-dropdown/issues/55
|
||||||
|
if(!$parent.hasClass('open') && !$parent.is(event.target)) {
|
||||||
|
// stop this event, stop executing any code
|
||||||
|
// in this callback but continue to propagate
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
openDropdown(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
// handle submenus
|
||||||
|
$parent.find('.dropdown-submenu').each(function (){
|
||||||
|
var $this = $(this);
|
||||||
|
var subTimeout;
|
||||||
|
$this.hover(function () {
|
||||||
|
window.clearTimeout(subTimeout);
|
||||||
|
$this.children('.dropdown-menu').show();
|
||||||
|
// always close submenu siblings instantly
|
||||||
|
$this.siblings().children('.dropdown-menu').hide();
|
||||||
|
}, function () {
|
||||||
|
var $submenu = $this.children('.dropdown-menu');
|
||||||
|
subTimeout = window.setTimeout(function () {
|
||||||
|
$submenu.hide();
|
||||||
|
}, settings.delay);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function openDropdown(event) {
|
||||||
|
$allDropdowns.find(':focus').blur();
|
||||||
|
|
||||||
|
if(settings.instantlyCloseOthers === true)
|
||||||
|
$allDropdowns.removeClass('open');
|
||||||
|
|
||||||
|
window.clearTimeout(timeout);
|
||||||
|
$parent.addClass('open');
|
||||||
|
$this.trigger(showEvent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
// apply dropdownHover to all elements with the data-hover="dropdown" attribute
|
||||||
|
$('[data-hover="dropdown"]').dropdownHover({delay: 100});
|
||||||
|
});
|
||||||
|
})(jQuery, this);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
function reIsOk(e){return e&&"object"==typeof e&&e.Ok}function showAlert(e,t,n,o){$(e).html(t).removeClass("alert-danger").removeClass("alert-success").removeClass("alert-warning").addClass("alert-"+n).show(),o&&$(o).focus()}function hideAlert(e,t){t?setTimeout(function(){$(e).hide()},t):$(e).hide()}function ajaxGet(e,t,n){$.get(e,t,n)}function ajaxPost(e,t,n){$.post(e,t,n)}function ajaxGetP(e,t,n){ajaxP("GET",e,t,n)}function ajaxPostP(e,t,n){ajaxP("POST",e,t,n)}function ajaxP(e,t,n,o){n=n||{},o=o||function(){},$.ajax({dataType:"jsonp",url:t,type:e,data:n,jsonp:"callback",jsonpCallback:"jsonpCallback",success:o})}function getShareUrl(){return location.href}function getShareTitle(e){return encodeURI(e+" (来自leanote.com)")}function shareSinaWeibo(e,t,n){var o="http://service.weibo.com/share/share.php?title="+getShareTitle(t)+"&url="+getShareUrl(e);window.open(o,"Share",windowParam)}function shareTencentWeibo(e,t,n){var o="801542571",i="http://share.v.t.qq.com/index.php?c=share&a=index&appkey="+o+"&title="+getShareTitle(t)+"&url="+getShareUrl(e)+"&pic="+n;window.open(i,"Share",windowParam)}function shareQQ(e,t,n){var o="http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url="+getShareUrl(e)+"&title="+t+"&pics="+n;window.open(o,"Share",windowParam)}function shareRenRen(e,t,n){var o="http://widget.renren.com/dialog/share?resourceUrl="+getShareUrl(e)+"&srcUrl="+getShareUrl(e)+"&title="+getShareTitle(t)+"&pic="+n;window.open(o,"Share",windowParam)}function shareTwitter(e,t,n){var o="https://twitter.com/intent/tweet?text="+getShareTitle(t)+"&pic="+n;window.open(o,"Share",windowParam)}function shareFacebook(e,t,n){var o=" http://www.facebook.com/sharer.php?t="+getShareTitle(t)+"&pic="+n;window.open(o,"Share",windowParam)}function goNowToDatetime(e){return e?e.substr(0,10)+" "+e.substr(11,8):""}function goNowToDate(e){if(!e)return"";var t=e.substr(0,10)+" "+e.substr(11,8),n=t.split(" "),o=n[0].split("-"),i=parseInt(o[0],10),a=parseInt(o[1],10)-1,r=parseInt(o[2],10),s=n[1].split(":"),l=parseInt(s[0],10),c=parseInt(s[1],10)-1,d=parseInt(s[2],10),f=new Date(i,a,r,l,c,d);return f}function getDateDiff(e){var t=(new Date).getTime(),n=t-e;if(0>n)return"";var o=n/diff.month,i=n/(7*diff.day),a=n/diff.day,r=n/diff.hour,s=n/diff.minute;return result=o>=1?parseInt(o)+"个月前":i>=1?parseInt(i)+"周前":a>=1?parseInt(a)+"天前":r>=1?parseInt(r)+"小时前":s>=1?parseInt(s)+"分钟前":"刚刚"}function weixin(){var e=window.location.href,t=$.trim($(".title").text()),n=$.trim($("#desc").text()),o=$("#content img").eq(0).attr("src");window.shareData={imgUrl:o,timeLineLink:e,sendFriendLink:e,weiboLink:e,tTitle:t,tContent:n,fTitle:t,fContent:n,wContent:n},document.addEventListener("WeixinJSBridgeReady",function i(){WeixinJSBridge.on("menu:share:appmessage",function(e){WeixinJSBridge.invoke("sendAppMessage",{img_url:window.shareData.imgUrl,img_width:"200",link:window.shareData.sendFriendLink,desc:window.shareData.fContent,title:window.shareData.fTitle},function(e){hs_guide("none"),_report("send_msg",e.err_msg)})}),WeixinJSBridge.on("menu:share:timeline",function(e){WeixinJSBridge.invoke("shareTimeline",{img_url:window.shareData.imgUrl,img_width:"200",link:window.shareData.timeLineLink,desc:window.shareData.tContent,title:window.shareData.tTitle},function(e){hs_guide("none"),_report("timeline",e.err_msg)})}),WeixinJSBridge.on("menu:share:weibo",function(e){WeixinJSBridge.invoke("shareWeibo",{content:window.shareData.wContent,url:window.shareData.weiboLink},function(e){hs_guide("none"),_report("weibo",e.err_msg)})})},!1)}function scrollTo(e,t,n){for(var o=$("#content"),i=o.find(t+":contains("+n+")"),a=$('#blogNavContent [data-a="'+t+"-"+encodeURI(n)+'"]'),r=a.size(),s=0;r>s&&a[s]!=e;++s);if(i.size()>=s+1){i=i.eq(s);var l=i.offset().top;LEA.isMobile&&(l-=50);var c=$(document).scrollTop();return void $("html,body").animate({scrollTop:l},200)}}function genNav(){for(var e=$("#content"),t=e.html(),n=[],o=e.find("h1,h2,h3,h4,h5,h6").toArray(),i="<ul>",a=0;a<o.length;++a){var r=$(o[a]).text(),s=o[a].tagName.toLowerCase();i+='<li class="nav-'+s+'"><a data-a="'+s+"-"+encodeURI(r)+'" onclick="scrollTo(this, \''+s+"', '"+r+"')\">"+r+"</a></li>"}return i+="</ul>",$("#blogNavContent").html(i),o.length?!0:($("#blogNavContent").html("无"),!1)}function initNav(){function e(){var e=r.scrollTop();i>=e?$("#blogNav").css("top",i-e):LEA.isMobile?$("#blogNav").css("top",50):$("#blogNav").css("top",10)}var t=genNav();if(t){var n=$(".title"),o=n.offset(),i=o.top+10;LEA.isMobile&&(i+=30),0>i&&(i=10);var a=n.width()+o.left-100;$("#blogNav").css("top",i).css("left",a),$("#blogNav").show(),$("#blogNavNav").click(function(){var e=$("#blogNavContent");e.is(":hidden")?e.show():e.hide()});var r=$(document);e(),$(window).scroll(e)}}function goLogin(){var e=siteUrl+"/login?from="+encodeURI(location.href);location.href=e}function goRegister(){var e=siteUrl+"/register?from="+encodeURI(location.href);location.href=e}function needLogin(){if("undefined"==typeLine truncated
|
||||||
@@ -0,0 +1,419 @@
|
|||||||
|
// 返回是否是re.Ok == true
|
||||||
|
function reIsOk(re) {
|
||||||
|
return re && typeof re == "object" && re.Ok;
|
||||||
|
}
|
||||||
|
function showAlert(id, msg, type, id2Focus) {
|
||||||
|
$(id).html(msg).removeClass("alert-danger").removeClass("alert-success").removeClass("alert-warning").addClass("alert-" + type).show();
|
||||||
|
if(id2Focus) {
|
||||||
|
$(id2Focus).focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function hideAlert(id, timeout) {
|
||||||
|
if(timeout) {
|
||||||
|
setTimeout(function() {
|
||||||
|
$(id).hide();
|
||||||
|
}, timeout);
|
||||||
|
} else {
|
||||||
|
$(id).hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function ajaxGet(url, param, func) {
|
||||||
|
$.get(url, param, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ajaxPost(url, param, func) {
|
||||||
|
$.post(url, param, func);
|
||||||
|
}
|
||||||
|
//------
|
||||||
|
// jsonp
|
||||||
|
function ajaxGetP(url, param, callback) {
|
||||||
|
ajaxP("GET", url, param, callback)
|
||||||
|
}
|
||||||
|
function ajaxPostP(url, param, callback) {
|
||||||
|
ajaxP("POST", url, param, callback)
|
||||||
|
}
|
||||||
|
function ajaxP(method, url, param, callback) {
|
||||||
|
param = param || {};
|
||||||
|
callback = callback || function() {};
|
||||||
|
$.ajax({
|
||||||
|
dataType: "jsonp",//跨域访问 dataType 必须是jsonp 类型。
|
||||||
|
url: url,
|
||||||
|
type: method,
|
||||||
|
data: param,
|
||||||
|
jsonp: "callback",
|
||||||
|
jsonpCallback: "jsonpCallback",
|
||||||
|
success: callback
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------
|
||||||
|
// 分享
|
||||||
|
var windowParam = 'width=700, height=580, top=180, left=320, toolbar=no, menubar=no, scrollbars=no, location=yes, resizable=no, status=no';
|
||||||
|
function getShareUrl() {
|
||||||
|
return location.href;
|
||||||
|
}
|
||||||
|
function getShareTitle(title) {
|
||||||
|
return encodeURI(title + " (来自leanote.com)");
|
||||||
|
}
|
||||||
|
function shareSinaWeibo(noteId, title, pic) {
|
||||||
|
var url = "http://service.weibo.com/share/share.php?title=" + getShareTitle(title) + "&url=" + getShareUrl(noteId);
|
||||||
|
window.open(url, 'Share', windowParam);
|
||||||
|
}
|
||||||
|
function shareTencentWeibo(noteId, title, pic) {
|
||||||
|
var _appkey = '801542571';
|
||||||
|
var url = "http://share.v.t.qq.com/index.php?c=share&a=index&appkey=" + _appkey +"&title=" + getShareTitle(title) + "&url=" + getShareUrl(noteId) +"&pic=" + pic;
|
||||||
|
window.open(url, 'Share', windowParam);
|
||||||
|
}
|
||||||
|
function shareQQ(noteId, title, pic) {
|
||||||
|
var url = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + getShareUrl(noteId) + '&title=' + title + '&pics=' + pic;
|
||||||
|
window.open(url, 'Share', windowParam);
|
||||||
|
}
|
||||||
|
function shareRenRen(noteId, title, pic) {
|
||||||
|
var url = 'http://widget.renren.com/dialog/share?resourceUrl=' + getShareUrl(noteId) + '&srcUrl=' + getShareUrl(noteId) + '&title=' + getShareTitle(title) + '&pic=' + pic;
|
||||||
|
window.open(url, 'Share', windowParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://twitter.com/intent/tweet?text=&pic=
|
||||||
|
function shareTwitter(noteId, title, pic) {
|
||||||
|
var url = 'https://twitter.com/intent/tweet?text=' + getShareTitle(title) + '&pic=' + pic;
|
||||||
|
window.open(url, 'Share', windowParam);
|
||||||
|
}
|
||||||
|
// http://www.facebook.com/sharer.php?u=<?php the_permalink();?>&t=<?php the_title(); ?>”
|
||||||
|
function shareFacebook(noteId, title, pic) {
|
||||||
|
var url = ' http://www.facebook.com/sharer.php?t=' + getShareTitle(title) + '&pic=' + pic;
|
||||||
|
window.open(url, 'Share', windowParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// go的datetime转成datetime字符串
|
||||||
|
// 2014-01-06T18:29:48.802+08:00 => 2012-12-12 12:12:12 字符串
|
||||||
|
function goNowToDatetime(goNow) {
|
||||||
|
if(!goNow) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return goNow.substr(0, 10) + " " + goNow.substr(11, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转成Date()
|
||||||
|
// 2014-01-06T18:29:48.802+08:00 => new Date(year, month, day, hour, minute, second)
|
||||||
|
function goNowToDate(goNow) {
|
||||||
|
if(!goNow) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
var str = goNow.substr(0, 10) + " " + goNow.substr(11, 8);
|
||||||
|
// 2012-12-12 12:12:12
|
||||||
|
var tempStrs = str.split(" ");
|
||||||
|
var dateStrs = tempStrs[0].split("-");
|
||||||
|
var year = parseInt(dateStrs[0], 10);
|
||||||
|
var month = parseInt(dateStrs[1], 10) - 1;
|
||||||
|
var day = parseInt(dateStrs[2], 10);
|
||||||
|
var timeStrs = tempStrs[1].split(":");
|
||||||
|
var hour = parseInt(timeStrs [0], 10);
|
||||||
|
var minute = parseInt(timeStrs[1], 10) - 1;
|
||||||
|
var second = parseInt(timeStrs[2], 10);
|
||||||
|
var date = new Date(year, month, day, hour, minute, second);
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 距离现在有多久, 评论时间间隔
|
||||||
|
var diff = {
|
||||||
|
minute : 1000 * 60,
|
||||||
|
hour : 1000 * 60 * 60,
|
||||||
|
day : 1000 * 60 * 60 * 24,
|
||||||
|
halfamonth : 1000 * 60 * 60 * 24 * 15,
|
||||||
|
month : 1000 * 60 * 60 * 24 * 30
|
||||||
|
}
|
||||||
|
function getDateDiff(dateTimeStamp) {
|
||||||
|
var now = new Date().getTime();
|
||||||
|
var diffValue = now - dateTimeStamp;
|
||||||
|
if (diffValue < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
var monthC = diffValue / diff.month;
|
||||||
|
var weekC = diffValue / (7 * diff.day);
|
||||||
|
var dayC = diffValue / diff.day;
|
||||||
|
var hourC = diffValue / diff.hour;
|
||||||
|
var minC = diffValue / diff.minute;
|
||||||
|
if (monthC >= 1) {
|
||||||
|
result = parseInt(monthC) + "个月前";
|
||||||
|
} else if (weekC >= 1) {
|
||||||
|
result = parseInt(weekC) + "周前";
|
||||||
|
} else if (dayC >= 1) {
|
||||||
|
result = parseInt(dayC) + "天前";
|
||||||
|
} else if (hourC >= 1) {
|
||||||
|
result = parseInt(hourC) + "小时前";
|
||||||
|
} else if (minC >= 1) {
|
||||||
|
result = parseInt(minC) + "分钟前";
|
||||||
|
} else {
|
||||||
|
result = "刚刚";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function weixin() {
|
||||||
|
var local=window.location.href;
|
||||||
|
var title = $.trim($(".title").text());
|
||||||
|
var desc = $.trim($("#desc").text());
|
||||||
|
var imgUrl = $("#content img").eq(0).attr('src');
|
||||||
|
window.shareData = {
|
||||||
|
"imgUrl": imgUrl,
|
||||||
|
"timeLineLink":local,
|
||||||
|
"sendFriendLink": local,
|
||||||
|
"weiboLink":local,
|
||||||
|
"tTitle": title,
|
||||||
|
"tContent": desc,
|
||||||
|
"fTitle": title,
|
||||||
|
"fContent": desc,
|
||||||
|
"wContent": desc
|
||||||
|
};
|
||||||
|
document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
|
||||||
|
// 发送给好友
|
||||||
|
WeixinJSBridge.on('menu:share:appmessage', function (argv) {
|
||||||
|
WeixinJSBridge.invoke('sendAppMessage', {
|
||||||
|
"img_url": window.shareData.imgUrl,
|
||||||
|
"img_width": "200",
|
||||||
|
"link": window.shareData.sendFriendLink,
|
||||||
|
"desc": window.shareData.fContent,
|
||||||
|
"title": window.shareData.fTitle
|
||||||
|
}, function (res) {
|
||||||
|
hs_guide('none');
|
||||||
|
_report('send_msg', res.err_msg);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// 分享到朋友圈
|
||||||
|
WeixinJSBridge.on('menu:share:timeline', function (argv) {
|
||||||
|
WeixinJSBridge.invoke('shareTimeline', {
|
||||||
|
"img_url": window.shareData.imgUrl,
|
||||||
|
"img_width": "200",
|
||||||
|
"link": window.shareData.timeLineLink,
|
||||||
|
"desc": window.shareData.tContent,
|
||||||
|
"title": window.shareData.tTitle
|
||||||
|
}, function (res) {
|
||||||
|
hs_guide('none');
|
||||||
|
_report('timeline', res.err_msg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 分享到微博
|
||||||
|
WeixinJSBridge.on('menu:share:weibo', function (argv) {
|
||||||
|
WeixinJSBridge.invoke('shareWeibo', {
|
||||||
|
"content": window.shareData.wContent,
|
||||||
|
"url": window.shareData.weiboLink,
|
||||||
|
}, function (res) {
|
||||||
|
hs_guide('none');
|
||||||
|
_report('weibo', res.err_msg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function scrollTo(self, tagName, text) {
|
||||||
|
var iframe = $("#content");
|
||||||
|
var target = iframe.find(tagName + ":contains(" + text + ")");
|
||||||
|
|
||||||
|
// 找到是第几个
|
||||||
|
// 在nav是第几个
|
||||||
|
var navs = $('#blogNavContent [data-a="' + tagName + '-' + encodeURI(text) + '"]');
|
||||||
|
var len = navs.size();
|
||||||
|
for(var i = 0; i < len; ++i) {
|
||||||
|
if(navs[i] == self) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.size() >= i+1) {
|
||||||
|
target = target.eq(i);
|
||||||
|
// 之前插入, 防止多行定位不准
|
||||||
|
var top = target.offset().top;
|
||||||
|
if(LEA.isMobile) {
|
||||||
|
top -= 50;
|
||||||
|
}
|
||||||
|
var nowTop = $(document).scrollTop();
|
||||||
|
// 用$("body").scrllTop(10)没反应 firefox下
|
||||||
|
$('html,body').animate({scrollTop: top}, 200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function genNav() {
|
||||||
|
var $con = $("#content");
|
||||||
|
var html = $con.html();
|
||||||
|
// 构造一棵树
|
||||||
|
// {"h1-title":{h2-title:{}}}
|
||||||
|
var tree = [];//[{title: "xx", children:[{}]}, {title:"xx2"}];
|
||||||
|
var hs = $con.find("h1,h2,h3,h4,h5,h6").toArray();
|
||||||
|
var titles = '<ul>';
|
||||||
|
for(var i = 0; i < hs.length; ++i) {
|
||||||
|
var text = $(hs[i]).text();
|
||||||
|
var tagName = hs[i].tagName.toLowerCase();
|
||||||
|
// scrollTo在page.js中定义
|
||||||
|
titles += '<li class="nav-' + tagName + '"><a data-a="' + tagName + '-' + encodeURI(text)+'" onclick="scrollTo(this, \'' + tagName + '\', \'' + text + '\')">' + text + '</a></li>';
|
||||||
|
}
|
||||||
|
titles += "</ul>";
|
||||||
|
$("#blogNavContent").html(titles);
|
||||||
|
if(!hs.length) {
|
||||||
|
$("#blogNavContent").html("无");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initNav() {
|
||||||
|
var hasNav = genNav();
|
||||||
|
if(!hasNav) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $title = $(".title");
|
||||||
|
var titlePos = $title.offset();
|
||||||
|
var top = titlePos.top + 10;// - $title.height();
|
||||||
|
// 手机下不要与标题在同一高度
|
||||||
|
if(LEA.isMobile){
|
||||||
|
top += 30;
|
||||||
|
}
|
||||||
|
if(top < 0) {
|
||||||
|
top = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
var left = $title.width() + titlePos.left - 100;
|
||||||
|
$("#blogNav").css("top", top).css("left", left);
|
||||||
|
$("#blogNav").show();
|
||||||
|
|
||||||
|
$("#blogNavNav").click(function() {
|
||||||
|
var $o = $("#blogNavContent");
|
||||||
|
if($o.is(":hidden")) {
|
||||||
|
$o.show();
|
||||||
|
} else {
|
||||||
|
$o.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var $d = $(document);
|
||||||
|
function reNav() {
|
||||||
|
var vtop = $d.scrollTop();
|
||||||
|
if(vtop <= top) {
|
||||||
|
$("#blogNav").css("top", top-vtop);
|
||||||
|
} else {
|
||||||
|
// 差距很磊了
|
||||||
|
if(LEA.isMobile) {
|
||||||
|
$("#blogNav").css("top", 50);
|
||||||
|
} else {
|
||||||
|
$("#blogNav").css("top", 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reNav();
|
||||||
|
$(window).scroll(reNav);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
// 分享与评论
|
||||||
|
|
||||||
|
// 得到登录的链接
|
||||||
|
function goLogin(){
|
||||||
|
var loginUrl = siteUrl + '/login?from=' + encodeURI(location.href);
|
||||||
|
location.href = loginUrl;
|
||||||
|
}
|
||||||
|
// 得到注册链接
|
||||||
|
function goRegister() {
|
||||||
|
var registerUrl = siteUrl + '/register?from=' + encodeURI(location.href);
|
||||||
|
location.href = registerUrl;
|
||||||
|
}
|
||||||
|
// 是否需要登录, 评论时用到
|
||||||
|
function needLogin() {
|
||||||
|
if(typeof visitUserInfo == "undefined" || !visitUserInfo || !visitUserInfo.UserId) {
|
||||||
|
// 弹框之
|
||||||
|
var loginUrl = siteUrl + '/login?from=' + encodeURI(location.href);
|
||||||
|
var registerUrl = siteUrl + '/register?from=' + encodeURI(location.href);
|
||||||
|
try {
|
||||||
|
var modal = BootstrapDialog.show({
|
||||||
|
title: "你还未登录",
|
||||||
|
message: '<div class="needLogin" style="border:none"><a href="' + loginUrl + '">立即登录</a>, 发表评论.<br />没有帐号? <a href="' + registerUrl +'">立即注册</a>',
|
||||||
|
nl2br: false
|
||||||
|
});
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定位评论
|
||||||
|
function scrollToTarget(t, fixed) {
|
||||||
|
if(!fixed) {
|
||||||
|
fixed = 0;
|
||||||
|
}
|
||||||
|
var $t = $(t)
|
||||||
|
var targetOffset = $t.offset().top + fixed;
|
||||||
|
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到访问者信息, 因为自定义域名的原因, 需要用jsonp来获取
|
||||||
|
function getCurVisitUserInfo() {
|
||||||
|
|
||||||
|
}
|
||||||
|
// 增加阅读次数
|
||||||
|
function incReadNum(noteId) {
|
||||||
|
if(!$.cookie(noteId)) {
|
||||||
|
$.cookie(noteId, 1);
|
||||||
|
ajaxGet(getCurHostUrl() + "/blog/incReadNum", {noteId: noteId});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getCurHostUrl() {
|
||||||
|
return "//" + location.host;
|
||||||
|
}
|
||||||
|
function getLeanoteUrl() {
|
||||||
|
return siteUrl || "http://leanote.com";
|
||||||
|
}
|
||||||
|
// 得到博客统计信息
|
||||||
|
function getPostStat(noteId, callback) {
|
||||||
|
ajaxGet(getCurHostUrl() + "/blog/getPostStat", {noteId: noteId}, callback);
|
||||||
|
}
|
||||||
|
// 得到赞
|
||||||
|
function getLikes(noteId, callback) {
|
||||||
|
ajaxGetP(getLeanoteUrl() + "/blog/getLikes", {noteId: noteId}, callback);
|
||||||
|
}
|
||||||
|
// 得到赞和评论
|
||||||
|
function getLikesAndComments(noteId, callback) {
|
||||||
|
ajaxGetP(getLeanoteUrl() + "/blog/getLikesAndComments", {noteId: noteId}, callback);
|
||||||
|
}
|
||||||
|
// 得到评论
|
||||||
|
function getComments(noteId, page) {
|
||||||
|
ajaxGetP(getLeanoteUrl() + "/blog/listComments", {noteId: noteId, page: page}, callback);
|
||||||
|
}
|
||||||
|
// 点赞
|
||||||
|
function likePost(noteId, callback) {
|
||||||
|
ajaxPostP(getLeanoteUrl() + "/blog/likePost", {noteId: noteId}, callback)
|
||||||
|
}
|
||||||
|
// 提交评论
|
||||||
|
function commentPost(noteId, commentId, content, callback) {
|
||||||
|
var data = {noteId: self.noteId, toCommentId: commentId, content: content};
|
||||||
|
ajaxPostP(getLeanoteUrl() + "/blog/commentPost", data, callback);
|
||||||
|
}
|
||||||
|
// 删除评论
|
||||||
|
function deleteComment(noteId, commentId, callback) {
|
||||||
|
ajaxPostP(getLeanoteUrl() + "/blog/deleteComment", {noteId: noteId, commentId: commentId}, callback);
|
||||||
|
}
|
||||||
|
// 点赞评论
|
||||||
|
function likeComment(commentId, callback) {
|
||||||
|
ajaxPostP(getLeanoteUrl() + "/blog/likeComment", {commentId: commentId}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分享与评论结束
|
||||||
|
//------------
|
||||||
|
|
||||||
|
//------------
|
||||||
|
// 手机端
|
||||||
|
var LEA = {isMobile: false};
|
||||||
|
function isMobile() {
|
||||||
|
var u = navigator.userAgent;
|
||||||
|
LEA.isMobile = false;
|
||||||
|
LEA.isMobile = /Mobile|Android|iPhone/i.test(u);
|
||||||
|
if(!LEA.isMobile && $(document).width() <= 600){
|
||||||
|
LEA.isMobile = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$(function() {
|
||||||
|
isMobile();
|
||||||
|
});
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
(function(factory){factory(jQuery)})(function($){var pluses=/\+/g;function encode(s){return config.raw?s:encodeURIComponent(s)}function decode(s){return config.raw?s:decodeURIComponent(s)}function stringifyCookieValue(value){return encode(config.json?JSON.stringify(value):String(value))}function parseCookieValue(s){if(s.indexOf('"')===0){s=s.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\")}try{s=decodeURIComponent(s.replace(pluses," "));return config.json?JSON.parse(s):s}catch(e){}}function read(s,converter){var value=config.raw?s:parseCookieValue(s);return $.isFunction(converter)?converter(value):value}var config=$.cookie=function(key,value,options){if(value!==undefined&&!$.isFunction(value)){options=$.extend({},config.defaults,options);if(typeof options.expires==="number"){var days=options.expires,t=options.expires=new Date;t.setTime(+t+days*864e5)}return document.cookie=[encode(key),"=",stringifyCookieValue(value),options.expires?"; expires="+options.expires.toUTCString():"",options.path?"; path="+options.path:"",options.domain?"; domain="+options.domain:"",options.secure?"; secure":""].join("")}var result=key?undefined:{};var cookies=document.cookie?document.cookie.split("; "):[];for(var i=0,l=cookies.length;i<l;i++){var parts=cookies[i].split("=");var name=decode(parts.shift());var cookie=parts.join("=");if(key&&key===name){result=read(cookie,value);break}if(!key&&(cookie=read(cookie))!==undefined){result[name]=cookie}}return result};config.defaults={};$.removeCookie=function(key,options){if($.cookie(key)===undefined){return false}$.cookie(key,"",$.extend({},options,{expires:-1}));return!$.cookie(key)}});
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
(function(r){r.fn.qrcode=function(h){var s;function u(a){this.mode=s;this.data=a}function o(a,c){this.typeNumber=a;this.errorCorrectLevel=c;this.modules=null;this.moduleCount=0;this.dataCache=null;this.dataList=[]}function q(a,c){if(void 0==a.length)throw Error(a.length+"/"+c);for(var d=0;d<a.length&&0==a[d];)d++;this.num=Array(a.length-d+c);for(var b=0;b<a.length-d;b++)this.num[b]=a[b+d]}function p(a,c){this.totalCount=a;this.dataCount=c}function t(){this.buffer=[];this.length=0}u.prototype={getLength:function(){return this.data.length},
|
||||||
|
write:function(a){for(var c=0;c<this.data.length;c++)a.put(this.data.charCodeAt(c),8)}};o.prototype={addData:function(a){this.dataList.push(new u(a));this.dataCache=null},isDark:function(a,c){if(0>a||this.moduleCount<=a||0>c||this.moduleCount<=c)throw Error(a+","+c);return this.modules[a][c]},getModuleCount:function(){return this.moduleCount},make:function(){if(1>this.typeNumber){for(var a=1,a=1;40>a;a++){for(var c=p.getRSBlocks(a,this.errorCorrectLevel),d=new t,b=0,e=0;e<c.length;e++)b+=c[e].dataCount;
|
||||||
|
for(e=0;e<this.dataList.length;e++)c=this.dataList[e],d.put(c.mode,4),d.put(c.getLength(),j.getLengthInBits(c.mode,a)),c.write(d);if(d.getLengthInBits()<=8*b)break}this.typeNumber=a}this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17;this.modules=Array(this.moduleCount);for(var d=0;d<this.moduleCount;d++){this.modules[d]=Array(this.moduleCount);for(var b=0;b<this.moduleCount;b++)this.modules[d][b]=null}this.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-
|
||||||
|
7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(a,c);7<=this.typeNumber&&this.setupTypeNumber(a);null==this.dataCache&&(this.dataCache=o.createData(this.typeNumber,this.errorCorrectLevel,this.dataList));this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,c){for(var d=-1;7>=d;d++)if(!(-1>=a+d||this.moduleCount<=a+d))for(var b=-1;7>=b;b++)-1>=c+b||this.moduleCount<=c+b||(this.modules[a+d][c+b]=
|
||||||
|
0<=d&&6>=d&&(0==b||6==b)||0<=b&&6>=b&&(0==d||6==d)||2<=d&&4>=d&&2<=b&&4>=b?!0:!1)},getBestMaskPattern:function(){for(var a=0,c=0,d=0;8>d;d++){this.makeImpl(!0,d);var b=j.getLostPoint(this);if(0==d||a>b)a=b,c=d}return c},createMovieClip:function(a,c,d){a=a.createEmptyMovieClip(c,d);this.make();for(c=0;c<this.modules.length;c++)for(var d=1*c,b=0;b<this.modules[c].length;b++){var e=1*b;this.modules[c][b]&&(a.beginFill(0,100),a.moveTo(e,d),a.lineTo(e+1,d),a.lineTo(e+1,d+1),a.lineTo(e,d+1),a.endFill())}return a},
|
||||||
|
setupTimingPattern:function(){for(var a=8;a<this.moduleCount-8;a++)null==this.modules[a][6]&&(this.modules[a][6]=0==a%2);for(a=8;a<this.moduleCount-8;a++)null==this.modules[6][a]&&(this.modules[6][a]=0==a%2)},setupPositionAdjustPattern:function(){for(var a=j.getPatternPosition(this.typeNumber),c=0;c<a.length;c++)for(var d=0;d<a.length;d++){var b=a[c],e=a[d];if(null==this.modules[b][e])for(var f=-2;2>=f;f++)for(var i=-2;2>=i;i++)this.modules[b+f][e+i]=-2==f||2==f||-2==i||2==i||0==f&&0==i?!0:!1}},setupTypeNumber:function(a){for(var c=
|
||||||
|
j.getBCHTypeNumber(this.typeNumber),d=0;18>d;d++){var b=!a&&1==(c>>d&1);this.modules[Math.floor(d/3)][d%3+this.moduleCount-8-3]=b}for(d=0;18>d;d++)b=!a&&1==(c>>d&1),this.modules[d%3+this.moduleCount-8-3][Math.floor(d/3)]=b},setupTypeInfo:function(a,c){for(var d=j.getBCHTypeInfo(this.errorCorrectLevel<<3|c),b=0;15>b;b++){var e=!a&&1==(d>>b&1);6>b?this.modules[b][8]=e:8>b?this.modules[b+1][8]=e:this.modules[this.moduleCount-15+b][8]=e}for(b=0;15>b;b++)e=!a&&1==(d>>b&1),8>b?this.modules[8][this.moduleCount-
|
||||||
|
b-1]=e:9>b?this.modules[8][15-b-1+1]=e:this.modules[8][15-b-1]=e;this.modules[this.moduleCount-8][8]=!a},mapData:function(a,c){for(var d=-1,b=this.moduleCount-1,e=7,f=0,i=this.moduleCount-1;0<i;i-=2)for(6==i&&i--;;){for(var g=0;2>g;g++)if(null==this.modules[b][i-g]){var n=!1;f<a.length&&(n=1==(a[f]>>>e&1));j.getMask(c,b,i-g)&&(n=!n);this.modules[b][i-g]=n;e--; -1==e&&(f++,e=7)}b+=d;if(0>b||this.moduleCount<=b){b-=d;d=-d;break}}}};o.PAD0=236;o.PAD1=17;o.createData=function(a,c,d){for(var c=p.getRSBlocks(a,
|
||||||
|
c),b=new t,e=0;e<d.length;e++){var f=d[e];b.put(f.mode,4);b.put(f.getLength(),j.getLengthInBits(f.mode,a));f.write(b)}for(e=a=0;e<c.length;e++)a+=c[e].dataCount;if(b.getLengthInBits()>8*a)throw Error("code length overflow. ("+b.getLengthInBits()+">"+8*a+")");for(b.getLengthInBits()+4<=8*a&&b.put(0,4);0!=b.getLengthInBits()%8;)b.putBit(!1);for(;!(b.getLengthInBits()>=8*a);){b.put(o.PAD0,8);if(b.getLengthInBits()>=8*a)break;b.put(o.PAD1,8)}return o.createBytes(b,c)};o.createBytes=function(a,c){for(var d=
|
||||||
|
0,b=0,e=0,f=Array(c.length),i=Array(c.length),g=0;g<c.length;g++){var n=c[g].dataCount,h=c[g].totalCount-n,b=Math.max(b,n),e=Math.max(e,h);f[g]=Array(n);for(var k=0;k<f[g].length;k++)f[g][k]=255&a.buffer[k+d];d+=n;k=j.getErrorCorrectPolynomial(h);n=(new q(f[g],k.getLength()-1)).mod(k);i[g]=Array(k.getLength()-1);for(k=0;k<i[g].length;k++)h=k+n.getLength()-i[g].length,i[g][k]=0<=h?n.get(h):0}for(k=g=0;k<c.length;k++)g+=c[k].totalCount;d=Array(g);for(k=n=0;k<b;k++)for(g=0;g<c.length;g++)k<f[g].length&&
|
||||||
|
(d[n++]=f[g][k]);for(k=0;k<e;k++)for(g=0;g<c.length;g++)k<i[g].length&&(d[n++]=i[g][k]);return d};s=4;for(var j={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,
|
||||||
|
78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(a){for(var c=a<<10;0<=j.getBCHDigit(c)-j.getBCHDigit(j.G15);)c^=j.G15<<j.getBCHDigit(c)-j.getBCHDigit(j.G15);return(a<<10|c)^j.G15_MASK},getBCHTypeNumber:function(a){for(var c=a<<12;0<=j.getBCHDigit(c)-
|
||||||
|
j.getBCHDigit(j.G18);)c^=j.G18<<j.getBCHDigit(c)-j.getBCHDigit(j.G18);return a<<12|c},getBCHDigit:function(a){for(var c=0;0!=a;)c++,a>>>=1;return c},getPatternPosition:function(a){return j.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,c,d){switch(a){case 0:return 0==(c+d)%2;case 1:return 0==c%2;case 2:return 0==d%3;case 3:return 0==(c+d)%3;case 4:return 0==(Math.floor(c/2)+Math.floor(d/3))%2;case 5:return 0==c*d%2+c*d%3;case 6:return 0==(c*d%2+c*d%3)%2;case 7:return 0==(c*d%3+(c+d)%2)%2;default:throw Error("bad maskPattern:"+
|
||||||
|
a);}},getErrorCorrectPolynomial:function(a){for(var c=new q([1],0),d=0;d<a;d++)c=c.multiply(new q([1,l.gexp(d)],0));return c},getLengthInBits:function(a,c){if(1<=c&&10>c)switch(a){case 1:return 10;case 2:return 9;case s:return 8;case 8:return 8;default:throw Error("mode:"+a);}else if(27>c)switch(a){case 1:return 12;case 2:return 11;case s:return 16;case 8:return 10;default:throw Error("mode:"+a);}else if(41>c)switch(a){case 1:return 14;case 2:return 13;case s:return 16;case 8:return 12;default:throw Error("mode:"+
|
||||||
|
a);}else throw Error("type:"+c);},getLostPoint:function(a){for(var c=a.getModuleCount(),d=0,b=0;b<c;b++)for(var e=0;e<c;e++){for(var f=0,i=a.isDark(b,e),g=-1;1>=g;g++)if(!(0>b+g||c<=b+g))for(var h=-1;1>=h;h++)0>e+h||c<=e+h||0==g&&0==h||i==a.isDark(b+g,e+h)&&f++;5<f&&(d+=3+f-5)}for(b=0;b<c-1;b++)for(e=0;e<c-1;e++)if(f=0,a.isDark(b,e)&&f++,a.isDark(b+1,e)&&f++,a.isDark(b,e+1)&&f++,a.isDark(b+1,e+1)&&f++,0==f||4==f)d+=3;for(b=0;b<c;b++)for(e=0;e<c-6;e++)a.isDark(b,e)&&!a.isDark(b,e+1)&&a.isDark(b,e+
|
||||||
|
2)&&a.isDark(b,e+3)&&a.isDark(b,e+4)&&!a.isDark(b,e+5)&&a.isDark(b,e+6)&&(d+=40);for(e=0;e<c;e++)for(b=0;b<c-6;b++)a.isDark(b,e)&&!a.isDark(b+1,e)&&a.isDark(b+2,e)&&a.isDark(b+3,e)&&a.isDark(b+4,e)&&!a.isDark(b+5,e)&&a.isDark(b+6,e)&&(d+=40);for(e=f=0;e<c;e++)for(b=0;b<c;b++)a.isDark(b,e)&&f++;a=Math.abs(100*f/c/c-50)/5;return d+10*a}},l={glog:function(a){if(1>a)throw Error("glog("+a+")");return l.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;256<=a;)a-=255;return l.EXP_TABLE[a]},EXP_TABLE:Array(256),
|
||||||
|
LOG_TABLE:Array(256)},m=0;8>m;m++)l.EXP_TABLE[m]=1<<m;for(m=8;256>m;m++)l.EXP_TABLE[m]=l.EXP_TABLE[m-4]^l.EXP_TABLE[m-5]^l.EXP_TABLE[m-6]^l.EXP_TABLE[m-8];for(m=0;255>m;m++)l.LOG_TABLE[l.EXP_TABLE[m]]=m;q.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var c=Array(this.getLength()+a.getLength()-1),d=0;d<this.getLength();d++)for(var b=0;b<a.getLength();b++)c[d+b]^=l.gexp(l.glog(this.get(d))+l.glog(a.get(b)));return new q(c,0)},mod:function(a){if(0>
|
||||||
|
this.getLength()-a.getLength())return this;for(var c=l.glog(this.get(0))-l.glog(a.get(0)),d=Array(this.getLength()),b=0;b<this.getLength();b++)d[b]=this.get(b);for(b=0;b<a.getLength();b++)d[b]^=l.gexp(l.glog(a.get(b))+c);return(new q(d,0)).mod(a)}};p.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],
|
||||||
|
[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,
|
||||||
|
116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,
|
||||||
|
43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,
|
||||||
|
3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,
|
||||||
|
55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,
|
||||||
|
45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];p.getRSBlocks=function(a,c){var d=p.getRsBlockTable(a,c);if(void 0==d)throw Error("bad rs block @ typeNumber:"+a+"/errorCorrectLevel:"+c);for(var b=d.length/3,e=[],f=0;f<b;f++)for(var h=d[3*f+0],g=d[3*f+1],j=d[3*f+2],l=0;l<h;l++)e.push(new p(g,j));return e};p.getRsBlockTable=function(a,c){switch(c){case 1:return p.RS_BLOCK_TABLE[4*(a-1)+0];case 0:return p.RS_BLOCK_TABLE[4*(a-1)+1];case 3:return p.RS_BLOCK_TABLE[4*
|
||||||
|
(a-1)+2];case 2:return p.RS_BLOCK_TABLE[4*(a-1)+3]}};t.prototype={get:function(a){return 1==(this.buffer[Math.floor(a/8)]>>>7-a%8&1)},put:function(a,c){for(var d=0;d<c;d++)this.putBit(1==(a>>>c-d-1&1))},getLengthInBits:function(){return this.length},putBit:function(a){var c=Math.floor(this.length/8);this.buffer.length<=c&&this.buffer.push(0);a&&(this.buffer[c]|=128>>>this.length%8);this.length++}};"string"===typeof h&&(h={text:h});h=r.extend({},{render:"canvas",width:256,height:256,typeNumber:-1,
|
||||||
|
correctLevel:2,background:"#ffffff",foreground:"#000000"},h);return this.each(function(){var a;if("canvas"==h.render){a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();var c=document.createElement("canvas");c.width=h.width;c.height=h.height;for(var d=c.getContext("2d"),b=h.width/a.getModuleCount(),e=h.height/a.getModuleCount(),f=0;f<a.getModuleCount();f++)for(var i=0;i<a.getModuleCount();i++){d.fillStyle=a.isDark(f,i)?h.foreground:h.background;var g=Math.ceil((i+1)*b)-Math.floor(i*b),
|
||||||
|
j=Math.ceil((f+1)*b)-Math.floor(f*b);d.fillRect(Math.round(i*b),Math.round(f*e),g,j)}}else{a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();c=r("<table></table>").css("width",h.width+"px").css("height",h.height+"px").css("border","0px").css("border-collapse","collapse").css("background-color",h.background);d=h.width/a.getModuleCount();b=h.height/a.getModuleCount();for(e=0;e<a.getModuleCount();e++){f=r("<tr></tr>").css("height",b+"px").appendTo(c);for(i=0;i<a.getModuleCount();i++)r("<td></td>").css("width",
|
||||||
|
d+"px").css("background-color",a.isDark(e,i)?h.foreground:h.background).appendTo(f)}}a=c;jQuery(a).appendTo(this)})}})(jQuery);
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
// leanote blog share & comment
|
||||||
|
var C = {
|
||||||
|
info: null,
|
||||||
|
noteId: noteId,
|
||||||
|
preLikeNum: preLikeNum,
|
||||||
|
commentNum: commentNum,
|
||||||
|
likeBtnO: $("#likeBtn"),
|
||||||
|
likeNumO: $("#likeNum"),
|
||||||
|
tLikersO: $("#tLikers"),
|
||||||
|
likersO: $("#likers"),
|
||||||
|
tCommentsO: $("#tComments"),
|
||||||
|
commentsO: $("#comments"),
|
||||||
|
|
||||||
|
commentBtnO: $("#commentBtn"),
|
||||||
|
|
||||||
|
commentsLoadingO: $(".comments-loading"),
|
||||||
|
commentsMoreO: $(".comments-more"),
|
||||||
|
|
||||||
|
commentBoxO: $(".comment-box"),
|
||||||
|
init: function() {
|
||||||
|
var self = this;
|
||||||
|
if(blogInfo.OpenComment && blogInfo.CommentType != "disqus") {
|
||||||
|
self.initLikesAndComments();
|
||||||
|
} else {
|
||||||
|
self.initLikes();
|
||||||
|
}
|
||||||
|
self.initEvent();
|
||||||
|
self.incReadNum();
|
||||||
|
|
||||||
|
//
|
||||||
|
},
|
||||||
|
|
||||||
|
// 博客的统计信息
|
||||||
|
getPostStat: function() {
|
||||||
|
|
||||||
|
},
|
||||||
|
// 增加阅读量
|
||||||
|
incReadNum: function() {
|
||||||
|
incReadNum(self.noteId);
|
||||||
|
},
|
||||||
|
initLikes: function() {
|
||||||
|
var self = this;
|
||||||
|
getLikes(self.noteId, function(ret) {
|
||||||
|
if(reIsOk(ret)) {
|
||||||
|
ret = ret.Item;
|
||||||
|
self.info = ret;
|
||||||
|
self.toggleLikeBtnActive();
|
||||||
|
self.renderLikers();
|
||||||
|
self.visitUserInfo = self.info.visitUserInfo || {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initLikesAndComments: function() {
|
||||||
|
var self = this;
|
||||||
|
getLikesAndComments(self.noteId, function(ret) {
|
||||||
|
if(reIsOk(ret)) {
|
||||||
|
ret = ret.Item;
|
||||||
|
self.info = ret;
|
||||||
|
self.toggleLikeBtnActive();
|
||||||
|
self.renderLikers();
|
||||||
|
// 是否需要renderComments?
|
||||||
|
self.info.commentUserInfo = self.info.commentUserInfo || {};
|
||||||
|
self.visitUserInfo = self.info.visitUserInfo || {};
|
||||||
|
// 为了防止第一条评论找不到用户信息情况
|
||||||
|
if(self.visitUserInfo.UserId) {
|
||||||
|
self.info.commentUserInfo[self.visitUserInfo.UserId] = self.visitUserInfo;
|
||||||
|
}
|
||||||
|
self.renderComments();
|
||||||
|
|
||||||
|
// 之前是隐藏的, 取消之
|
||||||
|
self.commentBoxO.removeClass("hide");
|
||||||
|
self.commentsLoadingO.addClass("hide");
|
||||||
|
if(self.info.pageInfo.TotalPage > self.info.pageInfo.CurPage) {
|
||||||
|
self.commentsMoreO.removeClass("hide");
|
||||||
|
self.initMoreComments();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否已经登录?
|
||||||
|
if(self.visitUserInfo.UserId) {
|
||||||
|
$("#commentForm").removeClass("hide");
|
||||||
|
$("#visitUserLogo").attr("src", self.visitUserInfo.Logo);
|
||||||
|
} else {
|
||||||
|
$("#noLoginContainer").removeClass("hide");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initMoreComments: function() {
|
||||||
|
var self = this;
|
||||||
|
self.commentsMoreO.find("a").click(function(){
|
||||||
|
if(self.info.pageInfo.TotalPage > self.info.pageInfo.CurPage) {
|
||||||
|
self.commentsMoreO.addClass("hide");
|
||||||
|
self.commentsLoadingO.removeClass("hide");
|
||||||
|
getComments(self.noteId, self.info.pageInfo.CurPage+1, function(ret) {
|
||||||
|
var pageInfo = ret.pageInfo;
|
||||||
|
var comments = ret.comments;
|
||||||
|
var commentUserInfo = ret.commentUserInfo;
|
||||||
|
|
||||||
|
$.extend(self.info.commentUserInfo, commentUserInfo);
|
||||||
|
|
||||||
|
// 渲染之
|
||||||
|
for(var i in comments) {
|
||||||
|
var comment = comments[i];
|
||||||
|
comment = self.parseComment(comment);
|
||||||
|
}
|
||||||
|
var html = self.tCommentsO.render({comments: comments, visitUserInfo: self.visitUserInfo});
|
||||||
|
self.commentsO.append(html);
|
||||||
|
|
||||||
|
self.info.pageInfo = pageInfo;
|
||||||
|
|
||||||
|
if(self.info.pageInfo.TotalPage > self.info.pageInfo.CurPage) {
|
||||||
|
self.commentsMoreO.removeClass("hide");
|
||||||
|
} else {
|
||||||
|
self.commentsMoreO.addClass("hide");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.commentsLoadingO.addClass("hide");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addCommentRender: function(comment){
|
||||||
|
var self = this;
|
||||||
|
comment = self.parseComment(comment);
|
||||||
|
var html = self.tCommentsO.render({comments: [comment], visitUserInfo: self.visitUserInfo});
|
||||||
|
self.commentsO.prepend(html);
|
||||||
|
var li = self.commentsO.find("li").eq(0);
|
||||||
|
li.hide();
|
||||||
|
li.show(500);
|
||||||
|
li.addClass("item-highlight");
|
||||||
|
setTimeout(function() {
|
||||||
|
li.removeClass("item-highlight");
|
||||||
|
}, 2000);
|
||||||
|
},
|
||||||
|
parseComment: function(comment) {
|
||||||
|
var self = this;
|
||||||
|
var authorUserId = blogInfo.UserId;
|
||||||
|
commentUserInfo = self.info.commentUserInfo;
|
||||||
|
comment.UserInfo = commentUserInfo[comment.UserId];
|
||||||
|
// 是作者自己
|
||||||
|
if(self.visitUserInfo.UserId == authorUserId) {
|
||||||
|
comment.IsMyNote = true;
|
||||||
|
}
|
||||||
|
if(comment.UserId == authorUserId) {
|
||||||
|
comment.IsAuthorComment = true;
|
||||||
|
}
|
||||||
|
if(comment.UserId == self.visitUserInfo.UserId) {
|
||||||
|
comment.IsMyComment = true;
|
||||||
|
}
|
||||||
|
// 不是回复自己
|
||||||
|
if(comment.ToUserId && comment.ToUserId != comment.UserId) {
|
||||||
|
comment.ToUserInfo = commentUserInfo[comment.ToUserId];
|
||||||
|
if(comment.ToUserInfo.UserId == authorUserId) {
|
||||||
|
comment.ToUserIsAuthor = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comment.PublishDate = getDateDiff(goNowToDate(comment.CreatedTime));
|
||||||
|
return comment;
|
||||||
|
},
|
||||||
|
// 渲染评论
|
||||||
|
renderComments: function() {
|
||||||
|
var self = this;
|
||||||
|
var comments = self.info.comments || [];
|
||||||
|
if(comments.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 整理数据
|
||||||
|
// 回复谁, 是否是作者?
|
||||||
|
// 回复日期, 几天前, 刚刚
|
||||||
|
for(var i in comments) {
|
||||||
|
var comment = comments[i];
|
||||||
|
comment = self.parseComment(comment);
|
||||||
|
}
|
||||||
|
var html = self.tCommentsO.render({comments: comments, visitUserInfo: self.visitUserInfo});
|
||||||
|
self.commentsO.html(html);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 重新渲染likers
|
||||||
|
reRenderLikers: function(addMe) {
|
||||||
|
var self = this;
|
||||||
|
var likedUsers = self.info.likedUsers || [];
|
||||||
|
for(var i = 0; i < likedUsers.length; ++i) {
|
||||||
|
var user = likedUsers[i];
|
||||||
|
if(user.UserId == self.visitUserInfo.UserId) {
|
||||||
|
likedUsers.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(addMe) {
|
||||||
|
likedUsers = [self.visitUserInfo].concat(likedUsers);
|
||||||
|
self.info.likedUsers = likedUsers;
|
||||||
|
}
|
||||||
|
self.renderLikers();
|
||||||
|
},
|
||||||
|
renderLikers: function() {
|
||||||
|
var self = this;
|
||||||
|
var users = self.info.likedUsers || [];
|
||||||
|
var html = self.tLikersO.render({users: users});
|
||||||
|
self.likersO.html(html);
|
||||||
|
},
|
||||||
|
toggleLikeBtnActive: function() {
|
||||||
|
var self = this;
|
||||||
|
if(self.info.isILikeIt) {
|
||||||
|
self.likeBtnO.addClass("active");
|
||||||
|
} else {
|
||||||
|
self.likeBtnO.removeClass("active");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
commentNumO: $("#commentNum"),
|
||||||
|
bindCommentNum: function(fix) {
|
||||||
|
var self = this;
|
||||||
|
self.commentNum += fix;
|
||||||
|
self.commentNumO.text(self.commentNum);
|
||||||
|
},
|
||||||
|
initEvent: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// like or not
|
||||||
|
self.likeBtnO.click(function() {
|
||||||
|
if(!self.visitUserInfo.UserId) {
|
||||||
|
needLogin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
likePost(noteId, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
// like
|
||||||
|
if(ret.Item) {
|
||||||
|
var num = self.preLikeNum+1;
|
||||||
|
} else {
|
||||||
|
var num = self.preLikeNum-1;
|
||||||
|
}
|
||||||
|
self.preLikeNum = num >= 0 ? num : 0;
|
||||||
|
self.likeNumO.text(self.preLikeNum);
|
||||||
|
self.info.isILikeIt = ret.Item;
|
||||||
|
self.toggleLikeBtnActive();
|
||||||
|
|
||||||
|
// 重新render likers
|
||||||
|
// 我是否在列表中
|
||||||
|
self.reRenderLikers(ret.Item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示回复回复
|
||||||
|
$("#comments").on("click", ".comment-reply", function() {
|
||||||
|
var form = $(this).closest("li").find("form");
|
||||||
|
if(form.is(":hidden")) {
|
||||||
|
form.show();
|
||||||
|
form.find("textarea").focus();
|
||||||
|
} else {
|
||||||
|
form.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#comments").on("click", ".reply-cancel", function() {
|
||||||
|
$(this).closest("form").hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 回复
|
||||||
|
$(".comment-box").on("click", ".reply-comment-btn", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var commentId = $(this).data("comment-id");
|
||||||
|
var $form = $(this).closest("form");
|
||||||
|
var $content = $form.find("textarea");
|
||||||
|
var content = $.trim($content.val());
|
||||||
|
if(!content) {
|
||||||
|
$content.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var t = $(this);
|
||||||
|
t.button("loading");
|
||||||
|
var data = {noteId: self.noteId, toCommentId: commentId, content: content};
|
||||||
|
commentPost(self.noteId, commentId, content, function(ret) {
|
||||||
|
t.button("reset");
|
||||||
|
$content.val("");
|
||||||
|
self.bindCommentNum(1);
|
||||||
|
if(commentId) {
|
||||||
|
$form.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(commentId) {
|
||||||
|
scrollToTarget("#comments", -200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加一个
|
||||||
|
self.addCommentRender(ret.Item);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
$(".comment-box").on("click", ".comment-trash", function(e) {
|
||||||
|
var commentId = $(this).parent().data("comment-id");
|
||||||
|
var t = this;
|
||||||
|
try {
|
||||||
|
BootstrapDialog.confirm("确定删除该评论?", function(yes) {
|
||||||
|
if(yes) {
|
||||||
|
deleteComment(noteId, commentId, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
var li = $(t).closest("li");
|
||||||
|
li.hide(500); // remove();
|
||||||
|
setTimeout(function() {
|
||||||
|
li.remove();
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
self.bindCommentNum(-1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch(e) {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 点zan
|
||||||
|
$(".comment-box").on("click", ".comment-like", function(e) {
|
||||||
|
var commentId = $(this).parent().data("comment-id");
|
||||||
|
var t = this;
|
||||||
|
|
||||||
|
likeComment(commentId, function(re) {
|
||||||
|
if(re.Ok) {
|
||||||
|
var ret = re.Item;
|
||||||
|
if(ret.Num <= 0) {
|
||||||
|
$(t).parent().find(".like-num").addClass("hide");
|
||||||
|
} else {
|
||||||
|
$(t).parent().find(".like-num").removeClass("hide");
|
||||||
|
$(t).parent().find(".like-num-i").text(ret.Num)
|
||||||
|
}
|
||||||
|
if(ret.IsILikeIt) {
|
||||||
|
$(t).find(".like-text").text("取消赞");
|
||||||
|
} else {
|
||||||
|
$(t).find(".like-text").text("赞");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$(".comment-box").on("click", ".comment-report", function() {
|
||||||
|
if(needLogin()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var commentId = $(this).parent().data("comment-id");
|
||||||
|
report(commentId, self.noteId, "举报评论?");
|
||||||
|
});
|
||||||
|
self.initShare();
|
||||||
|
},
|
||||||
|
weixinQRCodeO: $("#weixinQRCode"),
|
||||||
|
initShare: function() {
|
||||||
|
var self = this;
|
||||||
|
$(".btn-weixin").click(function() {
|
||||||
|
if(!self.weixinQRCodeO.html()) {
|
||||||
|
self.weixinQRCodeO.qrcode(location.href);
|
||||||
|
}
|
||||||
|
BootstrapDialog.show({
|
||||||
|
title: "打开微信扫一扫二维码",
|
||||||
|
message: self.weixinQRCodeO
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".btn-share").click(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var map = {"btn-weibo": shareSinaWeibo, "tencent-weibo": shareTencentWeibo, "qq": shareQQ, "renren": shareRenRen};
|
||||||
|
for(var i in map) {
|
||||||
|
if($this.hasClass(i)) {
|
||||||
|
map[i](self.noteId, document.title);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
C.init();
|
||||||
|
});
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
这里面是leanote默认主题
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="keywords" content="leanote,leanote.com">
|
||||||
|
<title>404</title>
|
||||||
|
|
||||||
|
<link href="/css/bootstrap.css" rel="stylesheet">
|
||||||
|
<link href="/css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet">
|
||||||
|
<link href="/css/index.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body id="boxBody">
|
||||||
|
<section id="box">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<h1 class="h text-white animated fadeInDownBig">life-404</h1>
|
||||||
|
</div>
|
||||||
|
<div id="errorBox">
|
||||||
|
<p class="error-info">
|
||||||
|
This page cann't found.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="list-group m-b-sm bg-white m-b-lg">
|
||||||
|
<a href="javascript:history.go(-1);" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-arrow-left icon-muted"></i> Back </a>
|
||||||
|
<a href="/index" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-home icon-muted"></i> Goto homepage </a>
|
||||||
|
<a href="/note" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-file-o icon-muted"></i> My note</a>
|
||||||
|
<a class="list-group-item" href="mailto:leanote@leanote.com">
|
||||||
|
<span class="badge">leanote@leanote.com</span>
|
||||||
|
<i class="fa fa-fw fa-envelope-o icon-muted"></i> Contact Us </a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<div id="boxFooter">
|
||||||
|
<p>
|
||||||
|
<a href="/index">leanote</a> © 2014
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
<div class="container">
|
||||||
|
<h2>归档 {{if $.curCateTitle}} - {{$.curCateTitle}}{{end}}</h2>
|
||||||
|
</div>
|
||||||
|
<div id="posts">
|
||||||
|
|
||||||
|
<div class="each-post">
|
||||||
|
<ul>
|
||||||
|
{{range $.archives}}
|
||||||
|
<li><span class="archive-year">{{.Year}}</span>
|
||||||
|
<ul>
|
||||||
|
{{range .Posts}}
|
||||||
|
<li>
|
||||||
|
{{dateFormat .PublicTime "2006-01-02"}} <a href="{{$.postUrl}}/{{.NoteId}}">{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "footer.html" .}}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
<div class="container">
|
||||||
|
<h2>分类 - {{$.curCateTitle}}</h2>
|
||||||
|
</div>
|
||||||
|
<div id="posts">
|
||||||
|
{{range $.posts}}
|
||||||
|
<div class="each-post">
|
||||||
|
<div class="title">
|
||||||
|
<a href="{{$.postUrl}}/{{.NoteId}}" title="全文">
|
||||||
|
{{.Title}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="created-time">
|
||||||
|
<i class="fa fa-bookmark-o"></i>
|
||||||
|
{{if .Tags}}
|
||||||
|
{{blogTags $ .Tags}}
|
||||||
|
{{else}}
|
||||||
|
无
|
||||||
|
{{end}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 更新 {{.UpdatedTime | datetime}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 创建 {{.CreatedTime | datetime}}
|
||||||
|
</div>
|
||||||
|
<div class="desc">
|
||||||
|
{{.Abstract | raw}}
|
||||||
|
</div>
|
||||||
|
<a class="more" href="{{$.postUrl}}/{{.NoteId}}" title="全文">查看</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<!-- 分页 -->
|
||||||
|
{{template "paging.html" $}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "footer.html" $}}
|
||||||
|
{{template "highlight.html" $}}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<div id="footerContainer">
|
||||||
|
{{$userId := $.blogInfo.UserId}}
|
||||||
|
<div class="container" id="footer">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h3>导航</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{{$.indexUrl}}">主页</a></li>
|
||||||
|
{{range $.cates}}
|
||||||
|
<li>
|
||||||
|
<a href="{{$.cateUrl}}/{{.CateId}}">{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h3>最近发表</h3>
|
||||||
|
<ul>
|
||||||
|
{{range .recentPosts}}
|
||||||
|
<li title="{{.Title}}"><a href="{{$.postUrl}}/{{.NoteId}}/">{{.Title}}</a></li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h3>友情链接 </h3>
|
||||||
|
<ul>
|
||||||
|
{{if $.themeInfo.FriendLinks}}
|
||||||
|
{{range $.themeInfo.FriendLinks}}
|
||||||
|
<li><a href="{{.Url}}" target="_blank">{{.Title}}</a></li>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="{{$.jQueryUrl}}"></script>
|
||||||
|
<script src="{{$.bootstrapJsUrl}}"></script>
|
||||||
|
<script src="{{$.siteUrl}}/js/bootstrap-hover-dropdown.js"></script>
|
||||||
|
<script>
|
||||||
|
// 搜索
|
||||||
|
function search(e) {
|
||||||
|
var keywords = $("#searchInput").val();
|
||||||
|
if(!keywords) {
|
||||||
|
location.href = "{{$.searchUrl}}";
|
||||||
|
} else {
|
||||||
|
var tpl = '<form action="{{$.searchUrl}}" method="get">';
|
||||||
|
tpl += '<input name="keywords" value="' + keywords + '" />';
|
||||||
|
tpl += "</form";
|
||||||
|
$(tpl).submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="keywords" content="leanote,leanote.com">
|
||||||
|
<meta name="description" content="leanote, not only a notebook">
|
||||||
|
<meta name="author" content="leanote">
|
||||||
|
|
||||||
|
<title>
|
||||||
|
{{if $.curIsIndex}}
|
||||||
|
{{$.blogInfo.Title}}
|
||||||
|
{{else if $.curIsCate}}
|
||||||
|
分类-{{$.curCateTitle}}
|
||||||
|
{{else if $.curIsView}}
|
||||||
|
{{$.post.Title}}
|
||||||
|
{{else if $.curIsSearch}}
|
||||||
|
搜索-{{$.keywords}}
|
||||||
|
{{else if $.curIsTags}}
|
||||||
|
我的标签
|
||||||
|
{{else if $.curIsTagPosts}}
|
||||||
|
标签-{{$.curTag}}
|
||||||
|
{{else}}
|
||||||
|
我的博客
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</title>
|
||||||
|
<!-- Bootstrap core CSS -->
|
||||||
|
<link href="{{$.bootstrapCssUrl}}" rel="stylesheet">
|
||||||
|
<!-- 字体必须同一域 -->
|
||||||
|
<link href="{{$.fontAwesomeUrl}}" rel="stylesheet">
|
||||||
|
<link href="{{$.themeBaseUrl}}/style.css" rel="stylesheet">
|
||||||
|
<script>
|
||||||
|
function log(o) {
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="headerAndNav" >
|
||||||
|
<div id="headerContainer" class="container">
|
||||||
|
<!-- 头部可放博客名, 导航 -->
|
||||||
|
<div id="header">
|
||||||
|
|
||||||
|
{{$username := .userInfo.Username}}
|
||||||
|
<h1>
|
||||||
|
<a href="{{$.indexUrl}}" id="logo">
|
||||||
|
{{if $.blogInfo.Logo}}
|
||||||
|
<img src="{{$.blogInfo.Logo}}" title="{{$.blogInfo.Title}}"/>
|
||||||
|
{{else}}
|
||||||
|
{{$.blogInfo.Title | raw}}
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
<div id="blogDesc">
|
||||||
|
{{$.blogInfo.SubTitle | raw}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Static navbar -->
|
||||||
|
<div class="navbar navbar-default">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a class="navbar-brand" href="{{.indexUrl}}">
|
||||||
|
{{if $.blogInfo.Logo}}
|
||||||
|
|
||||||
|
<img src="{{$.blogInfo.Logo}}" title="{{$.blogInfo.Title}}"/>
|
||||||
|
{{else}}
|
||||||
|
{{$.blogInfo.Title | raw}}
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-collapse collapse">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
|
||||||
|
<li class="{{if $.curIsIndex}}active{{end}}"><a href="{{.indexUrl}}">主页</a></li>
|
||||||
|
<!-- 分类页 -->
|
||||||
|
{{range $.cates}}
|
||||||
|
<li class="{{if eq .CateId $.curCateId}}active{{end}}">
|
||||||
|
<a href="{{$.cateUrl}}/{{.CateId}}"
|
||||||
|
>{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
<!-- 单页 -->
|
||||||
|
{{range $.singles}}
|
||||||
|
<li class="{{if eq $.curSingleId .SingleId}}active{{end}}">
|
||||||
|
<a href="{{$.singleUrl}}/{{.SingleId}}">{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!-- 归档 -->
|
||||||
|
<li class="{{if $.curIsArchive}}active{{end}}">
|
||||||
|
<a href="{{$.archiveUrl}}">归档</a>
|
||||||
|
</li>
|
||||||
|
<li class="{{if $.curIsTags}}active{{end}}">
|
||||||
|
<a href="{{$.tagsUrl}}">标签</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<form class="navbar-form navbar-right" id="search" onsubmit="search(event);return false;">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon" id="searchIcon" onclick="search(event);"><i class="fa fa-search"></i></span>
|
||||||
|
<input type="text" placeholder="search" id="searchInput" class="form-control" value="{{.keywords}}">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div><!--/.nav-collapse -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<link href="{{$.prettifyCssUrl}}" type="text/css" rel="stylesheet"/>
|
||||||
|
<script src="{{$.prettifyJsUrl}}"></script>
|
||||||
|
<script>
|
||||||
|
$("pre").addClass("prettyprint linenums");
|
||||||
|
prettyPrint();
|
||||||
|
</script>
|
||||||
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 629 B |
@@ -0,0 +1,39 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
|
||||||
|
<div id="posts">
|
||||||
|
{{range $.posts}}
|
||||||
|
<div class="each-post">
|
||||||
|
<div class="title">
|
||||||
|
<a href="{{$.postUrl}}/{{.NoteId}}" title="全文">
|
||||||
|
{{.Title}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="created-time">
|
||||||
|
<i class="fa fa-bookmark-o"></i>
|
||||||
|
{{if .Tags}}
|
||||||
|
{{blogTags $ .Tags}}
|
||||||
|
{{else}}
|
||||||
|
无
|
||||||
|
{{end}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 更新 {{.UpdatedTime | datetime}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 创建 {{.CreatedTime | datetime}}
|
||||||
|
</div>
|
||||||
|
<div class="desc">
|
||||||
|
{{.Abstract | raw}}
|
||||||
|
</div>
|
||||||
|
<a class="more" href="{{$.postUrl}}/{{.NoteId}}" title="全文">查看</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<!-- 分页 -->
|
||||||
|
{{template "paging.html" $}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "footer.html" $}}
|
||||||
|
{{template "highlight.html" $}}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
aaaaaaaaaaaaaaaaaaa
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{{if gt $.paging.TotalPage 1}}
|
||||||
|
|
||||||
|
<!-- 上一页 -->
|
||||||
|
{{if gt $.paging.CurPage 1}}
|
||||||
|
{{set . "prePageClass" ""}}
|
||||||
|
{{set . "prePageUrl" (urlConcat $.pagingBaseUrl "page" (incr $.paging.CurPage -1)) }}
|
||||||
|
{{else}}
|
||||||
|
{{set . "prePageClass" "disabled"}}
|
||||||
|
{{set . "prePageUrl" "#"}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!-- 下一页 -->
|
||||||
|
{{if lt $.paging.CurPage $.paging.TotalPage }}
|
||||||
|
{{set . "nextPageClass" ""}}
|
||||||
|
{{set . "nextPageUrl" (urlConcat $.pagingBaseUrl "page" (incr $.paging.CurPage 1)) }}
|
||||||
|
{{else}}
|
||||||
|
{{set . "nextPageClass" "disabled"}}
|
||||||
|
{{set . "nextPageUrl" "#"}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{$.paging.CurPage}}/{{$.paging.TotalPage}}
|
||||||
|
<ul class="pager">
|
||||||
|
<li class="{{$.prePageClass}}"><a href="{{$.prePageUrl}}">上一页</a></li>
|
||||||
|
<li class="{{$.nextPageClass}}"><a href="{{$.nextPageUrl}}">下一页</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{end}}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
<div id="posts">
|
||||||
|
<div class="each-post">
|
||||||
|
<div class="title">
|
||||||
|
{{.post.Title}}
|
||||||
|
</div>
|
||||||
|
<div class="created-time">
|
||||||
|
<i class="fa fa-bookmark-o"></i>
|
||||||
|
{{if .post.Tags}}
|
||||||
|
{{blogTags $ .post.Tags}}
|
||||||
|
{{else}}
|
||||||
|
无
|
||||||
|
{{end}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 更新 {{$.post.UpdatedTime | datetime}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 创建 {{$.post.CreatedTime | datetime}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 仅为移动端 -->
|
||||||
|
<div class="mobile-created-time">
|
||||||
|
{{ if $.blogInfo.UserLogo}}
|
||||||
|
<img src="{{$.blogInfo.UserLogo}}" id="userLogo">
|
||||||
|
{{else}}
|
||||||
|
<img src="{{$.siteUrl}}/images/blog/default_avatar.png" id="userLogo">
|
||||||
|
{{end}}
|
||||||
|
{{$.blogInfo.Username}}
|
||||||
|
|
||||||
|
{{if .post.Tags}}
|
||||||
|
|
||||||
|
<i class="fa fa-bookmark-o" style="color: #666"></i>
|
||||||
|
{{blogTags $ $.post.Tags}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="desc" id="content">
|
||||||
|
{{if $.post.IsMarkdown }}
|
||||||
|
<div id="markdownContent" style="display: none">
|
||||||
|
<!-- 用textarea装html, 防止得到的值失真 -->
|
||||||
|
<textarea>{{$.post.Content | raw}}</textarea>
|
||||||
|
</div>
|
||||||
|
<div style="padding: 20px; text-align: center">
|
||||||
|
<img src="{{$.themeBaseUrl}}/images/loading-32.gif" />
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{$.post.Content | raw}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pre-next-post">
|
||||||
|
<p>
|
||||||
|
上一篇: {{if $.prePost}}<a href="{{$.postUrl}}/{{$.prePost.NoteId}}">{{$.prePost.Title}}</a>{{else}}无{{end}}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
下一篇: {{if $.nextPost}}<a href="{{$.postUrl}}/{{$.nextPost.NoteId}}">{{$.nextPost.Title}}</a>{{else}}无{{end}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- share & comment -->
|
||||||
|
{{template "share_comment.html" $}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "footer.html" $}}
|
||||||
|
{{template "highlight.html" $}}
|
||||||
|
|
||||||
|
<div id="blogNav">
|
||||||
|
<div id="blogNavNav">
|
||||||
|
<i class="fa fa-align-justify" title="文档导航"></i>
|
||||||
|
<span>文档导航</span>
|
||||||
|
</div>
|
||||||
|
<div id="blogNavContent">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 一些在share_comment.js 需要使用的变量 -->
|
||||||
|
<script>
|
||||||
|
var siteUrl = "{{$.siteUrl}}"; // common.js需要
|
||||||
|
// 以下 share_comment.js需要
|
||||||
|
var blogInfo={UserId: "{{$.blogInfo.UserId}}", OpenComment: {{$.blogInfo.OpenComment}}, CommentType: "{{$.blogInfo.CommentType}}"};
|
||||||
|
var noteId = "{{$.post.NoteId}}"; //
|
||||||
|
var preLikeNum = +"{{$.post.LikeNum}}";
|
||||||
|
var commentNum = +"{{$.post.CommentNum}}";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- 共享与评论css -->
|
||||||
|
<link href="{{$.shareCommentCssUrl}}" rel="stylesheet">
|
||||||
|
<!-- 一些公用的js -->
|
||||||
|
<script src="{{$.blogCommonJsUrl}}"></script>
|
||||||
|
<script src="{{$.siteUrl}}/public/blog/js/jsrender.js"></script>
|
||||||
|
<script src="{{$.siteUrl}}/public/blog/js/jquery-cookie-min.js"></script>
|
||||||
|
<script src="{{$.siteUrl}}/public/blog/js/bootstrap-dialog.min.js"></script>
|
||||||
|
<script src="{{$.siteUrl}}/public/blog/js/jquery.qrcode.min.js"></script>
|
||||||
|
<!-- share && comment -->
|
||||||
|
<script src="{{$.shareCommentJsUrl}}"></script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
markdown
|
||||||
|
调用markdown来解析得到html
|
||||||
|
-->
|
||||||
|
|
||||||
|
{{if $.post.IsMarkdown }}
|
||||||
|
<script src="/public/mdeditor/editor/pagedown/Markdown.Converter.js"></script>
|
||||||
|
<script src="/public/mdeditor/editor/pagedown/Markdown.Sanitizer.js"></script>
|
||||||
|
<script src="/public/mdeditor/editor/pagedown/Markdown.Editor.js"></script>
|
||||||
|
<script src="/public/mdeditor/editor/pagedown/local/Markdown.local.zh.js"></script>
|
||||||
|
<script src="/public/mdeditor/editor/Markdown.Extra.js"></script>
|
||||||
|
|
||||||
|
<!--mathjax-->
|
||||||
|
<script type="text/x-mathjax-config">
|
||||||
|
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]], processEscapes: true }, messageStyle: "none"});
|
||||||
|
</script>
|
||||||
|
<script src="/public/mdeditor/editor/mathJax.js"></script>
|
||||||
|
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||||
|
<script>
|
||||||
|
var content = $.trim($("#markdownContent textarea").val());
|
||||||
|
var converter = Markdown.getSanitizingConverter();
|
||||||
|
Markdown.Extra.init(converter, {extensions: ["tables", "fenced_code_gfm", "def_list"]});
|
||||||
|
var html = converter.makeHtml(content);
|
||||||
|
$("#content").html(html);
|
||||||
|
$("pre").addClass("prettyprint linenums");
|
||||||
|
prettyPrint();
|
||||||
|
MathJax.Hub.Queue(["Typeset",MathJax.Hub,"wmd-preview"]);
|
||||||
|
|
||||||
|
initNav();
|
||||||
|
weixin();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- 不是markdown -->
|
||||||
|
{{else}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
initNav();
|
||||||
|
weixin();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
<div class="container">
|
||||||
|
<h2>搜索 - {{.keywords}} </h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="posts">
|
||||||
|
{{range .posts}}
|
||||||
|
<div class="each-post">
|
||||||
|
<div class="title">
|
||||||
|
<a href="{{$.postUrl}}/{{.NoteId}}" title="全文">
|
||||||
|
{{.Title}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="created-time">
|
||||||
|
<i class="fa fa-bookmark-o"></i>
|
||||||
|
{{if .Tags}}
|
||||||
|
{{blogTags $ .Tags}}
|
||||||
|
{{else}}
|
||||||
|
无
|
||||||
|
{{end}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 更新 {{.UpdatedTime | datetime}} |
|
||||||
|
<i class="fa fa-calendar"></i> 创建 {{.CreatedTime | datetime}}
|
||||||
|
</div>
|
||||||
|
<div class="desc">
|
||||||
|
{{.Abstract | raw}}
|
||||||
|
</div>
|
||||||
|
<a class="more" href="{{$.postUrl}}/{{.NoteId}}" title="全文">查看</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
<div class="each-post">
|
||||||
|
无
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
{{template "paging.html" $}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "footer.html" $}}
|
||||||
|
{{template "highlight.html" $}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
<!-- 赞 -->
|
||||||
|
<div class="entry-controls clearfix">
|
||||||
|
<div class="vote-section-wrapper clearfix">
|
||||||
|
<button class="btn btn-default btn-zan" id="likeBtn"><i class="fa fa-thumbs-o-up"></i> <span id="likeNum">{{$.post.LikeNum}}</span> 赞</button>
|
||||||
|
<span class="control-item read-counts"><i class="fa fa-eye"></i> {{if $.post.ReadNum}}{{$.post.ReadNum}}{{else}}1{{end}} 人读过</span>
|
||||||
|
</div>
|
||||||
|
<div class="right-section">
|
||||||
|
<div id="weixinQRCode"></div>
|
||||||
|
<button class="btn btn-share btn-default btn-weibo"><i class="fa fa-weibo"></i> 新浪微博</button>
|
||||||
|
<button class="btn btn-share btn-default btn-weixin"><i class="fa fa-wechat"></i> 微信</button>
|
||||||
|
<div class="dropdown" style="display: inline-block; cursor: pointer; padding: 5px 10px;">
|
||||||
|
<!-- open -->
|
||||||
|
<div class="dropdown-toggle" data-hover="dropdown" data-toggle="dropdown">
|
||||||
|
<i class="fa fa-share-square-o"></i>
|
||||||
|
更多分享
|
||||||
|
</div>
|
||||||
|
<ul class="dropdown-menu" role="menu">
|
||||||
|
<li><a href="#" class="btn-share tencent-weibo"><i class="fa fa-tencent-weibo"></i> 腾讯微博</a></li>
|
||||||
|
<li><a href="#" class="btn-share qq"><i class="fa fa-qq"></i> QQ空间</a></li>
|
||||||
|
<li><a href="#" class="btn-share renren"><i class="fa fa-renren"></i> 人人网</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="voters clearfix" id="likers">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/x-jsrender" id="tLikers">
|
||||||
|
[[for users]]
|
||||||
|
<a id="liker_[[:UserId]]" title="[[:BlogTitle]]" href="[[:BlogUrl]]" target="_blank" class="voter">
|
||||||
|
[[if Logo]]
|
||||||
|
<img alt="avatar" class="avatar-small" src="[[:Logo]]">
|
||||||
|
[[else]]
|
||||||
|
<img alt="avatar" class="avatar-small" src="/images/blog/default_avatar.png">
|
||||||
|
[[/if]]
|
||||||
|
</a>
|
||||||
|
[[/for]]
|
||||||
|
</script>
|
||||||
|
{{if and $.blogInfo.OpenComment (not (eq $.blogInfo.CommentType "disqus"))}}
|
||||||
|
|
||||||
|
<script type="text/x-jsrender" id="tComments">
|
||||||
|
[[for comments]]
|
||||||
|
<li class="comment-item">
|
||||||
|
<!-- 头像 -->
|
||||||
|
<a ui-hovercard="" target="_blank" class="avatar-link" title="[[:UserInfo.Username]]" href="[[:UserInfo.BlogUrl]]">
|
||||||
|
<img class="avatar" src="[[:UserInfo.Logo]]">
|
||||||
|
</a>
|
||||||
|
<!-- 评论 -->
|
||||||
|
<div class="comment-body">
|
||||||
|
<div class="comment-hd">
|
||||||
|
<a href="[[:UserInfo.BlogUrl]]" target="_blank" >[[:UserInfo.Username]]</a>
|
||||||
|
[[if IsAuthorComment]]
|
||||||
|
<span>(作者)</span>
|
||||||
|
[[/if]]
|
||||||
|
|
||||||
|
<!-- 回复其它人 -->
|
||||||
|
[[if ToUserInfo]]
|
||||||
|
<span class="in-reply-to">
|
||||||
|
回复
|
||||||
|
<a href="[[:ToUserInfo.BlogUrl]]">[[:ToUserInfo.Username]]</a>
|
||||||
|
</span>
|
||||||
|
[[if ToUserIsAuthor]]
|
||||||
|
<span>(作者)</span>
|
||||||
|
[[/if]]
|
||||||
|
[[/if]]
|
||||||
|
</div>
|
||||||
|
<div class="comment-content ng-binding" ng-bind-html="comment.content">
|
||||||
|
[[html:Content]]
|
||||||
|
</div>
|
||||||
|
<div class="comment-ft clearfix" data-comment-id="[[:CommentId]]" >
|
||||||
|
<span title="" ui-time="" class="date">[[:PublishDate]] </span>
|
||||||
|
<span class="like-num [[if !LikeNum]]hide[[/if]]" title="[[:LikeNum]] 赞"><span class="like-num-i">[[:LikeNum]]</span> 赞</span></span>
|
||||||
|
|
||||||
|
[[if ~root.visitUserInfo.UserId]]
|
||||||
|
[[if IsMyNote && !IsMyComment]]
|
||||||
|
<a href="javascript:;" class="comment-trash op-link "><i class="fa fa-trash"></i> 删除</a>
|
||||||
|
[[/if]]
|
||||||
|
[[if !IsMyComment]]
|
||||||
|
<a href="javascript:;" class="comment-reply op-link ">
|
||||||
|
<i class="fa fa-reply"></i>
|
||||||
|
回复
|
||||||
|
</a>
|
||||||
|
<a href="javascript:;" class="comment-like op-link"><i class="fa fa-thumbs-o-up"></i> <span class="like-text">[[if IsILikeIt]]取消赞[[else]]赞[[/if]]</span></a>
|
||||||
|
[[else]]
|
||||||
|
<a href="javascript:;" class="comment-trash op-link "><i class="fa fa-trash"></i> 删除</a>
|
||||||
|
[[/if]]
|
||||||
|
[[/if]]
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 回复该评论 -->
|
||||||
|
[[if ~root.visitUserInfo.UserId]]
|
||||||
|
<form class="comment-form comment-box-ft">
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="avatar-wrap">
|
||||||
|
<img class="avatar" src="[[:~root.visitUserInfo.Logo]]">
|
||||||
|
</div>
|
||||||
|
<div class="editor-wrap">
|
||||||
|
<textarea class="editable" id="commentContent" name="commentContent" placeholder="回复"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="command clearfix" style="display: block;">
|
||||||
|
<button class="reply-comment-btn save btn btn-primary" data-comment-id="[[:CommentId]]">提交评论</button>
|
||||||
|
<a class="cancel reply-cancel btn-link">取消</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
[[/if]]
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
[[/for]]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- 评论 -->
|
||||||
|
<div class="comment-box hide">
|
||||||
|
<form class="comment-form comment-box-ft hide" id="commentForm">
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="avatar-wrap">
|
||||||
|
<img class="avatar" id="visitUserLogo">
|
||||||
|
</div>
|
||||||
|
<div class="editor-wrap">
|
||||||
|
<textarea class="editable" id="commentContent" name="commentContent" placeholder="评论" style="height: 100px;"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="command clearfix" style="display: block;">
|
||||||
|
<button id="commentBtn" class="reply-comment-btn save btn btn-primary">提交评论</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="needLogin hide" id="noLoginContainer">
|
||||||
|
<a onclick="goLogin()">立即登录</a>, 发表评论.
|
||||||
|
<br />
|
||||||
|
没有帐号? <a onclick="goRegister()">立即注册</a>
|
||||||
|
</div>
|
||||||
|
<div class="box-header">
|
||||||
|
<span class="counter">
|
||||||
|
<i class="icon icon-comment"></i><span id="commentNum">{{$.post.CommentNum}}</span> 条评论
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- 评论列表 -->
|
||||||
|
<ul id="comments">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 更多评论 -->
|
||||||
|
<div id="moreComments">
|
||||||
|
<div class="hide comments-more">
|
||||||
|
<a>More...</a>
|
||||||
|
</div>
|
||||||
|
<div class="comments-loading">
|
||||||
|
<img src="/images/loading-32.gif" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if and $.blogInfo.OpenComment (eq $.blogInfo.CommentType "disqus")}}
|
||||||
|
|
||||||
|
<div id="disqus_thread"></div>
|
||||||
|
<!-- comment -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
|
||||||
|
var disqus_shortname = '{{.blogInfo.DisqusId}}'; // required: replace example with your forum shortname
|
||||||
|
var disqus_identifier = '{{.blogInfo.UserId}}/{{$.post.NoteId}}/{{$.post.Title}}'; // 博客链接
|
||||||
|
|
||||||
|
/* * * DON'T EDIT BELOW THIS LINE * * */
|
||||||
|
(function() {
|
||||||
|
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||||
|
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
||||||
|
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
|
||||||
|
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
|
||||||
|
{{end}}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
<div id="posts">
|
||||||
|
<div class="each-post">
|
||||||
|
<div class="title">
|
||||||
|
{{.single.Title}}
|
||||||
|
</div>
|
||||||
|
<div class="created-time">
|
||||||
|
<i class="fa fa-calendar"></i> 更新 {{$.single.UpdatedTime | datetime}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 创建 {{$.single.CreatedTime | datetime}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 仅为移动端 -->
|
||||||
|
<div class="mobile-created-time">
|
||||||
|
{{ if $.blogInfo.UserLogo}}
|
||||||
|
<img src="{{$.blogInfo.UserLogo}}" id="userLogo">
|
||||||
|
{{else}}
|
||||||
|
<img src="{{$.siteUrl}}/images/blog/default_avatar.png" id="userLogo">
|
||||||
|
{{end}}
|
||||||
|
{{$.blogInfo.Username}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="desc" id="content">
|
||||||
|
{{$.single.Content | raw}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "footer.html" $}}
|
||||||
|
|
||||||
|
{{template "highlight.html" $}}
|
||||||
|
|
||||||
|
<div id="blogNav">
|
||||||
|
<div id="blogNavNav">
|
||||||
|
<i class="fa fa-align-justify" title="文档导航"></i>
|
||||||
|
<span>文档导航</span>
|
||||||
|
</div>
|
||||||
|
<div id="blogNavContent">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 一些公用的js -->
|
||||||
|
<script src="{{$.leanoteUrl}}/public/blog/js/common.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
initNav();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,505 @@
|
|||||||
|
#posts img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
#content * {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
#content h1 {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
#content h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
#content h3 {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
#content h4 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
@-webkit-keyframes dropdown {
|
||||||
|
0% {
|
||||||
|
margin-top: -25px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
margin-top: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes dropdown {
|
||||||
|
0% {
|
||||||
|
margin-top: -25px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
margin-top: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-ms-keyframes dropdown {
|
||||||
|
0% {
|
||||||
|
margin-top: -25px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
margin-top: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes dropdown {
|
||||||
|
0% {
|
||||||
|
margin-top: -25px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
margin-top: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes pulldown {
|
||||||
|
0% {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
top: 90%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
top: 100%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes pulldown {
|
||||||
|
0% {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
top: 90%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
top: 100%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-ms-keyframes pulldown {
|
||||||
|
0% {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
top: 90%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
top: 100%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes pulldown {
|
||||||
|
0% {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
top: 90%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
top: 100%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a,
|
||||||
|
.btn {
|
||||||
|
-webkit-transition: all 0.2s ease;
|
||||||
|
-moz-transition: all 0.2s ease;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.btn:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
ul.dropdown-menu {
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.172549) 0px 6px 12px 0px;
|
||||||
|
}
|
||||||
|
ul.dropdown-menu:before {
|
||||||
|
content: "";
|
||||||
|
width: 20px;
|
||||||
|
height: 12px;
|
||||||
|
position: absolute;
|
||||||
|
top: -12px;
|
||||||
|
right: 20px;
|
||||||
|
background-image: url("images/triangle_2x.png");
|
||||||
|
background-size: 20px 12px;
|
||||||
|
}
|
||||||
|
ul.dropdown-menu {
|
||||||
|
display: block;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.open ul.dropdown-menu {
|
||||||
|
-webkit-animation: pulldown .2s;
|
||||||
|
animation: pulldown .2s;
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.created-time .fa {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
#blogNav {
|
||||||
|
display: none;
|
||||||
|
background-color: #fff;
|
||||||
|
opacity: 0.7;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 10;
|
||||||
|
padding: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
#blogNavContent {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 250px;
|
||||||
|
display: none;
|
||||||
|
-webkit-overflow-scrolling: touch !important;
|
||||||
|
}
|
||||||
|
#blogNavNav {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#blogNav a {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
#blogNav:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
#blogNav a:hover {
|
||||||
|
color: #0fb264;
|
||||||
|
}
|
||||||
|
#blogNav ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
#blogNav ul .nav-h2 {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
#blogNav ul .nav-h3 {
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
#blogNav ul .nav-h4 {
|
||||||
|
margin-left: 40px;
|
||||||
|
}
|
||||||
|
#blogNav ul .nav-h5 {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
.mobile-created-time {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#footer {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
.navbar-brand {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#themeList label {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
#themeList .preview {
|
||||||
|
display: block;
|
||||||
|
width: 400px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*"HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue", Helvetica, "Microsoft Yahei", Verdana, Simsun, "Segoe UI", "Segoe UI Web Regular", "Segoe UI Symbol", "BBAlpha Sans", "S60 Sans", Arial, sans-serif;*/
|
||||||
|
::selection {
|
||||||
|
background: #000000;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
::-moz-selection {
|
||||||
|
background: #000000;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
::-webkit-selection {
|
||||||
|
background: #000000;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
*,
|
||||||
|
body {
|
||||||
|
font-family: 'Open Sans', 'Helvetica Neue', Arial, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
font-family: 'Open Sans', 'Helvetica Neue', Arial, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif;
|
||||||
|
font-weight: 300 !important;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
#headerContainer {
|
||||||
|
height: 100px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
#posts {
|
||||||
|
width: 845px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
#postsContainer {
|
||||||
|
background: #f5f5f5 url("images/noise.png");
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
/* header */
|
||||||
|
#header {
|
||||||
|
color: #000000;
|
||||||
|
position: relative;
|
||||||
|
padding: 0 0 20px 0;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
#header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
#header h1 a {
|
||||||
|
color: #000000;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
#header h1 a img {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
#header #blogDesc {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.navbar {
|
||||||
|
margin-bottom: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.navbar-collapse {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
.navbar-form {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
/* posts */
|
||||||
|
#posts {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
#posts .each-post {
|
||||||
|
border-bottom: 1px solid #ebeff2;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #fff;
|
||||||
|
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
#posts .each-post .title {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #0fb264;
|
||||||
|
padding: 0 0 15px 0;
|
||||||
|
}
|
||||||
|
#posts .each-post .title a {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #0fb264;
|
||||||
|
padding: 0 0 15px 0;
|
||||||
|
}
|
||||||
|
#posts .each-post .created-time {
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding-bottom: 3px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
#posts .each-post .more {
|
||||||
|
background: #0fb264;
|
||||||
|
padding: 9px 10px;
|
||||||
|
border-radius: 2px;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 13px;
|
||||||
|
display: inline-block;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
#disqus_thread {
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
padding: 5px 0 0 0;
|
||||||
|
}
|
||||||
|
#search {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
#footerContainer {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
#footerContainer #footer a {
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
#footerContainer #footer ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
overflow-x: hidden;
|
||||||
|
background-color: #fbfcf7;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
#headerContainer,
|
||||||
|
#footerContainer {
|
||||||
|
background-color: #fbfcf7;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
#posts .each-post,
|
||||||
|
#postsContainer {
|
||||||
|
background-color: #fbfcf7 !important;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
#posts .each-post {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
#posts .each-post .title {
|
||||||
|
font-size: 24px;
|
||||||
|
border-left: 5px solid #65bd77;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px 0;
|
||||||
|
padding-left: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
padding-right: 10px;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
.created-time {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.mobile-created-time {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.mobile-created-time #userLogo {
|
||||||
|
display: inline-block;
|
||||||
|
max-height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.right-section .dropdown,
|
||||||
|
.right-section .btn {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
#blogNav {
|
||||||
|
left: initial !important;
|
||||||
|
right: 10px !important;
|
||||||
|
}
|
||||||
|
#postsContainer .container,
|
||||||
|
#footerContainer .container {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
#postsContainer {
|
||||||
|
margin: 0 !important;
|
||||||
|
max-width: 100%;
|
||||||
|
padding-top: 10px;
|
||||||
|
background: #f5f5f5 url("../../images/noise.png");
|
||||||
|
}
|
||||||
|
#posts {
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
#footerContainer #footer a {
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
#footerContainer #footer a:hover,
|
||||||
|
#footerContainer #footer a:focus {
|
||||||
|
color: #65bd77;
|
||||||
|
}
|
||||||
|
#headerAndNav {
|
||||||
|
position: initial;
|
||||||
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 2px dashed #ebeff2;
|
||||||
|
}
|
||||||
|
#headerAndNav #headerContainer {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
#headerAndNav #header {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#headerAndNav #header h1 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#headerAndNav .navbar-collapse {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
#headerAndNav #blogDesc {
|
||||||
|
border: none;
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
#headerAndNav .navbar-brand {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 50px;
|
||||||
|
padding: 0;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
#headerAndNav .navbar-brand img {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
#headerAndNav .navbar .container {
|
||||||
|
width: auto;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
#headerAndNav .navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
background: #fbfcf7;
|
||||||
|
z-index: 1000;
|
||||||
|
border-bottom: 1px solid #DEDDDF;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), inset 0 1px 0 #ffffff;
|
||||||
|
background-color: #FDFFF5;
|
||||||
|
}
|
||||||
|
#headerAndNav .navbar-nav {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
#headerAndNav .navbar-nav a {
|
||||||
|
padding-left: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
#headerAndNav #search {
|
||||||
|
width: 100%;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
#headerAndNav .navbar-form {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
#myTab,
|
||||||
|
.tab-content {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
<div class="container">
|
||||||
|
<h2>标签 - {{.curTag}} </h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="posts">
|
||||||
|
{{range .posts}}
|
||||||
|
<div class="each-post">
|
||||||
|
<div class="title">
|
||||||
|
<a href="{{$.postUrl}}/{{.NoteId}}" title="全文">
|
||||||
|
{{.Title}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="created-time">
|
||||||
|
<i class="fa fa-bookmark-o"></i>
|
||||||
|
{{if .Tags}}
|
||||||
|
{{blogTags $ .Tags}}
|
||||||
|
{{else}}
|
||||||
|
无
|
||||||
|
{{end}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 更新 {{.UpdatedTime | datetime}} |
|
||||||
|
<i class="fa fa-calendar"></i> 创建 {{.CreatedTime | datetime}}
|
||||||
|
</div>
|
||||||
|
<div class="desc">
|
||||||
|
{{.Abstract | raw}}
|
||||||
|
</div>
|
||||||
|
<a class="more" href="{{$.postUrl}}/{{.NoteId}}" title="全文">查看</a>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="each-post">
|
||||||
|
无
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
{{template "paging.html" $}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "footer.html" $}}
|
||||||
|
{{template "highlight.html" $}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
<div class="container">
|
||||||
|
<h2>标签</h2>
|
||||||
|
</div>
|
||||||
|
<div id="posts">
|
||||||
|
|
||||||
|
<div class="each-post">
|
||||||
|
<ul>
|
||||||
|
{{range $.tags}}
|
||||||
|
<li>
|
||||||
|
<a href="{{$.tagPostsUrl}}/{{.Tag}}">
|
||||||
|
{{.Tag}} {{.Count}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "footer.html" .}}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
以下是本主题的配置, 采用JSON格式
|
||||||
|
其中Name, Version, Author, AuthorUrl是必填项(注意首字大写)
|
||||||
|
你也可以定义其它的配置, 如FriendLinks, 在模板文件使用 $.themeInfo.FriendLinks来获取值
|
||||||
|
|
||||||
|
注意:
|
||||||
|
1) JSON语法严格, 键必须用双引号, 最后不得有空','来结尾
|
||||||
|
2) 以下配置不能包含任何注释, 不然解析会出错!
|
||||||
|
|
||||||
|
请在此解析所有配置
|
||||||
|
* Name 主题名
|
||||||
|
* Version 主题版本
|
||||||
|
* Author 主题的作者
|
||||||
|
* AuthorUrl 作者的博客链接或相关链接
|
||||||
|
|
||||||
|
* FriendLinks 友情链接
|
||||||
|
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
"Name": "leanote default theme",
|
||||||
|
"Version": "1.0",
|
||||||
|
"Author": "leanote.com",
|
||||||
|
"AuthorUrl": "http://leanote.com",
|
||||||
|
"FriendLinks": [
|
||||||
|
{"Title": "leanote", "Url": "http://leanote.com"}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="keywords" content="leanote,leanote.com">
|
||||||
|
<title>404</title>
|
||||||
|
|
||||||
|
<link href="/css/bootstrap.css" rel="stylesheet">
|
||||||
|
<link href="/css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet">
|
||||||
|
<link href="/css/index.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body id="boxBody">
|
||||||
|
<section id="box">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<h1 class="h text-white animated fadeInDownBig">life-404</h1>
|
||||||
|
</div>
|
||||||
|
<div id="errorBox">
|
||||||
|
<p class="error-info">
|
||||||
|
This page cann't found.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="list-group m-b-sm bg-white m-b-lg">
|
||||||
|
<a href="javascript:history.go(-1);" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-arrow-left icon-muted"></i> Back </a>
|
||||||
|
<a href="/index" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-home icon-muted"></i> Goto homepage </a>
|
||||||
|
<a href="/note" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-file-o icon-muted"></i> My note</a>
|
||||||
|
<a class="list-group-item" href="mailto:leanote@leanote.com">
|
||||||
|
<span class="badge">leanote@leanote.com</span>
|
||||||
|
<i class="fa fa-fw fa-envelope-o icon-muted"></i> Contact Us </a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<div id="boxFooter">
|
||||||
|
<p>
|
||||||
|
<a href="/index">leanote</a> © 2014
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
<div class="container">
|
||||||
|
<h2>归档 {{if $.curCateTitle}} - {{$.curCateTitle}}{{end}}</h2>
|
||||||
|
</div>
|
||||||
|
<div id="posts">
|
||||||
|
|
||||||
|
<div class="each-post">
|
||||||
|
<ul>
|
||||||
|
{{range $.archives}}
|
||||||
|
<li><span class="archive-year">{{.Year}}</span>
|
||||||
|
<ul>
|
||||||
|
{{range .Posts}}
|
||||||
|
<li>
|
||||||
|
{{dateFormat .PublicTime "2006-01-02"}} <a href="{{$.postUrl}}/{{.NoteId}}">{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "footer.html" .}}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
<div class="container">
|
||||||
|
<h2>分类 - {{$.curCateTitle}}</h2>
|
||||||
|
</div>
|
||||||
|
<div id="posts">
|
||||||
|
{{range $.posts}}
|
||||||
|
<div class="each-post">
|
||||||
|
<div class="title">
|
||||||
|
<a href="{{$.postUrl}}/{{.NoteId}}" title="全文">
|
||||||
|
{{.Title}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="created-time">
|
||||||
|
<i class="fa fa-bookmark-o"></i>
|
||||||
|
{{if .Tags}}
|
||||||
|
{{blogTags $ .Tags}}
|
||||||
|
{{else}}
|
||||||
|
无
|
||||||
|
{{end}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 更新 {{.UpdatedTime | datetime}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 创建 {{.CreatedTime | datetime}}
|
||||||
|
</div>
|
||||||
|
<div class="desc">
|
||||||
|
{{.Abstract | raw}}
|
||||||
|
</div>
|
||||||
|
<a class="more" href="{{$.postUrl}}/{{.NoteId}}" title="全文">查看</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<!-- 分页 -->
|
||||||
|
{{template "paging.html" $}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "footer.html" $}}
|
||||||
|
{{template "highlight.html" $}}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<div id="footerContainer">
|
||||||
|
{{$userId := $.blogInfo.UserId}}
|
||||||
|
<div class="container" id="footer">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h3>导航</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{{$.indexUrl}}">主页</a></li>
|
||||||
|
{{range $.cates}}
|
||||||
|
<li>
|
||||||
|
<a href="{{$.cateUrl}}/{{.CateId}}">{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h3>最近发表</h3>
|
||||||
|
<ul>
|
||||||
|
{{range .recentPosts}}
|
||||||
|
<li title="{{.Title}}"><a href="{{$.postUrl}}/{{.NoteId}}/">{{.Title}}</a></li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h3>友情链接 </h3>
|
||||||
|
<ul>
|
||||||
|
{{if $.themeInfo.FriendLinks}}
|
||||||
|
{{range $.themeInfo.FriendLinks}}
|
||||||
|
<li><a href="{{.Url}}" target="_blank">{{.Title}}</a></li>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="{{$.jQueryUrl}}"></script>
|
||||||
|
<script src="{{$.bootstrapJsUrl}}"></script>
|
||||||
|
<script src="{{$.siteUrl}}/js/bootstrap-hover-dropdown.js"></script>
|
||||||
|
<script>
|
||||||
|
// 搜索
|
||||||
|
function search(e) {
|
||||||
|
var keywords = $("#searchInput").val();
|
||||||
|
if(!keywords) {
|
||||||
|
location.href = "{{$.searchUrl}}";
|
||||||
|
} else {
|
||||||
|
var tpl = '<form action="{{$.searchUrl}}" method="get">';
|
||||||
|
tpl += '<input name="keywords" value="' + keywords + '" />';
|
||||||
|
tpl += "</form";
|
||||||
|
$(tpl).submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="keywords" content="leanote,leanote.com">
|
||||||
|
<meta name="description" content="leanote, not only a notebook">
|
||||||
|
<meta name="author" content="leanote">
|
||||||
|
|
||||||
|
<title>
|
||||||
|
{{if $.curIsIndex}}
|
||||||
|
{{$.blogInfo.Title}}
|
||||||
|
{{else if $.curIsCate}}
|
||||||
|
分类-{{$.curCateTitle}}
|
||||||
|
{{else if $.curIsSearch}}
|
||||||
|
搜索-{{$.keywords}}
|
||||||
|
{{else if $.curIsTags}}
|
||||||
|
我的标签
|
||||||
|
{{else if $.curIsTagPosts}}
|
||||||
|
标签-{{$.curTag}}
|
||||||
|
{{else if $.curIsPost}}
|
||||||
|
{{$.post.Title}}
|
||||||
|
{{else if $.curIsSingle}}
|
||||||
|
{{$.single.Title}}
|
||||||
|
{{else if $.curIsArchive}}
|
||||||
|
归档
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</title>
|
||||||
|
<!-- Bootstrap core CSS -->
|
||||||
|
<link href="{{$.bootstrapCssUrl}}" rel="stylesheet">
|
||||||
|
<!-- 字体必须同一域 -->
|
||||||
|
<link href="{{$.fontAwesomeUrl}}" rel="stylesheet">
|
||||||
|
<link href="{{$.themeBaseUrl}}/style.css" rel="stylesheet">
|
||||||
|
<script>
|
||||||
|
function log(o) {
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="headerAndNav" >
|
||||||
|
<div id="headerContainer" class="container">
|
||||||
|
<!-- 头部可放博客名, 导航 -->
|
||||||
|
<div id="header">
|
||||||
|
|
||||||
|
{{$username := .userInfo.Username}}
|
||||||
|
<h1>
|
||||||
|
<a href="{{$.indexUrl}}" id="logo">
|
||||||
|
{{if $.blogInfo.Logo}}
|
||||||
|
<img src="{{$.blogInfo.Logo}}" title="{{$.blogInfo.Title}}"/>
|
||||||
|
{{else}}
|
||||||
|
{{$.blogInfo.Title | raw}}
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
<div id="blogDesc">
|
||||||
|
{{$.blogInfo.SubTitle | raw}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Static navbar -->
|
||||||
|
<div class="navbar navbar-default">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a class="navbar-brand" href="{{.indexUrl}}">
|
||||||
|
{{if $.blogInfo.Logo}}
|
||||||
|
|
||||||
|
<img src="{{$.blogInfo.Logo}}" title="{{$.blogInfo.Title}}"/>
|
||||||
|
{{else}}
|
||||||
|
{{$.blogInfo.Title | raw}}
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-collapse collapse">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
|
||||||
|
<li class="{{if $.curIsIndex}}active{{end}}"><a href="{{.indexUrl}}">主页</a></li>
|
||||||
|
<!-- 分类页 -->
|
||||||
|
{{range $.cates}}
|
||||||
|
<li class="{{if eq .CateId $.curCateId}}active{{end}}">
|
||||||
|
<a href="{{$.cateUrl}}/{{.CateId}}"
|
||||||
|
>{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
<!-- 单页 -->
|
||||||
|
{{range $.singles}}
|
||||||
|
<li class="{{if eq $.curSingleId .SingleId}}active{{end}}">
|
||||||
|
<a href="{{$.singleUrl}}/{{.SingleId}}">{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!-- 归档 -->
|
||||||
|
<li class="{{if $.curIsArchive}}active{{end}}">
|
||||||
|
<a href="{{$.archiveUrl}}">归档</a>
|
||||||
|
</li>
|
||||||
|
<li class="{{if $.curIsTags}}active{{end}}">
|
||||||
|
<a href="{{$.tagsUrl}}">标签</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<form class="navbar-form navbar-right" id="search" onsubmit="search(event);return false;">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon" id="searchIcon" onclick="search(event);"><i class="fa fa-search"></i></span>
|
||||||
|
<input type="text" placeholder="search" id="searchInput" class="form-control" value="{{.keywords}}">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div><!--/.nav-collapse -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<link href="{{$.prettifyCssUrl}}" type="text/css" rel="stylesheet"/>
|
||||||
|
<script src="{{$.prettifyJsUrl}}"></script>
|
||||||
|
<script>
|
||||||
|
$("pre").addClass("prettyprint linenums");
|
||||||
|
prettyPrint();
|
||||||
|
</script>
|
||||||
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 629 B |
@@ -0,0 +1,39 @@
|
|||||||
|
{{template "header.html" .}}
|
||||||
|
|
||||||
|
<div id="postsContainer">
|
||||||
|
|
||||||
|
<div id="posts">
|
||||||
|
{{range $.posts}}
|
||||||
|
<div class="each-post">
|
||||||
|
<div class="title">
|
||||||
|
<a href="{{$.postUrl}}/{{.NoteId}}" title="全文">
|
||||||
|
{{.Title}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="created-time">
|
||||||
|
<i class="fa fa-bookmark-o"></i>
|
||||||
|
{{if .Tags}}
|
||||||
|
{{blogTags $ .Tags}}
|
||||||
|
{{else}}
|
||||||
|
无
|
||||||
|
{{end}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 更新 {{.UpdatedTime | datetime}}
|
||||||
|
|
|
||||||
|
<i class="fa fa-calendar"></i> 创建 {{.CreatedTime | datetime}}
|
||||||
|
</div>
|
||||||
|
<div class="desc">
|
||||||
|
{{.Abstract | raw}}
|
||||||
|
</div>
|
||||||
|
<a class="more" href="{{$.postUrl}}/{{.NoteId}}" title="全文">查看</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<!-- 分页 -->
|
||||||
|
{{template "paging.html" $}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "footer.html" $}}
|
||||||
|
{{template "highlight.html" $}}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{{if gt $.paging.TotalPage 1}}
|
||||||
|
|
||||||
|
<!-- 上一页 -->
|
||||||
|
{{if gt $.paging.CurPage 1}}
|
||||||
|
{{set . "prePageClass" ""}}
|
||||||
|
{{set . "prePageUrl" (urlConcat $.pagingBaseUrl "page" (incr $.paging.CurPage -1)) }}
|
||||||
|
{{else}}
|
||||||
|
{{set . "prePageClass" "disabled"}}
|
||||||
|
{{set . "prePageUrl" "#"}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!-- 下一页 -->
|
||||||
|
{{if lt $.paging.CurPage $.paging.TotalPage }}
|
||||||
|
{{set . "nextPageClass" ""}}
|
||||||
|
{{set . "nextPageUrl" (urlConcat $.pagingBaseUrl "page" (incr $.paging.CurPage 1)) }}
|
||||||
|
{{else}}
|
||||||
|
{{set . "nextPageClass" "disabled"}}
|
||||||
|
{{set . "nextPageUrl" "#"}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{$.paging.CurPage}}/{{$.paging.TotalPage}}
|
||||||
|
<ul class="pager">
|
||||||
|
<li class="{{$.prePageClass}}"><a href="{{$.prePageUrl}}">上一页</a></li>
|
||||||
|
<li class="{{$.nextPageClass}}"><a href="{{$.nextPageUrl}}">下一页</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{end}}
|
||||||