├── views
├── error.jade
├── listArticle.jade
├── gallary.jade
├── search.jade
├── advice.jade
├── broadchat.jade
├── login.jade
├── regist.jade
├── index.jade
├── editArticle.jade
├── writeArticle.jade
├── layout.jade
├── userDetail.jade
├── articleDetail.jade
└── userCenter.jade
├── public
├── 404
│ ├── boat.png
│ ├── cloud.png
│ ├── wave-back.png
│ ├── wave-front.png
│ ├── 404.html
│ └── 404.css
├── stylesheets
│ ├── page
│ │ ├── remind.css
│ │ ├── userDetail.css
│ │ ├── admire.css
│ │ ├── user.css
│ │ ├── bookmark.css
│ │ ├── writeArticle.css
│ │ ├── search.css
│ │ ├── uploadPic.css
│ │ ├── index.css
│ │ ├── tag.css
│ │ ├── articleDetail.css
│ │ ├── listArticle.css
│ │ ├── userCenter.css
│ │ ├── comment.css
│ │ └── gallary.css
│ ├── pageTools
│ │ ├── remind.css
│ │ ├── user.css
│ │ ├── article.css
│ │ ├── admire.css
│ │ ├── bookmark.css
│ │ ├── tag.css
│ │ └── comment.css
│ ├── github.css
│ ├── monokai.css
│ └── style.css
├── gallary
│ ├── 36.jpg
│ ├── 未来.JPG
│ ├── 无标题.jpg
│ ├── 97897383_2.jpg
│ ├── 1327390473_3dtj_4.jpg
│ ├── ae8e9a18ab19d23f4bedbce2.jpg
│ ├── large_nKru_2391000169cf1260.jpg
│ ├── 0750f1a8bb3bb36bc359cb9c6703f396.jpg
│ ├── 304be9c3a55a1b416cb91ada4875f0cb.jpg
│ ├── 347784364248d78f55c50f82fed7dd77.jpg
│ ├── 3622f6ee4bdcc69e40b2fd2a54562122.jpg
│ ├── 83146ca0gw1e5uv98fxwcj20c80nfdhs.jpg
│ ├── a3d96e7c85580ec6aef37b242a9ed451.jpg
│ ├── original_5fSW_59ff000093b9118c.jpg
│ ├── original_DVSi_2346000169651260.jpg
│ ├── u=553037556,1932829573&fm=9&gp=0.jpg
│ ├── 205cdf88d43f879491629c4bd21b0ef41ad53acb.jpg
│ ├── 25c9c636afc37931e9ac3401e9c4b74542a9118f.jpg
│ ├── 2fb27610b912c8fc769546e5fe039245d6882169.jpg
│ ├── 472309f7905298227ea53ce9d5ca7bcb0a46d401.jpg
│ ├── 57e853d9f2d3572c9c93a2f98813632762d0c35f.jpg
│ ├── 70ccd1fe9925bc31a8c823b35cdf8db1cb137039.jpg
│ ├── aa18972bd40735fab975fa929c510fb30f240817.jpg
│ ├── bdc7a825bc315c60dd857dca8fb1cb13495477b8.jpg
│ ├── d6ca7bcb0a46f21f78d01634f7246b600d33aef5.jpg
│ ├── m2w690hq92lt_large_LE4J_0156000035c81260.jpg
│ ├── m2w690hq92lt_large_xlCV_77500001a647125f.jpg
│ ├── m2w690hq92lt_original_sKaq_414f00003ce9118c.jpg
│ └── 科拉传奇.The.Legend.of.Korra.S01E12.Chi_Eng.WEB-HR.AAC.1024X576.x264-YYeTs&SLOMO[01-10-12].JPG
├── images
│ ├── boat.png
│ ├── cloud.png
│ ├── favicon.ico
│ ├── loading.gif
│ ├── wave-back.png
│ ├── wave-front.png
│ └── default_avatar.jpg
├── gallary_sm
│ ├── 36.jpg
│ ├── 无标题.jpg
│ ├── 未来.JPG
│ ├── 97897383_2.jpg
│ ├── 1327390473_3dtj_4.jpg
│ ├── ae8e9a18ab19d23f4bedbce2.jpg
│ ├── large_nKru_2391000169cf1260.jpg
│ ├── original_5fSW_59ff000093b9118c.jpg
│ ├── original_DVSi_2346000169651260.jpg
│ ├── 0750f1a8bb3bb36bc359cb9c6703f396.jpg
│ ├── 304be9c3a55a1b416cb91ada4875f0cb.jpg
│ ├── 347784364248d78f55c50f82fed7dd77.jpg
│ ├── 3622f6ee4bdcc69e40b2fd2a54562122.jpg
│ ├── 83146ca0gw1e5uv98fxwcj20c80nfdhs.jpg
│ ├── a3d96e7c85580ec6aef37b242a9ed451.jpg
│ ├── u=553037556,1932829573&fm=9&gp=0.jpg
│ ├── 205cdf88d43f879491629c4bd21b0ef41ad53acb.jpg
│ ├── 25c9c636afc37931e9ac3401e9c4b74542a9118f.jpg
│ ├── 2fb27610b912c8fc769546e5fe039245d6882169.jpg
│ ├── 472309f7905298227ea53ce9d5ca7bcb0a46d401.jpg
│ ├── 57e853d9f2d3572c9c93a2f98813632762d0c35f.jpg
│ ├── 70ccd1fe9925bc31a8c823b35cdf8db1cb137039.jpg
│ ├── aa18972bd40735fab975fa929c510fb30f240817.jpg
│ ├── bdc7a825bc315c60dd857dca8fb1cb13495477b8.jpg
│ ├── d6ca7bcb0a46f21f78d01634f7246b600d33aef5.jpg
│ ├── m2w690hq92lt_large_LE4J_0156000035c81260.jpg
│ ├── m2w690hq92lt_large_xlCV_77500001a647125f.jpg
│ ├── m2w690hq92lt_original_sKaq_414f00003ce9118c.jpg
│ └── 科拉传奇.The.Legend.of.Korra.S01E12.Chi_Eng.WEB-HR.AAC.1024X576.x264-YYeTs&SLOMO[01-10-12].JPG
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
└── javascripts
│ ├── page
│ ├── listArticle_owner.js
│ ├── login.js
│ ├── index.js
│ ├── global.js
│ ├── regist.js
│ ├── listArticle.js
│ ├── userDetail.js
│ ├── writeArticle.js
│ ├── search.js
│ ├── editArticle.js
│ ├── uploadPic.js
│ └── articleDetail.js
│ ├── tools
│ └── showdown_extensions
│ │ ├── github.js
│ │ ├── prettify.js
│ │ ├── twitter.js
│ │ └── table.js
│ ├── pageTools
│ ├── User.js
│ └── Remind.js
│ └── exp
│ └── broadchat.js
├── routes
├── Actions
│ ├── ExpAction.js
│ ├── GallaryAction.js
│ ├── RemindAction.js
│ ├── TagAction.js
│ ├── AdmireAction.js
│ ├── BookmarkAction.js
│ ├── UserAction.js
│ ├── PictureAction.js
│ ├── CommentAction.js
│ └── ArticleAction.js
├── setting.js
├── Model
│ ├── Tag.js
│ ├── User.js
│ ├── Admire.js
│ ├── Comment.js
│ ├── Bookmark.js
│ ├── CommonDAO.js
│ ├── Remind.js
│ └── Article.js
└── index.js
├── upload_tmp
└── 5792-oxlaq1.jpg
├── package.json
├── .gitattributes
├── README.md
├── doc
├── home.md
├── user.md
├── commonDAO.md
├── bookmark.md
└── comment.md
├── articles
└── test.md
└── .gitignore
/views/error.jade:
--------------------------------------------------------------------------------
1 | #{message}
--------------------------------------------------------------------------------
/public/stylesheets/page/remind.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/stylesheets/page/userDetail.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/404/boat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/404/boat.png
--------------------------------------------------------------------------------
/public/404/cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/404/cloud.png
--------------------------------------------------------------------------------
/public/gallary/36.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/36.jpg
--------------------------------------------------------------------------------
/public/gallary/未来.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/未来.JPG
--------------------------------------------------------------------------------
/public/gallary/无标题.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/无标题.jpg
--------------------------------------------------------------------------------
/public/images/boat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/images/boat.png
--------------------------------------------------------------------------------
/public/images/cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/images/cloud.png
--------------------------------------------------------------------------------
/public/404/wave-back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/404/wave-back.png
--------------------------------------------------------------------------------
/public/404/wave-front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/404/wave-front.png
--------------------------------------------------------------------------------
/public/gallary_sm/36.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/36.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/无标题.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/无标题.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/未来.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/未来.JPG
--------------------------------------------------------------------------------
/public/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/images/favicon.ico
--------------------------------------------------------------------------------
/public/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/images/loading.gif
--------------------------------------------------------------------------------
/routes/Actions/ExpAction.js:
--------------------------------------------------------------------------------
1 | exports.broadchat = function(req, res) {
2 | res.render("broadchat");
3 | };
--------------------------------------------------------------------------------
/upload_tmp/5792-oxlaq1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/upload_tmp/5792-oxlaq1.jpg
--------------------------------------------------------------------------------
/public/images/wave-back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/images/wave-back.png
--------------------------------------------------------------------------------
/public/images/wave-front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/images/wave-front.png
--------------------------------------------------------------------------------
/public/gallary/97897383_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/97897383_2.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/97897383_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/97897383_2.jpg
--------------------------------------------------------------------------------
/public/images/default_avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/images/default_avatar.jpg
--------------------------------------------------------------------------------
/public/gallary/1327390473_3dtj_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/1327390473_3dtj_4.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/1327390473_3dtj_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/1327390473_3dtj_4.jpg
--------------------------------------------------------------------------------
/public/gallary/ae8e9a18ab19d23f4bedbce2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/ae8e9a18ab19d23f4bedbce2.jpg
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/public/gallary/large_nKru_2391000169cf1260.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/large_nKru_2391000169cf1260.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/ae8e9a18ab19d23f4bedbce2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/ae8e9a18ab19d23f4bedbce2.jpg
--------------------------------------------------------------------------------
/public/gallary/0750f1a8bb3bb36bc359cb9c6703f396.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/0750f1a8bb3bb36bc359cb9c6703f396.jpg
--------------------------------------------------------------------------------
/public/gallary/304be9c3a55a1b416cb91ada4875f0cb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/304be9c3a55a1b416cb91ada4875f0cb.jpg
--------------------------------------------------------------------------------
/public/gallary/347784364248d78f55c50f82fed7dd77.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/347784364248d78f55c50f82fed7dd77.jpg
--------------------------------------------------------------------------------
/public/gallary/3622f6ee4bdcc69e40b2fd2a54562122.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/3622f6ee4bdcc69e40b2fd2a54562122.jpg
--------------------------------------------------------------------------------
/public/gallary/83146ca0gw1e5uv98fxwcj20c80nfdhs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/83146ca0gw1e5uv98fxwcj20c80nfdhs.jpg
--------------------------------------------------------------------------------
/public/gallary/a3d96e7c85580ec6aef37b242a9ed451.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/a3d96e7c85580ec6aef37b242a9ed451.jpg
--------------------------------------------------------------------------------
/public/gallary/original_5fSW_59ff000093b9118c.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/original_5fSW_59ff000093b9118c.jpg
--------------------------------------------------------------------------------
/public/gallary/original_DVSi_2346000169651260.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/original_DVSi_2346000169651260.jpg
--------------------------------------------------------------------------------
/public/gallary/u=553037556,1932829573&fm=9&gp=0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/u=553037556,1932829573&fm=9&gp=0.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/large_nKru_2391000169cf1260.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/large_nKru_2391000169cf1260.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/original_5fSW_59ff000093b9118c.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/original_5fSW_59ff000093b9118c.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/original_DVSi_2346000169651260.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/original_DVSi_2346000169651260.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/0750f1a8bb3bb36bc359cb9c6703f396.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/0750f1a8bb3bb36bc359cb9c6703f396.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/304be9c3a55a1b416cb91ada4875f0cb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/304be9c3a55a1b416cb91ada4875f0cb.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/347784364248d78f55c50f82fed7dd77.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/347784364248d78f55c50f82fed7dd77.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/3622f6ee4bdcc69e40b2fd2a54562122.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/3622f6ee4bdcc69e40b2fd2a54562122.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/83146ca0gw1e5uv98fxwcj20c80nfdhs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/83146ca0gw1e5uv98fxwcj20c80nfdhs.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/a3d96e7c85580ec6aef37b242a9ed451.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/a3d96e7c85580ec6aef37b242a9ed451.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/u=553037556,1932829573&fm=9&gp=0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/u=553037556,1932829573&fm=9&gp=0.jpg
--------------------------------------------------------------------------------
/public/gallary/205cdf88d43f879491629c4bd21b0ef41ad53acb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/205cdf88d43f879491629c4bd21b0ef41ad53acb.jpg
--------------------------------------------------------------------------------
/public/gallary/25c9c636afc37931e9ac3401e9c4b74542a9118f.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/25c9c636afc37931e9ac3401e9c4b74542a9118f.jpg
--------------------------------------------------------------------------------
/public/gallary/2fb27610b912c8fc769546e5fe039245d6882169.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/2fb27610b912c8fc769546e5fe039245d6882169.jpg
--------------------------------------------------------------------------------
/public/gallary/472309f7905298227ea53ce9d5ca7bcb0a46d401.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/472309f7905298227ea53ce9d5ca7bcb0a46d401.jpg
--------------------------------------------------------------------------------
/public/gallary/57e853d9f2d3572c9c93a2f98813632762d0c35f.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/57e853d9f2d3572c9c93a2f98813632762d0c35f.jpg
--------------------------------------------------------------------------------
/public/gallary/70ccd1fe9925bc31a8c823b35cdf8db1cb137039.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/70ccd1fe9925bc31a8c823b35cdf8db1cb137039.jpg
--------------------------------------------------------------------------------
/public/gallary/aa18972bd40735fab975fa929c510fb30f240817.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/aa18972bd40735fab975fa929c510fb30f240817.jpg
--------------------------------------------------------------------------------
/public/gallary/bdc7a825bc315c60dd857dca8fb1cb13495477b8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/bdc7a825bc315c60dd857dca8fb1cb13495477b8.jpg
--------------------------------------------------------------------------------
/public/gallary/d6ca7bcb0a46f21f78d01634f7246b600d33aef5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/d6ca7bcb0a46f21f78d01634f7246b600d33aef5.jpg
--------------------------------------------------------------------------------
/public/gallary/m2w690hq92lt_large_LE4J_0156000035c81260.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/m2w690hq92lt_large_LE4J_0156000035c81260.jpg
--------------------------------------------------------------------------------
/public/gallary/m2w690hq92lt_large_xlCV_77500001a647125f.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/m2w690hq92lt_large_xlCV_77500001a647125f.jpg
--------------------------------------------------------------------------------
/public/gallary/m2w690hq92lt_original_sKaq_414f00003ce9118c.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/m2w690hq92lt_original_sKaq_414f00003ce9118c.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/205cdf88d43f879491629c4bd21b0ef41ad53acb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/205cdf88d43f879491629c4bd21b0ef41ad53acb.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/25c9c636afc37931e9ac3401e9c4b74542a9118f.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/25c9c636afc37931e9ac3401e9c4b74542a9118f.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/2fb27610b912c8fc769546e5fe039245d6882169.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/2fb27610b912c8fc769546e5fe039245d6882169.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/472309f7905298227ea53ce9d5ca7bcb0a46d401.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/472309f7905298227ea53ce9d5ca7bcb0a46d401.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/57e853d9f2d3572c9c93a2f98813632762d0c35f.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/57e853d9f2d3572c9c93a2f98813632762d0c35f.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/70ccd1fe9925bc31a8c823b35cdf8db1cb137039.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/70ccd1fe9925bc31a8c823b35cdf8db1cb137039.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/aa18972bd40735fab975fa929c510fb30f240817.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/aa18972bd40735fab975fa929c510fb30f240817.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/bdc7a825bc315c60dd857dca8fb1cb13495477b8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/bdc7a825bc315c60dd857dca8fb1cb13495477b8.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/d6ca7bcb0a46f21f78d01634f7246b600d33aef5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/d6ca7bcb0a46f21f78d01634f7246b600d33aef5.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/m2w690hq92lt_large_LE4J_0156000035c81260.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/m2w690hq92lt_large_LE4J_0156000035c81260.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/m2w690hq92lt_large_xlCV_77500001a647125f.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/m2w690hq92lt_large_xlCV_77500001a647125f.jpg
--------------------------------------------------------------------------------
/public/gallary_sm/m2w690hq92lt_original_sKaq_414f00003ce9118c.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/m2w690hq92lt_original_sKaq_414f00003ce9118c.jpg
--------------------------------------------------------------------------------
/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/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/gallary/科拉传奇.The.Legend.of.Korra.S01E12.Chi_Eng.WEB-HR.AAC.1024X576.x264-YYeTs&SLOMO[01-10-12].JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary/科拉传奇.The.Legend.of.Korra.S01E12.Chi_Eng.WEB-HR.AAC.1024X576.x264-YYeTs&SLOMO[01-10-12].JPG
--------------------------------------------------------------------------------
/public/gallary_sm/科拉传奇.The.Legend.of.Korra.S01E12.Chi_Eng.WEB-HR.AAC.1024X576.x264-YYeTs&SLOMO[01-10-12].JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LingyuCoder/NodeBlog/HEAD/public/gallary_sm/科拉传奇.The.Legend.of.Korra.S01E12.Chi_Eng.WEB-HR.AAC.1024X576.x264-YYeTs&SLOMO[01-10-12].JPG
--------------------------------------------------------------------------------
/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/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/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 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/public/javascripts/page/listArticle_owner.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | $(".u-delete").click(function(event) {
3 | var that = $(this);
4 | $.ajax({
5 | url: "/nor/conf/article_remove",
6 | data: {
7 | articleId: that.attr("aid")
8 | },
9 | dataType: "json",
10 | type: "get",
11 | }).done(function(data) {
12 | if(data.success){
13 | that.parent().parent().remove();
14 | }
15 | }).fail(function(err) {
16 | console.log(err.message);
17 | });
18 | event.stopPropagation();
19 | });
20 | }(jQuery, window));
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/public/javascripts/page/login.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var formValidate = $("#formValidate");
3 | $("#loginForm").submit(function(event){
4 | formValidate.hide();
5 | if (!this.username.value) {
6 | formValidate.text("请输入用户名").slideDown();
7 | $(this.username).focus();
8 | return false;
9 | }
10 | if (!this.password.value.match(/^[\w\-\u4e00-\u9fa5]{3,12}$/)) {
11 | formValidate.text("请输入密码").slideDown();
12 | $(this.password).focus();
13 | return false;
14 | }
15 | $(this).find("button[type='submit']").text("登陆中...").attr("disabled","disabled");
16 | });
17 | }(jQuery, window));
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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')
--------------------------------------------------------------------------------
/public/javascripts/page/index.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | $('pre code').each(function(i, e) {
3 | hljs.highlightBlock(e);
4 | });
5 |
6 | $(".m-tags").each(function() {
7 | var that = $(this),
8 | articleId = that.attr("aid");
9 | $(document).trigger("tag.drawArticleTags", [articleId, that]);
10 | });
11 |
12 | $(".u-avatar").each(function() {
13 | var that = $(this);
14 | $(document).trigger("user.draw", [that.attr("uid"), that]);
15 | });
16 |
17 | $(".u-comment").each(function() {
18 | $(document).trigger("comment.drawCount", [$(this).attr("aid"), $(this)]);
19 | });
20 |
21 | $(".u-book").each(function() {
22 | $(document).trigger("bookmark.draw", [$(this).attr("aid"), $(this), $(this).attr("cur")]);
23 | });
24 |
25 | $(".g-art-body .u-panel").click(function(event){
26 | window.location.href = "/article_load?articleId=" + $(this).attr("aid");
27 | });
28 |
29 | }(jQuery, window));
--------------------------------------------------------------------------------
/public/javascripts/tools/showdown_extensions/github.js:
--------------------------------------------------------------------------------
1 | //
2 | // Github Extension (WIP)
3 | // ~~strike-through~~ -> strike-through
4 | //
5 |
6 | (function(){
7 | var github = function(converter) {
8 | return [
9 | {
10 | // strike-through
11 | // NOTE: showdown already replaced "~" with "~T", so we need to adjust accordingly.
12 | type : 'lang',
13 | regex : '(~T){2}([^~]+)(~T){2}',
14 | replace : function(match, prefix, content, suffix) {
15 | return '' + content + '';
16 | }
17 | }
18 | ];
19 | };
20 |
21 | // Client-side export
22 | if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.github = github; }
23 | // Server-side export
24 | if (typeof module !== 'undefined') module.exports = github;
25 | }());
26 |
--------------------------------------------------------------------------------
/public/javascripts/page/global.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | $("#hasRemind").each(function() {
3 | var that = $(this);
4 | $(document).trigger("remind.countAll", [
5 |
6 | function(err, total) {
7 | if (err) {
8 | that.text("获取消息失败");
9 | }
10 | var $reminds;
11 | if (total === 0) {
12 | that.text("没有新消息");
13 | } else {
14 | that.append("" + total + "").append("新消息").append("");
15 | $reminds = $("
)?/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/404/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 啊哦,好像有什么东西找不到了
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 | }
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 | ### 表示层(施工中)
--------------------------------------------------------------------------------
/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')
--------------------------------------------------------------------------------
/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'])
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/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/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/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/javascripts/pageTools/User.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var emitter = $(document);
3 | emitter.bind({
4 | "user.draw": function(event, username, container, fnCallback) {
5 | container.addClass("b-user-loading");
6 | emitter.trigger("user.getInfo", [username,
7 | function(err, user) {
8 | if (err) {
9 | if (typeof fnCallback === "function") fnCallback(err);
10 | return;
11 | }
12 | var $a,
13 | $img,
14 | $tags;
15 | container = container;
16 | $a = $("");
17 | $img = $("
");
18 | $a.append($img);
19 | container.append($a);
20 | $tags = $("");
21 | $img.popover({
22 | title: user.nickname,
23 | placement: "bottom",
24 | html: true,
25 | content: $tags
26 | }).hover(function(event) {
27 | $img.popover("show");
28 | }, function(event) {
29 | $img.popover("hide");
30 | }).bind("show.bs.popover", function() {
31 | $tags.html("");
32 | $(document).trigger("tag.drawUserTags", [user.username, $tags]);
33 | });
34 | container.removeClass("b-user-loading").data("user", user);
35 | if (typeof fnCallback === "function") fnCallback(null, container);
36 | }
37 | ]);
38 | },
39 | "user.getInfo": function(event, username, fnCallback) {
40 | $.ajax({
41 | url: "/user_getDetail",
42 | data: {
43 | username: username
44 | },
45 | type: "post",
46 | dataType: "json"
47 | }).done(function(data) {
48 | if (typeof fnCallback === "function") fnCallback(null, data);
49 | }).fail(function(err) {
50 | if (typeof fnCallback === "function") fnCallback(err);
51 | });
52 | }
53 | });
54 | }(jQuery, window));
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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/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')
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/public/javascripts/page/listArticle.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var curPage = 0,
3 | MAX_PANELS = $(window).width() >= 992?3:2,
4 | __draw = function(article) {
5 | var $row = $(".g-row:last"),
6 | $arts = $(".g-arts"),
7 | $art;
8 | if ($(".g-art", $row).length === MAX_PANELS || $row.length === 0) {
9 | $row = $("").addClass("g-row");
10 | $arts.append($row);
11 | }
12 |
13 | $art = $("").addClass("u-panel g-art");
14 | $art.append("" + article.writeTime + "")
15 | .append("")
16 | .append("" + article.title + "")
17 | .click(function(event) {
18 | window.location.href = "/article_load?articleId=" + article.id;
19 | });
20 | $(document).trigger("user.getInfo", [article.writer,
21 | function(err, user) {
22 | if (err) return;
23 | $(".u-avatar", $art).append("
");
24 | }
25 | ]);
26 | $row.append($art);
27 | },
28 | __readMore = function(event) {
29 | $(document).unbind("scroll", __readMore);
30 | $(".u-more").text("正在加载...");
31 | var perPage = 10;
32 | if ($(window).height() + $(window).scrollTop() >= $('body').height()) {
33 | $(document).trigger("article.getAll", [curPage, perPage,
34 | function(err, articles) {
35 | if (err) {
36 | return;
37 | }
38 | var i, m;
39 | for (i = 0, m = articles.length; i < m; i++) {
40 | __draw(articles[i]);
41 | }
42 | curPage++;
43 | if (articles.length < perPage) {
44 | $(".u-more").text("已经没有更多文章了");
45 | } else {
46 | $(document).bind("scroll", __readMore);
47 | $(".u-more").text("向下滚动加载更多");
48 | $(document).scroll();
49 | }
50 | }
51 | ]);
52 | }
53 | };
54 | $("pre code").each(function(i, e) {
55 | hljs.highlightBlock(e);
56 | });
57 | $("#articles tbody tr").click(function(event) {
58 | var that = $(this);
59 | window.location.href = "article_load?articleId=" + that.attr("aid");
60 | });
61 | $(document).scroll(__readMore);
62 | $(document).scroll();
63 | }(jQuery, window));
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/public/javascripts/exp/broadchat.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var ws,
3 | $chat = $("#chat"),
4 | $users = $("#users"),
5 | $logs = $("#logs"),
6 | curUser = $chat.attr("nick");
7 | if (window.WebSocket === undefined) {
8 | $chat.text("您的浏览器不支持WebSocket!");
9 | }
10 | if (window.ws) {
11 | ws.close();
12 | }
13 | ws = new WebSocket("ws://localhost:3001");
14 | ws.onopen = function(event) {
15 | $("#nickname").val("游客");
16 | $logs.append("您已加入版聊");
17 | };
18 | ws.onclose = function(event) {
19 | $logs.append("您已断开版聊");
20 | };
21 | ws.onmessage = function(event) {
22 | var data = JSON.parse(event.data);
23 | if (data.type === "message") {
24 | $chat.append("" + 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("" + data.nick + "加入了版聊");
29 | }
30 | } else if (data.type === "exit") {
31 | $("p[uid='" + data.uid + "']", $users).remove();
32 | $logs.append("" + data.nick + "离开了版聊");
33 | } else if (data.type === "nickname") {
34 | $("#nickname").val(data.nick);
35 | $("p[uid='" + data.uid + "']", $users).text(data.nick);
36 | $logs.append("" + data.oldnick + " 修改昵称为 " + data.nick + "");
37 | }
38 | };
39 | $("#send").click(function(event) {
40 | var message = $("#message").val();
41 | if (message.trim() !== "") {
42 | ws.send(JSON.stringify({
43 | time: new Date().getTime(),
44 | message: message,
45 | type: "message"
46 | }));
47 | $("#message").val("");
48 | }
49 | });
50 | $("#changeNick").click(function(event) {
51 | var nick = $("#nickname").val();
52 | if (nick.trim() !== "") {
53 | ws.send(JSON.stringify({
54 | nick: nick,
55 | type: "nickname"
56 | }));
57 | }
58 | });
59 | $("#message").bind("keypress", function(event) {
60 | if ((event.keyCode || event.which) == 13) {
61 | $("#send").click();
62 | }
63 | }).focus();
64 | }(jQuery, window));
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/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/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/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 | }
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/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')
--------------------------------------------------------------------------------
/public/javascripts/page/userDetail.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var formValidate = $("#formValidate"),
3 | $allTags = $("#allTags"),
4 | $myTags = $("#myTags"),
5 | __addToMyTags = function(event) {
6 | var tag = event.data,
7 | $div = $("" + tag.name + "");
8 | $existTag = $myTags.find("span[tid='" + tag.id + "']");
9 | $div.click(__removeFromMyTags);
10 | if ($existTag.length === 0) {
11 | $myTags.append($div);
12 | } else {
13 | $existTag.parent().removeClass("a-label-strike");
14 | setTimeout(function() {
15 | $existTag.parent().addClass("a-label-strike");
16 | }, 0);
17 | }
18 | },
19 | __removeFromMyTags = function(event) {
20 | $(this).remove();
21 | };
22 | $("#inputAvatar").change(function(event) {
23 | $("#avatarPreview").attr("src", $(this).val());
24 | });
25 | $("#detail").submit(function(event) {
26 | var that = $(this),
27 | mytags = $myTags.find("span"),
28 | tags = [],
29 | i, m;
30 | formValidate.hide();
31 | if (!this.nickname.value) {
32 | formValidate.text("昵称不能为空").slideDown();
33 | return false;
34 | }
35 |
36 | if (!this.nickname.value.match(/^[\w\-\u4e00-\u9fa5]{3,12}$/)) {
37 | formValidate.text("昵称必须为长度为3~12的中文、字母、数字、下划线").slideDown();
38 | $(this.nickname).focus();
39 | return false;
40 | }
41 | if (!this.password.value && this.password.value !== "") {
42 | if (!this.password.value.match(/^[a-zA-Z0-9]{5,15}$/)) {
43 | formValidate.text("密码必须为长度为5~15的字母或数字").slideDown();
44 | $(this.password).focus();
45 | return false;
46 | }
47 | if (this.password.value != this.passwordAgain.value) {
48 | formValidate.text("密码验证不正确,请重新填写").slideDown();
49 | return false;
50 | }
51 | }
52 | for (i = mytags.length; i--;) {
53 | tags.push($(mytags[i]).attr("tid"));
54 | }
55 | this.tags.value = JSON.stringify(tags);
56 | });
57 |
58 | $("#newTagInput").change(function() {
59 | $(this).removeClass("has-error");
60 | });
61 |
62 | $("#createTag").click(function(event) {
63 | var name = $("#newTagInput").val(),
64 | color = $("#newTagInput").attr("color");
65 | if (!name) {
66 | $("#newTagInput").addClass("has-error");
67 | return false;
68 | }
69 | $(document).trigger("tag.createTag", [name, color, $allTags,__addToMyTags,function(event) {
70 | $("#newTagInput").val("");
71 | }]);
72 | });
73 |
74 | $(document).trigger("tag.drawAllTags", [$allTags,__addToMyTags]);
75 |
76 | $(document).trigger("tag.drawUserTags", [$("#inputUsername").val(), $myTags, __removeFromMyTags]);
77 |
78 | $(".u-label-picker").click(function(event) {
79 | $("#newTag").attr("class", "label b-label-" + $(this).attr("value")).find("input").attr("color", $(this).attr("color"));
80 | });
81 | }(jQuery, window));
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/public/javascripts/page/writeArticle.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var formValidate = $("#formValidate"),
3 | converter = new Showdown.converter({
4 | extensions: 'twitter'
5 | }),
6 | $articleTags = $("#articleTags"),
7 | $allTags = $("#allTags"),
8 | __addToArticleTags = function(event) {
9 | var tag = event.data,
10 | $div = $("" + tag.name + ""),
11 | $existTag = $articleTags.find("span[tid='" + tag.id + "']");
12 | $div.click(__removeFromArticleTags);
13 | if ($existTag.length === 0) {
14 | $articleTags.append($div);
15 | } else {
16 | $existTag.parent().removeClass("a-label-strike");
17 | setTimeout(function() {
18 | $existTag.parent().addClass("a-label-strike");
19 | }, 0);
20 | }
21 | },
22 | __removeFromArticleTags = function(event) {
23 | $(this).remove();
24 | };
25 |
26 | getWindowHeight = function() {
27 | if (window.innerHeight)
28 | return window.innerHeight;
29 | else if (document.documentElement && document.documentElement.clientHeight)
30 | return document.documentElement.clientHeight;
31 | else if (document.body)
32 | return document.body.clientHeight;
33 | };
34 |
35 | $("#inputArticle").bind("keyup", function(event) {
36 | $("#outputArticle").html(converter.makeHtml(this.value));
37 | $('pre code').each(function(i, e) {
38 | hljs.highlightBlock(e);
39 | });
40 | });
41 |
42 | $(window).bind("resize", function(event) {
43 | $("body").height(getWindowHeight() - 150);
44 | $(".panel").height(getWindowHeight() - 350);
45 | }).trigger("resize");
46 |
47 | $(document).trigger("tag.drawAllTags", [$allTags, __addToArticleTags]);
48 |
49 | $("#createTag").click(function(event) {
50 | var name = $("#newTagInput").val(),
51 | color = $("#newTagInput").attr("color");
52 | if (!name) {
53 | $("#newTagInput").addClass("has-error");
54 | return false;
55 | }
56 |
57 | $(document).trigger("tag.createTag", [name, color, $allTags, __addToArticleTags,
58 | function(err, $tag) {
59 | if (err) {
60 | alert("创建标签失败");
61 | return;
62 | }
63 | $("#newTagInput").val("");
64 | }
65 | ]);
66 | });
67 |
68 | $(".u-label-picker").click(function(event) {
69 | $("#newTag").attr("class", "label b-label-" + $(this).attr("value")).find("input").attr("color", $(this).attr("color"));
70 | });
71 |
72 | $("#articleForm").submit(function(event) {
73 | var that = $(this),
74 | articleTags = $articleTags.find("span"),
75 | tags = [],
76 | i, m;
77 | formValidate.hide();
78 | if (!this.title.value) {
79 | formValidate.text("标题不能为空").slideDown();
80 | return false;
81 | }
82 | for (i = articleTags.length; i--;) {
83 | tags.push($(articleTags[i]).attr("tid"));
84 | }
85 | this.tags.value = JSON.stringify(tags);
86 | });
87 | }(jQuery, window));
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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/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 | };
--------------------------------------------------------------------------------
/public/javascripts/page/search.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var $tags = $("#tags"),
3 | $chosenTags = $("#chosenTags"),
4 | $articles = $("#articles"),
5 | tags = [],
6 | curPage = 0,
7 | perPage = 10,
8 | title = "",
9 | searchType,
10 | __chooseTag = function(event) {
11 | var that = $(this);
12 | $chosenTags.append(that);
13 | that.unbind("click", __chooseTag).bind("click", __unChooseTag);
14 | },
15 | __unChooseTag = function(event) {
16 | var that = $(this);
17 | $tags.append(that);
18 | that.unbind("click", __unChooseTag).bind("click", __chooseTag);
19 | },
20 | __drawArticle = function(article) {
21 | var $row = $(''),
22 | $avatar = $(''),
23 | $time = $('').text(article.writeTime),
24 | $title = $('').text(article.title);
25 | $row.append($avatar).append($time).append($title).click(function(event) {
26 | window.location.href = "/article_load?articleId=" + article.id;
27 | });
28 | $(document).trigger("user.getInfo", [article.writer,
29 | function(err, user) {
30 | if (err) return;
31 | if (user) {
32 | $avatar.append('
');
33 | }
34 | }
35 | ]);
36 | $articles.append($row);
37 | },
38 | __getMore = function(event) {
39 | var that = $(this),
40 | __searchCallback = function(err, articles) {
41 | if (err) {
42 | that.text("搜索发生错误");
43 | return;
44 | }
45 | for (var i = 0, m = articles.length; i < m; i++) {
46 | __drawArticle(articles[i]);
47 | }
48 | if (articles.length < perPage) {
49 | that.text("已经没有更多的结果了");
50 | } else {
51 | that.text("点击搜索更多").bind("click", __getMore);
52 | curPage++;
53 | }
54 | };
55 | if (searchType === "tags") {
56 | if (tags.length > 0) {
57 | that.text("搜索中,请稍后").unbind("click", __getMore);
58 | $(document).trigger("article.getByTags", [tags, curPage, perPage, __searchCallback]);
59 | }
60 | } else if (searchType === "title") {
61 | console.log(title);
62 | if (title.trim()) {
63 | that.text("搜索中,请稍后").unbind("click", __getMore);
64 | $(document).trigger("article.getByTitle", [title, curPage, perPage, __searchCallback]);
65 | }
66 | }
67 | };
68 | $(document).trigger("tag.drawAllTags", [$tags, __chooseTag]);
69 | $("#more").click(__getMore);
70 |
71 | $("#tagSearchBtn").click(function(event) {
72 | $articles.html("");
73 | tags = [];
74 | $chosenTags.find(".label").each(function() {
75 | tags.push($(this).attr("tid"));
76 | });
77 | curPage = 0;
78 | searchType = "tags";
79 | $("#more").unbind("click", __getMore).bind("click", __getMore).click();
80 | });
81 |
82 | $("#titleSearchBtn").click(function(event) {
83 | $articles.html("");
84 | title = $("#titleSearchInput").val();
85 | curPage = 0;
86 | searchType = "title";
87 | $("#more").unbind("click", __getMore).bind("click", __getMore).click();
88 | });
89 | }(jQuery, window));
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/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/javascripts/page/editArticle.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var converter = new Showdown.converter(),
3 | formValidate = $("#formValidate"),
4 | $articleTags = $("#articleTags"),
5 | $allTags = $("#allTags"),
6 | getWindowHeight = function() {
7 | if (window.innerHeight)
8 | return window.innerHeight;
9 | else if (document.documentElement && document.documentElement.clientHeight)
10 | return document.documentElement.clientHeight;
11 | else if (document.body)
12 | return document.body.clientHeight;
13 | },
14 | __addToArticleTags = function(event) {
15 | var tag = event.data,
16 | $div = $("" + tag.name + ""),
17 | $existTag = $articleTags.find("span[tid='" + tag.id + "']");
18 | $div.click(__removeFromArticleTags);
19 | if ($existTag.length === 0) {
20 | $articleTags.append($div);
21 | } else {
22 | $existTag.parent().removeClass("a-label-strike");
23 | setTimeout(function() {
24 | $existTag.parent().addClass("a-label-strike");
25 | }, 0);
26 | }
27 | },
28 | __removeFromArticleTags = function(event) {
29 | $(this).remove();
30 | };
31 |
32 | $("#inputArticle").bind("keyup", function(event) {
33 | $("#outputArticle").html(converter.makeHtml(this.value));
34 | $('pre code').each(function(i, e) {
35 | hljs.highlightBlock(e);
36 | });
37 | }).trigger("change");
38 |
39 | $(window).bind("resize", function(event) {
40 | $("body").height(getWindowHeight() - 150);
41 | $(".panel").height(getWindowHeight() - 350);
42 | }).trigger("resize");
43 |
44 | $("#saveArtBtn").click(function(event) {
45 | var that = $(this),
46 | articleTags = $articleTags.find("span"),
47 | tags = [],
48 | i, m;
49 | formValidate.hide();
50 | if (!$("#inputTitle").val() || $("#inputTitle").val() === "") {
51 | formValidate.text("标题不能为空").slideDown();
52 | return false;
53 | }
54 | for (i = articleTags.length; i--;) {
55 | tags.push($(articleTags[i]).attr("tid"));
56 | }
57 | $.ajax({
58 | url: "/nor/conf/article_update",
59 | data: {
60 | articleId: that.attr("aid"),
61 | title: $("#inputTitle").val(),
62 | content: $("#inputArticle").val(),
63 | tags: JSON.stringify(tags)
64 | },
65 | type: "POST",
66 | dataType: "json"
67 | }).done(function(data) {
68 | window.location.href = "/article_load?articleId=" + that.attr("aid");
69 | }).error(function(data) {
70 | console.log(data);
71 | });
72 | });
73 |
74 | $(document).trigger("tag.drawAllTags", [$allTags, __addToArticleTags]);
75 |
76 | $(document).trigger("tag.drawArticleTags", [$articleTags.attr("aid"), $articleTags, __removeFromArticleTags]);
77 |
78 | $("#createTag").click(function(event) {
79 | var name = $("#newTagInput").val(),
80 | color = $("#newTagInput").attr("color");
81 | if (!name) {
82 | $("#newTagInput").addClass("has-error");
83 | return false;
84 | }
85 |
86 | $(document).trigger("tag.createTag", [name, color, $allTags, __addToArticleTags,
87 | function(event) {
88 | $("#newTagInput").val("");
89 | }
90 | ]);
91 | });
92 |
93 | $(".u-label-picker").click(function(event) {
94 | $("#newTag").attr("class", "label b-label-" + $(this).attr("value")).find("input").attr("color", $(this).attr("color"));
95 | });
96 |
97 | }(jQuery, window));
--------------------------------------------------------------------------------
/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/javascripts/page/uploadPic.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var $uploadZone = $("#uploadZone"),
3 | $uploadOutput = $("#uploadOutput"),
4 | $uploadResult = $("#uploadResult"),
5 | __uploadCancel = function(event) {
6 | var that = $(this).parent(),
7 | fileName = that.attr("fileName");
8 | $.ajax({
9 | url: "/nor/conf/picture_uploadCancel",
10 | data: {
11 | fileName: fileName
12 | },
13 | dataType: "json",
14 | type: "post"
15 | }).done(function(data) {
16 | that.fadeOut(function() {
17 | $(this).remove();
18 | });
19 | }).fail(function(err) {
20 | console.log(err);
21 | });
22 | },
23 | __uploadFile = function(file) {
24 | var $div = $("
"),
25 | reader = new FileReader(),
26 | form = new FormData(),
27 | xhr = new XMLHttpRequest();
28 | $uploadOutput.prepend($div);
29 | reader.onload = __parseCallback($div);
30 | reader.readAsDataURL(file);
31 | form.append("image", file);
32 | xhr.open("post", "/nor/conf/picture_upload", true);
33 | xhr.onreadystatechange = function(event) {
34 | if (4 == this.readyState) {
35 | var data = JSON.parse(event.target.response);
36 | $div.attr("fileName", data.fileName);
37 | $div.find(".u-remove").click(__uploadCancel);
38 | }
39 | };
40 | xhr.upload.addEventListener("progress", function(event) {
41 | $div.find(".u-process").text(event.loaded / event.total * 100 + "%");
42 | }, false);
43 | xhr.send(form);
44 | },
45 | __parseCallback = function($div) {
46 | return function(event) {
47 | $div.find("img").attr("src", event.target.result);
48 | };
49 | };
50 |
51 | $.event.props.push("dataTransfer");
52 |
53 | $uploadZone.bind("dragover", function(event) {
54 | event.stopPropagation();
55 | event.preventDefault();
56 | event.dataTransfer.dropEffect = 'copy';
57 | });
58 |
59 | $uploadZone.bind("drop", function(event) {
60 | event.stopPropagation();
61 | event.preventDefault();
62 | var files = event.dataTransfer.files;
63 |
64 | for (var i = files.length; i--;) {
65 | if (!files[i].type.match(/image*/)) {
66 | continue;
67 | }
68 | __uploadFile(files[i]);
69 | }
70 | });
71 |
72 | $("#uploadBtn").bind("click", function(event) {
73 | var imgs = [];
74 | $uploadOutput.find("div").each(function() {
75 | if ($(this).attr("fileName")) {
76 | imgs.push($(this).attr("fileName"));
77 | }
78 | });
79 | $uploadResult.removeClass("alert-success alert-danger").hide();
80 | if (imgs.length > 0) {
81 | $.ajax({
82 | url: "/nor/conf/picture_confirm",
83 | type: "post",
84 | dataType: "json",
85 | data: {
86 | images: imgs
87 | }
88 | }).done(function(data) {
89 | $uploadOutput.find(".g-preview").fadeOut(function() {
90 | $uploadOutput.find(".g-preview").remove();
91 | });
92 | $uploadResult.addClass("alert-success").text("上传" + imgs.length + "张图片成功!").slideDown();
93 | }).fail(function(err) {
94 | $uploadResult.addClass("alert-danger").text("上传图片失败!").slideDown();
95 | });
96 | } else {
97 | $uploadResult.addClass("alert-danger").text("没有选择图片!").slideDown();
98 | }
99 | });
100 | }(jQuery, window));
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | ```
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/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')
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/public/javascripts/page/articleDetail.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var $replyComment = $("#replyComment"),
3 | $comments = $("#comments"),
4 | $bookmark = $("#bookmark"),
5 | curUser = $comments.attr("curUser"),
6 | __readMoreComments = function(event) {
7 | var articleId = $comments.attr("aid"),
8 | curPage = Number($comments.attr("cur")),
9 | perPage = 10,
10 | commentContainer = $comments.find(".g-container");
11 | $comments.find(".u-more").text("正在努力加载中...").unbind("click", __readMoreComments);
12 | $(document).trigger("comment.getByArticle", [articleId, curPage, perPage,
13 | function(err, comments) {
14 | var i, m, container,
15 | __deleteFn = function(container) {
16 | return function(event) {
17 | var comment = $(this).data("comment");
18 | $(document).trigger("comment.remove", [comment.id,
19 | function(err) {
20 | if (err) return;
21 | container.fadeOut(function() {
22 | container.remove();
23 | });
24 | }
25 | ]);
26 | };
27 | },
28 | __replyFn = function(container) {
29 | return function(event) {
30 | var comment = $(this).data("comment");
31 | $("textarea", $replyComment).val("");
32 | if ($("form input[name='replyId']", $replyComment).val() !== comment.id) {
33 | $replyComment.slideUp(function() {
34 | container.find(".g-comment-row:first").append($replyComment);
35 | $replyComment.slideDown(function() {
36 | $("textarea", $replyComment).focus();
37 | });
38 | $("form input[name='replyId']").val(comment.id);
39 | });
40 | } else {
41 | if ($replyComment.css("display") === "none") {
42 | $replyComment.slideDown(function() {
43 | $("textarea", $replyComment).focus();
44 | });
45 | } else {
46 | $replyComment.slideUp();
47 | }
48 | }
49 | };
50 | },
51 | __commentFn = function(err, $comment) {
52 | var comment = $comment.data("comment");
53 | if (comment.username !== curUser) {
54 | $comment.find("span[type='remove']").parent().remove();
55 | }
56 | if (!curUser) {
57 | $comment.find("span[type='reply']").parent().remove();
58 | }
59 | $(document).trigger("admire.draw", [$comment.data("comment").id, $comment.find(".u-admire").parent()]);
60 | };
61 | if (err) {
62 | $comments.find(".u-more").text("获取评论失败");
63 | return;
64 | }
65 | for (i = 0, m = comments.length; i < m; i++) {
66 | container = $("").appendTo(commentContainer);
67 | $(document).trigger("comment.drawOne", [comments[i], container, [{
68 | html: "删除",
69 | click: __deleteFn(container)
70 | }, {
71 | html: "回复",
72 | click: __replyFn(container)
73 | }, {
74 | html: ""
75 | }],
76 | __commentFn
77 | ]);
78 | }
79 | $comments.attr("cur", curPage + 1);
80 | if (comments.length < perPage) {
81 | $comments.find(".u-more").text("没有更多评论了");
82 | } else {
83 | $comments.find(".u-more").text("点击获取更多评论").bind("click", __readMoreComments);
84 | }
85 |
86 | }
87 | ]);
88 | };
89 | $('pre code').each(function(i, e) {
90 | hljs.highlightBlock(e);
91 | });
92 |
93 | $("#clearComment").click(function(event) {
94 | $("#newComments textarea").val("");
95 | });
96 |
97 | $(document).trigger("tag.drawArticleTags", [$("#tags").attr("aid"), $("#tags")]);
98 |
99 | $(".g-art-info .u-avatar").each(function() {
100 | $(document).trigger("user.draw", [$(this).attr("uid"), $(this),
101 | function(err, $user) {
102 | if (err) return;
103 | var user = $user.data("user");
104 | $(".g-art-info .u-nick").text(user.nickname);
105 | }
106 | ]);
107 | });
108 |
109 | $comments.find(".u-more").click(__readMoreComments).click();
110 |
111 | $(document).trigger("bookmark.draw", [$bookmark.attr("aid"), $bookmark, $bookmark.attr("cur")]);
112 |
113 | $("#deleteArticle").click(function(event) {
114 | $(document).trigger("article.remove", [$(this).attr("aid"), function(err){
115 | if(err) return;
116 | window.location.href = "/article_list";
117 | }]);
118 | });
119 | }(jQuery, window));
--------------------------------------------------------------------------------
/public/javascripts/pageTools/Remind.js:
--------------------------------------------------------------------------------
1 | (function($, window) {
2 | var emitter = $(document);
3 | emitter.bind({
4 | "remind.remove": function(event, remindId, fnCallback) {
5 | $.ajax({
6 | url: "/nor/remind_remove",
7 | type: "post",
8 | dataType: "json",
9 | data: {
10 | remindId: remindId
11 | }
12 | }).done(function(data) {
13 | if (typeof fnCallback === "function") fnCallback(null);
14 | }).fail(function(err) {
15 | if (typeof fnCallback === "function") fnCallback(err);
16 | });
17 | },
18 | "remind.countAll": function(event, fnCallback) {
19 | $.ajax({
20 | url: "/nor/remind_countAll",
21 | type: "post",
22 | dataType: "json"
23 | }).done(function(data) {
24 | if (typeof fnCallback === "function") fnCallback(null, data.total);
25 | }).fail(function(err) {
26 | if (typeof fnCallback === "function") fnCallback(err);
27 | });
28 | },
29 | "remind.countByType": function(event, type, fnCallback) {
30 | $.ajax({
31 | url: "/nor/remind_countByType",
32 | type: "post",
33 | dataType: "json",
34 | data: {
35 | type: type
36 | }
37 | }).done(function(data) {
38 | if (typeof fnCallback === "function") fnCallback(null, data.total);
39 | }).fail(function(err) {
40 | if (typeof fnCallback === "function") fnCallback(err);
41 | });
42 | },
43 | "remind.getAll": function(event, curPage, perPage, fnCallback) {
44 | $.ajax({
45 | url: "/nor/remind_getAll",
46 | type: "post",
47 | dataType: "json",
48 | data: {
49 | curPage: curPage,
50 | perPage: perPage
51 | }
52 | }).done(function(data) {
53 | if (typeof fnCallback === "function") fnCallback(null, data.reminds);
54 | }).fail(function(err) {
55 | if (typeof fnCallback === "function") fnCallback(err);
56 | });
57 | },
58 | "remind.getByType": function(event, type, curPage, perPage, fnCallback) {
59 | $.ajax({
60 | url: "/nor/remind_getByType",
61 | type: "post",
62 | dataType: "json",
63 | data: {
64 | type: type,
65 | curPage: curPage,
66 | perPage: perPage
67 | }
68 | }).done(function(data) {
69 | if (typeof fnCallback === "function") fnCallback(null, data.reminds);
70 | }).fail(function(err) {
71 | if (typeof fnCallback === "function") fnCallback(err);
72 | });
73 | },
74 | "remind.setReaded": function(event, remindIds, fnCallback) {
75 | $.ajax({
76 | url: "/nor/remind_setReaded",
77 | type: "post",
78 | dataType: "json",
79 | data: {
80 | remindIds: remindIds
81 | }
82 | }).done(function(data) {
83 | if (typeof fnCallback === "function") fnCallback(null);
84 | }).fail(function(err) {
85 | if (typeof fnCallback === "function") fnCallback(err);
86 | });
87 | },
88 | "remind.draw": function(event, container, fnCallback) {
89 | container.addClass("b-remind-loading");
90 | var i,
91 | __countComment = function(err, total) {
92 | if (err) {
93 | if (typeof fnCallback === "function") fnCallback(err);
94 | return;
95 | }
96 | var $li = $("");
97 | if (total) {
98 | $li.append(" " + total + " 条新回复");
99 | container.append($li);
100 | }
101 | container.data("commentTotal", total);
102 | emitter.trigger("remind.countByType", ["bookmark", __countBookmark]);
103 | },
104 | __countBookmark = function(err, total) {
105 | if (err) {
106 | if (typeof fnCallback === "function") fnCallback(err);
107 | return;
108 | }
109 | var $li = $("");
110 | if (total) {
111 | $li.append(" " + total + " 条新收藏消息");
112 | container.append($li);
113 | }
114 | container.data("bookmarkTotal", total);
115 | emitter.trigger("remind.countByType", ["admire", __countAdmire]);
116 | },
117 | __countAdmire = function(err, total) {
118 | if (err) {
119 | if (typeof fnCallback === "function") fnCallback(err);
120 | return;
121 | }
122 | var $li = $("");
123 | if (total) {
124 | $li.append(" " + total + " 条赞");
125 | container.append($li);
126 | }
127 | container.data("admireTotal", total);
128 | container.removeClass("b-remind-loading");
129 | if (typeof fnCallback === "function") fnCallback(null, container);
130 | };
131 | emitter.trigger("remind.countByType", ["comment", __countComment]);
132 | }
133 | });
134 | }(jQuery, window));
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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')
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------