Compare commits

..
Author SHA1 Message Date
binnchx fb484b2132 Merge remote-tracking branch 'origin/dev' into dev-binnchx 2015-01-22 23:18:20 +08:00
binnchx 4d5a3ffd0f .gitignore is now working 2015-01-22 23:16:26 +08:00
binnchx f78eb4db49 add share note 2015-01-22 23:13:58 +08:00
yfqin 8a61b64575 Merge branch 'dev-xqin' into dev 2015-01-20 13:13:58 +08:00
yfqin 419585ff7d _toHtmlEntity 对双引号进行转义
对其他地方中有可能产生XSS的地方进行修补
2015-01-20 11:31:17 +08:00
dds_feng ffaaa8c11a 对笔记的Tag中由JS创建的DOM节点在进行内容设置时对HTML进行转义 2015-01-20 01:15:55 +08:00
dds_feng 3417e71d04 Merge branch 'dev-xqin' into dev 2015-01-20 00:07:19 +08:00
dds_feng 014a141808 修复当笔记的Title中有HTML代码时,会被页面解析的问题 2015-01-20 00:06:36 +08:00
binnchx c35aa1eaa4 ignore app.conf 2015-01-11 22:34:17 +08:00
binnchx 96b094844e rm file 2015-01-11 22:06:09 +08:00
binnchx 9af13bcc32 Merge remote-tracking branch 'origin/dev' into dev-binnchx
Conflicts:
2015-01-11 22:04:18 +08:00
binnchx 29215a1d64 modify git ignore 2015-01-11 21:29:54 +08:00
binnchx d828a10e7b add conf file 2015-01-11 21:29:26 +08:00
binnchx a851aaa399 commit sharing note 2015-01-11 17:59:07 +08:00
life ac99e20aa4 default theme clean & replace install data 2015-01-10 20:51:50 +08:00
life d5dabecb81 blog theme redesign 2015-01-10 19:04:46 +08:00
life df9bc37e1d blog theme redesign 2015-01-10 19:04:06 +08:00
life 4277caa571 initial data, add index to notes 2015-01-09 00:32:34 +08:00
life 1d18908cd0 add images 2015-01-09 00:23:33 +08:00
life 916ee52cdb Update conf 2015-01-09 00:13:20 +08:00
life 289e7b16d9 build 2015-01-08 23:33:14 +08:00
life 016ef5de2d delete app.conf-default, routes-default 2015-01-08 23:29:24 +08:00
life 52d0a7ed21 delete medium theme 2015-01-08 23:27:13 +08:00
life ddf3236c4f Merge branch 'dev-life'
Conflicts:
	app/init.go
	public/js/common-min.js
	public/js/common.js
2015-01-08 23:14:27 +08:00
life 9515f1e58f 打包发布最新功能 2015-01-08 22:08:09 +08:00
life c514d0bc1c Ace & Markdown全新编辑器 & others
邀请注册
共享后图片可见问题 fileService::getFile()
笔记历史记录问题
共享后得到被共享者列表问题 shareService
themeService 博客主题新建问题, 模板循环引用问题
markdown编辑器双屏大小不能保存问题
2015-01-08 21:15:56 +08:00
life d24531dc78 update messages 2015-01-08 00:38:54 +08:00
life 2cfc89ca5f ace editor, markdown editor 2015-01-08 00:36:28 +08:00
binnchx a393bb8723 Merge branch 'master' into dev-binnchx 2015-01-03 21:25:34 +08:00
binnchx 599e54de5b share note to unregistered users
share note to unregistered users
2015-01-03 17:57:52 +08:00
dds_feng b0d4005ad6 修复在note的界面下从菜单中点退出,浏览器报错,导致退出不了的问题 2014-12-29 21:34:23 +08:00
asktalk c0cd433c3f fixed bug #5 2014-12-28 09:07:16 +08:00
asktalk 792c8cfd40 medium theme 2014-12-27 23:47:31 +08:00
asktalk 4f102ff883 Medium theme 2014-12-27 23:46:11 +08:00
asktalk 40973c4615 modify the product publicity picture 2014-12-27 23:32:32 +08:00
asktalk 58bf623d05 edit readme 2014-12-27 23:28:03 +08:00
asktalk 46e97abe91 edit readme 2014-12-27 23:25:32 +08:00
life be01c9c3f7 刷新共享笔记时有问题 2014-12-09 23:43:14 +08:00
life 17718732cc 国际化, #21, #26, 2014-12-09 23:17:36 +08:00
life e2e90f8618 Merge branch 'master' of github.com:leanote/leanote 2014-12-07 22:05:30 +08:00
life 25d5df6bfc update readme 2014-12-07 22:02:01 +08:00
asktalk b781f8318c fixed bug #24 2014-12-07 00:31:51 +08:00
asktalk 0e07cbab8b updated README.md 2014-12-07 00:23:00 +08:00
asktalk ed75704032 添加默认笔记本,默认笔记本无法删除。修改初始化数据添加默认笔记本数据。修改bug #23 2014-12-07 00:12:17 +08:00
life c49593171c note 2014-12-02 23:20:10 +08:00
life 45d72051d0 Note 2014-12-02 23:19:43 +08:00
life 10b387faa6 compatible for iphone/ipad 2014-12-02 22:56:48 +08:00
life 30ebc95abf compatible for iPhone/ipad 2014-12-02 22:47:12 +08:00
life 9bc65bc099 compatible for iPhone/ipad; writing mode for ipad/iphone 2014-12-02 22:42:46 +08:00
life 39809dc4c6 update read me 2014-11-21 09:52:37 +08:00
life 8c4a203d96 sort cate beta2 2014-11-17 14:21:25 +08:00
life 034ad821ca beta2 preNextBlog fixed 2014-11-13 16:46:22 +08:00
life c894b7b308 beta2 google code pretty js 2014-11-13 14:21:38 +08:00
life c0979be9f3 markdown table theme 2014-11-13 13:02:05 +08:00
life b45e9eacb0 beta2 preview controller 2014-11-13 12:35:48 +08:00
life 16d47418ad beta2 default theme url title 2014-11-13 10:31:11 +08:00
life 5d48d1853d use urlTitle for post url 2014-11-12 23:57:50 +08:00
life f503da30b7 member blog list avatar 2014-11-12 23:12:10 +08:00
1829 changed files with 25325 additions and 18762 deletions

No files matched your search

