├── .gitattributes ├── .gitignore ├── README.md ├── app.js ├── articles └── test.md ├── doc ├── article.md ├── bookmark.md ├── comment.md ├── commonDAO.md ├── home.md └── user.md ├── package.json ├── public ├── 404 │ ├── 404.css │ ├── 404.html │ ├── boat.png │ ├── cloud.png │ ├── wave-back.png │ └── wave-front.png ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── gallary │ ├── 0750f1a8bb3bb36bc359cb9c6703f396.jpg │ ├── 1327390473_3dtj_4.jpg │ ├── 205cdf88d43f879491629c4bd21b0ef41ad53acb.jpg │ ├── 25c9c636afc37931e9ac3401e9c4b74542a9118f.jpg │ ├── 2fb27610b912c8fc769546e5fe039245d6882169.jpg │ ├── 304be9c3a55a1b416cb91ada4875f0cb.jpg │ ├── 347784364248d78f55c50f82fed7dd77.jpg │ ├── 36.jpg │ ├── 3622f6ee4bdcc69e40b2fd2a54562122.jpg │ ├── 472309f7905298227ea53ce9d5ca7bcb0a46d401.jpg │ ├── 57e853d9f2d3572c9c93a2f98813632762d0c35f.jpg │ ├── 70ccd1fe9925bc31a8c823b35cdf8db1cb137039.jpg │ ├── 83146ca0gw1e5uv98fxwcj20c80nfdhs.jpg │ ├── 97897383_2.jpg │ ├── a3d96e7c85580ec6aef37b242a9ed451.jpg │ ├── aa18972bd40735fab975fa929c510fb30f240817.jpg │ ├── ae8e9a18ab19d23f4bedbce2.jpg │ ├── bdc7a825bc315c60dd857dca8fb1cb13495477b8.jpg │ ├── d6ca7bcb0a46f21f78d01634f7246b600d33aef5.jpg │ ├── large_nKru_2391000169cf1260.jpg │ ├── m2w690hq92lt_large_LE4J_0156000035c81260.jpg │ ├── m2w690hq92lt_large_xlCV_77500001a647125f.jpg │ ├── m2w690hq92lt_original_sKaq_414f00003ce9118c.jpg │ ├── original_5fSW_59ff000093b9118c.jpg │ ├── original_DVSi_2346000169651260.jpg │ ├── u=553037556,1932829573&fm=9&gp=0.jpg │ ├── 无标题.jpg │ ├── 未来.JPG │ └── 科拉传奇.The.Legend.of.Korra.S01E12.Chi_Eng.WEB-HR.AAC.1024X576.x264-YYeTs&SLOMO[01-10-12].JPG ├── gallary_sm │ ├── 0750f1a8bb3bb36bc359cb9c6703f396.jpg │ ├── 1327390473_3dtj_4.jpg │ ├── 205cdf88d43f879491629c4bd21b0ef41ad53acb.jpg │ ├── 25c9c636afc37931e9ac3401e9c4b74542a9118f.jpg │ ├── 2fb27610b912c8fc769546e5fe039245d6882169.jpg │ ├── 304be9c3a55a1b416cb91ada4875f0cb.jpg │ ├── 347784364248d78f55c50f82fed7dd77.jpg │ ├── 36.jpg │ ├── 3622f6ee4bdcc69e40b2fd2a54562122.jpg │ ├── 472309f7905298227ea53ce9d5ca7bcb0a46d401.jpg │ ├── 57e853d9f2d3572c9c93a2f98813632762d0c35f.jpg │ ├── 70ccd1fe9925bc31a8c823b35cdf8db1cb137039.jpg │ ├── 83146ca0gw1e5uv98fxwcj20c80nfdhs.jpg │ ├── 97897383_2.jpg │ ├── a3d96e7c85580ec6aef37b242a9ed451.jpg │ ├── aa18972bd40735fab975fa929c510fb30f240817.jpg │ ├── ae8e9a18ab19d23f4bedbce2.jpg │ ├── bdc7a825bc315c60dd857dca8fb1cb13495477b8.jpg │ ├── d6ca7bcb0a46f21f78d01634f7246b600d33aef5.jpg │ ├── large_nKru_2391000169cf1260.jpg │ ├── m2w690hq92lt_large_LE4J_0156000035c81260.jpg │ ├── m2w690hq92lt_large_xlCV_77500001a647125f.jpg │ ├── m2w690hq92lt_original_sKaq_414f00003ce9118c.jpg │ ├── original_5fSW_59ff000093b9118c.jpg │ ├── original_DVSi_2346000169651260.jpg │ ├── u=553037556,1932829573&fm=9&gp=0.jpg │ ├── 无标题.jpg │ ├── 未来.JPG │ └── 科拉传奇.The.Legend.of.Korra.S01E12.Chi_Eng.WEB-HR.AAC.1024X576.x264-YYeTs&SLOMO[01-10-12].JPG ├── images │ ├── boat.png │ ├── cloud.png │ ├── default_avatar.jpg │ ├── favicon.ico │ ├── loading.gif │ ├── wave-back.png │ └── wave-front.png ├── javascripts │ ├── exp │ │ └── broadchat.js │ ├── page │ │ ├── articleDetail.js │ │ ├── editArticle.js │ │ ├── gallary.js │ │ ├── global.js │ │ ├── index.js │ │ ├── listArticle.js │ │ ├── listArticle_owner.js │ │ ├── login.js │ │ ├── regist.js │ │ ├── search.js │ │ ├── uploadPic.js │ │ ├── userCenter.js │ │ ├── userDetail.js │ │ └── writeArticle.js │ ├── pageTools │ │ ├── Admire.js │ │ ├── Article.js │ │ ├── Bookmark.js │ │ ├── Comment.js │ │ ├── Remind.js │ │ ├── Tag.js │ │ └── User.js │ └── tools │ │ ├── bootstrap.min.js │ │ ├── highlight.pack.js │ │ ├── jquery-1.10.2.min.js │ │ ├── jquery-mousewheel.js │ │ ├── markdown.js │ │ ├── showdown.js │ │ └── showdown_extensions │ │ ├── github.js │ │ ├── prettify.js │ │ ├── table.js │ │ └── twitter.js └── stylesheets │ ├── bootstrap-theme.min.css │ ├── bootstrap.min.css │ ├── github.css │ ├── monokai.css │ ├── page │ ├── admire.css │ ├── articleDetail.css │ ├── bookmark.css │ ├── comment.css │ ├── gallary.css │ ├── index.css │ ├── listArticle.css │ ├── remind.css │ ├── search.css │ ├── tag.css │ ├── uploadPic.css │ ├── user.css │ ├── userCenter.css │ ├── userDetail.css │ └── writeArticle.css │ ├── pageTools │ ├── admire.css │ ├── article.css │ ├── bookmark.css │ ├── comment.css │ ├── remind.css │ ├── tag.css │ └── user.css │ └── style.css ├── routes ├── Actions │ ├── AdmireAction.js │ ├── ArticleAction.js │ ├── BookmarkAction.js │ ├── CommentAction.js │ ├── ExpAction.js │ ├── GallaryAction.js │ ├── PictureAction.js │ ├── RemindAction.js │ ├── TagAction.js │ └── UserAction.js ├── Model │ ├── Admire.js │ ├── Article.js │ ├── Bookmark.js │ ├── Comment.js │ ├── CommonDAO.js │ ├── Remind.js │ ├── Tag.js │ └── User.js ├── index.js └── setting.js ├── upload_tmp └── 5792-oxlaq1.jpg └── views ├── advice.jade ├── articleDetail.jade ├── broadchat.jade ├── editArticle.jade ├── error.jade ├── gallary.jade ├── index.jade ├── layout.jade ├── listArticle.jade ├── login.jade ├── regist.jade ├── search.jade ├── userCenter.jade ├── userDetail.jade └── writeArticle.jade /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 天镶的博客 2 | ==== 3 | 一个基于Node.js开发的公共博客管理系统,使用express,mongodb进行开发 4 | 5 | 目前已部署到[nodejitsu](https://www.nodejitsu.com/)上,数据库使用[mongohq](http://www.mongohq.com/home),[单击访问主页](http://skyinlayer.nodejitsu.com/) 6 | 7 | ##目前的角色 8 | 9 | 1. 管理员 10 | 2. 来访用户 11 | 12 | ##目前的功能 13 | 14 | ###系统 15 | 16 | 1. 普通用户注册 17 | 2. 瀑布流查看博客图片 18 | 19 | ###所有用户 20 | 21 | 1. 查看/评论文章 22 | 2. 对评论点赞 23 | 3. 收藏文章 24 | 4. 查看用户中心 25 | 5. 修改基本的个人信息 26 | 27 | ###管理员额外功能 28 | 29 | 1. 添加/修改/删除 文章 30 | 2. 添加/删除 图片 31 | 32 | ##添加中的功能 33 | 34 | 1. 查看他人用户中心 35 | 2. 用户关注 36 | 3. 图片点赞 37 | 4. 文章访问量统计 38 | 5. ... 39 | 40 | -------------------------------------------------------------------------------- /articles/test.md: -------------------------------------------------------------------------------- 1 | ## ZOJ 1091 Knight Moves ## 2 | >**题意**:骑士遍历,给源点、目标点,求源点到目标点的最短步数 3 | > 4 | >**解法**:经典bfs 5 | > 6 | >**吐槽** :一直想用双向bfs写一次,不过这两天各种屁事。这题完全就是C++版本的翻译...熟悉了一下python的队列实现和矩阵,还是挺有收获的,发现我特别依赖字典,这样不好不好 7 | 8 | 9 | import sys 10 | des=[[2,1],[2,-1],[-2,1],[-2,-1],[1,2],[1,-2],[-1,2],[-1,-2]] 11 | def bfs(start,end): 12 | q=[] 13 | flag = [([0] * 11) for i in range(11)] 14 | q.append(start) 15 | flag[start['x']][start['y']]=1 16 | while len(q): 17 | cur=q[0] 18 | q=q[1:] 19 | if cur['x']==end['x'] and cur['y']==end['y']: 20 | return cur 21 | for i in range(len(des)): 22 | curx=des[i][0]+cur['x'] 23 | cury=des[i][1]+cur['y'] 24 | if curx<=8 and curx>=1 and cury<=8 and cury>=1 and flag[curx][cury]==0: 25 | flag[curx][cury]=1 26 | q.append({'x':curx,'y':cury,'t':cur['t']+1}) 27 | 28 | for line in sys.stdin: 29 | a=line.rstrip().split() 30 | start={'x':ord(a[0][0])-ord('a')+1,'y':ord(a[0][1])-ord('0'),'t':0} 31 | end={'x':ord(a[1][0])-ord('a')+1,'y':ord(a[1][1])-ord('0'),'t':0} 32 | ans=bfs(start,end) 33 | print 'To get from %s to %s takes %d knight moves.' %(a[0],a[1],ans['t']) -------------------------------------------------------------------------------- /doc/bookmark.md: -------------------------------------------------------------------------------- 1 | 书签 [Bookmark] 2 | === 3 | *** 4 | #构造函数 5 | ```js 6 | function Bookmark(bookmark) { 7 | this.username = bookmark.username; 8 | this.articleId = bookmark.articleId; 9 | this.time = bookmark.time; 10 | this.id = bookmark.id; 11 | } 12 | ``` 13 | #属性 14 | > **id** [string] : uuid v4生成的字符串 15 | 16 | > **username** [string] : 书签拥有者的用户名 17 | 18 | > **articleId** [string] : 书签所属文章的id 19 | 20 | > **time** [number] : 创建书签的时间,为毫秒数 21 | 22 | #原型上的方法 23 | *** 24 | ##save 25 | ###说明 26 | > 保存当前书签对象 27 | 28 | ###参数 29 | > **callback** [function] : 保存完成后的回调函数,两个参数 30 | 31 | >> **err** [object]: 若未发生错误,为null 32 | 33 | >> **result** [Bookmark] :持久化后的Bookmark对象 34 | 35 | ###实例 36 | ```js 37 | var bookmark = new Bookmark({ 38 | articleId: req.body.articleId, 39 | username: req.session.user.username 40 | }); 41 | bookmark.save(function(err, bookmark) { 42 | //TODO 43 | }); 44 | ``` 45 | 46 | ##remove 47 | ###说明 48 | > 移除当前书签对象 49 | 50 | ###参数 51 | > **callback** [function] : 移除完成后的回调函数,一个参数 52 | 53 | >> **err** [object]: 若未发生错误,为null 54 | 55 | ###实例 56 | ```js 57 | bookmark.remove(function(err) { 58 | if (err) return res.json(500, { 59 | message: err.message 60 | }); 61 | res.json({ 62 | success: true 63 | }); 64 | }); 65 | ``` 66 | 67 | #方法 68 | *** 69 | ##get 70 | ###说明 71 | > 根据书签id获取一个书签 72 | 73 | ###参数 74 | > **bookmarkId** [string] : 书签的id 75 | 76 | > **callback** [function] : 移除完成后的回调函数,两个参数 77 | 78 | >> **err** [object]: 若未发生错误,为null 79 | 80 | >> **bookmark** [Bookmark] : 获取到的书签对象,若失败,则为null 81 | 82 | ###实例 83 | ```js 84 | Bookmark.get(req.body.bookmarkId, function(err, bookmark) { 85 | if (err) return res.json(500); 86 | if (!bookmark) return res.status(404).send("not found"); 87 | bookmark.time = moment(bookmark.time).format("HH:mm MM月DD日 YYYY年"); 88 | res.json({ 89 | bookmark: bookmark 90 | }); 91 | }); 92 | ``` 93 | ##checkBooked 94 | ###说明 95 | > 判断一个用户是否收藏了某篇文章 96 | 97 | ###参数 98 | > **username** [string] : 用户的用户名 99 | 100 | > **articleId** [string] : 文章的id 101 | 102 | > **callback** [function] : 移除完成后的回调函数,两个参数 103 | 104 | >> **err** [object]: 若未发生错误,为null 105 | 106 | >> **booked** [boolean] : 若已经加入收藏,则为true,否则为false 107 | 108 | ###实例 109 | ```js 110 | Bookmark.checkBooked(req.session.user.username, req.body.articleId, function(err, booked) { 111 | if (err) return res.json(500, { 112 | message: err.message 113 | }); 114 | res.json({ 115 | booked: booked 116 | }); 117 | }); 118 | ``` 119 | 120 | ##countByArticle 121 | ###说明 122 | > 统计一篇文章的被收藏次数 123 | 124 | ###参数 125 | > **articleId** [string] : 文章的id 126 | 127 | > **callback** [function] : 移除完成后的回调函数,两个参数 128 | 129 | >> **err** [object]: 若未发生错误,为null 130 | 131 | >> **total** [number] : 文章被收藏次数 132 | 133 | ###实例 134 | ```js 135 | Bookmark.countByArticle(req.body.articleId, function(err, total) { 136 | if (err) return res.json(500, { 137 | message: err.message 138 | }); 139 | res.json({ 140 | total: total 141 | }); 142 | }); 143 | ``` 144 | 145 | ##countByUser 146 | ###说明 147 | > 统计一个用户的书签总个数 148 | 149 | ###参数 150 | > **username** [string] :用户的用户名 151 | 152 | > **callback** [function] : 移除完成后的回调函数,两个参数 153 | 154 | >> **err** [object]: 若未发生错误,为null 155 | 156 | >> **total** [number] : 用户的书签总个数 157 | 158 | ###实例 159 | ```js 160 | Bookmark.countByUser(req.body.username, function(err, total) { 161 | if (err) return res.json(500); 162 | res.json({ 163 | total: total 164 | }); 165 | }); 166 | ``` 167 | ##getByUser 168 | ###说明 169 | > 分页获取一个用户的所有书签 170 | 171 | ###参数 172 | > **username** [string] :用户的用户名 173 | 174 | > **curPage** [integer] : 当前页,从0开始 175 | 176 | > **perPage** [integer] : 每页的书签个数 177 | 178 | > **callback** [function] : 查询完成后的回调函数 179 | 180 | >> **err** [object]: 若未发生错误,为null 181 | 182 | >> **bookmarks** [array:Bookmark] : 获取到的书签对象的数组 183 | 184 | ###实例 185 | ```js 186 | Bookmark.getByUser(req.body.username, Number(req.body.curPage), Number(req.body.perPage), function(err, bookmarks) { 187 | if (err) return res.json(500); 188 | for (var i = bookmarks.length; i--;) { 189 | bookmarks[i].time = moment(bookmarks[i].time).format("HH:mm MM月DD日 YYYY年"); 190 | } 191 | res.json({ 192 | bookmarks: bookmarks 193 | }); 194 | }); 195 | ``` 196 | -------------------------------------------------------------------------------- /doc/comment.md: -------------------------------------------------------------------------------- 1 | 评论 [Comment] 2 | === 3 | *** 4 | #构造函数 5 | *** 6 | ```js 7 | function Comment(comment) { 8 | this.comment = comment.comment; 9 | this.username = comment.username; 10 | this.reply = comment.reply; 11 | this.articleId = comment.articleId; 12 | this.time = comment.time; 13 | this.id = comment.id; 14 | } 15 | ``` 16 | #属性 17 | *** 18 | > **id** [string] : 评论的id,uuid的v4生成 19 | 20 | > **articleId** [string] : 评论所属文章的id 21 | 22 | > **username** [string] : 创建这条评论的用户名 23 | 24 | > **comment** [string] : 评论的内容 25 | 26 | > **time** [number] : 评论的时间,为毫秒数 27 | 28 | > **reply** [string] : 若本评论回复了其他评论,则reply的值为被回复的评论的id,否则为null 29 | 30 | #原型上的方法 31 | *** 32 | ##save 33 | ### 说明 34 | > 保存当前评论对象 35 | 36 | ### 参数 37 | > **callback** [function] : 保存完成后的回调函数,两个参数 38 | 39 | >> **err** [object]: 若未发生错误,为null 40 | 41 | >> **result** [Comment] :持久化后的Comment对象 42 | 43 | 44 | ### 实例 45 | ```js 46 | var comment = new Comment({ 47 | articleId: req.body.articleId, 48 | username: req.session.user.username, 49 | comment: req.body.comment, 50 | reply: req.body.replyId 51 | }); 52 | comment.save(function(err, comment) { 53 | if (err) return callback(err); 54 | callback(err, comment); 55 | }); 56 | ``` 57 | 58 | ##remove 59 | ### 说明 60 | > 删除当前评论 61 | 62 | ### 参数 63 | > **callback** [function] : 删除完成后的回调函数,一个参数 64 | 65 | >> **err** [object]: 若未发生错误,为null 66 | 67 | 68 | ### 实例 69 | ```js 70 | comment.remove(function(err) { 71 | if (err) return res.json(500, { 72 | message: err.message 73 | }); 74 | res.json({ 75 | success: true 76 | }); 77 | }); 78 | ``` 79 | #方法 80 | *** 81 | ##get 82 | ### 说明 83 | > 根据评论id获取一个评论 84 | 85 | ### 参数 86 | > **commentId** [string] : 需要获取的评论的id 87 | 88 | > **callback** [function] : 获取完成后的回调函数,两个参数 89 | 90 | >> **err** [object]: 若未发生错误,为null 91 | 92 | >> **comment** [Comment]: 获取的评论对象,没有则为null 93 | 94 | 95 | ### 实例 96 | ```js 97 | Comment.get(req.body.commentId, function(err, comment) { 98 | //TODO 99 | }); 100 | ``` 101 | 102 | ##countByArticle 103 | ###说明 104 | > 统计一篇文章的评论个数 105 | 106 | ###参数 107 | > **articleId** [string]: 文章的id 108 | 109 | > **callback** [function] : 统计完成后的回调函数,两个参数 110 | 111 | >> **err** [object]: 若未发生错误,为null 112 | 113 | >> **total** [number]: 该文章的评论总数 114 | 115 | ###实例 116 | ```js 117 | Comment.countByArticle(req.body.articleId, function(err, total) { 118 | if (err) return res.json(500, { 119 | message: err.message 120 | }); 121 | res.json({ 122 | total: total 123 | }); 124 | }); 125 | ``` 126 | 127 | ##getByArticle 128 | ### 说明 129 | > 分页获取一篇文章的评论 130 | 131 | ### 参数 132 | > **articleId** [string] : 文章的id 133 | 134 | > **curPage** [integer] : 当前页,从0开始 135 | 136 | > **perPage** [integer] : 每页的文章个数 137 | 138 | > **callback** [function] : 获取完成后的回调函数,两个参数 139 | 140 | >> **err** [object]: 若未发生错误,为null 141 | 142 | >> **comments** [array:Comment]: 获取的评论对象列表 143 | 144 | ### 实例 145 | ```js 146 | Comment.getByArticle(req.body.articleId, Number(req.body.curPage), Number(req.body.perPage), function(err, comments) { 147 | var i; 148 | if (err) return res.json(500, { 149 | message: err.message 150 | }); 151 | for (i = comments.length; i--;) { 152 | comments[i].time = moment(comments[i].time).format("HH:mm MM月DD日 YYYY年"); 153 | } 154 | res.json({ 155 | comments: comments 156 | }); 157 | }); 158 | ``` 159 | 160 | ##countByUser 161 | ###说明 162 | > 统计一个用户的评论个数 163 | 164 | ###参数 165 | > **username** [string]: 用户的用户名 166 | 167 | > **callback** [function] : 统计完成后的回调函数,两个参数 168 | 169 | >> **err** [object]: 若未发生错误,为null 170 | 171 | >> **total** [number]: 该用户的评论总数 172 | 173 | ###实例 174 | ```js 175 | Comment.countByUser(req.body.username, function(err, total) { 176 | if (err) return res.json(500, { 177 | message: err.message 178 | }); 179 | res.json({ 180 | total: total 181 | }); 182 | }); 183 | ``` 184 | 185 | ##getByUser 186 | ### 说明 187 | > 分页获取一个用户的评论 188 | 189 | ### 参数 190 | > **username** [string]: 用户的用户名 191 | 192 | > **curPage** [integer] : 当前页,从0开始 193 | 194 | > **perPage** [integer] : 每页的文章个数 195 | 196 | > **callback** [function] : 获取完成后的回调函数,两个参数 197 | 198 | >> **err** [object]: 若未发生错误,为null 199 | 200 | >> **comments** [array:Comment]: 获取的评论对象列表 201 | 202 | ### 实例 203 | ```js 204 | Comment.getByUser(req.body.username, Number(req.body.curPage), Number(req.body.perPage), function(err, comments) { 205 | if (err) return res.json(500, { 206 | message: err.message 207 | }); 208 | for (var i = comments.length; i--;) { 209 | comments[i].time = moment(comments[i].time).format("HH:mm MM月DD日 YYYY年"); 210 | } 211 | res.json({ 212 | comments: comments 213 | }); 214 | }); 215 | ``` 216 | 217 | -------------------------------------------------------------------------------- /doc/commonDAO.md: -------------------------------------------------------------------------------- 1 | 公用数据库连接层 [CommonDAO.js] 2 | === 3 | *** 4 | 使用[node-mongodb-native](https://github.com/mongodb/node-mongodb-native)直接与mongodb数据库相连 5 | 6 | 提供以下方法: 7 | 8 | 1. [save](#save) 9 | 2. [findOne](#findone) 10 | 3. [find](#find) 11 | 4. [count](#count) 12 | 5. [update](#update) 13 | 6. [remove](#remove) 14 | 15 | ## save 16 | *** 17 | ### 说明 18 | > 用于将一个对象保存到mongodb数据库中 19 | 20 | ### 参数 21 | > **collectionName** [string]:mongodb的collection名称 22 | 23 | > **obj** [object] : 需要保存到collection中的对象 24 | 25 | > **callback** [function]:保存完毕后执行的回调函数 26 | 27 | >> **err** [object]: 若未发生错误,为null 28 | 29 | >> **result** [array:object] :result[0]为存入数据库的对象,若长度为0则保存失败 30 | 31 | ### 实例 32 | ```js 33 | commonDao.save("article", { 34 | id: uuid.v4, 35 | content: "hello world" 36 | }, function(err, result) { 37 | if (err) return callback(err); 38 | if (!result[0]) return callback(new Error("保存失败")); 39 | callback(err, new Article(result[0])); 40 | }); 41 | ``` 42 | 43 | ## findOne 44 | *** 45 | ### 说明 46 | > 根据特定条件在数据库中查找一个匹配的对象 47 | 48 | ### 参数 49 | > **collectionName** [string]: mongodb的collection名称 50 | 51 | > **oArgs** [object]: mongodb查询时的条件 52 | 53 | > **callback** [function]: 查询执行完后的回调函数,两个参数: 54 | 55 | >> **err** [object]: 若未发生错误,则为null 56 | 57 | >> **result** [object]: 查询结果 58 | 59 | ### 实例 60 | 根据文章id查找文章 61 | ```js 62 | commonDao.findOne("article", { 63 | id: id 64 | }, callback); 65 | ``` 66 | 67 | ## find 68 | *** 69 | ### 说明 70 | > 根据特定条件和配置在数据库中查找所有匹配的对象 71 | 72 | ### 参数 73 | > **collectionName** [string] : mongodb的collection名称 74 | 75 | > **oArgs** [object] : mongodb查询的条件及分页、排序设置 76 | 77 | >> **condition** [object] : mongodb查询的条件 78 | 79 | >> **page** [object] : 查询的分页设置 80 | > 81 | >>> **curPage** [integer] : 查询的页数,从0开始 82 | > 83 | >>> **perPage** [integer] : 查询每页的个数 84 | > 85 | >> **sort** [object] : 查询的排序方式,键为排序的字段名称,值为**1**表示**正序**,值为**-1**表示倒序 86 | > 87 | > **callback** [function] : 查询完成之后的回调函数,有两个参数: 88 | > 89 | >> **err** [object]: 若未发生错误,则为null 90 | > 91 | >> **results** [array:object]: 查询结果数组 92 | 93 | ### 实例 94 | 以创作时间为倒序,每页10个结果,查询第二页的所有文章 95 | ```js 96 | commonDao.find("article", { 97 | sort: { 98 | writeTime: -1 99 | }, 100 | page: { 101 | curPage: 1, 102 | perPage: 10 103 | } 104 | }, callback); 105 | ``` 106 | 107 | ## count 108 | *** 109 | ### 说明 110 | > 统计数据库中符合条件的对象个数 111 | 112 | ### 参数 113 | > **collectionName** [string] : mongodb的collection名称 114 | > 115 | > **oArgs** [object] : 统计的条件 116 | > 117 | > **callback** [function] : 统计完成后的回调函数,两个参数: 118 | > > **err** [object] : 若未发生错误,则为null 119 | > 120 | > > **total** [number] : 统计的结果 121 | 122 | ### 实例 123 | 通过作者用户名查询文章 124 | ```js 125 | commonDao.count("article", { 126 | writer: username 127 | }, callback); 128 | ``` 129 | ## update 130 | *** 131 | ### 说明 132 | > 更新所有符合条件的对象 133 | 134 | ### 参数 135 | > **collectionName** [string] : mongodb的collection名称 136 | 137 | > **oArgs** [object] : 查找需要被更新对象的条件 138 | 139 | > **change** [object] : 需要被更新的数据,键为更新的字段名称,值为需要被更新的值 140 | 141 | > **callback** [function] : 更新完成后的回调函数,一个参数: 142 | 143 | >> **err** [object] : 若未发生错误,则为null 144 | 145 | ### 实例 146 | 更新一个文章的主题,内容,修改时间,及标签 147 | ```js 148 | commonDao.update("article", { 149 | id: this.id 150 | }, { 151 | content: this.content, 152 | title: this.title, 153 | lastModifyTime: new Date().getTime(), 154 | tags: this.tags 155 | }, callback); 156 | ``` 157 | ## remove 158 | *** 159 | ### 说明 160 | > 移除所有符合条件的对象 161 | 162 | ### 参数 163 | > **collectionName** [string] : mongodb的collection名称 164 | 165 | > **oArgs** [object] : 查找需要被删除对象的条件 166 | 167 | > **callback** [function] : 删除完成后的回调函数,一个参数: 168 | 169 | >> **err** [object] : 若未发生错误,则为null 170 | 171 | ### 实例 172 | 根据文章id删除一篇文章 173 | ```js 174 | commonDao.remove("article", { 175 | id: articleId 176 | }, callback); 177 | ``` -------------------------------------------------------------------------------- /doc/home.md: -------------------------------------------------------------------------------- 1 | 项目简介 2 | === 3 | *** 4 | ##简介 5 | > 一个多人共同管理的博客模板 6 | > 7 | > 使用nodejs和mongodb进行开发 8 | > 9 | > 采用了express框架和jade模板引擎 10 | 11 | ##效果 12 | > [点我跳转](http://skyinlayer.jit.su/) 13 | 14 | ##依赖 15 | > [express: 3.4.2](http://expressjs.com/) 16 | > 17 | > [jade: *](http://jade-lang.com/) 18 | > 19 | > [node-uuid: 1.4.1](http://github.com/broofa/node-uuid) 20 | > 21 | > [mongodb: 1.3.19](https://github.com/mongodb/node-mongodb-native) 22 | > 23 | > [markdown: 0.5.0](https://github.com/evilstreak/markdown-js) 24 | > 25 | > [async: 0.2.9](https://github.com/caolan/async) 26 | > 27 | > [moment: 2.4.0](http://momentjs.com/) 28 | > 29 | > [gm: 1.13.3](https://github.com/aheckmann/gm) 30 | 31 | ##文档 32 | 33 | ### 模型层 34 | > [公用数据库连接层](https://github.com/LingyuCoder/Blog/wiki/%E5%85%AC%E7%94%A8%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E5%B1%82-%5BCommonDAO.js%5D) 35 | 36 | > [文章](https://github.com/LingyuCoder/Blog/wiki/%E6%96%87%E7%AB%A0-%5BArticle%5D) 37 | 38 | > [用户](https://github.com/LingyuCoder/Blog/wiki/%E7%94%A8%E6%88%B7-%5BUser%5D) 39 | 40 | > [评论](https://github.com/LingyuCoder/Blog/wiki/%E8%AF%84%E8%AE%BA%5BComment%5D) 41 | 42 | > [书签](https://github.com/LingyuCoder/Blog/wiki/%E4%B9%A6%E7%AD%BE-%5BBookmark%5D) 43 | 44 | > [点赞(施工中)]() 45 | 46 | > [标签(施工中)]() 47 | 48 | ### 控制层(施工中) 49 | 50 | ### 表示层(施工中) -------------------------------------------------------------------------------- /doc/user.md: -------------------------------------------------------------------------------- 1 | 用户 [User] 2 | === 3 | *** 4 | #构造函数 5 | ```js 6 | function User(user) { 7 | this.username = user.username; 8 | this.nickname = user.nickname; 9 | this.password = user.password; 10 | this.owner = user.owner; 11 | this.avatar = user.avatar; 12 | this.tags = user.tags; 13 | } 14 | ``` 15 | # 属性 16 | *** 17 | > **username** [string] : 用户名,需手动保持唯一 18 | 19 | > **nickname** [string] : 用户昵称 20 | 21 | > **password** [string] : 用户密码 22 | 23 | > **owner** [boolean] : 用户是否为博客管理员 24 | 25 | > **avatar** [string] : 用户头像的url 26 | 27 | > **tags** [array:string] : 用户的标签列表,元素为标签的id 28 | 29 | # 原型上的方法 30 | *** 31 | ## save 32 | ### 说明 33 | > 保存当前用户 34 | 35 | ### 参数 36 | > **callback** [function] : 保存完成后的回调函数,两个参数 37 | 38 | >> **err** [object]: 若未发生错误,为null 39 | 40 | >> **result** [Article] :持久化后的User对象 41 | 42 | ### 实例 43 | ```js 44 | var user = new User({ 45 | username: req.body.username, 46 | password: req.body.password, 47 | nickname: req.body.nickname, 48 | avatar: "/images/default_avatar.jpg", 49 | owner: false, 50 | tags: [] 51 | }); 52 | user.save(function(err) { 53 | if (err) { 54 | return res.render("regist", { 55 | message: "发生错误,请稍后重试..." 56 | }); 57 | } else { 58 | req.session.user = user; 59 | res.redirect("/index"); 60 | } 61 | }); 62 | ``` 63 | ## update 64 | ### 说明 65 | > 更新当前用户 66 | 67 | ### 参数 68 | > **callback** [function] : 更新完成后的回调函数,一个参数 69 | 70 | >> **err** [object]: 若未发生错误,为null 71 | 72 | ### 实例 73 | ```js 74 | user.update(function(err) { 75 | req.session.user = user; 76 | res.render("userDetail", { 77 | user: req.session.user, 78 | success: true, 79 | message: "修改成功..." 80 | }); 81 | }); 82 | ``` 83 | ## remove 84 | ### 说明 85 | > 删除当前用户 86 | 87 | ### 参数 88 | > **callback** [function] : 删除完成后的回调函数,一个参数 89 | 90 | >> **err** [object]: 若未发生错误,为null 91 | 92 | 93 | ### 实例 94 | ```js 95 | user.remove(function(err) { 96 | if(err){ 97 | return res.render("error", { 98 | message: err.message 99 | }); 100 | } 101 | //do something after removing 102 | }); 103 | ``` 104 | # 方法 105 | *** 106 | ## get 107 | ### 说明 108 | > 根据用户的用户名,获取用户详细信息 109 | 110 | ### 参数 111 | > **username** [string] : 需要获取的用户的id 112 | 113 | > **callback** [function] : 获取完成后的回调函数,两个参数 114 | 115 | >> **err** [object]: 若未发生错误,为null 116 | 117 | >> **user** [User] : 该用户对象,没有则为null 118 | 119 | 120 | ### 实例 121 | ```js 122 | User.get(req.body.username, function(err, user) { 123 | if (err) return res.render("error", { 124 | message: err.message 125 | }); 126 | res.json({ 127 | username: user.username, 128 | nickname: user.nickname, 129 | owner: user.owner, 130 | tags: user.tags, 131 | avatar: user.avatar 132 | }); 133 | }); 134 | ``` 135 | 136 | ## countAll 137 | ### 说明 138 | > 统计系统中所有用户个数 139 | 140 | ### 参数 141 | > **callback** [function] : 删除完成后的回调函数,两个参数 142 | 143 | >> **err** [object]: 若未发生错误,为null 144 | 145 | >> **total** [number] : 系统中的用户总数 146 | 147 | 148 | ### 实例 149 | ```js 150 | User.count(function(err, total) { 151 | if(err) return res.json(500); 152 | return res.json({ 153 | total: total 154 | }); 155 | }); 156 | ``` 157 | ## getAll 158 | ### 说明 159 | > 分页获取系统中所有用户 160 | 161 | ### 参数 162 | > **curPage** [integer] : 当前页,从0开始 163 | 164 | > **perPage** [integer] : 每页用户个数 165 | 166 | > **callback** [function] : 删除完成后的回调函数,两个参数 167 | 168 | >> **err** [object]: 若未发生错误,为null 169 | 170 | >> **users** [array:User] : 获取的用户对象数组 171 | 172 | 173 | ### 实例 174 | ```js 175 | User.getAll(1, 10, function(err, useres) { 176 | if(err) return res.render("error"); 177 | return res.render("showUsers",{ 178 | useres: useres 179 | }); 180 | }); 181 | ``` 182 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myblog", 3 | "version": "0.0.1-31", 4 | "private": true, 5 | "scripts": { 6 | "start": "node app.js" 7 | }, 8 | "dependencies": { 9 | "express": "3.4.2", 10 | "jade": "*", 11 | "node-uuid": "1.4.1", 12 | "mongodb": "1.3.19", 13 | "markdown": "0.5.0", 14 | "async": "0.2.9", 15 | "moment": "2.4.0", 16 | "gm": "1.13.3", 17 | "ws": "0.4.31" 18 | }, 19 | "subdomain": "skyinlayer", 20 | "engines": { 21 | "node": "0.10.x" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /public/404/404.css: -------------------------------------------------------------------------------- 1 | .main { 2 | position: absolute; 3 | width: 800px; 4 | height: 500px; 5 | margin-top:100px; 6 | left: 50%; 7 | margin-left: -400px; 8 | background-image: -webkit-linear-gradient(top, #5CC9FC, #FFFFFF); 9 | border-radius: 10px; 10 | overflow: hidden; 11 | box-shadow : 5px 5px 6px #525252; 12 | 13 | } 14 | 15 | .clouds { 16 | position: absolute; 17 | -webkit-animation: cloud_move 20s linear infinite; 18 | } 19 | 20 | .clouds .cloud { 21 | position: absolute; 22 | background-image: url("cloud.png"); 23 | background-position: center; 24 | background-repeat: no-repeat; 25 | } 26 | 27 | .clouds .cloud-sm{ 28 | width: 223px; 29 | height: 98px; 30 | background-size: 223px 78px; 31 | } 32 | 33 | .clouds .cloud-md{ 34 | width: 335px; 35 | height: 147px; 36 | background-size: 335px 147px; 37 | } 38 | 39 | .clouds .cloud-lg{ 40 | width: 670px; 41 | height: 294px; 42 | background-size: 670px 294px; 43 | } 44 | 45 | .boat { 46 | position: absolute; 47 | width: 100%; 48 | height: 100%; 49 | -webkit-animation: boat_shake 5s linear infinite; 50 | } 51 | 52 | .boat .boat-body{ 53 | position: absolute; 54 | bottom: 20px; 55 | background-position: center; 56 | background-repeat: no-repeat; 57 | background-image: url(boat.png); 58 | width: 384px; 59 | height: 354px; 60 | -webkit-transform: scaleX(-1); 61 | } 62 | 63 | .wave { 64 | position: absolute; 65 | width: 900px; 66 | bottom: -20px; 67 | left: -50px; 68 | } 69 | 70 | .wave-front { 71 | height: 120px; 72 | background-image: url(wave-front.png); 73 | -webkit-animation: wave_shake 6s linear infinite; 74 | } 75 | 76 | .wave-back { 77 | height: 125px; 78 | background-image: url(wave-back.png); 79 | -webkit-animation: wave_shake 6s linear 3s infinite; 80 | } 81 | 82 | .message { 83 | position: absolute; 84 | left: 450px; 85 | top: 100px; 86 | width: 300px; 87 | height: 200px; 88 | text-align: center; 89 | font-family: "Microsoft YaHei"; 90 | font-weight: bolder; 91 | color: rgb(109, 109, 109); 92 | text-shadow : 2px 2px 2px #ACACAC; 93 | } 94 | 95 | .message .code { 96 | font-size: 80px; 97 | } 98 | 99 | /* .message .code span:hover { 100 | display: block; 101 | -webkit-transform: rotate(90deg); 102 | -webkit-transform-origin: 20% 47%; 103 | -webkit-animation: error_code_down 2s ease-in-out 1; 104 | } */ 105 | 106 | .message .content { 107 | font-size: 40px; 108 | } 109 | @-webkit-keyframes error_code_down { 110 | from { 111 | -webkit-transform: rotate(0deg); 112 | } 113 | to { 114 | -webkit-transform: rotate(90deg); 115 | } 116 | } 117 | 118 | @-webkit-keyframes wave_shake { 119 | 0% { 120 | -webkit-transform: translate(0px, 0px); 121 | } 122 | 25% { 123 | -webkit-transform: translate(5px, 5px); 124 | } 125 | 75% { 126 | -webkit-transform: translate(0px, 5px); 127 | } 128 | 100% { 129 | -webkit-transform: translate(0px, 0px); 130 | } 131 | } 132 | 133 | @-webkit-keyframes cloud_move { 134 | from { 135 | left: -800px; 136 | } 137 | to { 138 | left: 0px; 139 | } 140 | } 141 | 142 | @-webkit-keyframes boat_shake { 143 | 0% { 144 | -webkit-transform: translate(0px, 0px); 145 | } 146 | 25% { 147 | -webkit-transform: translate(-10px, -10px); 148 | } 149 | 75% { 150 | -webkit-transform: translate(0px, -10px); 151 | } 152 | 100% { 153 | -webkit-transform: translate(0px, 0px); 154 | } 155 | } -------------------------------------------------------------------------------- /public/404/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |" + data.nick + "(" + data.time + "): " + data.message + "
"); 25 | } else if (data.type === "join") { 26 | if ($("p[uid='" + data.uid + "']", $users).length === 0) { 27 | $users.append("" + data.nick + "
"); 28 | $logs.append(")?/gi, function(match, pre) {
14 | if (pre) {
15 | return '';
16 | } else {
17 | return '';
18 | }
19 | });
20 | }}
21 | ];
22 | };
23 |
24 | // Client-side export
25 | if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.prettify = prettify; }
26 | // Server-side export
27 | if (typeof module !== 'undefined') module.exports = prettify;
28 |
29 | }());
30 |
--------------------------------------------------------------------------------
/public/javascripts/tools/showdown_extensions/table.js:
--------------------------------------------------------------------------------
1 | /*global module:true*/
2 | /*
3 | * Basic table support with re-entrant parsing, where cell content
4 | * can also specify markdown.
5 | *
6 | * Tables
7 | * ======
8 | *
9 | * | Col 1 | Col 2 |
10 | * |======== |====================================================|
11 | * |**bold** | ![Valid XHTML] (http://w3.org/Icons/valid-xhtml10) |
12 | * | Plain | Value |
13 | *
14 | */
15 |
16 | (function(){
17 | var table = function(converter) {
18 | var tables = {}, style = 'text-align:left;', filter;
19 | tables.th = function(header){
20 | if (header.trim() === "") { return "";}
21 | var id = header.trim().replace(/ /g, '_').toLowerCase();
22 | return '' + header + ' ';
23 | };
24 | tables.td = function(cell) {
25 | return '' + converter.makeHtml(cell) + ' ';
26 | };
27 | tables.ths = function(){
28 | var out = "", i = 0, hs = [].slice.apply(arguments);
29 | for (i;i\n";
45 | out += tables.ths.apply(this, hs);
46 | out += "\n";
47 | out += "\n";
48 | return out;
49 | };
50 | tables.tr = function() {
51 | var out, i = 0, cs = [].slice.apply(arguments);
52 | out = "\n";
53 | out += tables.tds.apply(this, cs);
54 | out += " \n";
55 | return out;
56 | };
57 | filter = function(text) {
58 | var i=0, lines = text.split('\n'), tbl = [], line, hs, rows, out = [];
59 | for (i; i');
65 | hs = line.substring(1, line.length -1).split('|');
66 | tbl.push(tables.thead.apply(this, hs));
67 | line = lines[++i];
68 | if (!line.trim().match(/^[|]{1}[-=| ]+[|]{1}$/)) {
69 | // not a table rolling back
70 | line = lines[--i];
71 | }
72 | else {
73 | line = lines[++i];
74 | tbl.push('');
75 | while (line.trim().match(/^[|]{1}.*[|]{1}$/)) {
76 | line = line.trim();
77 | tbl.push(tables.tr.apply(this, line.substring(1, line.length -1).split('|')));
78 | line = lines[++i];
79 | }
80 | tbl.push('');
81 | tbl.push('');
82 | // we are done with this table and we move along
83 | out.push(tbl.join('\n'));
84 | continue;
85 | }
86 | }
87 | out.push(line);
88 | }
89 | return out.join('\n');
90 | };
91 | return [
92 | {
93 | type: 'lang',
94 | filter: filter
95 | }
96 | ];
97 | };
98 |
99 | // Client-side export
100 | if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.table = table; }
101 | // Server-side export
102 | if (typeof module !== 'undefined') {
103 | module.exports = table;
104 | }
105 | }());
106 |
--------------------------------------------------------------------------------
/public/javascripts/tools/showdown_extensions/twitter.js:
--------------------------------------------------------------------------------
1 | //
2 | // Twitter Extension
3 | // @username -> @username
4 | // #hashtag -> #hashtag
5 | //
6 |
7 | (function(){
8 |
9 | var twitter = function(converter) {
10 | return [
11 |
12 | // @username syntax
13 | { type: 'lang', regex: '\\B(\\\\)?@([\\S]+)\\b', replace: function(match, leadingSlash, username) {
14 | // Check if we matched the leading \ and return nothing changed if so
15 | if (leadingSlash === '\\') {
16 | return match;
17 | } else {
18 | return '@' + username + '';
19 | }
20 | }},
21 |
22 | // #hashtag syntax
23 | { type: 'lang', regex: '\\B(\\\\)?#([\\S]+)\\b', replace: function(match, leadingSlash, tag) {
24 | // Check if we matched the leading \ and return nothing changed if so
25 | if (leadingSlash === '\\') {
26 | return match;
27 | } else {
28 | return '#' + tag + '';
29 | }
30 | }},
31 |
32 | // Escaped @'s
33 | { type: 'lang', regex: '\\\\@', replace: '@' }
34 | ];
35 | };
36 |
37 | // Client-side export
38 | if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.twitter = twitter; }
39 | // Server-side export
40 | if (typeof module !== 'undefined') module.exports = twitter;
41 |
42 | }());
43 |
--------------------------------------------------------------------------------
/public/stylesheets/github.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | github.com style (c) Vasily Polovnyov
4 |
5 | */
6 |
7 | pre code {
8 | display: block; padding: 0.5em;
9 | color: #333;
10 | background: #f8f8ff
11 | }
12 |
13 | pre .comment,
14 | pre .template_comment,
15 | pre .diff .header,
16 | pre .javadoc {
17 | color: #998;
18 | font-style: italic
19 | }
20 |
21 | pre .keyword,
22 | pre .css .rule .keyword,
23 | pre .winutils,
24 | pre .javascript .title,
25 | pre .nginx .title,
26 | pre .subst,
27 | pre .request,
28 | pre .status {
29 | color: #333;
30 | font-weight: bold
31 | }
32 |
33 | pre .number,
34 | pre .hexcolor,
35 | pre .ruby .constant {
36 | color: #099;
37 | }
38 |
39 | pre .string,
40 | pre .tag .value,
41 | pre .phpdoc,
42 | pre .tex .formula {
43 | color: #d14
44 | }
45 |
46 | pre .title,
47 | pre .id,
48 | pre .coffeescript .params,
49 | pre .scss .preprocessor {
50 | color: #900;
51 | font-weight: bold
52 | }
53 |
54 | pre .javascript .title,
55 | pre .lisp .title,
56 | pre .clojure .title,
57 | pre .subst {
58 | font-weight: normal
59 | }
60 |
61 | pre .class .title,
62 | pre .haskell .type,
63 | pre .vhdl .literal,
64 | pre .tex .command {
65 | color: #458;
66 | font-weight: bold
67 | }
68 |
69 | pre .tag,
70 | pre .tag .title,
71 | pre .rules .property,
72 | pre .django .tag .keyword {
73 | color: #000080;
74 | font-weight: normal
75 | }
76 |
77 | pre .attribute,
78 | pre .variable,
79 | pre .lisp .body {
80 | color: #008080
81 | }
82 |
83 | pre .regexp {
84 | color: #009926
85 | }
86 |
87 | pre .class {
88 | color: #458;
89 | font-weight: bold
90 | }
91 |
92 | pre .symbol,
93 | pre .ruby .symbol .string,
94 | pre .lisp .keyword,
95 | pre .tex .special,
96 | pre .prompt {
97 | color: #990073
98 | }
99 |
100 | pre .built_in,
101 | pre .lisp .title,
102 | pre .clojure .built_in {
103 | color: #0086b3
104 | }
105 |
106 | pre .preprocessor,
107 | pre .pi,
108 | pre .doctype,
109 | pre .shebang,
110 | pre .cdata {
111 | color: #999;
112 | font-weight: bold
113 | }
114 |
115 | pre .deletion {
116 | background: #fdd
117 | }
118 |
119 | pre .addition {
120 | background: #dfd
121 | }
122 |
123 | pre .diff .change {
124 | background: #0086b3
125 | }
126 |
127 | pre .chunk {
128 | color: #aaa
129 | }
130 |
--------------------------------------------------------------------------------
/public/stylesheets/monokai.css:
--------------------------------------------------------------------------------
1 | /*
2 | Monokai style - ported by Luigi Maselli - http://grigio.org
3 | */
4 |
5 | pre code {
6 | display: block; padding: 0.5em;
7 | background: #272822;
8 | }
9 |
10 | pre .tag,
11 | pre .tag .title,
12 | pre .keyword,
13 | pre .literal,
14 | pre .strong,
15 | pre .change,
16 | pre .winutils,
17 | pre .flow,
18 | pre .lisp .title,
19 | pre .clojure .built_in,
20 | pre .nginx .title,
21 | pre .tex .special {
22 | color: #F92672;
23 | }
24 |
25 | pre code {
26 | color: #DDD;
27 | }
28 |
29 | pre code .constant {
30 | color: #66D9EF;
31 | }
32 |
33 | pre .code,
34 | pre .class .title,
35 | pre .header {
36 | color: white;
37 | }
38 |
39 | pre .link_label,
40 | pre .attribute,
41 | pre .symbol,
42 | pre .symbol .string,
43 | pre .value,
44 | pre .regexp {
45 | color: #BF79DB;
46 | }
47 |
48 | pre .link_url,
49 | pre .tag .value,
50 | pre .string,
51 | pre .bullet,
52 | pre .subst,
53 | pre .title,
54 | pre .emphasis,
55 | pre .haskell .type,
56 | pre .preprocessor,
57 | pre .ruby .class .parent,
58 | pre .built_in,
59 | pre .sql .aggregate,
60 | pre .django .template_tag,
61 | pre .django .variable,
62 | pre .smalltalk .class,
63 | pre .javadoc,
64 | pre .django .filter .argument,
65 | pre .smalltalk .localvars,
66 | pre .smalltalk .array,
67 | pre .attr_selector,
68 | pre .pseudo,
69 | pre .addition,
70 | pre .stream,
71 | pre .envvar,
72 | pre .apache .tag,
73 | pre .apache .cbracket,
74 | pre .tex .command,
75 | pre .prompt {
76 | color: #A6E22E;
77 | }
78 |
79 | pre .comment,
80 | pre .java .annotation,
81 | pre .blockquote,
82 | pre .horizontal_rule,
83 | pre .python .decorator,
84 | pre .template_comment,
85 | pre .pi,
86 | pre .doctype,
87 | pre .deletion,
88 | pre .shebang,
89 | pre .apache .sqbracket,
90 | pre .tex .formula {
91 | color: #75715E;
92 | }
93 |
94 | pre .keyword,
95 | pre .literal,
96 | pre .css .id,
97 | pre .phpdoc,
98 | pre .title,
99 | pre .header,
100 | pre .haskell .type,
101 | pre .vbscript .built_in,
102 | pre .sql .aggregate,
103 | pre .rsl .built_in,
104 | pre .smalltalk .class,
105 | pre .diff .header,
106 | pre .chunk,
107 | pre .winutils,
108 | pre .bash .variable,
109 | pre .apache .tag,
110 | pre .tex .special,
111 | pre .request,
112 | pre .status {
113 | font-weight: bold;
114 | }
115 |
116 | pre .coffeescript .javascript,
117 | pre .javascript .xml,
118 | pre .tex .formula,
119 | pre .xml .javascript,
120 | pre .xml .vbscript,
121 | pre .xml .css,
122 | pre .xml .cdata {
123 | opacity: 0.5;
124 | }
125 |
--------------------------------------------------------------------------------
/public/stylesheets/page/admire.css:
--------------------------------------------------------------------------------
1 | .admired{
2 | background-color: #f0f0f0
3 | }
4 |
5 | .b-admire-loading {
6 | background: url("/images/loading.gif") no-repeat;
7 | background-position: center;
8 | min-height: 32px;
9 | min-width: 32px
10 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/articleDetail.css:
--------------------------------------------------------------------------------
1 | @media (max-width: 992px) {
2 | div.g-art .g-art-body {
3 | width: 100%;
4 | }
5 | }
6 |
7 | .u-flag {
8 | position: relative;
9 | left : -50px;
10 | height: 60px;
11 | margin-bottom: 30px;
12 | }
13 |
14 | .u-flag .u-flag-left {
15 | min-width: 300px;
16 | max-width: 1000px;
17 | height: 60px;
18 | position: absolute;
19 | padding: 0 20px;
20 | background-color: #d9534f;
21 | text-align: center;
22 | color: white;
23 | }
24 |
25 | .u-flag .u-flag-left h3{
26 | text-overflow: ellipsis;
27 | white-space : nowrap;
28 | overflow: hidden;
29 | }
30 |
31 | .u-flag .u-flag-left:before {
32 | position: absolute;
33 | display: block;
34 | content : "";
35 | right: -30px;
36 | border-bottom : 30px solid #d9534f;
37 | border-top : 30px solid #d9534f;
38 | border-right : 30px solid transparent;
39 | }
40 |
41 | .u-flag .u-flag-left:after {
42 | position: absolute;
43 | display: block;
44 | content : "";
45 | width : 60px;
46 | height: 30px;
47 | left : -15px;
48 | top: 21px;
49 | background-color: #ac2925;
50 | -webkit-transform : rotate(90deg) skew(-20deg);
51 | -moz-transform : rotate(90deg) skew(-20deg);
52 | transform : rotate(90deg) skew(-20deg);
53 | z-index: -1;
54 | }
55 |
56 | .g-art-footer .u-bookmark {
57 | float:right;
58 | }
59 |
60 | .u-more {
61 | width: 100%;
62 | background-color: #f0f0f0;
63 | text-align: center;
64 | padding: 10px;
65 | border-bottom-right-radius: 20px;
66 | border-bottom-left-radius: 20px;
67 | cursor: pointer;
68 | }
69 |
70 | .u-more:hover {
71 | background-color: rgb(66, 139, 202);
72 | color: white;
73 | }
74 |
75 | .g-reply-form {
76 | display: none;
77 | margin-left: 100px;
78 | margin-top:30px;
79 | }
80 |
81 | .g-art {
82 | width: 100%;
83 | margin-top: 40px;
84 | }
85 |
86 | .g-art:after {
87 | display: table;
88 | clear: both;
89 | content: "";
90 | }
91 |
92 | .g-art .g-art-body {
93 | float: left;
94 | width: 73%;
95 | }
96 |
97 | .g-art .g-art-info {
98 | float: right;
99 | width: 25%;
100 | }
101 |
102 | .g-art .g-art-info .g-user .u-avatar{
103 | float: right;
104 | width: 33%;
105 | }
106 |
107 | .g-art .g-art-info .g-user .u-nick{
108 | float: left;
109 | width: 66%;
110 | margin-top: 20px;
111 |
112 | text-align: center;
113 | font-weight: bolder;
114 | font-size: 150%;
115 | }
116 |
117 | .g-art .g-art-info .u-time {
118 | margin-top: 20px;
119 | text-align: center;
120 | font-weight: bolder;
121 | font-size: 120%;
122 | }
123 |
124 | .g-art .g-art-info .u-tags {
125 | margin-top: 20px;
126 | }
127 |
128 |
--------------------------------------------------------------------------------
/public/stylesheets/page/bookmark.css:
--------------------------------------------------------------------------------
1 | .b-bookmark-loading {
2 | background: url("/images/loading.gif") no-repeat;
3 | background-position: center;
4 | min-height: 32px;
5 | min-width: 32px
6 | }
7 |
8 | .u-bookmark {
9 | padding : 5px 10px;
10 | border-radius: 10px;
11 | cursor: pointer;
12 | }
13 |
14 | .b-bookmark-booked {
15 | background-color: #f0f0f0;
16 | }
17 |
18 | .b-bookmark-book:hover{
19 | background-color: #f0f0f0;
20 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/comment.css:
--------------------------------------------------------------------------------
1 | .b-comment-loading {
2 | background: url("/images/loading.gif") no-repeat;
3 | background-position: center;
4 | min-height: 32px;
5 | min-width: 32px;
6 | }
7 |
8 | .g-comment-row {
9 | width : 100%;
10 | }
11 |
12 | .g-comment-row .g-info {
13 | display: block;
14 | height: 30px;
15 | margin-left : 100px;
16 | line-height: 30px;
17 | }
18 |
19 | .g-comment-row .g-info .u-nick{
20 | margin-right: 20px;
21 | font-weight : bolder;
22 | font-size: large
23 | }
24 |
25 | .g-comment-row .g-info .u-time{
26 | float:right;
27 | }
28 |
29 | .g-comment-row .u-content {
30 | display: block;
31 | margin-left : 100px;
32 | margin-top : 10px;
33 | font-size: large
34 | }
35 |
36 | .g-comment-row .u-avatar {
37 | float: left;
38 | }
39 |
40 | .g-comment-row .g-operate {
41 | margin-left: 100px;
42 | }
43 |
44 | .g-comment-row .g-operate:after {
45 | display: table;
46 | content: '';
47 | clear: both;
48 | }
49 |
50 | .g-comment-row .u-opt {
51 | float:right;
52 | margin-left : 10px;
53 | line-height: 14px;
54 | padding : 4px 6px;
55 | border-radius: 4px;
56 | cursor : pointer;
57 | }
58 |
59 | .g-comment-row .u-opt:hover {
60 | background-color: #f0f0f0;
61 | }
62 |
63 | .g-comment-row .admired {
64 | background-color: #f0f0f0;
65 | }
66 |
67 | .g-comment-row .u-opt span{
68 | margin-left : 5px;
69 | }
70 |
71 | .b-comment-reply {
72 | background: #f4f4f4;
73 | padding: 10px 20px;
74 | border-radius: 20px;
75 | margin-bottom: 20px;
76 | border: 2px dashed #8F8F8F;
77 | }
78 |
79 | .u-comment-count {
80 | cursor: pointer;
81 | }
82 |
83 | .u-comment-count a:hover {
84 | color:#333;
85 | }
86 |
87 | .u-comment-count a {
88 | color:#333;
89 | text-decoration: none
90 | }
91 |
92 | .a-comment-reply:hover {
93 | -webkit-animation: borderchange 1s infinite;
94 | -moz-animation: borderchange 1s infinite;
95 | animation: borderchange 1s infinite;
96 | }
97 |
98 | @-webkit-keyframes borderchange{
99 | 0% {
100 | border: 2px dashed #8F8F8F;
101 | }
102 | 25% {
103 | border: 2px dashed orange;
104 | }
105 | 50% {
106 | border: 2px dashed red;
107 | }
108 | 75% {
109 | border: 2px dashed blue;
110 | }
111 | 100%{
112 | border: 2px dashed #8F8F8F;
113 | }
114 | }
115 |
116 | @-moz-keyframes borderchange{
117 | 0% {
118 | border: 2px dashed #8F8F8F;
119 | }
120 | 25% {
121 | border: 2px dashed orange;
122 | }
123 | 50% {
124 | border: 2px dashed red;
125 | }
126 | 75% {
127 | border: 2px dashed blue;
128 | }
129 | 100%{
130 | border: 2px dashed #8F8F8F;
131 | }
132 | }
133 |
134 | @keyframes borderchange{
135 | 0% {
136 | border: 2px dashed #8F8F8F;
137 | }
138 | 25% {
139 | border: 2px dashed orange;
140 | }
141 | 50% {
142 | border: 2px dashed red;
143 | }
144 | 75% {
145 | border: 2px dashed blue;
146 | }
147 | 100%{
148 | border: 2px dashed #8F8F8F;
149 | }
150 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/gallary.css:
--------------------------------------------------------------------------------
1 | .u-pic {
2 | position: relative;
3 | border: 1px solid #f0f0f0;
4 | box-shadow: 0 0 6px #f0f0f0;
5 | display: block;
6 | cursor: pointer;
7 | }
8 |
9 | .u-pic img {
10 | width: 100%;
11 | }
12 |
13 | .u-pic:hover {
14 | position: relative;
15 | z-index: 100;
16 | -webkit-animation : bigger 1s 1;
17 | -webkit-transform: scale(1.25);
18 | -moz-animation : bigger 1s 1;
19 | -moz-transform: scale(1.25);
20 | animation : bigger 1s 1;
21 | transform: scale(1.25);
22 | }
23 |
24 | @-moz-keyframes bigger { /* firefox */
25 | from {
26 | -moz-transform: scale(1);
27 | }
28 | to {
29 | -moz-transform: scale(1.25);
30 | }
31 | }
32 |
33 | @-webkit-keyframes bigger { /*chrome & safari*/
34 | from {
35 | -webkit-transform: scale(1);
36 | }
37 | to {
38 | -webkit-transform: scale(1.25);
39 | }
40 | }
41 |
42 | @keyframes bigger {
43 | from {
44 | transform: scale(1);
45 | }
46 | to {
47 | transform: scale(1.25);
48 | }
49 | }
50 |
51 |
52 | .scrollFooter {
53 | width: 100%;
54 | border-radius: 10px;
55 | height: 40px;
56 | line-height: 35px;
57 | text-align: center;
58 | background-color: #f0f0f0;
59 | display: none
60 | }
61 |
62 | .g-gal-col {
63 | padding: 0
64 | }
65 |
66 | .u-block {
67 | position: fixed;
68 | width: 100%;
69 | height: 100%;
70 | left : 0;
71 | top : 0;
72 | background-color: rgba(240, 240, 240, 0.7);
73 | z-index: 101;
74 | display: none;
75 | overflow: auto;
76 | }
77 |
78 | .u-fillPic {
79 | position: absolute;
80 | margin-left: 50%;
81 | border: 1px solid #818181;
82 | box-shadow: 3px 3px 8px #818181;
83 | z-index: 200;
84 | display: none;
85 | width: 70%;
86 | left: -35%;
87 | background-color: #f0f0f0;
88 | margin-top : 50px;
89 | }
90 |
91 | .u-fillPic .u-opt {
92 | position : absolute;
93 | width: 36px;
94 | height: 36px;
95 | font-size: 20px;
96 | line-height: 36px;
97 | text-align: center;
98 | background-color: #f5f5f5;
99 | color : #818181;
100 | border: 1px solid #818181;
101 | border-radius: 18px;
102 | box-shadow: 3px 3px 8px #818181;
103 | }
104 |
105 | .u-fillPic .u-opt:hover {
106 | background-color: #818181;
107 | color : white;
108 | }
109 |
110 | .u-close {
111 | top : -16px;
112 | right : -16px;
113 | }
114 |
115 | .u-bigger{
116 | top : 24px;
117 | right : -16px;
118 | }
119 |
120 | .u-smaller{
121 | top : 64px;
122 | right : -16px;
123 | }
124 |
125 | .u-fillPic img{
126 | max-width: 100%;
127 | min-width: 300px;
128 | }
129 |
130 | .u-conf-opt {
131 | position: fixed;
132 | width: 100px;
133 | height: 100px;
134 | text-align: center;
135 | line-height: 85px;
136 | font-size: 60px;
137 | border: 4px dotted #333;
138 | border-radius: 20px;
139 | }
140 |
141 | .u-trash {
142 | right: 10px;
143 | top : 100px;
144 | }
145 |
146 | .u-upload {
147 | left: 10px;
148 | top : 100px;
149 | }
150 |
151 | .b-removing {
152 | width: 100%;
153 | height: 100%;
154 | position: absolute;
155 | background-color: rgba(0,0,0,0.7);
156 | left: 0;
157 | top: 0;
158 | text-align: center;
159 | font-size: 50px;
160 | color: #f0f0f0;
161 | font-weight: bolder;
162 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/index.css:
--------------------------------------------------------------------------------
1 | .u-flag .u-flag-left a{
2 | color : white;
3 | text-decoration: none;
4 | }
5 |
6 | .u-flag .u-flag-left a:hover{
7 | color : #f0f0f0;
8 | }
9 |
10 | .u-flag .u-flag-left a:active{
11 | color : gray;
12 | }
13 |
14 | .g-art-footer .m-tags {
15 | float: left;
16 | width: 60%;
17 | }
18 |
19 | .g-art-footer .u-item {
20 | float:right;
21 | padding : 5px 10px;
22 | border-radius: 10px;
23 | }
24 |
25 | .g-art-footer .u-item span{
26 | margin-left: 5px;
27 | }
28 |
29 | .g-art-footer .u-item:hover{
30 | background-color: #f0f0f0
31 | }
32 |
33 | .g-art-footer .u-booked {
34 | background-color: #f0f0f0
35 | }
36 |
37 | .g-art-info {
38 | height:200px;
39 | float:left;
40 | width: 20%;position:relative
41 | }
42 |
43 | .g-art-info .u-avatar {
44 | position: absolute;
45 | right: 20px;
46 | top: 45px;
47 | }
48 |
49 | .g-art-info .u-time {
50 | position: absolute;
51 | width: 100px;
52 | right: 20px;
53 | top: 120px;
54 | font-weight: bolder;
55 | text-align: right;
56 | }
57 |
58 | .g-art-body {
59 | float:left;
60 | width: 80%;
61 | position:relative;
62 | border-left: 3px solid #757575;
63 | }
64 |
65 | .g-art-body .u-panel {
66 | margin-top: 20px;
67 | min-height:200px;
68 | margin-left: 20px;
69 | cursor: pointer;
70 | }
71 |
72 | .g-art-body .u-panel:before {
73 | content: "";
74 | width: 20px;
75 | height: 20px;
76 | border-top: 20px solid transparent;
77 | border-right: 20px solid rgba(255,255,255,0.8);
78 | border-bottom: 20px solid transparent;
79 | position: absolute;
80 | left: 0px;
81 | top: 55px;
82 | }
83 |
84 | .g-art-body .u-dot {
85 | position: absolute;
86 | width: 12px;
87 | height: 12px;
88 | border-radius: 50%;
89 | background-color: #757575;
90 | left: -7px;
91 | top: 70px;
92 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/listArticle.css:
--------------------------------------------------------------------------------
1 | @media (max-width: 992px){
2 | div.g-row .g-art {
3 | width: 35%;
4 | margin-left: 10%;
5 | }
6 | div.g-row:nth-child(odd) .g-art:nth-child(1) {
7 | margin-left: 0;
8 | }
9 |
10 | div.g-row:nth-child(even) .g-art:nth-child(1) {
11 | margin-left: 10%;
12 | }
13 | }
14 |
15 | .g-arts {
16 | width: 100%;
17 | float: left;
18 | margin-top: 40px;
19 | }
20 |
21 | .g-arts .g-row {
22 | width: 100%;
23 | padding: 40px 0 0 0;
24 | }
25 |
26 | .g-arts .g-row:after {
27 | display: table;
28 | content: "";
29 | clear: both;
30 | }
31 |
32 | .g-row .g-art {
33 | position: relative;
34 | float: left;
35 | width: 22%;
36 |
37 | margin-left: 11%;
38 |
39 | cursor: pointer;
40 | }
41 |
42 | .g-row:nth-child(odd) .g-art:nth-child(1) {
43 | margin-left: 0;
44 | }
45 |
46 | .g-row:nth-child(even) .g-art:nth-child(1) {
47 | margin-left: 11%;
48 | }
49 |
50 | .g-row .g-art .u-time{
51 | position: absolute;
52 | left: 10%;
53 | top: -10px;
54 | height: 20px;
55 | width: 60%;
56 |
57 | border-radius: 10px;
58 | box-shadow: 2px 2px 2px #8A8A8A;
59 |
60 | font-weight: bolder;
61 | background-color: rgba(255,255,255,0.8);
62 | text-align: center;
63 | }
64 |
65 | .g-row .g-art .u-title{
66 | width: 100%;
67 |
68 | word-wrap: break-word;
69 | font-size: 150%;
70 | font-weight: bolder;
71 | text-align: center;
72 | }
73 |
74 | .g-row .g-art .u-avatar{
75 | position: absolute;
76 | right: 10px;
77 | top: -15px;
78 | width: 30px;
79 | height: 30px;
80 |
81 | border-radius: 50%;
82 |
83 | box-shadow: 2px 2px 2px #8A8A8A;
84 | overflow: hidden;
85 | }
86 |
87 | .g-row .g-art .u-avatar img{
88 | width: 100%;
89 | }
90 |
91 | .g-row .g-art:hover {
92 | -webkit-animation: art_rotate 1s linear infinite;
93 | -moz-animation: art_rotate 1s linear infinite;
94 | animation: art_rotate 1s linear infinite;
95 | }
96 |
97 | @-webkit-keyframes art_rotate {
98 | 0% 100% {
99 | -webkit-transform: scale(1);
100 | }
101 | 50% {
102 | -webkit-transform: scale(1.2);
103 | }
104 | }
105 |
106 | @-moz-keyframes art_rotate {
107 | 0% 100% {
108 | -moz-transform: scale(1);
109 | }
110 | 50% {
111 | -moz-transform: scale(1.2);
112 | }
113 | }
114 |
115 | @keyframes art_rotate {
116 | 0% 100% {
117 | transform: scale(1);
118 | }
119 | 50% {
120 | transform: scale(1.2);
121 | }
122 | }
123 |
124 | .u-more {
125 | margin-top:20px;
126 | float: right;
127 | font-weight: bolder;
128 | padding: 10px;
129 | }
130 |
131 | .u-more:hover {
132 | color: white;
133 | background-color: rgb(63, 93, 255);
134 | cursor: pointer;
135 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/remind.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/80e5fba805415f2110a13bb3c1705258b079f744/public/stylesheets/page/remind.css
--------------------------------------------------------------------------------
/public/stylesheets/page/search.css:
--------------------------------------------------------------------------------
1 | .u-more {
2 | width: 100%;
3 | background-color: #428bca;
4 | color:#fff;
5 | text-align: center;
6 | padding: 10px;
7 | border-radius: 20px;
8 | cursor: pointer;
9 | }
10 |
11 | .u-more:hover {
12 | background-color: #8f8f8f;
13 | color: #f0f0f0;
14 | }
15 |
16 | .g-row {
17 | margin: 10px 10px 20px 10px;
18 | padding: 10px;
19 | border: 2px dashed #333;
20 | border-radius: 10px;
21 | color: #333;
22 | cursor: pointer;
23 | }
24 |
25 | .g-row:after {
26 | display: table;
27 | content: "";
28 | clear: both;
29 | }
30 |
31 | .g-row:hover {
32 | background: #f0f0f0
33 | }
34 |
35 |
36 | .g-row .u-avatar {
37 | float: left;
38 | width: 60px;
39 | height: 60px;
40 | }
41 |
42 | .g-row .u-avatar img {
43 | height: 100%;
44 | width: 100%;
45 | border-radius: 50%;
46 | box-shadow: 2px 2px 2px #333
47 | }
48 |
49 | .g-row .u-time {
50 | margin-left: 80px;
51 | width: calc(100% - 80px);
52 |
53 | text-align: right;
54 | font-weight: bolder;
55 | font-size: 120%;
56 | }
57 |
58 | .g-row .u-title {
59 | margin-left: 80px;
60 | margin-bottom: 24px;
61 | width: calc(100% - 80px);
62 |
63 | text-align: center;
64 | font-weight: bolder;
65 | font-size: 180%;
66 | }
67 |
68 | .u-panel {
69 | margin-top: 20px;
70 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/tag.css:
--------------------------------------------------------------------------------
1 | .b-label-1 {
2 | background-color: #428bca
3 | }
4 |
5 | .b-label-2 {
6 | background-color: #5cb85c
7 | }
8 |
9 | .b-label-3 {
10 | background-color: #5cb0de
11 | }
12 |
13 | .b-label-4 {
14 | background-color: #f0ad4e
15 | }
16 |
17 | .b-label-5 {
18 | background-color: #d9543f
19 | }
20 |
21 | .u-label-picker {
22 | cursor: pointer;
23 | margin: 5px;
24 | font-size: 14px
25 | }
26 |
27 | .u-label {
28 | font-size: 15px;
29 | cursor: pointer;
30 | }
31 |
32 | .a-label-rotateX{
33 | margin: 5px;
34 | display: inline-block;
35 | }
36 |
37 | .a-label-rotateX:hover{
38 | -webkit-animation: labelrotatex 1s linear infinite;
39 | -moz-animation: labelrotatex 1s linear infinite;
40 | animation: labelrotatex 1s linear infinite;
41 | }
42 |
43 | @-webkit-keyframes labelrotatex{
44 | from {
45 | -webkit-transform : rotateX(0deg);
46 | }
47 | to {
48 | -webkit-transform : rotateX(360deg);
49 | }
50 | }
51 |
52 | @-moz-keyframes labelrotatex{
53 | from {
54 | -moz-transform : rotateX(0deg);
55 | }
56 | to {
57 | -moz-transform : rotateX(360deg);
58 | }
59 | }
60 |
61 | @keyframes labelrotatex{
62 | from {
63 | transform : rotateX(0deg);
64 | }
65 | to {
66 | transform : rotateX(360deg);
67 | }
68 | }
69 |
70 | .a-label-strike {
71 | -webkit-animation: labelstrike 1s linear 3;
72 | -moz-animation: labelstrike 1s linear 3;
73 | animation: labelstrike 1s linear 3;
74 | }
75 |
76 | @-webkit-keyframes labelstrike{
77 | 0% {
78 | -webkit-transform : scale(1);
79 | }
80 | 50%{
81 | -webkit-transform : scale(1.25);
82 | }
83 | 100% {
84 | -webkit-transform : scale(1);
85 | }
86 | }
87 |
88 | @-moz-keyframes labelstrike{
89 | 0% {
90 | -moz-transform : scale(1);
91 | }
92 | 50%{
93 | -moz-transform : scale(1.25);
94 | }
95 | 100% {
96 | -moz-transform : scale(1);
97 | }
98 | }
99 |
100 | @keyframes labelstrike{
101 | 0% {
102 | transform : scale(1);
103 | }
104 | 50%{
105 | transform : scale(1.25);
106 | }
107 | 100% {
108 | transform : scale(1);
109 | }
110 | }
111 |
112 | .b-label-loading {
113 | background: url("/images/loading.gif") no-repeat;
114 | background-position: center;
115 | min-height: 32px;
116 | min-width: 32px;
117 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/uploadPic.css:
--------------------------------------------------------------------------------
1 | .u-upload {
2 | width: 100%;
3 | border : 2px dashed #bbb;
4 | color : #bbb;
5 | -webkit-border-radius: 5px;
6 | -moz-border-radius: 5px;
7 | padding : 25px;
8 | margin : 50px 0;
9 | text-align: center;
10 | font: 20px bold 'Vollkorn';
11 | }
12 |
13 | .uploadResult {
14 | width: 100%;
15 | height: 50px;
16 | display: none
17 | }
18 |
19 | .g-preview {
20 | position: relative;
21 | height: 300px;
22 | float: left;
23 | }
24 |
25 | .g-preview .u-process {
26 | position: absolute;
27 | width: 100%;
28 | height: 100%;
29 | line-height: 300px;
30 | text-align: center;
31 | font-size: 50px;
32 | text-overflow: clip;
33 | opacity: 0.7;
34 | text-shadow: 0 0 6px #f0f0f0;
35 | }
36 |
37 | .g-preview .u-image {
38 | height: 100%
39 | }
40 |
41 | .g-preview .u-remove {
42 | position: absolute;
43 | right : 0px;
44 | top : 0px;
45 | width: 36px;
46 | height: 36px;
47 | font-size: 20px;
48 | line-height: 36px;
49 | text-align: center;
50 | background-color: #f5f5f5;
51 | color : #818181;
52 | border: 1px solid #818181;
53 | border-radius: 18px;
54 | box-shadow: 3px 3px 8px #818181;
55 | }
56 |
57 | .g-preview .u-remove:hover {
58 | background-color: #818181;
59 | color : white;
60 | }
61 |
62 | .u-output {
63 | width: 100%;
64 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/user.css:
--------------------------------------------------------------------------------
1 | .b-user-loading {
2 | background: url("/images/loading.gif") no-repeat;
3 | background-position: center;
4 | min-height: 32px;
5 | min-width: 32px
6 | }
7 |
8 | .u-user-avatar img {
9 | height: 60px;
10 | width: 60px;
11 | border-radius: 30px;
12 | box-shadow: 0 0 6px #707070
13 | }
14 |
15 | .u-user-tags {
16 | width: 272px;
17 | padding-right: 20px;
18 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/userCenter.css:
--------------------------------------------------------------------------------
1 | .g-hide {
2 | display: none
3 | }
4 |
5 | .g-item {
6 | padding: 5px 10px
7 | }
8 |
9 | .g-item .u-avatar {
10 | float: left;
11 | }
12 | .g-item .g-info {
13 | margin-left : 100px;
14 | height: 30px
15 | }
16 | .g-item .g-info .u-time{
17 | float:left;
18 | }
19 |
20 | .g-item .g-info .u-nick{
21 | font-size: 120%;
22 | font-weight: bolder;
23 | }
24 |
25 | .g-item .g-info .u-opt{
26 | float:right;
27 | padding : 5px 10px;
28 | border-radius: 10px;
29 | color: black;
30 | cursor: pointer;
31 | text-decoration: none
32 | }
33 |
34 | .g-item .g-info .u-opt:hover{
35 | background-color: #f0f0f0
36 | }
37 |
38 | .g-item .u-title {
39 | margin-left : 60px;
40 | text-align: center
41 | }
42 |
43 | .g-item .u-title a{
44 | text-decoration: none;
45 | font-size: 150%
46 | }
47 |
48 | .g-item .u-time {
49 | text-align: right
50 | }
51 |
52 | .g-item .u-content {
53 | margin-left : 100px;
54 | text-align: left;
55 | }
56 |
57 | .u-noitem {
58 | text-align: center
59 | }
60 |
61 | .a-fliker {
62 | display: inline-block;
63 | -webkit-animation: labelfliker 2s infinite;
64 | -moz-animation: labelfliker 2s infinite;
65 | animation: labelfliker 2s infinite;
66 | }
67 |
68 | .u-more {
69 | width: 100%;
70 | background-color: #428bca;
71 | color:#fff;
72 | text-align: center;
73 | padding: 10px;
74 | border-radius: 20px;
75 | cursor: pointer;
76 | }
77 |
78 | .u-more:hover {
79 | background-color: #8f8f8f;
80 | color: #f0f0f0;
81 | }
82 |
83 | @-moz-keyframes labelfliker {
84 | 0% {
85 | -moz-transform : scale(1);
86 | }
87 | 50% {
88 | -moz-transform : scale(1.15);
89 | }
90 | 100% {
91 | -moz-transform : scale(1);
92 | }
93 | }
94 |
95 | @-webkit-keyframes labelfliker {
96 | 0% {
97 | -webkit-transform : scale(1);
98 | }
99 | 50% {
100 | -webkit-transform : scale(1.15);
101 | }
102 | 100% {
103 | -webkit-transform : scale(1);
104 | }
105 | }
106 |
107 | @keyframes labelfliker {
108 | 0% {
109 | transform : scale(1);
110 | }
111 | 50% {
112 | transform : scale(1.15);
113 | }
114 | 100% {
115 | transform : scale(1);
116 | }
117 | }
118 |
119 | .g-row {
120 | width: 100%;
121 | }
122 |
123 | .g-row:after {
124 | display: table;
125 | content: "";
126 | clear: both;
127 | }
128 |
129 | .g-row .g-left {
130 | float: left;
131 | width: 25%;
132 | }
133 |
134 | .g-row .g-right {
135 | float: right;
136 | width: 73%;
137 | }
138 |
139 | .list-group .list-group-item {
140 | background: transparent;
141 | }
142 |
143 | .list-group .list-group-item.active {
144 | background: rgb(66, 139, 202)
145 | }
--------------------------------------------------------------------------------
/public/stylesheets/page/userDetail.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/80e5fba805415f2110a13bb3c1705258b079f744/public/stylesheets/page/userDetail.css
--------------------------------------------------------------------------------
/public/stylesheets/page/writeArticle.css:
--------------------------------------------------------------------------------
1 | .u-panel-body {
2 | margin: 0;
3 | padding: 0;
4 | position: relative;
5 | width: 47.5%;
6 | overflow: auto;
7 | height: 100%;
8 | }
9 |
10 | #leftPanel {
11 | float: left;
12 | left : 1.5%;
13 | }
14 |
15 | #rightPanel {
16 | float: right;
17 | right : 1.5%;
18 | padding: 2px;
19 | }
20 |
21 | #outputArticle {
22 | overflow: auto;
23 | }
24 |
25 | .u-pane {
26 | margin: 0;
27 | padding: 0;
28 | padding-left: 4px;
29 | width: 100%;
30 | border: none;
31 | display: block;
32 | border: 1px solid #888;
33 | border-right: 1px solid #000;
34 | border-bottom: 1px solid #000;
35 | height: 100%;
36 | }
--------------------------------------------------------------------------------
/public/stylesheets/pageTools/admire.css:
--------------------------------------------------------------------------------
1 | .admired{
2 | background-color: #f0f0f0
3 | }
4 |
5 | .b-admire-loading {
6 | background: url("/images/loading.gif") no-repeat;
7 | background-position: center;
8 | min-height: 32px;
9 | min-width: 32px
10 | }
11 |
12 | .g-admire-row {
13 | width: 100%;
14 | font-size: 14px;
15 | }
16 |
17 | .g-admire-row .g-info {
18 | display: block;
19 | height: 30px;
20 | margin-left : 100px;
21 | line-height: 30px;
22 | }
23 |
24 | .g-admire-row .g-info:after {
25 | display: table;
26 | clear: both;
27 | content: "";
28 | }
29 |
30 | .g-admire-row .g-info .u-nick{
31 | float: left;
32 | width: 50%;
33 | font-weight : bolder;
34 | font-size: large
35 | }
36 |
37 | .g-admire-row .g-info .u-time{
38 | float:right;
39 | width: 50%;
40 | text-align: right
41 | }
42 |
43 | .g-admire-row .u-comment {
44 | display: block;
45 | margin-left : 100px;
46 | margin-top : 10px;
47 | font-size: large;
48 | border: 2px dashed #8F8F8F;
49 | border-radius: 20px;
50 | padding: 10px;
51 | margin-bottom: 10px
52 | }
53 |
54 | .g-admire-row .u-avatar {
55 | float: left;
56 | }
57 |
58 | .g-admire-row .g-operate {
59 | margin-left: 100px;
60 | height: 25px;
61 | }
62 |
63 | .g-admire-row .g-operate:after {
64 | display: table;
65 | content: '';
66 | clear: both;
67 | }
68 |
69 | .g-admire-row .u-opt {
70 | float:right;
71 | margin-left : 10px;
72 | line-height: 14px;
73 | padding : 4px 6px;
74 | border-radius: 4px;
75 | cursor : pointer;
76 | }
77 |
78 | .g-admire-row .u-opt:hover {
79 | background-color: #f0f0f0;
80 | }
81 |
82 | .g-admire-row .u-opt{
83 | text-decoration: none;
84 | color:#333;
85 | }
86 |
--------------------------------------------------------------------------------
/public/stylesheets/pageTools/article.css:
--------------------------------------------------------------------------------
1 | .b-article-loading {
2 | background: url("/images/loading.gif") no-repeat;
3 | background-position: center;
4 | min-height: 32px;
5 | min-width: 32px
6 | }
7 |
8 | .g-article-row {
9 | width: 100%;
10 | font-size: 14px;
11 | }
12 |
13 | .g-article-row .g-info {
14 | display: block;
15 | height: 30px;
16 | margin-left : 100px;
17 | line-height: 30px;
18 | }
19 |
20 | .g-article-row .g-info .u-nick{
21 | margin-right: 20px;
22 | font-weight : bolder;
23 | font-size: large
24 | }
25 |
26 | .g-article-row .g-info .u-time{
27 | float:right;
28 | }
29 |
30 | .g-article-row .u-title {
31 | display: block;
32 | margin-left : 100px;
33 | margin-top : 10px;
34 | font-size: 150%;
35 | font-weight: bolder;
36 | text-align: center;
37 | margin-bottom: 10px
38 | }
39 |
40 | .g-article-row .u-avatar {
41 | float: left;
42 | }
43 |
44 | .g-article-row .g-operate {
45 | margin-left: 100px;
46 | height: 25px;
47 | }
48 |
49 | .g-article-row .g-operate:after {
50 | display: table;
51 | content: '';
52 | clear: both;
53 | }
54 |
55 | .g-article-row .u-opt {
56 | float:right;
57 | margin-left : 10px;
58 | line-height: 14px;
59 | padding : 4px 6px;
60 | border-radius: 4px;
61 | cursor : pointer;
62 | }
63 |
64 | .g-article-row .u-opt:hover {
65 | background-color: #f0f0f0;
66 | }
67 |
68 | .g-article-row .u-opt{
69 | text-decoration: none;
70 | color:#333;
71 | }
--------------------------------------------------------------------------------
/public/stylesheets/pageTools/bookmark.css:
--------------------------------------------------------------------------------
1 | .b-bookmark-loading {
2 | background: url("/images/loading.gif") no-repeat;
3 | background-position: center;
4 | min-height: 32px;
5 | min-width: 32px
6 | }
7 |
8 | .u-bookmark {
9 | padding : 5px 10px;
10 | border-radius: 10px;
11 | cursor: pointer;
12 | }
13 |
14 | .b-bookmark-booked, .b-bookmark-book:hover {
15 | background-color: rgba(66, 139, 202, 0.7);
16 | color: white;
17 | }
18 |
19 | .g-bookmark-row {
20 | width: 100%;
21 | font-size: 14px;
22 | }
23 |
24 | .g-bookmark-row .g-info {
25 | display: block;
26 | height: 30px;
27 | margin-left : 100px;
28 | line-height: 30px;
29 | }
30 |
31 | .g-bookmark-row .g-info:after {
32 | display: table;
33 | clear: both;
34 | content: "";
35 | }
36 |
37 | .g-bookmark-row .g-info .u-nick{
38 | float: left;
39 | width: 50%;
40 | font-weight : bolder;
41 | font-size: large
42 | }
43 |
44 | .g-bookmark-row .g-info .u-time{
45 | float:right;
46 | width: 50%;
47 | text-align: right
48 | }
49 |
50 | .g-bookmark-row .u-comment {
51 | display: block;
52 | margin-left : 100px;
53 | margin-top : 10px;
54 | font-size: large;
55 | border: 2px dashed #8F8F8F;
56 | border-radius: 20px;
57 | padding: 10px;
58 | margin-bottom: 10px
59 | }
60 |
61 | .g-bookmark-row .u-avatar {
62 | float: left;
63 | }
64 |
65 | .g-bookmark-row .g-operate {
66 | margin-left: 100px;
67 | height: 25px;
68 | }
69 |
70 | .g-bookmark-row .g-operate:after {
71 | display: table;
72 | content: '';
73 | clear: both;
74 | }
75 |
76 | .g-bookmark-row .u-opt {
77 | float:right;
78 | margin-left : 10px;
79 | line-height: 14px;
80 | padding : 4px 6px;
81 | border-radius: 4px;
82 | cursor : pointer;
83 | }
84 |
85 | .g-bookmark-row .u-opt:hover {
86 | background-color: #f0f0f0;
87 | }
88 |
89 | .g-bookmark-row .u-opt{
90 | text-decoration: none;
91 | color:#333;
92 | }
--------------------------------------------------------------------------------
/public/stylesheets/pageTools/comment.css:
--------------------------------------------------------------------------------
1 | @media (max-width: 992px) {
2 | div.b-comment-reply {
3 | padding: 5px 10px;
4 | }
5 | }
6 |
7 | .b-comment-loading {
8 | background: url("/images/loading.gif") no-repeat;
9 | background-position: center;
10 | min-height: 32px;
11 | min-width: 32px;
12 | }
13 |
14 | .g-comment-row {
15 | width : 100%;
16 | font-size: 14px;
17 | }
18 |
19 | .g-comment-row .g-info {
20 | display: block;
21 | height: 30px;
22 | margin-left : 100px;
23 | line-height: 30px;
24 | }
25 |
26 | .g-comment-row .g-info:after{
27 | display: table;
28 | content: "";
29 | clear: both;
30 | }
31 |
32 |
33 | .g-comment-row .g-info .u-nick{
34 | float: left;
35 | width: 50%;
36 | font-weight : bolder;
37 | font-size: large
38 | }
39 |
40 | .g-comment-row .g-info .u-time{
41 | width: 50%;
42 | float:right;
43 | text-align: right;
44 | }
45 |
46 | .g-comment-row .u-content {
47 | display: block;
48 | margin-left : 100px;
49 | margin-top : 10px;
50 | font-size: large
51 | }
52 |
53 | .g-comment-row .u-avatar {
54 | float: left;
55 | }
56 |
57 | .g-comment-row .g-operate {
58 | margin-left: 100px;
59 | height: 25px;
60 | }
61 |
62 | .g-comment-row .g-operate:after {
63 | display: table;
64 | content: '';
65 | clear: both;
66 | }
67 |
68 | .g-comment-row .u-opt {
69 | float:right;
70 | margin-left : 10px;
71 | line-height: 14px;
72 | padding : 4px 6px;
73 | border-radius: 4px;
74 | cursor : pointer;
75 | }
76 |
77 | .g-comment-row .u-opt:hover, div.g-comment-row .admired{
78 | background-color: rgba(66, 139, 202, 0.7);
79 | color: white;
80 | }
81 |
82 | .g-comment-row .u-opt{
83 | text-decoration: none;
84 | color:#333;
85 | }
86 |
87 | .g-comment-row .u-opt span{
88 | margin-left : 5px;
89 | }
90 |
91 | .b-comment-reply {
92 | background: #f4f4f4;
93 | padding: 10px 20px;
94 | border-radius: 20px;
95 | margin-bottom: 20px;
96 | border: 2px dashed #8F8F8F;
97 | }
98 |
99 | .u-comment-count {
100 | cursor: pointer;
101 | }
102 |
103 | .u-comment-count a:hover {
104 | color:#333;
105 | }
106 |
107 | .u-comment-count a {
108 | color:#333;
109 | text-decoration: none
110 | }
111 |
112 | .a-comment-reply:hover {
113 | -webkit-animation: borderchange 1s infinite;
114 | -moz-animation: borderchange 1s infinite;
115 | animation: borderchange 1s infinite;
116 | }
117 |
118 | @-webkit-keyframes borderchange{
119 | 0% {
120 | border: 2px dashed #8F8F8F;
121 | }
122 | 25% {
123 | border: 2px dashed orange;
124 | }
125 | 50% {
126 | border: 2px dashed red;
127 | }
128 | 75% {
129 | border: 2px dashed blue;
130 | }
131 | 100%{
132 | border: 2px dashed #8F8F8F;
133 | }
134 | }
135 |
136 | @-moz-keyframes borderchange{
137 | 0% {
138 | border: 2px dashed #8F8F8F;
139 | }
140 | 25% {
141 | border: 2px dashed orange;
142 | }
143 | 50% {
144 | border: 2px dashed red;
145 | }
146 | 75% {
147 | border: 2px dashed blue;
148 | }
149 | 100%{
150 | border: 2px dashed #8F8F8F;
151 | }
152 | }
153 |
154 | @keyframes borderchange{
155 | 0% {
156 | border: 2px dashed #8F8F8F;
157 | }
158 | 25% {
159 | border: 2px dashed orange;
160 | }
161 | 50% {
162 | border: 2px dashed red;
163 | }
164 | 75% {
165 | border: 2px dashed blue;
166 | }
167 | 100%{
168 | border: 2px dashed #8F8F8F;
169 | }
170 | }
--------------------------------------------------------------------------------
/public/stylesheets/pageTools/remind.css:
--------------------------------------------------------------------------------
1 | .b-remind-loading {
2 | background: url("/images/loading.gif") no-repeat;
3 | background-position: center;
4 | min-height: 32px;
5 | min-width: 32px
6 | }
--------------------------------------------------------------------------------
/public/stylesheets/pageTools/tag.css:
--------------------------------------------------------------------------------
1 | .b-label-1 {
2 | background-color: #428bca
3 | }
4 |
5 | .b-label-2 {
6 | background-color: #5cb85c
7 | }
8 |
9 | .b-label-3 {
10 | background-color: #5cb0de
11 | }
12 |
13 | .b-label-4 {
14 | background-color: #f0ad4e
15 | }
16 |
17 | .b-label-5 {
18 | background-color: #d9543f
19 | }
20 |
21 | .u-label-picker {
22 | cursor: pointer;
23 | margin: 5px;
24 | font-size: 14px;
25 | display: inline-block;
26 | }
27 |
28 | .u-label {
29 | font-size: 15px;
30 | height: 23px;
31 | cursor: pointer;
32 | }
33 |
34 | .a-label{
35 | margin: 5px;
36 | display: inline-block;
37 | }
38 |
39 | .a-label:hover{
40 | -webkit-animation: a_label 1s linear infinite;
41 | -moz-animation: a_label 1s linear infinite;
42 | animation: a_label 1s linear infinite;
43 | }
44 |
45 | @-webkit-keyframes a_label{
46 | 0% 100% {
47 | -webkit-transform: scale(1);
48 | }
49 | 50% {
50 | -webkit-transform: scale(1.2);
51 | }
52 | }
53 |
54 | @-moz-keyframes a_label{
55 | 0% 100% {
56 | -moz-transform: scale(1);
57 | }
58 | 50% {
59 | -moz-transform: scale(1.2);
60 | }
61 | }
62 |
63 | @keyframes a_label{
64 | 0% 100% {
65 | transform: scale(1);
66 | }
67 | 50% {
68 | transform: scale(1.2);
69 | }
70 | }
71 |
72 | .a-label-strike {
73 | -webkit-animation: labelstrike 1s linear 3;
74 | -moz-animation: labelstrike 1s linear 3;
75 | animation: labelstrike 1s linear 3;
76 | }
77 |
78 | @-webkit-keyframes labelstrike{
79 | 0% {
80 | -webkit-transform : scale(1);
81 | }
82 | 50%{
83 | -webkit-transform : scale(1.25);
84 | }
85 | 100% {
86 | -webkit-transform : scale(1);
87 | }
88 | }
89 |
90 | @-moz-keyframes labelstrike{
91 | 0% {
92 | -moz-transform : scale(1);
93 | }
94 | 50%{
95 | -moz-transform : scale(1.25);
96 | }
97 | 100% {
98 | -moz-transform : scale(1);
99 | }
100 | }
101 |
102 | @keyframes labelstrike{
103 | 0% {
104 | transform : scale(1);
105 | }
106 | 50%{
107 | transform : scale(1.25);
108 | }
109 | 100% {
110 | transform : scale(1);
111 | }
112 | }
113 |
114 | .b-label-loading {
115 | background: url("/images/loading.gif") no-repeat;
116 | background-position: center;
117 | min-height: 32px;
118 | min-width: 32px;
119 | }
--------------------------------------------------------------------------------
/public/stylesheets/pageTools/user.css:
--------------------------------------------------------------------------------
1 | .b-user-loading {
2 | background: url("/images/loading.gif") no-repeat;
3 | background-position: center;
4 | min-height: 32px;
5 | min-width: 32px
6 | }
7 |
8 | .u-user-avatar img {
9 | height: 60px;
10 | width: 60px;
11 | border-radius: 30px;
12 | box-shadow: 0 0 6px #707070
13 | }
14 |
15 | .u-user-tags {
16 | width: 272px;
17 | padding-right: 20px;
18 | }
--------------------------------------------------------------------------------
/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 14px;
3 | padding-top: 50px;
4 | margin-top:-50px;
5 | font-family: ff-tisa-web-pro-1, ff-tisa-web-pro-2, 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Hiragino Sans GB W3', 'Microsoft YaHei UI', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif;
6 | }
7 |
8 | h1,h2,h3 {
9 | font-family: ff-tisa-web-pro-1, ff-tisa-web-pro-2, 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Hiragino Sans GB W3', 'Microsoft YaHei UI', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif;
10 | }
11 |
12 | .b-loading {
13 | background: url("/images/loading.gif") no-repeat;
14 | background-position: center;
15 | min-height: 32px;
16 | min-width: 32px;
17 | }
18 |
19 |
20 | .footer hr{
21 | border-top: 1px solid #383838;
22 | }
23 |
24 | .footer p{
25 | text-align : center;
26 | font-style : italic;
27 | }
28 |
29 | .b-clouds {
30 | z-index: -1;
31 | position: fixed;
32 | width: 100%;
33 | height: 100%;
34 | background-image: -webkit-linear-gradient(top, #5CC9FC, #FFFFFF);
35 | background-image: -moz-linear-gradient(top, #5CC9FC, #FFFFFF);
36 | background-image: -ms-linear-gradient(top, #5CC9FC, #FFFFFF);
37 | overflow: hidden;
38 | }
39 |
40 | .b-clouds .block {
41 | position: absolute;
42 | background-image: -webkit-linear-gradient(left, #ffffff, transparent, #ffffff);
43 | background-image: -moz-linear-gradient(to right, rgba(255,255,255,1), rgba(255,255,255,0), rgba(255,255,255,1));
44 | background-image: linear-gradient(left, white, transparent, white);
45 | background-image: -ms-linear-gradient(left, #ffffff00, transparent, #ffffff00);
46 | overflow: hidden;
47 | width: 100%;
48 | height: 100%;
49 | }
50 |
51 | .b-clouds .clouds {
52 | position: absolute;
53 | width: 200%;
54 | height: 400px;
55 | /* -webkit-animation: cloud_move 60s linear infinite;
56 | -moz-animation: cloud_move 60s linear infinite; */
57 | }
58 |
59 | .b-clouds .clouds .cloud {
60 | position: absolute;
61 | background-image: url("/images/cloud.png");
62 | background-position: center;
63 | background-repeat: no-repeat;
64 | }
65 |
66 | .b-clouds .clouds .cloud-sm{
67 | width: 223px;
68 | height: 98px;
69 | background-size: 223px 78px;
70 | }
71 |
72 | .b-clouds .clouds .cloud-md{
73 | width: 335px;
74 | height: 147px;
75 | background-size: 335px 147px;
76 | }
77 |
78 | .b-clouds .clouds .cloud-lg{
79 | width: 670px;
80 | height: 294px;
81 | background-size: 670px 294px;
82 | }
83 |
84 | @-webkit-keyframes cloud_move {
85 | from {
86 | left: -100%;
87 | }
88 | to {
89 | left: 0;
90 | }
91 | }
92 |
93 | @-moz-keyframes cloud_move {
94 | from {
95 | left: -100%;
96 | }
97 | to {
98 | left: 0;
99 | }
100 | }
101 |
102 | @-ms-keyframes cloud_move {
103 | from {
104 | left: -100%;
105 | }
106 | to {
107 | left: 0;
108 | }
109 | }
110 |
111 | .scrollToTop {
112 | width: 100px;
113 | height: 100px;
114 | border-radius: 20px;
115 | font-size: 80px;
116 | line-height: 100px;
117 | background-color: #6D6D6D;
118 | color: white;
119 | opacity: 0.5;
120 | text-align: center;
121 | position: fixed;
122 | right: 80px;
123 | bottom: 80px;
124 | padding-right: 5px;
125 | cursor: pointer;
126 | }
127 |
128 | .scrollToTop:hover{
129 | opacity: 1;
130 | }
131 |
132 | .g-main {
133 | margin-top: 50px;
134 | }
135 |
136 | .u-panel {
137 | padding: 20px;
138 | border-radius: 20px;
139 | box-shadow: 3px 3px 6px #8A8A8A;
140 | background: rgba(255,255,255,0.8);
141 | }
142 |
--------------------------------------------------------------------------------
/routes/Actions/AdmireAction.js:
--------------------------------------------------------------------------------
1 | var Admire = require("../Model/Admire.js"),
2 | Comment = require("../Model/Comment.js"),
3 | Remind = require("../Model/Remind.js"),
4 | moment = require("moment");
5 |
6 | moment.lang("zh-cn");
7 |
8 | exports.add = function(req, res) {
9 | var admire = new Admire({
10 | username: req.session.user.username,
11 | commentId: req.body.commentId
12 | });
13 | admire.save(function(err, admire) {
14 | if (err) return res.json(500, {
15 | message: err.message
16 | });
17 | Comment.get(admire.commentId, function(err, comment) {
18 | if (err) return res.json(500, {
19 | message: err.message
20 | });
21 | new Remind({
22 | type: "admire",
23 | ref: admire.id,
24 | user: comment.username
25 | }).save(function(err) {
26 | if (err) return res.json(500, {
27 | message: err.message
28 | });
29 | res.json({
30 | success: true
31 | });
32 | });
33 | });
34 | });
35 | };
36 |
37 | exports.remove = function(req, res) {
38 | var admire = new Admire({
39 | username: req.session.user.username,
40 | commentId: req.body.commentId
41 | });
42 | admire.remove(function(err) {
43 | if (err) return res.json(500, {
44 | message: err.message
45 | });
46 | res.json({
47 | success: true
48 | });
49 | });
50 | };
51 |
52 | exports.checkAdmired = function(req, res) {
53 | var username = req.session.user.username,
54 | commentId = req.body.commentId;
55 | Admire.checkAdmired(username, commentId, function(err, admired) {
56 | if (err) return res.json(500, {
57 | message: err.message
58 | });
59 | res.json({
60 | admired: admired
61 | });
62 | });
63 | };
64 |
65 | exports.countByComment = function(req, res) {
66 | var commentId = req.body.commentId;
67 | Admire.countByComment(commentId, function(err, total) {
68 | if (err) return res.json(500, {
69 | message: err.message
70 | });
71 | res.json({
72 | total: total
73 | });
74 | });
75 | };
76 |
77 | exports.getOne = function(req, res) {
78 | Admire.get(req.body.admireId, function(err, admire) {
79 | if (err) return res.json(500);
80 | if (!admire) return res.status(404).send("not fount");
81 | admire.time = moment(admire.time).fromNow();
82 | res.json({
83 | admire: admire
84 | });
85 | });
86 | };
87 |
88 | exports.getByUser = function(req, res) {
89 | Admire.getByUser(req.body.username, Number(req.body.curPage), Number(req.body.perPage), function(err, admires) {
90 | if (err) return res.json(500);
91 | for (var i = admires.length; i--;) {
92 | admires[i].time = moment(admires[i].time).fromNow();
93 | }
94 | res.json({
95 | admires: admires
96 | });
97 | });
98 | };
99 |
100 | exports.countByUser = function(req, res) {
101 | Admire.countByUser(req.body.username, function(err, total) {
102 | if (err) return res.json(500);
103 | res.json({
104 | total: total
105 | });
106 | });
107 | };
--------------------------------------------------------------------------------
/routes/Actions/ArticleAction.js:
--------------------------------------------------------------------------------
1 | var Article = require("../Model/Article.js"),
2 | User = require("../Model/User.js"),
3 | Comment = require("../Model/Comment.js"),
4 | Admire = require("../Model/Admire.js"),
5 | Bookmark = require("../Model/Bookmark.js"),
6 | Tag = require("../Model/Tag.js"),
7 | async = require("async"),
8 | markdown = require("markdown").markdown,
9 | moment = require("moment");
10 |
11 | moment.lang("zh-cn");
12 |
13 | exports.writePage = function(req, res) {
14 | res.render("writeArticle");
15 | };
16 |
17 | exports.editPage = function(req, res) {
18 | Article.get(req.query.articleId, function(err, article) {
19 | if (err) {
20 | return res.render("error", {
21 | message: err.message
22 | });
23 | }
24 | if (article) {
25 | return res.render("editArticle", {
26 | article: article
27 | });
28 | }
29 | });
30 | };
31 |
32 | exports.update = function(req, res) {
33 | Article.get(req.body.articleId, function(err, article) {
34 | if (err) return res.json(500, {
35 | message: err.message
36 | });
37 | article.title = req.body.title;
38 | article.content = req.body.content;
39 | article.tags = JSON.parse(req.body.tags);
40 | article.update(function(err) {
41 | if (err) return res.json(500, {
42 | message: err.message
43 | });
44 | res.json("editArticle", {
45 | success: true
46 | });
47 | });
48 | });
49 | };
50 |
51 | exports.save = function(req, res) {
52 | console.log(req.body.tags);
53 | var article = new Article({
54 | writer: req.session.user.username,
55 | content: req.body.content,
56 | title: req.body.title,
57 | tags: JSON.parse(req.body.tags)
58 | });
59 | article.save(function(err, art) {
60 | if (err) return res.render("err", {
61 | message: "保存文章失败"
62 | });
63 | res.redirect("/article_load?articleId=" + art.id);
64 | });
65 | };
66 |
67 | exports.remove = function(req, res) {
68 | Article.get(req.body.articleId, function(err, article) {
69 | if (err) return res.json(500);
70 | article.remove(function(err) {
71 | if (err) return res.json(500);
72 | res.json({});
73 | });
74 | });
75 | };
76 |
77 | exports.getOne = function(req, res) {
78 | Article.get(req.body.articleId, function(err, article) {
79 | if (err) return res.json(500);
80 | if (!article) return res.status(404).send("not fount");
81 | article.writeTime = moment(article.writeTime).fromNow();
82 | return res.json({
83 | article: article
84 | });
85 | });
86 | };
87 |
88 |
89 | exports.load = function(req, res) {
90 | Article.get(req.query.articleId, function(err, article) {
91 | if (err) return res.render("error", {
92 | message: err.message
93 | });
94 | if (!article) return res.render("error", {
95 | message: "没有找到该文章"
96 | });
97 | article.content = markdown.toHTML(article.content);
98 | article.writeTime = moment(article.writeTime).fromNow();
99 | res.render("articleDetail", {
100 | article: article
101 | });
102 | });
103 | };
104 |
105 | exports.listAll = function(req, res) {
106 | Article.getAll(Number(req.body.curPage), Number(req.body.perPage), function(err, articles) {
107 | var i;
108 | if (err) return res.json(500);
109 | for (i = articles.length; i--;) {
110 | articles[i].content = markdown.toHTML(articles[i].content);
111 | articles[i].writeTime = moment(articles[i].writeTime).fromNow();
112 | }
113 | return res.json({
114 | articles: articles
115 | });
116 | });
117 | };
118 |
119 |
120 | exports.getByUser = function(req, res) {
121 | Article.getByUser(req.body.username, Number(req.body.curPage), Number(req.body.perPage), function(err, articles) {
122 | if (err) return res.json(500);
123 | for (var i = articles.length; i--;) {
124 | articles[i].writeTime = moment(articles[i].writeTime).fromNow();
125 | }
126 | res.json({
127 | articles: articles
128 | });
129 | });
130 | };
131 |
132 | exports.countByUser = function(req, res) {
133 | Article.countByUser(req.body.username, function(err, total) {
134 | if (err) return res.json(500);
135 | res.json({
136 | total: total
137 | });
138 | });
139 | };
140 |
141 | exports.getByTags = function(req, res) {
142 | Article.getByTags(req.body.tags, Number(req.body.curPage), Number(req.body.perPage), function(err, articles) {
143 | if (err) return res.json(500);
144 | for (var i = articles.length; i--;) {
145 | articles[i].writeTime = moment(articles[i].writeTime).fromNow();
146 | }
147 | res.json({
148 | articles: articles
149 | });
150 | });
151 | };
152 |
153 | exports.getByTitle = function(req, res) {
154 | Article.getByTitle(req.body.title, Number(req.body.curPage), Number(req.body.perPage), function(err, articles) {
155 | if (err) return res.json(500);
156 | for (var i = articles.length; i--;) {
157 | articles[i].writeTime = moment(articles[i].writeTime).fromNow();
158 | }
159 | res.json({
160 | articles: articles
161 | });
162 | });
163 | };
--------------------------------------------------------------------------------
/routes/Actions/BookmarkAction.js:
--------------------------------------------------------------------------------
1 | var Bookmark = require("../Model/Bookmark.js"),
2 | Article = require("../Model/Article.js"),
3 | Remind = require("../Model/Remind.js"),
4 | moment = require("moment");
5 |
6 | moment.lang("zh-cn");
7 |
8 | exports.save = function(req, res) {
9 | var bookmark = new Bookmark({
10 | articleId: req.body.articleId,
11 | username: req.session.user.username
12 | });
13 | bookmark.save(function(err, bookmark) {
14 | if (err) return res.json(500, {
15 | message: err.message
16 | });
17 | Article.get(bookmark.articleId, function(err, article) {
18 | if (err) return res.json(500, {
19 | message: err.message
20 | });
21 | new Remind({
22 | type: "bookmark",
23 | ref: bookmark.id,
24 | user: article.writer
25 | }).save(function(err, remind) {
26 | if (err) return res.json(500, {
27 | message: err.message
28 | });
29 | res.json({
30 | success: true
31 | });
32 | });
33 | });
34 | res.json({
35 | success: true
36 | });
37 | });
38 | };
39 |
40 | exports.remove = function(req, res) {
41 | var bookmark = new Bookmark({
42 | articleId: req.body.articleId,
43 | username: req.session.user.username
44 | });
45 | bookmark.remove(function(err) {
46 | if (err) return res.json(500, {
47 | message: err.message
48 | });
49 | res.json({
50 | success: true
51 | });
52 | });
53 | };
54 |
55 | exports.countByArticle = function(req, res) {
56 | Bookmark.countByArticle(req.body.articleId, function(err, total) {
57 | if (err) return res.json(500, {
58 | message: err.message
59 | });
60 | res.json({
61 | total: total
62 | });
63 | });
64 | };
65 |
66 | exports.checkBooked = function(req, res) {
67 | Bookmark.checkBooked(req.session.user.username, req.body.articleId, function(err, booked) {
68 | if (err) return res.json(500, {
69 | message: err.message
70 | });
71 | res.json({
72 | booked: booked
73 | });
74 | });
75 | };
76 |
77 | exports.getOne = function(req, res) {
78 | Bookmark.get(req.body.bookmarkId, function(err, bookmark) {
79 | if (err) return res.json(500);
80 | if (!bookmark) return res.status(404).send("not found");
81 | bookmark.time = moment(bookmark.time).fromNow();
82 | res.json({
83 | bookmark: bookmark
84 | });
85 | });
86 | };
87 |
88 | exports.getByUser = function(req, res) {
89 | Bookmark.getByUser(req.body.username, Number(req.body.curPage), Number(req.body.perPage), function(err, bookmarks) {
90 | if (err) return res.json(500);
91 | for (var i = bookmarks.length; i--;) {
92 | bookmarks[i].time = moment(bookmarks[i].time).fromNow();
93 | }
94 | res.json({
95 | bookmarks: bookmarks
96 | });
97 | });
98 | };
99 |
100 | exports.countByUser = function(req, res) {
101 | Bookmark.countByUser(req.body.username, function(err, total) {
102 | if (err) return res.json(500);
103 | res.json({
104 | total: total
105 | });
106 | });
107 | };
--------------------------------------------------------------------------------
/routes/Actions/CommentAction.js:
--------------------------------------------------------------------------------
1 | var Comment = require("../Model/Comment.js"),
2 | Remind = require("../Model/Remind.js"),
3 | moment = require("moment"),
4 | async = require("async");
5 |
6 | moment.lang("zh-cn");
7 |
8 | exports.save = function(req, res) {
9 | var remind,
10 | comment = new Comment({
11 | articleId: req.body.articleId,
12 | username: req.session.user.username,
13 | comment: req.body.comment,
14 | reply: req.body.replyId
15 | });
16 |
17 | async.waterfall([
18 |
19 | function(callback) {
20 | comment.save(function(err, comment) {
21 | if (err) return callback(err);
22 | callback(err, comment);
23 | });
24 | },
25 | function(comment, callback) {
26 | if (comment.reply) {
27 | Comment.get(comment.reply, function(err, com) {
28 | if (err) return callback(err);
29 | var remind = new Remind({
30 | type: "comment",
31 | ref: comment.id,
32 | user: com.username
33 | });
34 | remind.save(function(err) {
35 | if (err) return callback(err);
36 | callback(comment);
37 | });
38 | });
39 | } else {
40 | callback(comment);
41 | }
42 | },
43 | function(comment, callback) {
44 | Article.get(comment.articleId, function(err, com) {
45 | if (err) return callback(err);
46 | var remind = new Remind({
47 | type: "comment",
48 | ref: comment.id,
49 | user: com.username
50 | });
51 | remind.save(function(err) {
52 | if (err) return callback(err);
53 | callback(comment);
54 | });
55 | });
56 | }
57 | ], function(err) {
58 | if (err) res.render("error", {
59 | message: err.message
60 | });
61 | res.redirect("/article_load?articleId=" + comment.articleId + "#comments");
62 | });
63 | };
64 |
65 | exports.remove = function(req, res) {
66 | Comment.get(req.body.commentId, function(err, comment) {
67 | if (err) return res.json(500, {
68 | message: err.message
69 | });
70 | if (req.session.user.username === comment.username) {
71 | comment.remove(function(err) {
72 | if (err) return res.json(500, {
73 | message: err.message
74 | });
75 | res.json({
76 | success: true
77 | });
78 | });
79 | } else {
80 | return res.json(500, {
81 | message: "不能删除他人的评论"
82 | });
83 | }
84 | });
85 | };
86 |
87 | exports.getByArticle = function(req, res) {
88 | Comment.getByArticle(req.body.articleId, Number(req.body.curPage), Number(req.body.perPage), function(err, comments) {
89 | var i;
90 | if (err) return res.json(500, {
91 | message: err.message
92 | });
93 | for (i = comments.length; i--;) {
94 | comments[i].time = moment(comments[i].time).fromNow();
95 | }
96 | res.json({
97 | comments: comments
98 | });
99 | });
100 | };
101 |
102 | exports.countByArticle = function(req, res) {
103 | Comment.countByArticle(req.body.articleId, function(err, total) {
104 | if (err) return res.json(500, {
105 | message: err.message
106 | });
107 | res.json({
108 | total: total
109 | });
110 | });
111 | };
112 |
113 | exports.countByUser = function(req, res) {
114 | Comment.countByUser(req.body.username, function(err, total) {
115 | if (err) return res.json(500, {
116 | message: err.message
117 | });
118 | res.json({
119 | total: total
120 | });
121 | });
122 | };
123 |
124 | exports.getByUser = function(req, res) {
125 | Comment.getByUser(req.body.username, Number(req.body.curPage), Number(req.body.perPage), function(err, comments) {
126 | if (err) return res.json(500, {
127 | message: err.message
128 | });
129 | for (var i = comments.length; i--;) {
130 | comments[i].time = moment(comments[i].time).fromNow();
131 | }
132 | res.json({
133 | comments: comments
134 | });
135 | });
136 | };
137 |
138 |
139 | exports.getOne = function(req, res) {
140 | Comment.get(req.body.commentId, function(err, comment) {
141 | if (err) return res.json(500);
142 | if (!comment) return res.status(404).send("not fount");
143 | comment.time = moment(comment.time).fromNow();
144 | res.json({
145 | comment: comment
146 | });
147 | });
148 | };
--------------------------------------------------------------------------------
/routes/Actions/ExpAction.js:
--------------------------------------------------------------------------------
1 | exports.broadchat = function(req, res) {
2 | res.render("broadchat");
3 | };
--------------------------------------------------------------------------------
/routes/Actions/GallaryAction.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs"),
2 | gallary = require("../setting.js").gallary;
3 |
4 | exports.gallaryPage = function(req, res) {
5 | res.render("gallary");
6 | };
7 |
8 | exports.listByPage = function(req, res) {
9 | var curPage = req.query.curPage || 0,
10 | perPage = Number(req.query.perPage) || 10;
11 | path = "public/" + gallary.name;
12 | fs.readdir(path, function(err, files) {
13 | var i,
14 | start = curPage * perPage,
15 | end,
16 | total;
17 | if (err) return res.json(500, {
18 | message: err.message
19 | });
20 | if (start > files.length) {
21 | res.json({
22 | files: [],
23 | total: files.length,
24 | gallary: gallary.name,
25 | gallary_small: gallary.small
26 | });
27 | } else {
28 | end = start + perPage > files.length ? files.length : start + perPage;
29 | res.json({
30 | files: files.slice(start, end),
31 | total: files.length,
32 | start: start,
33 | end: end,
34 | gallary_small: gallary.small,
35 | gallary: gallary.name
36 | });
37 | }
38 | });
39 | };
--------------------------------------------------------------------------------
/routes/Actions/PictureAction.js:
--------------------------------------------------------------------------------
1 | var setting = require("../setting.js"),
2 | fs = require("fs"),
3 | async = require("async"),
4 | gm = require("gm"),
5 | path = require("path"),
6 | imageMagick = gm.subClass({
7 | imageMagick: true
8 | }),
9 | uuid = require("node-uuid"),
10 | util = require("util"),
11 | __copyFile = function copyFile(file, toDir, callback) {
12 | var reads = fs.createReadStream(file);
13 | var writes = fs.createWriteStream(path.join(path.dirname(toDir), path.basename(file)));
14 | reads.pipe(writes);
15 | //don't forget close the when all the data are read
16 | reads.on("end", function() {
17 | writes.end();
18 | callback(null);
19 | });
20 | reads.on("error", function(err) {
21 | console.log("error occur in reads");
22 | callback(true, err);
23 | });
24 | };
25 |
26 | exports.remove = function(req, res) {
27 | var fileName = req.body.fileName,
28 | smallFile = "public/" + setting.gallary.small + "/" + fileName,
29 | orignFile = "public/" + setting.gallary.name + "/" + fileName;
30 | try {
31 | fs.unlinkSync(smallFile);
32 | fs.unlinkSync(orignFile);
33 | } catch (e) {
34 | return res.json(500, {
35 | message: e.message
36 | });
37 | }
38 | res.json({
39 | success: true
40 | });
41 |
42 | };
43 |
44 | exports.uploadDirect = function(req, res) {
45 | var inputFile = req.files.image.path,
46 | fileName = new RegExp('^' + setting.uploadDir + '\\\\([\\w-\\.]+)$').exec(inputFile)[1],
47 | resizeFile = "public/" + setting.gallary.small + "/" + fileName,
48 | outputFile = "public/" + setting.gallary.name + "/" + fileName;
49 | async.waterfall([
50 |
51 | function(callback) {
52 | imageMagick(inputFile).write(outputFile, function(err) {
53 | if (err) return callback(err);
54 | callback(null);
55 | });
56 | },
57 | function(callback) {
58 | imageMagick(inputFile).resize(400).write(resizeFile, function(err) {
59 | if (err) return callback(err);
60 | callback(null);
61 | });
62 | },
63 | function(callback) {
64 | if (fs.existsSync(inputFile)) {
65 | fs.unlink(inputFile, function(err) {
66 | if (err) return callback(err);
67 | callback(null);
68 | });
69 | } else {
70 | callback(new Error("未找到文件"));
71 | }
72 | }
73 | ], function(err) {
74 | if (err) return res.json(500, {
75 | message: err.message
76 | });
77 | res.json({
78 | success: true,
79 | fileName: fileName,
80 | gallary: setting.gallary.name,
81 | gallary_small: setting.gallary.small
82 | });
83 | });
84 | };
85 |
86 | exports.uploadDirectNoCompress = function(req, res) {
87 | var inputFile = req.files.image.path,
88 | fileName = (/^upload_tmp\/([\w\-\.]+)$/.exec(inputFile) || /^upload_tmp\\([\w\-\.]+)$/.exec(inputFile))[1],
89 | resizeFile = "public/" + setting.gallary.small + "/" + fileName,
90 | outputFile = "public/" + setting.gallary.name + "/" + fileName;
91 | async.waterfall([
92 |
93 | function(callback) {
94 | __copyFile(inputFile, resizeFile, callback);
95 | },
96 | function(callback) {
97 | __copyFile(inputFile, outputFile, callback);
98 | },
99 | function(callback) {
100 | if (fs.existsSync(inputFile)) {
101 | fs.unlink(inputFile, function(err) {
102 | if (err) return callback(err);
103 | callback(null);
104 | });
105 | } else {
106 | callback(new Error("未找到文件"));
107 | }
108 | }
109 | ], function(err) {
110 | if (err) return res.json(500, {
111 | message: err.message
112 | });
113 | res.json({
114 | success: true,
115 | fileName: fileName,
116 | gallary: setting.gallary.name,
117 | gallary_small: setting.gallary.small
118 | });
119 | });
120 | };
121 |
--------------------------------------------------------------------------------
/routes/Actions/RemindAction.js:
--------------------------------------------------------------------------------
1 | var Remind = require("../Model/Remind.js"),
2 | moment = require("moment"),
3 | async = require("async");
4 |
5 | exports.getAll = function(req, res) {
6 | Remind.getByUser(req.session.user.username, Number(req.body.curPage), Number(req.body.perPage), function(err, reminds) {
7 | if (err) res.json(500, {
8 | message: err.message
9 | });
10 | res.json({
11 | reminds: reminds
12 | });
13 | });
14 | };
15 |
16 | exports.getByType = function(req, res) {
17 | Remind.getByUserAndType(req.session.user.username, req.body.type, Number(req.body.curPage), Number(req.body.perPage), function(err, reminds) {
18 | if (err) res.json(500, {
19 | message: err.message
20 | });
21 | res.json({
22 | reminds: reminds
23 | });
24 | });
25 | };
26 |
27 | exports.countUnreadAll = function(req, res) {
28 | Remind.countUnreadByUser(req.session.user.username, function(err, total) {
29 | if (err) res.json(500, {
30 | message: err.message
31 | });
32 | res.json({
33 | total: total
34 | });
35 | });
36 | };
37 |
38 | exports.countUnreadByType = function(req, res) {
39 | Remind.countUnreadByUserAndType(req.session.user.username, req.body.type, function(err, total) {
40 | if (err) res.json(500, {
41 | message: err.message
42 | });
43 | res.json({
44 | total: total
45 | });
46 | });
47 | };
48 |
49 | exports.remove = function(req, res) {
50 | var remindId = req.body.remindId;
51 | Remind.getOne(remindId, function(err, remind) {
52 | if (err) return callback(err);
53 | remind.remove(function(err) {
54 | if (err) return res.json(500);
55 | res.json(null);
56 | });
57 | });
58 | };
59 |
60 | exports.setReaded = function(req, res) {
61 | var remindIds = req.body.remindIds;
62 | async.each(remindIds, function(remindId, callback) {
63 | Remind.getOne(remindId, function(err, remind) {
64 | if (err) return callback(err);
65 | remind.readed = true;
66 | remind.update(function(err) {
67 | if (err) return callback(err);
68 | callback(null);
69 | });
70 | });
71 | }, function(err) {
72 | if (err) return res.json(500);
73 | res.json(null);
74 | });
75 | };
--------------------------------------------------------------------------------
/routes/Actions/TagAction.js:
--------------------------------------------------------------------------------
1 | var Tag = require("../Model/Tag.js"),
2 | User = require("../Model/User.js"),
3 | Article = require("../Model/Article.js"),
4 | async = require("async");
5 |
6 | exports.create = function(req, res) {
7 | var tag = new Tag({
8 | name: req.body.name,
9 | color: req.body.color
10 | });
11 | tag.save(function(err, newTag) {
12 | if (err) return res.json(500, {
13 | message: err.message
14 | });
15 | res.json({
16 | tag: newTag
17 | });
18 | });
19 | };
20 |
21 | exports.listAll = function(req, res) {
22 | var name = req.query.name;
23 | Tag.getAll(function(err, tags) {
24 | if (err) return res.json(500, {
25 | message: err.message
26 | });
27 | res.json({
28 | tags: tags
29 | });
30 | });
31 | };
32 |
33 | exports.listUserTags = function(req, res) {
34 | User.get(req.body.username, function(err, user) {
35 | if (err) return req.json(500, {
36 | message: err.message
37 | });
38 | async.map(user.tags, function(tagId, callback) {
39 | Tag.get(tagId, function(err, tag) {
40 | if (err) return callback(tag);
41 | callback(null, tag);
42 | });
43 | }, function(err, tags) {
44 | if (err) return req.json(500, {
45 | message: err.message
46 | });
47 | res.json({
48 | tags: tags
49 | });
50 | });
51 | });
52 | };
53 |
54 | exports.listArticleTags = function(req, res) {
55 | Article.get(req.body.articleId, function(err, article) {
56 | if (err) return req.json(500, {
57 | message: err.message
58 | });
59 | async.map(article.tags, function(tagId, callback) {
60 | Tag.get(tagId, function(err, tag) {
61 | if (err) return callback(tag);
62 | callback(null, tag);
63 | });
64 | }, function(err, tags) {
65 | if (err) return req.json(500, {
66 | message: err.message
67 | });
68 | res.json({
69 | tags: tags
70 | });
71 | });
72 | });
73 | };
74 |
75 | exports.listFuzzy = function(req, res) {
76 | var name = req.query.name;
77 | Tag.getByFuzzyName(name, function(err, tags) {
78 | if (err) return res.json(500, {
79 | message: err.message
80 | });
81 | res.json({
82 | tags: tags
83 | });
84 | });
85 | };
--------------------------------------------------------------------------------
/routes/Actions/UserAction.js:
--------------------------------------------------------------------------------
1 | var User = require("../Model/User.js"),
2 | async = require("async"),
3 | Bookmark = require("../Model/Bookmark.js"),
4 | Admire = require("../Model/Admire.js"),
5 | Article = require("../Model/Article.js"),
6 | Comment = require("../Model/Comment.js"),
7 | moment = require("moment");
8 | exports.loginPage = function(req, res) {
9 | res.render('login');
10 | };
11 |
12 | exports.registPage = function(req, res) {
13 | res.render('regist');
14 | };
15 |
16 | exports.login = function(req, res) {
17 | User.get(req.body.username, function(err, user) {
18 | if (err) return req.render("error", {
19 | message: "发生错误,请稍后重试..."
20 | });
21 | if (user && user.password === req.body.password) {
22 | req.session.user = user;
23 | res.redirect("/index");
24 | } else {
25 | res.render("login", {
26 | message: "用户名或密码错误..."
27 | });
28 | }
29 | });
30 | };
31 |
32 | exports.logout = function(req, res) {
33 | if (typeof req.session.user !== "undefined") {
34 | delete req.session.user;
35 | }
36 | res.redirect("index");
37 | };
38 |
39 | exports.loadDetail = function(req, res) {
40 | res.render("userDetail", {
41 | user: req.session.user
42 | });
43 | };
44 |
45 | exports.getDetail = function(req, res) {
46 | User.get(req.body.username, function(err, user) {
47 | if (err) return res.render("error", {
48 | message: err.message
49 | });
50 | res.json({
51 | username: user.username,
52 | nickname: user.nickname,
53 | owner: user.owner,
54 | tags: user.tags,
55 | avatar: user.avatar
56 | });
57 | });
58 | };
59 |
60 | exports.modify = function(req, res) {
61 | var tags = JSON.parse(req.body.tags);
62 | User.get(req.session.user.username, function(err, user) {
63 | if (err) return res.render("error", {
64 | message: err.message
65 | });
66 | if (user) {
67 | user.nickname = req.body.nickname;
68 | user.tags = tags;
69 | if (req.body.password) {
70 | user.password = req.body.password;
71 | }
72 | user.avatar = req.body.avatar || "/images/default_avatar.jpg";
73 | user.update(function(err) {
74 | req.session.user = user;
75 | res.render("userDetail", {
76 | user: req.session.user,
77 | success: true,
78 | message: "修改成功..."
79 | });
80 | });
81 | } else {
82 | res.render("userDetail", {
83 | user: req.session.user,
84 | success: false,
85 | message: "修改失败,用户不存在..."
86 | });
87 | }
88 | });
89 | };
90 |
91 | exports.regist = function(req, res) {
92 | User.get(req.body.username, function(err, user) {
93 | if (err) return res.render("error", {
94 | message: err.message
95 | });
96 | if (user) {
97 | return res.render("regist", {
98 | message: "用户名已被注册..."
99 | });
100 | } else {
101 | user = new User({
102 | username: req.body.username,
103 | password: req.body.password,
104 | nickname: req.body.nickname,
105 | avatar: "/images/default_avatar.jpg",
106 | owner: false,
107 | tags: []
108 | });
109 | user.save(function(err) {
110 | if (err) {
111 | return res.render("regist", {
112 | message: "发生错误,请稍后重试..."
113 | });
114 | } else {
115 | req.session.user = user;
116 | res.redirect("/index");
117 | }
118 | });
119 | }
120 | });
121 | };
--------------------------------------------------------------------------------
/routes/Model/Admire.js:
--------------------------------------------------------------------------------
1 | var commonDao = require("./CommonDAO.js"),
2 | collectionName = "admire",
3 | uuid = require("node-uuid"),
4 | __resultToListFn = function(callback) {
5 | return function(err, results) {
6 | var i;
7 | if (err) return callback(err);
8 | for (i = results.length; i--;) {
9 | results[i] = new Admire(results[i]);
10 | }
11 | callback(err, results);
12 |
13 | };
14 | };
15 |
16 | function Admire(admire) {
17 | this.username = admire.username;
18 | this.commentId = admire.commentId;
19 | this.time = admire.time;
20 | this.id = admire.id;
21 | }
22 |
23 | module.exports = Admire;
24 |
25 | Admire.prototype.save = function(callback) {
26 | commonDao.save(collectionName, {
27 | username: this.username,
28 | commentId: this.commentId,
29 | time: new Date().getTime(),
30 | id: uuid.v4()
31 | }, function(err, result) {
32 | if (err) return callback(err);
33 | if (!result[0]) return callback(new Error("保存失败"));
34 | callback(err, new Admire(result[0]));
35 | });
36 | };
37 |
38 | Admire.get = function(admireId, callback) {
39 | commonDao.findOne(collectionName, {
40 | id: admireId
41 | }, function(err, result) {
42 | if (err) return callback(err);
43 | callback(err, result ? new Admire(result) : result);
44 | });
45 | };
46 |
47 | Admire.removeByComment = function(commentId, callback) {
48 | commonDao.remove(collectionName, {
49 | commentId: commentId
50 | }, callback);
51 | };
52 |
53 | Admire.getByUser = function(username, curPage, perPage, callback) {
54 | commonDao.find(collectionName, {
55 | condition: {
56 | username: username
57 | },
58 | sort: {
59 | time: -1
60 | },
61 | page: {
62 | curPage: curPage,
63 | perPage: perPage
64 | }
65 | }, __resultToListFn(callback));
66 | };
67 |
68 | Admire.countByUser = function(username, callback) {
69 | commonDao.count(collectionName, {
70 | username: username
71 | }, callback);
72 | };
73 |
74 | Admire.prototype.remove = function(callback) {
75 | commonDao.remove(collectionName, {
76 | username: this.username,
77 | commentId: this.commentId
78 | }, callback);
79 | };
80 |
81 | Admire.countByComment = function(commentId, callback) {
82 | commonDao.count(collectionName, {
83 | commentId: commentId
84 | }, callback);
85 | };
86 |
87 | Admire.checkAdmired = function(username, commentId, callback) {
88 | commonDao.findOne(collectionName, {
89 | username: username,
90 | commentId: commentId
91 | }, function(err, result) {
92 | if (err) return callback(err);
93 | if (!result) return callback(err, false);
94 | return callback(err, true);
95 | });
96 | };
--------------------------------------------------------------------------------
/routes/Model/Article.js:
--------------------------------------------------------------------------------
1 | var commonDao = require("./CommonDAO.js"),
2 | collectionName = "article",
3 | uuid = require("node-uuid"),
4 | async = require("async"),
5 | Bookmark = require("./Bookmark.js"),
6 | Comment = require("./Comment.js"),
7 | __resultToListFn = function(callback) {
8 | return function(err, results) {
9 | var i;
10 | if (err) return callback(err);
11 | for (i = results.length; i--;) {
12 | results[i] = new Article(results[i]);
13 | }
14 | callback(err, results);
15 | };
16 | };
17 |
18 | function Article(article) {
19 | this.content = article.content;
20 | this.title = article.title;
21 | this.writer = article.writer;
22 | this.id = article.id;
23 | this.writeTime = article.writeTime;
24 | this.lastModifyTime = article.lastModifyTime;
25 | this.tags = article.tags;
26 | }
27 |
28 | module.exports = Article;
29 |
30 | Article.prototype.save = function(callback) {
31 | var article = {
32 | content: this.content,
33 | title: this.title,
34 | writer: this.writer,
35 | writeTime: new Date().getTime(),
36 | lastModifyTime: new Date().getTime(),
37 | tags: this.tags,
38 | id: uuid.v4()
39 | };
40 | commonDao.save(collectionName, article, function(err, result) {
41 | if (err) return callback(err);
42 | if (!result[0]) return callback(new Error("保存失败"));
43 | callback(err, new Article(result[0]));
44 | });
45 | };
46 |
47 | Article.prototype.update = function(callback) {
48 | commonDao.update(collectionName, {
49 | id: this.id
50 | }, {
51 | content: this.content,
52 | title: this.title,
53 | lastModifyTime: new Date().getTime(),
54 | tags: this.tags
55 | }, callback);
56 | };
57 |
58 | Article.prototype.remove = function(callback) {
59 | var articleId = this.id;
60 | commonDao.remove(collectionName, {
61 | id: articleId
62 | }, callback);
63 | };
64 |
65 | Article.get = function(id, callback) {
66 | commonDao.findOne(collectionName, {
67 | id: id
68 | }, function(err, result) {
69 | if (err) return callback(err);
70 | callback(err, result ? new Article(result) : result);
71 | });
72 | };
73 |
74 | Article.countAll = function(callback) {
75 | commonDao.count(collectionName, {}, callback);
76 | };
77 |
78 | Article.getAll = function(curPage, perPage, callback) {
79 | commonDao.find(collectionName, {
80 | sort: {
81 | writeTime: -1
82 | },
83 | page: {
84 | curPage: curPage,
85 | perPage: perPage
86 | }
87 | }, __resultToListFn(callback));
88 | };
89 |
90 | Article.getByUser = function(username, curPage, perPage, callback) {
91 | commonDao.find(collectionName, {
92 | condition: {
93 | writer: username
94 | },
95 | sort: {
96 | writeTime: -1
97 | },
98 | page: {
99 | curPage: curPage,
100 | perPage: perPage
101 | }
102 | }, __resultToListFn(callback));
103 | };
104 |
105 | Article.countByUser = function(username, callback) {
106 | commonDao.count(collectionName, {
107 | writer: username
108 | }, callback);
109 | };
110 |
111 | Article.getByTags = function(tags, curPage, perPage, callback) {
112 | commonDao.find(collectionName, {
113 | condition: {
114 | tags: {
115 | $all: tags
116 | }
117 | },
118 | sort: {
119 | writeTime: -1
120 | },
121 | page: {
122 | curPage: curPage,
123 | perPage: perPage
124 | }
125 | }, __resultToListFn(callback));
126 | };
127 |
128 | Article.getByTitle = function(title, curPage, perPage, callback) {
129 | console.log(title);
130 | commonDao.find(collectionName, {
131 | condition: {
132 | title: new RegExp(title, "i")
133 | },
134 | sort: {
135 | writeTime: -1
136 | },
137 | page: {
138 | curPage: curPage,
139 | perPage: perPage
140 | }
141 | }, __resultToListFn(callback));
142 | };
--------------------------------------------------------------------------------
/routes/Model/Bookmark.js:
--------------------------------------------------------------------------------
1 | var commonDao = require("./CommonDAO.js"),
2 | collectionName = "bookmark",
3 | uuid = require("node-uuid"),
4 | __resultToListFn = function(callback) {
5 | return function(err, results) {
6 | var i;
7 | if (err) return callback(err);
8 | for (i = results.length; i--;) {
9 | results[i] = new Bookmark(results[i]);
10 | }
11 | callback(err, results);
12 | };
13 | };
14 |
15 | function Bookmark(bookmark) {
16 | this.username = bookmark.username;
17 | this.articleId = bookmark.articleId;
18 | this.time = bookmark.time;
19 | this.id = bookmark.id;
20 | }
21 |
22 | module.exports = Bookmark;
23 |
24 | Bookmark.prototype.save = function(callback) {
25 | commonDao.save(collectionName, {
26 | username: this.username,
27 | articleId: this.articleId,
28 | time: new Date().getTime(),
29 | id: uuid.v4()
30 | }, function(err, result) {
31 | if (err) return callback(err);
32 | if (!result[0]) return callback(new Error("保存失败"));
33 | callback(err, new Bookmark(result[0]));
34 | });
35 | };
36 |
37 | Bookmark.prototype.remove = function(callback) {
38 | commonDao.remove(collectionName, {
39 | username: this.username,
40 | articleId: this.articleId
41 | }, callback);
42 | };
43 |
44 |
45 | Bookmark.get = function(bookmarkId, callback) {
46 | commonDao.findOne(collectionName, {
47 | id: bookmarkId
48 | }, function(err, result) {
49 | if (err) return callback(err);
50 | callback(err, result ? new Bookmark(result) : result);
51 | });
52 | };
53 |
54 | Bookmark.checkBooked = function(username, articleId, callback) {
55 | commonDao.findOne(collectionName, {
56 | username: username,
57 | articleId: articleId
58 | }, function(err, result) {
59 | if (err) return callback(err);
60 | if (!result) return callback(err, false);
61 | return callback(err, true);
62 | });
63 | };
64 |
65 | Bookmark.getByUser = function(username, curPage, perPage, callback) {
66 | commonDao.find(collectionName, {
67 | condition: {
68 | username: username
69 | },
70 | sort: {
71 | time: -1
72 | },
73 | page: {
74 | curPage: curPage,
75 | perPage: perPage
76 | }
77 | }, __resultToListFn(callback));
78 | };
79 |
80 | Bookmark.countByUser = function(username, callback) {
81 | commonDao.count(collectionName, {
82 | username: username
83 | }, callback);
84 | };
85 |
86 | Bookmark.getByArticle = function(articleId, callback) {
87 | commonDao.find(collectionName, {
88 | condition: {
89 | articleId: articleId
90 | },
91 | sort: {
92 | time: -1
93 | }
94 | }, __resultToListFn(callback));
95 | };
96 |
97 | Bookmark.countByArticle = function(articleId, callback) {
98 | commonDao.count(collectionName, {
99 | articleId: articleId
100 | }, function(err, total) {
101 | if (err) return callback(err);
102 | callback(err, total);
103 | });
104 | };
--------------------------------------------------------------------------------
/routes/Model/Comment.js:
--------------------------------------------------------------------------------
1 | var commonDao = require("./CommonDAO.js"),
2 | collectionName = "comment",
3 | uuid = require("node-uuid"),
4 | Admire = require("./Admire.js"),
5 | async = require("async"),
6 | __resultToListFn = function(callback) {
7 | return function(err, results) {
8 | var i;
9 | if (err) {
10 | return callback(err);
11 | }
12 | for (i = results.length; i--;) {
13 | results[i] = new Comment(results[i]);
14 | }
15 | callback(err, results);
16 | };
17 | };
18 |
19 | function Comment(comment) {
20 | this.comment = comment.comment;
21 | this.username = comment.username;
22 | this.reply = comment.reply;
23 | this.articleId = comment.articleId;
24 | this.time = comment.time;
25 | this.id = comment.id;
26 | }
27 |
28 | module.exports = Comment;
29 |
30 | Comment.prototype.save = function(callback) {
31 | commonDao.save(collectionName, {
32 | comment: this.comment,
33 | username: this.username,
34 | articleId: this.articleId,
35 | time: new Date().getTime(),
36 | reply: this.reply,
37 | id: uuid.v4()
38 | }, function(err, result) {
39 | if (err) return callback(err);
40 | if (!result[0]) return new Error("保存评论失败");
41 | return callback(err, new Comment(result[0]));
42 | });
43 | };
44 |
45 | Comment.prototype.remove = function(callback) {
46 | var commentId = this.id;
47 | commonDao.remove(collectionName, {
48 | id: commentId
49 | }, callback);
50 | };
51 |
52 | Comment.get = function(commentId, callback) {
53 | commonDao.findOne(collectionName, {
54 | id: commentId
55 | }, function(err, result) {
56 | if (err) return callback(err);
57 | callback(err, result ? new Comment(result) : result);
58 | });
59 | };
60 |
61 | Comment.getByArticle = function(articleId, curPage, perPage, callback) {
62 | commonDao.find(collectionName, {
63 | condition: {
64 | articleId: articleId
65 | },
66 | sort: {
67 | time: -1
68 | },
69 | page: {
70 | curPage: curPage,
71 | perPage: perPage
72 | }
73 | }, __resultToListFn(callback));
74 | };
75 |
76 | Comment.getByUser = function(username, curPage, perPage, callback) {
77 | commonDao.find(collectionName, {
78 | condition: {
79 | username: username
80 | },
81 | sort: {
82 | time: -1
83 | },
84 | page: {
85 | curPage: curPage,
86 | perPage: perPage
87 | }
88 | }, __resultToListFn(callback));
89 | };
90 |
91 | Comment.countByUser = function(username, callback) {
92 | commonDao.count(collectionName, {
93 | username: username
94 | }, callback);
95 | };
96 |
97 | Comment.countByArticle = function(articleId, callback) {
98 | commonDao.count(collectionName, {
99 | articleId: articleId
100 | }, callback);
101 | };
--------------------------------------------------------------------------------
/routes/Model/CommonDAO.js:
--------------------------------------------------------------------------------
1 | var MongoClient = require('mongodb').MongoClient,
2 | setting = require("../setting.js"),
3 | client;
4 | console.log("MongoDB connecting...");
5 | exports.save = function(collectionName, obj, callback) {
6 | MongoClient.connect(setting.host, function(err, client) {
7 | client.collection(collectionName, function(err, collection) {
8 | if (err) return callback(err);
9 | collection.insert(obj, {
10 | safe: true
11 | }, function(err, result) {
12 | callback(err, result);
13 | client.close();
14 | });
15 | });
16 | });
17 | };
18 |
19 | exports.findOne = function(collectionName, oArgs, callback) {
20 | MongoClient.connect(setting.host, function(err, client) {
21 | client.collection(collectionName, function(err, collection) {
22 | if (err) return callback(err);
23 | collection.findOne(oArgs, function(err, result) {
24 | callback(err, result);
25 | client.close();
26 | });
27 | });
28 | });
29 | };
30 |
31 | exports.update = function(collectionName, oArgs, newObj, callback) {
32 | if (newObj._id) delete newObj._id;
33 | MongoClient.connect(setting.host, function(err, client) {
34 | client.collection(collectionName, function(err, collection) {
35 | if (err) return callback(err);
36 | collection.update(oArgs, {
37 | $set: newObj
38 | }, {
39 | safe: true,
40 | upsert: false,
41 | multi: true
42 | },
43 | function(err, result) {
44 | callback(err, result);
45 | client.close();
46 | });
47 | });
48 | });
49 |
50 | };
51 |
52 | exports.remove = function(collectionName, oArgs, callback) {
53 | MongoClient.connect(setting.host, function(err, client) {
54 | client.collection(collectionName, function(err, collection) {
55 | if (err) return callback(err);
56 | collection.remove(oArgs, function(err, result) {
57 | callback(err, result);
58 | client.close();
59 | });
60 | });
61 | });
62 | };
63 |
64 | exports.count = function(collectionName, oArgs, callback) {
65 | MongoClient.connect(setting.host, function(err, client) {
66 | client.collection(collectionName, function(err, collection) {
67 | if (err) return callback(err);
68 | collection.count(oArgs, function(err, result) {
69 | callback(err, result);
70 | client.close();
71 | });
72 | });
73 | });
74 | };
75 |
76 | exports.find = function(collectionName, oArgs, callback) {
77 | MongoClient.connect(setting.host, function(err, client) {
78 | client.collection(collectionName, function(err, collection) {
79 | var tmp,
80 | skip;
81 | if (err) return callback(err);
82 | tmp = collection.find(oArgs.condition);
83 | if (oArgs.sort) tmp.sort(oArgs.sort);
84 | if (oArgs.page) {
85 | skip = oArgs.page.curPage * oArgs.page.perPage;
86 | tmp.limit(oArgs.page.perPage).skip(skip);
87 | }
88 | tmp.toArray(function(err, result) {
89 | callback(err, result);
90 | client.close();
91 | });
92 | });
93 | });
94 | };
--------------------------------------------------------------------------------
/routes/Model/Remind.js:
--------------------------------------------------------------------------------
1 | var commonDao = require("./CommonDAO.js"),
2 | collectionName = "remind",
3 | uuid = require("node-uuid"),
4 | async = require("async"),
5 | __resultToListFn = function(callback) {
6 | return function(err, results) {
7 | var i;
8 | if (err) return callback(err);
9 | for (i = results.length; i--;) {
10 | results[i] = new Remind(results[i]);
11 | }
12 | callback(err, results);
13 | };
14 | };
15 |
16 | function Remind(remind) {
17 | this.id = remind.id;
18 | this.time = remind.time;
19 | this.type = remind.type;
20 | this.ref = remind.ref;
21 | this.readed = remind.readed;
22 | this.user = remind.user;
23 | }
24 |
25 | module.exports = Remind;
26 |
27 | Remind.prototype.save = function(callback) {
28 | commonDao.save(collectionName, {
29 | time: new Date().getTime(),
30 | type: this.type,
31 | ref: this.ref,
32 | user: this.user,
33 | readed: false,
34 | id: uuid.v4()
35 | }, function(err, result) {
36 | if (err) return callback(err);
37 | if (!result[0]) return callback(new Error("保存失败"));
38 | callback(err, new Remind(result[0]));
39 | });
40 | };
41 |
42 | Remind.getOne = function(remindId, callback) {
43 | commonDao.findOne(collectionName, {
44 | id: remindId
45 | }, function(err, result) {
46 | if (err) return callback(err);
47 | callback(err, result ? new Remind(result) : null);
48 | });
49 | };
50 |
51 | Remind.prototype.remove = function(callback) {
52 | commonDao.remove(collectionName, {
53 | id: this.id
54 | }, callback);
55 | };
56 |
57 | Remind.prototype.update = function(callback) {
58 | commonDao.update(collectionName, {
59 | id: this.id
60 | }, {
61 | readed: this.readed
62 | }, callback);
63 | };
64 |
65 | Remind.getByUser = function(username, curPage, perPage, callback) {
66 | commonDao.find(collectionName, {
67 | condition: {
68 | user: username
69 | },
70 | sort: {
71 | time: -1
72 | },
73 | page: {
74 | curPage: curPage,
75 | perPage: perPage
76 | },
77 | }, __resultToListFn(callback));
78 | };
79 |
80 | Remind.getByUserAndType = function(username, type, curPage, perPage, callback) {
81 | commonDao.find(collectionName, {
82 | condition: {
83 | user: username,
84 | type: type
85 | },
86 | page: {
87 | curPage: curPage,
88 | perPage: perPage
89 | },
90 | sort: {
91 | time: -1
92 | }
93 | }, __resultToListFn(callback));
94 | };
95 |
96 | Remind.countByUser = function(username, callback) {
97 | commonDao.count(collectionName, {
98 | user: username
99 | }, callback);
100 | };
101 |
102 | Remind.countByUserAndType = function(username, type, callback) {
103 | commonDao.count(collectionName, {
104 | user: username,
105 | type: type
106 | }, callback);
107 | };
108 |
109 | Remind.countUnreadByUser = function(username, callback) {
110 | commonDao.count(collectionName, {
111 | user: username,
112 | readed: false
113 | }, callback);
114 | };
115 |
116 | Remind.countUnreadByUserAndType = function(username, type, callback) {
117 | commonDao.count(collectionName, {
118 | user: username,
119 | type: type,
120 | readed: false
121 | }, callback);
122 | };
--------------------------------------------------------------------------------
/routes/Model/Tag.js:
--------------------------------------------------------------------------------
1 | var commonDao = require("./CommonDAO.js"),
2 | collectionName = "tag",
3 | uuid = require("node-uuid"),
4 | __resultToListFn = function(callback) {
5 | return function(err, results) {
6 | var i;
7 | if (err) return callback(err);
8 | for (i = results.length; i--;) {
9 | results[i] = new Tag(results[i]);
10 | }
11 | callback(err, results);
12 |
13 | };
14 | };
15 |
16 | function Tag(tag) {
17 | this.name = tag.name;
18 | this.createTime = tag.createTime;
19 | this.id = tag.id;
20 | this.color = tag.color;
21 | }
22 |
23 | module.exports = Tag;
24 |
25 | Tag.prototype.save = function(callback) {
26 | commonDao.save(collectionName, {
27 | name: this.name,
28 | color: this.color,
29 | createTime: new Date().getTime(),
30 | id: uuid.v4()
31 | }, function(err, result) {
32 | if (err) return callback(err);
33 | if (!result[0]) return new Error("保存标签失败");
34 | return callback(err, new Tag(result[0]));
35 | });
36 | };
37 |
38 | Tag.get = function(id, callback) {
39 | commonDao.findOne(collectionName, {
40 | id: id
41 | }, function(err, result) {
42 | if (err) return callback(err);
43 | callback(err, result ? new Tag(result) : result);
44 | });
45 | };
46 |
47 | Tag.getAll = function(callback) {
48 | commonDao.find(collectionName, {
49 | sort: {
50 | createTime: -1
51 | }
52 | }, __resultToListFn(callback));
53 | };
54 |
55 | Tag.getByFuzzyName = function(name, callback) {
56 | commonDao.find(collectionName, {
57 | condition: {
58 | name: new RegExp(name)
59 | },
60 | sort: {
61 | createTime: -1
62 | }
63 | }, __resultToListFn(callback));
64 | };
--------------------------------------------------------------------------------
/routes/Model/User.js:
--------------------------------------------------------------------------------
1 | var commonDao = require("./CommonDAO.js"),
2 | collectionName = "user",
3 | __resultToListFn = function(callback) {
4 | return function(err, results) {
5 | var i;
6 | if (err) {
7 | return callback(err);
8 | }
9 | for (i = results.length; i--;) {
10 | results[i] = new User(results[i]);
11 | }
12 | callback(err, results);
13 |
14 | };
15 | };
16 |
17 | function User(user) {
18 | this.username = user.username;
19 | this.nickname = user.nickname;
20 | this.password = user.password;
21 | this.owner = user.owner;
22 | this.avatar = user.avatar;
23 | this.tags = user.tags;
24 | }
25 |
26 | module.exports = User;
27 |
28 | User.prototype.save = function(callback) {
29 | commonDao.save(collectionName, {
30 | username: this.username,
31 | password: this.password,
32 | nickname: this.nickname,
33 | owner: this.owner,
34 | avatar: this.avatar,
35 | tags: this.tags
36 | }, function(err, result) {
37 | if (err) return callback(err);
38 | if (!result[0]) return new Error("保存评论失败");
39 | return callback(err, new User(result[0]));
40 | });
41 | };
42 |
43 | User.prototype.remove = function(callback) {
44 | commonDao.remove(collectionName, {
45 | username: this.username
46 | }, callback);
47 | };
48 |
49 | User.prototype.update = function(callback) {
50 | commonDao.update(collectionName, {
51 | username: this.username
52 | }, {
53 | username: this.username,
54 | password: this.password,
55 | nickname: this.nickname,
56 | owner: this.owner,
57 | avatar: this.avatar,
58 | tags: this.tags
59 | }, callback);
60 | };
61 |
62 | User.get = function(username, callback) {
63 | commonDao.findOne(collectionName, {
64 | username: username
65 | }, function(err, result) {
66 | if (err) return callback(err);
67 | callback(err, result ? new User(result) : result);
68 | });
69 | };
70 |
71 | User.getAll = function(curPage, perPage, callback) {
72 | commonDao.find(collectionName, {
73 | page: {
74 | curPage: curPage,
75 | perPage: perPage
76 | },
77 | sort: {
78 | username: 1
79 | }
80 | }, __resultToListFn(callback));
81 | };
82 |
83 | User.countAll = function(callback) {
84 | commonDao.count(collectionName, {}, callback);
85 | };
--------------------------------------------------------------------------------
/routes/index.js:
--------------------------------------------------------------------------------
1 | var Article = require("./Model/Article.js"),
2 | User = require("./Model/User.js"),
3 | Comment = require("./Model/Comment.js"),
4 | Admire = require("./Model/Admire.js"),
5 | Bookmark = require("./Model/Bookmark.js"),
6 | markdown = require("markdown").markdown,
7 | async = require("async"),
8 | moment = require("moment");
9 |
10 | exports.index = function(req, res) {
11 | var page = (req.query.page || 1) - 1,
12 | artPerPage = req.query.artPerPage || 5;
13 | async.waterfall([
14 |
15 | function(callback) {
16 | Article.getAll(page, artPerPage, function(err, articles) {
17 | if (err) return callback(err);
18 | callback(err, articles);
19 | });
20 | },
21 | function(articles, callback) {
22 | Article.countAll(function(err, total) {
23 | if (err) return callback(err);
24 | callback(err, articles, total);
25 | });
26 | }
27 | ], function(err, articles, total) {
28 | var i,
29 | totalPage,
30 | curPage,
31 | startPage,
32 | endPage;
33 | if (err) return res.render("error", {
34 | message: "获取文章列表时发生错误..."
35 | });
36 | for (i = articles.length; i--;) {
37 | articles[i].content = markdown.toHTML(articles[i].content);
38 | articles[i].writeTime = moment(articles[i].writeTime).fromNow();
39 | }
40 | totalPage = Math.ceil(total / artPerPage);
41 | curPage = page + 1;
42 |
43 | if (curPage <= 2) {
44 | startPage = 1;
45 | endPage = totalPage >= 5 ? 5 : totalPage;
46 | } else if (curPage >= totalPage - 2) {
47 | endPage = totalPage;
48 | startPage = totalPage >= 5 ? totalPage - 4 : 1;
49 | } else {
50 | startPage = curPage - 2;
51 | endPage = curPage + 2;
52 | }
53 | res.render("index", {
54 | articles: articles,
55 | curPage: page + 1,
56 | artPerPage: artPerPage,
57 | totalPage: totalPage,
58 | startPage: startPage,
59 | endPage: endPage
60 | });
61 | });
62 | };
63 |
64 | exports.userCenter = function(req, res) {
65 | var username = req.query.username || req.session.user.username;
66 | User.get(username, function(err, user) {
67 | if (err) return res.render("error", {
68 | message: err.message
69 | });
70 | res.render("userCenter", {
71 | curUser: user
72 | });
73 | });
74 | };
75 |
76 | exports.advicePage = function(req, res) {
77 | res.render("advice");
78 | };
79 |
80 | exports.searchPage = function(req, res) {
81 | res.render("search");
82 | };
83 |
84 | exports.articleListPage = function(req, res){
85 | res.render("listArticle");
86 | };
--------------------------------------------------------------------------------
/routes/setting.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | if(!fs.existsSync("upload_tmp")){
3 | fs.mkdirSync("upload_tmp");
4 | }
5 |
6 | if(!fs.existsSync("public/gallary_sm")){
7 | fs.mkdirSync("public/gallary_sm");
8 | }
9 |
10 | if(!fs.existsSync("public/gallary")){
11 | fs.mkdirSync("public/gallary");
12 | }
13 |
14 | module.exports = {
15 | //本地数据库测试
16 | host : process.env.DB || "mongodb://127.0.0.1:27017/myblog",
17 | gallary : {
18 | small : "gallary_sm",
19 | name : "gallary"
20 | },
21 | uploadDir : "upload_tmp"
22 | };
--------------------------------------------------------------------------------
/upload_tmp/5792-oxlaq1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/80e5fba805415f2110a13bb3c1705258b079f744/upload_tmp/5792-oxlaq1.jpg
--------------------------------------------------------------------------------
/views/advice.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 |
5 | block content
6 | div(class="container")
7 | div(class="jumbotron u-panel", style="margin-top:50px")
8 | h1 感谢您提供宝贵的意见
9 | p 如果您对这个博客有任何意见和建议,或者遇到了任何bug,均可在此进行提交
10 | p 如果您喜欢这个博客,请分享给你的好友:
11 | div(class="jiathis_style_32x32")
12 | a(class="jiathis_button_qzone")
13 | a(class="jiathis_button_tsina")
14 | a(class="jiathis_button_tqq")
15 | a(class="jiathis_button_renren")
16 | a(class="jiathis_button_kaixin001")
17 | a(href="http://www.jiathis.com/share", class="jiathis jiathis_txt jtico jtico_jiathis", target="_blank")
18 | a(class="jiathis_counter_style")
19 | div(class="clearfix")
20 | div(class = "ds-thread")
21 |
22 | block javascript
23 | script(type="text/javascript",src="http://v3.jiathis.com/code/jia.js",charset="utf-8")
24 | script(type = 'text/javascript')
25 | var duoshuoQuery = {
26 | short_name: "skyinlayer"
27 | };
28 | (function() {
29 | var ds = document.createElement('script');
30 | ds.type = 'text/javascript';
31 | ds.async = true;
32 | ds.src = 'http://static.duoshuo.com/embed.js';
33 | ds.charset = 'UTF-8';
34 | (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ds);
35 | })();
36 |
37 |
--------------------------------------------------------------------------------
/views/articleDetail.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | link(rel='stylesheet', href='/stylesheets/github.css')
5 | link(rel='stylesheet', href='/stylesheets/pageTools/tag.css')
6 | link(rel='stylesheet', href='/stylesheets/pageTools/admire.css')
7 | link(rel='stylesheet', href='/stylesheets/pageTools/comment.css')
8 | link(rel='stylesheet', href='/stylesheets/pageTools/user.css')
9 | link(rel='stylesheet', href='/stylesheets/pageTools/bookmark.css')
10 | link(rel='stylesheet', href='/stylesheets/page/articleDetail.css')
11 | //- script(src="http://tjs.sjs.sinajs.cn/open/api/js/wb.js", type="text/javascript", charset="utf-8")
12 | block content
13 | div(class="container")
14 | div(class="g-art", id="artBody")
15 | div(class="u-panel g-art-body")
16 | div(class="u-flag")
17 | div(class="u-flag-left")
18 | h3
19 | !=article.title
20 | section
21 | !=article.content
22 | div(class="g-art-footer")
23 | div(id="bookmark", aid="#{article.id}", cur=user?"#{user.username}":"")
24 | div(style="float:right;padding:5px 10px")
25 | //- wb:share-button(appkey="1yj5nG", addition="number", type="button", default_text="#{article.title} 来自 天镶的博客", ralateUid="1162383197")
26 | div(class="clearfix")
27 | hr
28 | div(id="comments", aid="#{article.id}", cur="0", curUser=user?"#{user.username}":"")
29 | div(class="g-container")
30 | div(class="u-more") 点击获取更多
31 |
32 | div(id="replyComment", class="g-reply-form")
33 | form(action="/nor/comment_addComment", method="post")
34 | input(type="hidden", name="articleId", value="#{article.id}")
35 | input(type="hidden", name="replyId")
36 | div(class="form-group")
37 | textarea(class="form-control", name="comment", id="inputComment", style="resize: none", rows=2)
38 | div(class="form-group")
39 | button(class="btn btn-success", type="submit", style="float:right") 发送
40 | div(class="clearfix")
41 |
42 | div(id="newComments")
43 | if user
44 | h3 新评论:
45 | form(action="/nor/comment_addComment", method="post")
46 | input(type="hidden", name="articleId", value="#{article.id}")
47 | div(class="form-group")
48 | textarea(class="form-control", name="comment", id="inputComment", style="resize: none", rows=4)
49 | div(class="form-group")
50 | button(class="btn btn-success", id="sendComment", type="submit", style="float:left") 发送
51 | button(class="btn btn-danger", type="button" ,id="clearComment", style="float:right") 清空
52 | else
53 | h3(style="text-align:center") 请登录后评论
54 | div(class="g-art-info hidden-sm")
55 | div(class="u-panel")
56 | div(class="g-user")
57 | div(class="u-avatar", uid="#{article.writer}")
58 | div(class="u-nick")
59 | div(class="clearfix")
60 | div(class="u-time") #{"作于: " + article.writeTime}
61 | if user&&user.owner
62 | div(class="g-opt")
63 | a(class="btn btn-primary", style="width:100%;margin-top:10px", href="/nor/conf/article_edit?articleId=#{article.id}") 修改
64 | button(class="btn btn-danger", aid="#{article.id}",style="width:100%;margin-top:10px", id="deleteArticle") 删除
65 | div(class="u-panel", style="margin-top: 20px") 文章标签:
66 | div(class="u-tags", id="tags", aid="#{article.id}")
67 |
68 | block javascript
69 | script(type='text/javascript', src='/javascripts/tools/highlight.pack.js')
70 | script(type='text/javascript', src='/javascripts/pageTools/Tag.js')
71 | script(type='text/javascript', src='/javascripts/pageTools/Admire.js')
72 | script(type='text/javascript', src='/javascripts/pageTools/Comment.js')
73 | script(type='text/javascript', src='/javascripts/pageTools/Article.js')
74 | script(type='text/javascript', src='/javascripts/pageTools/User.js')
75 | script(type='text/javascript', src='/javascripts/pageTools/Bookmark.js')
76 | script(type='text/javascript', src='/javascripts/page/articleDetail.js')
--------------------------------------------------------------------------------
/views/broadchat.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | style(type="text/stylesheet")
5 | .g-row {
6 | width: 100%;
7 | margin-top:40px;
8 | }
9 | .g-row:after{
10 | content:"";
11 | display: table;
12 | clear:both;
13 | }
14 | block content
15 | div(class="container")
16 | h2
17 | strong 版聊
18 | div(class="g-row", style="font-size:120%;font-weight: bolder")
19 | div(class="", style="width: 32%;float:right")
20 | div(class="u-panel", id="users") 版上的用户:
21 | hr
22 | div(class="u-panel", style="margin-top:20px", id="logs")
23 | div(class="u-panel", style="width: 66%;float:left")
24 | div(class="panel-body",nick=user?"#{user.nickname}":"游客", id="chat")
25 | div(class="form-group", style="padding: 20px 0;")
26 | input(type="text",class="form-control", style="width: 83%;float:left", id="message")
27 | button(class="btn btn-success", style="width: 15%;float:right", id="send") 发送
28 | div(class="form-group", style="padding: 20px 0;")
29 | input(type="text",class="form-control", style="width: 83%;float:left", id="nickname")
30 | button(class="btn btn-success", style="width: 15%;float:right", id="changeNick") 修改昵称
31 |
32 |
33 | block javascript
34 | script(type='text/javascript', src="/javascripts/exp/broadchat.js")
35 |
36 |
--------------------------------------------------------------------------------
/views/editArticle.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | link(rel='stylesheet', href='/stylesheets/github.css')
5 | link(rel='stylesheet', href='/stylesheets/pageTools/tag.css')
6 | link(rel='stylesheet', href='/stylesheets/page/writeArticle.css')
7 | block content
8 | div(class="container")
9 | h2
10 | strong 修改文章
11 | div(class="u-panel")
12 | div(class="alert alert-danger", id="formValidate", style="display:none")
13 | div(class="form-group")
14 | label(for="inputTitle")
15 | h3 标题:
16 | input(class="form-control", type="text", id="inputTitle", placeholder="文章标题", value="#{article.title}")
17 | div(class="panel", style="padding:10px;height:80%;background:transparent")
18 | div(class="u-panel-body" id="leftPanel")
19 | textarea(class="u-pane", id="inputArticle", style="resize: none;")
20 | =article.content
21 | div(class="u-panel-body" id="rightPanel")
22 | div(class="u-pane", id="outputArticle")
23 | div(style="clear:both")
24 | div(class="row")
25 | input(type="hidden", name="tags")
26 | div(class="col-md-6")
27 | h2 本文标签
28 | hr
29 | div(id="articleTags", aid="#{article.id}")
30 | div(class="col-md-6")
31 | h2 所有标签
32 | hr
33 | div(id="allTags")
34 | hr
35 | span(class="label b-label-1", style="padding:8px 5px", id="newTag")
36 | input(id="newTagInput",type="text", placeholder="标签名", color="#428bca")
37 | span(class="glyphicon glyphicon-plus u-tag-create", style="margin-left:5px;cursor:pointer", id="createTag")
38 | span(class="label b-label-1 u-label-picker", value=1, color="#428bca") 深蓝
39 | span(class="label b-label-2 u-label-picker", value=2, color="#5cb85c") 绿色
40 | span(class="label b-label-3 u-label-picker", value=3, color="#5cb0de") 淡蓝
41 | span(class="label b-label-4 u-label-picker", value=4, color="#f0ad4e") 黄色
42 | span(class="label b-label-5 u-label-picker", value=5, color="#d9543f") 红色
43 | div(class="form-group", style="margin-top:20px")
44 | button(class="btn btn-primary", style="width:100%", id="saveArtBtn", aid="#{article.id}") 保存文章
45 |
46 | block javascript
47 | script(type='text/javascript', src='/javascripts/tools/showdown.js')
48 | script(type='text/javascript', src='/javascripts/tools/highlight.pack.js')
49 | script(type='text/javascript', src='/javascripts/pageTools/Tag.js')
50 | script(type='text/javascript', src='/javascripts/page/editArticle.js')
51 |
--------------------------------------------------------------------------------
/views/error.jade:
--------------------------------------------------------------------------------
1 | #{message}
--------------------------------------------------------------------------------
/views/gallary.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | link(rel='stylesheet', href='/stylesheets/page/gallary.css')
5 | block content
6 | div(class="u-block", id="blocker")
7 | div(class="u-loading") 加载中,请等待
8 | div(class="u-fillPic", id="filler")
9 | div(class="u-opt u-close")
10 | span(class="glyphicon glyphicon-remove")
11 | center
12 | img
13 | div(class="container")
14 | div(id="gallary", class="row")
15 | div(class="col-sm-3 g-gal-col", index=0, id="col-0")
16 | div(class="col-sm-3 g-gal-col", index=1, id="col-1")
17 | div(class="col-sm-3 g-gal-col", index=2, id="col-2")
18 | div(class="col-sm-3 g-gal-col", index=3, id="col-3")
19 | div(class="clearfix")
20 | div(class="scrollFooter" ) 加载中,请稍后
21 | if user&&user.owner
22 | div(class="glyphicon glyphicon-trash u-conf-opt u-trash", id="trash")
23 | div(class="glyphicon glyphicon-upload u-conf-opt u-upload", id="upload")
24 | block javascript
25 | script(type='text/javascript', src='/javascripts/tools/jquery-mousewheel.js')
26 | script(type='text/javascript', src='/javascripts/page/gallary.js')
--------------------------------------------------------------------------------
/views/index.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | link(rel='stylesheet', href='/stylesheets/github.css')
5 | link(rel='stylesheet', href='/stylesheets/pageTools/tag.css')
6 | link(rel='stylesheet', href='/stylesheets/pageTools/user.css')
7 | link(rel='stylesheet', href='/stylesheets/pageTools/comment.css')
8 | link(rel='stylesheet', href='/stylesheets/pageTools/bookmark.css')
9 | link(rel='stylesheet', href='/stylesheets/page/index.css')
10 | block content
11 | div(class='container', style="padding-top: 20px")
12 | each article in articles
13 | div(class="row" style="")
14 | div(class='g-art-info')
15 | div(class="u-avatar", uid="#{article.writer}")
16 | div(class="u-time") #{article.writeTime}
17 |
18 | div(class='g-art-body')
19 | div(class="u-dot")
20 | div(class="u-panel", aid="#{article.id}")
21 | div(class="u-title")
22 | h3 #{article.title}
23 | hr
24 | div
25 | !=article.content
26 | hr
27 | div(class="g-art-footer")
28 | div(class="m-tags", aid="#{article.id}")
29 | div(class="u-item u-book", aid="#{article.id}", cur=user?"#{user.username}":"")
30 | div(class="u-item u-comment", aid="#{article.id}")
31 | div(class="clearfix")
32 | ul(class="pager")
33 | li(class=curPage===1?"previous disabled" : "previous")
34 | a(href=curPage===1?"javascript:void(0)":"/index?page=#{curPage-1}")
35 | ←上一页
36 | li(class=curPage===totalPage?"next disabled" : "next")
37 | a(href=curPage===totalPage?"javascript:void(0)":"/index?page=#{curPage+1}")
38 | →下一页
39 |
40 | block javascript
41 | script(type='text/javascript', src='/javascripts/tools/highlight.pack.js')
42 | script(type='text/javascript', src='/javascripts/pageTools/Tag.js')
43 | script(type='text/javascript', src='/javascripts/pageTools/User.js')
44 | script(type='text/javascript', src='/javascripts/pageTools/Comment.js')
45 | script(type='text/javascript', src='/javascripts/pageTools/Bookmark.js')
46 | script(type='text/javascript', src='/javascripts/page/index.js')
--------------------------------------------------------------------------------
/views/layout.jade:
--------------------------------------------------------------------------------
1 | doctype 5
2 | html(xmlns:wb="http://open.weibo.com/wb")
3 | head
4 | meta(property="wb:webmaster", content="8984d0c69a7d9445")
5 | meta(name="description", content="天镶的博客,使用nodejs+mongodb搭建")
6 | meta(name="keywords", content="天镶,博客,skyinlayer,nodejs,mongodb,前端,html,css,javascript")
7 | title 天镶的博客
8 | link(rel="shortcut icon", href="/favicon.ico", type="image/x-icon")
9 | link(rel='stylesheet', href='/stylesheets/bootstrap.min.css')
10 | link(rel='stylesheet', href='/stylesheets/pageTools/remind.css')
11 | link(rel='stylesheet', href='/stylesheets/style.css')
12 | block style
13 |
14 | body
15 | div(class="b-clouds")
16 | div(class="clouds")
17 | div(class="cloud cloud-lg", style="left: 10%;top: 20%")
18 | div(class="cloud cloud-sm", style="top: 30%")
19 | div(class="cloud cloud-md", style="left: 20%;top: 50%")
20 | div(class="cloud cloud-lg", style="left: 60%;top: 20%")
21 | div(class="cloud cloud-sm", style="left: 50%;top: 30%")
22 | div(class="cloud cloud-md", style="left: 70%;top: 40%")
23 | div(class="block")
24 | div(class="scrollToTop", style="display:none", id="scrollToTop")
25 | span(class="glyphicon glyphicon-arrow-up")
26 | div(class='navbar navbar-inverse navbar-fixed-top')
27 | div(class="container")
28 | div(class='navbar-header')
29 | button(type='button', class='navbar-toggle', data-toggle='collapse', data-target='.navbar-collapse')
30 | span(class='icon-bar')
31 | span(class='icon-bar')
32 | span(class='icon-bar')
33 | a(class='navbar-brand', href='/index') 天镶的博客
34 |
35 | div(class='collapse navbar-collapse')
36 | ul(class='nav navbar-nav')
37 | li
38 | a(href='/index') 首页
39 | li
40 | a(href='/articleList') 文章列表
41 | li
42 | a(href='/search') 搜索
43 | li
44 | a(href='/gallary') 图片墙
45 | li(class="dropdown")
46 | a(href="#", class="dropdown-toggle", data-toggle="dropdown") 小玩意
47 | b(class="caret")
48 | ul(class="dropdown-menu")
49 | li
50 | a(href="/broadchat") 版聊
51 | li
52 | a(href="/advicePage") 建议
53 | if user
54 | li
55 | a(href="/userCenter") 个人中心
56 | ul(class='nav navbar-nav navbar-right')
57 | if user
58 | li(class="dropdown")
59 | a(href="#", class="dropdown-toggle", data-toggle="dropdown", id="hasRemind")
60 | li(class="dropdown")
61 | a(href="#", class="dropdown-toggle", data-toggle="dropdown") #{user.nickname}
62 | b(class="caret")
63 | ul(class="dropdown-menu")
64 | if user.owner
65 | li
66 | a(href="/nor/conf/article_write") 写新文章
67 | li
68 | a(href="/article_list") 管理文章
69 | li
70 | a(href="/nor/user_detail") 修改个人信息
71 | li
72 | a(href="/user_logout") 登出
73 | else
74 | li
75 | a(href='/user_loginPage') 登录
76 | div(class="g-main")
77 | block content
78 | div(class="footer")
79 | hr
80 | p LingyuCoder 2013
81 |
82 | script(type='text/javascript', src='/javascripts/tools/jquery-1.10.2.min.js')
83 | script(type='text/javascript', src='/javascripts/tools/bootstrap.min.js')
84 | script(type='text/javascript', src='/javascripts/pageTools/Remind.js')
85 | script(type='text/javascript', src='/javascripts/page/global.js')
86 |
87 | block javascript
88 |
--------------------------------------------------------------------------------
/views/listArticle.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | link(rel='stylesheet', href='/stylesheets/github.css')
5 | link(rel='stylesheet', href='/stylesheets/page/listArticle.css')
6 | block content
7 | div(class="container")
8 | div(class="g-arts")
9 | div(class="u-panel u-more") 向下滚动加载更多
10 |
11 | block javascript
12 | script(type='text/javascript', src='/javascripts/tools/highlight.pack.js')
13 | script(type='text/javascript', src='/javascripts/pageTools/User.js')
14 | script(type='text/javascript', src='/javascripts/pageTools/Article.js')
15 | script(type='text/javascript', src='/javascripts/page/listArticle.js')
16 | if user && user.owner
17 | script(type='text/javascript', src='/javascripts/page/listArticle_owner.js')
--------------------------------------------------------------------------------
/views/login.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | div(class='container')
5 | h1
6 | strong 登录
7 | if message
8 | div(class='alert alert-danger') #{message}
9 | div(class="alert alert-danger", id="formValidate", style="display:none")
10 | div(class="u-panel")
11 | div(class="panel-body")
12 | form(class="form-horizontal", method="post", action="/user_login", id="loginForm")
13 | div(class="form-group")
14 | label(for="inputUsername", class="col-sm-2 col-sm-offset-2 control-label") 用户名
15 | div(class="col-sm-5")
16 | input(type="text", name="username", class="form-control", id="inputUsername", placeholder="用户名")
17 | div(class="form-group")
18 | label(for="inputPassword", class="col-sm-2 col-sm-offset-2 control-label") 密码
19 | div(class="col-sm-5")
20 | input(type="password", name="password", class="form-control", id="inputPassword", placeholder="填写密码")
21 | div(class="form-group")
22 | button(type='submit', id='loginBtn', class='btn btn-success col-sm-1 col-sm-offset-4') 登录
23 | a(href="user_registPage", class="btn btn-primary col-sm-1 col-sm-offset-2") 注册
24 |
25 | block javascript
26 | script(type='text/javascript', src='/javascripts/page/login.js')
--------------------------------------------------------------------------------
/views/regist.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | div(class='container')
5 | h1
6 | strong 注册
7 | if message
8 | div(class="alert alert-danger") #{message}
9 | div(class="alert alert-danger", id="formValidate", style="display:none")
10 | div(class="u-panel")
11 | div(class="panel-body")
12 | form(class="form-horizontal", method="post", action="/user_regist", id="registForm")
13 | div(class="form-group")
14 | label(for="inputUsername", class="col-sm-2 col-sm-offset-2 control-label") 用户名
15 | div(class="col-sm-5")
16 | input(type="text", name="username", class="form-control", id="inputUsername", placeholder="用户名")
17 | div(class="form-group")
18 | label(for="inputNickname", class="col-sm-2 col-sm-offset-2 control-label") 昵称
19 | div(class="col-sm-5")
20 | input(type="text", name="nickname", class="form-control", id="inputNickname", placeholder="昵称")
21 | div(class="form-group")
22 | label(for="inputPassword", class="col-sm-2 col-sm-offset-2 control-label") 密码
23 | div(class="col-sm-5")
24 | input(type="password", name="password", class="form-control", id="inputPassword", placeholder="填写密码")
25 | div(class="form-group")
26 | label(for="inputPassAgain", class="col-sm-2 col-sm-offset-2 control-label") 密码重复
27 | div(class="col-sm-5")
28 | input(type="password", name="passAgain", class="form-control", id="inputPassAgain", placeholder="再次填写密码")
29 | div(class="form-group")
30 | button(type="submit" class="col-sm-1 col-sm-offset-4 btn btn-success") 注册
31 | a(class="col-sm-offset-2 col-sm-1 btn btn-primary", href="user_loginPage") 登录
32 |
33 | block javascript
34 | script(type='text/javascript', src='/javascripts/page/regist.js')
35 |
36 |
--------------------------------------------------------------------------------
/views/search.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | link(rel='stylesheet', href='/stylesheets/pageTools/tag.css')
5 | link(rel='stylesheet', href='/stylesheets/page/search.css')
6 |
7 | block content
8 | div(class="container")
9 | div(class="row", style="margin-top:40px")
10 | div(class="col-sm-8")
11 | div(class="g-arts u-panel")
12 | div(id="articles", curPage=0)
13 | div(class="u-more", id="more") 请根据条件进行搜索
14 | div(class="col-sm-4")
15 | div(class="g-tags u-panel")
16 | h3 标签搜索:
17 | hr
18 | div(id="tags")
19 | hr
20 | p 已选择标签:
21 | div(id="chosenTags")
22 | hr
23 | button(class="btn btn-success", id="tagSearchBtn") 给我搜
24 | div(class="g-tags u-panel")
25 | h3 标题搜索:
26 | hr
27 | input(class="form-control", type="text", id="titleSearchInput", placeholder="请输入部分标题")
28 | hr
29 | button(class="btn btn-success", id="titleSearchBtn") 给我搜
30 |
31 | block javascript
32 | script(type='text/javascript', src="/javascripts/pageTools/Tag.js")
33 | script(type='text/javascript', src="/javascripts/pageTools/Article.js")
34 | script(type='text/javascript', src="/javascripts/pageTools/User.js")
35 | script(type='text/javascript', src="/javascripts/page/search.js")
36 |
37 |
--------------------------------------------------------------------------------
/views/userCenter.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | link(rel='stylesheet', href='/stylesheets/pageTools/comment.css')
5 | link(rel='stylesheet', href='/stylesheets/pageTools/tag.css')
6 | link(rel='stylesheet', href='/stylesheets/pageTools/admire.css')
7 | link(rel='stylesheet', href='/stylesheets/pageTools/user.css')
8 | link(rel='stylesheet', href='/stylesheets/pageTools/bookmark.css')
9 | link(rel='stylesheet', href='/stylesheets/pageTools/admire.css')
10 | link(rel='stylesheet', href='/stylesheets/pageTools/article.css')
11 | link(rel='stylesheet', href='/stylesheets/page/userCenter.css')
12 |
13 | block content
14 | input(type="hidden", id="user", uid=user?"#{user.username}":"")
15 | input(type="hidden", id="curUser", uid="#{curUser.username}")
16 | div(class='container')
17 | h1
18 | div(style="float:left")
19 | strong #{curUser.nickname}的用户中心
20 | div(class="u-avatar", style="float:right", id="user")
21 | div(class="clearfix")
22 |
23 | div(class="g-row")
24 | div(class="g-left")
25 | div(class="list-group u-panel", id="chosePanel", style="padding:0;border-radius:20px;overflow:hidden")
26 | if user&&curUser.username === user.username
27 | a(href="#", class="list-group-item", ref="getComments") 收到的评论
28 | span(class="badge pull-right remind-count", type="comment")
29 | a(href="#", class="list-group-item", ref="getAdmires") 收到的贊
30 | span(class="badge pull-right remind-count", type="admire")
31 | a(href="#", class="list-group-item", ref="getBookmarks") 收到的收藏
32 | span(class="badge pull-right remind-count", type="bookmark")
33 | if curUser.owner
34 | a(href="#", class="list-group-item", ref="articles")
35 | if user&&curUser.username === user.username
36 | != "我的文章"
37 | else
38 | != "ta的文章"
39 | span(class="badge pull-right article-count")
40 | a(href="#", class=curUser.owner?"list-group-item" : "list-group-item active", ref="bookmarks")
41 | if user&&curUser.username === user.username
42 | != "我的收藏"
43 | else
44 | != "ta的收藏"
45 | span(class="badge pull-right bookmark-count")
46 | a(href="#", class="list-group-item", ref="comments")
47 | if user&&curUser.username === user.username
48 | != "我的评论"
49 | else
50 | != "ta的评论"
51 | span(class="badge pull-right comment-count")
52 | a(href="#", class="list-group-item", ref="admires")
53 | if user&&curUser.username === user.username
54 | != "我赞过的评论"
55 | else
56 | != "ta赞过的评论"
57 | span(class="badge pull-right admire-count")
58 | div(class="u-panel", style="margin-top:20px")
59 | if user&&curUser.username === user.username
60 | != "我的标签:"
61 | else
62 | != "ta的标签:"
63 | div(id="tags")
64 | div(class="g-right")
65 | div(class="u-panel")
66 | if user&&curUser.username === user.username
67 | div(class="panel-body g-hide", id="getComments", cur="0")
68 | div(class="g-container")
69 | div(class="u-more") 点击加载更多
70 | div(class="panel-body g-hide", id="getAdmires", cur="0")
71 | div(class="g-container")
72 | div(class="u-more") 点击加载更多
73 | div(class="panel-body g-hide", id="getBookmarks", cur="0")
74 | div(class="g-container")
75 | div(class="u-more") 点击加载更多
76 | if curUser.owner
77 | div(class="panel-body g-hide", id="articles", cur="0")
78 | div(class="g-container")
79 | div(class="u-more") 点击加载更多
80 |
81 | div(class="panel-body g-hide", id="comments", cur="0")
82 | div(class="g-container")
83 | div(class="u-more") 点击加载更多
84 | div(class="panel-body g-hide", id="bookmarks", cur="0")
85 | div(class="g-container")
86 | div(class="u-more") 点击加载更多
87 | div(class="panel-body g-hide", id="admires", cur="0")
88 | div(class="g-container")
89 | div(class="u-more") 点击加载更多
90 |
91 | block javascript
92 | script(type='text/javascript', src='/javascripts/pageTools/User.js')
93 | script(type='text/javascript', src='/javascripts/pageTools/Tag.js')
94 | script(type='text/javascript', src='/javascripts/pageTools/Article.js')
95 | script(type='text/javascript', src='/javascripts/pageTools/Bookmark.js')
96 | script(type='text/javascript', src='/javascripts/pageTools/Admire.js')
97 | script(type='text/javascript', src='/javascripts/pageTools/Comment.js')
98 | script(type='text/javascript', src='/javascripts/page/userCenter.js')
--------------------------------------------------------------------------------
/views/userDetail.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | link(rel='stylesheet', href='/stylesheets/pageTools/tag.css')
5 | link(rel='stylesheet', href='/stylesheets/pageTools/user.css')
6 |
7 | block content
8 | div(class='container')
9 | h1
10 | strong 个人信息
11 | form(class="form-horizontal", method="post", action="/nor/user_modify", id="detail")
12 | div(class="u-panel")
13 | if message
14 | if success
15 | div(class="alert alert-success") #{message}
16 | else
17 | div(class="alert alert-danger") #{message}
18 | div(class="alert alert-danger", id="formValidate", style="display:none")
19 | div(class="form-group")
20 | label(for="inputUsername", class="col-sm-2 col-sm-offset-2 control-label") 用户名
21 | div(class="col-sm-4")
22 | input(type="text", name="username", readonly="readonly", class="form-control", id="inputUsername", value="#{user.username}")
23 | div(class="form-group")
24 | label(for="inputNickname", class="col-sm-2 col-sm-offset-2 control-label") 昵称
25 | div(class="col-sm-4")
26 | input(type="text", name="nickname", class="form-control", id="inputNickname", value="#{user.nickname}")
27 | div(class="form-group")
28 | label(for="inputAvatar", class="col-sm-2 col-sm-offset-2 control-label") 头像地址
29 | div(class="col-sm-4")
30 | input(type="text", name="avatar", class="form-control", id="inputAvatar", value="#{user.avatar}")
31 | div(class="form-group")
32 | label(class="col-sm-2 col-sm-offset-2 control-label") 头像预览
33 | div(class="col-sm-4")
34 | div(class="u-user-avatar")
35 | img(src="#{user.avatar}",id="avatarPreview")
36 | div(class="form-group")
37 | label(for="inputPassword", class="col-sm-2 col-sm-offset-2 control-label") 密码
38 | div(class="col-sm-4")
39 | input(type="password", name="password", class="form-control", id="inputPassword", placeholder="填写密码,为空则不修改")
40 | div(class="form-group")
41 | label(for="inputPassAgain", class="col-sm-2 col-sm-offset-2 control-label") 密码重复
42 | div(class="col-sm-4")
43 | input(type="password", name="passwordAgain", class="form-control", id="inputPassAgain", placeholder="再次填写密码")
44 | div(class="form-group", style="margin-top:20px")
45 | input(type="hidden", name="tags")
46 | div(class="col-sm-6")
47 | div(class="u-panel")
48 | h3 您的标签
49 | hr
50 | div(id="myTags", class="m-myTags")
51 | div(class="col-sm-6")
52 | div(class="u-panel")
53 | h3 所有标签
54 | hr
55 | div(id="allTags", class="m-allTags")
56 | hr
57 | span(class="label b-label-1", style="padding:8px 5px", id="newTag")
58 | input(id="newTagInput", type="text", placeholder="标签名", color="#428bca")
59 | span(class="glyphicon glyphicon-plus u-tag-create", style="margin-left:5px;cursor:pointer", id="createTag")
60 | span(class="label b-label-1 u-label-picker", value=1, color="#428bca") 深蓝
61 | span(class="label b-label-2 u-label-picker", value=2, color="#5cb85c") 绿色
62 | span(class="label b-label-3 u-label-picker", value=3, color="#5cb0de") 淡蓝
63 | span(class="label b-label-4 u-label-picker", value=4, color="#f0ad4e") 黄色
64 | span(class="label b-label-5 u-label-picker", value=5, color="#d9543f") 红色
65 | div(class="form-group")
66 | button(type="submit" class="col-sm-offset-3 col-sm-2 btn btn-primary") 提交修改
67 | a(class="btn btn-default col-sm-offset-2 col-sm-2", href="user_detail") 恢复
68 |
69 | block javascript
70 | script(type='text/javascript', src='/javascripts/pageTools/Tag.js')
71 | script(type='text/javascript', src='/javascripts/page/userDetail.js')
72 |
73 |
--------------------------------------------------------------------------------
/views/writeArticle.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block style
4 | link(rel='stylesheet', href='/stylesheets/github.css')
5 | link(rel='stylesheet', href='/stylesheets/pageTools/tag.css')
6 | link(rel='stylesheet', href='/stylesheets/page/writeArticle.css')
7 |
8 | block content
9 | div(class="container")
10 | form(action="/nor/conf/article_save", method="post", id="articleForm")
11 | h2
12 | strong 写新文章
13 | div(class="u-panel")
14 | div(class="alert alert-danger", id="formValidate", style="display:none")
15 |
16 | div(class="form-group")
17 | label(for="inputTitle")
18 | h3 标题:
19 | input(class="form-control", type="text", name="title",id="inputTitle", placeholder="文章标题")
20 | div(class="panel panel-default", style="padding:10px;height:80%")
21 | div(class="u-panel-body" id="leftPanel")
22 | textarea(class="u-pane", id="inputArticle", name="content",style="resize: none;")
23 | div(class="u-panel-body" id="rightPanel")
24 | div(class="u-pane", id="outputArticle")
25 | div(style="clear:both")
26 | div(class="row")
27 | input(type="hidden", name="tags")
28 | div(class="col-sm-6")
29 | h2 本文标签
30 | hr
31 | div(id="articleTags")
32 | div(class="col-sm-6")
33 | h2 所有标签
34 | hr
35 | div(id="allTags")
36 | hr
37 | span(class="label b-label-1", style="padding:8px 5px", id="newTag")
38 | input(id="newTagInput",type="text", placeholder="标签名", color="#428bca")
39 | span(class="glyphicon glyphicon-plus u-tag-create", style="margin-left:5px;cursor:pointer", id="createTag")
40 | span(class="label b-label-1 u-label-picker", value=1, color="#428bca") 深蓝
41 | span(class="label b-label-2 u-label-picker", value=2, color="#5cb85c") 绿色
42 | span(class="label b-label-3 u-label-picker", value=3, color="#5cb0de") 淡蓝
43 | span(class="label b-label-4 u-label-picker", value=4, color="#f0ad4e") 黄色
44 | span(class="label b-label-5 u-label-picker", value=5, color="#d9543f") 红色
45 | div(class="form-group", style="margin-top:20px")
46 | button(class="btn btn-primary", style="width:100%", id="saveArtBtn", type="submit") 保存文章
47 |
48 | block javascript
49 | script(type='text/javascript', src='/javascripts/tools/showdown.js')
50 | script(type='text/javascript', src='/javascripts/tools/showdown_extensions/twitter.js')
51 | script(type='text/javascript', src='/javascripts/tools/highlight.pack.js')
52 | script(type='text/javascript', src='/javascripts/pageTools/Tag.js')
53 | script(type='text/javascript', src='/javascripts/page/writeArticle.js')
--------------------------------------------------------------------------------