This commit is contained in:
deepzz0
2016-09-29 02:59:27 +08:00
parent 60af472ca7
commit ddf508825c
121 changed files with 711894 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
*.DS_Store
imququ
vendor
*.exe
eiblog
conf/certs/*

0
.travis.yml Normal file
View File

0
CHANGELOG.md Normal file
View File

13
Dockerfile Normal file
View File

@@ -0,0 +1,13 @@
FROM ubuntu:trusty
MAINTAINER deepzz <deepzz.qi@gmail.com>
ADD conf /eiblog/conf
ADD static /eiblog/static
ADD views /eiblog/views
ADD eiblog /eiblog/eiblog
EXPOSE 80
EXPOSE 443
WORKDIR /eiblog
ENTRYPOINT ["./eiblog"]

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Manuel Martínez-Almeida
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

390
api.go Normal file
View File

@@ -0,0 +1,390 @@
package main
import (
"errors"
"fmt"
"net/http"
"sort"
"strconv"
"strings"
"time"
"github.com/EiBlog/eiblog/setting"
"github.com/EiBlog/utils/logd"
"github.com/gin-gonic/gin"
"gopkg.in/mgo.v2/bson"
)
const (
NOTICE_SUCCESS = "success"
NOTICE_NOTICE = "notice"
NOTICE_ERROR = "error"
)
var APIs = make(map[string]func(c *gin.Context))
func init() {
// 更新账号信息
APIs["account"] = apiAccount
// 更新博客信息
APIs["blog"] = apiBlog
// 更新密码
APIs["password"] = apiPassword
// 删除文章
APIs["post-delete"] = apiPostDelete
APIs["post-add"] = apiPostAdd
// 专题
APIs["serie-delete"] = apiSerieDelete
APIs["serie-add"] = apiSerieAdd
APIs["serie-sort"] = apiSerieSort
// xx箱
APIs["draft-delete"] = apiDraftDelete
APIs["trash-delete"] = apiTrashDelete
APIs["trash-recover"] = apiTrashRecover
}
func apiAccount(c *gin.Context) {
e := c.PostForm("email")
pn := c.PostForm("phoneNumber")
ad := c.PostForm("address")
logd.Debug(e, pn, ad)
if (e != "" && !CheckEmail(e)) || (pn != "" && !CheckSMS(pn)) {
responseNotice(c, NOTICE_NOTICE, "参数错误", "")
return
}
Ei.Email = e
Ei.PhoneN = pn
Ei.Address = ad
err := UpdateAccountField(bson.M{"$set": bson.M{"email": e, "phonen": pn, "address": ad}})
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
responseNotice(c, NOTICE_SUCCESS, "更新成功", "")
}
func apiBlog(c *gin.Context) {
bn := c.PostForm("blogName")
bt := c.PostForm("bTitle")
ba := c.PostForm("beiAn")
st := c.PostForm("subTitle")
ss := c.PostForm("seriessay")
as := c.PostForm("archivessay")
if bn == "" || bt == "" {
responseNotice(c, NOTICE_NOTICE, "参数错误", "")
return
}
Ei.BlogName = bn
Ei.BTitle = bt
Ei.BeiAn = ba
Ei.SubTitle = st
Ei.SeriesSay = ss
Ei.ArchivesSay = as
err := UpdateAccountField(bson.M{"$set": bson.M{"blogger.blogname": bn, "blogger.btitle": bt, "blogger.beian": ba, "blogger.subtitle": st, "blogger.seriessay": ss, "blogger.archivessay": as}})
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
Ei.CH <- SERIES_MD
Ei.CH <- ARCHIVE_MD
responseNotice(c, NOTICE_SUCCESS, "更新成功", "")
}
func apiPassword(c *gin.Context) {
logd.Debug(c.Request.PostForm.Encode())
od := c.PostForm("old")
nw := c.PostForm("new")
cf := c.PostForm("confirm")
if nw != cf {
responseNotice(c, NOTICE_NOTICE, "两次密码输入不一致", "")
return
}
if !CheckPwd(nw) {
responseNotice(c, NOTICE_NOTICE, "密码格式错误", "")
return
}
if !VerifyPasswd(Ei.Password, Ei.BlogName, od) {
responseNotice(c, NOTICE_NOTICE, "原始密码不正确", "")
return
}
Ei.Password = EncryptPasswd(Ei.BlogName, nw)
responseNotice(c, NOTICE_SUCCESS, "更改成功", "")
}
func apiPostDelete(c *gin.Context) {
var err error
defer func() {
if err != nil {
logd.Error(err)
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
responseNotice(c, NOTICE_SUCCESS, "删除成功", "")
}()
err = c.Request.ParseForm()
if err != nil {
return
}
var ids []int32
var i int
for _, v := range c.Request.PostForm["cid[]"] {
i, err = strconv.Atoi(v)
if err != nil || i < 1 {
err = errors.New("参数错误")
return
}
ids = append(ids, int32(i))
}
err = DelArticles(ids...)
if err != nil {
return
}
// elasticsearch 删除索引
err = ElasticDelIndex(ids)
if err != nil {
return
}
}
func apiPostAdd(c *gin.Context) {
var err error
var publish bool
var cid int
defer func() {
if !publish {
// TODO 返回cid, success改为0
// {"success":1,"time":"10:40:46 AM","cid":"4"}
if err != nil {
c.JSON(http.StatusOK, gin.H{"success": FAIL, "time": time.Now().Format("15:04:05 PM"), "cid": cid})
} else {
c.JSON(http.StatusOK, gin.H{"success": SUCCESS, "time": time.Now().Format("15:04:05 PM"), "cid": cid})
}
return
}
if err != nil {
} else {
c.Redirect(http.StatusFound, "/admin/posts")
}
}()
do := c.PostForm("do") // save or publish
slug := c.PostForm("slug")
title := c.PostForm("title")
text := c.PostForm("text")
date := c.PostForm("date")
serie := c.PostForm("serie")
tag := c.PostForm("tags")
if title == "" || text == "" || slug == "" {
err = errors.New("参数错误")
return
}
var tags []string
if tag != "" {
tags = strings.Split(tag, ",")
}
t := CheckDate(date)
serieid := CheckSerieID(serie)
publish = CheckPublish(do)
if cid, err = strconv.Atoi(c.PostForm("cid")); err != nil || cid < 1 {
artc := &Article{
Title: title,
Content: text,
Slug: slug,
CreateTime: t,
IsDraft: !publish,
Author: Ei.Username,
SerieID: serieid,
Tags: tags,
}
err = AddArticle(artc)
if err != nil {
logd.Error(err)
return
}
cid = int(artc.ID)
if publish {
ElasticIndex(artc)
}
} else {
artc := QueryArticle(int32(cid))
if artc == nil {
err = errors.New("没有发现该文章")
return
}
if publish {
if Ei.MapArticles[artc.Slug] != nil {
i, a := GetArticle(artc.ID)
DelFromLinkedList(a)
Ei.Articles[i] = artc
if a.SerieID != serieid {
ManageSeriesArticle(a, false, DELETE)
}
if strings.Join(a.Tags, ",") != tag {
ManageTagsArticle(a, false, DELETE)
}
ManageArchivesArticle(a, false, DELETE)
} else {
Ei.Articles = append(Ei.Articles, artc)
artc.IsDraft = false
}
Ei.MapArticles[artc.Slug] = artc
}
artc.Title = title
artc.Slug = slug
artc.Content = text
artc.CreateTime = t
artc.UpdateTime = time.Now()
artc.SerieID = serieid
artc.Tags = tags
err = UpdateArticle(bson.M{"id": artc.ID}, artc)
if err != nil {
logd.Error(err)
return
}
if publish {
sort.Sort(Ei.Articles)
GenerateExcerptAndRender(artc)
// elasticsearch 索引
ElasticIndex(artc)
if artc.ID >= setting.Conf.StartID {
ManageTagsArticle(artc, true, ADD)
ManageSeriesArticle(artc, true, ADD)
ManageArchivesArticle(artc, true, ADD)
AddToLinkedList(artc.ID)
}
}
}
}
func apiSerieDelete(c *gin.Context) {
err := c.Request.ParseForm()
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
// 只能逐一删除
for _, v := range c.Request.PostForm["mid[]"] {
id, err := strconv.Atoi(v)
if err != nil || id < 1 {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
err = DelSerie(int32(id))
if err != nil {
logd.Error(err)
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
}
responseNotice(c, NOTICE_SUCCESS, "删除成功", "")
}
func apiSerieAdd(c *gin.Context) {
name := c.PostForm("name")
slug := c.PostForm("slug")
desc := c.PostForm("description")
if name == "" || slug == "" || desc == "" {
responseNotice(c, NOTICE_NOTICE, "参数错误", "")
return
}
err := AddSerie(name, slug, desc)
if err != nil {
logd.Error(err)
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
responseNotice(c, NOTICE_SUCCESS, "添加成功", "")
}
// 暂未启用
func apiSerieSort(c *gin.Context) {
err := c.Request.ParseForm()
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
v := c.Request.PostForm["mid[]"]
logd.Debug(v)
}
func apiDraftDelete(c *gin.Context) {
err := c.Request.ParseForm()
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
for _, v := range c.Request.PostForm["mid[]"] {
i, err := strconv.Atoi(v)
if err != nil || i < 1 {
responseNotice(c, NOTICE_NOTICE, "参数错误", "")
return
}
err = RemoveArticle(int32(i))
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
}
responseNotice(c, NOTICE_SUCCESS, "删除成功", "")
}
func apiTrashDelete(c *gin.Context) {
logd.Debug(c.PostForm("key"))
logd.Debug(c.Request.PostForm)
err := c.Request.ParseForm()
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
for _, v := range c.Request.PostForm["mid[]"] {
i, err := strconv.Atoi(v)
if err != nil || i < 1 {
responseNotice(c, NOTICE_NOTICE, "参数错误", "")
return
}
err = RemoveArticle(int32(i))
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
}
c.JSON(http.StatusOK, nil)
responseNotice(c, NOTICE_SUCCESS, "删除成功", "")
}
func apiTrashRecover(c *gin.Context) {
logd.Debug(c.PostForm("key"))
logd.Debug(c.Request.PostForm)
err := c.Request.ParseForm()
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
for _, v := range c.Request.PostForm["mid[]"] {
i, err := strconv.Atoi(v)
if err != nil || i < 1 {
responseNotice(c, NOTICE_NOTICE, "参数错误", "")
return
}
err = RecoverArticle(int32(i))
if err != nil {
responseNotice(c, NOTICE_NOTICE, err.Error(), "")
return
}
}
responseNotice(c, NOTICE_SUCCESS, "恢复成功", "")
}
func responseNotice(c *gin.Context, typ, content, hl string) {
domain := runmode.Domain
if i := strings.Index(domain, ":"); i > -1 {
domain = domain[0:i]
}
if hl != "" {
c.SetCookie("notice_highlight", hl, 86400, "/", domain, runmode.EnableHttps, false)
}
c.SetCookie("notice_type", typ, 86400, "/", domain, runmode.EnableHttps, false)
c.SetCookie("notice", fmt.Sprintf("[\"%s\"]", content), 86400, "/", domain, runmode.EnableHttps, false)
c.Redirect(http.StatusFound, c.Request.Referer())
}

277
back.go Normal file
View File

@@ -0,0 +1,277 @@
// Package main provides ...
package main
import (
"fmt"
"net/http"
"strconv"
"time"
"github.com/EiBlog/eiblog/setting"
"github.com/EiBlog/utils/logd"
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
"gopkg.in/mgo.v2/bson"
)
func AuthFilter() gin.HandlerFunc {
return func(c *gin.Context) {
// TODO 过滤登录
session := sessions.Default(c)
v := session.Get("username")
if v == nil {
c.Abort()
c.Redirect(http.StatusFound, "/admin/login")
return
}
if v.(string) != Ei.Username {
c.Abort()
c.Redirect(http.StatusFound, "/admin/login")
return
}
c.Next()
}
}
// 登录界面
func HandleLogin(c *gin.Context) {
logout := c.Query("logout")
if logout == "true" {
session := sessions.Default(c)
session.Delete("username")
session.Save()
}
c.HTML(http.StatusOK, "login.html", gin.H{
"BTitle": Ei.BTitle,
})
}
func HandleLoginPost(c *gin.Context) {
user := c.PostForm("user")
pwd := c.PostForm("password")
// code := c.PostForm("code") // 二次验证
if user == "" || pwd == "" {
logd.Info("参数错误", user, pwd)
c.Redirect(http.StatusFound, "/admin/login")
return
}
if Ei.Username != user || !VerifyPasswd(Ei.Password, user, pwd) {
logd.Info("账号或密码错误", user, pwd)
c.Redirect(http.StatusFound, "/admin/login")
return
}
session := sessions.Default(c)
session.Set("username", user)
session.Save()
Ei.LoginIP = c.ClientIP()
Ei.LoginTime = time.Now()
UpdateAccountField(bson.M{"$set": bson.M{"loginip": Ei.LoginIP, "logintime": Ei.LoginTime}})
c.Redirect(http.StatusFound, "/admin/profile")
}
func GetBack() gin.H {
return gin.H{"Author": Ei.Username}
}
// 个人配置
func HandleProfile(c *gin.Context) {
h := GetBack()
h["Console"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "个人配置 | " + Ei.BTitle
h["Account"] = Ei
h["Profile"] = true
c.HTML(http.StatusOK, "backLayout.html", h)
}
// 插件
func HandlePlugins(c *gin.Context) {
h := GetBack()
h["Console"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "插件管理 | " + Ei.BTitle
c.HTML(http.StatusOK, "backLayout.html", h)
}
// 主题
func HandleThemes(c *gin.Context) {
h := GetBack()
h["Console"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "主题管理 | " + Ei.BTitle
c.HTML(http.StatusOK, "backLayout.html", h)
}
// 写文章==>Write
func HandlePost(c *gin.Context) {
h := GetBack()
id, err := strconv.Atoi(c.Query("cid"))
if artc := QueryArticle(int32(id)); err == nil && id > 0 && artc != nil {
h["Title"] = "编辑文章 | " + Ei.BTitle
h["Edit"] = artc
} else {
h["Title"] = "撰写文章 | " + Ei.BTitle
}
h["Post"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "撰写文章 | " + Ei.BTitle
h["Domain"] = runmode.Domain
h["Series"] = Ei.Series
c.HTML(http.StatusOK, "backLayout.html", h)
}
func HandleDraftDelete(c *gin.Context) {
id, err := strconv.Atoi(c.Query("cid"))
if err != nil || id < 1 {
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
return
}
if err = RemoveArticle(int32(id)); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "删除错误"})
return
}
c.JSON(http.StatusOK, nil)
}
// 文章管理==>Manage
func HandlePosts(c *gin.Context) {
kw := c.Query("keywords")
tmp := c.Query("serie")
se, err := strconv.Atoi(tmp)
if err != nil || se < 1 {
se = 0
}
pg, err := strconv.Atoi(c.Query("page"))
if err != nil || pg < 1 {
pg = 1
}
vals := c.Request.URL.Query()
h := GetBack()
h["Manage"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "文章管理 | " + Ei.BTitle
h["Posts"] = true
h["Series"] = Ei.Series
h["Serie"] = se
h["KW"] = kw
var max int
max, h["List"] = PageListBack(se, kw, false, false, pg, setting.Conf.PageSize)
if pg < max {
vals.Set("page", fmt.Sprint(pg+1))
h["Next"] = vals.Encode()
}
if pg > 1 {
vals.Set("page", fmt.Sprint(pg-1))
h["Prev"] = vals.Encode()
}
h["PP"] = make(map[int]string, max)
for i := 0; i < max; i++ {
vals.Set("page", fmt.Sprint(i+1))
h["PP"].(map[int]string)[i+1] = vals.Encode()
}
h["Cur"] = pg
c.HTML(http.StatusOK, "backLayout.html", h)
}
// 专题列表
func HandleSeries(c *gin.Context) {
h := GetBack()
h["Manage"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "专题管理 | " + Ei.BTitle
h["Series"] = true
h["List"] = Ei.Series
c.HTML(http.StatusOK, "backLayout.html", h)
}
func HandleSerie(c *gin.Context) {
h := GetBack()
id, err := strconv.Atoi(c.Query("mid"))
if serie := QuerySerie(int32(id)); err == nil && id > 0 && serie != nil {
h["Title"] = "编辑专题 | " + Ei.BTitle
h["Edit"] = serie
} else {
h["Title"] = "新增专题 | " + Ei.BTitle
}
h["Manage"] = true
h["Path"] = c.Request.URL.Path
h["Serie"] = true
c.HTML(http.StatusOK, "backLayout.html", h)
}
// 标签列表
func HandleTags(c *gin.Context) {
h := GetBack()
h["Manage"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "标签管理 | " + Ei.BTitle
h["Tags"] = true
h["List"] = Ei.Tags
c.HTML(http.StatusOK, "backLayout.html", h)
}
// 草稿箱
func HandleDraft(c *gin.Context) {
h := GetBack()
h["Manage"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "草稿箱 | " + Ei.BTitle
h["Draft"] = true
var err error
h["List"], err = LoadDraft()
if err != nil {
logd.Error(err)
c.HTML(http.StatusBadRequest, "backLayout.html", h)
return
}
c.HTML(http.StatusOK, "backLayout.html", h)
}
// 回收箱
func HandleTrash(c *gin.Context) {
h := GetBack()
h["Manage"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "回收箱 | " + Ei.BTitle
h["Trash"] = true
var err error
h["List"], err = LoadTrash()
if err != nil {
logd.Error(err)
c.HTML(http.StatusBadRequest, "backLayout.html", h)
return
}
c.HTML(http.StatusOK, "backLayout.html", h)
}
// 基本设置==>Setting
func HandleGeneral(c *gin.Context) {
h := GetBack()
h["Setting"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "基本设置 | " + Ei.BTitle
h["General"] = true
c.HTML(http.StatusOK, "backLayout.html", h)
}
// 阅读设置
func HandleDiscussion(c *gin.Context) {
h := GetBack()
h["Setting"] = true
h["Path"] = c.Request.URL.Path
h["Title"] = "阅读设置 | " + Ei.BTitle
h["Discussion"] = true
c.HTML(http.StatusOK, "backLayout.html", h)
}
// api
func HandleAPI(c *gin.Context) {
action := c.Param("action")
logd.Debug("action=======>", action)
api := APIs[action]
if api == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Invalid API Request"})
return
}
api(c)
}

18
build_docker.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
echo "go build..."
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build && \
mkdir tmp && \
cp -a conf tmp/conf && \
cp -a static tmp/static && \
cp -a views tmp/views && \
cp eiblog tmp/eiblog && \
cp Dockerfile tmp/Dockerfile && \
cd tmp && \
domain="registry.cn-hangzhou.aliyuncs.com" && \
docker build -t $domain/deepzz/eiblog . && \
read -p "是否上传到服务器(y/n):" word && \
if [ $word = "y" ] ;then
docker push $domain/deepzz/eiblog
fi
cd ..
rm -rf tmp

48
check.go Normal file
View File

@@ -0,0 +1,48 @@
package main
import (
"regexp"
"strconv"
"time"
)
func CheckEmail(e string) bool {
reg := regexp.MustCompile(`^(\w)+([\.\-]\w+)*#(\w)+((\.\w+)+)$`)
return reg.MatchString(e)
}
func CheckDomain(domain string) bool {
reg := regexp.MustCompile(`^(http://|https://)?[0-9a-zA-Z]+[0-9a-zA-Z\.-]*\.[a-zA-Z]{2,4}$`)
return reg.MatchString(domain)
}
func CheckSMS(sms string) bool {
reg := regexp.MustCompile(`^\+\d+$`)
return reg.MatchString(sms)
}
func CheckPwd(pwd string) bool {
return len(pwd) > 5 && len(pwd) < 19
}
func CheckDate(date string) time.Time {
if t, err := time.Parse("2006-01-02 15:04", date); err == nil {
return t
}
return time.Now()
}
func CheckSerieID(sid string) int32 {
if id, err := strconv.Atoi(sid); err == nil {
return int32(id)
}
return 0
}
func CheckBool(str string) bool {
return str == "true"
}
func CheckPublish(do string) bool {
return do == "publish"
}

29
check_test.go Normal file
View File

@@ -0,0 +1,29 @@
package main
import (
"testing"
)
func TestCheckEmail(t *testing.T) {
e := "xx@email.com"
e1 := "xxxxemail.com"
e2 := "xxx#email.com"
t.Log(CheckEmail(e))
t.Log(CheckEmail(e1))
t.Log(CheckEmail(e2))
}
func TestCheckDomain(t *testing.T) {
d := "123.com"
d1 := "http://123.com"
d2 := "https://123.com"
d3 := "123#.com"
d4 := "123.coooom"
t.Log(CheckDomain(d))
t.Log(CheckDomain(d1))
t.Log(CheckDomain(d1))
t.Log(CheckDomain(d1))
t.Log(CheckDomain(d4))
}

76
conf/app.yml Normal file
View File

@@ -0,0 +1,76 @@
# 静态文件版本
staticversion: 2
# 运行模式 dev or prod
runmode: dev
# 回收箱保留48小时
trash: -48
# 定时清理回收箱,%d小时
clean: 12
# 首页展示文章数量
pagenum: 10
# 管理界面
pagesize: 20
# 自动截取预览, 字符数
length: 200
# 截取预览标识
identifier: <!-- more -->
# favicon
favicon: //st.deepzz.com/static/img/favicon.png
# 起始ID预留id不时之需, 不用管
startid: 11
# 静态文件地址, 后台js,css在用, cdn: //domain.com
static: //127.0.0.1:8080
# elasticsearch url
searchurl: http://elasticsearch:9200
# 评论相关
disqus:
shortname: deepzz
publickey: wdSgxRm9rdGAlLKFcFdToBe3GT4SibmV7Y8EjJQ0r4GWXeKtxpopMAeIeoI2dTEg
url: https://disqus.com/api/3.0/threads/set.json
interval: 5
# 运行模式
modes:
dev:
# don't modify
enablehttp: true
httpport: 8080
domain: 127.0.0.1:8080
prod:
# you can fix certfile, keyfile, domain
enablehttp: true
httpport: 80
enablehttps: true
httpsport: 443
certfile: conf/certs/domain.pem
keyfile: conf/certs/domain.key
domain: deepzz.com
# twitter地址: //twitter.com/chenqijing2
twitter: //twitter.com/chenqijing2
# rss地址
rss: /rss.html
# search地址
search: /search.html
# 以下数据初始化用,可在后台修改
account:
# *后台登录用户名
username: deepzz
# *登录明文密码
password: deepzz
# 邮箱,用于通知: chenqijing2#163.com
email: chenqijing2#163.com
# 手机号, "+8615100000000"
phonenumber: "+8615100000000"
# 家庭住址
address: ""
blogger:
# left显示名称: Deepzz
blogname: Deepzz
# 小标题: 不抛弃,不放弃
subtitle: 不抛弃,不放弃
# 备案号: 蜀 ICP 备 16021362 号
beian: 蜀 ICP 备 16021362 号
# footer显示名称及tab标题: Deepzz's Blog
btitle: Deepzz's Blog
# 版权声明: 本站使用「<a href="//creativecommons.org/licenses/by/4.0/">署名 4.0 国际</a>」创作共享协议,转载请注明作者及原网址。
copyright: 本站使用「<a href="//creativecommons.org/licenses/by/4.0/">署名 4.0 国际</a>」创作共享协议,转载请注明作者及原网址。

0
conf/blackip.yml Normal file
View File

View File

@@ -0,0 +1,3 @@
ua,user-agent,userAgent
js,javascript
谷歌=>google

View File

@@ -0,0 +1,17 @@
network.host: 0.0.0.0
index:
analysis:
analyzer:
ik_syno:
type: custom
tokenizer: ik_max_word
filter: [my_synonym_filter]
ik_syno_smart:
type: custom
tokenizer: ik_smart
filter: [my_synonym_filter]
filter:
my_synonym_filter:
type: synonym
synonyms_path: analysis/synonym.txt

View File

@@ -0,0 +1,15 @@
# you can override this using by setting a system property, for example -Des.logger.level=DEBUG
es.logger.level: INFO
rootLogger: ${es.logger.level}, console
logger:
# log action execution errors for easier debugging
action: DEBUG
# reduce the logging for aws, too much is logged under the default INFO
com.amazonaws: WARN
appender:
console:
type: console
layout:
type: consolePattern
conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">custom/ext_stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

View File

@@ -0,0 +1,31 @@
使

View File

@@ -0,0 +1,14 @@
medcl
elastic
elasticsearch
kogstash
kibana
marvel
shield
watcher
beats
packetbeat
filebeat
topbeat
metrixbeat
kimchy

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
使

View File

@@ -0,0 +1,316 @@
世纪
位数
像素
克拉
公亩
公克
公分
公升
公尺
公担
公斤
公里
公顷
分钟
分米
加仑
千克
千米
厘米
周年
小时
平方
平方公尺
平方公里
平方分米
平方厘米
平方码
平方米
平方英寸
平方英尺
平方英里
平米
年代
年级
月份
毫升
毫米
毫克
海里
点钟
盎司
秒钟
立方公尺
立方分米
立方厘米
立方码
立方米
立方英寸
立方英尺
英亩
英寸
英尺
英里
阶段

View File

@@ -0,0 +1,33 @@
a
an
and
are
as
at
be
but
by
for
if
in
into
is
it
no
not
of
on
or
such
that
the
their
then
there
these
they
this
to
was
will
with

View File

@@ -0,0 +1,37 @@
斯基
维奇
诺夫

View File

@@ -0,0 +1,131 @@
万俟
上官
东方
令狐
仲孙
公冶
公孙
公羊
单于
司徒
司空
司马
夏侯
太叔
宇文
宗政
尉迟
慕容
欧阳
淳于
澹台
濮阳
申屠
皇甫
诸葛
赫连
轩辕
钟离
长孙
闻人
闾丘
鲜于

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,80 @@
# Elasticsearch plugin descriptor file
# This file must exist as 'plugin-descriptor.properties' at
# the root directory of all plugins.
#
# A plugin can be 'site', 'jvm', or both.
#
### example site plugin for "foo":
#
# foo.zip <-- zip file for the plugin, with this structure:
# _site/ <-- the contents that will be served
# plugin-descriptor.properties <-- example contents below:
#
# site=true
# description=My cool plugin
# version=1.0
#
### example jvm plugin for "foo"
#
# foo.zip <-- zip file for the plugin, with this structure:
# <arbitrary name1>.jar <-- classes, resources, dependencies
# <arbitrary nameN>.jar <-- any number of jars
# plugin-descriptor.properties <-- example contents below:
#
# jvm=true
# classname=foo.bar.BazPlugin
# description=My cool plugin
# version=2.0.0-rc1
# elasticsearch.version=2.0
# java.version=1.7
#
### mandatory elements for all plugins:
#
# 'description': simple summary of the plugin
description=IK Analyzer for Elasticsearch
#
# 'version': plugin's version
version=1.10.0
#
# 'name': the plugin name
name=analysis-ik
### mandatory elements for site plugins:
#
# 'site': set to true to indicate contents of the _site/
# directory in the root of the plugin should be served.
site=${elasticsearch.plugin.site}
#
### mandatory elements for jvm plugins :
#
# 'jvm': true if the 'classname' class should be loaded
# from jar files in the root directory of the plugin.
# Note that only jar files in the root directory are
# added to the classpath for the plugin! If you need
# other resources, package them into a resources jar.
jvm=true
#
# 'classname': the name of the class to load, fully-qualified.
classname=org.elasticsearch.plugin.analysis.ik.AnalysisIkPlugin
#
# 'java.version' version of java the code is built against
# use the system property java.specification.version
# version string must be a sequence of nonnegative decimal integers
# separated by "."'s and may have leading zeros
java.version=1.7
#
# 'elasticsearch.version' version of elasticsearch compiled against
# You will have to release a new version of the plugin for each new
# elasticsearch release. This version is checked when the plugin
# is loaded so Elasticsearch will refuse to start in the presence of
# plugins with the incorrect elasticsearch.version.
elasticsearch.version=2.4.0
#
### deprecated elements for jvm plugins :
#
# 'isolated': true if the plugin should have its own classloader.
# passing false is deprecated, and only intended to support plugins
# that have hard dependencies against each other. If this is
# not specified, then the plugin is isolated by default.
isolated=${elasticsearch.plugin.isolated}
#

151
conf/nginx/eiblog.conf Normal file
View File

@@ -0,0 +1,151 @@
server {
listen 443 ssl http2 fastopen=3 reuseport;
server_name www.deepzz.com deepzz.com;
server_tokens off;
include /data/eiblog/nginx/ip.blacklist;
# https://imququ.com/post/certificate-transparency.html#toc-2
# ssl_ct on;
# ssl_ct_static_scts /home/jerry/www/scts;
# 中间证书 + 站点证书
ssl_certificate /data/eiblog/conf/certs/chained.pem;
# 创建 CSR 文件时用的密钥
ssl_certificate_key /data/eiblog/conf/certs/domain.key;
# openssl dhparam -out dhparams.pem 2048
# https://weakdh.org/sysadmin.html
ssl_dhparam /data/eiblog/conf/ssl/dhparams.pem;
# https://github.com/cloudflare/sslconfig/blob/master/conf
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
# 如果启用了 RSA + ECDSA 双证书Cipher Suite 可以参考以下配置:
# ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets on;
# openssl rand 48 > session_ticket.key
# 单机部署可以不指定 ssl_session_ticket_key
ssl_session_ticket_key /data/eiblog/conf/ssl/session_ticket.key;
ssl_stapling on;
ssl_stapling_verify on;
# 根证书 + 中间证书
# https://imququ.com/post/why-can-not-turn-on-ocsp-stapling.html
# ssl_trusted_certificate /home/jerry/www/ssl/full_chained.pem;
resolver 114.114.114.114 valid=300s;
resolver_timeout 10s;
access_log /data/eiblog/log/nginx.log;
if ($request_method !~ ^(GET|HEAD|POST|OPTIONS)$ ) {
return 444;
}
if ($host != 'deepzz.com' ) {
rewrite ^/(.*)$ https://deepzz.com/$1 permanent;
}
location ~* (robots\.txt|favicon\.ico|crossdomain\.xml|google4c90d18e696bdcf8\.html|BingSiteAuth\.xml)$ {
root /home/jerry/www/imququ.com/www/static;
expires 1d;
}
location ^~ /static/uploads/ {
root /home/jerry/www/imququ.com/www;
add_header Access-Control-Allow-Origin *;
set $expires_time max;
valid_referers blocked none server_names *.qgy18.com *.inoreader.com feedly.com *.feedly.com www.udpwork.com theoldreader.com digg.com *.feiworks.com *.newszeit.com r.mail.qq.com yuedu.163.com *.w3ctech.com;
if ($invalid_referer) {
set $expires_time -1;
return 403;
}
expires $expires_time;
}
location ^~ /static/ {
root /home/jerry/www/imququ.com/www;
add_header Access-Control-Allow-Origin *;
expires max;
}
location ^~ /admin/ {
proxy_http_version 1.1;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
# DENY 将完全不允许页面被嵌套,可能会导致一些异常。如果遇到这样的问题,建议改成 SAMEORIGIN
# https://imququ.com/post/web-security-and-response-header.html#toc-1
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
proxy_set_header X-Via QingDao.Aliyun;
proxy_set_header Connection "";
proxy_set_header Host imququ.com;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:9095;
}
location / {
proxy_http_version 1.1;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header X-Frame-Options deny;
add_header X-Content-Type-Options nosniff;
add_header Content-Security-Policy "default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' blob: https:; img-src data: https: http://ip.qgy18.com; style-src 'unsafe-inline' https:; child-src https:; connect-src 'self' https://translate.googleapis.com; frame-src https://disqus.com https://www.slideshare.net";
add_header Public-Key-Pins 'pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; pin-sha256="aef6IF2UF6jNEwA2pNmP7kpgT6NFSdt7Tqf5HzaIGWI="; max-age=2592000; includeSubDomains';
add_header Cache-Control no-cache;
proxy_ignore_headers Set-Cookie;
proxy_hide_header Vary;
proxy_hide_header X-Powered-By;
proxy_set_header X-Via QingDao.Aliyun;
proxy_set_header Connection "";
proxy_set_header Host deepzz.com;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:9095;
}
}
server {
server_name www.deepzz.com deepzz.com;
server_tokens off;
access_log /dev/null;
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
}
location ^~ /.well-known/acme-challenge/ {
alias /home/jerry/www/challenges/;
try_files $uri =404;
}
location / {
rewrite ^/(.*)$ https://deepzz.com/$1 permanent;
}
}

95
conf/nginx/nginx.conf Normal file
View File

@@ -0,0 +1,95 @@
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_min_length 1000;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
##
# nginx-naxsi config
##
# Uncomment it if you installed nginx-naxsi
##
#include /etc/nginx/naxsi_core.rules;
##
# nginx-passenger config
##
# Uncomment it if you installed nginx-passenger
##
#passenger_root /usr;
#passenger_ruby /usr/bin/ruby;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}

6
conf/robots.txt Normal file
View File

@@ -0,0 +1,6 @@
User-agent: *
Allow: /
Sitemap: https://deepzz.com/sitemap.xml
User-agent: MJ12bot
Disallow: /

20
conf/tpl/feedTpl.xml Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{.Title}}</title>
<link>{{if .EnableHttps}}https://{{else}}http://{{end}}{{.Domain}}</link>
<atom:link href="{{if .EnableHttps}}https://{{else}}http://{{end}}{{.Domain}}/feed" rel="self"/>
<description>{{.SubTitle}}</description>
<language>zh-CN</language>
<lastBuildDate>{{.BuildDate}}</lastBuildDate>
{{range .Artcs}}
<item>
<title>{{.Title}}</title>
<link>{{if $.EnableHttps}}https://{{else}}http://{{end}}{{$.Domain}}/post/{{.Slug}}.html</link>
<comments>{{if $.EnableHttps}}https://{{else}}http://{{end}}{{$.Domain}}/post/{{.Slug}}.html#comments</comments>
<guid>{{if $.EnableHttps}}https://{{else}}http://{{end}}{{$.Domain}}/post/{{.Slug}}.html</guid>
<description><![CDATA[<blockquote>{{.Content}}]]></description>
</item>
{{end}}
</channel>
</rss>

10
conf/tpl/sitemapTpl.xml Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{{range .Artcs}}
<url>
<loc>{{if $.EnableHttps}}https{{else}}http{{end}}://{{$.Domain}}/post/{{.Slug}}.html</loc>
<lastmod>{{dateformat .CreateTime "2006-01-02"}}</lastmod>
<priority>0.6</priority>
</url>
{{end}}
</urlset>

591
db.go Normal file
View File

@@ -0,0 +1,591 @@
// Package main provides ...
package main
import (
"bytes"
"fmt"
"regexp"
"sort"
// "strings"
"sync"
"time"
"github.com/EiBlog/blackfriday"
"github.com/EiBlog/eiblog/helper"
"github.com/EiBlog/eiblog/setting"
"github.com/EiBlog/utils/logd"
db "github.com/EiBlog/utils/mgo"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
const (
DB = "eiblog"
COLLECTION_ACCOUNT = "account"
COLLECTION_ARTICLE = "article"
COUNTER_TAG = "tag"
COUNTER_SERIE = "serie"
COUNTER_ARTICLE = "article"
SERIES_MD = "series_md"
ARCHIVE_MD = "archive_md"
ADD = "add"
DELETE = "delete"
)
const (
commonHtmlFlags = 0 |
blackfriday.HTML_TOC |
blackfriday.HTML_USE_XHTML |
blackfriday.HTML_USE_SMARTYPANTS |
blackfriday.HTML_SMARTYPANTS_FRACTIONS |
blackfriday.HTML_SMARTYPANTS_DASHES |
blackfriday.HTML_SMARTYPANTS_LATEX_DASHES |
blackfriday.HTML_NOFOLLOW_LINKS
commonExtensions = 0 |
blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
blackfriday.EXTENSION_TABLES |
blackfriday.EXTENSION_FENCED_CODE |
blackfriday.EXTENSION_AUTOLINK |
blackfriday.EXTENSION_STRIKETHROUGH |
blackfriday.EXTENSION_SPACE_HEADERS |
blackfriday.EXTENSION_HEADER_IDS |
blackfriday.EXTENSION_BACKSLASH_LINE_BREAK |
blackfriday.EXTENSION_DEFINITION_LISTS
)
// Global Account
var (
Ei *Account
lock sync.Mutex
)
func init() {
// 数据库加索引
ms, c := db.Connect(DB, COLLECTION_ACCOUNT)
index := mgo.Index{
Key: []string{"username"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
}
if err := c.EnsureIndex(index); err != nil {
logd.Fatal(err)
}
ms.Close()
ms, c = db.Connect(DB, COLLECTION_ARTICLE)
index = mgo.Index{
Key: []string{"id", "slug"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
}
if err := c.EnsureIndex(index); err != nil {
logd.Fatal(err)
}
ms.Close()
// 读取帐号信息
Ei = loadAccount()
// 获取文章
Ei.Articles = loadArticles()
// 生成markdown文档
go generateMarkdown()
// 启动定时器
go timer()
// 获取评论数量
// go CommentsCount()
}
// 读取或初始化帐号信息
func loadAccount() (a *Account) {
a = &Account{}
err := db.FindOne(DB, COLLECTION_ACCOUNT, bson.M{"username": setting.Conf.Account.Username}, a)
// 初始化用户数据
if err == mgo.ErrNotFound {
a = &Account{
Username: setting.Conf.Account.Username,
Password: helper.EncryptPasswd(setting.Conf.Account.Username, setting.Conf.Account.Password),
Email: setting.Conf.Account.Email,
PhoneN: setting.Conf.Account.PhoneNumber,
Address: setting.Conf.Account.Address,
CreateTime: time.Now(),
}
a.BlogName = setting.Conf.Blogger.BlogName
a.SubTitle = setting.Conf.Blogger.SubTitle
a.BeiAn = setting.Conf.Blogger.BeiAn
a.BTitle = setting.Conf.Blogger.BTitle
a.Copyright = setting.Conf.Blogger.Copyright
err = db.Insert(DB, COLLECTION_ACCOUNT, a)
generateTopic()
} else if err != nil {
logd.Fatal(err)
}
a.CH = make(chan string, 2)
a.MapArticles = make(map[string]*Article)
a.Tags = make(map[string]SortArticles)
return
}
func loadArticles() (artcs SortArticles) {
err := db.FindAll(DB, COLLECTION_ARTICLE, bson.M{"isdraft": false, "deletetime": bson.M{"$eq": time.Time{}}}, &artcs)
if err != nil {
logd.Fatal(err)
}
sort.Sort(artcs)
for i, v := range artcs {
// 渲染文章
GenerateExcerptAndRender(v)
Ei.MapArticles[v.Slug] = v
// 分析文章
if v.ID < setting.Conf.StartID {
continue
}
if i > 0 {
v.Prev = artcs[i-1]
}
if artcs[i+1].ID >= setting.Conf.StartID {
v.Next = artcs[i+1]
}
ManageTagsArticle(v, false, ADD)
ManageSeriesArticle(v, false, ADD)
ManageArchivesArticle(v, false, ADD)
}
Ei.CH <- SERIES_MD
Ei.CH <- ARCHIVE_MD
return
}
// generate series,archive markdown
func generateMarkdown() {
for {
switch typ := <-Ei.CH; typ {
case SERIES_MD:
sort.Sort(Ei.Series)
var buffer bytes.Buffer
buffer.WriteString(Ei.SeriesSay)
buffer.WriteString("\n\n")
for _, serie := range Ei.Series {
buffer.WriteString(fmt.Sprintf("### %s{#toc-%d}", serie.Name, serie.ID))
buffer.WriteString("\n")
buffer.WriteString(serie.Desc)
buffer.WriteString("\n\n")
for _, artc := range serie.Articles {
// * [标题一](/post/hello-world.html) <span class="date">(Man 02, 2006)</span>
buffer.WriteString("* [" + artc.Title + "](/post/" + artc.Slug + ".html) <span class=\"date\">(" + artc.CreateTime.Format("Jan 02, 2006") + ")</span>\n")
}
buffer.WriteByte('\n')
}
Ei.PageSeries = string(renderPage(buffer.Bytes()))
case ARCHIVE_MD:
sort.Sort(Ei.Archives)
var buffer bytes.Buffer
buffer.WriteString(Ei.ArchivesSay)
buffer.WriteString("\n\n")
for _, archive := range Ei.Archives {
buffer.WriteString(fmt.Sprintf("### %s", archive.Time.Format("2006年01月")))
buffer.WriteString("\n\n")
for _, artc := range archive.Articles {
buffer.WriteString("* [" + artc.Title + "](/post/" + artc.Slug + ".html) <span class=\"date\">(" + artc.CreateTime.Format("Jan 02, 2006") + ")</span>\n")
}
buffer.WriteByte('\n')
}
Ei.PageArchives = string(renderPage(buffer.Bytes()))
}
}
}
// init account: generate blogroll and about page
func generateTopic() {
about := &Article{
ID: db.NextVal(DB, COUNTER_ARTICLE),
Author: setting.Conf.Account.Username,
Title: "关于",
Slug: "about",
CreateTime: time.Now(),
UpdateTime: time.Now(),
}
blogroll := &Article{
ID: db.NextVal(DB, COUNTER_ARTICLE),
Author: setting.Conf.Account.Username,
Title: "友情链接",
Slug: "blogroll",
UpdateTime: time.Now(),
CreateTime: time.Now(),
}
err := db.Insert(DB, COLLECTION_ARTICLE, blogroll)
if err != nil {
logd.Fatal(err)
}
err = db.Insert(DB, COLLECTION_ARTICLE, about)
if err != nil {
logd.Fatal(err)
}
}
// render page
func renderPage(md []byte) []byte {
renderer := blackfriday.HtmlRenderer(commonHtmlFlags, "", "")
return blackfriday.Markdown(md, renderer, commonExtensions)
}
// 文章分页
func PageList(p, n int) (prev int, next int, artcs []*Article) {
var l int
for l = len(Ei.Articles); l > 0; l-- {
if Ei.Articles[l-1].ID >= setting.Conf.StartID {
break
}
}
if l == 0 {
return 0, 0, nil
}
m := l / n
if d := l % n; d > 0 {
m++
}
if p > m {
p = m
}
if p > 1 {
prev = p - 1
}
if p < m {
next = p + 1
}
s := (p - 1) * n
e := p * n
if e > l {
e = l
}
artcs = Ei.Articles[s:e]
return
}
func ManageTagsArticle(artc *Article, s bool, dos ...string) {
for _, do := range dos {
switch do {
case ADD:
for _, tag := range artc.Tags {
Ei.Tags[tag] = append(Ei.Tags[tag], artc)
if s {
sort.Sort(Ei.Tags[tag])
}
}
case DELETE:
for _, tag := range artc.Tags {
for i, v := range Ei.Tags[tag] {
if v == artc {
Ei.Tags[tag] = append(Ei.Tags[tag][0:i], Ei.Tags[tag][i+1:]...)
if len(Ei.Tags[tag]) == 0 {
delete(Ei.Tags, tag)
}
return
}
}
}
}
}
}
func ManageSeriesArticle(artc *Article, s bool, dos ...string) {
for _, do := range dos {
switch do {
case ADD:
if artc.SerieID != 0 {
for i, serie := range Ei.Series {
if serie.ID == artc.SerieID {
Ei.Series[i].Articles = append(Ei.Series[i].Articles, artc)
if s {
sort.Sort(Ei.Series[i].Articles)
Ei.CH <- SERIES_MD
return
}
}
}
}
case DELETE:
if artc.SerieID != 0 {
for i, serie := range Ei.Series {
if serie.ID == artc.SerieID {
for j, v := range serie.Articles {
if v == artc {
Ei.Series[i].Articles = append(Ei.Series[i].Articles[0:j], Ei.Series[i].Articles[j+1:]...)
Ei.CH <- SERIES_MD
return
}
}
}
}
}
}
}
}
func ManageArchivesArticle(artc *Article, s bool, dos ...string) {
for _, do := range dos {
switch do {
case ADD:
add := false
y, m, _ := artc.CreateTime.Date()
for i, archive := range Ei.Archives {
ay, am, _ := archive.Time.Date()
if y == ay && m == am {
add = true
Ei.Archives[i].Articles = append(Ei.Archives[i].Articles, artc)
if s {
sort.Sort(Ei.Archives[i].Articles)
Ei.CH <- ARCHIVE_MD
break
}
}
}
if !add {
Ei.Archives = append(Ei.Archives, &Archive{Time: artc.CreateTime, Articles: SortArticles{artc}})
}
case DELETE:
for i, archive := range Ei.Archives {
ay, am, _ := archive.Time.Date()
if y, m, _ := artc.CreateTime.Date(); ay == y && am == m {
for j, v := range archive.Articles {
if v == artc {
Ei.Archives[i].Articles = append(Ei.Archives[i].Articles[0:j], Ei.Archives[i].Articles[j+1:]...)
Ei.CH <- ARCHIVE_MD
return
}
}
}
}
}
}
}
// 渲染markdown操作和截取摘要操作
var reg = regexp.MustCompile(setting.Conf.Identifier)
func GenerateExcerptAndRender(artc *Article) {
index := reg.FindStringIndex(artc.Content)
if len(index) > 0 {
artc.Excerpt = artc.Content[0:index[0]]
} else {
uc := []rune(artc.Content)
length := setting.Conf.Length
if len(uc) < length {
length = len(uc)
}
artc.Excerpt = string(uc[0:length])
}
artc.Content = string(renderPage([]byte(artc.Content)))
}
// 读取草稿箱
func LoadDraft() (artcs SortArticles, err error) {
err = db.FindAll(DB, COLLECTION_ARTICLE, bson.M{"isdraft": true}, &artcs)
sort.Sort(artcs)
return
}
// 读取回收箱
func LoadTrash() (artcs SortArticles, err error) {
err = db.FindAll(DB, COLLECTION_ARTICLE, bson.M{"deletetime": bson.M{"$ne": time.Time{}}}, &artcs)
sort.Sort(artcs)
return
}
// 添加文章
func AddArticle(artc *Article) error {
// 分配ID, 占位至起始id
for {
if id := db.NextVal(DB, COUNTER_ARTICLE); id < setting.Conf.StartID {
continue
} else {
artc.ID = id
break
}
}
if !artc.IsDraft {
defer GenerateExcerptAndRender(artc)
Ei.MapArticles[artc.Slug] = artc
Ei.Articles = append([]*Article{artc}, Ei.Articles...)
sort.Sort(Ei.Articles)
AddToLinkedList(artc.ID)
ManageTagsArticle(artc, true, ADD)
ManageSeriesArticle(artc, true, ADD)
ManageArchivesArticle(artc, true, ADD)
Ei.CH <- ARCHIVE_MD
if artc.SerieID > 0 {
Ei.CH <- SERIES_MD
}
}
return db.Insert(DB, COLLECTION_ARTICLE, artc)
}
// 删除文章,移入回收箱
func DelArticles(ids ...int32) error {
lock.Lock()
defer lock.Unlock()
for _, id := range ids {
i, artc := GetArticle(id)
DelFromLinkedList(artc)
Ei.Articles = append(Ei.Articles[:i], Ei.Articles[i+1:]...)
delete(Ei.MapArticles, artc.Slug)
ManageTagsArticle(artc, false, DELETE)
ManageSeriesArticle(artc, false, DELETE)
ManageArchivesArticle(artc, false, DELETE)
err := UpdateArticle(bson.M{"id": id}, bson.M{"$set": bson.M{"deletetime": time.Now()}})
if err != nil {
return err
}
}
Ei.CH <- ARCHIVE_MD
Ei.CH <- SERIES_MD
return nil
}
func DelFromLinkedList(artc *Article) {
if artc.Prev == nil && artc.Next != nil {
artc.Next.Prev = nil
} else if artc.Prev != nil && artc.Next == nil {
artc.Prev.Next = nil
} else if artc.Prev != nil && artc.Next != nil {
artc.Prev.Next = artc.Next
artc.Next.Prev = artc.Prev
}
}
func AddToLinkedList(id int32) {
i, artc := GetArticle(id)
if i == 0 && Ei.Articles[i+1].ID >= setting.Conf.StartID {
artc.Next = Ei.Articles[i+1]
Ei.Articles[i+1].Prev = artc
} else if i > 0 && Ei.Articles[i-1].ID >= setting.Conf.StartID {
artc.Prev = Ei.Articles[i-1]
if Ei.Articles[i-1].Next != nil {
artc.Next = Ei.Articles[i-1].Next
}
Ei.Articles[i-1].Next = artc
}
}
// 从缓存获取文章
func GetArticle(id int32) (int, *Article) {
for i, artc := range Ei.Articles {
if id == artc.ID {
return i, artc
}
}
return -1, nil
}
// 定时清除回收箱文章
func timer() {
delT := time.NewTicker(time.Duration(setting.Conf.Clean) * time.Hour)
for {
<-delT.C
db.Remove(DB, COLLECTION_ARTICLE, bson.M{"deletetime": bson.M{"$gt": time.Time{}, "$lt": time.Now().Add(time.Duration(setting.Conf.Trash) * time.Hour)}})
}
}
// 操作帐号字段
func UpdateAccountField(M bson.M) error {
return db.Update(DB, COLLECTION_ACCOUNT, bson.M{"username": Ei.Username}, M)
}
// 删除草稿箱或回收箱,永久删除
func RemoveArticle(id int32) error {
return db.Remove(DB, COLLECTION_ARTICLE, bson.M{"id": id})
}
// 恢复删除文章到草稿箱
func RecoverArticle(id int32) error {
return db.Update(DB, COLLECTION_ARTICLE, bson.M{"id": id}, bson.M{"$set": bson.M{"deletetime": time.Time{}, "isdraft": true}})
}
// 更新文章
func UpdateArticle(query, update interface{}) error {
return db.Update(DB, COLLECTION_ARTICLE, query, update)
}
// 编辑文档
func QueryArticle(id int32) *Article {
artc := &Article{}
if err := db.FindOne(DB, COLLECTION_ARTICLE, bson.M{"id": id}, artc); err != nil {
return nil
}
return artc
}
// 添加专题
func AddSerie(name, slug, desc string) error {
serie := &Serie{db.NextVal(DB, COUNTER_SERIE), name, slug, desc, time.Now(), nil}
Ei.Series = append(Ei.Series, serie)
sort.Sort(Ei.Series)
Ei.CH <- SERIES_MD
return UpdateAccountField(bson.M{"$addToSet": bson.M{"blogger.series": serie}})
}
// 删除专题
func DelSerie(id int32) error {
for i, serie := range Ei.Series {
if id == serie.ID {
if len(serie.Articles) > 0 {
return fmt.Errorf("请删除该专题下的所有文章")
}
err := UpdateAccountField(bson.M{"$pull": bson.M{"blogger.series": bson.M{"id": id}}})
if err != nil {
return err
}
Ei.Series[i] = nil
Ei.Series = append(Ei.Series[:i], Ei.Series[i+1:]...)
Ei.CH <- SERIES_MD
}
}
return nil
}
// 查找专题
func QuerySerie(id int32) *Serie {
for _, serie := range Ei.Series {
if serie.ID == id {
return serie
}
}
return nil
}
func PageListBack(se int, kw string, draft, del bool, p, n int) (max int, artcs []*Article) {
M := bson.M{}
if draft {
M["isdraft"] = true
} else if del {
M["deletetime"] = bson.M{"$ne": time.Time{}}
} else {
M["isdraft"] = false
M["deletetime"] = bson.M{"$eq": time.Time{}}
if se > 0 {
M["serieid"] = se
}
if kw != "" {
M["title"] = bson.M{"$regex": kw, "$options": "$i"}
}
}
ms, c := db.Connect(DB, COLLECTION_ARTICLE)
defer ms.Close()
err := c.Find(M).Select(bson.M{"content": 0}).Sort("-createtime").Limit(n).Skip((p - 1) * n).All(&artcs)
if err != nil {
logd.Error(err)
}
count, err := c.Find(M).Count()
if err != nil {
logd.Error(err)
}
max = count / n
if count%n > 0 {
max++
}
return
}

44
db_test.go Normal file
View File

@@ -0,0 +1,44 @@
package main
import (
"testing"
)
func TestPageListBack(t *testing.T) {
_, artcs := PageListBack(0, "", false, false, 1, 20)
for _, artc := range artcs {
t.Log(*artc)
}
t.Log("------------------------------------------------------------")
_, artcs = PageListBack(0, "", false, false, 2, 10)
for _, artc := range artcs {
t.Log(*artc)
}
t.Log("------------------------------------------------------------")
_, artcs = PageListBack(3, "", false, false, 1, 20)
for _, artc := range artcs {
t.Log(*artc)
}
t.Log("------------------------------------------------------------")
_, artcs = PageListBack(3, "19", false, false, 1, 20)
for _, artc := range artcs {
t.Log(*artc)
}
t.Log("------------------------------------------------------------")
_, artcs = PageListBack(0, "", false, true, 1, 20)
for _, artc := range artcs {
t.Log(*artc)
}
t.Log("------------------------------------------------------------")
_, artcs = PageListBack(0, "", true, false, 1, 20)
for _, artc := range artcs {
t.Log(*artc)
}
}
func TestAddSerie(t *testing.T) {
err := AddSerie("测试", "nothing", "这里是描述")
if err != nil {
t.Error(err)
}
}

75
disqus.go Normal file
View File

@@ -0,0 +1,75 @@
// Package main provides ...
// Get article' comments count
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/EiBlog/eiblog/setting"
"github.com/EiBlog/utils/logd"
)
type result struct {
Code int
Response []struct {
Posts int
Identifiers []string
}
}
func CommentsCount() {
if setting.Conf.Disqus.URL == "" || setting.Conf.Disqus.PublicKey == "" || setting.Conf.Disqus.ShortName == "" {
return
}
baseUrl := setting.Conf.Disqus.URL + "?api_key=" + setting.Conf.Disqus.PublicKey + "&forum=" + setting.Conf.Disqus.ShortName + "&"
domain := "http:" + runmode.Domain
if runmode.EnableHttps {
domain = "https:" + runmode.Domain
}
var count, index int
for index < len(Ei.Articles) {
logd.Debugf("count=====%d, index=======%d, length=======%d, bool=========%t", count, index, len(Ei.Articles), index < len(Ei.Articles) && count < 10)
var threads []string
for ; index < len(Ei.Articles) && count < 20; index++ {
artc := Ei.Articles[index]
threads = append(threads, fmt.Sprintf("thread=link:%s/post/%s.html", domain, artc.Slug))
count++
}
count = 0
url := baseUrl + strings.Join(threads, "&")
resp, err := http.Get(url)
if err != nil {
logd.Error(err)
break
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
logd.Error(err)
break
}
rst := result{}
err = json.Unmarshal(b, &rst)
if err != nil {
logd.Error(err)
break
}
if rst.Code != SUCCESS {
logd.Error(rst.Code)
break
}
for _, v := range rst.Response {
i := strings.Index(v.Identifiers[0], "-")
artc := Ei.MapArticles[v.Identifiers[0][i+1:]]
if artc != nil {
artc.Count = v.Posts
}
}
}
time.AfterFunc(time.Duration(setting.Conf.Disqus.Interval)*time.Hour, CommentsCount)
}

9
disqus_test.go Normal file
View File

@@ -0,0 +1,9 @@
package main
import (
"testing"
)
func TestDisqus(t *testing.T) {
CommentsCount()
}

36
docker-compose.yml Normal file
View File

@@ -0,0 +1,36 @@
version: '2'
services:
mongodb:
image: mongo:3.2
container_name: eidb
volumes:
- /data/eiblog/db:/data/db
restart: always
elasticsearch:
image: elasticsearch:2.4
container_name: eisearch
volumes:
- /data/eiblog/conf/es/config:/usr/share/elasticsearch/config
- /data/eiblog/conf/es/plugins:/usr/share/elasticsearch/plugins
- /data/eiblog/conf/es/data:/usr/share/elasticsearch/data
- /data/eiblog/conf/es/logs:/usr/share/elasticsearch/logs
environment:
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
# 需注释掉
ports:
- "9200:9200"
restart: always
eiblog:
image: registry.cn-hangzhou.aliyuncs.com/deepzz/eiblog
container_name: eiblog
volumes:
- /data/eiblog/logdata:/eiblog/logdata
- /data/eiblog/conf:/eiblog/conf
links:
- elasticsearch
- mongodb
ports:
- "443:443"
- "80:80"
- "8080:8080"
restart: always

344
elasticsearch.go Normal file
View File

@@ -0,0 +1,344 @@
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/EiBlog/eiblog/setting"
"github.com/EiBlog/utils/logd"
)
const (
INDEX = "eiblog"
TYPE = "article"
)
var es *ElasticService
func init() {
es = &ElasticService{url: setting.Conf.SearchURL, c: new(http.Client)}
initIndex()
}
func initIndex() {
mapping := map[string]interface{}{
"mappings": map[string]interface{}{
TYPE: map[string]interface{}{
"properties": map[string]interface{}{
"title": map[string]string{
"type": "string",
"term_vector": "with_positions_offsets",
"analyzer": "ik_syno",
"search_analyzer": "ik_syno",
},
"content": map[string]string{
"type": "string",
"term_vector": "with_positions_offsets",
"analyzer": "ik_syno",
"search_analyzer": "ik_syno",
},
"slug": map[string]string{
"type": "string",
},
"tags": map[string]string{
"type": "string",
"index": "not_analyzed",
},
"create_time": map[string]string{
"type": "date",
"index": "not_analyzed",
},
},
},
},
}
b, _ := json.Marshal(mapping)
err := CreateIndexAndMappings(INDEX, TYPE, b)
if err != nil {
logd.Fatal(err)
}
}
func Elasticsearch(kw string, size, from int) *ESSearchResult {
dsl := map[string]interface{}{
"query": map[string]interface{}{
"dis_max": map[string]interface{}{
"queries": []map[string]interface{}{
map[string]interface{}{
"match": map[string]interface{}{
"title": map[string]interface{}{
"query": kw,
"minimum_should_match": "50%",
"boost": 4,
},
},
},
map[string]interface{}{
"match": map[string]interface{}{
"content": map[string]interface{}{
"query": kw,
"minimum_should_match": "75%",
"boost": 4,
},
},
},
map[string]interface{}{
"match": map[string]interface{}{
"tags": map[string]interface{}{
"query": kw,
"minimum_should_match": "100%",
"boost": 2,
},
},
},
map[string]interface{}{
"match": map[string]interface{}{
"slug": map[string]interface{}{
"query": kw,
"minimum_should_match": "100%",
"boost": 1,
},
},
},
},
"tie_breaker": 0.3,
},
},
"highlight": map[string]interface{}{
"pre_tags": []string{"<b>"},
"post_tags": []string{"</b>"},
"fields": map[string]interface{}{
"title": map[string]string{},
"content": map[string]string{
// "fragment_size": 150,
// "number_of_fragments": "3",
},
},
},
}
b, _ := json.Marshal(dsl)
docs, err := IndexQueryDSL(INDEX, TYPE, size, from, b)
if err != nil {
logd.Error(err)
return nil
}
return docs
}
func ElasticsearchSimple(q string, size, from int) *ESSearchResult {
docs, err := IndexQuerySimple(INDEX, TYPE, size, from, q)
if err != nil {
logd.Error(err)
return nil
}
return docs
}
func ElasticIndex(artc *Article) error {
mapping := map[string]interface{}{
"title": artc.Title,
"content": artc.Content,
"slug": artc.Slug,
"tags": artc.Tags,
"create_time": artc.CreateTime.Format("2006-01-02"),
}
b, _ := json.Marshal(mapping)
return IndexOrUpdateDocument(INDEX, TYPE, artc.ID, b)
}
func ElasticDelIndex(ids []int32) error {
var target []string
for _, id := range ids {
target = append(target, fmt.Sprint(id))
}
return DeleteDocument(INDEX, TYPE, target)
}
///////////////////////////// Elasticsearch api /////////////////////////////
type ElasticService struct {
c *http.Client
url string
}
type IndicesCreateResult struct {
Acknowledged bool `json:"acknowledged"`
}
func (s *ElasticService) ParseURL(format string, params ...interface{}) string {
return fmt.Sprintf(s.url+format, params...)
}
func (s *ElasticService) Do(req *http.Request) (interface{}, error) {
resp, err := s.c.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
switch req.Method {
case "POST":
fallthrough
case "DELETE":
fallthrough
case "PUT":
fallthrough
case "GET":
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return b, nil
case "HEAD":
return resp.StatusCode, nil
default:
return nil, errors.New("unknown methods")
}
return nil, nil
}
func CreateIndexAndMappings(index, typ string, mappings []byte) (err error) {
req, err := http.NewRequest("HEAD", es.ParseURL("/%s/%s", index, typ), nil)
code, err := es.Do(req)
if err != nil {
return err
}
if code.(int) == http.StatusOK {
return nil
}
req, err = http.NewRequest("PUT", es.ParseURL("/%s", index), bytes.NewReader(mappings))
if err != nil {
return err
}
data, err := es.Do(req)
if err != nil {
return err
}
var rst IndicesCreateResult
err = json.Unmarshal(data.([]byte), &rst)
if err != nil {
return err
}
if !rst.Acknowledged {
return errors.New(string(data.([]byte)))
}
return nil
}
func IndexOrUpdateDocument(index, typ string, id int32, doc []byte) (err error) {
req, err := http.NewRequest("PUT", es.ParseURL("/%s/%s/%d", index, typ, id), bytes.NewReader(doc))
if err != nil {
return err
}
data, err := es.Do(req)
if err != nil {
return err
}
fmt.Println(string(data.([]byte)))
return nil
}
type ESDeleteDocument struct {
_Index string `json:"_index"`
_Type string `json:"_type"`
_ID string `json:"_id"`
}
type ESDeleteResult struct {
Errors bool `json:"errors"`
Iterms []map[string]struct {
Error string `json:"error"`
} `json:"iterms"`
}
func DeleteDocument(index, typ string, ids []string) error {
var buff bytes.Buffer
for _, id := range ids {
dd := &ESDeleteDocument{_Index: index, _Type: typ, _ID: id}
m := map[string]*ESDeleteDocument{"delete": dd}
b, _ := json.Marshal(m)
buff.Write(b)
buff.WriteByte('\n')
}
req, err := http.NewRequest("POST", es.ParseURL("/_bulk"), bytes.NewReader(buff.Bytes()))
if err != nil {
return err
}
data, err := es.Do(req)
if err != nil {
return err
}
var result ESDeleteResult
err = json.Unmarshal(data.([]byte), &result)
if err != nil {
return err
}
if result.Errors {
for _, iterm := range result.Iterms {
for _, s := range iterm {
if s.Error != "" {
return errors.New(s.Error)
}
}
}
}
return nil
}
type ESSearchResult struct {
Took float32 `json:"took"`
Hits struct {
Total int `json:"total"`
Hits []struct {
ID string `json:"_id"`
Source struct {
Slug string `json:"slug"`
Content string `json:"content"`
CreateTime time.Time `json:"create_time"`
Title string `json:"title"`
} `json:"_source"`
Highlight struct {
Title []string `json:"title"`
Content []string `json:"content"`
} `json:"highlight"`
} `json:"hits"`
} `json:"hits"`
}
func IndexQuerySimple(index, typ string, size, from int, q string) (*ESSearchResult, error) {
req, err := http.NewRequest("GET", es.ParseURL("/%s/%s/_search?size=%d&from=%d&q=%s", index, typ, size, from, q), nil)
if err != nil {
return nil, err
}
data, err := es.Do(req)
if err != nil {
return nil, err
}
result := &ESSearchResult{}
err = json.Unmarshal(data.([]byte), result)
if err != nil {
return nil, err
}
return result, nil
}
func IndexQueryDSL(index, typ string, size, from int, dsl []byte) (*ESSearchResult, error) {
req, err := http.NewRequest("POST", es.ParseURL("/%s/%s/_search?size=%d&from=%d", index, typ, size, from), bytes.NewReader(dsl))
if err != nil {
return nil, err
}
data, err := es.Do(req)
if err != nil {
return nil, err
}
result := &ESSearchResult{}
err = json.Unmarshal(data.([]byte), result)
if err != nil {
return nil, err
}
return result, nil
}

135
elasticsearch_test.go Normal file
View File

@@ -0,0 +1,135 @@
package main
import (
"encoding/json"
"fmt"
"testing"
)
func TestCreateIndexAndMappings(t *testing.T) {
mapping := map[string]interface{}{
"mappings": map[string]interface{}{
"article": map[string]interface{}{
"properties": map[string]interface{}{
"title": map[string]string{
"type": "string",
"term_vector": "with_positions_offsets",
"analyzer": "ik_syno",
"search_analyzer": "ik_syno",
},
"content": map[string]string{
"type": "string",
"term_vector": "with_positions_offsets",
"analyzer": "ik_syno",
"search_analyzer": "ik_syno",
},
"slug": map[string]string{
"type": "string",
},
"tags": map[string]string{
"type": "string",
"index": "not_analyzed",
},
"update_time": map[string]string{
"type": "date",
"index": "not_analyzed",
},
},
},
},
}
b, _ := json.Marshal(mapping)
err := CreateIndexAndMappings(INDEX, TYPE, b)
if err != nil {
t.Error(err)
}
}
func TestIndexDocument(t *testing.T) {
mapping := map[string]interface{}{
"title": "简单到不知道为什么",
"content": `最近有很多朋友邮件或者留言询问本博客服务端配置相关问题,基本都是关于 HTTPS 和 HTTP/2 的,其实我的 Nginx 配置在之前的文章中多次提到过,不过都比较分散。为了方便大家参考,本文贴出完整配置。本文内容会随时调整或更新,请大家不要把本文内容全文转载到第三方平台,以免给他人造成困扰或误导。另外限于篇幅,本文不会对配置做过多说明,如有疑问或不同意见,欢迎留言指出。
`,
"slug": "vim3",
"tags": []string{"js", "javascript", "test"},
"update_time": "2015-12-15T13:05:55Z",
}
b, _ := json.Marshal(mapping)
err := IndexOrUpdateDocument(INDEX, TYPE, int32(11), b)
if err != nil {
t.Error(err)
}
}
func TestIndexQuerySimple(t *testing.T) {
_, err := IndexQuerySimple(INDEX, TYPE, "JS")
if err != nil {
t.Error(err)
}
}
func TestIndexQueryDSL(t *testing.T) {
kw := "实现访问限制"
dsl := map[string]interface{}{
"query": map[string]interface{}{
"dis_max": map[string]interface{}{
"queries": []map[string]interface{}{
map[string]interface{}{
"match": map[string]interface{}{
"title": map[string]interface{}{
"query": kw,
"minimum_should_match": "50%",
"boost": 4,
},
},
},
map[string]interface{}{
"match": map[string]interface{}{
"content": map[string]interface{}{
"query": kw,
"minimum_should_match": "75%",
"boost": 4,
},
},
},
map[string]interface{}{
"match": map[string]interface{}{
"tags": map[string]interface{}{
"query": kw,
"minimum_should_match": "100%",
"boost": 2,
},
},
},
map[string]interface{}{
"match": map[string]interface{}{
"slug": map[string]interface{}{
"query": kw,
"minimum_should_match": "100%",
"boost": 1,
},
},
},
},
"tie_breaker": 0.3,
},
},
"highlight": map[string]interface{}{
"pre_tags": []string{"<b>"},
"post_tags": []string{"</b>"},
"fields": map[string]interface{}{
"title": map[string]string{},
"content": map[string]string{
// "fragment_size": 150,
// "number_of_fragments": "3",
},
},
},
}
b, _ := json.Marshal(dsl)
fmt.Println(string(b))
_, err := IndexQueryDSL(INDEX, TYPE, 10, 1, b)
if err != nil {
t.Error(err)
}
}

255
front.go Normal file
View File

@@ -0,0 +1,255 @@
// Package main provides ...
// 这里是前端页面展示相关接口
package main
import (
"fmt"
"net/http"
"regexp"
"strconv"
"strings"
"time"
"github.com/EiBlog/eiblog/setting"
"github.com/EiBlog/utils/logd"
"github.com/gin-gonic/gin"
)
func Filter() gin.HandlerFunc {
return func(c *gin.Context) {
// 过滤黑名单
BlackFilter(c)
// 用户cookie用于统计
UserCookie(c)
c.Next()
}
}
// 用户识别
func UserCookie(c *gin.Context) {
cookie, err := c.Request.Cookie("u")
if err != nil || cookie.Value == "" {
}
}
// 黑名单过滤
func BlackFilter(c *gin.Context) {
ip := c.ClientIP()
if setting.BlackIP[ip] {
c.Abort()
c.String(http.StatusForbidden, "Your IP is blacklisted.")
}
}
// 解析静态文件版本
func StaticVersion(c *gin.Context) (version int) {
cookie, err := c.Request.Cookie("v")
if err != nil || cookie.Value != fmt.Sprint(setting.Conf.StaticVersion) {
return setting.Conf.StaticVersion
}
return 0
}
func HandleNotFound(c *gin.Context) {
h := GetBase()
h["Version"] = StaticVersion(c)
h["Title"] = "Not Found"
h["NotFoundPage"] = true
h["Path"] = ""
c.HTML(http.StatusNotFound, "homeLayout.html", h)
}
func GetBase() gin.H {
return gin.H{
"Favicon": setting.Conf.Favicon,
"BlogName": Ei.BlogName,
"SubTitle": Ei.SubTitle,
"Twitter": setting.Conf.Twitter,
"RSS": setting.Conf.RSS,
"Search": setting.Conf.Search,
"CopyYear": time.Now().Year(),
"BTitle": Ei.BTitle,
"BeiAn": Ei.BeiAn,
"Domain": runmode.Domain,
"Static": setting.Conf.Static,
}
}
func HandleHomePage(c *gin.Context) {
h := GetBase()
h["Version"] = StaticVersion(c)
h["Title"] = Ei.BTitle
h["Path"] = c.Request.URL.Path
h["HomePage"] = true
h["CurrentPage"] = "blog-home"
pn, err := strconv.Atoi(c.Query("pn"))
if err != nil || pn < 1 {
pn = 1
}
h["Prev"], h["Next"], h["List"] = PageList(pn, setting.Conf.PageNum)
c.HTML(http.StatusOK, "homeLayout.html", h)
}
func HandleSeriesPage(c *gin.Context) {
h := GetBase()
h["Version"] = StaticVersion(c)
h["Title"] = "专题 | " + Ei.BTitle
h["Path"] = c.Request.URL.Path
h["SeriesPage"] = true
h["CurrentPage"] = "series"
h["Article"] = Ei.PageSeries
c.HTML(http.StatusOK, "homeLayout.html", h)
}
func HandleArchivesPage(c *gin.Context) {
h := GetBase()
h["Version"] = StaticVersion(c)
h["Title"] = "归档 | " + Ei.BTitle
h["Path"] = c.Request.URL.Path
h["ArchivesPage"] = true
h["CurrentPage"] = "archives"
h["Article"] = Ei.PageArchives
c.HTML(http.StatusOK, "homeLayout.html", h)
}
func HandleArticlePage(c *gin.Context) {
path := c.Param("slug")
artc := Ei.MapArticles[path[0:strings.Index(path, ".")]]
if artc == nil {
HandleNotFound(c)
return
}
h := GetBase()
h["Version"] = StaticVersion(c)
h["Title"] = artc.Title + " | " + Ei.BTitle
h["Path"] = c.Request.URL.Path
h["CurrentPage"] = "post-" + artc.Slug
if path == "blogroll.html" {
h["BlogrollPage"] = true
} else if path == "about.html" {
h["AboutPage"] = true
} else {
h["ArticlePage"] = true
h["Copyright"] = Ei.Copyright
if !artc.UpdateTime.IsZero() {
h["Days"] = int(time.Now().Sub(artc.UpdateTime).Hours()) / 24
}
if artc.SerieID > 0 {
h["Serie"] = QuerySerie(artc.SerieID)
}
}
h["Article"] = artc
h["EnableHttps"] = runmode.EnableHttps
c.HTML(http.StatusOK, "homeLayout.html", h)
}
type temp struct {
Title string
Slug string
URL string
Img string
CreateTime time.Time
}
func HandleSearchPage(c *gin.Context) {
h := GetBase()
h["Version"] = StaticVersion(c)
h["Title"] = "站内搜索 | " + Ei.BTitle
h["Path"] = ""
h["SearchPage"] = true
h["CurrentPage"] = "search-post"
q := c.Query("q")
start, err := strconv.Atoi(c.Query("start"))
if start < 1 || err != nil {
start = 1
}
if q != "" {
h["Word"] = q
// TODO search
var result *ESSearchResult
vals := c.Request.URL.Query()
reg := regexp.MustCompile(`^[a-z]+:\w+$`)
logd.Debug(reg.MatchString(q))
if reg.MatchString(q) {
result = ElasticsearchSimple(q, setting.Conf.PageNum, start-1)
} else {
result = Elasticsearch(q, setting.Conf.PageNum, start-1)
}
if result != nil {
result.Took /= 1000
for i, v := range result.Hits.Hits {
if artc := Ei.MapArticles[result.Hits.Hits[i].Source.Slug]; len(v.Highlight.Content) == 0 && artc != nil {
result.Hits.Hits[i].Highlight.Content = []string{artc.Excerpt}
}
}
h["SearchResult"] = result
if start-setting.Conf.PageNum > 0 {
vals.Set("start", fmt.Sprint(start-setting.Conf.PageNum))
h["Prev"] = vals.Encode()
}
if result.Hits.Total >= start+setting.Conf.PageNum {
vals.Set("start", fmt.Sprint(start+setting.Conf.PageNum))
h["Next"] = vals.Encode()
}
}
}
c.HTML(http.StatusOK, "homeLayout.html", h)
}
func HandleFeed(c *gin.Context) {
http.ServeFile(c.Writer, c.Request, "conf/feed.xml")
}
func HandleOpenSearch(c *gin.Context) {
c.Header("Content-Type", "application/xml; charset=utf-8")
c.Writer.WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
c.HTML(http.StatusOK, "opensearch.xml", gin.H{
"BTitle": Ei.BTitle,
"SubTitle": Ei.SubTitle,
})
}
func HandleRobots(c *gin.Context) {
http.ServeFile(c.Writer, c.Request, "conf/robots.txt")
}
func HandleSitemap(c *gin.Context) {
http.ServeFile(c.Writer, c.Request, "conf/sitemap.xml")
}
func HandleComments(c *gin.Context) {
// TODO comments
var ss = map[string]interface{}{
"errno": 0,
"errmsg": "",
"data": map[string]interface{}{
"next": "",
"commentNum": 2,
"comments": []map[string]interface{}{
map[string]interface{}{
"id": "2361914870",
"name": "Rekey Luo",
"url": "https://disqus.com/by/rekeyluo/",
"avatar": "//a.disquscdn.com/uploads/users/15860/7550/avatar92.jpg?1438917750",
"createdAt": "2015-11-16T05:00:02",
"createdAtStr": "9 months ago",
"message": "你最近对 http2 ssl 相关关注好多啊。",
"children": []map[string]interface{}{
map[string]interface{}{
"id": "2361915528",
"name": "Jerry Qu",
"url": "https://disqus.com/by/JerryQu/",
"avatar": "//a.disquscdn.com/uploads/users/1668/8837/avatar92.jpg?1472281172",
"createdAt": "2015-11-16T05:01:05",
"createdAtStr": "9 months ago",
"message": "嗯,最近对 web 性能优化这一块研究得比较多。",
},
},
},
},
},
}
c.JSON(http.StatusOK, ss)
}

18
glide.lock generated Normal file
View File

@@ -0,0 +1,18 @@
hash: 0da7cc4f8131804e7a030fd66408ea7b0d8796970eda67b7a18fa7e4f6ab5292
updated: 2016-08-06T23:43:20.163798264+08:00
imports:
- name: github.com/EiBlog/utils
version: 5a2bb8d46f95cd0d799a7eeebfb611431305eed3
subpackages:
- log
- mgo
- name: gopkg.in/ini.v1
version: 9144852efba7c4daf409943ee90767da62d55438
- name: gopkg.in/mgo.v2
version: 01084657862d7b12d3b10ffd0394357abf8f8bc2
subpackages:
- bson
- internal/json
- internal/sasl
- internal/scram
testImports: []

2
glide.yaml Normal file
View File

@@ -0,0 +1,2 @@
package: github.com/EiBlog/eiblog
import: []

26
helper.go Normal file
View File

@@ -0,0 +1,26 @@
package main
import (
"crypto/sha256"
"fmt"
"io"
)
const (
SUCCESS = iota
FAIL
)
// encrypt password
func EncryptPasswd(name, pass string) string {
salt := "%$@w*)("
h := sha256.New()
io.WriteString(h, name)
io.WriteString(h, salt)
io.WriteString(h, pass)
return fmt.Sprintf("%x", h.Sum(nil))
}
func VerifyPasswd(origin, name, input string) bool {
return origin == EncryptPasswd(name, input)
}

19
main.go Normal file
View File

@@ -0,0 +1,19 @@
// Package main provides ...
package main
import (
"net/http"
_ "net/http/pprof"
"github.com/EiBlog/utils/logd"
)
func main() {
// set log print level
logd.SetLevel(logd.Ldebug)
// pprof
go func() {
http.ListenAndServe(":6060", nil)
}()
Run()
}

126
model.go Normal file
View File

@@ -0,0 +1,126 @@
// Package main provides ...
package main
import "time"
type Account struct {
// 账户名
Username string
// 账户密码
Password string
// 二次验证token
Token string
// 账户
Email string
// 手机号
PhoneN string
// 住址
Address string
// 创建时间
CreateTime time.Time
// 最后登录时间
LoginTime time.Time
// 登出时间
LogoutTime time.Time
// 最后登录ip
LoginIP string
// 博客信息
Blogger
}
type Blogger struct {
// 博客名
BlogName string
// SubTitle
SubTitle string
// 备案号
BeiAn string
// 底部title
BTitle string
// 版权声明
Copyright string
// 专题,倒序
SeriesSay string
Series SortSeries
// 归档描述
ArchivesSay string
Archives SortArchives
// 忽略存储,前端界面全部缓存
PageSeries string `bson:"-"` // 专题页面
PageArchives string `bson:"-"` // 归档页面
Tags map[string]SortArticles `bson:"-"` // 标签 name->tag
Articles SortArticles `bson:"-"` // 所有文章
MapArticles map[string]*Article `bson:"-"` // url->Article
CH chan string `bson:"-"` // channel
}
type Serie struct {
// 自增id
ID int32
// 名称unique
Name string
// 缩略名
Slug string
// 专题描述
Desc string
// 创建时间
CreateTime time.Time
// 文章
Articles SortArticles `bson:"-"`
}
type SortSeries []*Serie
func (s SortSeries) Len() int { return len(s) }
func (s SortSeries) Less(i, j int) bool { return s[i].ID > s[j].ID }
func (s SortSeries) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type Archive struct {
Time time.Time
Articles SortArticles `bson:"-"`
}
type SortArchives []*Archive
func (s SortArchives) Len() int { return len(s) }
func (s SortArchives) Less(i, j int) bool { return s[i].Time.After(s[j].Time) }
func (s SortArchives) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type Article struct {
// 自增id
ID int32
// 作者名
Author string
// 标题
Title string
// 文章名: how-to-get-girlfriend
Slug string
// 评论数量
Count int
// markdown文档
Content string
// 归属专题
SerieID int32
// tagname
Tags []string
// 是否是草稿
IsDraft bool
// 创建时间
CreateTime time.Time
// 更新时间
UpdateTime time.Time
// 开始删除时间
DeleteTime time.Time
// 上篇文章
Prev *Article `bson:"-"`
// 下篇文章
Next *Article `bson:"-"`
// 预览信息
Excerpt string `bson:"-"`
}
type SortArticles []*Article
func (s SortArticles) Len() int { return len(s) }
func (s SortArticles) Less(i, j int) bool { return s[i].CreateTime.After(s[j].CreateTime) }
func (s SortArticles) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

112
router.go Normal file
View File

@@ -0,0 +1,112 @@
// Package main provides ...
package main
import (
"fmt"
"html/template"
"time"
"github.com/EiBlog/eiblog/setting"
"github.com/EiBlog/utils/logd"
"github.com/EiBlog/utils/tmpl"
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
)
var router *gin.Engine
var runmode = setting.Conf.Modes[setting.Conf.RunMode]
func init() {
if setting.Conf.RunMode == setting.PROD {
gin.SetMode(gin.ReleaseMode)
}
router = gin.Default()
store := sessions.NewCookieStore([]byte("eiblog321"))
store.Options(sessions.Options{
MaxAge: 86400 * 999,
Path: "/",
Secure: runmode.EnableHttps,
HttpOnly: true,
})
router.Use(sessions.Sessions("su", store))
// 匹配模版
//router.LoadHTMLGlob("views/*.html")
if tmpl, err := template.New("").Funcs(tmpl.TplFuncMap).ParseGlob("views/*.*"); err == nil {
tmpl, err = tmpl.ParseGlob("views/admin/*.html")
if err != nil {
logd.Fatal(err)
}
router.SetHTMLTemplate(tmpl)
} else {
logd.Fatal(err)
}
// 测试,开启静态文件
router.Static("/static", "./static")
router.Use(Filter())
router.NoRoute(HandleNotFound)
router.GET("/", HandleHomePage)
router.GET("/post/:slug", HandleArticlePage)
router.GET("/series.html", HandleSeriesPage)
router.GET("/archives.html", HandleArchivesPage)
router.GET("/search.html", HandleSearchPage)
router.GET("/data/comment", HandleComments)
router.GET("/feed", HandleFeed)
router.GET("/opensearch.xml", HandleOpenSearch)
router.GET("/sitemap.xml", HandleSitemap)
router.GET("/robots.txt", HandleRobots)
// 后台相关
admin := router.Group("/admin")
admin.GET("/login", HandleLogin)
admin.POST("/login", HandleLoginPost)
auth := admin.Use(AuthFilter())
{
// console
auth.GET("/profile", HandleProfile)
auth.GET("/plugins", HandlePlugins)
auth.GET("/themes", HandleThemes)
// write
auth.GET("/write-post", HandlePost)
// manage
auth.GET("/manage-posts", HandlePosts)
auth.GET("/manage-series", HandleSeries)
auth.GET("/add-serie", HandleSerie)
auth.GET("/manage-tags", HandleTags)
auth.GET("/manage-draft", HandleDraft)
auth.GET("/manage-trash", HandleTrash)
auth.GET("/options-general", HandleGeneral)
auth.GET("/options-discussion", HandleDiscussion)
auth.GET("/draft-delete", HandleDraftDelete)
// api
auth.POST("/api/:action", HandleAPI)
}
}
func Run() {
var (
endRunning = make(chan bool, 1)
err error
)
if runmode.EnableHttp {
go func() {
logd.Info(fmt.Sprintf("http server Running on %d", runmode.HttpPort))
err = router.Run(fmt.Sprintf(":%d", runmode.HttpPort))
if err != nil {
logd.Info("ListenAndServe: ", err)
time.Sleep(100 * time.Microsecond)
endRunning <- true
}
}()
}
if runmode.EnableHttps {
go func() {
logd.Info(fmt.Sprintf("https server Running on %d", runmode.HttpsPort))
err = router.RunTLS(fmt.Sprintf(":%d", runmode.HttpsPort), runmode.CertFile, runmode.KeyFile)
if err != nil {
logd.Info("ListenAndServe: ", err)
time.Sleep(100 * time.Microsecond)
endRunning <- true
}
}()
}
<-endRunning
}

91
setting/setting.go Normal file
View File

@@ -0,0 +1,91 @@
// Package setting provides ...
package setting
import (
"io/ioutil"
"os"
"path"
"github.com/EiBlog/utils/logd"
"gopkg.in/yaml.v2"
)
const (
DEV = "dev"
PROD = "prod"
)
var (
wd, _ = os.Getwd()
Conf = new(Config)
BlackIP = make(map[string]bool)
)
type Config struct {
StaticVersion int
RunMode string
Trash int
Clean int
PageNum int
PageSize int
Length int
Identifier string
Favicon string
StartID int32
Static string
SearchURL string
Disqus struct {
ShortName string
PublicKey string
URL string
Interval int
}
Modes map[string]RunMode
Twitter string
RSS string
Search string
Blogger struct {
BlogName string
SubTitle string
BeiAn string
BTitle string
Copyright string
}
Account struct {
Username string
Password string
Email string
PhoneNumber string
Address string
}
}
type RunMode struct {
EnableHttp bool
HttpPort int
EnableHttps bool
HttpsPort int
CertFile string
KeyFile string
Domain string
}
func init() {
// 初始化配置
dir := wd + "/conf"
data, err := ioutil.ReadFile(path.Join(dir, "app.yml"))
checkError(err)
err = yaml.Unmarshal(data, Conf)
checkError(err)
data, err = ioutil.ReadFile(path.Join(dir, "blackip.yml"))
checkError(err)
err = yaml.Unmarshal(data, BlackIP)
chekError(err)
}
func checkError(err error) {
if err != nil {
logd.Fatal(err)
}
}

12
setting/setting_test.go Normal file
View File

@@ -0,0 +1,12 @@
// Package setting provides ...
package setting
import (
"fmt"
"testing"
)
func TestInit(t *testing.T) {
init()
fmt.Printf("%v\n", *Conf)
}

File diff suppressed because one or more lines are too long

1
static/admin/diff.js Normal file

File diff suppressed because one or more lines are too long

16
static/admin/jquery-ui.js vendored Normal file

File diff suppressed because one or more lines are too long

25
static/admin/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

1
static/admin/moxie.js Normal file

File diff suppressed because one or more lines are too long

1
static/admin/pagedown.js Normal file

File diff suppressed because one or more lines are too long

1
static/admin/plupload.js Normal file

File diff suppressed because one or more lines are too long

1
static/admin/stmd.js Normal file

File diff suppressed because one or more lines are too long

1
static/admin/style.css Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

55
static/admin/typecho.js Normal file

File diff suppressed because one or more lines are too long

BIN
static/bg/bg01.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
static/bg/bg02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
static/bg/bg03.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
static/bg/bg04.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
static/bg/bg05.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
static/bg/bg06.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
static/bg/bg07.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

1
static/blog.css Normal file

File diff suppressed because one or more lines are too long

BIN
static/img/ajax-loader.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

BIN
static/img/editor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
static/img/editor@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
static/img/noscreen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="110px" height="26px" viewBox="0 0 110 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<title>typecho-logo</title>
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<path d="M34.75,5.288 C34.288,6.542 33.76,7.73 32.22,7.862 L32,9.468 L33.562,9.468 L33.562,15.342 C33.562,16.882 33.54,18.994 36.972,18.994 C38.006,18.994 39.106,18.686 39.766,18.224 L39.106,16.53 C38.754,16.75 38.204,16.992 37.61,16.992 C36.708,16.992 36.18,16.596 36.18,15.254 L36.18,9.468 L38.886,9.468 L39.106,7.62 L36.18,7.62 L36.18,5.288 L34.75,5.288 Z M48.258,18.268 C48.258,20.27 47.444,21.502 45.42,21.502 C44.76,21.502 44.276,21.436 43.858,21.282 C43.462,21.128 43.352,20.908 43.352,20.49 L43.352,19.434 L41.262,19.61 L41.262,22.668 C42.186,23.13 44.012,23.394 45.398,23.394 C48.676,23.394 50.502,21.898 50.502,18.268 L50.502,7.62 L46.63,7.62 L46.63,9.424 L47.334,9.468 C47.752,9.468 47.884,9.644 47.884,10.128 L47.884,14.11 C47.884,15.254 47.07,16.288 45.53,16.288 C44.122,16.288 43.902,15.276 43.902,13.934 L43.902,7.62 L40.03,7.62 L40.03,9.424 L40.734,9.468 C41.108,9.49 41.284,9.622 41.284,10.084 L41.284,14.506 C41.284,17.102 42.494,18.312 44.694,18.312 C46.146,18.312 47.488,17.696 48.258,16.596 L48.258,18.268 Z M54,20.776 C54,21.326 53.78,21.458 53.362,21.502 L52.636,21.568 L52.636,23.24 L58.312,23.24 L58.312,21.502 L56.53,21.414 L56.53,18.378 C57.102,18.73 58.026,19.016 58.884,19.016 C61.788,19.016 63.702,16.926 63.702,12.878 C63.702,8.94 62.162,7.29 59.72,7.29 C57.85,7.29 56.64,8.302 56.244,9.05 L56.244,7.62 L52.526,7.62 L52.526,9.402 L53.45,9.468 C53.868,9.468 54,9.644 54,10.128 L54,20.776 Z M60.974,13.098 C60.974,15.012 60.336,16.926 58.466,16.926 C57.894,16.926 57.102,16.75 56.53,16.376 L56.53,11.316 C56.53,10.304 57.498,9.424 58.752,9.424 C59.918,9.424 60.974,10.172 60.974,13.098 Z M70.786,7.29 C67.178,7.29 65.352,10.15 65.352,13.406 C65.352,16.684 66.804,18.972 70.544,18.972 C72.612,18.972 74.064,18.048 74.416,17.74 L73.58,15.958 C73.052,16.332 72.106,16.926 70.808,16.926 C68.938,16.926 68.19,15.76 68.102,14.33 C70.698,14.308 74.372,13.736 74.372,10.348 C74.372,8.39 72.942,7.29 70.786,7.29 Z M71.952,10.392 C71.952,12.086 69.642,12.46 68.014,12.482 C68.08,10.854 68.872,9.16 70.632,9.16 C71.424,9.16 71.952,9.578 71.952,10.392 Z M81.192,16.97 C79.234,16.97 78.354,15.43 78.354,13.032 C78.354,10.59 79.256,9.27 81.016,9.27 C81.346,9.27 81.61,9.314 81.874,9.402 C82.27,9.534 82.336,9.732 82.336,10.15 L82.336,11.206 L84.36,11.052 L84.36,8.192 C83.304,7.62 82.248,7.29 80.928,7.29 C78.442,7.29 75.692,8.83 75.692,13.296 C75.692,16.948 77.606,18.994 80.84,18.994 C82.468,18.994 83.81,18.422 84.668,17.718 L83.722,16.024 C82.82,16.684 82.05,16.97 81.192,16.97 Z M87.286,16.222 C87.286,16.772 87.066,16.904 86.648,16.948 L85.922,17.014 L85.922,18.686 L91.158,18.686 L91.158,16.926 L89.904,16.86 L89.904,11.536 C89.904,10.392 90.718,9.314 92.258,9.314 C93.666,9.314 93.974,10.348 93.974,11.69 L93.974,16.222 C93.974,16.772 93.754,16.904 93.336,16.948 L92.61,17.014 L92.61,18.686 L97.846,18.686 L97.846,16.926 L96.592,16.86 L96.592,11.118 C96.592,8.522 95.294,7.29 93.094,7.29 C91.642,7.29 90.542,7.972 89.882,8.918 L89.882,3 L85.966,3 L85.966,4.826 L86.736,4.87 C87.154,4.892 87.286,5.024 87.286,5.508 L87.286,16.222 Z M98.924,13.142 C98.924,17.124 100.86,19.016 103.808,19.016 C106.712,19.016 109.066,17.08 109.066,12.856 C109.066,7.796 105.788,7.29 104.16,7.29 C101.894,7.29 98.924,8.566 98.924,13.142 Z M103.984,17.08 C101.872,17.08 101.586,14.88 101.586,12.834 C101.586,10.722 102.29,9.226 104.028,9.226 C105.788,9.226 106.382,10.744 106.382,13.208 C106.382,15.496 105.7,17.08 103.984,17.08 Z" id="typecho" fill="#000000" sketch:type="MSShapeGroup"></path>
<path d="M13,26 C3.36833333,26 0,22.631 0,13 C0,3.36866667 3.36833333,0 13,0 C22.6316667,0 26,3.36866667 26,13 C26,22.631 22.6316667,26 13,26 Z M6,9 L20,9 L20,7 L6,7 L6,9 Z M6,14 L16,14 L16,12 L6,12 L6,14 Z M6,19 L18,19 L18,17 L6,17 L6,19 Z" id="icon" fill="#000000" sketch:type="MSShapeGroup"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

6
static/opensearch.xml Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<ShortName>Deepzz's Blog</ShortName>
<Description>不抛弃,不放弃</Description>
<Url type="text/html" template="https://deepzz.com/search.html?s={searchTerms}" />
</OpenSearchDescription>

1
views/404.html Normal file
View File

@@ -0,0 +1 @@
{{define "notfound"}}<div id=content class=inner><article class="post post-404"><h1 class=title>404 - 什么也没有</h1><div class="entry-content"><p>你要找的东东不存在喔!</p><p>请检查 URL 拼写是否有误,或者通过<a href="/search.html"> 站内搜索 </a>搜一下吧~</p></div></article></div>{{end}}

1
views/about.html Normal file
View File

@@ -0,0 +1 @@
{{define "about"}}<div id=content class=inner>{{with .Article}}<article class="post post-{{.ID}}" itemscope itemtype="http://schema.org/Article"><h1 class=title itemprop=headline>{{.Title}}</h1><div class="entry-content" itemprop=articleBody>{{str2html .Content}}</div></article><section id=comments><h1 class=title>Comments<span id=switch_thread_mode></h1><div id=disqus_thread class=ds-thread data-identifier="post-{{.Slug}}" data-url="{{if $.EnableHttps}}https://{{else}}http://{{end}}{{$.Domain}}/post/{{.Slug}}.html"></div><div id=simple_thread data-id="golomb-coded-sets"></div></section>{{end}}</div>{{end}}

178
views/admin/backLayout.html Normal file
View File

@@ -0,0 +1,178 @@
<!DOCTYPE HTML>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{.Title}}</title>
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="/static/admin/background.css">
<link rel="stylesheet" href="/static/admin/style.css">
<!--[if lt IE 9]>
<script src="//cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="//cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--[if lt IE 9]>
<div class="alert alert-danger topframe" role="alert">你的浏览器实在<strong>太太太太太太旧了</strong>,放学别走,升级完浏览器再说 <a target="_blank" class="alert-link" href="http://browsehappy.com">立即升级</a></div>
<![endif]-->
<script src="/static/admin/jquery.js"></script>
<script src="/static/admin/jquery-ui.js"></script>
<script src="/static/admin/typecho.js"></script>
<div class="typecho-head-nav clearfix" role="navigation">
<nav id="typecho-nav-list">
<ul class="root {{if .Console}}focus{{end}}">
<li class="parent"><a target="_self" href="/admin/profile">控制台</a></dt>
</li>
<ul class="child">
<li {{if eq .Path "/admin/profile"}}class="focus" {{end}}><a target="_self" href="/admin/profile">个人设置</a></li>
<li {{if eq .Path "/admin/plugins"}}class="focus" {{end}}><a target="_self" href="/admin/plugins">插件</a></li>
<li class="last {{if eq .Path "/admin/themes"}}focus{{end}}"><a target="_self" href="/admin/themes">外观</a></li>
</ul>
</ul>
<ul class="root {{if .Post}}focus{{end}}">
<li class="parent"><a target="_self" href="/admin/write-post">撰写</a></dt>
</li>
<ul class="child">
<li class="last {{if eq .Path "/admin/write-post"}}focus{{end}}"><a target="_self" href="/admin/write-post">撰写文章</a></li>
</ul>
</ul>
<ul class="root {{if .Manage}}focus{{end}}">
<li class="parent"><a target="_self" href="/admin/manage-posts">管理</a></dt>
</li>
<ul class="child">
<li {{if eq .Path "/admin/manage-posts"}}class="focus" {{end}}><a target="_self" href="/admin/manage-posts">文章</a></li>
<li {{if eq .Path "/admin/manage-series"}}class="focus" {{end}}><a target="_self" href="/admin/manage-series">专题</a></li>
{{if eq .Path "/admin/add-serie"}}<li class="focus"><a target="_self" href="/admin/add-serie">{{if .Edit}}编辑专题{{else}}新增专题{{end}}</a></li>{{end}}
<li class="last {{if eq .Path "/admin/manage-tags"}}focus{{end}}"><a target="_self" href="/admin/manage-tags">标签</a></li>
<li class="last {{if eq .Path "/admin/manage-draft"}}focus{{end}}"><a target="_self" href="/admin/manage-draft">草稿箱</a></li>
<li class="last {{if eq .Path "/admin/manage-trash"}}focus{{end}}"><a target="_self" href="/admin/manage-trash">回收箱</a></li>
</ul>
</ul>
<ul class="root {{if .Setting}}focus{{end}}">
<li class="parent"><a target="_self" href="/admin/options-general">设置</a></dt>
</li>
<ul class="child">
<li {{if eq .Path "/admin/options-general"}}class="focus" {{end}}><a target="_self" href="/admin/options-general">基本</a></li>
<li class="last {{if eq .Path "/admin/options-discussion"}}focus{{end}}"><a target="_self" href="/admin/options-discussion">阅读</a></li>
</ul>
</ul>
</nav>
<div class="operate">
<a target="_self" title="{{.LastLogin}}" href="/admin/profile" class="author">{{.Author}}</a><a class="exit" href="/admin/login?logout=true">登出</a><a target="_back" href="/">网站</a>
</div>
</div>
<div class="main">
{{if .Profile}}{{template "admin-profile" .}}{{else if .Post}}{{template "admin-post" .}}{{else if .Posts}}{{template "admin-posts" .}}{{else if .Series}}{{template "admin-series" .}}{{else if .Serie}}{{template "admin-serie" .}}{{else if .Tags}}{{template "admin-tags" .}}{{else if .General}}{{template "admin-general" .}}{{else if .Discussion}}{{template "admin-discussion" .}}{{else if .Draft}}{{template "admin-draft" .}}{{else if .Trash}}{{template "admin-trash" .}}{{end}}
</div>
<div class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="http://typecho.org" class="i-logo-s">Typecho</a>
<p><a href="http://typecho.org">Typecho</a> 提供皮肤, 版本 1.0 (14.10.10)</p>
</div>
</div>
<script>
(function () {
$(document).ready(function() {
// 处理消息机制
(function () {
cookies = {
notice : $.cookie( 'notice'),
noticeType : $.cookie( 'notice_type'),
highlight : $.cookie('notice_highlight')
},
path = '/';
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
p = $('<div class="message popup ' + cookies.noticeType + '">'
+ '<ul><li>' + $.parseJSON(cookies.notice).join('</li><li>')
+ '</li></ul></div>'), offset = 0;
if (head.length > 0) {
p.insertAfter(head);
offset = head.outerHeight();
} else {
p.prependTo(document.body);
}
function checkScroll () {
if ($(window).scrollTop() >= offset) {
p.css({
'position' : 'fixed',
'top' : 0
});
} else {
p.css({
'position' : 'absolute',
'top' : offset
});
}
}
$(window).scroll(function () {
checkScroll();
});
checkScroll();
p.slideDown(function () {
var t = $(this), color = '#C6D880';
if (t.hasClass('error')) {
color = '#FBC2C4';
} else if (t.hasClass('notice')) {
color = '#FFD324';
}
t.effect('highlight', {color : color})
.delay(5000).slideUp(function () {
$(this).remove();
});
});
$.cookie('notice', null, {path : path});
$.cookie('notice_type', null, {path : path});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie('notice_highlight', null, {path : path});
}
})();
// 导航菜单 tab 聚焦时展开下拉菜单
(function () {
$('#typecho-nav-list').find('.parent a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
$(this).parents('.root').find('.child').show();
});
$('.operate').find('a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
});
})();
// if ($('.typecho-login').length == 0) {
// $('a').each(function() {
// var t = $(this),
// href = t.attr('href');
// if ((href && href[0] == '#') || /^http\:\/\/localhost\/admin\/.*$/.exec(href)) {
// return;
// }
// t.attr('target', '_blank');
// });
// }
});
})();
</script>
</body>
</html>

View File

@@ -0,0 +1,3 @@
{{define "admin-discussion"}}
{{end}}

81
views/admin/draft.html Normal file
View File

@@ -0,0 +1,81 @@
{{define "admin-draft"}}
<div class="body container">
<div class="typecho-page-title">
<h2>草稿箱</h2>
</div>
<div class="row typecho-page-main manage-metas">
<div class="col-mb-12" role="main">
<form method="post" name="manage_draft" class="operate-form">
<div class="typecho-list-operate clearfix">
<div class="operate">
<label><i class="sr-only">全选</i>
<input type="checkbox" class="typecho-table-select-all" />
</label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only">操作</i>选中项 <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="此草稿箱下的所有内容将被永久删除, 你确认要删除这些文章吗?" href="/admin/api/draft-delete">删除</a></li>
</ul>
</div>
</div>
<div class="search" role="search">
</div>
</div>
<div class="typecho-table-wrap">
<table class="typecho-list-table">
<colgroup>
<col width="20" />
<col width="40%" />
<col width="" />
<col width="12%" />
<col width="14%" />
<col width="14%" />
</colgroup>
<thead>
<tr>
<th> </th>
<th>标题</th>
<th>作者</th>
<th>专题</th>
<th>创建</th>
<th>保存</th>
</tr>
</thead>
<tbody>
{{range .List}}
<tr id="mid-article-{{.ID}}">
<td>
<input type="checkbox" value="{{.ID}}" name="mid[]" />
</td>
<td><a href="/admin/write-post?cid={{.ID}}">{{.Title}}</a></td>
<td>{{.Author}}</td>
<td>{{if gt .SerieID 0}}专题ID:{{.SerieID}}{{else}}--{{end}}</td>
<td>{{dateformat .CreateTime "2006/01/02 15:04"}}</td>
<td>{{dateformat .UpdateTime "2006/01/02 15:04"}}</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</form>
</div>
</div>
</div>
<script>
(function() {
$(document).ready(function() {
$('.typecho-list-table').tableSelectable({
checkEl: 'input[type=checkbox]',
rowEl: 'tr',
selectAllEl: '.typecho-table-select-all',
actionEl: '.dropdown-menu a,button.btn-operate'
});
$('.btn-drop').dropdownMenu({
btnEl: '.dropdown-toggle',
menuEl: '.dropdown-menu'
});
});
})();
</script>
{{end}}

3
views/admin/general.html Normal file
View File

@@ -0,0 +1,3 @@
{{define "admin-general"}}
{{end}}

38
views/admin/login.html Normal file
View File

@@ -0,0 +1,38 @@
<!Doctype html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name=viewport>
<meta name=robots content="noindex, nofollow">
<title>Login | {{.BTitle}}</title>
<link rel=stylesheet href="/static/admin/background.css">
</head>
<body class="body-100">
<div class="typecho-login-wrap">
<div class="typecho-login">
<h1><a href="/">{{.BTitle}}</a></h1>
<form action="/admin/login" method=post>
<p>
<label for=user class="sr-only">用户名</label>
<input type=text id=user name=user value="" placeholder="用户名" class="text-l w-100">
</p>
<p>
<label for=password class="sr-only">密码</label>
<input type=password id=password name=password class="text-l w-100" placeholder="密码">
</p>
<!-- <p>
<label for=code class="sr-only">两步验证</label>
<input type=text id=code name=code class="text-l w-100" placeholder="两步验证">
</p> -->
<p class=submit>
<button type=submit class="btn btn-l w-100 primary">登录</button>
</p>
</form>
<p class="more-link">管理后台皮肤来自于<a href="http://typecho.org" target=_blank>Typecho</a>.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,328 @@
<!DOCTYPE HTML>
<html class="no-js">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>管理文章 - Hello World - Powered by Typecho</title>
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="http://localhost/admin/css/normalize.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/grid.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/style.css?v=14.10.10">
<!--[if lt IE 9]>
<script src="http://localhost/admin/js/html5shiv.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/respond.js?v=14.10.10"></script>
<![endif]-->
</head>
<body>
<!--[if lt IE 9]>
<div class="message error browsehappy" role="dialog">当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>.</div>
<![endif]-->
<div class="typecho-head-nav clearfix" role="navigation">
<nav id="typecho-nav-list">
<ul class="root focus">
<li class="parent"><a target="_self" href="/admin/home">控制台</a></dt>
</li>
<ul class="child">
<li target="_self" class="focus"><a href="/admin/home">概要</a></li>
<li><a target="_self" href="/admin/profile">个人设置</a></li>
<li><a target="_self" href="/admin/plugin">插件</a></li>
<li class="last"><a target="_self" href="/admin/theme">外观</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/write">撰写</a></dt>
</li>
<ul class="child">
<li class="last"><a target="_self" href="/admin/write">撰写文章</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/articles">管理</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/articles">文章</a></li>
<li><a target="_self" href="/admin/categories">分类</a></li>
<li class="last"><a target="_self" href="/admin/tags">标签</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/setting">设置</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/setting">基本</a></li>
<li class="last"><a target="_self" href="/admin/reading">阅读</a></li>
</ul>
</ul>
</nav>
<div class="operate">
<a target="_self" title="最后登录: 7小时前" href="/admin/profile" class="author">admin</a><a target="_self" class="exit" href="/admin/login?logout=true">登出</a><a href="/">网站</a>
</div>
</div>
<div class="main">
<div class="body container">
<div class="typecho-page-title">
<h2>管理文章<a href="http://localhost/admin/write-post.php">新增</a></h2>
</div>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12 typecho-list">
<div class="typecho-list-operate clearfix">
<form method="get">
<div class="operate">
<label><i class="sr-only">全选</i>
<input type="checkbox" class="typecho-table-select-all" />
</label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only">操作</i>选中项 <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="你确认要删除这些文章吗?" href="http://localhost/index.php/action/contents-post-edit?do=delete&_=448a1ea454e9a1e7c93f8dd9b97b087a">删除</a></li>
</ul>
</div>
</div>
<div class="search" role="search">
<input type="text" class="text-s" placeholder="请输入关键字" value="" name="keywords" />
<select name="category">
<option value="">所有分类</option>
<option value="1">默认分类</option>
<option value="2">232</option>
<option value="3">234</option>
<option value="4">2</option>
<option value="5">4</option>
<option value="6">3</option>
<option value="7">5</option>
<option value="8">6</option>
<option value="9">7</option>
<option value="10">8</option>
<option value="11">9</option>
</select>
<button type="submit" class="btn btn-s">筛选</button>
</div>
</form>
</div>
<!-- end .typecho-list-operate -->
<form method="post" name="manage_posts" class="operate-form">
<div class="typecho-table-wrap">
<table class="typecho-list-table">
<colgroup>
<col width="20" />
<col width="6%" />
<col width="45%" />
<col width="" />
<col width="18%" />
<col width="16%" />
</colgroup>
<thead>
<tr>
<th> </th>
<th> </th>
<th>标题</th>
<th>作者</th>
<th>分类</th>
<th>日期</th>
</tr>
</thead>
<tbody>
<tr id="post-3">
<td>
<input type="checkbox" value="3" name="cid[]" />
</td>
<td><a href="http://localhost/admin/manage-comments.php?cid=3" class="balloon-button size-1">0</a></td>
<td>
<a href="http://localhost/admin/write-post.php?cid=3">未命名文档</a>
<a href="http://localhost/index.php/archives/3/" title="浏览 未命名文档"><i class="i-exlink"></i></a>
</td>
<td><a href="http://localhost/admin/manage-posts.php?uid=1">admin</a></td>
<td> <a href="http://localhost/admin/manage-posts.php?category=1">默认分类</a> </td>
<td>
2天前 </td>
</tr>
<tr id="post-1">
<td>
<input type="checkbox" value="1" name="cid[]" />
</td>
<td><a href="http://localhost/admin/manage-comments.php?cid=1" class="balloon-button size-10">1</a></td>
<td>
<a href="http://localhost/admin/write-post.php?cid=1">欢迎使用 Typecho</a>
<a href="http://localhost/index.php/archives/1/" title="浏览 欢迎使用 Typecho"><i class="i-exlink"></i></a>
</td>
<td><a href="http://localhost/admin/manage-posts.php?uid=1">admin</a></td>
<td> <a href="http://localhost/admin/manage-posts.php?category=1">默认分类</a> </td>
<td>
4天前 </td>
</tr>
</tbody>
</table>
</div>
</form>
<!-- end .operate-form -->
<div class="typecho-list-operate clearfix">
<form method="get">
<div class="operate">
<label><i class="sr-only">全选</i>
<input type="checkbox" class="typecho-table-select-all" />
</label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only">操作</i>选中项 <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="你确认要删除这些文章吗?" href="http://localhost/index.php/action/contents-post-edit?do=delete&_=448a1ea454e9a1e7c93f8dd9b97b087a">删除</a></li>
</ul>
</div>
</div>
<ul class="typecho-pager">
<li class="current"><a href="http://localhost/admin/manage-posts.php?page=1">1</a></li>
</ul>
</form>
</div>
<!-- end .typecho-list-operate -->
</div>
<!-- end .typecho-list -->
</div>
<!-- end .typecho-page-main -->
</div>
</div>
<div class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="http://typecho.org" class="i-logo-s">Typecho</a>
<p><a href="http://typecho.org">Typecho</a> 强力驱动, 版本 1.0 (14.10.10)</p>
</div>
<nav class="resource">
<a href="http://docs.typecho.org">帮助文档</a> &bull;
<a href="http://forum.typecho.org">支持论坛</a> &bull;
<a href="https://github.com/typecho/typecho/issues">报告错误</a> &bull;
<a href="http://extends.typecho.org">资源下载</a>
</nav>
</div>
<script src="http://localhost/admin/js/jquery.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/jquery-ui.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/typecho.js?v=14.10.10"></script>
<script>
(function() {
$(document).ready(function() {
// 处理消息机制
(function() {
var prefix = '86a9106ae65537651a8e456835b316ab',
cookies = {
notice: $.cookie(prefix + '__typecho_notice'),
noticeType: $.cookie(prefix + '__typecho_notice_type'),
highlight: $.cookie(prefix + '__typecho_notice_highlight')
},
path = '/';
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
p = $('<div class="message popup ' + cookies.noticeType + '">' + '<ul><li>' + $.parseJSON(cookies.notice).join('</li><li>') + '</li></ul></div>'),
offset = 0;
if (head.length > 0) {
p.insertAfter(head);
offset = head.outerHeight();
} else {
p.prependTo(document.body);
}
function checkScroll() {
if ($(window).scrollTop() >= offset) {
p.css({
'position': 'fixed',
'top': 0
});
} else {
p.css({
'position': 'absolute',
'top': offset
});
}
}
$(window).scroll(function() {
checkScroll();
});
checkScroll();
p.slideDown(function() {
var t = $(this),
color = '#C6D880';
if (t.hasClass('error')) {
color = '#FBC2C4';
} else if (t.hasClass('notice')) {
color = '#FFD324';
}
t.effect('highlight', {
color: color
})
.delay(5000).slideUp(function() {
$(this).remove();
});
});
$.cookie(prefix + '__typecho_notice', null, {
path: path
});
$.cookie(prefix + '__typecho_notice_type', null, {
path: path
});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie(prefix + '__typecho_notice_highlight', null, {
path: path
});
}
})();
// 导航菜单 tab 聚焦时展开下拉菜单
(function() {
$('#typecho-nav-list').find('.parent a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
$(this).parents('.root').find('.child').show();
});
$('.operate').find('a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
});
})();
if ($('.typecho-login').length == 0) {
$('a').each(function() {
var t = $(this),
href = t.attr('href');
if ((href && href[0] == '#') || /^http\:\/\/localhost\/admin\/.*$/.exec(href) || /^http\:\/\/localhost\/index\.php\/action\/[_a-zA-Z0-9\/]+.*$/.exec(href)) {
return;
}
t.attr('target', '_blank');
});
}
});
})();
</script>
<script>
(function() {
$(document).ready(function() {
$('.typecho-list-table').tableSelectable({
checkEl: 'input[type=checkbox]',
rowEl: 'tr',
selectAllEl: '.typecho-table-select-all',
actionEl: '.dropdown-menu a,button.btn-operate'
});
$('.btn-drop').dropdownMenu({
btnEl: '.dropdown-toggle',
menuEl: '.dropdown-menu'
});
});
})();
</script>
</body>
</html>

View File

@@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{.Title}}</title>
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="/static/admin/background.css">
<!--[if lt IE 9]>
<script src="//cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="//cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--[if lt IE 9]>
<div class="alert alert-danger topframe" role="alert">你的浏览器实在<strong>太太太太太太旧了</strong>,放学别走,升级完浏览器再说 <a target="_blank" class="alert-link" href="http://browsehappy.com">立即升级</a></div>
<![endif]-->
<div class="typecho-head-nav clearfix" role="navigation">
<nav id="typecho-nav-list">
<ul class="root {{if .Console}}focus{{end}}">
<li class="parent"><a target="_self" href="/admin/home">控制台</a></dt>
</li>
<ul class="child">
<li {{if eq .Path "/admin/home"}}class="focus"{{end}}><a target="_self" href="/admin/home">概要</a></li>
<li {{if eq .Path "/admin/profile"}}class="focus"{{end}}><a target="_self" href="/admin/profile">个人设置</a></li>
<li {{if eq .Path "/admin/plugin"}}class="focus"{{end}}><a target="_self" href="/admin/plugin">插件</a></li>
<li class="last {{if eq .Path "/admin/theme"}}focus{{end}}"><a target="_self" href="/admin/theme">外观</a></li>
</ul>
</ul>
<ul class="root {{if .Write}}focus{{end}}">
<li class="parent"><a target="_self" href="/admin/write">撰写</a></dt>
</li>
<ul class="child">
<li class="last"><a target="_self" href="/admin/write">撰写文章</a></li>
</ul>
</ul>
<ul class="root {{if .Manage}}focus{{end}}">
<li class="parent"><a target="_self" href="/admin/articles">管理</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/articles">文章</a></li>
<li><a target="_self" href="/admin/series">分类</a></li>
<li class="last"><a target="_self" href="/admin/tags">标签</a></li>
</ul>
</ul>
<ul class="root {{if .Setting}}focus{{end}}">
<li class="parent"><a target="_self" href="/admin/setting">设置</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/setting">基本</a></li>
<li class="last"><a target="_self" href="/admin/reading">阅读</a></li>
</ul>
</ul>
</nav>
<div class="operate">
<a target="_self" title="{{.LastLogin}}" href="/admin/profile" class="author">admin</a><a target="_self" class="exit" href="/admin/login?logout=true">登出</a><a href="/">网站</a>
</div>
</div>
<div class="main">
</div>
<div class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="http://typecho.org" class="i-logo-s">Typecho</a>
<p><a href="http://typecho.org">Typecho</a> 强力驱动, 版本 1.0 (14.10.10)</p>
</div>
<nav class="resource">
<a href="http://docs.typecho.org">帮助文档</a> &bull;
<a href="http://forum.typecho.org">支持论坛</a> &bull;
<a href="https://github.com/typecho/typecho/issues">报告错误</a> &bull;
<a href="http://extends.typecho.org">资源下载</a>
</nav>
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
none

View File

@@ -0,0 +1,38 @@
<!Doctype html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name=viewport>
<meta name=robots content="noindex, nofollow">
<title>Login | {{.BTitle}}</title>
<link rel=stylesheet href="/static/admin/background.css">
</head>
<body class="body-100">
<div class="typecho-login-wrap">
<div class="typecho-login">
<h1><a href="/">{{.BTitle}}</a></h1>
<form action="/admin/api/login" method=post>
<p>
<label for=user class="sr-only">用户名</label>
<input type=text id=user name=user value="" placeholder="用户名" class="text-l w-100">
</p>
<p>
<label for=password class="sr-only">密码</label>
<input type=password id=password name=password class="text-l w-100" placeholder="密码">
</p>
<p>
<label for=code class="sr-only">两步验证</label>
<input type=text id=code name=code class="text-l w-100" placeholder="两步验证">
</p>
<p class=submit>
<button type=submit class="btn btn-l w-100 primary">登录</button>
</p>
</form>
<p class="more-link">管理后台皮肤来自于<a href="http://typecho.org" target=_blank>Typecho</a>.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,393 @@
<!DOCTYPE HTML>
<html class="no-js">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>个人设置 - Hello World - Powered by Typecho</title>
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="http://localhost/admin/css/normalize.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/grid.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/style.css?v=14.10.10">
<!--[if lt IE 9]>
<script src="http://localhost/admin/js/html5shiv.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/respond.js?v=14.10.10"></script>
<![endif]-->
</head>
<body>
<!--[if lt IE 9]>
<div class="message error browsehappy" role="dialog">当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>.</div>
<![endif]-->
<div class="typecho-head-nav clearfix" role="navigation">
<nav id="typecho-nav-list">
<ul class="root focus">
<li class="parent"><a target="_self" href="/admin/home">控制台</a></dt>
</li>
<ul class="child">
<li target="_self" class="focus"><a href="/admin/home">概要</a></li>
<li><a target="_self" href="/admin/profile">个人设置</a></li>
<li><a target="_self" href="/admin/plugin">插件</a></li>
<li class="last"><a target="_self" href="/admin/theme">外观</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/write">撰写</a></dt>
</li>
<ul class="child">
<li class="last"><a target="_self" href="/admin/write">撰写文章</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/articles">管理</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/articles">文章</a></li>
<li><a target="_self" href="/admin/categories">分类</a></li>
<li class="last"><a target="_self" href="/admin/tags">标签</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/setting">设置</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/setting">基本</a></li>
<li class="last"><a target="_self" href="/admin/reading">阅读</a></li>
</ul>
</ul>
</nav>
<div class="operate">
<a target="_self" title="最后登录: 7小时前" href="/admin/profile" class="author">admin</a><a target="_self" class="exit" href="/admin/login?logout=true">登出</a><a href="/">网站</a>
</div>
</div>
<div class="main">
<div class="body container">
<div class="typecho-page-title">
<h2>个人设置</h2>
</div>
<div class="row typecho-page-main">
<div class="col-mb-12 col-tb-3">
<p>
<a href="http://gravatar.com/emails/" title="在 Gravatar 上修改头像"><img class="profile-avatar" src="http://www.gravatar.com/avatar/20a5844bc608d51cdbe28b74495f809d?s=220&amp;r=X&amp;d=mm" alt="admin" /></a>
</p>
<h2>admin</h2>
<p>admin</p>
<p>目前有 <em>2</em> 篇日志, 并有 <em>1</em> 条关于你的评论在 <em>11</em> 个分类中.</p>
<p>最后登录: 2天前</p>
</div>
<div class="col-mb-12 col-tb-6 col-tb-offset-1 typecho-content-panel" role="form">
<section>
<h3>个人资料</h3>
<form action="http://localhost/index.php/action/users-profile?_=48e2b106ce2f611ac20443fb2acdc076" method="post" enctype="application/x-www-form-urlencoded">
<ul class="typecho-option" id="typecho-option-item-screenName-0">
<li>
<label class="typecho-label" for="screenName-0-1">
昵称</label>
<input id="screenName-0-1" name="screenName" type="text" class="text" value="admin" />
<p class="description">
用户昵称可以与用户名不同, 用于前台显示.
<br />如果你将此项留空, 将默认使用用户名.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-url-1">
<li>
<label class="typecho-label" for="url-0-2">
个人主页地址</label>
<input id="url-0-2" name="url" type="text" class="text" value="http://www.typecho.org" />
<p class="description">
此用户的个人主页地址, 请用 <code>http://</code> 开头.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-mail-2">
<li>
<label class="typecho-label" for="mail-0-3">
电子邮箱地址 *</label>
<input id="mail-0-3" name="mail" type="text" class="text" value="webmaster@yourdomain.com" />
<p class="description">
电子邮箱地址将作为此用户的主要联系方式.
<br />请不要与系统中现有的电子邮箱地址重复.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-do-3" style="display:none">
<li>
<input name="do" type="hidden" value="profile" />
</li>
</ul>
<ul class="typecho-option typecho-option-submit" id="typecho-option-item-submit-4">
<li>
<button type="submit" class="btn primary">
更新我的档案</button>
</li>
</ul>
</form>
</section>
<br>
<section id="writing-option">
<h3>撰写设置</h3>
<form action="http://localhost/index.php/action/users-profile?_=48e2b106ce2f611ac20443fb2acdc076" method="post" enctype="application/x-www-form-urlencoded">
<ul class="typecho-option" id="typecho-option-item-markdown-5">
<li>
<label class="typecho-label">
使用 Markdown 语法编辑和解析内容</label>
<span>
<input name="markdown" type="radio" value="0" id="markdown-0" />
<label for="markdown-0">
关闭</label>
</span>
<span>
<input name="markdown" type="radio" value="1" id="markdown-1" checked="true" />
<label for="markdown-1">
打开</label>
</span>
<p class="description">
使用 <a href="http://daringfireball.net/projects/markdown/">Markdown</a> 语法能够使您的撰写过程更加简便直观.
<br />此功能开启不会影响以前没有使用 Markdown 语法编辑的内容.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-autoSave-6">
<li>
<label class="typecho-label">
自动保存</label>
<span>
<input name="autoSave" type="radio" value="0" id="autoSave-0" checked="true" />
<label for="autoSave-0">
关闭</label>
</span>
<span>
<input name="autoSave" type="radio" value="1" id="autoSave-1" />
<label for="autoSave-1">
打开</label>
</span>
<p class="description">
自动保存功能可以更好地保护你的文章不会丢失.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-defaultAllow-7">
<li>
<label class="typecho-label">
默认允许</label>
<span>
<input name="defaultAllow[]" type="checkbox" value="comment" id="defaultAllow-comment" checked="true" />
<label for="defaultAllow-comment">
可以被评论</label>
</span>
<span>
<input name="defaultAllow[]" type="checkbox" value="ping" id="defaultAllow-ping" checked="true" />
<label for="defaultAllow-ping">
可以被引用</label>
</span>
<span>
<input name="defaultAllow[]" type="checkbox" value="feed" id="defaultAllow-feed" checked="true" />
<label for="defaultAllow-feed">
出现在聚合中</label>
</span>
<p class="description">
设置你经常使用的默认允许权限</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-do-8" style="display:none">
<li>
<input name="do" type="hidden" value="options" />
</li>
</ul>
<ul class="typecho-option typecho-option-submit" id="typecho-option-item-submit-9">
<li>
<button type="submit" class="btn primary">
保存设置</button>
</li>
</ul>
</form>
</section>
<br>
<section id="change-password">
<h3>密码修改</h3>
<form action="http://localhost/index.php/action/users-profile?_=48e2b106ce2f611ac20443fb2acdc076" method="post" enctype="application/x-www-form-urlencoded">
<ul class="typecho-option" id="typecho-option-item-password-10">
<li>
<label class="typecho-label" for="password-0-11">
用户密码</label>
<input id="password-0-11" name="password" type="password" class="w-60" />
<p class="description">
为此用户分配一个密码.
<br />建议使用特殊字符与字母、数字的混编样式,以增加系统安全性.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-confirm-11">
<li>
<label class="typecho-label" for="confirm-0-12">
用户密码确认</label>
<input id="confirm-0-12" name="confirm" type="password" class="w-60" />
<p class="description">
请确认你的密码, 与上面输入的密码保持一致.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-do-12" style="display:none">
<li>
<input name="do" type="hidden" value="password" />
</li>
</ul>
<ul class="typecho-option typecho-option-submit" id="typecho-option-item-submit-13">
<li>
<button type="submit" class="btn primary">
更新密码</button>
</li>
</ul>
</form>
</section>
</div>
</div>
</div>
</div>
<div class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="http://typecho.org" class="i-logo-s">Typecho</a>
<p><a href="http://typecho.org">Typecho</a> 强力驱动, 版本 1.0 (14.10.10)</p>
</div>
<nav class="resource">
<a href="http://docs.typecho.org">帮助文档</a> &bull;
<a href="http://forum.typecho.org">支持论坛</a> &bull;
<a href="https://github.com/typecho/typecho/issues">报告错误</a> &bull;
<a href="http://extends.typecho.org">资源下载</a>
</nav>
</div>
<script src="http://localhost/admin/js/jquery.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/jquery-ui.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/typecho.js?v=14.10.10"></script>
<script>
(function() {
$(document).ready(function() {
// 处理消息机制
(function() {
var prefix = '86a9106ae65537651a8e456835b316ab',
cookies = {
notice: $.cookie(prefix + '__typecho_notice'),
noticeType: $.cookie(prefix + '__typecho_notice_type'),
highlight: $.cookie(prefix + '__typecho_notice_highlight')
},
path = '/';
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
p = $('<div class="message popup ' + cookies.noticeType + '">' + '<ul><li>' + $.parseJSON(cookies.notice).join('</li><li>') + '</li></ul></div>'),
offset = 0;
if (head.length > 0) {
p.insertAfter(head);
offset = head.outerHeight();
} else {
p.prependTo(document.body);
}
function checkScroll() {
if ($(window).scrollTop() >= offset) {
p.css({
'position': 'fixed',
'top': 0
});
} else {
p.css({
'position': 'absolute',
'top': offset
});
}
}
$(window).scroll(function() {
checkScroll();
});
checkScroll();
p.slideDown(function() {
var t = $(this),
color = '#C6D880';
if (t.hasClass('error')) {
color = '#FBC2C4';
} else if (t.hasClass('notice')) {
color = '#FFD324';
}
t.effect('highlight', {
color: color
})
.delay(5000).slideUp(function() {
$(this).remove();
});
});
$.cookie(prefix + '__typecho_notice', null, {
path: path
});
$.cookie(prefix + '__typecho_notice_type', null, {
path: path
});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie(prefix + '__typecho_notice_highlight', null, {
path: path
});
}
})();
// 导航菜单 tab 聚焦时展开下拉菜单
(function() {
$('#typecho-nav-list').find('.parent a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
$(this).parents('.root').find('.child').show();
});
$('.operate').find('a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
});
})();
if ($('.typecho-login').length == 0) {
$('a').each(function() {
var t = $(this),
href = t.attr('href');
if ((href && href[0] == '#') || /^http\:\/\/localhost\/admin\/.*$/.exec(href) || /^http\:\/\/localhost\/index\.php\/action\/[_a-zA-Z0-9\/]+.*$/.exec(href)) {
return;
}
t.attr('target', '_blank');
});
}
});
})();
</script>
<script>
(function() {
$(document).ready(function() {
var error = $('.typecho-option .error:first');
if (error.length > 0) {
$('html,body').scrollTop(error.parents('.typecho-option').offset().top);
}
$('form').submit(function() {
if (this.submitted) {
return false;
} else {
this.submitted = true;
}
});
$('label input[type=text]').click(function(e) {
var check = $('#' + $(this).parents('label').attr('for'));
check.prop('checked', true);
return false;
});
});
})();
</script>
</body>
</html>

View File

@@ -0,0 +1,311 @@
<!DOCTYPE HTML>
<html class="no-js">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>阅读设置 - Hello World - Powered by Typecho</title>
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="http://localhost/admin/css/normalize.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/grid.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/style.css?v=14.10.10">
<!--[if lt IE 9]>
<script src="http://localhost/admin/js/html5shiv.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/respond.js?v=14.10.10"></script>
<![endif]-->
</head>
<body>
<!--[if lt IE 9]>
<div class="message error browsehappy" role="dialog">当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>.</div>
<![endif]-->
<div class="typecho-head-nav clearfix" role="navigation">
<nav id="typecho-nav-list">
<ul class="root focus">
<li class="parent"><a target="_self" href="/admin/home">控制台</a></dt>
</li>
<ul class="child">
<li target="_self" class="focus"><a href="/admin/home">概要</a></li>
<li><a target="_self" href="/admin/profile">个人设置</a></li>
<li><a target="_self" href="/admin/plugin">插件</a></li>
<li class="last"><a target="_self" href="/admin/theme">外观</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/write">撰写</a></dt>
</li>
<ul class="child">
<li class="last"><a target="_self" href="/admin/write">撰写文章</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/articles">管理</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/articles">文章</a></li>
<li><a target="_self" href="/admin/categories">分类</a></li>
<li class="last"><a target="_self" href="/admin/tags">标签</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/setting">设置</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/setting">基本</a></li>
<li class="last"><a target="_self" href="/admin/reading">阅读</a></li>
</ul>
</ul>
</nav>
<div class="operate">
<a target="_self" title="最后登录: 7小时前" href="/admin/profile" class="author">admin</a><a target="_self" class="exit" href="/admin/login?logout=true">登出</a><a href="/">网站</a>
</div>
</div>
<div class="main">
<div class="body container">
<div class="typecho-page-title">
<h2>阅读设置</h2>
</div>
<div class="row typecho-page-main" role="form">
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
<form action="http://localhost/index.php/action/options-reading?_=e53d9ccaafcd7253533d0586ebb24d30" method="post" enctype="application/x-www-form-urlencoded">
<ul class="typecho-option" id="typecho-option-item-postDateFormat-0">
<li>
<label class="typecho-label" for="postDateFormat-0-1">
文章日期格式</label>
<input id="postDateFormat-0-1" name="postDateFormat" type="text" class="w-40 mono" value="Y-m-d" />
<p class="description">
此格式用于指定显示在文章归档中的日期默认显示格式.
<br />在某些主题中这个格式可能不会生效, 因为主题作者可以自定义日期格式.
<br />请参考 <a href="http://www.php.net/manual/zh/function.date.php">PHP 日期格式写法</a>.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-frontPage-1">
<li>
<label class="typecho-label">
站点首页</label>
<span class="multiline">
<input name="frontPage" type="radio" value="recent" id="frontPage-recent" checked="true" />
<label for="frontPage-recent">
显示最新发布的文章</label>
</span>
<span class="multiline">
<input name="frontPage" type="radio" value="page" id="frontPage-page" />
<label for="frontPage-page">
使用 </label><select name="frontPagePage" id="frontPage-frontPagePage"><option value="2">关于</option></select><label for="frontPage-frontPagePage"> 页面作为首页</label></span><span class="multiline front-archive hidden"><input type="checkbox" id="frontArchive" name="frontArchive" value="1" />
<label for="frontArchive">同时将文章列表页路径更改为 <input type="text" name="archivePattern" class="w-20 mono" value="/blog/" /></label></label>
</span>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-postsListSize-2">
<li>
<label class="typecho-label" for="postsListSize-0-3">
文章列表数目</label>
<input id="postsListSize-0-3" name="postsListSize" type="text" class="w-20" value="10" />
<p class="description">
此数目用于指定显示在侧边栏中的文章列表数目.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-pageSize-3">
<li>
<label class="typecho-label" for="pageSize-0-4">
每页文章数目</label>
<input id="pageSize-0-4" name="pageSize" type="text" class="w-20" value="5" />
<p class="description">
此数目用于指定文章归档输出时每页显示的文章数目.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-feedFullText-4">
<li>
<label class="typecho-label">
聚合全文输出</label>
<span>
<input name="feedFullText" type="radio" value="0" id="feedFullText-0" />
<label for="feedFullText-0">
仅输出摘要</label>
</span>
<span>
<input name="feedFullText" type="radio" value="1" id="feedFullText-1" checked="true" />
<label for="feedFullText-1">
全文输出</label>
</span>
<p class="description">
如果你不希望在聚合中输出文章全文,请使用仅输出摘要选项.
<br />摘要的文字取决于你在文章中使用分隔符的位置.</p>
</li>
</ul>
<ul class="typecho-option typecho-option-submit" id="typecho-option-item-submit-5">
<li>
<button type="submit" class="btn primary">
保存设置</button>
</li>
</ul>
</form>
</div>
</div>
</div>
</div>
<div class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="http://typecho.org" class="i-logo-s">Typecho</a>
<p><a href="http://typecho.org">Typecho</a> 强力驱动, 版本 1.0 (14.10.10)</p>
</div>
<nav class="resource">
<a href="http://docs.typecho.org">帮助文档</a> &bull;
<a href="http://forum.typecho.org">支持论坛</a> &bull;
<a href="https://github.com/typecho/typecho/issues">报告错误</a> &bull;
<a href="http://extends.typecho.org">资源下载</a>
</nav>
</div>
<script src="http://localhost/admin/js/jquery.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/jquery-ui.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/typecho.js?v=14.10.10"></script>
<script>
(function() {
$(document).ready(function() {
// 处理消息机制
(function() {
var prefix = '86a9106ae65537651a8e456835b316ab',
cookies = {
notice: $.cookie(prefix + '__typecho_notice'),
noticeType: $.cookie(prefix + '__typecho_notice_type'),
highlight: $.cookie(prefix + '__typecho_notice_highlight')
},
path = '/';
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
p = $('<div class="message popup ' + cookies.noticeType + '">' + '<ul><li>' + $.parseJSON(cookies.notice).join('</li><li>') + '</li></ul></div>'),
offset = 0;
if (head.length > 0) {
p.insertAfter(head);
offset = head.outerHeight();
} else {
p.prependTo(document.body);
}
function checkScroll() {
if ($(window).scrollTop() >= offset) {
p.css({
'position': 'fixed',
'top': 0
});
} else {
p.css({
'position': 'absolute',
'top': offset
});
}
}
$(window).scroll(function() {
checkScroll();
});
checkScroll();
p.slideDown(function() {
var t = $(this),
color = '#C6D880';
if (t.hasClass('error')) {
color = '#FBC2C4';
} else if (t.hasClass('notice')) {
color = '#FFD324';
}
t.effect('highlight', {
color: color
})
.delay(5000).slideUp(function() {
$(this).remove();
});
});
$.cookie(prefix + '__typecho_notice', null, {
path: path
});
$.cookie(prefix + '__typecho_notice_type', null, {
path: path
});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie(prefix + '__typecho_notice_highlight', null, {
path: path
});
}
})();
// 导航菜单 tab 聚焦时展开下拉菜单
(function() {
$('#typecho-nav-list').find('.parent a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
$(this).parents('.root').find('.child').show();
});
$('.operate').find('a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
});
})();
if ($('.typecho-login').length == 0) {
$('a').each(function() {
var t = $(this),
href = t.attr('href');
if ((href && href[0] == '#') || /^http\:\/\/localhost\/admin\/.*$/.exec(href) || /^http\:\/\/localhost\/index\.php\/action\/[_a-zA-Z0-9\/]+.*$/.exec(href)) {
return;
}
t.attr('target', '_blank');
});
}
});
})();
</script>
<script>
(function() {
$(document).ready(function() {
var error = $('.typecho-option .error:first');
if (error.length > 0) {
$('html,body').scrollTop(error.parents('.typecho-option').offset().top);
}
$('form').submit(function() {
if (this.submitted) {
return false;
} else {
this.submitted = true;
}
});
$('label input[type=text]').click(function(e) {
var check = $('#' + $(this).parents('label').attr('for'));
check.prop('checked', true);
return false;
});
});
})();
</script>
<script>
$('#frontPage-recent,#frontPage-page,#frontPage-file').change(function() {
var t = $(this);
if (t.prop('checked')) {
if ('frontPage-recent' == t.attr('id')) {
$('.front-archive').addClass('hidden');
} else {
$('.front-archive').insertAfter(t.parent()).removeClass('hidden');
}
}
});
</script>
</body>
</html>

View File

@@ -0,0 +1,480 @@
<!DOCTYPE HTML>
<html class="no-js">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>管理分类 - Hello World - Powered by Typecho</title>
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="http://localhost/admin/css/normalize.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/grid.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/style.css?v=14.10.10">
<!--[if lt IE 9]>
<script src="http://localhost/admin/js/html5shiv.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/respond.js?v=14.10.10"></script>
<![endif]-->
</head>
<body>
<!--[if lt IE 9]>
<div class="message error browsehappy" role="dialog">当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>.</div>
<![endif]-->
<div class="typecho-head-nav clearfix" role="navigation">
<nav id="typecho-nav-list">
<ul class="root focus">
<li class="parent"><a target="_self" href="/admin/home">控制台</a></dt>
</li>
<ul class="child">
<li target="_self" class="focus"><a href="/admin/home">概要</a></li>
<li><a target="_self" href="/admin/profile">个人设置</a></li>
<li><a target="_self" href="/admin/plugin">插件</a></li>
<li class="last"><a target="_self" href="/admin/theme">外观</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/write">撰写</a></dt>
</li>
<ul class="child">
<li class="last"><a target="_self" href="/admin/write">撰写文章</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/articles">管理</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/articles">文章</a></li>
<li><a target="_self" href="/admin/categories">分类</a></li>
<li class="last"><a target="_self" href="/admin/tags">标签</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/setting">设置</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/setting">基本</a></li>
<li class="last"><a target="_self" href="/admin/reading">阅读</a></li>
</ul>
</ul>
</nav>
<div class="operate">
<a target="_self" title="最后登录: 7小时前" href="/admin/profile" class="author">admin</a><a target="_self" class="exit" href="/admin/login?logout=true">登出</a><a href="/">网站</a>
</div>
</div>
<div class="main">
<div class="body container">
<div class="typecho-page-title">
<h2>管理分类<a href="http://localhost/admin/category.php">新增</a></h2>
</div>
<div class="row typecho-page-main manage-metas">
<div class="col-mb-12" role="main">
<form method="post" name="manage_categories" class="operate-form">
<div class="typecho-list-operate clearfix">
<div class="operate">
<label><i class="sr-only">全选</i>
<input type="checkbox" class="typecho-table-select-all" />
</label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only">操作</i>选中项 <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="此分类下的所有内容将被删除, 你确认要删除这些分类吗?" href="http://localhost/index.php/action/metas-category-edit?do=delete&_=7fe4662ec063c94e7072ce37ddbe3abc">删除</a></li>
<li><a lang="刷新分类可能需要等待较长时间, 你确认要刷新这些分类吗?" href="http://localhost/index.php/action/metas-category-edit?do=refresh&_=7fe4662ec063c94e7072ce37ddbe3abc">刷新</a></li>
<li class="multiline">
<button type="button" class="btn merge btn-s" rel="http://localhost/index.php/action/metas-category-edit?do=merge&_=7fe4662ec063c94e7072ce37ddbe3abc">合并到</button>
<select name="merge">
<option value="1">默认分类</option>
<option value="2">232</option>
<option value="3">234</option>
<option value="4">2</option>
<option value="5">4</option>
<option value="6">3</option>
<option value="7">5</option>
<option value="8">6</option>
<option value="9">7</option>
<option value="10">8</option>
<option value="11">9</option>
</select>
</li>
</ul>
</div>
</div>
<div class="search" role="search">
</div>
</div>
<div class="typecho-table-wrap">
<table class="typecho-list-table">
<colgroup>
<col width="20" />
<col width="30%" />
<col width="15%" />
<col width="25%" />
<col width="" />
<col width="10%" />
</colgroup>
<thead>
<tr class="nodrag">
<th> </th>
<th>名称</th>
<th>子分类</th>
<th>缩略名</th>
<th> </th>
<th>文章数</th>
</tr>
</thead>
<tbody>
<tr id="mid-category-1">
<td>
<input type="checkbox" value="1" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=1">默认分类</a>
<a href="http://localhost/index.php/category/default/" title="浏览 默认分类"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=1">新增</a>
</td>
<td>default</td>
<td>
默认 </td>
<td><a class="balloon-button left size-10" href="http://localhost/admin/manage-posts.php?category=1">2</a></td>
</tr>
<tr id="mid-category-2">
<td>
<input type="checkbox" value="2" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=2">232</a>
<a href="http://localhost/index.php/category/2342/" title="浏览 232"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=2">新增</a>
</td>
<td>2342</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=2&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=2">0</a></td>
</tr>
<tr id="mid-category-3">
<td>
<input type="checkbox" value="3" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=3">234</a>
<a href="http://localhost/index.php/category/23423/" title="浏览 234"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=3">新增</a>
</td>
<td>23423</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=3&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=3">0</a></td>
</tr>
<tr id="mid-category-4">
<td>
<input type="checkbox" value="4" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=4">2</a>
<a href="http://localhost/index.php/category/2/" title="浏览 2"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=4">新增</a>
</td>
<td>2</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=4&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=4">0</a></td>
</tr>
<tr id="mid-category-5">
<td>
<input type="checkbox" value="5" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=5">4</a>
<a href="http://localhost/index.php/category/4/" title="浏览 4"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=5">新增</a>
</td>
<td>4</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=5&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=5">0</a></td>
</tr>
<tr id="mid-category-6">
<td>
<input type="checkbox" value="6" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=6">3</a>
<a href="http://localhost/index.php/category/3/" title="浏览 3"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=6">新增</a>
</td>
<td>3</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=6&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=6">0</a></td>
</tr>
<tr id="mid-category-7">
<td>
<input type="checkbox" value="7" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=7">5</a>
<a href="http://localhost/index.php/category/5/" title="浏览 5"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=7">新增</a>
</td>
<td>5</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=7&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=7">0</a></td>
</tr>
<tr id="mid-category-8">
<td>
<input type="checkbox" value="8" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=8">6</a>
<a href="http://localhost/index.php/category/6/" title="浏览 6"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=8">新增</a>
</td>
<td>6</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=8&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=8">0</a></td>
</tr>
<tr id="mid-category-9">
<td>
<input type="checkbox" value="9" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=9">7</a>
<a href="http://localhost/index.php/category/7/" title="浏览 7"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=9">新增</a>
</td>
<td>7</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=9&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=9">0</a></td>
</tr>
<tr id="mid-category-10">
<td>
<input type="checkbox" value="10" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=10">8</a>
<a href="http://localhost/index.php/category/8/" title="浏览 8"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=10">新增</a>
</td>
<td>8</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=10&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=10">0</a></td>
</tr>
<tr id="mid-category-11">
<td>
<input type="checkbox" value="11" name="mid[]" />
</td>
<td><a href="http://localhost/admin/category.php?mid=11">9</a>
<a href="http://localhost/index.php/category/9/" title="浏览 9"><i class="i-exlink"></i></a>
</td>
<td>
<a href="http://localhost/admin/category.php?parent=11">新增</a>
</td>
<td>9</td>
<td>
<a class="hidden-by-mouse" href="http://localhost/index.php/action/metas-category-edit?do=default&mid=11&_=7fe4662ec063c94e7072ce37ddbe3abc" title="设为默认">默认</a>
</td>
<td><a class="balloon-button left size-1" href="http://localhost/admin/manage-posts.php?category=11">0</a></td>
</tr>
</tbody>
</table>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="http://typecho.org" class="i-logo-s">Typecho</a>
<p><a href="http://typecho.org">Typecho</a> 强力驱动, 版本 1.0 (14.10.10)</p>
</div>
<nav class="resource">
<a href="http://docs.typecho.org">帮助文档</a> &bull;
<a href="http://forum.typecho.org">支持论坛</a> &bull;
<a href="https://github.com/typecho/typecho/issues">报告错误</a> &bull;
<a href="http://extends.typecho.org">资源下载</a>
</nav>
</div>
<script src="http://localhost/admin/js/jquery.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/jquery-ui.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/typecho.js?v=14.10.10"></script>
<script>
(function() {
$(document).ready(function() {
// 处理消息机制
(function() {
var prefix = '86a9106ae65537651a8e456835b316ab',
cookies = {
notice: $.cookie(prefix + '__typecho_notice'),
noticeType: $.cookie(prefix + '__typecho_notice_type'),
highlight: $.cookie(prefix + '__typecho_notice_highlight')
},
path = '/';
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
p = $('<div class="message popup ' + cookies.noticeType + '">' + '<ul><li>' + $.parseJSON(cookies.notice).join('</li><li>') + '</li></ul></div>'),
offset = 0;
if (head.length > 0) {
p.insertAfter(head);
offset = head.outerHeight();
} else {
p.prependTo(document.body);
}
function checkScroll() {
if ($(window).scrollTop() >= offset) {
p.css({
'position': 'fixed',
'top': 0
});
} else {
p.css({
'position': 'absolute',
'top': offset
});
}
}
$(window).scroll(function() {
checkScroll();
});
checkScroll();
p.slideDown(function() {
var t = $(this),
color = '#C6D880';
if (t.hasClass('error')) {
color = '#FBC2C4';
} else if (t.hasClass('notice')) {
color = '#FFD324';
}
t.effect('highlight', {
color: color
})
.delay(5000).slideUp(function() {
$(this).remove();
});
});
$.cookie(prefix + '__typecho_notice', null, {
path: path
});
$.cookie(prefix + '__typecho_notice_type', null, {
path: path
});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie(prefix + '__typecho_notice_highlight', null, {
path: path
});
}
})();
// 导航菜单 tab 聚焦时展开下拉菜单
(function() {
$('#typecho-nav-list').find('.parent a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
$(this).parents('.root').find('.child').show();
});
$('.operate').find('a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
});
})();
if ($('.typecho-login').length == 0) {
$('a').each(function() {
var t = $(this),
href = t.attr('href');
if ((href && href[0] == '#') || /^http\:\/\/localhost\/admin\/.*$/.exec(href) || /^http\:\/\/localhost\/index\.php\/action\/[_a-zA-Z0-9\/]+.*$/.exec(href)) {
return;
}
t.attr('target', '_blank');
});
}
});
})();
</script>
<script type="text/javascript">
(function() {
$(document).ready(function() {
var table = $('.typecho-list-table').tableDnD({
onDrop: function() {
var ids = [];
$('input[type=checkbox]', table).each(function() {
ids.push($(this).val());
});
$.post('http://localhost/index.php/action/metas-category-edit?do=sort&_=7fe4662ec063c94e7072ce37ddbe3abc',
$.param({
mid: ids
}));
$('tr', table).each(function(i) {
if (i % 2) {
$(this).addClass('even');
} else {
$(this).removeClass('even');
}
});
}
});
table.tableSelectable({
checkEl: 'input[type=checkbox]',
rowEl: 'tr',
selectAllEl: '.typecho-table-select-all',
actionEl: '.dropdown-menu a'
});
$('.btn-drop').dropdownMenu({
btnEl: '.dropdown-toggle',
menuEl: '.dropdown-menu'
});
$('.dropdown-menu button.merge').click(function() {
var btn = $(this);
btn.parents('form').attr('action', btn.attr('rel')).submit();
});
});
})();
</script>
</body>
</html>

View File

@@ -0,0 +1,374 @@
<!DOCTYPE HTML>
<html class="no-js">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>基本设置 - Hello World - Powered by Typecho</title>
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="http://localhost/admin/css/normalize.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/grid.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/style.css?v=14.10.10">
<!--[if lt IE 9]>
<script src="http://localhost/admin/js/html5shiv.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/respond.js?v=14.10.10"></script>
<![endif]-->
</head>
<body>
<!--[if lt IE 9]>
<div class="message error browsehappy" role="dialog">当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>.</div>
<![endif]-->
<div class="typecho-head-nav clearfix" role="navigation">
<nav id="typecho-nav-list">
<ul class="root focus">
<li class="parent"><a target="_self" href="/admin/home">控制台</a></dt>
</li>
<ul class="child">
<li target="_self" class="focus"><a href="/admin/home">概要</a></li>
<li><a target="_self" href="/admin/profile">个人设置</a></li>
<li><a target="_self" href="/admin/plugin">插件</a></li>
<li class="last"><a target="_self" href="/admin/theme">外观</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/write">撰写</a></dt>
</li>
<ul class="child">
<li class="last"><a target="_self" href="/admin/write">撰写文章</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/articles">管理</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/articles">文章</a></li>
<li><a target="_self" href="/admin/categories">分类</a></li>
<li class="last"><a target="_self" href="/admin/tags">标签</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/setting">设置</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/setting">基本</a></li>
<li class="last"><a target="_self" href="/admin/reading">阅读</a></li>
</ul>
</ul>
</nav>
<div class="operate">
<a target="_self" title="最后登录: 7小时前" href="/admin/profile" class="author">admin</a><a target="_self" class="exit" href="/admin/login?logout=true">登出</a><a href="/">网站</a>
</div>
</div>
<div class="main">
<div class="body container">
<div class="typecho-page-title">
<h2>基本设置</h2>
</div>
<div class="row typecho-page-main" role="form">
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
<form action="http://localhost/index.php/action/options-general?_=f90abdb2b52a2818286e72429dfcc97b" method="post" enctype="application/x-www-form-urlencoded">
<ul class="typecho-option" id="typecho-option-item-title-0">
<li>
<label class="typecho-label" for="title-0-1">
站点名称</label>
<input id="title-0-1" name="title" type="text" class="w-100" value="Hello World" />
<p class="description">
站点的名称将显示在网页的标题处.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-siteUrl-1">
<li>
<label class="typecho-label" for="siteUrl-0-2">
站点地址</label>
<input id="siteUrl-0-2" name="siteUrl" type="text" class="w-100 mono" value="http://localhost" />
<p class="description">
站点地址主要用于生成内容的永久链接.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-description-2">
<li>
<label class="typecho-label" for="description-0-3">
站点描述</label>
<input id="description-0-3" name="description" type="text" class="text" value="Just So So ..." />
<p class="description">
站点描述将显示在网页代码的头部.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-keywords-3">
<li>
<label class="typecho-label" for="keywords-0-4">
关键词</label>
<input id="keywords-0-4" name="keywords" type="text" class="text" value="typecho,php,blog" />
<p class="description">
请以半角逗号 "," 分割多个关键字.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-allowRegister-4">
<li>
<label class="typecho-label">
是否允许注册</label>
<span>
<input name="allowRegister" type="radio" value="0" id="allowRegister-0" checked="true" />
<label for="allowRegister-0">
不允许</label>
</span>
<span>
<input name="allowRegister" type="radio" value="1" id="allowRegister-1" />
<label for="allowRegister-1">
允许</label>
</span>
<p class="description">
允许访问者注册到你的网站, 默认的注册用户不享有任何写入权限.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-timezone-5">
<li>
<label class="typecho-label" for="timezone-0-6">
时区</label>
<select name="timezone" id="timezone-0-6">
<option value="0">
格林威治(子午线)标准时间 (GMT)</option>
<option value="3600">
中欧标准时间 阿姆斯特丹,荷兰,法国 (GMT +1)</option>
<option value="7200">
东欧标准时间 布加勒斯特,塞浦路斯,希腊 (GMT +2)</option>
<option value="10800">
莫斯科时间 伊拉克,埃塞俄比亚,马达加斯加 (GMT +3)</option>
<option value="14400">
第比利斯时间 阿曼,毛里塔尼亚,留尼汪岛 (GMT +4)</option>
<option value="18000">
新德里时间 巴基斯坦,马尔代夫 (GMT +5)</option>
<option value="21600">
科伦坡时间 孟加拉 (GMT +6)</option>
<option value="25200">
曼谷雅加达 柬埔寨,苏门答腊,老挝 (GMT +7)</option>
<option value="28800" selected="true">
北京时间 香港,新加坡,越南 (GMT +8)</option>
<option value="32400">
东京平壤时间 西伊里安,摩鹿加群岛 (GMT +9)</option>
<option value="36000">
悉尼关岛时间 塔斯马尼亚岛,新几内亚 (GMT +10)</option>
<option value="39600">
所罗门群岛 库页岛 (GMT +11)</option>
<option value="43200">
惠灵顿时间 新西兰,斐济群岛 (GMT +12)</option>
<option value="-3600">
佛德尔群岛 亚速尔群岛,葡属几内亚 (GMT -1)</option>
<option value="-7200">
大西洋中部时间 格陵兰 (GMT -2)</option>
<option value="-10800">
布宜诺斯艾利斯 乌拉圭,法属圭亚那 (GMT -3)</option>
<option value="-14400">
智利巴西 委内瑞拉,玻利维亚 (GMT -4)</option>
<option value="-18000">
纽约渥太华 古巴,哥伦比亚,牙买加 (GMT -5)</option>
<option value="-21600">
墨西哥城时间 洪都拉斯,危地马拉,哥斯达黎加 (GMT -6)</option>
<option value="-25200">
美国丹佛时间 (GMT -7)</option>
<option value="-28800">
美国旧金山时间 (GMT -8)</option>
<option value="-32400">
阿拉斯加时间 (GMT -9)</option>
<option value="-36000">
夏威夷群岛 (GMT -10)</option>
<option value="-39600">
东萨摩亚群岛 (GMT -11)</option>
<option value="-43200">
艾尼威托克岛 (GMT -12)</option>
</select>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-attachmentTypes-6">
<li>
<label class="typecho-label">
允许上传的文件类型</label>
<span class="multiline">
<input name="attachmentTypes[]" type="checkbox" value="@image@" id="attachmentTypes-image" checked="true" />
<label for="attachmentTypes-image">
图片文件 <code>(gif jpg jpeg png tiff bmp)</code></label>
</span>
<span class="multiline">
<input name="attachmentTypes[]" type="checkbox" value="@media@" id="attachmentTypes-media" />
<label for="attachmentTypes-media">
多媒体文件 <code>(mp3 wmv wma rmvb rm avi flv)</code></label>
</span>
<span class="multiline">
<input name="attachmentTypes[]" type="checkbox" value="@doc@" id="attachmentTypes-doc" />
<label for="attachmentTypes-doc">
常用档案文件 <code>(txt doc docx xls xlsx ppt pptx zip rar pdf)</code></label>
</span>
<span class="multiline">
<input name="attachmentTypes[]" type="checkbox" value="@other@" id="attachmentTypes-other" />
<label for="attachmentTypes-other">
其他格式 <input type="text" class="w-50 text-s mono" name="attachmentTypesOther" value="" /></label>
</span>
<p class="description">
用逗号 "," 将后缀名隔开, 例如: <code>cpp, h, mak</code></p>
</li>
</ul>
<ul class="typecho-option typecho-option-submit" id="typecho-option-item-submit-7">
<li>
<button type="submit" class="btn primary">
保存设置</button>
</li>
</ul>
</form>
</div>
</div>
</div>
</div>
<div class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="http://typecho.org" class="i-logo-s">Typecho</a>
<p><a href="http://typecho.org">Typecho</a> 强力驱动, 版本 1.0 (14.10.10)</p>
</div>
<nav class="resource">
<a href="http://docs.typecho.org">帮助文档</a> &bull;
<a href="http://forum.typecho.org">支持论坛</a> &bull;
<a href="https://github.com/typecho/typecho/issues">报告错误</a> &bull;
<a href="http://extends.typecho.org">资源下载</a>
</nav>
</div>
<script src="http://localhost/admin/js/jquery.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/jquery-ui.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/typecho.js?v=14.10.10"></script>
<script>
(function() {
$(document).ready(function() {
// 处理消息机制
(function() {
var prefix = '86a9106ae65537651a8e456835b316ab',
cookies = {
notice: $.cookie(prefix + '__typecho_notice'),
noticeType: $.cookie(prefix + '__typecho_notice_type'),
highlight: $.cookie(prefix + '__typecho_notice_highlight')
},
path = '/';
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
p = $('<div class="message popup ' + cookies.noticeType + '">' + '<ul><li>' + $.parseJSON(cookies.notice).join('</li><li>') + '</li></ul></div>'),
offset = 0;
if (head.length > 0) {
p.insertAfter(head);
offset = head.outerHeight();
} else {
p.prependTo(document.body);
}
function checkScroll() {
if ($(window).scrollTop() >= offset) {
p.css({
'position': 'fixed',
'top': 0
});
} else {
p.css({
'position': 'absolute',
'top': offset
});
}
}
$(window).scroll(function() {
checkScroll();
});
checkScroll();
p.slideDown(function() {
var t = $(this),
color = '#C6D880';
if (t.hasClass('error')) {
color = '#FBC2C4';
} else if (t.hasClass('notice')) {
color = '#FFD324';
}
t.effect('highlight', {
color: color
})
.delay(5000).slideUp(function() {
$(this).remove();
});
});
$.cookie(prefix + '__typecho_notice', null, {
path: path
});
$.cookie(prefix + '__typecho_notice_type', null, {
path: path
});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie(prefix + '__typecho_notice_highlight', null, {
path: path
});
}
})();
// 导航菜单 tab 聚焦时展开下拉菜单
(function() {
$('#typecho-nav-list').find('.parent a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
$(this).parents('.root').find('.child').show();
});
$('.operate').find('a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
});
})();
if ($('.typecho-login').length == 0) {
$('a').each(function() {
var t = $(this),
href = t.attr('href');
if ((href && href[0] == '#') || /^http\:\/\/localhost\/admin\/.*$/.exec(href) || /^http\:\/\/localhost\/index\.php\/action\/[_a-zA-Z0-9\/]+.*$/.exec(href)) {
return;
}
t.attr('target', '_blank');
});
}
});
})();
</script>
<script>
(function() {
$(document).ready(function() {
var error = $('.typecho-option .error:first');
if (error.length > 0) {
$('html,body').scrollTop(error.parents('.typecho-option').offset().top);
}
$('form').submit(function() {
if (this.submitted) {
return false;
} else {
this.submitted = true;
}
});
$('label input[type=text]').click(function(e) {
var check = $('#' + $(this).parents('label').attr('for'));
check.prop('checked', true);
return false;
});
});
})();
</script>
</body>
</html>

View File

@@ -0,0 +1,321 @@
<!DOCTYPE HTML>
<html class="no-js">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>管理标签 - Hello World - Powered by Typecho</title>
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="http://localhost/admin/css/normalize.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/grid.css?v=14.10.10">
<link rel="stylesheet" href="http://localhost/admin/css/style.css?v=14.10.10">
<!--[if lt IE 9]>
<script src="http://localhost/admin/js/html5shiv.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/respond.js?v=14.10.10"></script>
<![endif]-->
</head>
<body>
<!--[if lt IE 9]>
<div class="message error browsehappy" role="dialog">当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>.</div>
<![endif]-->
<div class="typecho-head-nav clearfix" role="navigation">
<nav id="typecho-nav-list">
<ul class="root focus">
<li class="parent"><a target="_self" href="/admin/home">控制台</a></dt>
</li>
<ul class="child">
<li target="_self" class="focus"><a href="/admin/home">概要</a></li>
<li><a target="_self" href="/admin/profile">个人设置</a></li>
<li><a target="_self" href="/admin/plugin">插件</a></li>
<li class="last"><a target="_self" href="/admin/theme">外观</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/write">撰写</a></dt>
</li>
<ul class="child">
<li class="last"><a target="_self" href="/admin/write">撰写文章</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/articles">管理</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/articles">文章</a></li>
<li><a target="_self" href="/admin/categories">分类</a></li>
<li class="last"><a target="_self" href="/admin/tags">标签</a></li>
</ul>
</ul>
<ul class="root">
<li class="parent"><a target="_self" href="/admin/setting">设置</a></dt>
</li>
<ul class="child">
<li><a target="_self" href="/admin/setting">基本</a></li>
<li class="last"><a target="_self" href="/admin/reading">阅读</a></li>
</ul>
</ul>
</nav>
<div class="operate">
<a target="_self" title="最后登录: 7小时前" href="/admin/profile" class="author">admin</a><a target="_self" class="exit" href="/admin/login?logout=true">登出</a><a href="/">网站</a>
</div>
</div>
<div class="main">
<div class="body container">
<div class="typecho-page-title">
<h2>管理标签</h2>
</div>
<div class="row typecho-page-main manage-metas">
<div class="col-mb-12 col-tb-8" role="main">
<form method="post" name="manage_tags" class="operate-form">
<div class="typecho-list-operate clearfix">
<div class="operate">
<label><i class="sr-only">全选</i>
<input type="checkbox" class="typecho-table-select-all" />
</label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only">操作</i>选中项 <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="你确认要删除这些标签吗?" href="http://localhost/index.php/action/metas-tag-edit?do=delete&_=2e6004cd103d97bddfccf02fddd0ecbe">删除</a></li>
<li><a lang="刷新标签可能需要等待较长时间, 你确认要刷新这些标签吗?" href="http://localhost/index.php/action/metas-tag-edit?do=refresh&_=2e6004cd103d97bddfccf02fddd0ecbe">刷新</a></li>
<li class="multiline">
<button type="button" class="btn btn-s merge" rel="http://localhost/index.php/action/metas-tag-edit?do=merge&_=2e6004cd103d97bddfccf02fddd0ecbe">合并到</button>
<input type="text" name="merge" class="text-s" />
</li>
</ul>
</div>
</div>
</div>
<ul class="typecho-list-notable tag-list clearfix">
<li class="size-5" id="tag-18">
<input type="checkbox" value="18" name="mid[]" />
<span rel="http://localhost/admin/manage-tags.php?mid=18">sad</span>
<a class="tag-edit-link" href="http://localhost/admin/manage-tags.php?mid=18"><i class="i-edit"></i></a>
</li>
<li class="size-5" id="tag-17">
<input type="checkbox" value="17" name="mid[]" />
<span rel="http://localhost/admin/manage-tags.php?mid=17">sdasdf</span>
<a class="tag-edit-link" href="http://localhost/admin/manage-tags.php?mid=17"><i class="i-edit"></i></a>
</li>
<li class="size-5" id="tag-16">
<input type="checkbox" value="16" name="mid[]" />
<span rel="http://localhost/admin/manage-tags.php?mid=16">sdfsad</span>
<a class="tag-edit-link" href="http://localhost/admin/manage-tags.php?mid=16"><i class="i-edit"></i></a>
</li>
<li class="size-5" id="tag-15">
<input type="checkbox" value="15" name="mid[]" />
<span rel="http://localhost/admin/manage-tags.php?mid=15">asdfasd</span>
<a class="tag-edit-link" href="http://localhost/admin/manage-tags.php?mid=15"><i class="i-edit"></i></a>
</li>
<li class="size-5" id="tag-14">
<input type="checkbox" value="14" name="mid[]" />
<span rel="http://localhost/admin/manage-tags.php?mid=14">sdfsdfasdf</span>
<a class="tag-edit-link" href="http://localhost/admin/manage-tags.php?mid=14"><i class="i-edit"></i></a>
</li>
<li class="size-5" id="tag-13">
<input type="checkbox" value="13" name="mid[]" />
<span rel="http://localhost/admin/manage-tags.php?mid=13">sdfsdfasd</span>
<a class="tag-edit-link" href="http://localhost/admin/manage-tags.php?mid=13"><i class="i-edit"></i></a>
</li>
<li class="size-5" id="tag-12">
<input type="checkbox" value="12" name="mid[]" />
<span rel="http://localhost/admin/manage-tags.php?mid=12">sadfasdf</span>
<a class="tag-edit-link" href="http://localhost/admin/manage-tags.php?mid=12"><i class="i-edit"></i></a>
</li>
</ul>
<input type="hidden" name="do" value="delete" />
</form>
</div>
<div class="col-mb-12 col-tb-4" role="form">
<form action="http://localhost/index.php/action/metas-tag-edit?_=2e6004cd103d97bddfccf02fddd0ecbe" method="post" enctype="application/x-www-form-urlencoded">
<ul class="typecho-option" id="typecho-option-item-name-0">
<li>
<label class="typecho-label" for="name-0-1">
标签名称 *</label>
<input id="name-0-1" name="name" type="text" class="text" />
<p class="description">
这是标签在站点中显示的名称.可以使用中文,如 "地球".</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-slug-1">
<li>
<label class="typecho-label" for="slug-0-2">
标签缩略名</label>
<input id="slug-0-2" name="slug" type="text" class="text" />
<p class="description">
标签缩略名用于创建友好的链接形式, 如果留空则默认使用标签名称.</p>
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-do-2" style="display:none">
<li>
<input name="do" type="hidden" value="insert" />
</li>
</ul>
<ul class="typecho-option" id="typecho-option-item-mid-3" style="display:none">
<li>
<input name="mid" type="hidden" />
</li>
</ul>
<ul class="typecho-option typecho-option-submit" id="typecho-option-item--4">
<li>
<button type="submit" class="btn primary">
增加标签</button>
</li>
</ul>
</form>
</div>
</div>
</div>
</div>
<div class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="http://typecho.org" class="i-logo-s">Typecho</a>
<p><a href="http://typecho.org">Typecho</a> 强力驱动, 版本 1.0 (14.10.10)</p>
</div>
<nav class="resource">
<a href="http://docs.typecho.org">帮助文档</a> &bull;
<a href="http://forum.typecho.org">支持论坛</a> &bull;
<a href="https://github.com/typecho/typecho/issues">报告错误</a> &bull;
<a href="http://extends.typecho.org">资源下载</a>
</nav>
</div>
<script src="http://localhost/admin/js/jquery.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/jquery-ui.js?v=14.10.10"></script>
<script src="http://localhost/admin/js/typecho.js?v=14.10.10"></script>
<script>
(function() {
$(document).ready(function() {
// 处理消息机制
(function() {
var prefix = '86a9106ae65537651a8e456835b316ab',
cookies = {
notice: $.cookie(prefix + '__typecho_notice'),
noticeType: $.cookie(prefix + '__typecho_notice_type'),
highlight: $.cookie(prefix + '__typecho_notice_highlight')
},
path = '/';
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
p = $('<div class="message popup ' + cookies.noticeType + '">' + '<ul><li>' + $.parseJSON(cookies.notice).join('</li><li>') + '</li></ul></div>'),
offset = 0;
if (head.length > 0) {
p.insertAfter(head);
offset = head.outerHeight();
} else {
p.prependTo(document.body);
}
function checkScroll() {
if ($(window).scrollTop() >= offset) {
p.css({
'position': 'fixed',
'top': 0
});
} else {
p.css({
'position': 'absolute',
'top': offset
});
}
}
$(window).scroll(function() {
checkScroll();
});
checkScroll();
p.slideDown(function() {
var t = $(this),
color = '#C6D880';
if (t.hasClass('error')) {
color = '#FBC2C4';
} else if (t.hasClass('notice')) {
color = '#FFD324';
}
t.effect('highlight', {
color: color
})
.delay(5000).slideUp(function() {
$(this).remove();
});
});
$.cookie(prefix + '__typecho_notice', null, {
path: path
});
$.cookie(prefix + '__typecho_notice_type', null, {
path: path
});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie(prefix + '__typecho_notice_highlight', null, {
path: path
});
}
})();
// 导航菜单 tab 聚焦时展开下拉菜单
(function() {
$('#typecho-nav-list').find('.parent a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
$(this).parents('.root').find('.child').show();
});
$('.operate').find('a').focus(function() {
$('#typecho-nav-list').find('.child').hide();
});
})();
if ($('.typecho-login').length == 0) {
$('a').each(function() {
var t = $(this),
href = t.attr('href');
if ((href && href[0] == '#') || /^http\:\/\/localhost\/admin\/.*$/.exec(href) || /^http\:\/\/localhost\/index\.php\/action\/[_a-zA-Z0-9\/]+.*$/.exec(href)) {
return;
}
t.attr('target', '_blank');
});
}
});
})();
</script>
<script type="text/javascript">
(function() {
$(document).ready(function() {
$('.typecho-list-notable').tableSelectable({
checkEl: 'input[type=checkbox]',
rowEl: 'li',
selectAllEl: '.typecho-table-select-all',
actionEl: '.dropdown-menu a'
});
$('.btn-drop').dropdownMenu({
btnEl: '.dropdown-toggle',
menuEl: '.dropdown-menu'
});
$('.dropdown-menu button.merge').click(function() {
var btn = $(this);
btn.parents('form').attr('action', btn.attr('rel')).submit();
});
});
})();
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More