+1 -2
View File
@@ -8,8 +8,6 @@ bin/release
bin/tmp
bin/test
bin/src
conf/app.conf
conf/routes
public/upload
app/routes/routes.go
app/tmp/main.go
@@ -18,3 +16,4 @@ app/tmp/main.go
.project
public/config.codekit
files
conf/app.conf
-17
View File
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>leanote-public</name>
<comment>leanote, your own cloud note!</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.googlecode.goclipse.goBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>goclipse.goNature</nature>
</natures>
</projectDescription>
+19 -100
View File
@@ -1,8 +1,10 @@
[中文](https://github.com/leanote/leanote#1-介绍)
# Leanote
## 1. Introduction
Leanote, note just a notebook!
Leanote, not just a notebook!
![leanote.png](leanote.png "")
**Some Features**
@@ -20,12 +22,18 @@ To be honest, our inspiration comes from Evernote. We use Evernote to manage our
## 3. How to install leanote
More information about how to install leanote please see:
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
### 3.1. Download leanote
Leanote V1.0-beta has been released. Binaries:
Leanote V1.0.2-beta has been released. Binaries:
* Linux: [leanote-linux-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.bin.tar.gz)
* MacOS X: [leanote-mac-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.tar.gz)
* Linux: [leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz)
* MacOS X: [leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.2.tar.gz)
Or you can clone [Leanote bin repository](https://github.com/leanote/leanote-bin) (Recommend)
### 3.2. Install MongoDB
@@ -89,106 +97,17 @@ this project. Your help is much appreciated.
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
## Docs
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
* [leanote blog theme api](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api_en)
## Discussion
* [leanote bbs](http://bbs.leanote.com)
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
* QQ Group: 158716820
-----------------------------------------------------------------------
[中文](README_zh.md)
## 1. 介绍
Leanote, 不只是笔记!
**特性**
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
* 协作: 在分享的同时也可以与好友一起协作知识.
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
## 2. 为什么我们要创建leanote?
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
* 我们是markdown的爱好者, 可是evernote竟然没有.
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
* 还有...
## 3.安装leanote
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
### 3.1. 下载leanote
Leanote V1.0-beta 已发布, 二进制文件(暂时没有windows版的):
* Linux: [leanote-linux-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.bin.tar.gz)
* MacOS X: [leanote-mac-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.tar.gz)
### 3.2. 安装 MongodbDB
Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
### 3.3. 导入初始数据
MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
```
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
```
初始数据包含两个用户:
```
user2 username: admin, password: abc123 (管理员, 重要!)
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
```
### 3.4. 配置
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
``mongodb`` **必须配置!**
```Shell
db.host=localhost
db.port=27017
db.dbname=leanote
db.username=
db.password=
```
``app.secret`` **重要**
请随意修改一个, app的密钥, 不能使用默认的, 不然会有安全问题
更多配置请查看 `app/app.conf` 和 [revel 手册](https://revel.github.io/)
### 3.5. 运行leanote
```
$> cd PATH_TO_LEANOTE/bin
$> sudo sh run.sh
```
## 4. 如何对leanote进行二次开发
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
## 5. 贡献者
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
## 6. 加入我们
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
## 讨论
* [leanote 社区](http://bbs.leanote.com)
* QQ群: 158716820
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
+113
View File
@@ -0,0 +1,113 @@
# Leanote产品
## 1. 介绍
Leanote, 不只是笔记!
![leanote.png](leanote.png "")
**特性**
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
* 协作: 在分享的同时也可以与好友一起协作知识.
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
## 2. 为什么我们要创建leanote?
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
* 我们是markdown的爱好者, 可是evernote竟然没有.
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
* 还有...
## 3.安装leanote
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
### 3.1. 下载leanote
Leanote V1.0-beta.2 已发布, 二进制文件(暂时没有windows版的):
* Linux: [leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz)
* MacOS X: [leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz)
或者直接检出[Leanote bin repository](https://github.com/leanote/leanote-bin) (推荐, 因为为最新版本)
### 3.2. 安装 MongodbDB
Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
### 3.3. 导入初始数据
MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
```
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
```
初始数据包含两个用户:
```
user2 username: admin, password: abc123 (管理员, 重要!)
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
```
### 3.4. 配置
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
``mongodb`` **必须配置!**
```Shell
db.host=localhost
db.port=27017
db.dbname=leanote
db.username=
db.password=
```
``app.secret`` **重要**
请随意修改一个, app的密钥, 不能使用默认的, 不然会有安全问题
更多配置请查看 `app/app.conf` 和 [revel 手册](https://revel.github.io/)
### 3.5. 运行leanote
```
$> cd PATH_TO_LEANOTE/bin
$> sudo sh run.sh
```
## 4. 如何对leanote进行二次开发
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
## 5. 贡献者
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
## 6. 加入我们
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
## 相关文档
* [leanote二进制版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [Leanote source leanote源码导读](https://github.com/leanote/leanote/wiki/Leanote-source-leanote源码导读)
* [leanote blog theme api(中文版)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
* [How to develop leanote 如何开发leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-如何开发leanote)
## 讨论
* [leanote 社区](http://bbs.leanote.com)
* QQ群: 158716820
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
----------------------------------------------------------------
[English](README.md)
+20 -7
View File
@@ -62,7 +62,7 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
maxFileSize = 1000
}
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
resultMsg = fmt.Sprintf("附件大于%vM", maxFileSize)
resultMsg = fmt.Sprintf("The file's size is bigger than %vM", maxFileSize)
return re
}
@@ -100,11 +100,15 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
id := bson.NewObjectId();
fileInfo.AttachId = id
fileId = id.Hex()
Ok = attachService.AddAttach(fileInfo)
Ok, resultMsg = attachService.AddAttach(fileInfo)
if resultMsg != "" {
resultMsg = c.Message(resultMsg)
}
fileInfo.Path = ""; // 不要返回
resultMsg = "success"
if Ok {
resultMsg = "success"
}
return re
}
@@ -125,9 +129,18 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
// 下载附件
// 权限判断
func (c Attach) Download(attachId string) revel.Result {
attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
func (c Attach) Download(attachId, token string) revel.Result {
if c.GetUserId() == "" && token == "" {
return c.RenderText("你需要从分享页面下载附件!")
}
sessionId := c.Session.Id()
attach := attachService.GetAttach(attachId, c.GetUserId(), token, sessionId); // 得到路径
path := attach.Path
if token != "" && attach.Path == "" {
return c.RenderText("该下载链接已经失效,请重新刷新原分享笔记页面下载")
}
if path == "" {
return c.RenderText("")
}
@@ -212,4 +225,4 @@ func (c Attach) DownloadAll(noteId string) revel.Result {
// file, _ := os.Open(dir + "/" + filename)
// fw.Seek(0, 0)
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
}
}
+7 -5
View File
@@ -5,6 +5,7 @@ import (
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
// "strconv"
"fmt"
)
// 用户登录/注销/找回密码
@@ -40,7 +41,7 @@ func (c Auth) Login(email, from string) revel.Result {
func (c Auth) doLogin(email, pwd string) revel.Result {
sessionId := c.Session.Id()
var msg = ""
fmt.Println(sessionId)
userInfo := authService.Login(email, pwd)
if userInfo.Email != "" {
c.SetSession(userInfo)
@@ -55,8 +56,8 @@ func (c Auth) doLogin(email, pwd string) revel.Result {
}
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
sessionId := c.Session.Id()
var msg = ""
var msg = ""
// > 5次需要验证码, 直到登录成功
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
msg = "captchaError"
@@ -91,18 +92,19 @@ func (c Auth) Demo() revel.Result {
//--------
// 注册
func (c Auth) Register(from string) revel.Result {
func (c Auth) Register(from, iu string) revel.Result {
if !configService.IsOpenRegister() {
return c.Redirect("/index")
}
c.SetLocale()
c.RenderArgs["from"] = from
c.RenderArgs["iu"] = iu
c.RenderArgs["title"] = c.Message("register")
c.RenderArgs["subTitle"] = c.Message("register")
return c.RenderTemplate("home/register.html")
}
func (c Auth) DoRegister(email, pwd string) revel.Result {
func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
if !configService.IsOpenRegister() {
return c.Redirect("/index")
}
@@ -117,7 +119,7 @@ func (c Auth) DoRegister(email, pwd string) revel.Result {
}
// 注册
re.Ok, re.Msg = authService.Register(email, pwd)
re.Ok, re.Msg = authService.Register(email, pwd, iu)
// 注册成功, 则立即登录之
if re.Ok {
+6 -1
View File
@@ -193,12 +193,13 @@ func (c BaseController) SetLocale() string {
}
// 设置userInfo
func (c BaseController) SetUserInfo() {
func (c BaseController) SetUserInfo() info.User {
userInfo := c.GetUserInfo()
c.RenderArgs["userInfo"] = userInfo
if(userInfo.Username == configService.GetAdminUsername()) {
c.RenderArgs["isAdmin"] = true
}
return userInfo
}
// life
@@ -224,6 +225,7 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
// 为了msg
// msg-v1-v2-v3
func (c BaseController) RenderRe(re info.Re) revel.Result {
oldMsg := re.Msg
if re.Msg != "" {
if(strings.Contains(re.Msg, "-")) {
msgAndValues := strings.Split(re.Msg, "-")
@@ -241,5 +243,8 @@ func (c BaseController) RenderRe(re info.Re) revel.Result {
re.Msg = c.Message(re.Msg)
}
}
if strings.HasPrefix(re.Msg, "???") {
re.Msg = oldMsg
}
return c.RenderJson(re)
}
+22 -8
View File
@@ -57,6 +57,9 @@ func (c Blog) render(templateName string, themePath string) revel.Result {
isPreview = true
themePath = themePath2.(string)
c.setPreviewUrl()
// 因为common的themeInfo是从UserBlog.ThemeId来取的, 所以这里要fugai下
c.RenderArgs["themeInfo"] = c.RenderArgs["themeInfoPreview"];
}
return blog.RenderTemplate(templateName, c.RenderArgs, revel.BasePath+"/"+themePath, isPreview)
}
@@ -102,19 +105,23 @@ func (c Blog) setPreviewUrl() {
var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl string
userId := c.GetUserId()
userIdOrEmail := userId
username := c.GetUsername()
if username != "" {
userIdOrEmail = username
}
themeId := c.Session["themeId"]
theme := themeService.GetTheme(userId, themeId)
siteUrl := configService.GetSiteUrl()
blogUrl := siteUrl + "/preview" // blog.leanote.com
userIdOrEmail := userId
indexUrl = blogUrl + "/" + userIdOrEmail
cateUrl = blogUrl + "/cate" // /notebookId
cateUrl = blogUrl + "/cate/" + userIdOrEmail // /notebookId
postUrl = blogUrl + "/post" // /xxxxx
postUrl = blogUrl + "/post/" + userIdOrEmail // /xxxxx
searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId
singleUrl = blogUrl + "/single" // blog.leanote.com/single/singleId
singleUrl = blogUrl + "/single/" + userIdOrEmail // blog.leanote.com/single/singleId
archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId
tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId
@@ -533,21 +540,27 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
}
userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
var ok = false
fmt.Println("before test...");
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
fmt.Println("404 occur");
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
}
fmt.Println("after test0...");
// 分页的话, 需要分页信息, totalPage, curPage
page := c.GetPage()
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
blogs2 := blogService.FixBlogs(blogs)
c.RenderArgs["posts"] = blogs2
c.setPaging(pageInfo)
c.RenderArgs["pagingBaseUrl"] = c.RenderArgs["indexUrl"]
c.RenderArgs["curIsIndex"] = true
return c.render("index.html", userBlog.ThemePath)
}
@@ -577,7 +590,8 @@ func (c Blog) Post(userIdOrEmail, noteId string) (re revel.Result) {
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
}
c.RenderArgs["post"] = blogService.FixBlog(blogInfo)
post := blogService.FixBlog(blogInfo)
c.RenderArgs["post"] = post
// c.RenderArgs["userInfo"] = userInfo
c.RenderArgs["curIsPost"] = true
@@ -593,7 +607,7 @@ func (c Blog) Post(userIdOrEmail, noteId string) (re revel.Result) {
baseTime = blogInfo.Title
}
prePost, nextPost := blogService.PreNextBlog(userId, userBlog.SortField, userBlog.IsAsc, baseTime)
prePost, nextPost := blogService.PreNextBlog(userId, userBlog.SortField, userBlog.IsAsc, post.NoteId, baseTime)
if prePost.NoteId != "" {
c.RenderArgs["prePost"] = prePost
}
+15 -84
View File
@@ -9,9 +9,9 @@ import (
"github.com/leanote/leanote/app/info"
"io/ioutil"
"os"
"fmt"
"strconv"
// "strconv"
"strings"
"fmt"
)
// 首页
@@ -85,7 +85,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
var fileUrlPath = ""
var fileId = ""
var resultCode = 0 // 1表示正常
var resultMsg = "内部错误" // 错误信息
var resultMsg = "error" // 错误信息
var Ok = false
defer func() {
@@ -120,7 +120,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
} else {
_, ext = SplitFilename(filename)
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
resultMsg = "不是图片"
resultMsg = "Please upload image"
return re
}
}
@@ -147,7 +147,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
// > 2M?
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
resultCode = 0
resultMsg = fmt.Sprintf("图片大于%vM", maxFileSize)
resultMsg = fmt.Sprintf("The file Size is bigger than %vM", maxFileSize)
return re
}
@@ -163,7 +163,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
filesize := GetFilesize(toPathGif)
fileUrlPath += "/" + filename
resultCode = 1
resultMsg = "上传成功!"
resultMsg = "Upload Success!"
// File
fileInfo := info.File{Name: filename,
@@ -178,7 +178,8 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
}
Ok = fileService.AddImage(fileInfo, albumId, c.GetUserId())
Ok, resultMsg = fileService.AddImage(fileInfo, albumId, c.GetUserId(), from == "" || from == "pasteImage")
resultMsg = c.Message(resultMsg)
fileInfo.Path = ""; // 不要返回
re.Item = fileInfo
@@ -203,61 +204,13 @@ func (c File) DeleteImage(fileId string) revel.Result {
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
return c.RenderJson(re)
}
// update image uploader to leaui image,
// scan all user's images and insert into db
func (c File) UpgradeLeauiImage() revel.Result {
re := info.NewRe()
if ok, _ := revel.Config.Bool("upgradeLeauiImage"); !ok {
re.Msg = "Not allowed"
return c.RenderJson(re)
}
uploadPath := revel.BasePath + "/public/upload";
userIds := ListDir(uploadPath)
if userIds == nil {
re.Msg = "no user"
return c.RenderJson(re)
}
msg := "";
for _, userId := range userIds {
dirPath := uploadPath + "/" + userId + "/images"
images := ListDir(dirPath)
if images == nil {
msg += userId + " no images "
continue;
}
hadImages := fileService.GetAllImageNamesMap(userId)
i := 0
for _, filename := range images {
if _, ok := hadImages[filename]; !ok {
fileUrlPath := "/upload/" + userId + "/images/" + filename
fileInfo := info.File{Name: filename,
Title: filename,
Path: fileUrlPath,
Size: GetFilesize(dirPath + "/" + filename)}
fileService.AddImage(fileInfo, "", userId)
i++
}
}
msg += userId + ": " + strconv.Itoa(len(images)) + " -- " + strconv.Itoa(i) + " images "
}
re.Msg = msg
return c.RenderJson(re)
}
//-----------
// 输出image
// 权限判断
func (c File) OutputImage(noteId, fileId string) revel.Result {
path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
func (c File) OutputImage(noteId, fileId , token string) revel.Result {
sessionId := c.Session.Id()
path := fileService.GetFile(c.GetUserId(), fileId, sessionId, token); // 得到路径
if path == "" {
return c.RenderText("")
}
@@ -267,15 +220,15 @@ func (c File) OutputImage(noteId, fileId string) revel.Result {
}
// 协作时复制图片到owner
// 需要计算对方大小
func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
re := info.NewRe()
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
return c.RenderJson(re)
}
// 复制外网的图片, 成公共图片 放在/upload下
// 都要好好的计算大小
func (c File) CopyHttpImage(src string) revel.Result {
re := info.NewRe()
fileUrlPath := "upload/" + c.GetUserId() + "/images"
@@ -302,29 +255,7 @@ func (c File) CopyHttpImage(src string) revel.Result {
re.Id = id.Hex()
re.Item = fileInfo.Path
re.Ok = fileService.AddImage(fileInfo, "", c.GetUserId())
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
return c.RenderJson(re)
}
//------------
// 过时 已弃用!
func (c File) UploadImage(renderHtml string) revel.Result {
if renderHtml == "" {
renderHtml = "file/image.html"
}
re := c.uploadImage("", "");
c.RenderArgs["fileUrlPath"] = configService.GetSiteUrl() + re.Id
c.RenderArgs["resultCode"] = re.Code
c.RenderArgs["resultMsg"] = re.Msg
return c.RenderTemplate(renderHtml)
}
// 已弃用
func (c File) UploadImageJson(from, noteId string) revel.Result {
re := c.uploadImage(from, "");
return c.RenderJson(re)
}
}
+68 -10
View File
@@ -22,9 +22,8 @@ type Note struct {
// 笔记首页, 判断是否已登录
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
// 否则, 转向登录页面
func (c Note) Index() revel.Result {
func (c Note) Index(noteId string) revel.Result {
c.SetLocale()
userInfo := c.GetUserInfo()
userId := userInfo.UserId.Hex()
@@ -35,7 +34,7 @@ func (c Note) Index() revel.Result {
}
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
// 已登录了, 那么得到所有信息
notebooks := notebookService.GetNotebooks(userId)
shareNotebooks, sharedUserInfos := shareService.GetShareNotebooks(userId)
@@ -43,22 +42,78 @@ func (c Note) Index() revel.Result {
// 还需要按时间排序(DESC)得到notes
notes := []info.Note{}
noteContent := info.NoteContent{}
if len(notebooks) > 0 {
// _, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), pageSize, defaultSortField, false, false);
// 变成最新
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
if len(notes) > 0 {
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
// noteId是否存在
// 是否传入了正确的noteId
hasRightNoteId := false
if IsObjectId(noteId) {
note := noteService.GetNoteById(noteId)
var noteOwner = note.UserId.Hex()
noteContent = noteService.GetNoteContent(noteId, noteOwner)
if note.NoteId != "" {
hasRightNoteId = true
c.RenderArgs["curNoteId"] = noteId
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
// 打开的是共享的笔记, 那么判断是否是共享给我的默认笔记
if noteOwner != c.GetUserId() {
if shareService.HasReadPerm(noteOwner, c.GetUserId(), noteId) {
// 不要获取notebook下的笔记
// 在前端下发请求
c.RenderArgs["curSharedNoteNotebookId"] = note.NotebookId.Hex()
c.RenderArgs["curSharedUserId"] = noteOwner;
// 没有读写权限
} else {
hasRightNoteId = false
}
} else {
_, notes = noteService.ListNotes(c.GetUserId(), note.NotebookId.Hex(), false, c.GetPage(), 50, defaultSortField, false, false);
// 如果指定了某笔记, 则该笔记放在首位
lenNotes := len(notes)
if lenNotes > 1 {
notes2 := make([]info.Note, len(notes))
notes2[0] = note
i := 1
for _, note := range notes {
if note.NoteId.Hex() != noteId {
if i == lenNotes { // 防止越界
break;
}
notes2[i] = note
i++
}
}
notes = notes2
}
}
}
// 得到最近的笔记
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
c.RenderArgs["latestNotes"] = latestNotes
}
// 没有传入笔记
// 那么得到最新笔记
if !hasRightNoteId {
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
if len(notes) > 0 {
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
c.RenderArgs["curNoteId"] = notes[0].NoteId.Hex()
}
}
}
// 当然, 还需要得到第一个notes的content
//...
Log(configService.GetAdminUsername())
c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
c.RenderArgs["userInfo"] = userInfo
c.RenderArgs["notebooks"] = notebooks
c.RenderArgs["shareNotebooks"] = shareNotebooks
c.RenderArgs["shareNotebooks"] = shareNotebooks // note信息在notes列表中
c.RenderArgs["sharedUserInfos"] = sharedUserInfos
c.RenderArgs["notes"] = notes
@@ -69,6 +124,9 @@ func (c Note) Index() revel.Result {
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
// return c.RenderTemplate("note/note.html")
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
return c.RenderTemplate("note/note-dev.html")
} else {
+2
View File
@@ -33,6 +33,8 @@ func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
theme := themeService.GetTheme(c.GetUserId(), themeId)
c.RenderArgs["isPreview"] = true
c.RenderArgs["themeId"] = themeId
c.RenderArgs["themeInfoPreview"] = theme.Info
c.RenderArgs["themePath"] = theme.Path
if theme.Path == "" {
return false
+65
View File
@@ -9,12 +9,15 @@ import (
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "time"
)
type Share struct {
BaseController
}
const AttachToken = 2
// 添加共享note
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
status := make(map[string]info.Re, len(emails))
@@ -36,6 +39,8 @@ func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Resu
return c.RenderJson(status)
}
// 添加共享notebook
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
status := make(map[string]info.Re, len(emails))
@@ -185,4 +190,64 @@ func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result
// 更新, 也是一样, 先删后加
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
return c.AddShareNotebookGroup(notebookId, groupId, perm)
}
//生成笔记分享密码及更新到db
func (c Share) GenShareLinkPass(noteId string) revel.Result {
pass, ok := shareService.GenSharePass(noteId)
re := info.Re{Ok : true, Item : pass, List: ok}
return c.RenderJson(re);
}
func (c Share) QuerySharePass(noteId string) revel.Result {
pass := shareService.QuerySharePass(noteId)
re := info.Re{Ok : true, Item : pass}
return c.RenderJson(re);
}
//展示分享笔记
func (c Share) ShowShareNote(noteId string) revel.Result {
note := noteService.GetNoteById(noteId)
//
c.RenderArgs["noteId"] = noteId
username := userService.GetUsernameById(note.UserId)
c.RenderArgs["userName"] = username
c.RenderArgs["isMarkDown"] = note.IsMarkdown
// c.RenderArgs["timestamp"] = time.Now().Unix()
c.SetLocale()
return c.RenderTemplate("share/show_share_note.html")
}
//验证分享密码
func (c Share) Verify4ShareNote(noteId string, sharePass int) revel.Result {
ok, note, noteContent := shareService.Verify4ShareNote(noteId, sharePass)
attaches := []info.Attach{}
if ok && note.AttachNum > 0 {
attaches = attachService.ListAttachs(noteId, "")
}
token := tokenService.NewToken(noteId, noteId, AttachToken)
//插入笔记作为链接中的附件
noteAttachIds := map[string]bool{}
noteContent.Content, noteAttachIds = shareService.AppendToken4URL(token, noteContent.Content)
//过滤掉插入笔记的附件
filteredAttaches := []info.Attach{}
if len(noteAttachIds) > 0 && len(attaches) > 0 {
for _, attach := range attaches {
if !noteAttachIds[attach.AttachId.Hex()] {
filteredAttaches = append(filteredAttaches, attach)
}
}
} else {
filteredAttaches = attaches
}
sessionId := c.Session.Id()
sessionService.SetToken(sessionId, token)
re := info.Re{Ok : ok, Item: note, List: filteredAttaches, Id: token, Msg: noteContent.Content}
return c.RenderJson(re)
}
+1 -1
View File
@@ -44,7 +44,7 @@ func (c AdminUser) Register(email, pwd string) revel.Result {
}
// 注册
re.Ok, re.Msg = authService.Register(email, pwd)
re.Ok, re.Msg = authService.Register(email, pwd, "")
return c.RenderRe(re)
}
+1
View File
@@ -49,6 +49,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
"Suggestion": true,
},
"Note": map[string]bool{"ToImage": true},
"Share": map[string]bool{"ShowShareNote": true, "Verify4ShareNote": true},
"Blog": map[string]bool{"Index": true,
"View": true,
"AboutMe": true,
+98 -91
View File
@@ -1,15 +1,15 @@
package member
import (
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"os"
"io/ioutil"
"time"
"fmt"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"io/ioutil"
"os"
"strings"
// "github.com/leanote/leanote/app/lea/blog"
"time"
// "github.com/leanote/leanote/app/lea/blog"
)
// 博客管理
@@ -28,35 +28,34 @@ func (c MemberBlog) common() info.UserBlog {
userBlog := blogService.GetUserBlog(userId)
c.RenderArgs["userBlog"] = userBlog
c.SetUserInfo()
c.SetLocale()
return userBlog
}
// 得到sorterField 和 isAsc
// okSorter = ['email', 'username']
func (c MemberBlog) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
func (c MemberBlog) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
sorter := ""
c.Params.Bind(&sorter, "sorter")
if sorter == "" {
return sorterField, isAsc;
return sorterField, isAsc
}
// sorter形式 email-up, email-down
s2 := strings.Split(sorter, "-")
if len(s2) != 2 {
return sorterField, isAsc;
return sorterField, isAsc
}
// 必须是可用的sorter
if okSorter != nil && len(okSorter) > 0 {
if !InArray(okSorter, s2[0]) {
return sorterField, isAsc;
return sorterField, isAsc
}
}
sorterField = strings.Title(s2[0])
if s2[1] == "up" {
isAsc = true
@@ -64,24 +63,29 @@ func (c MemberBlog) getSorter(sorterField string, isAsc bool, okSorter []string)
isAsc = false
}
c.RenderArgs["sorter"] = sorter
return sorterField, isAsc;
return sorterField, isAsc
}
// 博客列表
var userPageSize = 15
func (c MemberBlog) Index(sorter, keywords string) revel.Result {
userId := c.GetUserId()
userInfo := userService.GetUserInfo(userId)
c.RenderArgs["userInfo"] = userInfo
c.RenderArgs["title"] = "Posts"
pageNumber := c.GetPage()
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"});
pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"})
pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["blogs"] = blogs
c.RenderArgs["keywords"] = keywords
userAndBlog := userService.GetUserAndBlog(c.GetUserId())
c.RenderArgs["userAndBlog"] = userAndBlog
return c.RenderTemplate("member/blog/list.html");
return c.RenderTemplate("member/blog/list.html")
}
// 修改笔记的urlTitle
@@ -91,17 +95,16 @@ func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result {
return c.RenderJson(re)
}
// 修改笔记的urlTitle
func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
c.RenderArgs["title"] = "Update Post Abstract"
note := noteService.GetNoteAndContent(noteId, c.GetUserId());
note := noteService.GetNoteAndContent(noteId, c.GetUserId())
if !note.Note.IsBlog {
return c.E404();
return c.E404()
}
c.RenderArgs["note"] = note
c.RenderArgs["noteId"] = noteId
return c.RenderTemplate("member/blog/update_abstract.html");
return c.RenderTemplate("member/blog/update_abstract.html")
}
func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string) revel.Result {
@@ -114,38 +117,33 @@ func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string)
func (c MemberBlog) Base() revel.Result {
c.common()
c.RenderArgs["title"] = "Blog Base Info"
return c.RenderTemplate("member/blog/base.html");
return c.RenderTemplate("member/blog/base.html")
}
func (c MemberBlog) Comment() revel.Result {
c.common()
c.RenderArgs["title"] = "Comment"
return c.RenderTemplate("member/blog/comment.html");
}
func (c MemberBlog) Domain() revel.Result {
c.common()
c.RenderArgs["title"] = "Domain"
return c.RenderTemplate("member/blog/domain.html");
return c.RenderTemplate("member/blog/comment.html")
}
func (c MemberBlog) Paging() revel.Result {
c.common()
c.RenderArgs["title"] = "Paging"
return c.RenderTemplate("member/blog/paging.html");
return c.RenderTemplate("member/blog/paging.html")
}
func (c MemberBlog) Cate() revel.Result {
userBlog := c.common()
c.RenderArgs["title"] = "Cate"
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
notebooksMap := map[string]info.Notebook{}
for _, each := range notebooks {
notebooksMap[each.NotebookId.Hex()] = each
}
var i = 0;
var i = 0
notebooks2 := make([]info.Notebook, len(notebooks))
// 先要保证已有的是正确的排序
cateIds := userBlog.CateIds
has := map[string]bool{} // cateIds中有的
@@ -167,8 +165,8 @@ func (c MemberBlog) Cate() revel.Result {
}
}
c.RenderArgs["notebooks"] = notebooks2
return c.RenderTemplate("member/blog/cate.html");
return c.RenderTemplate("member/blog/cate.html")
}
// 修改分类排序
@@ -195,9 +193,10 @@ func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
c.RenderArgs["title"] = "Add Single"
c.RenderArgs["singleId"] = singleId
if singleId != "" {
c.RenderArgs["title"] = "Update Single"
c.RenderArgs["single"] = blogService.GetSingle(singleId)
}
return c.RenderTemplate("member/blog/add_single.html");
return c.RenderTemplate("member/blog/add_single.html")
}
func (c MemberBlog) SortSingles(singleIds []string) revel.Result {
re := info.NewRe()
@@ -222,8 +221,8 @@ func (c MemberBlog) Single() revel.Result {
c.common()
c.RenderArgs["title"] = "Cate"
c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId())
return c.RenderTemplate("member/blog/single.html");
return c.RenderTemplate("member/blog/single.html")
}
// 主题
@@ -232,15 +231,16 @@ func (c MemberBlog) Theme() revel.Result {
activeTheme, otherThemes := themeService.GetUserThemes(c.GetUserId())
c.RenderArgs["activeTheme"] = activeTheme
c.RenderArgs["otherThemes"] = otherThemes
c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes()
c.RenderArgs["title"] = "Theme"
return c.RenderTemplate("member/blog/theme.html");
return c.RenderTemplate("member/blog/theme.html")
}
// 编辑主题
var baseTpls = []string{"header.html", "footer.html", "index.html", "cate.html", "search.html", "post.html", "single.html", "tags.html", "tag_posts.html", "archive.html", "share_comment.html", "404.html", "theme.json", "style.css", "blog.js"}
func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
// 查看用户是否有该theme, 若没有则复制default之
// 得到主题的文件列表
@@ -249,22 +249,25 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
_, themeId = themeService.NewThemeForFirst(userBlog)
return c.Redirect("/member/blog/updateTheme?themeId=" + themeId)
}
c.common()
c.RenderArgs["title"] = "Upate Theme"
c.RenderArgs["isNew"] = isNew
// 先复制之
c.RenderArgs["themeId"] = themeId
// 得到脚本目录
userId := c.GetUserId()
theme := themeService.GetTheme(userId, themeId)
theme := themeService.GetTheme(userId, themeId)
if theme.ThemeId == "" {
return c.E404()
}
c.RenderArgs["theme"] = theme
path := revel.BasePath + "/" + theme.Path
tpls := ListDir(path)
myTpls := make([]string, len(baseTpls))
tplMap := map[string]bool{}
@@ -275,16 +278,16 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
// 得到没有的tpls
for _, t := range tpls {
if t == "images" {
continue;
continue
}
if !tplMap[t] {
myTpls = append(myTpls, t)
}
}
c.RenderArgs["myTpls"] = myTpls
return c.RenderTemplate("member/blog/update_theme.html");
return c.RenderTemplate("member/blog/update_theme.html")
}
// 得到文件内容
@@ -292,13 +295,13 @@ func (c MemberBlog) GetTplContent(themeId string, filename string) revel.Result
re := info.NewRe()
re.Ok = true
re.Item = themeService.GetTplContent(c.GetUserId(), themeId, filename)
return c.RenderJson(re)
}
func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = themeService.UpdateTplContent(c.GetUserId(), themeId, filename, content)
return c.RenderJson(re)
return c.RenderRe(re)
}
func (c MemberBlog) DeleteTpl(themeId, filename string) revel.Result {
@@ -327,7 +330,7 @@ func (c MemberBlog) DeleteThemeImage(themeId, filename string) revel.Result {
// 上传主题图片
func (c MemberBlog) UploadThemeImage(themeId string) revel.Result {
re := c.uploadImage(themeId);
re := c.uploadImage(themeId)
c.RenderArgs["fileUrlPath"] = re.Id
c.RenderArgs["resultCode"] = re.Code
c.RenderArgs["resultMsg"] = re.Msg
@@ -335,17 +338,17 @@ func (c MemberBlog) UploadThemeImage(themeId string) revel.Result {
}
func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
var fileId = ""
var resultCode = 0 // 1表示正常
var resultCode = 0 // 1表示正常
var resultMsg = "内部错误" // 错误信息
var Ok = false
defer func() {
re.Id = fileId // 只是id, 没有其它信息
re.Code = resultCode
re.Msg = resultMsg
re.Ok = Ok
}()
file, handel, err := c.Request.FormFile("file")
if err != nil {
return re
@@ -359,11 +362,11 @@ func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
}
// 生成新的文件名
filename := handel.Filename
var ext string;
var ext string
_, ext = SplitFilename(filename)
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
resultMsg = "不是图片"
return re
}
@@ -374,15 +377,15 @@ func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
LogJ(err)
return re
}
// > 2M?
if(len(data) > 5 * 1024 * 1024) {
if len(data) > 5*1024*1024 {
resultCode = 0
resultMsg = "图片大于2M"
return re
}
toPath := dir + "/" + filename;
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
LogJ(err)
@@ -391,7 +394,7 @@ func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
TransToGif(toPath, 0, true)
resultCode = 1
resultMsg = "上传成功!"
return re
}
@@ -402,18 +405,21 @@ func (c MemberBlog) ActiveTheme(themeId string) revel.Result {
re.Ok = themeService.ActiveTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
}
// 删除主题
func (c MemberBlog) DeleteTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.DeleteTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
}
// 管理员公开主题
func (c MemberBlog) PublicTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.PublicTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
}
// 导出
func (c MemberBlog) ExportTheme(themeId string) revel.Result {
re := info.NewRe()
@@ -423,21 +429,21 @@ func (c MemberBlog) ExportTheme(themeId string) revel.Result {
return c.RenderText("error...")
}
fw, err := os.Open(path)
if err != nil {
if err != nil {
return c.RenderText("error")
}
return c.RenderBinary(fw, GetFilename(path), revel.Attachment, time.Now()) // revel.Attachment
}
return c.RenderBinary(fw, GetFilename(path), revel.Attachment, time.Now()) // revel.Attachment
}
// 导入主题
func (c MemberBlog) ImportTheme() revel.Result {
re := info.NewRe()
file, handel, err := c.Request.FormFile("file")
if err != nil {
re.Msg = fmt.Sprintf("%v", err)
return c.RenderJson(re)
}
defer file.Close()
// 生成上传路径
@@ -450,10 +456,10 @@ func (c MemberBlog) ImportTheme() revel.Result {
}
// 生成新的文件名
filename := handel.Filename
var ext string;
var ext string
_, ext = SplitFilename(filename)
if(ext != ".zip") {
if ext != ".zip" {
re.Msg = "请上传zip文件"
return c.RenderJson(re)
}
@@ -463,40 +469,40 @@ func (c MemberBlog) ImportTheme() revel.Result {
if err != nil {
return c.RenderJson(re)
}
// > 10M?
if(len(data) > 10 * 1024 * 1024) {
if len(data) > 10*1024*1024 {
re.Msg = "文件大于10M"
return c.RenderJson(re)
}
toPath := dir + "/" + filename;
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
re.Msg = fmt.Sprintf("%v", err)
return c.RenderJson(re)
}
// 上传好后, 增加之
themeService.ImportTheme(c.GetUserId(), toPath)
re.Ok = true
return c.RenderJson(re)
re.Ok, re.Msg = themeService.ImportTheme(c.GetUserId(), toPath)
return c.RenderRe(re)
}
// 安装
func (c MemberBlog) InstallTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.InstallTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
}
// 新建主题
func (c MemberBlog) NewTheme() revel.Result {
_, themeId := themeService.NewTheme(c.GetUserId())
return c.Redirect("/member/blog/updateTheme?isNew=1&themeId=" + themeId)
}
//-----------
//
//
func (c MemberBlog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
@@ -512,6 +518,7 @@ func (c MemberBlog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
return c.RenderJson(re)
}
func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc bool) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = blogService.UpdateUserBlogPaging(c.GetUserId(), perPageSize, sortField, isAsc)
@@ -35,7 +35,7 @@ func (c MemberGroup) UpdateGroupTitle(groupId, title string) revel.Result {
func (c MemberGroup) DeleteGroup(groupId string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = groupService.DeleteGroup(c.GetUserId(), groupId)
return c.RenderJson(re)
return c.RenderRe(re)
}
// 添加用户
+2 -1
View File
@@ -128,6 +128,7 @@ func init() {
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberIndex{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberUser{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberBlog{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberGroup{})
revel.OnAppStart(func() {
})
}
}
+10 -5
View File
@@ -3,6 +3,7 @@ package db
import (
"fmt"
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
@@ -56,12 +57,15 @@ var Themes *mgo.Collection
var Sessions *mgo.Collection
// 初始化时连接数据库
func Init() {
var url string
var ok bool
func Init(url, dbname string) {
ok := true
config := revel.Config
url, ok = config.String("db.url")
dbname, _ := config.String("db.dbname")
if url == "" {
url, ok = config.String("db.url")
}
if dbname == "" {
dbname, _ = config.String("db.dbname")
}
if !ok {
host, _ := revel.Config.String("db.host")
port, _ := revel.Config.String("db.port")
@@ -73,6 +77,7 @@ func Init() {
}
url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
}
Log(url)
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
+2
View File
@@ -40,6 +40,8 @@ type Note struct {
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
SharePass int `SharePass` //分享笔记的密码
}
// 内容
+3 -2
View File
@@ -10,10 +10,11 @@ type Session struct {
Id bson.ObjectId `bson:"_id,omitempty"` // 没有意义
SessionId string `bson:"SessionId"` // SessionId
LoginTimes int `LoginTimes` // 登录错误时间
Captcha string `Captcha` // 验证码
Token string `Token` //attach token
TokenTime time.Time `TokenTime` //token生成时间
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
}
+1 -1
View File
@@ -41,7 +41,7 @@ type User struct {
ImageSize int `bson:"ImageSize" json:"-"` // 图片大小
AttachNum int `bson:"AttachNum" json:"-"` // 附件数量
AttachSize int `bson:"AttachSize" json:"-"` // 附件大小
PerAttachSize int `bson:"PerAttachSize" json:"-"` // 单个附件大小
FromUserId bson.ObjectId `FromUserId,omitempty` // 邀请的用户
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
+56 -5
View File
@@ -111,6 +111,7 @@ func init() {
}
// tags
// 2014/12/30 标签添加链接
revel.TemplateFuncs["blogTags"] = func(renderArgs map[string]interface{}, tags []string) template.HTML {
if tags == nil || len(tags) == 0 {
return ""
@@ -118,18 +119,68 @@ func init() {
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
tagStr := ""
lenTags := len(tags)
tagPostUrl, _ := renderArgs["tagPostsUrl"].(string)
for i, tag := range tags {
str := revel.Message(locale, tag)
var classes = "label"
if strings.HasPrefix(str, "???") {
str = tag
}
tagStr += str
if InArray([]string{"red", "blue", "yellow", "green"}, tag) {
classes += " label-" + tag
} else {
classes += " label-default"
}
classes += " label-post"
var url = tagPostUrl + "/" + url.QueryEscape(tag)
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
if i != lenTags - 1 {
tagStr += ","
tagStr += " "
}
}
return template.HTML(tagStr)
}
// lea++
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, isRecommend bool) template.HTML {
if tags == nil || len(tags) == 0 {
return ""
}
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
tagStr := ""
lenTags := len(tags)
tagPostUrl := "http://lea.leanote.com/"
if isRecommend {
tagPostUrl += "?tag=";
} else {
tagPostUrl += "latest?tag=";
}
for i, tag := range tags {
str := revel.Message(locale, tag)
var classes = "label"
if strings.HasPrefix(str, "???") {
str = tag
}
if InArray([]string{"red", "blue", "yellow", "green"}, tag) {
classes += " label-" + tag
} else {
classes += " label-default"
}
classes += " label-post"
var url = tagPostUrl + url.QueryEscape(tag)
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
if i != lenTags - 1 {
tagStr += " "
}
}
return template.HTML(tagStr)
}
/*
revel.TemplateFuncs["blogTags"] = func(tags []string) template.HTML {
if tags == nil || len(tags) == 0 {
@@ -311,7 +362,7 @@ func init() {
// init Email
revel.OnAppStart(func() {
// 数据库
db.Init()
db.Init("", "")
// email配置
InitEmail()
InitVd()
@@ -322,5 +373,5 @@ func init() {
admin.InitService()
member.InitService()
service.ConfigS.InitGlobalConfigs()
})
}
});
}
+12 -1
View File
@@ -3,6 +3,7 @@ package lea
import (
"encoding/json"
"github.com/revel/revel"
"fmt"
)
func Log(i interface{}) {
@@ -12,4 +13,14 @@ func Log(i interface{}) {
func LogJ(i interface{}) {
b, _ := json.MarshalIndent(i, "", " ")
revel.INFO.Println(string(b))
}
}
// 为test用
func L(i interface{}) {
fmt.Println(i)
}
func LJ(i interface{}) {
b, _ := json.MarshalIndent(i, "", " ")
fmt.Println(string(b))
}
+4 -2
View File
@@ -51,6 +51,7 @@ func init() {
// Id retrieves from the cookie or creates a time-based UUID identifying this
// session.
func (s Session) Id() string {
if sessionIdStr, ok := s[SESSION_ID_KEY]; ok {
return sessionIdStr
}
@@ -131,7 +132,7 @@ func getSessionFromCookie(cookie *http.Cookie) Session {
return session
}
sig, data := cookie.Value[:hyphen], cookie.Value[hyphen+1:]
// Verify the signature.
if !revel.Verify(data, sig) {
revel.INFO.Println("Session cookie signature failed")
@@ -145,7 +146,7 @@ func getSessionFromCookie(cookie *http.Cookie) Session {
if sessionTimeoutExpiredOrMissing(session) {
session = make(Session)
}
return session
}
@@ -157,6 +158,7 @@ func SessionFilter(c *revel.Controller, fc []revel.Filter) {
// c.Session, 重新生成一个revel.Session给controller!!!
// Log("sessoin--------")
// LogJ(session)
revelSession := revel.Session(session) // 强制转换 还是同一个对象, 但有个问题, 这样Session.Id()方法是用revel的了
c.Session = revelSession
// 生成sessionId
+24 -8
View File
@@ -7,6 +7,7 @@ import (
"io/ioutil"
"strings"
)
/*
用golang exec 总是说找不到uglifyjs命令, 需要全部路径
而且node, npm要在/usr/bin下, 已建ln
@@ -31,7 +32,7 @@ import (
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
var jss = []string{"js/jquery-cookie", "js/bootstrap",
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
"js/object_id"}
var base1 = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/"
var base = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/"
@@ -52,7 +53,7 @@ func compressJs(filename string) {
to := base + filename + "-min.js"
cmd := exec.Command(cmdPath, source, "-o", to)
_, err := cmd.CombinedOutput()
fmt.Println(source);
cmdError(err)
}
@@ -80,7 +81,10 @@ func combineJs() {
// 改note-dev->note
func dev() {
// 即替换note.js->note-min.js
m := map[string]string{"note.js": "note-min.js",
m := map[string]string{"tinymce.dev.js": "tinymce.min.js",
"tinymce.js": "tinymce.min.js",
"jquery.ztree.all-3.5.js": "jquery.ztree.all-3.5-min.js",
"note.js": "note-min.js",
"app.js": "app-min.js",
"page.js": "page-min.js",
"common.js": "common-min.js",
@@ -88,6 +92,7 @@ func dev() {
"share.js": "share-min.js",
"tag.js": "tag-min.js",
"main.js": "main-min.js",
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
"editor/editor.js": "editor/editor-min.js",
"/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js",
@@ -111,12 +116,21 @@ func tinymce() {
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify")
cmd.Dir = "/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master"
c, err := cmd.CombinedOutput()
// 必须要先删除
cmd2 := exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.dev.js")
cmd2.CombinedOutput()
cmd2 = exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.jquery.dev.js")
c, _ := cmd2.CombinedOutput()
fmt.Println(string(c))
c, _ = cmd.CombinedOutput()
fmt.Println(string(c))
cmdError(err)
}
func main() {
// 压缩tinymce
tinymce()
dev();
// 其它零散的需要压缩的js
@@ -133,6 +147,10 @@ func main() {
"mdeditor/editor/underscore",
"mdeditor/editor/mathJax",
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
"js/app/editor_drop_paste",
"js/app/attachment_upload",
"js/jquery.ztree.all-3.5",
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
}
for _, js := range otherJss {
@@ -141,7 +159,5 @@ func main() {
// 先压缩后合并
combineJs()
// 压缩tinymce
tinymce()
}
+18 -6
View File
@@ -15,16 +15,16 @@ type AttachService struct {
}
// add attach
func (this *AttachService) AddAttach(attach info.Attach) bool {
func (this *AttachService) AddAttach(attach info.Attach) (ok bool, msg string) {
attach.CreatedTime = time.Now()
ok := db.Insert(db.Attachs, attach)
ok = db.Insert(db.Attachs, attach)
if ok {
// 更新笔记的attachs num
this.updateNoteAttachNum(attach.NoteId, 1)
}
return ok
return
}
// 更新笔记的附件个数
@@ -46,8 +46,8 @@ func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int)
// list attachs
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
attachs := []info.Attach{}
// 判断是否有权限为笔记添加附件
if !shareService.HasUpdateNotePerm(noteId, userId) {
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
return attachs
}
@@ -56,6 +56,7 @@ func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
return attachs
}
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
}
@@ -105,7 +106,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
// 获取文件路径
// 要判断是否具有权限
// userId是否具有attach的访问权限
func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attach) {
func (this *AttachService) GetAttach(attachId, userId, token, sessionId string) (attach info.Attach) {
if attachId == "" {
return
}
@@ -136,6 +137,17 @@ func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attac
return
}
//userId为空则是分享笔记的附件
if userId == "" && sessionId != "" {
if token != "" {
realToken := sessionService.GetToken(sessionId)
if token == realToken {
Log("attach token is equal!")
return
}
}
}
attach = info.Attach{}
return
}
+9 -2
View File
@@ -5,6 +5,7 @@ import (
// "github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
// "github.com/revel/revel"
"strings"
. "github.com/leanote/leanote/app/lea"
"fmt"
"strconv"
@@ -17,6 +18,8 @@ type AuthService struct {
// pwd已md5了
func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
emailOrUsername = strings.Trim(emailOrUsername, " ")
// pwd = strings.Trim(pwd, " ")
userInfo := userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
return userInfo
}
@@ -32,12 +35,16 @@ func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
// 1. 添加用户
// 2. 将leanote共享给我
// [ok]
func (this *AuthService) Register(email, pwd string) (bool, string) {
func (this *AuthService) Register(email, pwd, fromUserId string) (bool, string) {
// 用户是否已存在
if userService.IsExistsUser(email) {
return false, "userHasBeenRegistered-" + email
}
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
if fromUserId != "" && IsObjectId(fromUserId) {
user.FromUserId = bson.ObjectIdHex(fromUserId)
}
LogJ(user)
return this.register(user)
}
@@ -129,4 +136,4 @@ func (this *AuthService) ThirdRegister(thirdType, thirdUserId, thirdUsername str
}
_, _ = this.register(userInfo)
return
}
}
+12 -6
View File
@@ -353,7 +353,7 @@ func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sort
// 上一篇文章, 下一篇文章
// sorterField, baseTime是基准, sorterField=PublicTime, title
// isAsc是用户自定义的排序方式
func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bool, baseTime interface{}) (info.Post, info.Post) {
func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bool, noteId string, baseTime interface{}) (info.Post, info.Post) {
userIdO := bson.ObjectIdHex(userId)
var sortFieldT1, sortFieldT2 bson.M
@@ -367,10 +367,10 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo
--
*/
// 上一篇时间要比它大, 找最小的
sortFieldT1 = bson.M{"$gt": baseTime}
sortFieldT1 = bson.M{"$gte": baseTime} // 为什么要相等, 因为将notebook发布成博客, 会统一修改note的publicTime, 此时所有notes都一样
sortFieldR1 = sorterField
// 下一篇时间要比它小
sortFieldT2 = bson.M{"$lt": baseTime}
sortFieldT2 = bson.M{"$lte": baseTime}
sortFieldR2 = "-" + sorterField
} else {
// 升序
@@ -381,22 +381,28 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo
---------
*/
// 上一篇要比它小, 找最大的
sortFieldT1 = bson.M{"$lt": baseTime}
sortFieldT1 = bson.M{"$lte": baseTime}
sortFieldR1 = "-" + sorterField
// 下一篇, 找最小的
sortFieldT2 = bson.M{"$gt": baseTime}
sortFieldT2 = bson.M{"$gte": baseTime}
sortFieldR2 = sorterField
}
// 上一篇, 比基时间要小, 但是是最后一篇, 所以是降序
note := info.Note{}
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true,
query := bson.M{"UserId": userIdO,
"IsTrash": false,
"IsBlog": true,
"_id": bson.M{"$ne": bson.ObjectIdHex(noteId)},
sorterField: sortFieldT1,
}
q := db.Notes.Find(query)
q.Sort(sortFieldR1).Limit(1).One(&note)
// 下一篇, 比基时间要大, 但是是第一篇, 所以是升序
if note.NoteId != "" {
query["_id"] = bson.M{"$nin": []bson.ObjectId{bson.ObjectIdHex(noteId), note.NoteId}}
}
note2 := info.Note{}
query[sorterField] = sortFieldT2
// Log(isAsc)
+39 -6
View File
@@ -9,6 +9,7 @@ import (
"time"
"os"
"strings"
// "fmt"
)
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
@@ -17,7 +18,7 @@ type FileService struct {
}
// add Image
func (this *FileService) AddImage(image info.File, albumId, userId string) bool {
func (this *FileService) AddImage(image info.File, albumId, userId string, needCheckSize bool) (ok bool, msg string) {
image.CreatedTime = time.Now()
if albumId != "" {
image.AlbumId = bson.ObjectIdHex(albumId)
@@ -27,7 +28,8 @@ func (this *FileService) AddImage(image info.File, albumId, userId string) bool
}
image.UserId = bson.ObjectIdHex(userId)
return db.Insert(db.Files, image)
ok = db.Insert(db.Files, image)
return
}
// list images
@@ -117,7 +119,8 @@ func (this *FileService) UpdateImage(userId, fileId, title string) bool {
// 获取文件路径
// 要判断是否具有权限
// userId是否具有fileId的访问权限
func (this *FileService) GetFile(userId, fileId string) string {
func (this *FileService) GetFile(userId, fileId , sessionId , token string) string {
if fileId == "" {
return ""
}
@@ -130,7 +133,8 @@ func (this *FileService) GetFile(userId, fileId string) string {
}
// 1. 判断权限
//未登录用户,判断token
noteIds := noteImageService.GetNoteIds(fileId)
// 是否是我的文件
if userId != "" && file.UserId.Hex() == userId {
return path
@@ -140,14 +144,41 @@ func (this *FileService) GetFile(userId, fileId string) string {
// 这些笔记是否有public的, 若有则ok
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
noteIds := noteImageService.GetNoteIds(fileId)
if noteIds != nil && len(noteIds) > 0 {
// 这些笔记是否有public的
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
return path
}
//分享给未注册用户
if userId == "" && sessionId != "" {
if token != "" {
realToken := sessionService.GetToken(sessionId)
if token == realToken {
Log("image token is equal!")
return path
} else {
Log("image token is different!")
return ""
}
} else {
return ""
}
}
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
for _, noteId := range noteIds {
note := noteService.GetNoteById(noteId.Hex())
if shareService.HasReadPerm(note.UserId.Hex(), userId, noteId.Hex()) {
return path;
}
}
/*
// 若有共享给我的笔记?
// 对该笔记可读?
if db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NoteId": bson.M{"$in": noteIds}}) {
return path
}
@@ -166,6 +197,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
return path
}
}
*/
}
// 可能是刚复制到owner上, 但内容又没有保存, 所以没有note->imageId的映射, 此时看是否有fromFileId
@@ -180,6 +212,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
return ""
}
// 复制图片
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
// 是否已经复制过了
@@ -222,7 +255,7 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
id := bson.NewObjectId();
fileInfo.FileId = id
fileId = id.Hex()
Ok := this.AddImage(fileInfo, "", toUserId)
Ok, _ := this.AddImage(fileInfo, "", toUserId, false)
if Ok {
return Ok, id.Hex()
+4 -1
View File
@@ -27,9 +27,12 @@ func (this *GroupService) AddGroup(userId, title string) (bool, info.Group) {
// 删除分组
// 判断是否有好友
func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg string) {
/*
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}) {
return false, "hasUsers"
return false, "groupHasUsers"
}
*/
db.DeleteAll(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)})
return db.DeleteByIdAndUserId(db.Groups, groupId, userId), ""
// TODO 删除分组后, 在shareNote, shareNotebook中也要删除
+3 -2
View File
@@ -33,7 +33,8 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
// TODO
l := len(history.Histories)
if l >= maxSize {
history.Histories = history.Histories[l-maxSize:]
// history.Histories = history.Histories[l-maxSize:] // BUG, 致使都是以前的
history.Histories = history.Histories[:maxSize]
}
newHistory := []info.EachHistory{eachHistory}
newHistory = append(newHistory, history.Histories...) // 在开头加了, 最近的在最前
@@ -61,4 +62,4 @@ func (this *NoteContentHistoryService) ListHistories(noteId, userId string) []in
histories := info.NoteContentHistory{}
db.GetByIdAndUserId(db.NoteContentHistories, noteId, userId, &histories)
return histories.Histories
}
}
+11
View File
@@ -17,6 +17,17 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
db.GetByIdAndUserId(db.Notes, noteId, userId, &note)
return
}
//通过附件id得到note
func (this *NoteService) GetNoteByAttachId(attachId string) (note info.Note) {
attach := info.Attach{}
db.Get(db.Attachs, attachId, &attach)
note = info.Note{}
noteId := attach.NoteId
db.Get(db.Notes, noteId.Hex(), &note)
return
}
// fileService调用
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
note = info.Note{}
+23
View File
@@ -17,6 +17,13 @@ func (this *SessionService) Update(sessionId, key string, value interface{}) boo
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{key: value, "UpdatedTime": time.Now()})
}
func (this *SessionService) UpdateToken(sessionId, key string, value interface{}) bool {
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{key: value, "UpdatedTime": time.Now(), "TokenTime": time.Now()})
}
// 注销时清空session
func (this *SessionService) Clear(sessionId string) bool {
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
@@ -69,3 +76,19 @@ func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
Log(ok)
return ok
}
// 附件token
func (this *SessionService) GetToken(sessionId string) string {
session := this.Get(sessionId)
return session.Token
}
func (this *SessionService) SetToken(sessionId, token string) bool {
this.Get(sessionId)
Log(sessionId)
Log(token)
ok := this.UpdateToken(sessionId, "Token", token)
Log(ok)
return ok
}
+63 -1
View File
@@ -7,6 +7,9 @@ import (
"gopkg.in/mgo.v2/bson"
"time"
"sort"
"math/rand"
"regexp"
"strings"
)
// 共享Notebook, Note服务
@@ -49,6 +52,7 @@ func (this *ShareService) getOrQ(userId string) bson.M {
return q
}
// 得到共享给我的笔记本和用户(谁共享给了我)
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
// 得到共享给我的用户s信息
// 得到我参与的组织
@@ -60,7 +64,7 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
db.Distinct(db.ShareNotes, q, "UserId", &userIds1)
userIds2 := []bson.ObjectId{}
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds1)
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds2) // BUG之前是userId1, 2014/12/29
userIds := append(userIds1, userIds2...)
userInfos := userService.GetUserInfosOrderBySeq(userIds);
@@ -336,12 +340,14 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
"ToUserId": bson.ObjectIdHex(toUserId),
});
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId),
ToUserId: bson.ObjectIdHex(toUserId),
Perm: perm,
CreatedTime: time.Now(),
}
return db.Insert(db.ShareNotes, shareNote), "", toUserId
}
@@ -776,3 +782,59 @@ func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId s
"ToGroupId": bson.ObjectIdHex(groupId),
});
}
func (this *ShareService) GenSharePass(noteId string) (int, bool) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
pass := 1000 + r.Intn(9000)
ok := db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$set": bson.M{"SharePass": pass}})
return pass, ok
}
func (this *ShareService) QuerySharePass(noteId string) int {
note := &info.Note{}
db.Get(db.Notes, noteId, note)
return note.SharePass
}
func (this *ShareService) Verify4ShareNote(noteId string, sharePass int) (flag bool, note info.Note, noteContent info.NoteContent) {
note = info.Note{}
db.Get(db.Notes, noteId, &note)
if note.SharePass == sharePass {
note = noteService.GetNoteById(noteId)
noteContent = noteService.GetNoteContent(noteId, note.UserId.Hex())
flag = true
} else {
note = info.Note{}
noteContent = info.NoteContent{}
flag = false
}
return
}
//把笔记中含有attachID的url后加上token,返回笔记中含有的attachids
func (this *ShareService) AppendToken4URL(token, content string) (c string, attachIds map[string]bool) {
re := regexp.MustCompile(`href=\"(.*?attachId.*?)\".*?data-mce-href=\"(.*?attachId.*?)\"`)
re2 := regexp.MustCompile(`\"(.*?attachId.*?)\"`)
attachIds = map[string]bool{}
s := re.ReplaceAllStringFunc(content, func(m string) string {
idx := strings.Index(m, "attachId=") + len("attachId=")
var ss []byte = []byte(m)
attachId := string(ss[idx: idx + 24])
attachIds[attachId] = true
return re2.ReplaceAllString(m, `"${1}&token=` + token + `"`)
})
re3 := regexp.MustCompile(`<img\s+src=\"(.*?fileId.*?)\".*?data-mce-src=\"(.*?fileId.*?)\"`)
re4 := regexp.MustCompile(`\"(.*?fileId.*?)\"`)
c = re3.ReplaceAllStringFunc(s, func(m string) string {
return re4.ReplaceAllString(m, `"${1}&token=` + token + `"`)
})
return
}
+130 -5
View File
@@ -13,6 +13,7 @@ import (
"fmt"
"html/template"
"regexp"
"io/ioutil"
"encoding/json"
)
@@ -127,7 +128,8 @@ func (this *ThemeService) CopyDefaultTheme(userBlog info.UserBlog) (ok bool, the
// 设为active true
func (this *ThemeService) NewThemeForFirst(userBlog info.UserBlog) (ok bool, themeId string) {
ok, themeId = this.CopyDefaultTheme(userBlog)
db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true)
this.ActiveTheme(userBlog.UserId.Hex(), themeId)
// db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true)
return
}
@@ -285,11 +287,15 @@ func (this *ThemeService) GetThemePath(userId, themeId string) string {
}
// 更新模板内容
func (this *ThemeService) UpdateTplContent(userId, themeId, filename, content string) (ok bool, msg string) {
path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename
basePath := this.GetThemeAbsolutePath(userId, themeId)
path := basePath + "/" + filename
if strings.Contains(filename, ".html") {
// 模板
if ok, msg = this.mustTpl(filename, content); ok {
ok = PutFileStrContent(path, content)
Log(">>")
if ok, msg = this.ValidateTheme(basePath, filename, content); ok {
// 模板
if ok, msg = this.mustTpl(filename, content); ok {
ok = PutFileStrContent(path, content)
}
}
return
} else if filename == "theme.json" {
@@ -410,6 +416,11 @@ func (this *ThemeService) ImportTheme(userId, path string) (ok bool, msg string)
DeleteFile(targetPath)
return
}
// 主题验证
if ok, msg = this.ValidateTheme(targetPath, "", ""); !ok {
DeleteFile(targetPath)
return
}
// 解压成功, 那么新建之
// 保存到数据库中
theme, _ := this.getThemeConfig(targetPath)
@@ -505,5 +516,119 @@ func (this *ThemeService) InstallTheme(userId, themeId string) (ok bool) {
ok = db.Insert(db.Themes, theme)
// 激活之
this.ActiveTheme(userId, themeId);
return ok
}
// 验证主题是否全法, 存在循环引用?
// filename, newContent 表示在修改模板时要判断模板修改时是否有错误
func (this *ThemeService) ValidateTheme(path string, filename, newContent string) (ok bool, msg string) {
Log("theme Path")
Log(path)
// 建立一个有向图
// 将该path下的所有文件提出, 得到文件的引用情况
files := ListDir(path)
LogJ(files);
size := len(files)
if(size > 100) {
ok = false;
msg = "tooManyFiles"
return
}
/*
111111111
111000000
*/
vector := make([][]int, size)
for i := 0; i < size; i++ {
vector[i] = make([]int, size)
}
fileIndexMap := map[string]int{} // fileName => index
fileContent := map[string]string{} // fileName => content
index := 0
// 得到文件内容, 和建立索引, 每个文件都有一个index, 对应数组位置
for _, t := range files {
if !strings.Contains(t, ".html") {
continue;
}
if t != filename {
fileBytes, err := ioutil.ReadFile(path + "/" + t)
if err != nil {
continue
}
fileIndexMap[t] = index;
// html内容
fileStr := string(fileBytes)
fileContent[t] = fileStr
} else {
fileIndexMap[t] = index
fileContent[t] = newContent
}
index++
}
// 分析文件内容, 建立有向图
reg, _ := regexp.Compile("{{ *template \"(.+?\\.html)\".*}}")
for filename, content := range fileContent {
thisIndex := fileIndexMap[filename]
finds := reg.FindAllStringSubmatch(content, -1) // 子匹配
LogJ(finds)
// Log(content)
if finds != nil && len(finds) > 0 {
for _, includes := range finds {
include := includes[1]
includeIndex, has := fileIndexMap[include]
Log(includeIndex)
Log("??")
Log(has)
if has {
vector[thisIndex][includeIndex] = 1
}
}
}
}
LogJ(vector)
LogJ(fileIndexMap)
// 建立图后, 判断是否有环
if this.hasRound(vector, index) {
ok = false
msg = "themeValidHasRoundInclude"
} else {
ok = true
}
return;
}
// 检测有向图是否有环, DFS
func (this *ThemeService) hasRound(vector [][]int, size int) (ok bool) {
for i := 0; i < size; i++ {
visited := make([]int, size)
if this.hasRoundEach(vector, i, size, visited) {
Log(">>")
Log(i);
return true;
}
}
return false
}
// 从每个节点出发, 判断是否有环
func (this *ThemeService) hasRoundEach(vector [][]int, index int, size int, visited []int) (ok bool) {
if visited[index] > 0 {
Log("<")
Log(index)
return true
}
visited[index] = 1;
// 遍历它的孩子
for i := 0; i < size; i++ {
if vector[index][i] > 0 {
return this.hasRoundEach(vector, i, size, visited);
}
}
visited[index] = 0;
return false;
}
+8 -1
View File
@@ -48,6 +48,13 @@ func (this *UserService) GetUsername(userId string) string {
return user.Username
}
// 得到用户名
func (this *UserService) GetUsernameById(userId bson.ObjectId) string {
user := info.User{}
db.GetByQWithFields(db.Users, bson.M{"_id": userId}, []string{"Username"}, &user)
return user.Username
}
// 是否存在该用户 email
func (this *UserService) IsExistsUser(email string) bool {
if this.GetUserId(email) == "" {
@@ -369,7 +376,7 @@ func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg s
// 宽度
func (this *UserService)UpdateColumnWidth(userId string, notebookWidth, noteListWidth, mdEditorWidth int) bool {
return db.UpdateByQMap(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)},
bson.M{"NotebookWidth": notebookWidth, "NoteListWidth": noteListWidth, "mdEditorWidth": mdEditorWidth})
bson.M{"NotebookWidth": notebookWidth, "NoteListWidth": noteListWidth, "MdEditorWidth": mdEditorWidth})
}
// 左侧是否隐藏
func (this *UserService)UpdateLeftIsMin(userId string, leftIsMin bool) bool {
+1 -1
View File
@@ -84,7 +84,7 @@
</section>
<footer class="footer lt hidden-xs b-t b-light" style="min-height: initial;
padding: 10px 15px;text-align:center;">
<a href="http://leanote.com" target="_blank">leanote</a> © 2014
<a href="http://leanote.com" target="_blank">leanote</a> © 2015
<!--
<a href="#nav" data-toggle="class:nav-xs" class="pull-right btn btn-sm btn-default btn-icon">
<i class="fa fa-angle-left text">
+63
View File
@@ -0,0 +1,63 @@
{{template "home/header_box.html" .}}
<section id="box">
<div>
<div>
<h1 class="h text-white animated fadeInDownBig">ERROR!</h1>
</div>
<div id="errorBox">
<p class="error-info">
Sorry, you(not we) got an error. This error is just showing in blog preview for test.
</p>
<div class="list-group m-b-sm bg-white m-b-lg">
{{with .Error}}
<div id="header" class="block">
<h1>
{{.Title}}
</h1>
<p>
{{if .SourceType}}
The {{.SourceType}} <strong>{{.Path}}</strong> does not compile: <strong>{{.Description}}</strong>
{{else}}
{{.Description}}
{{end}}
</p>
</div>
{{if .Path}}
<div id="source" class="block">
<h2>In {{.Path}}
{{if .Line}}
(around {{if .Line}}line {{.Line}}{{end}}{{if .Column}} column {{.Column}}{{end}})
{{end}}
</h2>
{{range .ContextSource}}
<div class="line {{if .IsError}}error{{end}}">
<span class="lineNumber">{{.Line}}:</span>
<pre>{{.Source}}</pre>
</div>
{{end}}
</div>
{{end}}
{{if .MetaError}}
<div id="source" class="block">
<h2>Additionally, an error occurred while handling this error.</h2>
<div class="line error">
{{.MetaError}}
</div>
</div>
{{end}}
{{end}}
</div>
</div>
</div>
</section>
<div id="boxFooter">
<p>
<a href="/index">leanote</a> © 2014
</p>
</div>
</body>
</html>
-1
View File
@@ -44,7 +44,6 @@ function log(o) {
-->
<li><a href="/index#download" target="#download" class="smooth-scroll">{{msg . "download"}}</a> </li>
<li><a href="/index#donate" target="#donate" class="smooth-scroll">{{msg . "donate"}}</a> </li>
<li><a id="leanoteBlog" href="{{.leaUrl}}/index" target="_blank" title="lea++, leanote博客平台" class="">lea++</a></li>
<li style="position: relative; margin-right: 3px;">
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
<div class="red-circle" style=""></div>
+3 -1
View File
@@ -100,7 +100,9 @@ $(function() {
$("#registerBtn").html("{{msg . "ing"}}...").addClass("disabled");
// hideMsg();
$.post("/doRegister", {email: email, pwd: pwd}, function(e) {
var iu = "{{.iu}}";
$.post("/doRegister", {email: email, pwd: pwd, iu: iu}, function(e) {
$("#registerBtn").html("{{msg . "register"}}").removeClass("disabled");
if(e.Ok) {
$("#registerBtn").html("{{msg . "registerSuccessAndRdirectToNote"}}");
+10 -10
View File
@@ -1,13 +1,13 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">
{{if .page}}
修改页面
{{if .single}}
{{msg . "updateSingle"}}
{{else}}
添加页面
{{msg . "addSingle"}}
{{end}}
</h3></div>
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" type="text/css">
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" type="text/css">
<div class="row">
<div class="col-sm-10">
<form id="formData">
@@ -16,18 +16,18 @@
<div class="alert alert-danger" id="baseMsg" style="display: none"></div>
<input type="hidden" id="singleId" value="{{.single.SingleId.Hex}}" />
<div class="form-group">
<label>标题</label>
<label>{{msg . "title"}}</label>
<input type="text" class="form-control" id="title" name="title"
value="{{.single.Title}}"
data-rules='[
{rule: "required", msg: "请输入页面标题"},
{rule: "required", msg: "{{msg . "inputSingleTitle"}}"},
]'
data-msg_target="#baseMsg"
/>
</div>
<div class="form-group">
<label for="content1">内容</label>
<label for="content1">{{msg . "content"}}</label>
<div id="popularToolbar"></div>
<textarea id="content1" name="content">{{.single.Content}}</textarea>
</div>
@@ -41,9 +41,9 @@
</div>
{{template "member/footer.html" .}}
<script type="text/javascript" src="/tinymce/tinymce.min.js"></script>
<script type="text/javascript" src="/tinymce/tinymce.js"></script>
<script>
var urlPrefix = "{{.siteUrl}}";
var urlPrefix = "{{.siteUrl}}";
$(function() {
tinymce.init({
selector : "#content1",
@@ -55,7 +55,7 @@ $(function() {
skin : "custom",
plugins : [
"advlist autolink link leanote_image lists charmap hr ",
"searchreplace visualblocks visualchars leanote_code tabfocus",
"searchreplace visualblocks visualchars tabfocus",
"table contextmenu directionality textcolor paste fullpage textcolor"],
toolbar1 : "formatselect |fontselect fontsizeselect| forecolor backcolor | bold italic underline strikethrough | bullist numlist |",
menubar : false,
+9 -15
View File
@@ -1,29 +1,26 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "baseInfoSet"}}</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg $ "basicInfoSet"}}</h3></div>
<div class="row">
<div class="col-sm-10">
<div class="col-sm-8">
<div id="formData">
<section class="panel panel-default">
<div class="panel-body">
<div class="alert alert-danger" id="baseMsg" style="display: none"></div>
<div class="form-horizontal" role="form" id="userBlogForm">
<div role="form" id="userBlogForm">
<div class="form-group">
<label for="title" class="col-sm-2 control-label">{{msg . "blogName"}}</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="Title" name="Title"
<label for="title" >{{msg . "blogName"}}</label>
<input type="text" class="form-control" id="Title" name="Title"
placeholder="eg: leanote's blog"
value="{{if .userBlog.Title}}{{.userBlog.Title}}{{else}}{{.userInfo.Email}} 's blog{{end}}">
</div>
</div>
<div class="form-group">
<label for="logo" class="col-sm-2 control-label">{{msg . "blogLogo"}}</label>
<div class="col-sm-10">
<label for="logo">{{msg . "blogLogo"}}</label>
<input type="hidden" name="Logo" id="Logo"
value="{{.userBlog.Logo}}" />
<form id="formLogo" action="{{$.siteUrl}}/file/uploadBlogLogo" method="post"
<form id="formLogo" action="/file/uploadBlogLogo" method="post"
enctype="multipart/form-data" target="logoTarget">
<input type="file" class="form-control" id="logo2" name="file"
onChange='$("#formLogo").submit();' />
@@ -37,16 +34,13 @@
</div>
</form>
<iframe id="logoTarget" name="logoTarget" src="#" style="display: none"></iframe>
</div>
</div>
<div class="form-group">
<label for="subTitle" class="col-sm-2 control-label">{{msg . "blogDesc"}}</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="SubTitle"
<label for="subTitle">{{msg . "blogDesc"}}</label>
<input type="text" class="form-control" id="SubTitle"
name="SubTitle" value="{{.userBlog.SubTitle}}"
placeholder="eg: leanote, Not Just A Notebook">
</div>
</div>
<div class="form-group">
+14 -6
View File
@@ -1,29 +1,37 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">(笔记本)分类</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "cate"}}</h3></div>
<div class="row">
<div class="col-sm-8">
<section class="panel panel-default">
<div class="panel-body">
分类是公开为博客的笔记本
{{msg . "cateIsPublicNotebook"}}
<br />
拖动可排序
{{if .notebooks}}
{{msg . "dragAndSort"}}
<ul class="list-group gutter list-group-lg list-group-sp sortable">
{{range .notebooks}}
<li class="list-group-item" draggable="true" data-id="{{.NotebookId.Hex}}">
<span class="pull-left media-xs"><i class="fa fa-sort text-muted fa m-r-sm"></i></span>
<div class="pull-right" style="margin-right: 10px">
固定链接: /cate/<input data-id="{{.NotebookId.Hex}}" class="url-title" type="text" value="{{if .UrlTitle}}{{.UrlTitle|decodeUrlValue}}{{else}}{{.NotebookId.Hex}}{{end}}"/>
{{msg $ "permanentLink"}}: /cate/<input data-id="{{.NotebookId.Hex}}" class="url-title" type="text" value="{{if .UrlTitle}}{{.UrlTitle|decodeUrlValue}}{{else}}{{.NotebookId.Hex}}{{end}}"/>
</div>
{{.Title}}
</li>
{{end}}
</ul>
{{else}}
{{msg . "noCates"}}
{{end}}
</div>
{{if .notebooks}}
<footer class="panel-footer text-right bg-light lter">
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "saveSort"}}</button>
</footer>
{{end}}
</section>
</div>
</div>
@@ -36,7 +44,7 @@ $(function() {
$(".list-group-item").each(function() {
ids.push($(this).data("id"));
});
ajaxPost("/member/blog/", {cateIds: ids}, function(re){
ajaxPost("/member/blog/upateCateIds", {cateIds: ids}, function(re){
if(reIsOk(re)) {
art.tips("Success");
} else {
+1 -1
View File
@@ -22,7 +22,7 @@
<input type="radio"
name="commentType"
value="default"
{{if or (not .userBlog.CommentType) (eq .userBlog.CommentType "default")}}checked="checked"{{end}} > Default
{{if or (not .userBlog.CommentType) (eq .userBlog.CommentType "default")}}checked="checked"{{end}} > {{msg $ "defaultComment"}}
</label>
<label>
+9 -9
View File
@@ -1,5 +1,5 @@
{{template "member/top.html" .}}
<div class="m-b-md"><h3 class="m-b-none">文章列表</h3></div>
<div class="m-b-md"><h3 class="m-b-none">{{msg . "postList"}}</h3></div>
<style>
.url-title {
width: 260px;
@@ -13,7 +13,7 @@
</div>
<div class="col-sm-3">
<div class="input-group search-group">
<input type="text" class="input-sm form-control" placeholder="Title" id="keywords" value="{{.keywords}}" />
<input type="text" class="input-sm form-control" placeholder="{{msg . "title"}}" id="keywords" value="{{.keywords}}" />
<span class="input-group-btn">
<button class="btn btn-sm btn-default" type="button" data-url="/member/blog/index">Search</button>
</span>
@@ -40,7 +40,7 @@
style="width: 300px"
{{sorterTh $url "urlTitle" .sorter}}
>
固定链接
{{msg $ "permanentLink"}}
<span class="th-sort">
<i class="fa fa-sort-down"></i>
<i class="fa fa-sort-up"></i>
@@ -50,7 +50,7 @@
<th
{{sorterTh $url "publicTime" .sorter}}
>
发布日期
{{msg . "publicTime"}}
<span class="th-sort">
<i class="fa fa-sort-down"></i>
<i class="fa fa-sort-up"></i>
@@ -61,7 +61,7 @@
<th
{{sorterTh $url "updatedTime" .sorter}}
>
更新日期
{{msg . "updatedTime"}}
<span class="th-sort">
<i class="fa fa-sort-down"></i>
<i class="fa fa-sort-up"></i>
@@ -71,7 +71,7 @@
<th
{{sorterTh $url "createdTime" .sorter}}
>
创建日期
{{msg . "createdTime"}}
<span class="th-sort">
<i class="fa fa-sort-down"></i>
<i class="fa fa-sort-up"></i>
@@ -114,13 +114,13 @@
<a
{{if .HasSelfDefined}}
title="已设置"
title="{{msg $ "hasSelfDefined"}}"
class="btn btn-sm btn-success"
{{else}}
title="未设置"
title="{{msg $ "noSelfDefined"}}"
class="btn btn-sm btn-default"
{{end}}
href="/member/blog/updateBlogAbstract?noteId={{.NoteId.Hex}}">摘要设置</a>
href="/member/blog/updateBlogAbstract?noteId={{.NoteId.Hex}}">{{msg $ "setAbstract"}}</a>
</td>
</tr>
{{end}}
+18 -26
View File
@@ -1,5 +1,5 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">分页与排序设置</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg $ "pagingAndSort"}}</h3></div>
<div class="row">
<div class="col-sm-8">
@@ -8,43 +8,35 @@
<div class="panel-body">
<div class="alert alert-danger" id="domainMsg" style="display: none"></div>
<form class="form-horizontal" role="form" id="dataFrom">
<form role="form" id="dataFrom">
<div class="form-group">
<label for="perPageSize" class="col-sm-2 control-label">每页记录数</label>
<div class="col-sm-10">
<input type="text" class="form-control"
<label for="perPageSize">{{msg . "perPageSize"}}</label>
<input type="text" class="form-control"
placeholder="10"
id="perPageSize"
name="perPageSize"
value="{{.userBlog.PerPageSize}}" />
</div>
</div>
<div class="form-group">
<label for="perPageSize" class="col-sm-2 control-label">排序字段</label>
<div class="col-sm-10">
<select class="form-control"
id="sortField"
name="sortField"
value="">
<option value="PublicTime" {{if eq $.userBlog.SortField "PublicTime"}}selected{{end}}>公开为博客时间</option>
<option value="CreatedTime" {{if eq $.userBlog.SortField "CreatedTimeTime"}}selected{{end}}>创建时间</option>
<option value="UpdatedTime" {{if eq $.userBlog.SortField "UpdatedTime"}}selected{{end}}>更新时间</option>
<option value="Title" {{if eq $.userBlog.SortField "Title"}}selected{{end}}>标题</option>
</select>
</div>
<label for="perPageSize" >{{msg . "sortField"}}</label>
<select class="form-control"
id="sortField"
name="sortField"
value="">
<option value="PublicTime" {{if eq $.userBlog.SortField "PublicTime"}}selected{{end}}>{{msg $ "publicTime"}}</option>
<option value="CreatedTime" {{if eq $.userBlog.SortField "CreatedTimeTime"}}selected{{end}}>{{msg $ "createdTime"}}</option>
<option value="UpdatedTime" {{if eq $.userBlog.SortField "UpdatedTime"}}selected{{end}}>{{msg $ "updatedTime"}}</option>
<option value="Title" {{if eq $.userBlog.SortField "Title"}}selected{{end}}>{{msg . "title"}}</option>
</select>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">排序类型</label>
<div class="col-sm-10" style="margin-top: 5px;">
<label><input type="radio" name="isAsc" value="0" {{if not .userBlog.IsAsc}}checked{{end}}> 降序</label>
<label><input type="radio" name="isAsc" value="1" {{if .userBlog.IsAsc}}checked{{end}}> 升序</label>
<label>{{msg $ "sortType"}}</label>
<div>
<label><input type="radio" name="isAsc" value="0" {{if not .userBlog.IsAsc}}checked{{end}}> {{msg . "desc"}}</label>
<label><input type="radio" name="isAsc" value="1" {{if .userBlog.IsAsc}}checked{{end}}> {{msg . "asc"}}</label>
</div>
</div>
</form>
</div>
<footer class="panel-footer text-right bg-light lter">
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
+7 -7
View File
@@ -1,13 +1,13 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">单页面</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "single"}}</h3></div>
<div class="row">
<div class="col-sm-8">
<section class="panel panel-default">
<div class="panel-body">
<p>
您可以添加多个单页面
<a href="/member/blog/addOrUpdateSingle" id="addBtn" class="btn btn-success">添加页面</a>
{{msg $ "singleTips"}}
<a href="/member/blog/addOrUpdateSingle" id="addBtn" class="btn btn-success">{{msg $ "addSingle"}}</a>
</p>
<ul class="list-group gutter list-group-lg list-group-sp sortable">
{{range .singles}}
@@ -18,7 +18,7 @@
<a href="#"><i class="fa fa-times icon-muted fa-fw page-delete" data-id="{{.SingleId}}"></i></a>
</span>
<div class="pull-right" style="margin-right: 10px">
固定链接: /single/<input data-id="{{.SingleId}}" class="url-title" type="text" value="{{if .UrlTitle}}{{.UrlTitle|decodeUrlValue}}{{else}}{{.SingleId}}{{end}}"/>
{{msg $ "permanentLink"}}: /single/<input data-id="{{.SingleId}}" class="url-title" type="text" value="{{if .UrlTitle}}{{.UrlTitle|decodeUrlValue}}{{else}}{{.SingleId}}{{end}}"/>
</div>
<div class="clear">
{{.Title}}
@@ -29,7 +29,7 @@
</div>
{{if .singles}}
<footer class="panel-footer text-right bg-light lter">
<button type="submit" id="baseBtn" class="btn btn-success">保存排序</button>
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "saveSort"}}</button>
</footer>
{{end}}
</section>
@@ -37,7 +37,7 @@
</div>
{{template "member/footer.html" .}}
<script type="text/javascript" src="{{.siteUrl}}/public/member/js/jquery.sortable.js"></script>
<script type="text/javascript" src="/public/member/js/jquery.sortable.js"></script>
<script>
$(function() {
$("#baseBtn").click(function(){
@@ -79,7 +79,7 @@ $(function() {
art.alert(re.Msg || "error");
}
});
});
});
});
</script>
+43 -20
View File
@@ -2,9 +2,13 @@
<div class="m-b-md clearfix">
<h3 class="m-b-none">
{{msg . "themeSet"}}
<small>(<a href="http://blog.leanote.com/post/545f1a5c380782565e000000" target="_blank">{{msg . "needHelp"}}</a>)</small>
<small>
(<a href="http://blog.leanote.com/post/545f1a5c380782565e000000" target="_blank">{{msg . "needHelp"}}</a>
<a target="_blank" href="https://github.com/leanote/leanote/wiki/leanote-blog-theme-api">Leanote Blog Theme Api</a>)
</small>
</h3>
</div>
<div class="row">
<div class="col-sm-12 theme-container">
<section class="panel panel-default">
@@ -12,9 +16,9 @@
<div>
<form id="uploadAvatar" method="post" action="/member/blog/importTheme" enctype="multipart/form-data">
<div id="dropAvatar" class="dropzone">
<a class="btn btn-default btn-new" href="/member/blog/newTheme"><span class="fa fa-plus"></span> 新建主题</a>
<a class="btn btn-default btn-new" href="/member/blog/newTheme"><span class="fa fa-plus"></span> {{msg . "addTheme"}}</a>
<a class="btn btn-success btn-choose-file">
<span class="fa fa-upload"></span> 导入主题(.zip)
<span class="fa fa-upload"></span> {{msg . "importTheme"}}(.zip)
</a>
<input type="file" name="file" multiple/>
<div id="avatarUploadMsg"></div>
@@ -22,10 +26,10 @@
</form>
</div>
<p>
当前主题:
{{msg . "currentTheme"}}:
</p>
<ul class="themes">
<li class="theme">
<div class="themes clearfix">
<div class="theme pull-left">
<a class="choose-theme" data-method="put" href="#" rel="nofollow">
<div class="theme-thumb thumb active-theme">
<img src="/{{.activeTheme.Path}}/images/screenshot.png" alt="preview">
@@ -37,17 +41,26 @@
</span>
<div class="theme-btns">
<div class="btn-group" data-id="{{.activeTheme.ThemeId.Hex}}">
<a class="btn btn-default btn-sm btn-export"><span class="fa fa-download"></span> 导出</a>
<a class="btn btn-default btn-sm" href="{{$.siteUrl}}/preview?themeId={{.activeTheme.ThemeId.Hex}}" target="_blank"><span class="fa fa-eye"></span> 预览</a>
<a class="btn btn-primary btn-sm" target="_blank" href="/member/blog/updateTheme?themeId={{if .activeTheme.ThemeId}}{{.activeTheme.ThemeId.Hex}}{{end}}"><span class="fa fa-pencil"></span> 编辑</a>
<a class="btn btn-default btn-sm btn-export"><span class="fa fa-download"></span> {{msg $ "export"}}</a>
<!-- 必须是自己的主题 -->
{{if .activeTheme.ThemeId}}
<a class="btn btn-default btn-sm" href="{{$.siteUrl}}/preview?themeId={{.activeTheme.ThemeId.Hex}}" target="_blank"><span class="fa fa-eye"></span> {{msg $ "preview"}}</a>
{{end}}
<a class="btn btn-primary btn-sm" target="_blank" href="/member/blog/updateTheme?themeId={{if .activeTheme.ThemeId}}{{.activeTheme.ThemeId.Hex}}{{end}}"><span class="fa fa-pencil"></span> {{msg $ "edit"}}</a>
</div>
</div>
</li>
</ul>
</div>
{{if .activeTheme.Info.Desc}}
<!-- 描述 -->
<div class="pull-left theme-desc">
{{.activeTheme.Info.Desc|raw}}
</div>
{{end}}
</div>
<hr />
<p>
我的其它主题:
{{msg . "myOtherThemes"}}:
</p>
<ul class="themes">
{{range $.otherThemes}}
@@ -56,6 +69,11 @@
<a class="choose-theme" data-method="put" href="#" rel="nofollow">
<div class="theme-thumb thumb">
<img src="/{{.Path}}/images/screenshot.png" alt="preview">
{{if .Info.Desc}}
<div class="theme-desc-mask">
{{.Info.Desc|raw}}
</div>
{{end}}
</div>
<span class="theme-title">{{.Name}}</span>
</a>
@@ -64,11 +82,11 @@
</span>
<div class="theme-btns">
<div class="btn-group" data-id="{{.ThemeId.Hex}}">
<a class="btn btn-default btn-sm btn-delete" data-loading-text="..."><span class="fa fa-remove"></span> 删除</a>
<a class="btn btn-default btn-sm btn-export"><span class="fa fa-download"></span> 导出</a>
<a class="btn btn-default btn-sm" href="{{$.siteUrl}}/preview?themeId={{.ThemeId.Hex}}" target="_blank"><span class="fa fa-eye"></span> 预览</a>
<a class="btn btn-default btn-sm" target="_blank" href="/member/blog/updateTheme?themeId={{.ThemeId.Hex}}"><span class="fa fa-pencil"></span> 编辑</a>
<a class="btn btn-primary btn-sm btn-active" data-loading-text="..."><span class="fa fa-check"></span> 使用</a>
<a class="btn btn-default btn-sm btn-delete" data-loading-text="..."><span class="fa fa-remove"></span> {{msg $ "delete"}}</a>
<a class="btn btn-default btn-sm btn-export"><span class="fa fa-download"></span> {{msg $ "export"}}</a>
<a class="btn btn-default btn-sm" href="{{$.siteUrl}}/preview?themeId={{.ThemeId.Hex}}" target="_blank"><span class="fa fa-eye"></span> {{msg $ "preview"}}</a>
<a class="btn btn-default btn-sm" target="_blank" href="/member/blog/updateTheme?themeId={{.ThemeId.Hex}}"><span class="fa fa-pencil"></span> {{msg $ "edit"}}</a>
<a class="btn btn-primary btn-sm btn-active" data-loading-text="..."><span class="fa fa-check"></span> {{msg $ "use"}}</a>
{{if $.isAdmin}}
<a class="btn btn-default btn-sm btn-public" data-loading-text="...">
{{if .IsDefault}}
@@ -83,13 +101,13 @@
</li>
{{end}}
{{else}}
无
{{msg $ "none"}}
{{end}}
</ul>
<hr />
<p>
leanote主题市场:
{{msg . "leanoteThemeMarket"}}:
</p>
<ul class="themes">
{{range $.optionThemes}}
@@ -97,6 +115,11 @@
<a class="choose-theme" data-method="put" href="#" rel="nofollow">
<div class="theme-thumb thumb">
<img src="/{{.Path}}/images/screenshot.png" alt="preview">
{{if .Info.Desc}}
<div class="theme-desc-mask">
{{.Info.Desc|raw}}
</div>
{{end}}
</div>
<span class="theme-title">{{.Name}}</span>
</a>
@@ -104,7 +127,7 @@
By: <a href="{{.AuthorUrl}}" target="_blank">{{.Author}}</a>
</span>
<p class="theme-btns" data-id="{{.ThemeId.Hex}}">
<a class="btn btn-primary btn-sm btn-install"><span class="fa fa-gear"></span> 安装</a>
<a class="btn btn-primary btn-sm btn-install"><span class="fa fa-gear"></span> {{msg $ "install"}}</a>
</p>
</li>
{{end}}
+4 -4
View File
@@ -11,7 +11,7 @@
</h3>
</div>
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" type="text/css">
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" type="text/css">
<div class="row">
<div class="col-sm-10">
<form id="formData">
@@ -61,7 +61,7 @@
{{template "member/footer.html" .}}
<script type="text/javascript" src="/tinymce/tinymce.js"></script>
<script>
var UrlPrefix = "{{.siteUrl}}";
var UrlPrefix = "{{.siteUrl}}";
$(function() {
tinymce.init({
selector : "#content1",
@@ -73,9 +73,9 @@ $(function() {
skin : "custom",
plugins : [
"advlist autolink link leanote_image lists charmap hr ",
"searchreplace visualblocks visualchars leanote_code tabfocus",
"searchreplace visualblocks visualchars tabfocus",
"table contextmenu directionality textcolor paste fullpage textcolor"],
toolbar1 : "formatselect |fontselect fontsizeselect| forecolor backcolor | bold italic underline strikethrough | bullist numlist | leanote_code",
toolbar1 : "formatselect |fontselect fontsizeselect| forecolor backcolor | bold italic underline strikethrough | bullist numlist",
menubar : false,
statusbar : false,
font_formats : "Arial=arial,helvetica,sans-serif;"
+19 -14
View File
@@ -2,13 +2,18 @@
<div class="m-b-md">
<h3 class="m-b-none">
{{if .isNew}}
新建主题
{{msg $ "addTheme"}}
{{else}}
编辑主题
{{msg $ "updateTheme"}}
-
{{.theme.Name}}
{{end}}
<a class="btn btn-default" href="{{$.siteUrl}}/preview?themeId={{.themeId}}" target="_blank"><span class="fa fa-eye"></span> 预览</a>
<a class="btn btn-default" href="{{$.siteUrl}}/preview?themeId={{.themeId}}" target="_blank"><span class="fa fa-eye"></span> {{msg . "preview"}}</a>
<small>
(<a href="http://blog.leanote.com/post/545f1a5c380782565e000000" target="_blank">{{msg . "needHelp"}}</a>
<a target="_blank" href="https://github.com/leanote/leanote/wiki/leanote-blog-theme-api">Leanote Blog Theme Api</a>)
</small>
</h3>
</div>
@@ -42,7 +47,7 @@
<div class="col-sm-4">
<section class="panel panel-default">
<header class="panel-heading">
模板, 样式, 脚本:
{{msg . "tplStyleScript"}}:
</header>
<div class="panel-body" style="height:430px;overflow: auto;">
@@ -58,14 +63,14 @@
</div>
</div>
<footer class="panel-footer text-right bg-light lter">
<a class="btn btn-default" id="newFile">新建文件</a>
<a class="btn btn-default" id="newFile">{{msg . "newFile"}}</a>
</footer>
</section>
</div>
<div class="col-sm-8">
<section class="panel panel-default">
<header class="panel-heading">
当前文件: <span id="curTpl">header.html</span>
{{msg . "currentFile"}}: <span id="curTpl">header.html</span>
<span id="msg"></span>
</header>
<div class="panel-body">
@@ -82,7 +87,7 @@
<div class="col-sm-12">
<section class="panel panel-default">
<header class="panel-heading">
图片: images/
{{msg . "image"}}: images/
</header>
<div class="panel-body">
<ul class="image-list" id="imageList">
@@ -102,7 +107,7 @@
</div>
{{template "member/footer.html" .}}
<script src="/public/member/js/ace/ace.js" type="text/javascript"></script>
<script src="/public/libs/ace/ace.js" type="text/javascript"></script>
<script>
var editor = ace.edit("tplContent");
editor.setTheme("ace/theme/tomorrow");
@@ -118,7 +123,7 @@ var theme = {
saveBtnO: $("#saveBtn"),
newFileO: $("#newFile"),
curTpl: "",
tplInfos: {"header.html": "头部", "footer.html": "底部", "index.html": "首页", "cate.html": "分类页", "search.html": "搜索页", "single.html": "单页", "archive.html": "归档页", "post.html": "文章页", "tags.html": "标签页", "tag_posts.html": "标签文章页", "share_comment.html": "分享评论", "404.html":"404", "theme.json": "主题配置", "paging.html": "分页", "highlight.html": "高亮"},
tplInfos: {"header.html": "{{msg . "header"}}", "footer.html": "{{msg . "footer"}}", "index.html": "{{msg . "header"}}", "cate.html": "{{msg . "cate"}}", "search.html": "{{msg . "search"}}", "single.html": "{{msg . "single"}}", "archive.html": "{{msg . "archive"}}", "post.html": "{{msg . "post"}}", "tags.html": "{{msg . "tags"}}", "tag_posts.html": "{{msg . "tag_posts"}}", "share_comment.html": "{{msg . "share_comment"}}", "404.html":"404", "theme.json": "{{msg . "themeJson"}}", "paging.html": "{{msg . "paging"}}", "highlight.html": "{{msg . "highlight"}}"},
init: function() {
var self = this;
self.showTplInfo();
@@ -183,11 +188,11 @@ var theme = {
info = self.tplInfos[file];
if(!info) {
if(file.indexOf(".css") > 0) {
info = "样式";
info = "{{msg . "style"}}";
} else if(file.indexOf(".js") > 0) {
info = "脚本";
info = "{{msg . "script"}}";
} else if(file.indexOf(".html") > 0) {
info = "模板";
info = "{{msg . "tpl"}}";
}
} else {
$(this).find(".remove-file").remove();
@@ -209,7 +214,7 @@ var theme = {
if(t) {
t.button("loading");
}
self.msgO.html("正在保存...");
self.msgO.html("...");
ajaxPost("/member/blog/updateTplContent", {themeId: themeId, filename: self.curTpl, content: content}, function(re) {
if(t) {
t.button("reset");
@@ -217,7 +222,7 @@ var theme = {
if(reIsOk(re)) {
self.cache[filename] = content;
// art.tips("Success");
self.msgO.html("保存成功")
self.msgO.html("{{msg . "saveSuccess"}}")
setTimeout(function() {
self.msgO.html("");
}, 3000);
+13 -11
View File
@@ -8,17 +8,19 @@
width: 200px;
}
</style>
<div class="m-b-md"> <h3 class="m-b-none">项目组/成员</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "group"}}</h3></div>
<p>
<a class="btn btn-default btn-add-group"><span class="fa fa-plus"></span> 新建分组</a>
<a class="btn btn-default btn-add-group"><span class="fa fa-plus"></span> {{msg . "newGroup"}}</a>
</p>
<script type="text/x-jsrender" id="tUser">
<li class="list-group-item" data-id="[[:UserId]]">
[[:Username]] [[if Email != Username]]([[:Email]])[[/if]]
<span class="fa fa-remove pull-right text-xs m-t-sm"></span>
<a title="{{msg . "deleteMember"}}" class="delete-user">
<span class="fa fa-remove pull-right text-xs m-t-sm"></span>
</a>
</li>
</script>
@@ -30,7 +32,7 @@
<div class="clear">
<div class="h3 m-t-xs m-b-xs text-white">
<input type="text" data-ever="[[:Title]]" value="[[:Title]]" class="group-title" />
<a title="删除分组" class="delete-group">
<a title="{{msg . "deleteGroup"}}" class="delete-group">
<i class="fa fa-remove text-white pull-right text-xs m-t-sm"></i>
</a>
</div>
@@ -39,7 +41,7 @@
</header>
<ul class="list-group no-radius">
<li class="list-group-item">
<input type="text" class="add-user-input form-control" placeholder="输入用户名或邮箱添加成员" />
<input type="text" class="add-user-input form-control" placeholder="{{msg . "addMemberTips"}}" />
</li>
</ul>
</section>
@@ -57,7 +59,7 @@
<div class="clear">
<div class="h3 m-t-xs m-b-xs text-white">
<input type="text" data-ever="{{.Title}}" value="{{.Title}}" class="group-title" />
<a title="删除分组" class="delete-group">
<a title="{{msg $ "deleteGroup"}}" class="delete-group">
<i class="fa fa-remove text-white pull-right text-xs m-t-sm"></i>
</a>
</div>
@@ -69,13 +71,13 @@
{{range .Users}}
<li class="list-group-item" data-id="{{.UserId.Hex}}">
{{.Username}} {{if not (eq .Email .Username)}}({{.Email}}){{end}}
<a title="删除成员" class="delete-user">
<a title="{{msg $ "deleteMember"}}" class="delete-user">
<span class="fa fa-remove pull-right text-xs m-t-sm"></span>
</a>
</li>
{{end}}
<li class="list-group-item">
<input type="text" class="add-user-input form-control" placeholder="输入用户名或邮箱添加成员" />
<input type="text" class="add-user-input form-control" placeholder="{{msg $ "addMemberTips"}}" />
</li>
</ul>
</section>
@@ -85,7 +87,7 @@
</div>
{{template "member/footer.html" .}}
<script src="http://leanote.com/public/blog/js/jsrender.js"></script>
<script src="/public/blog/js/jsrender.js"></script>
<script>
var group = {
tGroupO: $("#tGroup"),
@@ -111,7 +113,7 @@ var group = {
addGroupEvent: function() {
var self = this;
$('.btn-add-group').click(function() {
ajaxPost("/member/group/addGroup", {title: "分组名"}, function(re) {
ajaxPost("/member/group/addGroup", {title: "Group Title"}, function(re) {
if(reIsOk(re)) {
var group = re.Item;
self.groupsO.prepend(self.tGroupO.render(group))
@@ -217,4 +219,4 @@ $(function() {
});
</script>
{{template "member/end.html" .}}
{{template "member/end.html" .}}
+2 -3
View File
@@ -1,5 +1,5 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">{{.userInfo.Username}}, 欢迎来到leanote</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{.userInfo.Username}}, {{msg . "welcomeToLeanote"}}.</h3></div>
<section class="panel panel-default">
<div class="row m-l-none m-r-none bg-light lter">
@@ -26,11 +26,10 @@
</div>
</div>
</section>
<!-- 最新动态 -->
<section class="panel panel-default">
<h4 class="font-thin padder">
Leanote 动态
{{msg . "leanoteEvents"}}
</h4>
<ul class="list-group" id="eventsList"></ul>
</section>
+27 -24
View File
@@ -26,45 +26,47 @@
</i>
</span>
<span>
帐户信息
{{msg . "accountInfo"}}
</span>
</a>
<!-- 导航列表 -->
<ul class="nav lt">
{{if $.userInfo.Email}}
<li>
<a href="/member/user/username">
<span>
用户名
</span>
</a>
</li>
<li>
<a href="/member/user/avatar">
<span>
头像
{{msg . "avatar"}}
</span>
</a>
</li>
{{if $.userInfo.Email}}
<li>
<a href="/member/user/username">
<span>
{{msg . "username"}}
</span>
</a>
</li>
<li>
<a href="/member/user/email">
<span>
邮箱
{{msg . "email"}}
</span>
</a>
</li>
<li>
<a href="/member/user/password">
<span>
密码
{{msg . "password"}}
</span>
</a>
</li>
{{else}}
<li>
<a href="/member/user/add_account">
<a href="/member/user/addAccount">
<span>
添加leanote帐户
{{msg . "addLeanoteAccount"}}
</span>
</a>
</li>
@@ -85,14 +87,14 @@
</i>
</span>
<span>
博客
{{msg . "blog"}}
</span>
</a>
<ul class="nav lt">
<li>
<a href="/member/blog/index">
<span>
文章列表
{{msg . "postList"}}
</span>
</a>
</li>
@@ -100,42 +102,43 @@
<li>
<a href="/member/blog/base">
<span>
基本信息
{{msg . "basicInfoSet"}}
</span>
</a>
</li>
<li>
<a href="/member/blog/comment">
<span>
评论
{{msg . "comment"}}
</span>
</a>
</li>
<li>
<a href="/member/blog/cate">
<span>
分类
{{msg . "cate"}}
</span>
</a>
</li>
<li>
<a href="/member/blog/single">
<span>
单页面
{{msg . "single"}}
</span>
</a>
</li>
<li>
<a href="/member/blog/paging">
<span>
分页与排序设置
{{msg . "pagingAndSort"}}
</span>
</a>
</li>
<li>
<a href="/member/blog/theme">
<span>
主题
{{msg . "theme"}}
</span>
</a>
</li>
@@ -149,9 +152,9 @@
</b>
</i>
<span>
项目组/成员
{{msg . "group"}}
</span>
</a>
</li>
</ul>
</nav>
</nav>
+2 -7
View File
@@ -27,11 +27,6 @@
</div>
<ul class="nav navbar-nav navbar-right m-n hidden-xs nav-user">
<li class="hidden-xs">
<a href="http://lea.leanote.com" class="dk" target="_blank">
lea++
</a>
</li>
<li class="hidden-xs">
<a href="/note" class="dk" target="_blank">
{{msg . "myNote"}}
@@ -79,7 +74,7 @@
</section>
<footer class="footer lt hidden-xs b-t b-light" style="min-height: initial;
padding: 10px 15px;text-align:center;">
<a href="http://leanote.com" target="_blank">leanote</a> © 2014
<a href="http://leanote.com" target="_blank">leanote</a> © 2015
<!--
<a href="#nav" data-toggle="class:nav-xs" class="pull-right btn btn-sm btn-default btn-icon">
<i class="fa fa-angle-left text">
@@ -115,4 +110,4 @@ padding: 10px 15px;text-align:center;">
</ul>
-->
<!-- 主要内容区 -->
+2 -2
View File
@@ -1,9 +1,9 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">用户名设置</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "addLeanoteAccount"}}</h3></div>
<div class="row">
<div class="col-sm-6">
<div class="col-sm-8">
<form id="formData">
<section class="panel panel-default">
<div class="panel-body">
+3 -3
View File
@@ -1,10 +1,10 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">头像设置</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "avatar"}}</h3></div>
<div class="row">
<div class="col-sm-6">
<div class="col-sm-8">
<form id="uploadAvatar" method="post" action="/file/uploadAvatar" enctype="multipart/form-data">
<section class="panel panel-default">
<div class="panel-body">
@@ -14,7 +14,7 @@
<img src="{{if .userInfo.Logo}}{{.userInfo.Logo}}{{else}}/images/blog/default_avatar.png{{end}}" id="avatar"/>
</div>
<a class="btn btn-success btn-choose-file">
<span class="fa fa-upload"></span> Choose Image
<span class="fa fa-upload"></span> {{msg . "chooseImage"}}
</a>
<input type="file" name="file" multiple/>
</div>
+2 -2
View File
@@ -1,9 +1,9 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">邮箱设置</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "email"}}</h3></div>
<div class="row">
<div class="col-sm-6">
<div class="col-sm-8">
<form id="formData">
<section class="panel panel-default">
<div class="panel-body">
+2 -4
View File
@@ -1,9 +1,7 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">用户名设置</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "password"}}</h3></div>
<div class="row">
<div class="col-sm-6">
<div class="col-sm-8">
<form id="formData">
<section class="panel panel-default">
<div class="panel-body">
+2 -2
View File
@@ -1,9 +1,9 @@
{{template "member/top.html" .}}
<div class="m-b-md"> <h3 class="m-b-none">用户名设置</h3></div>
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "username"}}</h3></div>
<div class="row">
<div class="col-sm-6">
<div class="col-sm-8">
<form id="formData">
<section class="panel panel-default">
<div class="panel-body">
+194 -55
View File
@@ -12,17 +12,19 @@
<link href="/css/bootstrap.css" rel="stylesheet" />
<!-- 先加载, 没有样式, 宽度不定 -->
<link rel="stylesheet" href="tinymce/skins/custom/skin.min.css" rel="stylesheet"/>
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" rel="stylesheet"/>
<!-- leanote css -->
<link href="css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet" />
<link href="css/zTreeStyle/zTreeStyle.css" rel="stylesheet" />
<link href="/css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet" />
<link href="/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" />
<!-- mdeditor -->
<link href="/public/dist/themes/default.css" rel="stylesheet" />
<script>
var hash = location.hash;
if(hash == "#writing") {
var files = '<link rel="stylesheet" href="css/theme/writting-overwrite.css" type="text/css" id="themeLink" />';
if(hash.indexOf("writing") >= 0) {
var files = '<link rel="stylesheet" href="/css/theme/writting-overwrite.css" type="text/css" id="themeLink" />';
} else {
var files ='<link rel="stylesheet" href="css/theme/{{if .userInfo.Theme}}{{.userInfo.Theme}}{{else}}default{{end}}.css" type="text/css" id="themeLink" />';
var files ='<link rel="stylesheet" href="/css/theme/{{if .userInfo.Theme}}{{.userInfo.Theme}}{{else}}default{{end}}.css" type="text/css" id="themeLink" />';
}
document.write(files);
</script>
@@ -160,12 +162,18 @@ function log(o) {
{{msg . "myBlog"}}</a>
</li>
<li role="presentation" class="divider my-link writing-mobile-hide"></li>
<li role="presentation" class="my-link toggle-editor-mode writing-mobile-hide" >
<a href="#writing"><i class="fa fa-rocket"></i>
{{msg . "writingMode"}}</a>
</li>
{{if .isAdmin}}
<li role="presentation" class="divider"></li>
<li role="presentation">
<a target="_blank" title="{{msg . "amdin"}}" href="/admin/index">
<a target="_blank" title="{{msg . "admin"}}" href="/admin/index">
<i class="fa fa-dashboard"></i>
{{msg . "admin"}}
<span>{{msg . "admin"}}</span>
</a>
</li>
{{end}}
@@ -178,14 +186,22 @@ function log(o) {
</div>
</div>
<div class="pull-right top-nav" id="myBlog">
<!--
<div class="pull-right top-nav writting-hide lea-blog">
<a target="_blank" href="http://lea.leanote.com">
lea++
</a>
</div>
-->
<div class="pull-right top-nav writting-hide" id="myBlog">
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
{{msg . "myBlog"}}
</a>
</div>
<div class="pull-right" style="line-height: 60px; margin-right:10px" id="toggleEditorMode">
<a href="#writing">{{msg . "writingMode"}}</a>
<div class="pull-right toggle-editor-mode" style="line-height: 60px; margin-right:10px" id="toggleEditorMode">
<a href="#writing"><span>{{msg . "writingMode"}}</span></a>
</div>
{{if eq .userInfo.Email "demo@leanote.com"}}
@@ -321,6 +337,11 @@ function log(o) {
<div class="noteSplit" id="notebookSplitter"></div>
<div id="noteAndEditor">
<div id="noteAndEditorMask">
<img src="/images/loading-24.gif"/>
<br />
loading...
</div>
<div id="noteList">
<div class="clearfix" id="notesAndSort" style="position: relative">
<div class="pull-left">
@@ -405,11 +426,11 @@ function log(o) {
<span id="noteReadTags"></span>
<!-- 修改时间 -->
<i class="fa fa-calendar"></i>{{msg . "update"}}
<i class="fa fa-clock-o"></i>{{msg . "update"}}
<span id="noteReadUpdatedTime"></span>
<!-- 修改时间 -->
<i class="fa fa-calendar"></i>{{msg . "create"}}
<i class="fa fa-clock-o"></i>{{msg . "create"}}
<span id="noteReadCreatedTime"></span>
</div>
</div>
@@ -538,12 +559,12 @@ function log(o) {
</a>
</div>
<div class="editorBg"></div>
<div id="leanoteNav">
<div id="leanoteNav" class="leanoteNav">
<h1>
<i class="fa fa-align-justify" title="文档导航"></i>
<i class="fa fa-align-justify" title="{{msg . "nav"}}"></i>
<span>{{msg . "nav"}}</span>
</h1>
<div id="leanoteNavContent">
<div id="leanoteNavContent" class="leanoteNavContent">
</div>
</div>
@@ -564,9 +585,85 @@ function log(o) {
</div>
<div id="mdEditor">
<div class="layout-wrapper-l1">
<div class="layout-wrapper-l2">
<div class="navbar navbar-default">
<div class="navbar-inner" id="wmd-button-bar">
<ul class="nav left-buttons">
<li class="wmd-button-group1 btn-group"></li>
</ul>
<ul class="nav left-buttons">
<li class="wmd-button-group2 btn-group"></li>
</ul>
<ul class="nav left-buttons">
<li class="wmd-button-group3 btn-group"></li>
</ul>
<ul class="nav left-buttons">
<li class="wmd-button-group5 btn-group"></li>
</ul>
<!-- 帮助 -->
<ul class="nav left-buttons">
<li class="wmd-button-group6 btn-group">
<li class="wmd-button btn btn-success" id="wmd-help-button" title="Markdown syntax" style="left: 0px; display: none;"><span style="display: none; background-position: 0px 0px;"></span><i class="fa fa-question-circle"></i></li>
</li>
</ul>
<!--
<ul class="nav pull-right right-buttons">
<li class="offline-status hide">
<div class="text-danger">
<i class="icon-attention-circled"></i>offline
</div>
</li>
<li class="extension-buttons"></li>
</ul>
<ul class="nav pull-right title-container">
<li><div class="working-indicator"></div></li>
<li><a class="btn btn-success file-title-navbar" href="#"
title="Rename document"> </a></li>
<li><div class="input-file-title-container"><input type="text"
class="col-sm-4 form-control hide input-file-title"
placeholder="Document title" /></div></li>
</ul>
-->
</div>
<div class="editorBg"></div>
</div>
<div class="layout-wrapper-l3">
<div id="left-column">
<pre id="wmd-input" class="form-control"><div class="editor-content mousetrap" contenteditable=true></div><div class="editor-margin"></div></pre>
</div>
<div id="right-column">
<div class="preview-panel panel-open" id="preview-panel">
<div id="mdSplitter2" class="layout-resizer layout-resizer-preview open" style="-webkit-user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); touch-action: none;"></div>
<div class="layout-toggler layout-toggler-preview btn btn-info open" title="Toggle preview" data-open="1"><i class="fa fa-angle-right"></i></div>
<div class="preview-container">
<div id="preview-contents">
<div id="wmd-preview" class="preview-content"></div>
</div>
</div>
</div>
</div>
</div>
<div class="extension-preview-buttons">
<div id="leanoteNavMd" class="leanoteNav">
<h1>
<i class="fa fa-align-justify" title="{{msg . "nav"}}"></i>
<span>{{msg . "nav"}}</span>
</h1>
<div id="leanoteNavContentMd" class="leanoteNavContent table-of-contents">
</div>
</div>
</div>
</div>
<div id="wmd-button-bar" class="hide"></div>
</div>
<!--
<div id="wmd-button-bar" id="mdBar"></div>
<div class="editorBg"></div>
<!-- 为了scroll -->
<div class="clearfix" id="mdEditorPreview">
<div id="left-column">
@@ -582,11 +679,59 @@ function log(o) {
</div>
</div>
<textarea id="md-section-helper"></textarea>
-->
</div>
</div>
</div>
<!-- mdEditor -->
<!-- v2 -->
<div class="modal fade modal-insert-link">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
<h4 class="modal-title">Hyperlink</h4>
</div>
<div class="modal-body">
<p>Please provide the link URL and an optional title:</p>
<div class="input-group">
<span class="input-group-addon"><i class="icon-globe"></i></span><input
id="input-insert-link" type="text" class="col-sm-5 form-control"
placeholder='http://example.com/ "optional title"' />
</div>
</div>
<div class="modal-footer">
<a href="#" class="btn btn-default" data-dismiss="modal">Cancel</a>
<a href="#" class="btn btn-primary action-insert-link"
data-dismiss="modal">OK</a>
</div>
</div>
</div>
</div>
<!-- 插入图片 -->
<div class="modal fade modal-insert-image">
<div class="modal-dialog" style="width: 840px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
<h4 class="modal-title">Image</h4>
</div>
<div class="modal-body" style="padding-top: 0; padding-bottom: 0">
<iframe name="mdImageManager" style="width: 100%; height: 350px" scrolling="no" id="leauiIfrForMD" src="" frameborder="0"></iframe>
</div>
<div class="modal-footer">
<a href="#" class="btn btn-default"
data-dismiss="modal">Cancel</a> <a href="#"
class="btn btn-primary action-insert-image" data-dismiss="modal">Insert Image</a>
</div>
</div>
</div>
</div>
<!-- v1 -->
<!-- Hidden Popup Modal -->
<div class="modal fade bs-modal-sm" id="editorDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
@@ -731,17 +876,22 @@ function log(o) {
</div>
</div>
</div>
<script src="js/jquery-1.9.0.min.js"></script>
<script src="js/jquery.ztree.all-3.5.js"></script>
<script src="js/i18n/msg.{{.locale}}.js"></script>
<script src="js/common.js"></script>
<script src="/js/jquery-1.9.0.min.js"></script>
<script src="/js/jquery.ztree.all-3.5.js"></script>
<script src="/js/i18n/msg.{{.locale}}.js"></script>
<script src="/js/common.js"></script>
<script>
var UrlPrefix = "{{.siteUrl}}"; // 为了发weibo
var UrlPrefix = '{{.siteUrl}}'; // 为了发weibo
var UserInfo = {{.userInfo|jsonJs}};
var notebooks = {{.notebooks|jsonJs}};
var shareNotebooks = {{.shareNotebooks|jsonJs}};
var sharedUserInfos = {{.sharedUserInfos|jsonJs}};
var notes = {{.notes|jsonJs}}
var curNoteId = '{{.curNoteId}}';
var curNotebookId = '{{.curNotebookId}}';
var curSharedNoteNotebookId = '{{.curSharedNoteNotebookId}}';
var curSharedUserId = '{{.curSharedUserId}}';
var notes = {{.notes|jsonJs}};
var latestNotes = {{if .latestNotes}}{{.latestNotes|jsonJs}}{{else}}[]{{end}};
var noteContentJson = {{.noteContentJson|jsonJs}};
var tagsJson = {{.tags|jsonJs}};
LEA.locale = "{{.locale}}";
@@ -749,44 +899,33 @@ var GlobalConfigs = {{.globalConfigs|jsonJs}}; // 2014/11/9 beta2
</script>
<!-- 渲染view -->
<script src="tinymce/tinymce.js"></script>
<script src="js/app/page.js"></script>
<script src="/tinymce/tinymce.js"></script>
<script src="/public/libs/ace/ace.js"></script>
<script src="/js/app/page.js"></script>
<script src="/js/jQuery-slimScroll-1.3.0/jquery.slimscroll.js"></script>
<script src="/js/contextmenu/jquery.contextmenu.js"></script>
<script src="js/jquery-cookie.js"></script>
<script src="js/bootstrap-min.js"></script>
<script src="js/app/note.js"></script>
<script src="js/app/tag.js"></script>
<script src="js/app/notebook.js"></script>
<script src="js/app/share.js"></script>
<script src="js/object_id-min.js"></script>
<script src="js/ZeroClipboard/ZeroClipboard-min.js"></script>
<script src="/js/bootstrap-min.js"></script>
<script src="/js/app/note.js"></script>
<script src="/js/app/tag.js"></script>
<script src="/js/app/notebook.js"></script>
<script src="/js/app/share.js"></script>
<script src="/js/object_id-min.js"></script>
<script>
Notebook.renderNotebooks(notebooks);
Share.renderShareNotebooks(sharedUserInfos, shareNotebooks);
Note.setNoteCache(noteContentJson);
Note.renderNotes(notes);
if(!isEmpty(notes)) {
Note.changeNote(notes[0].NoteId);
}
// Note.chanteNote设置content
// Note.renderNoteContent(noteContentJson)
Tag.renderTagNav(tagsJson);
// init notebook后才调用
initSlimScroll();
initPage();
</script>
<!-- context-menu -->
<link rel="stylesheet" href="/js/contextmenu/css/contextmenu.css" type="text/css" />
<!-- code -->
<link href="/public/mdeditor/editor/google-code-prettify/prettify.css" rel="stylesheet" />
<!-- js version 2.0 use require.js -->
<!-- v2 use require.js, mdeditor -->
<script>
window.baseDir = '/public/dist';
window.require = {
baseUrl: window.baseDir,
deps: ['main']
};
</script>
<script src="/js/require.js"></script>
<script src="/js/main.js"></script>
</script>
</body>
</html>
+195 -56
View File
@@ -12,17 +12,19 @@
<link href="/css/bootstrap.css" rel="stylesheet" />
<!-- 先加载, 没有样式, 宽度不定 -->
<link rel="stylesheet" href="tinymce/skins/custom/skin.min.css" rel="stylesheet"/>
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" rel="stylesheet"/>
<!-- leanote css -->
<link href="css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet" />
<link href="css/zTreeStyle/zTreeStyle.css" rel="stylesheet" />
<link href="/css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet" />
<link href="/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" />
<!-- mdeditor -->
<link href="/public/dist/themes/default.css" rel="stylesheet" />
<script>
var hash = location.hash;
if(hash == "#writing") {
var files = '<link rel="stylesheet" href="css/theme/writting-overwrite.css" type="text/css" id="themeLink" />';
if(hash.indexOf("writing") >= 0) {
var files = '<link rel="stylesheet" href="/css/theme/writting-overwrite.css" type="text/css" id="themeLink" />';
} else {
var files ='<link rel="stylesheet" href="css/theme/{{if .userInfo.Theme}}{{.userInfo.Theme}}{{else}}default{{end}}.css" type="text/css" id="themeLink" />';
var files ='<link rel="stylesheet" href="/css/theme/{{if .userInfo.Theme}}{{.userInfo.Theme}}{{else}}default{{end}}.css" type="text/css" id="themeLink" />';
}
document.write(files);
</script>
@@ -160,12 +162,18 @@ function log(o) {
{{msg . "myBlog"}}</a>
</li>
<li role="presentation" class="divider my-link writing-mobile-hide"></li>
<li role="presentation" class="my-link toggle-editor-mode writing-mobile-hide" >
<a href="#writing"><i class="fa fa-rocket"></i>
{{msg . "writingMode"}}</a>
</li>
{{if .isAdmin}}
<li role="presentation" class="divider"></li>
<li role="presentation">
<a target="_blank" title="{{msg . "amdin"}}" href="/admin/index">
<a target="_blank" title="{{msg . "admin"}}" href="/admin/index">
<i class="fa fa-dashboard"></i>
{{msg . "admin"}}
<span>{{msg . "admin"}}</span>
</a>
</li>
{{end}}
@@ -178,14 +186,22 @@ function log(o) {
</div>
</div>
<div class="pull-right top-nav" id="myBlog">
<!--
<div class="pull-right top-nav writting-hide lea-blog">
<a target="_blank" href="http://lea.leanote.com">
lea++
</a>
</div>
-->
<div class="pull-right top-nav writting-hide" id="myBlog">
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
{{msg . "myBlog"}}
</a>
</div>
<div class="pull-right" style="line-height: 60px; margin-right:10px" id="toggleEditorMode">
<a href="#writing">{{msg . "writingMode"}}</a>
<div class="pull-right toggle-editor-mode" style="line-height: 60px; margin-right:10px" id="toggleEditorMode">
<a href="#writing"><span>{{msg . "writingMode"}}</span></a>
</div>
{{if eq .userInfo.Email "demo@leanote.com"}}
@@ -321,6 +337,11 @@ function log(o) {
<div class="noteSplit" id="notebookSplitter"></div>
<div id="noteAndEditor">
<div id="noteAndEditorMask">
<img src="/images/loading-24.gif"/>
<br />
loading...
</div>
<div id="noteList">
<div class="clearfix" id="notesAndSort" style="position: relative">
<div class="pull-left">
@@ -405,11 +426,11 @@ function log(o) {
<span id="noteReadTags"></span>
<!-- 修改时间 -->
<i class="fa fa-calendar"></i>{{msg . "update"}}
<i class="fa fa-clock-o"></i>{{msg . "update"}}
<span id="noteReadUpdatedTime"></span>
<!-- 修改时间 -->
<i class="fa fa-calendar"></i>{{msg . "create"}}
<i class="fa fa-clock-o"></i>{{msg . "create"}}
<span id="noteReadCreatedTime"></span>
</div>
</div>
@@ -538,12 +559,12 @@ function log(o) {
</a>
</div>
<div class="editorBg"></div>
<div id="leanoteNav">
<div id="leanoteNav" class="leanoteNav">
<h1>
<i class="fa fa-align-justify" title="文档导航"></i>
<i class="fa fa-align-justify" title="{{msg . "nav"}}"></i>
<span>{{msg . "nav"}}</span>
</h1>
<div id="leanoteNavContent">
<div id="leanoteNavContent" class="leanoteNavContent">
</div>
</div>
@@ -564,9 +585,85 @@ function log(o) {
</div>
<div id="mdEditor">
<div class="layout-wrapper-l1">
<div class="layout-wrapper-l2">
<div class="navbar navbar-default">
<div class="navbar-inner" id="wmd-button-bar">
<ul class="nav left-buttons">
<li class="wmd-button-group1 btn-group"></li>
</ul>
<ul class="nav left-buttons">
<li class="wmd-button-group2 btn-group"></li>
</ul>
<ul class="nav left-buttons">
<li class="wmd-button-group3 btn-group"></li>
</ul>
<ul class="nav left-buttons">
<li class="wmd-button-group5 btn-group"></li>
</ul>
<!-- 帮助 -->
<ul class="nav left-buttons">
<li class="wmd-button-group6 btn-group">
<li class="wmd-button btn btn-success" id="wmd-help-button" title="Markdown syntax" style="left: 0px; display: none;"><span style="display: none; background-position: 0px 0px;"></span><i class="fa fa-question-circle"></i></li>
</li>
</ul>
<!--
<ul class="nav pull-right right-buttons">
<li class="offline-status hide">
<div class="text-danger">
<i class="icon-attention-circled"></i>offline
</div>
</li>
<li class="extension-buttons"></li>
</ul>
<ul class="nav pull-right title-container">
<li><div class="working-indicator"></div></li>
<li><a class="btn btn-success file-title-navbar" href="#"
title="Rename document"> </a></li>
<li><div class="input-file-title-container"><input type="text"
class="col-sm-4 form-control hide input-file-title"
placeholder="Document title" /></div></li>
</ul>
-->
</div>
<div class="editorBg"></div>
</div>
<div class="layout-wrapper-l3">
<div id="left-column">
<pre id="wmd-input" class="form-control"><div class="editor-content mousetrap" contenteditable=true></div><div class="editor-margin"></div></pre>
</div>
<div id="right-column">
<div class="preview-panel panel-open" id="preview-panel">
<div id="mdSplitter2" class="layout-resizer layout-resizer-preview open" style="-webkit-user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); touch-action: none;"></div>
<div class="layout-toggler layout-toggler-preview btn btn-info open" title="Toggle preview" data-open="1"><i class="fa fa-angle-right"></i></div>
<div class="preview-container">
<div id="preview-contents">
<div id="wmd-preview" class="preview-content"></div>
</div>
</div>
</div>
</div>
</div>
<div class="extension-preview-buttons">
<div id="leanoteNavMd" class="leanoteNav">
<h1>
<i class="fa fa-align-justify" title="{{msg . "nav"}}"></i>
<span>{{msg . "nav"}}</span>
</h1>
<div id="leanoteNavContentMd" class="leanoteNavContent table-of-contents">
</div>
</div>
</div>
</div>
<div id="wmd-button-bar" class="hide"></div>
</div>
<!--
<div id="wmd-button-bar" id="mdBar"></div>
<div class="editorBg"></div>
<!-- 为了scroll -->
<div class="clearfix" id="mdEditorPreview">
<div id="left-column">
@@ -582,11 +679,59 @@ function log(o) {
</div>
</div>
<textarea id="md-section-helper"></textarea>
-->
</div>
</div>
</div>
<!-- mdEditor -->
<!-- v2 -->
<div class="modal fade modal-insert-link">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
<h4 class="modal-title">Hyperlink</h4>
</div>
<div class="modal-body">
<p>Please provide the link URL and an optional title:</p>
<div class="input-group">
<span class="input-group-addon"><i class="icon-globe"></i></span><input
id="input-insert-link" type="text" class="col-sm-5 form-control"
placeholder='http://example.com/ "optional title"' />
</div>
</div>
<div class="modal-footer">
<a href="#" class="btn btn-default" data-dismiss="modal">Cancel</a>
<a href="#" class="btn btn-primary action-insert-link"
data-dismiss="modal">OK</a>
</div>
</div>
</div>
</div>
<!-- 插入图片 -->
<div class="modal fade modal-insert-image">
<div class="modal-dialog" style="width: 840px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
<h4 class="modal-title">Image</h4>
</div>
<div class="modal-body" style="padding-top: 0; padding-bottom: 0">
<iframe name="mdImageManager" style="width: 100%; height: 350px" scrolling="no" id="leauiIfrForMD" src="" frameborder="0"></iframe>
</div>
<div class="modal-footer">
<a href="#" class="btn btn-default"
data-dismiss="modal">Cancel</a> <a href="#"
class="btn btn-primary action-insert-image" data-dismiss="modal">Insert Image</a>
</div>
</div>
</div>
</div>
<!-- v1 -->
<!-- Hidden Popup Modal -->
<div class="modal fade bs-modal-sm" id="editorDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
@@ -731,17 +876,22 @@ function log(o) {
</div>
</div>
</div>
<script src="js/jquery-1.9.0.min.js"></script>
<script src="js/jquery.ztree.all-3.5.js"></script>
<script src="js/i18n/msg.{{.locale}}.js"></script>
<script src="js/common-min.js"></script>
<script src="/js/jquery-1.9.0.min.js"></script>
<script src="/js/jquery.ztree.all-3.5-min.js"></script>
<script src="/js/i18n/msg.{{.locale}}.js"></script>
<script src="/js/common-min.js"></script>
<script>
var UrlPrefix = "{{.siteUrl}}"; // 为了发weibo
var UrlPrefix = '{{.siteUrl}}'; // 为了发weibo
var UserInfo = {{.userInfo|jsonJs}};
var notebooks = {{.notebooks|jsonJs}};
var shareNotebooks = {{.shareNotebooks|jsonJs}};
var sharedUserInfos = {{.sharedUserInfos|jsonJs}};
var notes = {{.notes|jsonJs}}
var curNoteId = '{{.curNoteId}}';
var curNotebookId = '{{.curNotebookId}}';
var curSharedNoteNotebookId = '{{.curSharedNoteNotebookId}}';
var curSharedUserId = '{{.curSharedUserId}}';
var notes = {{.notes|jsonJs}};
var latestNotes = {{if .latestNotes}}{{.latestNotes|jsonJs}}{{else}}[]{{end}};
var noteContentJson = {{.noteContentJson|jsonJs}};
var tagsJson = {{.tags|jsonJs}};
LEA.locale = "{{.locale}}";
@@ -749,44 +899,33 @@ var GlobalConfigs = {{.globalConfigs|jsonJs}}; // 2014/11/9 beta2
</script>
<!-- 渲染view -->
<script src="tinymce/tinymce.js"></script>
<script src="js/app/page-min.js"></script>
<script src="/js/jQuery-slimScroll-1.3.0/jquery.slimscroll.js"></script>
<script src="/tinymce/tinymce.min.js"></script>
<script src="/public/libs/ace/ace.js"></script>
<script src="/js/app/page-min.js"></script>
<script src="/js/jQuery-slimScroll-1.3.0/jquery.slimscroll-min.js"></script>
<script src="/js/contextmenu/jquery.contextmenu-min.js"></script>
<script src="js/jquery-cookie.js"></script>
<script src="js/bootstrap-min.js"></script>
<script src="js/app/note-min.js"></script>
<script src="js/app/tag-min.js"></script>
<script src="js/app/notebook-min.js"></script>
<script src="js/app/share-min.js"></script>
<script src="js/object_id-min.js"></script>
<script src="js/ZeroClipboard/ZeroClipboard-min.js"></script>
<script src="/js/bootstrap-min.js"></script>
<script src="/js/app/note-min.js"></script>
<script src="/js/app/tag-min.js"></script>
<script src="/js/app/notebook-min.js"></script>
<script src="/js/app/share-min.js"></script>
<script src="/js/object_id-min.js"></script>
<script>
Notebook.renderNotebooks(notebooks);
Share.renderShareNotebooks(sharedUserInfos, shareNotebooks);
Note.setNoteCache(noteContentJson);
Note.renderNotes(notes);
if(!isEmpty(notes)) {
Note.changeNote(notes[0].NoteId);
}
// Note.chanteNote设置content
// Note.renderNoteContent(noteContentJson)
Tag.renderTagNav(tagsJson);
// init notebook后才调用
initSlimScroll();
initPage();
</script>
<!-- context-menu -->
<link rel="stylesheet" href="/js/contextmenu/css/contextmenu.css" type="text/css" />
<!-- code -->
<link href="/public/mdeditor/editor/google-code-prettify/prettify.css" rel="stylesheet" />
<!-- js version 2.0 use require.js -->
<!-- v2 use require.js, mdeditor -->
<script>
window.baseDir = '/public/dist';
window.require = {
baseUrl: window.baseDir,
deps: ['main']
};
</script>
<script src="/js/require.js"></script>
<script src="/js/main-min.js"></script>
</script>
</body>
</html>
@@ -5,11 +5,14 @@
<h4 class="modal-title" id="modalTitle">{{msg . "share"}} <b>{{.title}}</b></h4>
</div>
{{$noteOrNotebookId := .noteOrNotebookId}}
{{$isNote := .isNote}}
<div class="modal-body">
<ul id="myTab" class="nav nav-tabs">
<li class="active"><a href="#baseInfo" data-toggle="tab">分享给好友</a></li>
<li class=""><a href="#groupInfo" data-toggle="tab">分享给项目组</a></li>
{{if $isNote}}
<li class=""><a href="#shareInfo" data-toggle="tab">分享给未注册好友</a></li>
{{end}}
</ul>
<div class="tab-content">
@@ -95,6 +98,19 @@
{{end}}
</table>
</div>
<div class="tab-pane" id="shareInfo">
<p>
<button class="btn btn-default" id="genShareLink">生成该笔记的分享链接和密码</button>
<span id="showMsg"></span>
</p>
<br>
分享链接:<input type="text" id="shareLink" value="" size=50> <br/><br/>
查看密码:<input type="text" id="sharePass" value="" />
</div>
</div>
</div>
@@ -108,11 +124,55 @@
<script>
Share.dialogIsNote = {{.isNote}};
Share.dialogNoteOrNotebookId = '{{.noteOrNotebookId}}';
var getHost = function(url) {
var host = "null";
if(typeof url == "undefined"
|| null == url)
url = window.location.href;
var regex = /.*\:\/\/([^\/]*).*/;
var match = url.match(regex);
if(typeof match != "undefined"
&& null != match)
host = match[1];
return host;
}
$(function() {
setTimeout(function() {
$("#tr1 #friendsEmail").focus();
}, 500);
var host = getHost();
if (Share.dialogIsNote) {
var url = "/share/querySharePass";
var data = {noteId: Share.dialogNoteOrNotebookId};
ajaxPost(url, data, function(re) {
if(reIsOk(re)) {
if (re.Item >= 1000 && re.Item < 10000) {
var shareLink = host + '/share/note/{{.noteOrNotebookId}}';
$("#shareLink").val(shareLink);
$("#sharePass").val(re.Item);
}
}
});
}
$("#shareLink").hover(function() {
$("#shareLink").focus(function(){
$(this).css({'background-color' : '#f5f5dc'});
}).select();
})
$("#sharePass").hover(function() {
$("#sharePass").focus(function(){
$(this).css({'background-color' : '#f5f5dc'});
}).select();
})
// 分享/删除给分组
$("#groupInfo").on("click", ".btn-share-or-not", function() {
var $t = $(this);
@@ -155,6 +215,28 @@ $("#groupInfo").on("click", ".btn-share-or-not", function() {
});
});
//生成分享链接和密码
$("#genShareLink").on("click", function() {
var sharePass = $("#sharePass").val();
if (sharePass != '' && sharePass > 1000 && sharePass < 10000) {
$("#showMsg").html("<font color='red'>不能重复生成分享链接和密码</font>");
return;
}
var url = "/share/genShareLinkPass";
var shareLink = host + '/share/note/{{.noteOrNotebookId}}';
var data = {noteId: Share.dialogNoteOrNotebookId};
ajaxPost(url, data, function(re) {
if(reIsOk(re)) {
$("#shareLink").val(shareLink);
$("#sharePass").val(re.Item);
}
});
});
$(".group-perm").click(function() {
var $t = $(this);
var $ptr = $t.closest("tr");
@@ -179,5 +261,6 @@ $(".group-perm").click(function() {
});
});
});
</script>
+134
View File
@@ -0,0 +1,134 @@
{{template "home/header.html" .}}
<section>
</section>
{{$isMarkDown := .isMarkDown}}
<div id="queryNote" style="height:300px;padding-top:80px" align="center">
{{ .userName }}分享了笔记<br/><br>
您需要输入分享密码才能查看:<br><br>
<input type="password" id="sharePass" />
<button id="showShareNote">点击查看</button><br/><br/>
<span id="showMsg"></span>
</div>
<div id="noteContainer" style="display:none">
</div>
{{template "home/footer.html"}}
<script src="/js/jquery-1.9.0.min.js"></script>
<script src="/js/bootstrap.js"></script>
<script src="/js/common-min.js"></script>
<script>
var noteId = {{ .noteId }};
var isMarkDown = {{ .isMarkDown}}
String.prototype.format = function() {
var s = this,
i = arguments.length;
while (i--) {
s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
}
return s;
};
var getHost = function(url) {
var host = "null";
if(typeof url == "undefined"
|| null == url)
url = window.location.href;
var regex = /.*\:\/\/([^\/]*).*/;
var match = url.match(regex);
if(typeof match != "undefined"
&& null != match)
host = match[1];
return "http://" + host;
}
$(function() {
$("#showShareNote").on("click", function() {
$("#showMsg").html("");
var url = "/share/verify4ShareNote";
var sharePass = $("#sharePass").val();
var data = {noteId: noteId, sharePass: sharePass};
ajaxPost(url, data, function(re) {
if(reIsOk(re)) {
$("#queryNote").css("display", "none");
var title = re.Item.Title;
var content = re.Msg;
var imgSrc = re.Item.ImgSrc;
var htmlContent = "<div><h1 height='50px'>{0}</h1></div><hr/><div style='vertical-align:center'><p height='auto'>{1}<br>{2}</p>";
var attaches = re.List;
var attachesHtml = "";
if (attaches.length > 0) {
var token = re.Id;
for (var i=0; i<attaches.length; i++) {
var linkUrl = "{0}/attach/download?attachId={1}&token={2}".format(getHost(), attaches[i].AttachId, token);
attachesHtml += "<p><a href='{0}' target='_blank' data-mce-href='{1}' >附件{2}</a></p><br/>".format(linkUrl, linkUrl, i+1);
}
}
htmlContent = htmlContent.format(title, content, attachesHtml) + "</div>";
/* if (isMarkDown) {
var converter = Markdown.getSanitizingConverter();
Markdown.Extra.init(converter, {extensions: ["tables", "fenced_code_gfm", "def_list"]});
var mdDesc = converter.makeHtml(desc);
$("pre").addClass("prettyprint linenums");
prettyPrint();
MathJax.Hub.Queue(["Typeset",MathJax.Hub,"wmd-preview"]);
htmlContent = "<div><h1 height='50px'>"+title+"</h1></div><hr/><div style='vertical-align:center'><p height='auto'>"
+mdDesc+"</p></div>";
} else {
htmlContent = "<div><h1 height='50px'>"+title+"</h1></div><hr/><div style='vertical-align:center'><p height='auto'>"
+desc+"</p></div>";
} */
$("#noteContainer").css("display", "block").css("height", "auto")
.css("padding-top", "20px").css("text-align", "center")
.css("margin-left", "auto").css("margin-right", "auto");
$("#noteContainer").html(htmlContent);
} else {
$("#showMsg").html("<font color='red'>密码错误</font>");
}
});
});
// 平滑滚动
$(".smooth-scroll").click(function(e) {
e.preventDefault();
var t = $(this).attr("target");
var targetOffset = $(t).offset().top - 80;
$('html,body').animate({scrollTop: targetOffset}, 300);
});
});
</script>
{{if $isMarkDown}}
<script src="/public/mdeditor/editor/pagedown/Markdown.Converter.js"></script>
<script src="/public/mdeditor/editor/pagedown/Markdown.Sanitizer.js"></script>
<script src="/public/mdeditor/editor/pagedown/Markdown.Editor.js"></script>
<script src="/public/mdeditor/editor/pagedown/local/Markdown.local.zh.js"></script>
<script src="/public/mdeditor/editor/Markdown.Extra.js"></script>
<script src="/public/mdeditor/editor/editor.js"></script>
<script src="/public/js/google-code-prettify/prettify.js"></script>
<!--mathjax-->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]], processEscapes: true }, messageStyle: "none"});
</script>
<script src="/public/mdeditor/editor/mathJax.js"></script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
{{end}}
+9 -2
View File
@@ -10,7 +10,7 @@ cd ../
# tmp path to store leanote release files
tmp="/Users/life/Desktop/leanote_release"
version=x86_64.v1.0-beta2
version=x86_64.v1.0-beta.2
rm -rf $tmp/leanote
mkdir -p $tmp/leanote/app
@@ -52,7 +52,7 @@ rm $tmp/leanote/public/config.codekit
# make link
cd $tmp/leanote/bin
mkdir ./src/github.com/leanote
ln -s ../../../../ ./src/github.com/leanote/leanote
# ln -s ../../../../ ./src/github.com/leanote/leanote
# archieve
# << 'BLOCK
@@ -73,4 +73,11 @@ cd $tmp
tar -cvf $tmp/leanote-mac-$version.bin.tar leanote
gzip $tmp/leanote-mac-$version.bin.tar
cd $SP
cd ../
cp ./bin/leanote-linux $tmp/leanote/bin/
rm $tmp/bin/src/github.com/leanote/leanote
cp -r $tmp/leanote/* $tmp/leanote_release_github
# BLOCK'
+6 -6
View File
@@ -2,12 +2,12 @@
SCRIPTPATH=$(cd "$(dirname "$0")"; pwd)
# set link
#
#path="$SCRIPTPATH/src/github.com/leanote"
#if [ ! -d "$path" ]; then
# mkdir -p "$path"
#fi
# ln -s ../../../../ $SCRIPTPATH/src/github.com/leanote/leanote
path="$SCRIPTPATH/src/github.com/leanote"
if [ ! -d "$path" ]; then
mkdir -p "$path"
fi
ln -s ../../../../ $SCRIPTPATH/src/github.com/leanote/leanote
# set GOPATH
export GOPATH=$GOPATH:$SCRIPTPATH
@@ -1,545 +0,0 @@
3dm=x-world/x-3dmf
3dmf=x-world/x-3dmf
7z=application/x-7z-compressed
a=application/octet-stream
aab=application/x-authorware-bin
aam=application/x-authorware-map
aas=application/x-authorware-seg
abc=text/vndabc
ace=application/x-ace-compressed
acgi=text/html
afl=video/animaflex
ai=application/postscript
aif=audio/aiff
aifc=audio/aiff
aiff=audio/aiff
aim=application/x-aim
aip=text/x-audiosoft-intra
alz=application/x-alz-compressed
ani=application/x-navi-animation
aos=application/x-nokia-9000-communicator-add-on-software
aps=application/mime
arc=application/x-arc-compressed
arj=application/arj
art=image/x-jg
asf=video/x-ms-asf
asm=text/x-asm
asp=text/asp
asx=application/x-mplayer2
au=audio/basic
avi=video/x-msvideo
avs=video/avs-video
bcpio=application/x-bcpio
bin=application/mac-binary
bmp=image/bmp
boo=application/book
book=application/book
boz=application/x-bzip2
bsh=application/x-bsh
bz2=application/x-bzip2
bz=application/x-bzip
c++=text/plain
c=text/x-c
cab=application/vnd.ms-cab-compressed
cat=application/vndms-pkiseccat
cc=text/x-c
ccad=application/clariscad
cco=application/x-cocoa
cdf=application/cdf
cer=application/pkix-cert
cha=application/x-chat
chat=application/x-chat
chrt=application/vnd.kde.kchart
class=application/java
# ? class=application/java-vm
com=text/plain
conf=text/plain
cpio=application/x-cpio
cpp=text/x-c
cpt=application/mac-compactpro
crl=application/pkcs-crl
crt=application/pkix-cert
crx=application/x-chrome-extension
csh=text/x-scriptcsh
css=text/css
csv=text/csv
cxx=text/plain
dar=application/x-dar
dcr=application/x-director
deb=application/x-debian-package
deepv=application/x-deepv
def=text/plain
der=application/x-x509-ca-cert
dif=video/x-dv
dir=application/x-director
divx=video/divx
dl=video/dl
dmg=application/x-apple-diskimage
doc=application/msword
dot=application/msword
dp=application/commonground
drw=application/drafting
dump=application/octet-stream
dv=video/x-dv
dvi=application/x-dvi
dwf=drawing/x-dwf=(old)
dwg=application/acad
dxf=application/dxf
dxr=application/x-director
el=text/x-scriptelisp
elc=application/x-bytecodeelisp=(compiled=elisp)
eml=message/rfc822
env=application/x-envoy
eps=application/postscript
es=application/x-esrehber
etx=text/x-setext
evy=application/envoy
exe=application/octet-stream
f77=text/x-fortran
f90=text/x-fortran
f=text/x-fortran
fdf=application/vndfdf
fif=application/fractals
fli=video/fli
flo=image/florian
flv=video/x-flv
flx=text/vndfmiflexstor
fmf=video/x-atomic3d-feature
for=text/x-fortran
fpx=image/vndfpx
frl=application/freeloader
funk=audio/make
g3=image/g3fax
g=text/plain
gif=image/gif
gl=video/gl
gsd=audio/x-gsm
gsm=audio/x-gsm
gsp=application/x-gsp
gss=application/x-gss
gtar=application/x-gtar
gz=application/x-compressed
gzip=application/x-gzip
h=text/x-h
hdf=application/x-hdf
help=application/x-helpfile
hgl=application/vndhp-hpgl
hh=text/x-h
hlb=text/x-script
hlp=application/hlp
hpg=application/vndhp-hpgl
hpgl=application/vndhp-hpgl
hqx=application/binhex
hta=application/hta
htc=text/x-component
htm=text/html
html=text/html
htmls=text/html
htt=text/webviewhtml
htx=text/html
ice=x-conference/x-cooltalk
ico=image/x-icon
ics=text/calendar
icz=text/calendar
idc=text/plain
ief=image/ief
iefs=image/ief
iges=application/iges
igs=application/iges
ima=application/x-ima
imap=application/x-httpd-imap
inf=application/inf
ins=application/x-internett-signup
ip=application/x-ip2
isu=video/x-isvideo
it=audio/it
iv=application/x-inventor
ivr=i-world/i-vrml
ivy=application/x-livescreen
jam=audio/x-jam
jav=text/x-java-source
java=text/x-java-source
jcm=application/x-java-commerce
jfif-tbnl=image/jpeg
jfif=image/jpeg
jnlp=application/x-java-jnlp-file
jpe=image/jpeg
jpeg=image/jpeg
jpg=image/jpeg
jps=image/x-jps
js=application/javascript
json=application/json
jut=image/jutvision
kar=audio/midi
karbon=application/vnd.kde.karbon
kfo=application/vnd.kde.kformula
flw=application/vnd.kde.kivio
kml=application/vnd.google-earth.kml+xml
kmz=application/vnd.google-earth.kmz
kon=application/vnd.kde.kontour
kpr=application/vnd.kde.kpresenter
kpt=application/vnd.kde.kpresenter
ksp=application/vnd.kde.kspread
kwd=application/vnd.kde.kword
kwt=application/vnd.kde.kword
ksh=text/x-scriptksh
la=audio/nspaudio
lam=audio/x-liveaudio
latex=application/x-latex
lha=application/lha
lhx=application/octet-stream
list=text/plain
lma=audio/nspaudio
log=text/plain
lsp=text/x-scriptlisp
lst=text/plain
lsx=text/x-la-asf
ltx=application/x-latex
lzh=application/octet-stream
lzx=application/lzx
m1v=video/mpeg
m2a=audio/mpeg
m2v=video/mpeg
m3u=audio/x-mpegurl
m=text/x-m
man=application/x-troff-man
manifest=text/cache-manifest
map=application/x-navimap
mar=text/plain
mbd=application/mbedlet
mc$=application/x-magic-cap-package-10
mcd=application/mcad
mcf=text/mcf
mcp=application/netmc
me=application/x-troff-me
mht=message/rfc822
mhtml=message/rfc822
mid=application/x-midi
midi=application/x-midi
mif=application/x-frame
mime=message/rfc822
mjf=audio/x-vndaudioexplosionmjuicemediafile
mjpg=video/x-motion-jpeg
mm=application/base64
mme=application/base64
mod=audio/mod
moov=video/quicktime
mov=video/quicktime
movie=video/x-sgi-movie
mp2=audio/mpeg
mp3=audio/mpeg3
mp4=video/mp4
mpa=audio/mpeg
mpc=application/x-project
mpe=video/mpeg
mpeg=video/mpeg
mpg=video/mpeg
mpga=audio/mpeg
mpp=application/vndms-project
mpt=application/x-project
mpv=application/x-project
mpx=application/x-project
mrc=application/marc
ms=application/x-troff-ms
mv=video/x-sgi-movie
my=audio/make
mzz=application/x-vndaudioexplosionmzz
nap=image/naplps
naplps=image/naplps
nc=application/x-netcdf
ncm=application/vndnokiaconfiguration-message
nif=image/x-niff
niff=image/x-niff
nix=application/x-mix-transfer
nsc=application/x-conference
nvd=application/x-navidoc
o=application/octet-stream
oda=application/oda
odb=application/vnd.oasis.opendocument.database
odc=application/vnd.oasis.opendocument.chart
odf=application/vnd.oasis.opendocument.formula
odg=application/vnd.oasis.opendocument.graphics
odi=application/vnd.oasis.opendocument.image
odm=application/vnd.oasis.opendocument.text-master
odp=application/vnd.oasis.opendocument.presentation
ods=application/vnd.oasis.opendocument.spreadsheet
odt=application/vnd.oasis.opendocument.text
oga=audio/ogg
ogg=audio/ogg
ogv=video/ogg
omc=application/x-omc
omcd=application/x-omcdatamaker
omcr=application/x-omcregerator
otc=application/vnd.oasis.opendocument.chart-template
otf=application/vnd.oasis.opendocument.formula-template
otg=application/vnd.oasis.opendocument.graphics-template
oth=application/vnd.oasis.opendocument.text-web
oti=application/vnd.oasis.opendocument.image-template
otm=application/vnd.oasis.opendocument.text-master
otp=application/vnd.oasis.opendocument.presentation-template
ots=application/vnd.oasis.opendocument.spreadsheet-template
ott=application/vnd.oasis.opendocument.text-template
p10=application/pkcs10
p12=application/pkcs-12
p7a=application/x-pkcs7-signature
p7c=application/pkcs7-mime
p7m=application/pkcs7-mime
p7r=application/x-pkcs7-certreqresp
p7s=application/pkcs7-signature
p=text/x-pascal
part=application/pro_eng
pas=text/pascal
pbm=image/x-portable-bitmap
pcl=application/vndhp-pcl
pct=image/x-pict
pcx=image/x-pcx
pdb=chemical/x-pdb
pdf=application/pdf
pfunk=audio/make
pgm=image/x-portable-graymap
pic=image/pict
pict=image/pict
pkg=application/x-newton-compatible-pkg
pko=application/vndms-pkipko
pl=text/x-scriptperl
plx=application/x-pixclscript
pm4=application/x-pagemaker
pm5=application/x-pagemaker
pm=text/x-scriptperl-module
png=image/png
pnm=application/x-portable-anymap
pot=application/mspowerpoint
pov=model/x-pov
ppa=application/vndms-powerpoint
ppm=image/x-portable-pixmap
pps=application/mspowerpoint
ppt=application/mspowerpoint
ppz=application/mspowerpoint
pre=application/x-freelance
prt=application/pro_eng
ps=application/postscript
psd=application/octet-stream
pvu=paleovu/x-pv
pwz=application/vndms-powerpoint
py=text/x-scriptphyton
pyc=applicaiton/x-bytecodepython
qcp=audio/vndqcelp
qd3=x-world/x-3dmf
qd3d=x-world/x-3dmf
qif=image/x-quicktime
qt=video/quicktime
qtc=video/x-qtc
qti=image/x-quicktime
qtif=image/x-quicktime
ra=audio/x-pn-realaudio
ram=audio/x-pn-realaudio
rar=application/x-rar-compressed
ras=application/x-cmu-raster
rast=image/cmu-raster
rexx=text/x-scriptrexx
rf=image/vndrn-realflash
rgb=image/x-rgb
rm=application/vndrn-realmedia
rmi=audio/mid
rmm=audio/x-pn-realaudio
rmp=audio/x-pn-realaudio
rng=application/ringing-tones
rnx=application/vndrn-realplayer
roff=application/x-troff
rp=image/vndrn-realpix
rpm=audio/x-pn-realaudio-plugin
rt=text/vndrn-realtext
rtf=text/richtext
rtx=text/richtext
rv=video/vndrn-realvideo
s=text/x-asm
s3m=audio/s3m
s7z=application/x-7z-compressed
saveme=application/octet-stream
sbk=application/x-tbook
scm=text/x-scriptscheme
sdml=text/plain
sdp=application/sdp
sdr=application/sounder
sea=application/sea
set=application/set
sgm=text/x-sgml
sgml=text/x-sgml
sh=text/x-scriptsh
shar=application/x-bsh
shtml=text/x-server-parsed-html
sid=audio/x-psid
skd=application/x-koan
skm=application/x-koan
skp=application/x-koan
skt=application/x-koan
sit=application/x-stuffit
sitx=application/x-stuffitx
sl=application/x-seelogo
smi=application/smil
smil=application/smil
snd=audio/basic
sol=application/solids
spc=text/x-speech
spl=application/futuresplash
spr=application/x-sprite
sprite=application/x-sprite
spx=audio/ogg
src=application/x-wais-source
ssi=text/x-server-parsed-html
ssm=application/streamingmedia
sst=application/vndms-pkicertstore
step=application/step
stl=application/sla
stp=application/step
sv4cpio=application/x-sv4cpio
sv4crc=application/x-sv4crc
svf=image/vnddwg
svg=image/svg+xml
svr=application/x-world
swf=application/x-shockwave-flash
t=application/x-troff
talk=text/x-speech
tar=application/x-tar
tbk=application/toolbook
tcl=text/x-scripttcl
tcsh=text/x-scripttcsh
tex=application/x-tex
texi=application/x-texinfo
texinfo=application/x-texinfo
text=text/plain
tgz=application/gnutar
tif=image/tiff
tiff=image/tiff
tr=application/x-troff
tsi=audio/tsp-audio
tsp=application/dsptype
tsv=text/tab-separated-values
turbot=image/florian
txt=text/plain
uil=text/x-uil
uni=text/uri-list
unis=text/uri-list
unv=application/i-deas
uri=text/uri-list
uris=text/uri-list
ustar=application/x-ustar
uu=text/x-uuencode
uue=text/x-uuencode
vcd=application/x-cdlink
vcf=text/x-vcard
vcard=text/x-vcard
vcs=text/x-vcalendar
vda=application/vda
vdo=video/vdo
vew=application/groupwise
viv=video/vivo
vivo=video/vivo
vmd=application/vocaltec-media-desc
vmf=application/vocaltec-media-file
voc=audio/voc
vos=video/vosaic
vox=audio/voxware
vqe=audio/x-twinvq-plugin
vqf=audio/x-twinvq
vql=audio/x-twinvq-plugin
vrml=application/x-vrml
vrt=x-world/x-vrt
vsd=application/x-visio
vst=application/x-visio
vsw=application/x-visio
w60=application/wordperfect60
w61=application/wordperfect61
w6w=application/msword
wav=audio/wav
wb1=application/x-qpro
wbmp=image/vnd.wap.wbmp
web=application/vndxara
wiz=application/msword
wk1=application/x-123
wmf=windows/metafile
wml=text/vnd.wap.wml
wmlc=application/vnd.wap.wmlc
wmls=text/vnd.wap.wmlscript
wmlsc=application/vnd.wap.wmlscriptc
word=application/msword
wp5=application/wordperfect
wp6=application/wordperfect
wp=application/wordperfect
wpd=application/wordperfect
wq1=application/x-lotus
wri=application/mswrite
wrl=application/x-world
wrz=model/vrml
wsc=text/scriplet
wsrc=application/x-wais-source
wtk=application/x-wintalk
x-png=image/png
xbm=image/x-xbitmap
xdr=video/x-amt-demorun
xgz=xgl/drawing
xif=image/vndxiff
xl=application/excel
xla=application/excel
xlb=application/excel
xlc=application/excel
xld=application/excel
xlk=application/excel
xll=application/excel
xlm=application/excel
xls=application/excel
xlt=application/excel
xlv=application/excel
xlw=application/excel
xm=audio/xm
xml=text/xml
xmz=xgl/movie
xpix=application/x-vndls-xpix
xpm=image/x-xpixmap
xsr=video/x-amt-showrun
xwd=image/x-xwd
xyz=chemical/x-pdb
z=application/x-compress
zip=application/zip
zoo=application/octet-stream
zsh=text/x-scriptzsh
# Office 2007 mess - http://wdg.uncc.edu/Microsoft_Office_2007_MIME_Types_for_Apache_and_IIS
docx=application/vnd.openxmlformats-officedocument.wordprocessingml.document
docm=application/vnd.ms-word.document.macroEnabled.12
dotx=application/vnd.openxmlformats-officedocument.wordprocessingml.template
dotm=application/vnd.ms-word.template.macroEnabled.12
xlsx=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsm=application/vnd.ms-excel.sheet.macroEnabled.12
xltx=application/vnd.openxmlformats-officedocument.spreadsheetml.template
xltm=application/vnd.ms-excel.template.macroEnabled.12
xlsb=application/vnd.ms-excel.sheet.binary.macroEnabled.12
xlam=application/vnd.ms-excel.addin.macroEnabled.12
pptx=application/vnd.openxmlformats-officedocument.presentationml.presentation
pptm=application/vnd.ms-powerpoint.presentation.macroEnabled.12
ppsx=application/vnd.openxmlformats-officedocument.presentationml.slideshow
ppsm=application/vnd.ms-powerpoint.slideshow.macroEnabled.12
potx=application/vnd.openxmlformats-officedocument.presentationml.template
potm=application/vnd.ms-powerpoint.template.macroEnabled.12
ppam=application/vnd.ms-powerpoint.addin.macroEnabled.12
sldx=application/vnd.openxmlformats-officedocument.presentationml.slide
sldm=application/vnd.ms-powerpoint.slide.macroEnabled.12
thmx=application/vnd.ms-officetheme
onetoc=application/onenote
onetoc2=application/onenote
onetmp=application/onenote
onepkg=application/onenote
# koffice
# iWork
key=application/x-iwork-keynote-sffkey
kth=application/x-iwork-keynote-sffkth
nmbtemplate=application/x-iwork-numbers-sfftemplate
numbers=application/x-iwork-numbers-sffnumbers
pages=application/x-iwork-pages-sffpages
template=application/x-iwork-pages-sfftemplate
# Extensions for Mozilla apps (Firefox and friends)
xpi=application/x-xpinstall
# Opera extensions
oex=application/x-opera-extension
@@ -1,100 +0,0 @@
package controllers
import (
"github.com/revel/revel"
"os"
fpath "path/filepath"
"strings"
"syscall"
)
type Static struct {
*revel.Controller
}
// This method handles requests for files. The supplied prefix may be absolute
// or relative. If the prefix is relative it is assumed to be relative to the
// application directory. The filepath may either be just a file or an
// additional filepath to search for the given file. This response may return
// the following responses in the event of an error or invalid request;
// 403(Forbidden): If the prefix filepath combination results in a directory.
// 404(Not found): If the prefix and filepath combination results in a non-existent file.
// 500(Internal Server Error): There are a few edge cases that would likely indicate some configuration error outside of revel.
//
// Note that when defining routes in routes/conf the parameters must not have
// spaces around the comma.
// Bad: Static.Serve("public/img", "favicon.png")
// Good: Static.Serve("public/img","favicon.png")
//
// Examples:
// Serving a directory
// Route (conf/routes):
// GET /public/{<.*>filepath} Static.Serve("public")
// Request:
// public/js/sessvars.js
// Calls
// Static.Serve("public","js/sessvars.js")
//
// Serving a file
// Route (conf/routes):
// GET /favicon.ico Static.Serve("public/img","favicon.png")
// Request:
// favicon.ico
// Calls:
// Static.Serve("public/img", "favicon.png")
func (c Static) Serve(prefix, filepath string) revel.Result {
var basePath string
if !fpath.IsAbs(prefix) {
basePath = revel.BasePath
}
basePathPrefix := fpath.Join(basePath, fpath.FromSlash(prefix))
fname := fpath.Join(basePathPrefix, fpath.FromSlash(filepath))
if !strings.HasPrefix(fname, basePathPrefix) {
revel.WARN.Printf("Attempted to read file outside of base path: %s", fname)
return c.NotFound("")
}
finfo, err := os.Stat(fname)
if err != nil {
if os.IsNotExist(err) || err.(*os.PathError).Err == syscall.ENOTDIR {
revel.WARN.Printf("File not found (%s): %s ", fname, err)
return c.NotFound("File not found")
}
revel.ERROR.Printf("Error trying to get fileinfo for '%s': %s", fname, err)
return c.RenderError(err)
}
if finfo.Mode().IsDir() {
revel.WARN.Printf("Attempted directory listing of %s", fname)
return c.Forbidden("Directory listing not allowed")
}
file, err := os.Open(fname)
if err != nil {
if os.IsNotExist(err) {
revel.WARN.Printf("File not found (%s): %s ", fname, err)
return c.NotFound("File not found")
}
revel.ERROR.Printf("Error opening '%s': %s", fname, err)
return c.RenderError(err)
}
return c.RenderFile(file, revel.Inline)
}
// This method allows modules to serve binary files. The parameters are the same
// as Static.Serve with the additional module name pre-pended to the list of
// arguments.
func (c Static) ServeModule(moduleName, prefix, filepath string) revel.Result {
var basePath string
for _, module := range revel.Modules {
if module.Name == moduleName {
basePath = module.Path
}
}
absPath := fpath.Join(basePath, fpath.FromSlash(prefix))
return c.Serve(absPath, filepath)
}
@@ -1,152 +0,0 @@
package controllers
import (
"bytes"
"fmt"
"github.com/revel/revel"
"html"
"html/template"
"reflect"
"strings"
)
type TestRunner struct {
*revel.Controller
}
type TestSuiteDesc struct {
Name string
Tests []TestDesc
}
type TestDesc struct {
Name string
}
type TestSuiteResult struct {
Name string
Passed bool
Results []TestResult
}
type TestResult struct {
Name string
Passed bool
ErrorHtml template.HTML
ErrorSummary string
}
var NONE = []reflect.Value{}
func (c TestRunner) Index() revel.Result {
var testSuites []TestSuiteDesc
for _, testSuite := range revel.TestSuites {
testSuites = append(testSuites, DescribeSuite(testSuite))
}
return c.Render(testSuites)
}
// Run runs a single test, given by the argument.
func (c TestRunner) Run(suite, test string) revel.Result {
result := TestResult{Name: test}
for _, testSuite := range revel.TestSuites {
t := reflect.TypeOf(testSuite).Elem()
if t.Name() != suite {
continue
}
// Found the suite, create a new instance and run the named method.
v := reflect.New(t)
func() {
defer func() {
if err := recover(); err != nil {
error := revel.NewErrorFromPanic(err)
if error == nil {
result.ErrorHtml = template.HTML(html.EscapeString(fmt.Sprint(err)))
} else {
var buffer bytes.Buffer
tmpl, _ := revel.MainTemplateLoader.Template("TestRunner/FailureDetail.html")
tmpl.Render(&buffer, error)
result.ErrorSummary = errorSummary(error)
result.ErrorHtml = template.HTML(buffer.String())
}
}
}()
// Initialize the test suite with a NewTestSuite()
testSuiteInstance := v.Elem().FieldByName("TestSuite")
testSuiteInstance.Set(reflect.ValueOf(revel.NewTestSuite()))
// Call Before(), call the test, and call After().
if m := v.MethodByName("Before"); m.IsValid() {
m.Call(NONE)
}
if m := v.MethodByName("After"); m.IsValid() {
defer m.Call(NONE)
}
v.MethodByName(test).Call(NONE)
// No panic means success.
result.Passed = true
}()
break
}
return c.RenderJson(result)
}
// List returns a JSON list of test suites and tests.
// Used by the "test" command line tool.
func (c TestRunner) List() revel.Result {
var testSuites []TestSuiteDesc
for _, testSuite := range revel.TestSuites {
testSuites = append(testSuites, DescribeSuite(testSuite))
}
return c.RenderJson(testSuites)
}
func DescribeSuite(testSuite interface{}) TestSuiteDesc {
t := reflect.TypeOf(testSuite)
// Get a list of methods of the embedded test type.
super := t.Elem().Field(0).Type
superMethodNameSet := map[string]struct{}{}
for i := 0; i < super.NumMethod(); i++ {
superMethodNameSet[super.Method(i).Name] = struct{}{}
}
// Get a list of methods on the test suite that take no parameters, return
// no results, and were not part of the embedded type's method set.
var tests []TestDesc
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
mt := m.Type
_, isSuperMethod := superMethodNameSet[m.Name]
if mt.NumIn() == 1 &&
mt.NumOut() == 0 &&
mt.In(0) == t &&
!isSuperMethod &&
strings.HasPrefix(m.Name, "Test") {
tests = append(tests, TestDesc{m.Name})
}
}
return TestSuiteDesc{
Name: t.Elem().Name(),
Tests: tests,
}
}
func errorSummary(error *revel.Error) string {
var message = fmt.Sprintf("%4sStatus: %s\n%4sIn %s", "", error.Description, "", error.Path)
if error.Line != 0 {
message += fmt.Sprintf(" (around line %d): ", error.Line)
for _, line := range error.ContextSource() {
if line.IsError {
message += line.Source
}
}
}
return message
}
@@ -1,12 +0,0 @@
package app
import (
"fmt"
"github.com/revel/revel"
)
func init() {
revel.OnAppStart(func() {
fmt.Println("Go to /@tests to run the tests.")
})
}
@@ -1,9 +0,0 @@
<b>{{.Description}}</b><br>
In {{.Path}}
{{if .Line}}
(around {{if .Line}}line {{.Line}}{{end}}{{if .Column}} column {{.Column}}{{end}})
{{end}}:
{{range .ContextSource}}{{if .IsError}}<code>{{.Source}}</code>{{end}}{{end}}<br>
<a style="cursor:pointer;"
onclick="x=this.nextSibling.style;if(!x.display)x.display='none';else x.display=''">
Show Stack</a><pre style="display:none;">{{.Stack}}</pre>
@@ -1,84 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Revel Test Runner</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link href="/@tests/public/css/bootstrap.css" type="text/css" rel="stylesheet"></link>
<script src="/@tests/public/js/jquery-1.9.1.min.js" type="text/javascript"></script>
<style>
header { padding:20px 0; background-color:#ADD8E6 }
.passed td { background-color: #90EE90 !important; }
.failed td { background-color: #FFB6C1 !important; }
.tests td.name, .tests td.result { padding-top: 13px; }
pre { font-size:10px; white-space: pre; }
</style>
</head>
<body>
<header>
<div class="container">
<table><tr><td>
<h1>Test Runner</h1>
<p class="lead">Run all of your application's tests from here.</p>
</td><td style="padding-left:150px;">
<button class="btn btn-large" all-tests="">Run All Tests</button>
</td></tr></table>
</div>
</header>
<div class="container">
{{range .testSuites}}
<p class="lead" style="margin-top:20px;">{{.Name}}</p>
<table class="table table-striped tests" suite="{{.Name}}">
{{range .Tests}}
<tr>
<td class="name">{{.Name}}</td>
<td class="result">
</td>
<td><button test="{{.Name}}" class="btn">Run</button></td>
</tr>
{{end}}
</table>
{{end}}
</div>
<script>
var running = 0;
$("button[test]").click(function() {
var button = $(this).addClass("disabled").text("Running");
running += 1;
runTest(button);
});
$("button[all-tests]").click(function() {
var button = $(this).addClass("disabled").text("Running");
$("button[test]").click();
});
function runTest(button) {
var suite = button.parents("table").attr("suite");
var test = button.attr("test");
var row = button.parents("tr");
var resultCell = row.children(".result");
$.ajax({
dataType: "json",
url: "/@tests/"+suite+"/"+test,
async: false,
success: function(result) {
row.attr("class", result.Passed ? "passed" : "failed");
if (result.Passed) {
resultCell.html("");
} else {
resultCell.html(result.ErrorHtml);
}
button.removeClass("disabled").text("Run");
running -= 1;
if (running == 0) {
$("button[all-tests]").removeClass("disabled").text("Run All Tests");
}
}});
}
</script>
</body>
</html>
@@ -1,47 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Revel Test Runner</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style>
body {
margin: 0;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 20px;
color: #333333;
background-color: #ffffff;
}
header { padding:20px 0; }
header.passed { background-color: #90EE90 !important; }
header.failed { background-color: #FFB6C1 !important; }
table { margin-top: 20px; padding: 8px; line-height: 20px; }
td { vertical-align: top; padding-right:20px; }
a { color: #0088cc; }
.container { margin-left: auto; margin-right: auto; width: 940px; }
.result.failed b { font-weight:bold; color: #C00; font-size: 14px; }
.result.failed span { color: #C00; font-size: 14px; }
</style>
</head>
<body>
<header class="{{if .Passed}}passed{{else}}failed{{end}}">
<div class="container">
<h1>{{.Name}}</h1>
<p>{{if .Passed}}PASSED{{else}}FAILED{{end}}</p>
</div>
</header>
<div class="container">
<table>
{{range .Results}}
<tr class="result {{if .Passed}}passed{{else}}failed{{end}}">
<td><span>{{.Name}}</span></td>
<td>{{if .ErrorHtml}}{{.ErrorHtml}}{{else}}PASSED{{end}}</td>
</tr>
{{end}}
</table>
</div>
</body>
</html>
@@ -1,4 +0,0 @@
GET /@tests TestRunner.Index
GET /@tests.list TestRunner.List
GET /@tests/public/*filepath Static.ServeModule(testrunner,public)
GET /@tests/:suite/:test TestRunner.Run
File diff suppressed because it is too large. Load diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

@@ -1,5 +0,0 @@
/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
//@ sourceMappingURL=jquery.min.map
*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(Line truncated
return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+Line truncated
}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}reLine truncated
@@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Forbidden</title>
</head>
<body>
{{with .Error}}
<h1>
{{.Title}}
</h1>
<p>
{{.Description}}
</p>
{{end}}
</body>
</html>
@@ -1,4 +0,0 @@
{
"title": "{{js .Error.Title}}",
"description": "{{js .Error.Description}}"
}
@@ -1,3 +0,0 @@
{{.Error.Title}}
{{.Error.Description}}
@@ -1 +0,0 @@
<forbidden>{{.Error.Description}}</forbidden>
@@ -1,63 +0,0 @@
<style type="text/css">
html, body {
margin: 0;
padding: 0;
font-family: Helvetica, Arial, Sans;
background: #EEEEEE;
}
.block {
padding: 20px;
border-bottom: 1px solid #aaa;
}
#header h1 {
font-weight: normal;
font-size: 28px;
margin: 0;
}
#more {
color: #666;
font-size: 80%;
border: none;
}
#header {
background: #FFFFCC;
}
#header p {
color: #333;
}
#routes {
background: #f6f6f6;
}
#routes h2 {
font-weight: normal;
font-size: 18px;
margin: 0 0 10px 0;
}
#routes ol {
}
#routes li {
font-size: 14px;
font-family: monospace;
color: #333;
}
</style>
<div id="header" class="block">
{{with .Error}}
<h1>
{{.Title}}
</h1>
<p>
{{.Description}}
</p>
{{end}}
</div>
<div id="routes" class="block">
<h2>These routes have been tried, in this order :</h2>
<ol>
{{range .Router.Routes}}
<li>{{pad .Method 10}}{{pad .Path 50}}{{.Action}}</li>
{{end}}
</ol>
</div>
@@ -1,26 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Not found</title>
</head>
<body>
{{if .DevMode}}
{{template "errors/404-dev.html" .}}
{{else}}
{{with .Error}}
<h1>
{{.Title}}
</h1>
<p>
{{.Description}}
</p>
{{end}}
{{end}}
</body>
</html>
@@ -1,4 +0,0 @@
{
"title": "{{js .Error.Title}}",
"description": "{{js .Error.Description}}"
}
@@ -1,3 +0,0 @@
{{.Error.Title}}
{{.Error.Description}}
@@ -1 +0,0 @@
<notfound>{{.Error.Description}}</notfound>
@@ -1,118 +0,0 @@
<style type="text/css">
html, body {
margin: 0;
padding: 0;
font-family: Helvetica, Arial, Sans;
background: #EEEEEE;
}
.block {
padding: 20px;
border-bottom: 1px solid #aaa;
}
#header h1 {
font-weight: normal;
font-size: 28px;
margin: 0;
}
#more {
color: #666;
font-size: 80%;
border: none;
}
#header {
background: #fcd2da;
}
#header p {
color: #333;
}
#source {
background: #f6f6f6;
}
#source h2 {
font-weight: normal;
font-size: 18px;
margin: 0 0 10px 0;
}
#source .lineNumber {
float: left;
display: block;
width: 40px;
text-align: right;
margin-right: 10px;
font-size: 14px;
font-family: monospace;
background: #333;
color: #fff;
}
#source .line {
clear: both;
color: #333;
margin-bottom: 1px;
}
#source pre {
font-size: 14px;
margin: 0;
overflow-x: hidden;
}
#source .error {
color: #c00 !important;
}
#source .error .lineNumber {
background: #c00;
}
#source a {
text-decoration: none;
}
#source a:hover * {
cursor: pointer !important;
}
#source a:hover pre {
background: #FAFFCF !important;
}
#source em {
font-style: normal;
text-decoration: underline;
font-weight: bold;
}
#source strong {
font-style: normal;
font-weight: bold;
}
</style>
{{with .Error}}
<div id="header" class="block">
<h1>
{{.Title}}
</h1>
<p>
{{if .SourceType}}
The {{.SourceType}} <strong>{{.Path}}</strong> does not compile: <strong>{{.Description}}</strong>
{{else}}
{{.Description}}
{{end}}
</p>
</div>
{{if .Path}}
<div id="source" class="block">
<h2>In {{.Path}}
{{if .Line}}
(around {{if .Line}}line {{.Line}}{{end}}{{if .Column}} column {{.Column}}{{end}})
{{end}}
</h2>
{{range .ContextSource}}
<div class="line {{if .IsError}}error{{end}}">
<span class="lineNumber">{{.Line}}:</span>
<pre>{{.Source}}</pre>
</div>
{{end}}
</div>
{{end}}
{{if .MetaError}}
<div id="source" class="block">
<h2>Additionally, an error occurred while handling this error.</h2>
<div class="line error">
{{.MetaError}}
</div>
</div>
{{end}}
{{end}}
@@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Application error</title>
</head>
<body>
{{if .DevMode}}
{{template "errors/500-dev.html" .}}
{{else}}
<h1>Oops, an error occured</h1>
<p>
This exception has been logged.
</p>
{{end}}
</body>
</html>
@@ -1,4 +0,0 @@
{
"title": "{{js .Error.Title}}",
"description": "{{js .Error.Description}}"
}
@@ -1,15 +0,0 @@
{{.Error.Title}}
{{.Error.Description}}
{{if eq .RunMode "dev"}}
{{with .Error}}
{{if .Path}}
----------
In {{.Path}} {{if .Line}}(around line {{.Line}}){{end}}
{{range .ContextSource}}
{{if .IsError}}>{{else}} {{end}} {{.Line}}: {{.Source}}{{end}}
{{end}}
{{end}}
{{end}}
@@ -1,4 +0,0 @@
<error>
<title>{{.Error.Title}}</title>
<description>{{.Error.Description}}</description>
</error>
-70
View File
@@ -1,70 +0,0 @@
#------------------------
# leanote config
#------------------------
http.port=80
site.url=http://localhost # or http://x.com:8080, http://www.xx.com:9000
# mongdb
db.host=localhost
db.port=27017
db.dbname=leanote # required
db.username=root # if not exists, please leave it blank
db.password=root123 # if not exists, please leave it blank
# or you can set the mongdb url for more complex needs the format is:
# mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
# db.url=mongodb://root:root123@localhost:27017/leanote
# You Must Change It !! About Security!!
app.secret=V85ZzBeTnzpsHyjQX4zukbQ8qqtju9y2aDM55VWxAH9Qop19poekx3xkcDVvrD0y
app.name=leanote
http.addr=
http.ssl=false
cookie.domain=
cookie.httponly=false
cookie.prefix=LEANOTE
cookie.secure=false
format.date=01/02/2006
format.datetime=01/02/2006 15:04
results.chunked=false
#--------------------------------
# revel config
# for dev
#--------------------------------
log.trace.prefix = "TRACE "
log.info.prefix = "INFO "
log.warn.prefix = "WARN "
log.error.prefix = "ERROR "
# The default language of this application.
i18n.default_language=en
module.static=github.com/revel/revel/modules/static
[dev]
mode.dev=true
results.pretty=true
watch=true
module.testrunner = github.com/revel/revel/modules/testrunner
log.trace.output = stderr
log.info.output = stderr
log.warn.output = stderr
log.error.output = stderr
[prod]
mode.dev=false
results.pretty=false
watch=false
module.testrunner =
log.trace.output = off
log.info.output = off
log.warn.output = %(app.name)s.log
log.error.output = %(app.name)s.log
+25 -6
View File
@@ -5,7 +5,7 @@
module:testrunner
# Home is My Blog
Get / Index.Default
Get / Index.Index
GET /note Note.Index
# leanote home
GET /index Index.Index
@@ -23,6 +23,25 @@ GET /findPassword Auth.FindPassword
POST /doFindPassword Auth.DoFindPassword
POST /findPasswordUpdate Auth.FindPasswordUpdate
#####
# 这么多列表, 只是为了最后一句pjax
# note
* /note/listNotes Note.ListNotes
* /note/listTrashNotes Note.ListTrashNotes
* /note/getNoteAndContent Note.GetNoteAndContent
* /note/getNoteContent Note.GetNoteContent
* /note/updateNoteOrContent Note.UpdateNoteOrContent
* /note/deleteNote Note.DeleteNote
* /note/deleteTrash Note.DeleteTrash
* /note/moveNote Note.MoveNote
* /note/copyNote Note.CopyNote
* /note/copySharedNote Note.CopySharedNote
* /note/searchNoteByTags Note.SearchNoteByTags
* /note/toImage Note.ToImage
* /note/html2Image Note.Html2Image
* /note/setNote2Blog Note.SetNote2Blog
# pjax
GET /note/:noteId Note.Index
# blog
@@ -64,7 +83,6 @@ GET /blog/:userIdOrEmail Blog.Index
GET /blog Blog.Index
GET /blog/* Blog.E()
#---------------
# preview
GET /preview/tags/:userIdOrEmail Preview.Tags
@@ -82,13 +100,13 @@ GET /preview/archives Preview.Archives
GET /preview/view/:noteId Preview.Post
GET /preview/post/:noteId Preview.Post
GET /preview/post/userIdOrEmail/:noteId Preview.Post
GET /preview/post/:userIdOrEmail/:noteId Preview.Post
GET /preview/single/userIdOrEmail/:singleId Preview.Single
GET /preview/single/:userIdOrEmail/:singleId Preview.Single
GET /preview/single/:singleId Preview.Single
GET /preview/cate/:notebookId Preview.Cate
GET /preview/cate/userIdOrEmail/:notebookId Preview.Cate
GET /preview/cate/:userIdOrEmail/:notebookId Preview.Cate
GET /preview/:userIdOrEmail Preview.Index
GET /preview Preview.Index
@@ -110,7 +128,8 @@ GET /upload/*filepath Static.Serve("public/upload")
* /member MemberIndex.Index
* /member/index MemberIndex.Index
GET /share/note/:noteId Share.ShowShareNote
# common
* /:controller/:action :controller.:action
* /api/:controller/:action :controller.:action
* /member/:controller/:action :controller.:action
* /member/:controller/:action :controller.:action
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

+94 -4
View File
@@ -79,7 +79,7 @@ myBlog=Blog
history=Histories
save=Save
editorTips=Tips
editorTipsInfo=<h4>1. Short cuts</h4>ctrl+shift+c Toggle code <br /> ctrl+shift+i Insert/edit image <h4>2. shift+enter Get out of current block</h4> eg. <img src="/images/outofcode.png" style="width: 90px"/> in this situation you can use shift+enter to get out of current code block.
editorTipsInfo=<h4>1. Short cuts</h4>ctrl+shift+c Toggle code<h4>2. shift+enter Get out of current block</h4> eg. <img src="/images/outofcode.png" style="width: 90px"/> in this situation you can use shift+enter to get out of current code block.
newNote=New note
newMarkdownNote=New Markdown Note
noNoteNewNoteTips=The notebook is empty, why not...
@@ -129,9 +129,12 @@ themeSetting=Theme
setAvatar=Avatar
logout=Logout
basicInfo=Basic
basicInfoSet=Blog Basic Setting
updateEmail=Update email
usernameSetting=Update username
username=Username
avatar=Avatar
chooseImage=Choose Image
oldPassword=Old password
newPassword=New password
admin=Admin
@@ -144,7 +147,7 @@ uploadImage=Upload image
# blog
aboutMe=About me
blogSet=Set blog
blogSet=Blog Settings
# index
discussion=Discussion
@@ -235,6 +238,7 @@ subDomainExisted=Sub domain is already existed
domainNotPointToLeanote=The custom domin hasn't pointed to d.leanote.com
errorPerPageSize=Page size is error
errorSortField=Sort Field is error
themeValidHasRoundInclude=WARNING: Templates have circular references!
# lea++
leaDesc=leanote blog platform
@@ -243,8 +247,94 @@ latest=Latest
# 用户中心
memberCenter=Member Center
userNotExists=该成员沿未注册
hasUsers=已存在该成员
userNotExists=The user is not exists
hasUsers=The user already exists
# yu
service=Service
imageSizeOver=Sorry, you have no image opacity, please <a href="/service">upgrade your account</a>.
attachSizeOver=Sorry, you have no attachment opacity, please <a href="/service">upgrade your account</a>.
#memeber
welcomeToLeanote=Welcome
accountInfo=Account Info
accountType=Account Type
premiumAccountType=Premium
normalAccountType=Normal
imageSize=Image Opacity
attachSize=Attachment Opacity
upgrade=Upgrade My Account
leanoteEvents=Leanote News
addLeanoteAccount=New Leanote Account
defaultComment=Default leanote comment system
upgradeAccountTips=I want to using a custom domain for my blog, <a class="btn btn-default" href="/service">Upgrade My Account</a>
cateIsPublicNotebook=Category is the published notebooks
dragAndSort=Drag it to sort
permanentLink=Permanent Link
cate=Category
noCates=No Category
single=Single Page
singleTips=You can add many single pages
addSingle=New single page
updateSingle=Update single page
inputSingleTitle=Single page title is required
saveSort=Save sequencing
pagingAndSort=Paging And Sort Settings
perPageSize=Per page size
sortField=Sorter field
sortType=Sorter type
publicTime=Published time
createdTime=Created time
updatedTime=Updated time
desc=Desc
asc=Asc
postList=Post List
hasSelfDefined=Has defined
noSelfDefined=Not defined
setAbstract=Abstract settings
title=Title
content=Content
addTheme=New theme
importTheme=Import theme
exportTheme=Export theme
export=Export
preview=Preview
edit=Edit
use=Use
install=Install
currentTheme=Current theme
myOtherThemes=My other themes
leanoteThemeMarket=Leanote theme market
updateTheme=Update Theme
tplStyleScript=template, style, script
newFile=New file
image=Image
currentFile=Current file
tpl=Template
style=Style
script=Script
header=Header
footer=Footer
index=Home
cate=Category
search=Search
single=Single Page
archive=Archive
post=Post
tags=Tags
tag_posts=Tag's posts
share_comment=Comments
themeJson=Theme settings
paging=Paging
highlight=Code highlight
group=Group
newGroup=New group
deleteGroup=Delete group
addMemberTips=Input username or email to add member
deleteMember=Delete member
# error
notFound=This page cann't found.
+91 -1
View File
@@ -100,7 +100,7 @@ myBlog=我的博客
history=历史记录
save=保存
editorTips=帮助
editorTipsInfo=<h4>1. 快捷键</h4>ctrl+shift+c 代码块切换 <br /> ctrl+shift+i 插入/修改图片<h4>2. shift+enter 跳出当前区域</h4>比如在代码块中<img src="/images/outofcode.png" style="width: 90px"/>按shift+enter可跳出当前代码块.
editorTipsInfo=<h4>1. 快捷键</h4>ctrl+shift+c 代码块切换 <h4>2. shift+enter 跳出当前区域</h4>比如在代码块中<img src="/images/outofcode.png" style="width: 90px"/>按shift+enter可跳出当前代码块.
newNote=新建笔记
newMarkdownNote=新建Markdown笔记
noNoteNewNoteTips=该笔记本下空空如也...何不
@@ -150,9 +150,12 @@ themeSetting=主题设置
setAvatar=头像设置
logout=退出
basicInfo=基本信息
basicInfoSet=博客基本设置
updateEmail=修改Email
usernameSetting=用户名设置
username=用户名
avatar=头像
chooseImage=选择图片
oldPassword=旧密码
newPassword=新密码
admin=后台管理
@@ -261,6 +264,7 @@ subDomainExisted=博客子域名已存在
domainNotPointToLeanote=该域名还未指向 d.leanote.com, 请稍后再试
errorPerPageSize=每页记录数至少为1
errorSortField=排序类型错误
themeValidHasRoundInclude=警告: 模板存在循环引用问题!
# lea++
leaDesc=leanote博客平台
@@ -272,5 +276,91 @@ memberCenter=用户中心
userNotExists=该成员沿未注册
hasUsers=已存在该成员
# yu
service=服务
imageSizeOver=对不起, 您的图片容量不足, 请<a href="/service">升级您的帐户</a>
attachSizeOver=对不起, 您的附件容量不足, 请<a href="/service">升级您的帐户</a>
#memeber
welcomeToLeanote=欢迎来到leanote
accountInfo=帐户信息
accountType=帐户类型
premiumAccountType=彩色套餐
normalAccountType=共享套餐
imageSize=图片空间
attachSize=附件空间
upgrade=升级套餐
leanoteEvents=Leanote动态
addLeanoteAccount=新建Leanote帐户
defaultComment=默认leanote评论系统
upgradeAccountTips=Leanote支持绑定自己的域名到博客上, 请 <a class="btn btn-default" href="/service">升级您的帐户</a>
cateIsPublicNotebook=分类是公开为博客的笔记本
dragAndSort=拖动可排序
permanentLink=固定链接
cate=分类
noCates=无分类
single=单页面
singleTips=您可以添加多个单页面
addSingle=添加单页面
updateSingle=修改单页面
inputSingleTitle=请输入单页面标题
saveSort=保存排序
pagingAndSort=分页与排序设置
perPageSize=每页记录数
sortField=排序字段
sortType=排序类型
publicTime=发表时间
createdTime=创建时间
updatedTime=更新时间
desc=降序
asc=升序
postList=文章列表
hasSelfDefined=已设置
noSelfDefined=未设置
setAbstract=摘要设置
title=标题
content=内容
addTheme=添加主题
importTheme=导入主题
exportTheme=导出主题
export=导出
preview=预览
edit=编辑
use=使用
install=安装
currentTheme=当前主题
myOtherThemes=我的其它主题
leanoteThemeMarket=Leanote主题市场
updateTheme=编辑主题
tplStyleScript=模板, 样式, 脚本
newFile=新建文件
image=图片
currentFile=当前文件
tpl=模板
style=样式
script=脚本
header=头部
footer=底部
index=首页
cate=分类页
search=搜索页
single=单页
archive=归档页
post=文章页
tags=标签页
tag_posts=标签文章页
share_comment=分享评论
themeJson=主题配置
paging=分页
highlight=高亮
group=用户组
newGroup=新建组
deleteGroup=删除组
addMemberTips=输入用户名或邮箱添加成员
deleteMember=删除成员
# 必须要加这个, 奇怪
[CN]
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 1829 files, more files were not shown because too many files have changed in this diff. Show more