Compare commits

...

58 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

3
.gitignore vendored
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

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>

119
README.md
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
README_zh.md Normal file
View File

@@ -0,0 +1,113 @@
# Leanote<74><65>Ʒ
## 1. <20><><EFBFBD><EFBFBD>
Leanote, <20><>ֻ<EFBFBD>DZʼ<C7B1>!
![leanote.png](leanote.png "")
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**
* ֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD>: ͨ<><CDA8>leanote<74><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪ʶ, leanote<74><65><EFBFBD>ײ<EFBFBD><D7B2><EFBFBD><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0BCAD>tinymce<63><65>markdown. <20><>leanote, <20><><EFBFBD><EFBFBD><EFBFBD>Ծ<EFBFBD><D4BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>.
* <20><><EFBFBD><EFBFBD>: <20><>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20>ú<EFBFBD><C3BA><EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪ʶ.
* Э<><D0AD>: <20>ڷ<EFBFBD><DAB7><EFBFBD><EFBFBD><EFBFBD>ͬʱҲ<CAB1><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>Э<EFBFBD><D0AD>֪ʶ.
* <20><><EFBFBD><EFBFBD>: leanoteҲ<65><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD>, <20><>֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD><EFBFBD>ɲ<EFBFBD><C9B2><EFBFBD>, <20><>leanote<74><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD>Զ!
## 2. Ϊʲô<CAB2><C3B4><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>leanote?
˵ʵ<EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>evernote<74><65><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>˿, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD>evernote<74>IJ<EFBFBD><C4B2><EFBFBD>:
* evernote<74>ı<C4B1><E0BCAD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><>ʽ<EFBFBD><CABD><EFBFBD>ҵ<EFBFBD>, <20><>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>Ա, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵĻ<C7B5><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>), ͼƬ<CDBC><C6AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>markdown<77>İ<EFBFBD><C4B0><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD>evernote<74><65>Ȼû<C8BB><C3BB>.
* <20><><EFBFBD><EFBFBD>Ҳ<EFBFBD>뽫֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><D4BC>IJ<EFBFBD><C4B2><EFBFBD>, <20><>wordpress, <20><>Ϊʲô<CAB2><C3B4><EFBFBD><EFBFBD><EFBFBD>߲<EFBFBD><DFB2>ܺ϶<DCBA>Ϊһ<CEAA><D2BB>?
* <20><><EFBFBD><EFBFBD>...
## 3.<2E><>װleanote
leanote<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>˽<EFBFBD><EFBFBD><EFBFBD>Ʊʼ<EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD><D7B0><EFBFBD>Լ<EFBFBD><D4BC>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><>ȻҲ<C8BB><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD> http://leanote.com <20><>ע<EFBFBD><D7A2>.
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>İ<EFBFBD>װ<EFBFBD>̳<EFBFBD>, <20><><EFBFBD>Ʋ<EFBFBD><C6B2><EFBFBD>:
* [leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD>װ<EFBFBD>̳<EFBFBD>](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<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD>װ<EFBFBD>̳<EFBFBD>](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. <20><><EFBFBD><EFBFBD>leanote
Leanote V1.0-beta.2 <20>ѷ<EFBFBD><D1B7><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>(<28><>ʱû<CAB1><C3BB>windows<77><73><EFBFBD><EFBFBD>):
* 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)
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD>Ӽ<EFBFBD><EFBFBD><EFBFBD>[Leanote bin repository](https://github.com/leanote/leanote-bin) (<28>Ƽ<EFBFBD>, <20><>ΪΪ<CEAA><CEAA><EFBFBD>°汾)
### 3.2. <20><>װ MongodbDB
Leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD>golang(ʹ<><CAB9>[revel](https://revel.github.io/)<29><><EFBFBD><EFBFBD> <20><> [MongoDB](https://www.mongodb.org)<29><><EFBFBD>ݿ<EFBFBD>), <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD>Ȱ<EFBFBD>װMongodb.
<EFBFBD><EFBFBD>װMongodbDB, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݸ<EFBFBD><DDB8><EFBFBD>ϸ<EFBFBD><CFB8><EFBFBD><EFBFBD><EFBFBD>鿴: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
### 3.3. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>
MongodbDB<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
```
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
```
<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD>ݰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD>:
```
user2 username: admin, password: abc123 (<28><><EFBFBD><EFBFBD>Ա, <20><>Ҫ!)
user3 username: demo@leanote.com, password: demo@leanote.com (Ϊ<><CEAA><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>)
```
### 3.4. <20><><EFBFBD><EFBFBD>
<EFBFBD>޸<EFBFBD> `[PATH_TO_LEANOTE]/conf/app.conf`. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>:
``mongodb`` **<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!**
```Shell
db.host=localhost
db.port=27017
db.dbname=leanote
db.username=
db.password=
```
``app.secret`` **<2A><>Ҫ**
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޸<EFBFBD>һ<EFBFBD><EFBFBD>, app<70><70><EFBFBD><EFBFBD>Կ, <20><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Ĭ<EFBFBD>ϵ<EFBFBD>, <20><>Ȼ<EFBFBD><C8BB><EFBFBD>а<EFBFBD>ȫ<EFBFBD><C8AB><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鿴 `app/app.conf` <20><> [revel <20>ֲ<EFBFBD>](https://revel.github.io/)
### 3.5. <20><><EFBFBD><EFBFBD>leanote
```
$> cd PATH_TO_LEANOTE/bin
$> sudo sh run.sh
```
## 4. <20><><EFBFBD>ζ<EFBFBD>leanote<74><65><EFBFBD>ж<EFBFBD><D0B6>ο<EFBFBD><CEBF><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>鿴 [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. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>л [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](https://github.com/leanote/leanote/graphs/contributors) <20>Ĺ<EFBFBD><C4B9><EFBFBD>, leanote<74><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD><C7B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!
## 6. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ӭ<EFBFBD>ύ[pull requests](https://github.com/leanote/leanote/pulls) <20><>leanote.
leanote<EFBFBD><EFBFBD><EFBFBD>кܶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϲ<EFBFBD><CFB2><EFBFBD><EFBFBD>, <20><>ӭ<EFBFBD><D3AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>leanote.
## <20><><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>
* [leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ư<EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD>װ<EFBFBD>̳<EFBFBD>](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<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD>װ<EFBFBD>̳<EFBFBD>](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Դ<65><EFBFBD><EBB5BC>](https://github.com/leanote/leanote/wiki/Leanote-source-leanoteԴ<65><EFBFBD><EBB5BC>)
* [leanote blog theme api(<28><><EFBFBD>İ<EFBFBD>)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
* [How to develop leanote <20><><EFBFBD>ο<EFBFBD><CEBF><EFBFBD>leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-<2D><><EFBFBD>ο<EFBFBD><CEBF><EFBFBD>leanote)
## <20><><EFBFBD><EFBFBD>
* [leanote <20><><EFBFBD><EFBFBD>](http://bbs.leanote.com)
* QQȺ: 158716820
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
----------------------------------------------------------------
[English](README.md)

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
}
}

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 {

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)
}

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
}

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)
}
}

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 {

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

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)
}

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)
}

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,

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)

View File

@@ -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)
}
// 添加用户

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() {
})
}
}

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

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` //分享笔记的密码
}
// 内容

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这个时间会自动清空
}

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:"-"` // 开始日期

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()
})
}
});
}

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))
}

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

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()
}

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
}

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
}
}

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)

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()

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中也要删除

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
}
}

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{}

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
}

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
}

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;
}

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 {

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">

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>

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>

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"}}");

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,

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">

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 {

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>

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}}

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>

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>

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}}

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;"

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);

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" .}}

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>

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>

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>
-->
<!-- 主要内容区 -->

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">

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>

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">

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">

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">

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>

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>

View File

@@ -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>

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}}

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'

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

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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.")
})
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

File diff suppressed because one or more lines are too long

View File

@@ -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>

View File

@@ -1,4 +0,0 @@
{
"title": "{{js .Error.Title}}",
"description": "{{js .Error.Description}}"
}

View File

@@ -1,3 +0,0 @@
{{.Error.Title}}
{{.Error.Description}}

View File

@@ -1 +0,0 @@
<forbidden>{{.Error.Description}}</forbidden>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,4 +0,0 @@
{
"title": "{{js .Error.Title}}",
"description": "{{js .Error.Description}}"
}

View File

@@ -1,3 +0,0 @@
{{.Error.Title}}
{{.Error.Description}}

View File

@@ -1 +0,0 @@
<notfound>{{.Error.Description}}</notfound>

View File

@@ -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}}

View File

@@ -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>

View File

@@ -1,4 +0,0 @@
{
"title": "{{js .Error.Title}}",
"description": "{{js .Error.Description}}"
}

View File

@@ -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}}

View File

@@ -1,4 +0,0 @@
<error>
<title>{{.Error.Title}}</title>
<description>{{.Error.Description}}</description>
</error>

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

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
leanote.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

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.

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]

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